一、公式
卡方检验的基本公式,也就是χ2的计算公式,即观察值和理论值之间的偏差
其中:A 为观察值,E为理论值,k为观察值的个数,最后一个式子实际上就是具体计算的方法了 n 为总的频数,p为理论频率,那么n*p自然就是理论频数(理论值)
二、相关概念
卡方分布:可以看出当观察值和理论值十分接近的时候,也就是我们做的假设是正确的时候,χ2的值就越趋近于0,也就是说我们计算的偏差越小,那么假设值就越可能是对的,反之偏差值越大,假设值就越不准确。那么到底多大才算不准确,有没有个衡量的数值标准呢?答案是有:卡方分布。
卡方检验是以χ2分布为基础的一种常用假设检验方法。若k 个随机变量Z1、……、Zk 相互独立,且数学期望为0、方差为 1(即服从标准正态分布),则随机变量X被称为服从自由度为 k 的卡方分布,记作
,卡方分布的公式为:
自由度:自由度指的是计算某一统计量时,取值不受限制的变量个数。通常df=n-k。其中n为样本数量,k为被限制的条件数或变量个数。自由度v=(行数-1)(列数-1)。
自由度与卡方分布的关系:
如图
图中的Freedom 这里有5条线,分别对应Freedom=1, 4, 10, 20 , 100 。这个Freedom 就是自由度,即个式子中独立变量的个数。 x 横坐标是卡方检验公式计算出来的偏差χ2,而 y 纵坐标表示假设的正确的概率。当自由度为1时,卡方分布式一个倾斜的曲线,当自由度逐渐增大是,卡方分布逐步变的平缓。在一定范围内,随着自由度越来越大,卡方分布会越来越接近正态分布。
三、利用卡方检验用来特征选择
特征选择(Feature Selection):指的是在特征向量中选择出那些“优秀”的特征,组成新的、更“精简”的特征向量的过程。它在高维数据分析中十分常用,可以剔除掉“冗余”和“无关”的特征,提升学习器的性能。
特征选择方法和分类方法一样,也主要分为有监督(Supervised)和无监督(Unsupervised)两种,卡方选择则是统计学上常用的一种有监督特征选择方法,它通过对特征和真实标签之间进行卡方检验,来判断该特征和真实标签的关联程度,进而确定是否对其进行选择。
对于建立模型而言并非特征越多越好,因为建模的目标是使用尽量简单的模型去实现尽量好的效果。减少一些价值小贡献小的特征有利于在表现效果不变或降低度很小的前提下,新找到最简单的模型。
那么什么样的特征是价值小的呢?想想我们之所以用机器学习的模型去学习特征,是为了更好地预测被特征影响着的应变量(标签)。那么那些根本不会对应变量产生影响,或者影响很小的特征理应事先去掉。
那么怎么判断特征对应变量的影响程度的大小呢?我们可以使用卡方检验对特征与应变量进行独立性检验,如果独立性高,那么表示两者没太大关系,特征可以舍弃;如果独立性小,两者相关性高,则说明该特征会对应变量产生比较大的影响,应当选择。
卡方检验在实际应用到特征选择中的时候,不需要知道自由度,也不用知道卡方分布,只需要根据算出来的χ2 进行排序即可,值越大越好。挑选最大的一堆,就完成了利用卡方检验来进行特征提取。
四、代码实现
和ML库中的大多数学习方法一样,ML中的卡方选择也是以estimator+transformer的形式出现的,其主要由ChiSqSelector和ChiSqSelectorModel两个类来实现。
1、首先引入相关需要用的包
import java.util.Arrays;
import java.util.List;
import org.apache.spark.ml.feature.ChiSqSelector;
import org.apache.spark.ml.feature.ChiSqSelectorModel;
import org.apache.spark.ml.linalg.VectorUDT;
import org.apache.spark.ml.linalg.Vectors;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.RowFactory;
import org.apache.spark.sql.SparkSession;
import org.apache.spark.sql.types.DataTypes;
import org.apache.spark.sql.types.Metadata;
import org.apache.spark.sql.types.StructField;
import org.apache.spark.sql.types.StructType;
2、接下来获取spark
SparkSession spark = SparkSession.builder().appName("ChiSqSelectorTest").master("local").getOrCreate();
3、然后,我们构造一个数据集DataFrame:
List<Row> rawData = Arrays.asList(RowFactory.create(1, Vectors.dense(0.0, 0.0, 18.0, 1.0), 1),
RowFactory.create(2, Vectors.dense(0.0, 1.0, 12.0, 0.0), 0),
RowFactory.create(3, Vectors.dense(1.0, 0.0, 15.0, 0.1), 0));
StructType schema = new StructType(new StructField[] {
new StructField("id",DataTypes.IntegerType,false,Metadata.empty()),
new StructField("features",new VectorUDT(),false,Metadata.empty()),
new StructField("label",DataTypes.IntegerType,false,Metadata.empty())
});
Dataset<Row> df = spark.createDataFrame(rawData,schema);
df.show(false);
打印结果:
+---+------------------+-----+
|id |features |label|
+---+------------------+-----+
|1 |[0.0,0.0,18.0,1.0]|1 |
|2 |[0.0,1.0,12.0,0.0]|0 |
|3 |[1.0,0.0,15.0,0.1]|0 |
+---+------------------+-----+
4、接着我们开始用卡方选择进行特征选择器的训练
ChiSqSelector select = new ChiSqSelector().setNumTopFeatures(1)
.setFeaturesCol("features")
.setLabelCol("label")
.setOutputCol("selected-feature");
ChiSqSelectorModel selectModel = select.fit(df);
Dataset<Row> result = selectModel.transform(df);
result.show(false);
numTopFeatures:用来设置固定的提取特征的数量,程序会根据卡方值的高低返回前n个卡方值最高的特征。(预测能力最强的前n个特征),默认选择前50个特征。这里,我们设置ChiSqSelector(卡方选择器)的numTopFeatures = 1,即在4个特征中选择处最好的1个特征。
打印结果:
+---+------------------+-----+----------------+
|id |features |label|selected-feature|
+---+------------------+-----+----------------+
|1 |[0.0,0.0,18.0,1.0]|1 |[18.0] |
|2 |[0.0,1.0,12.0,0.0]|0 |[12.0] |
|3 |[1.0,0.0,15.0,0.1]|0 |[15.0] |
+---+------------------+-----+----------------+
用训练出的模型对原数据集进行处理,可以看见,第三列特征被选出作为最有用的特征列。
本文来自博客园,作者:大码王,转载请注明原文链接:https://www.cnblogs.com/huanghanyu/