为了账号安全,请及时绑定邮箱和手机立即绑定

卡方检验的计算

卡方检验的计算

明月笑刀无情 2023-10-18 21:03:58
我试图了解如何针对以下输入计算 chi2 函数。sklearn.feature_selection.chi2([[1, 2, 0, 0, 1],                                 [0, 0, 1, 0, 0],                                 [0, 0, 0, 2, 1]], [True, False, False])我得到 chi2 的以下结果[2, 4, 0.5, 1, 0.25]。我已经在维基百科上找到了以下计算公式(x_i 也被称为观察值,m_i 被称为预期值),但我不知道如何应用它。我的理解是,我有三个类别的输入(行)和四个特征(列),chi2 函数返回特征和类之间是否存在相关性。第一列表示的特征在第一个类别中出现两次,并且 chi2 值为 4。我想我已经弄清楚的是这些列是相互独立的,这是有道理的如果我省略第三行,预期值将是列的总和,观察值只是相应单元格中的值,但这不适用于最后一列这两列False似乎以某种方式组合在一起,但我还没有弄清楚如何组合。如果有人可以帮助我,我将不胜感激。谢谢!
查看完整描述

2 回答

?
慕娘9325324

TA贡献1783条经验 获得超4个赞

该计算sklearn.feature_selection.chi2 与卡方独立性检验的典型教科书示例不同(对于此类经典的卡方检验,请参阅下面我提供的手动计算)。


sklearn.feature_selection.chi2:假设我们有一个目标变量 y(分类,例如 0, 1, 2)和一个非负连续变量 x(例如,0 到 100 之间的任何位置),并且我们想要测试 x 和 y 之间的独立性(例如,y 独立于 x 意味着 x 作为预测特征没有用)。该算法计算给定 y 的 x 的组和(例如,sum_x_y0、sum_x_y1、sum_x_y2 - 称它们为观察值),并将这些 观察值与 x 的概率权重总计(例如,prob_y0*x_tot、prob_y1*x_tot、prob_y2* x_tot——称它们为预期),使用卡方检验,对 y 中的 k 类别具有 (k-1) 个自由度。因为它使用卡方检验,所以正如我想象的那样,它的计算中不能有负和。(我不确定这是否有学术参考,但这种方法似乎是有意义的。)

这是sklearn 用户指南中的示例代码,用于使用chi2.

from sklearn.datasets import load_iris

from sklearn.feature_selection import SelectKBest

from sklearn.feature_selection import chi2

X, y = load_iris(return_X_y=True)

print(X.shape)


X_new = SelectKBest(chi2, k=2).fit_transform(X, y)

X_new.shape

对于两个分类变量之间独立性的经典卡方检验,这是我的手动计算代码,它似乎与scipy卡方计算相匹配。我使用的公式与您上面发布的相同,但dof是(x - 1 中的 var 级别)和(y - 1 中的级别)。

from sklearn.feature_selection import chi2

x = [[1, 2, 0, 0, 1],

     [0, 0, 1, 0, 0],

     [0, 0, 0, 2, 1]]

y = [True, False, False]


chi2(x,y)[0]

import numpy as np

def is_val_eq(vec, val): return [i==val for i in vec]


def chi_E(vec1, vec1_val, vec2, vec2_val): 

    num1 = sum(is_val_eq(vec1, vec1_val))

    num2 = sum(is_val_eq(vec2, vec2_val))

    return num1*num2/len(vec1)


def chi_O(vec1, vec1_val, vec2, vec2_val):

    idx1 = is_val_eq(vec1, vec1_val)

    idx2 = is_val_eq(vec2, vec2_val)

    return sum(np.logical_and(idx1, idx2))


def chi_inside(O, E): return (O-E)**2/E


def chi_square(Os, Es): return sum([chi_inside(O,E) for O,E in zip(Os, Es)])


def get_col(x, col): return [row[col] for row in x]


def calc_chi(vec_x, vec_y):

    val_xs = set(vec_x)

    val_ys = set(vec_y)

    Es = [chi_E(vec_x, val_x, vec_y, val_y) 

      for val_x in val_xs for val_y in val_ys]


    Os = [chi_O(vec_x, val_x, vec_y, val_y) 

      for val_x in val_xs for val_y in val_ys]

    return chi_square(Os, Es), Es, Os

from scipy.stats import chi2_contingency 

from scipy import stats


chi_calc = dict(manual=[], scipy_cont=[], scipy_stats=[])


for idx_feature in range(5):

    chi_sq, Es, Os = calc_chi(get_col(x, idx_feature), y)

    chi_calc['manual'].append(chi_sq)

    

    data = [Os[0:2], Os[2:4]]

    stat, p, dof, expected = chi2_contingency(data, correction=False)

    chi_calc['scipy_cont'].append(stat)

    

    result = stats.chisquare(data, f_exp = expected, ddof = 1, axis=None)

    chi_calc['scipy_stats'].append(result.statistic)

直观上,如果您试图测试 的分类变量列相x对于 的独立性y,则 的前两列x应该给出相同的统计量(因为它们只是彼此的缩放版本,因此在分类级别方面是相同的) 。


查看完整回答
反对 回复 2023-10-18
?
撒科打诨

TA贡献1934条经验 获得超2个赞

我刚刚研究了 scikit-learn 的来源。计算实际上相当简单。在我的示例中,我们有两个类(True 和 False)。对于第二类,我们有两个样本 ([0, 0, 1, 0, 0][0, 0, 0, 2, 1])。

我们首先列出每个类的一些列,其中给出了观察到的值:

 True: [1, 2, 0, 0, 1]
 False: [0, 0, 1, 2, 1]

为了计算预期值,我们计算所有列的总和(即在所有类中观察到的特征的总数),得出[1, 2, 1, 2, 2]。如果我们假设某个特征与其所在的类别之间没有相关性,则这些值的分布必须与我们拥有的样本数量相对应。即,应该在类和类1/3中找到值,这给出了预期值:True2/3False

 True: 1/3 * [1, 2, 1, 2, 2] = [1/3 2/3 1/3 2/3 2/3]
 False: 2/3 * [1, 2, 1, 2, 2] = [2/3 4/3 2/3 4/3 4/3]

现在可以计算每一列的 chi2,作为最有趣的最后一列的示例:

(1-2/3)^2 / (2/3) + (1-4/3)^2 / (4/3) = 1/6 + 1/12 = 1/4 = 0.25

0.25 的误差相对较小,因此,正如人们所期望的那样,该特征与类别无关。


查看完整回答
反对 回复 2023-10-18
  • 2 回答
  • 0 关注
  • 78 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信