Source code for dodiscover.ci.fisher_z_test

from math import log, sqrt
from typing import Optional, Set, Tuple

import numpy as np
import pandas as pd
from scipy.stats import norm

from dodiscover.typing import Column

from .base import BaseConditionalIndependenceTest


[docs]class FisherZCITest(BaseConditionalIndependenceTest): def __init__(self, correlation_matrix=None): """Conditional independence test using Fisher-Z's test for Gaussian random variables. Parameters ---------- correlation_matrix : np.ndarray of shape (n_variables, n_variables), optional ``None`` means without the parameter of correlation matrix and the correlation will be computed from the data., by default None """ self.correlation_matrix = correlation_matrix
[docs] def test( self, df: pd.DataFrame, x_vars: Set[Column], y_vars: Set[Column], z_covariates: Optional[Set[Column]] = None, ) -> Tuple[float, float]: """Abstract method for all conditional independence tests. Parameters ---------- df : pd.DataFrame The dataframe containing the dataset. x_vars : Set of column A column in ``df``. y_vars : Set of column A column in ``df``. z_covariates : Set, optional A set of columns in ``df``, by default None. If None, then the test should run a standard independence test. Returns ------- stat : float The test statistic. pvalue : float The p-value of the test. """ self._check_test_input(df, x_vars, y_vars, z_covariates) if z_covariates is None: z_covariates = set() x_var = x_vars.pop() y_var = y_vars.pop() stat, pvalue = fisherz(df, x_var, y_var, z_covariates, self.correlation_matrix) return stat, pvalue
def fisherz( data: pd.DataFrame, x: Column, y: Column, sep_set: Set, correlation_matrix=None, ): """Perform an independence test using Fisher-Z's test. Works on Gaussian random variables. Parameters ---------- data : pd.DataFrame The data. x : Column the first node variable. If ``data`` is a DataFrame, then 'x' must be in the columns of ``data``. y : Column the second node variable. If ``data`` is a DataFrame, then 'y' must be in the columns of ``data``. sep_set : set the set of neibouring nodes of x and y (as a set()). correlation_matrix : np.ndarray of shape (n_variables, n_variables), optional ``None`` means without the parameter of correlation matrix and the correlation will be computed from the data., by default None Returns ------- X : float The test statistic. p : float The p-value of the test. """ data_arr = data.to_numpy() if correlation_matrix is None: correlation_matrix = np.corrcoef(data_arr.T) sample_size = data.shape[0] var = list({x, y}.union(sep_set)) # type: ignore (var_idx,) = np.in1d(data.columns, var).nonzero() # compute the correlation matrix within the specified data sub_corr_matrix = correlation_matrix[np.ix_(var_idx, var_idx)] inv = np.linalg.inv(sub_corr_matrix) r = -inv[0, 1] / sqrt(inv[0, 0] * inv[1, 1]) # apply the Fisher Z-transformation Z = 0.5 * log((1 + r) / (1 - r)) # compute the test statistic X = sqrt(sample_size - len(sep_set) - 3) * abs(Z) p = 2 * (1 - norm.cdf(abs(X))) return X, p