华电北风吹
天津大学认知计算与应用重点实验室
最后修改日期:2015/8/22
在现实数据处理中很多时候往往都需要对得到的数据做特征选择,因为很多采集的样本特征是无效的,最明显的例子就是核磁数据,每一个核磁数据样本都是上万维的数据,降维大部分依赖于mask的获取。但是mask的获取需要先验知识来确定固定的脑区mask,但是如果没有先验知识的话我们就需要一个标准来将特征排序,供我们选择有用的特征。本文介绍F值在特征选择中的原理及应用。
首先,来说一说单因素方差分析。单因素方差分析的前提是不同条件下各个样本服从正态分布,每一个条件下的样本服从于这个类别的正态分布,并且相互独立。零假设是:所有条件下样本的均值相等;备择假设当然是均值不等了。然后怎么来判断是否要拒绝零假设(这里记得还有一个问题就是拒绝不代表接受,这个涉及到第一类错误和第二类错误问题,详细介绍参看方差分析相关博文),方差分析告诉我们F值是组间平方和的均值与组内平方和的均值的商,F值越大,代表组间差距越大,因此接受零假设的概率就越小。
其次,对于样本的每一个特征来说这些特征是来自于不同的类别,我的目标是得到有助于我进行分类的那些特征,为了区分出不同的类别,我要挑选的特征肯定是与类别相关的,而F值在方差分析中的原理告诉我们F值越大,组间差距就越大,而且对于采集到的样本来说他们的F分布的自由度是完全相同的,因此F值具有可比性,所以可以利用F值排序,F值大的先选择,一次往后,直到挑选够想要的特征个数。
接下来说说我对F值做特征选择的思考,有不对的地方,欢迎大家交流。F值仅仅是一种参考指标,因为方差分析里面F值有效需要满足正态分布的前提,而这里不管样本所属类别是否满足正态性。第一个函数计算F值调用了matlab做方差分析的内部函数,第二个是参考F值的计算公式。
函数一:
function [selected_indices, selected_feature_matrix] = FValueCalcuation(feature_matrix, labels, selected_feature_num) feature_number = size(feature_matrix, 2); f_values = zeros(feature_number, 1); for i = 1 : feature_number [p,table] = anova1(feature_matrix(:, i),labels, 'off'); %#ok<ASGLU> f_values(i, 1) = table{2, 5}; end index_f_value = [(1:feature_number)', f_values]; index_f_value = flipdim( sortrows(index_f_value, 2), 1 ); selected_indices = sort(index_f_value(1:selected_feature_num, 1)); selected_feature_matrix = feature_matrix(:, selected_indices); end
函数二:
function [result] = FScoreCalculate(Data,Label) % 自己写的 % F-Score, use the N var formulation,详细解释见数据分析 单因素方差分析F值计算公式 % Data, the data, each raw is an instance % Label, the label in 1 2 3 ... format,stand for the classtype classNum = max(Label); [~, featureNum] = size(Data); result.fisherscore = zeros(1,featureNum); % statistic for classes classSet = cell(classNum,1); classLength = zeros(classNum,1); for k = 1:classNum classSet{k} = find(Label(:)==k); classLength(k) = length(classSet{k}); end % calculate score for each features for i = 1:featureNum temp1 = 0; temp2 = 0; feature = Data(:,i); totalmean = mean(feature); for k = 1:classNum classmean = mean(feature(classSet{k})); classvar = var(feature(classSet{k}),1); temp1 = temp1+classLength(k)*(classmean-totalmean)^2; temp2 = temp2+(classLength(k)-1)*classvar; end if temp1 == 0 result.fisherscore(i) = 0; else if temp2 == 0 result.fisherscore(i) = 100; else result.fisherscore(i) = temp1/temp2; end end end [~, result.DescendList] = sort(result.fisherscore, 'descend');