Scipy 和 Sklearn chi2 实现给出不同的结果
Posted
技术标签:
【中文标题】Scipy 和 Sklearn chi2 实现给出不同的结果【英文标题】:Scipy and Sklearn chi2 implementations give different results 【发布时间】:2018-11-28 15:43:36 【问题描述】:我使用sklearn.feature_selection.chi2
进行特征选择,发现了一些意想不到的结果(检查代码)。有谁知道是什么原因,或者可以向我指出一些文档或拉取请求?
我将我得到的结果与使用scipy.stats.chi2_contingency
手工获得的预期结果进行了比较。
代码:
import numpy as np
import pandas as pd
from scipy.stats import chi2_contingency
from sklearn.feature_selection import chi2, SelectKBest
x = np.array([[1, 1, 1, 0, 1], [1, 0, 1, 0, 0], [0, 0, 1, 1, 1], [0, 0, 1, 1, 0], [0, 0, 0, 1, 1], [0, 0, 0, 1, 0]])
y = np.array([1, 1, 2, 2, 3, 3])
scores = []
for i in range(x.shape[1]):
result = chi2_contingency(pd.crosstab(x[:, i], y))
scores.append(result[0])
sel = SelectKBest(score_func=chi2, k=3)
sel.fit(x, y)
print(scores)
print(sel.scores_)
print(sel.get_support())
结果是:
[6., 2.4, 6.0, 6.0, 0.0] (Expected)
[4. 2. 2. 2. 0.] (Unexpected)
[ True True False True False]
使用 scipy,它保留特征 0、2、3,而使用 sklearn,它保留特征 0、1、3。
【问题讨论】:
【参考方案1】:首先,使用 scipy 实现计算时,观察值和期望值互换,应该是
scores = []
for i in range(x.shape[1]):
result = chi2_contingency(pd.crosstab(y,x[:,i] ))
scores.append(result[0])
所以现在 scipy 结果是:
[6.000000000000001, 2.4000000000000004, 6.000000000000001, 6.000000000000001, 0.0]
而带有sklearn的chi2
的是
[4. 2. 2. 2. 0.]
现在我进入源代码,它们计算卡方值的方式略有不同
sklearn 实现
您可以检查line 171 where chi2 class is defined,这是在传递给_chisquare
类之前在sklearn 中的实现。
scipy 实现 您可以查看scipy implementation here,它调用this function 最终计算卡方值。
从实现中可以看出,值的差异是由于它们在计算卡方值之前对观察值和预期值执行的转换。
参考资料:
chi square feature selection using scipy【讨论】:
【参考方案2】:是的,它们确实给出了不同的结果。而且我认为你应该相信 scipy 的结果,而拒绝 sklearn 的结果。
但让我详细说明我的推理,因为我可能是错的。
我最近观察到与您描述的类似的效果,数据集包含 300 个数据点:两个 chi2 实现的结果确实不同。就我而言,差异是惊人的。我详细描述了这个问题in this article,然后是这个Cross Validated discussion thread,我还向sklearn提交了一个错误请求,available for review here。
我的研究的附加价值(如果有的话)似乎是 scipy 实现提供的结果似乎正确,而 sklearn 的结果不正确。详情请参阅文章。但我只关注我的样本,所以结论可能并不普遍正确。遗憾的是,源代码分析超出了我的能力范围,但我希望此输入可以帮助某人改进代码,或者在错误的情况下反驳我的推理。
【讨论】:
以上是关于Scipy 和 Sklearn chi2 实现给出不同的结果的主要内容,如果未能解决你的问题,请参考以下文章
SelectKBest with chi2 给出 ValueError: could not convert string to float