tia*_*iao 11 python statistics numpy machine-learning scikit-learn
在scikit-learn http://cikit-learn.org/stable/modules/generated/sklearn.feature_selection.chi2.html的卡方单面特征选择函数的文档中,它指出
该分数可用于选择具有来自X的χ2(卡方)统计值的最高值的n_features特征,其必须包含相对于类的布尔值或频率(例如,文档分类中的术语计数).
我很难理解相应的列联表是什么样的,特别是在频率特征的情况下.
例如,考虑具有布尔特征和目标的以下数据集:
import numpy as np
>>> X = np.random.randint(2, size=50).reshape(10, 5)
array([[1, 0, 0, 0, 1],
[1, 1, 0, 1, 1],
[1, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 1],
[1, 0, 0, 0, 1],
[1, 0, 1, 1, 1],
[0, 1, 1, 0, 0],
[1, 0, 1, 1, 1],
[1, 1, 1, 1, 0]])
>>> y = np.random.randint(2, size=10)
array([1, 0, 0, 0, 1, 1, 1, 1, 0, 1])
Run Code Online (Sandbox Code Playgroud)
要构建关于第一个特征的列联表,我们可以这样做(原谅我的PEP8违规)
import scipy as sp
>>> contingency_table = sp.sparse.coo_matrix(
... (np.ones_like(y), (X[:, 0], y)),
... shape=(np.unique(X[:, 0]).shape[0], np.unique(y).shape[0])).A
array([[1, 2],
[3, 4]])
Run Code Online (Sandbox Code Playgroud)
所以现在我可以计算卡方统计量及其p值
>>> sp.stats.chi2_contingency(contingency_table)
(0.17857142857142855,
0.67260381744151676,
1,
array([[ 1.2, 1.8],
[ 2.8, 4.2]]))
Run Code Online (Sandbox Code Playgroud)
这应该与scikit-learn的一致 chi2
from sklearn.feature_selection import chi2
>>> chi2_, pval = chi2(X, y)
>>> chi2_[0], pval[0]
(0.023809523809523787, 0.87737055606414338)
Run Code Online (Sandbox Code Playgroud)
...不.我误解了什么吗?
此外,在频率情况下,列联表是什么样的?我以为它会是这样的
contingency_table = sp.sparse.coo_matrix(
(np.ones_like(y), (X[:, 0], y)),
shape=(X[:, 0].max()+1, np.unique(y).shape[0])).A
Run Code Online (Sandbox Code Playgroud)
但是相应的预期频率表很可能有几个零元素.
编辑:
为了进一步澄清,考虑第一个特征X[:, 0],即性别和目标y,比如手性.
从这里我们得到交叉表
Right-handed Left-handed (!right-handed)
Male 1 2
Female (!male) 3 4
Run Code Online (Sandbox Code Playgroud)
我们可以通过设置预期频率,使用卡方检验来评估两个比例之间差异的显着性
sklearn.feature_selection.chi2直接做到这一点,无需借助于显式计算表,并使用相当于更高效的过程获得分数scipy.stats.chisquare.
在明确枚举上面显示的表之后,我想验证它与chi2应用时是否一致,scipy.stats.chi2_contingency令我沮丧的是,它不是.我想问为什么不是.
鉴于您的数据,
>>> X = array([[1, 0, 0, 0, 1],
... [1, 1, 0, 1, 1],
... [1, 0, 0, 0, 0],
... [0, 0, 0, 0, 0],
... [0, 0, 0, 0, 1],
... [1, 0, 0, 0, 1],
... [1, 0, 1, 1, 1],
... [0, 1, 1, 0, 0],
... [1, 0, 1, 1, 1],
... [1, 1, 1, 1, 0]])
>>> y = array([1, 0, 0, 0, 1, 1, 1, 1, 0, 1])
Run Code Online (Sandbox Code Playgroud)
这是feature_selection.chi2计算:
>>> Y = np.vstack([1 - y, y])
>>> observed = np.dot(Y, X)
>>> observed
array([[3, 1, 1, 2, 2],
[4, 2, 3, 2, 4]])
Run Code Online (Sandbox Code Playgroud)
这些是每类观察到的特征频率,即列联表.那么期望值:
>>> feature_count = X.sum(axis=0)
>>> class_prob = Y.mean(axis=1)
>>> expected = np.dot(feature_count.reshape(-1, 1), class_prob.reshape(1, -1)).T
>>> expected
array([[ 2.8, 1.2, 1.6, 1.6, 2.4],
[ 4.2, 1.8, 2.4, 2.4, 3.6]])
Run Code Online (Sandbox Code Playgroud)
最后,它运行χ²测试:
>>> from scipy.stats import chisquare
>>> score, pval = chisquare(observed, expected)
>>> score
array([ 0.02380952, 0.05555556, 0.375 , 0.16666667, 0.11111111])
>>> pval
array([ 0.87737056, 0.81366372, 0.54029137, 0.6830914 , 0.73888268])
Run Code Online (Sandbox Code Playgroud)
分数是相关的位:它们用于通过判别力对特征进行排序.请注意,每个功能可获得一个分数和一个p值.
考虑列x的X. sklearn.feature_selection.chi2测试y值为x1的频率是否y与整个群体的频率一致.(@ larsman的回答显示了如何再现与numpy的和SciPy的计算.)这是不一样的标准2×2列联表分析x和y.在2x2列联表分析中,y
where x为0 的频率也有助于测试.
假设我们为x和形成了列联表y:
| y=0 y=1
----+---------
x=0 | a b
x=1 | c d
Run Code Online (Sandbox Code Playgroud)
设n = a + b + c + d.这是样本数(即与len(x)和len(y)相同).
设nx = c + d.这是1in 的出现次数x.
设py1 =(b + d)/ n.这是y为1的完整人口的一部分.
sklearn.feature_selection.chi2使用期望值[(1-py1)*nx,py1*nx]对[c,d]执行chi2检验.这与2x2表的标准列联表分析不同.
这是一个极端的例子.假设2×2列联表的x和y是
| y=0 y=1
----+----------
x=0 | 8 8
x=1 | 20 188
Run Code Online (Sandbox Code Playgroud)
sklearn计算得出的chi2得分为1.58,p值为0.208.
列联表分析scipy.stats.chi2_contingency得出chi2得分为18.6,p值为1.60e-5.