数据预处理和特征工程 - 特征选择 - 相关性过滤 - 卡方过滤
方差挑选完毕之后,我们就要考虑下一个问题:相关性了。我们希望选出与标签相关且有意义的特征,因为这样的特征能够为我们提供大量信息。
分布可以用来检验模型的适合性,变量的独立性等,对象是类别变量。的检验公式是
其中,是 observation,观测数据,是 Expectation,期望数据
卡方分布的思想:我们先假设数据服从某一分布或者是某一模型,然后通过假设,计算出数据应该有的样子,再用现实中观察到的值与比较,即代入卡方检验公式。如果观测值与期望值相差值很大,就很大,我们就会拒绝假设对于列联表,假设数据服从的模型就是每一行列最后的统计量,每一格,然后计算其与的……
例:
假设这里有三个搜索引擎,我们假设:三个算法一样好(不同算法对搜索结果的好坏无影响、属性和组别无关),:三个算法不一样好一般思路我们是假设成立,对于取定的显著性水平,若计算出的H{0}H
{0}H_{1}对于本例,对于第一行第一列,有
也就是表中括号内的数字。由此,我们可以得到
得到后我们还需要知道对应分布的自由度
因为我们知道了 Total 行和 Total 列,因此,对于某一行假设有个元素,只要我们确定个元素,就能固定剩余一个元素的取值。对于列同理。因此自由度为
对于上例,有
自由度为 2 的卡方分布有 $\chi^{2}{0.050}=5.99147,\chi^{2}{0.010}=9.21034\alpha=0.055.99147<6.12H_{0}\alpha=0.01H_{0}H_{1}$
我们这里:属性和组别无关,不好理解,我们可以想:属性和组别相关,当属性与组别完全相关,显然,也就是越小,接受的可能性越大;对于来说,越小,对应的可能性越小,因此我们是要更大的,才能接受
卡方过滤是专门针对离散型标签(即分类问题)的相关性过滤。卡方检验类 feature_selection.chi2 计算每个非负特征和标签之间的卡方统计量,并依照卡方统计量由高到低为特征排名(卡方越大特征越好)。再结合 feature_selection.SelectKBest 这个可以输入”评分标准“来选出前 K 个分数最高的特征的类,我们可以借此除去最可能独立于标签,与我们分类目的无关的特征。
为什么卡方越大越好,这是因为卡方越大,根据上面的数学推理,我们可以认为标签和特征无关,就是二者之间独立的可能性越大。对于独立的标签和特征,如果我们知道了特征的取值,但由于二者独立,即其中一个的取值不影响另一个,因此该特征对于标签是哪个的贡献并不大,所以我们要求卡方越大越好
如果卡方检验检测到某个特征中所有的值都相同,会提示我们使用方差先进行方差过滤。
分数降低了,说明我们这里卡方过滤的效果并不好,不如没过滤,我们需要更换 k 值或者换方法
选取超参数 k
我们可以话学习曲线,但由于过于耗时间,所以实际应用不考虑
通过这条曲线,我们可以观察到,随着 k 值的不断增加,模型的表现不断上升,这说明,k 越大越好,数据中所有的特征都是与标签相关的。
实际上,我们是通过指定 p 来选择 k,一般指定 p=0.05 或 0.01,要求特征对于标签的 p 值≤0.05 或 0.01
所谓差异不是自然形成的,可以这样理解,假设标签可能取值为 0,1,特征可能取值为 2,3,当特征取 2 的时候,标签取 0 的可能性大于取 1 的时候的可能性
从特征工程的角度,我们希望选择卡饭值很大,p 值小于 0.05 的特征,即和标签是相关的特征。实际上我们调用 SelectKBest 之前,我们可以直接从 chi2 实例化后的模型中获得各个特征所对应的卡方值和 P 值,由此来过滤 p 值>0.05 的特征
可以观察到,所有特征的 p 值都是≤0.05,这说明对于 digit recognizor 这个数据集来说,方差验证已经把所有和标签无关的特征都剔除了,或者这个数据集本身就不含与标签无关的特征。在这种情况下,舍弃任何一个特征,都会舍弃对模型有用的信息,而使模型表现下降,因此在这种情况下,在我们对计算速度感到满意时,我们不需要使用相关性过滤来过滤我们的数据。如果我们认为运算速度太缓慢,那我们可以酌情删除一些特征,但前提是,我们必须牺牲模型的表现。
卡方验证的 python 实现(其实我觉得还挺有用的)
from sklearn.preprocessing import LabelBinarizer from scipy.special import chdtrc import numpy as np import pandas as pd X = np.array([3.4, 3.4, 3. , 2.8, 2.7, 2.9, 3.3, 3. , 3.8, 2.5]) y = np.array([0, 0, 0, 1, 1, 1, 2, 2, 2, 2]) y = LabelBinarizer().fit_transform(y) observed = y.T.dot(X) observed # 不同y的观测值 --- array([ 9.8, 8.4, 12.6]) feature_count = X.sum().reshape(-1,1) feature_count # X求和,用于算预测值 --- array([[30.8]]) class_prob = y.mean(axis=0).reshape(1,-1) class_prob # 不同y出现的次数来估计概率 --- array([[0.3, 0.3, 0.4]]) expected = np.dot(class_prob.T, feature_count) expected # 不同y的期望值 --- array([[ 9.24], [ 9.24], [12.32]]) chi2 = ((observed.reshape(-1,1) - expected) ** 2 / expected).sum(axis=0) # 卡方公式 chi2 --- array([0.11666667]) p = chdtrc(3-1,chi2) # 用自由度和卡方值来算p值 p --- array([0.94333545]) from sklearn.feature_selection import SelectKBest from sklearn.feature_selection import chi2 X = np.array([[3.4, 3.4, 3. , 2.8, 2.7, 2.9, 3.3, 3. , 3.8, 2.5],[0, 0, 9, 0, 0, 0, 0, 0, 0, 0]]) # 添加[0, 0, 9, 0, 0, 0, 0, 0, 0, 0],为了更好的理解什么叫标签与特征相关,也就是说,如果我们给定x=0,那么我们就能有很大概率y=0 y = np.array([0, 0, 0, 1, 1, 1, 2, 2, 2, 2]) chivalue, pvalues_chi = chi2(X.T,y) chivalue, pvalues_chi --- (array([ 0.11666667, 21. ]), array([9.43335450e-01, 2.75364493e-05])) X = SelectKBest(chi2,k=1).fit_transform(X.T,y) X --- array([[0.], [0.], [9.], [0.], [0.], [0.], [0.], [0.], [0.], [0.]])
作者:hellpanderr 链接:用户对问题“SelectKBest (chi2)如何计算分数?”的回答 - 问答 - 腾讯云开发者社区-腾讯云 (tencent.com)
视频作者:菜菜TsaiTsai链接:【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili
版权声明: 本文为 InfoQ 作者【烧灯续昼2002】的原创文章。
原文链接:【http://xie.infoq.cn/article/4016f720d1acf9558d7e32ca8】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论