特征相关性分析

一、特征选择

特征选择是特征工程里的一个重要问题,其目标是寻找最优特征子集。特征选择能剔除不相关(irrelevant)或冗余(redundant )的特征,从而达到减少特征个数,提高模型精确度,减少运行时间的目的。另一方面,选取出真正相关的特征简化模型,协助理解数据产生的过程。并且常能听到“数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已”,由此可见其重要性,但是它几乎很少出现于机器学习书本里面的某一章,然而在机器学习方面的成功很大程度上在于如果使用特征工程。

二、做特征选择的原因

考虑特征选择,是因为机器学习经常面临过拟合的问题。 过拟合的表现是模型参数太贴合训练集数据,模型在训练集上效果很好而在测试集上表现不好,也就是在高方差。简言之模型的泛化能力差。

即使用原始数据集的话:

  • 耗时:特征个数越多,分析特征、训练模型所需的时间就越长。
  • 过拟合:特征个数越多,容易引起“维度灾难”,模型也会越复杂,其推广能力会下降。
  • 共线性:单因子对目标的作用被稀释,解释力下降

三、特征选择的一般过程

  • 生成子集:搜索特征子集,为评价函数提供特征子集;
  • 评价函数:评价特征子集的好坏;
  • 停止准则:与评价函数相关,一般是阈值,评价函数达到一定标准后就可停止搜索;
  • 验证过程:在验证数据集上验证选出来的特征子集的有效性;

四、如何做特征相关性分析

(一)绘图判断

一般对于强相关性的两个变量,画图就能定性判断是否相关。

# 散点图矩阵初判多变量间关系
data = pd.DataFrame(np.random.randn(200,4)*100, columns = ['A','B','C','D'])
pd.plotting.scatter_matrix(data,figsize=(8,8),
                         c = 'k',
                         marker = '+',
                         diagonal='hist',
                         alpha = 0.8,
                         range_padding=0.1)
data.head()

(二)方差单特征选择

不需要度量特征 x_i 和类别标签 y 的信息量。这种方法(ANOVA)先要计算各个特征的方差,然后根据阈值,选择方差大于阈值的特征。

方差选择法用于特征选择的本质:

  • 移除低方差特征 : 是指移除那些方差低于某个阈值,即特征值变动幅度小于某个范围的特征,这一部分特征的区分度较差,我们进行移除
  • 考虑有值数据中的占比,异常数据的占比,正常范围数据过少的数据也可以移除。

假设我们有一个特征是由0和1组成的数据集,利用Removing features with low variance方法移除那些在整个数据集中特征值为0或者为1的比例超过p(同一类样本所占的比例)的特征。0 1 组成的数据集满足伯努利( Bernoulli )分布,因此其特征变量的方差为:p(1-p)。
在Removing features with low variance方法中,将剔除方差低于p(1-p)的特征。在Pyhon的sklearn模块中,具有该方法的实现,具体使用如下:

删除方差为0的特征

# 计算变量的方差
# 如果方差接近于0,也就是该特征的特征值之间基本上没有差异,这个特征对于样本的区分并没有什么用,剔除
from sklearn.feature_selection import VarianceThreshold
selector = VarianceThreshold(threshold=0.1)#默认threshold=0.0
selector.fit_transform(offline_data_shuffle1[numerical_features])

# 查看各个特征的方差,
selector.variances_ ,len(selector.variances_)

# 特征对应方差
all_used_features_dict = dict(zip(numerical_features,selector.variances_ ))
all_used_features_dict

(三)数值特征与数值特征

   1.协方差

  • 如果协方差为正,说明X,Y同向变化,协方差越大说明同向程度越高;
  • 如果协方差维负,说明X,Y反向运动,协方差越小说明反向程度越高;
  • 如果两个变量相互独立,那么协方差就是0,说明两个变量不相关。

    2.★pearson系数

  • 相关系数也可以看成协方差:一种剔除了两个变量量纲影响、标准化后的特殊协方差

    

  • 可以反映两个变量变化时是同向还是反向,如果同向变化就为正,反向变化就为负。由于它是标准化后的协方差,因此更重要的特性来了,它消除了两个变量变化幅度的影响,而只是单纯反应两个变量每单位变化时的相似程度。
  • 相关系数分类:
    • 0.8-1.0 极强相关;0.6-0.8 强相关;0.4-0.6 中等程度相关;0.2-0.4 弱相关;0.0-0.2 极弱相关或无相关
  • 假设: 对于Pearson r相关性,两个变量都应该是正态分布的(正态分布变量具有钟形曲线)。其他假设包括线性和同态性。线性度假设分析中每个变量之间存在直线关系,同质性假定数据在回归线上正态分布。
皮尔逊系数/斯皮尔曼系数:衡量2个变量之间的线性相关性。
.00-.19 “very weak”
.20-.39 “weak”
.40-.59 “moderate”
.60-.79 “strong”
.80-1.0 “very strong”
  • 如果>0.8,说明2个变量有明显线性关系,只保留一个,保留与label的皮尔逊系数较大的那个变量或者保留lightgbm AUC最大的那个;

优点:可以通过数字对变量的关系进行度量,并且带有方向性,1表示正相关,-1表示负相关,可以对变量关系的强弱进行度量,越靠近0相关性越弱。

缺点:无法利用这种关系对数据进行预测,简单的说就是没有对变量间的关系进行提炼和固化,形成模型。要利用变量间的关系进行预测,需要使用到下一种相关分析方法,回归分析。

使用场景:当两个变量的标准差都不为零时,相关系数才有定义,皮尔逊相关系数适用于:

  • 两个变量之间是线性关系,都是连续数据。
  • 两个变量的总体是正态分布,或接近正态的单峰分布。
  • 两个变量的观测值是成对的,每对观测值之间相互独立。

举例1:

# 方法1,numpy.corrcoef,求多个数组的相关系数
import numpy as np
np.corrcoef([a,b,c,d])
 
# 方法2.计算特征间的pearson相关系数,画heatmap图
plt.figure(figsize = (25,25))
corr_values1 = data[all_used_features].corr() # pandas直接调用corr就能计算特征之间的相关系数
sns.heatmap(corr_values1, annot=True,vmax=1, square=True, cmap="Blues",fmt='.2f')
plt.tight_layout()
# plt.savefig('prepare_data/columns37.png',dpi=600)
plt.show()
 
# 方法3.Scipy的pearsonr方法能够同时计算相关系数和p-value
import numpy as np
from scipy.stats import pearsonr
 
np.random.seed(0)
size = 300
x = np.random.normal(0, 1, size)
print("Lower noise", pearsonr(x, x + np.random.normal(0, 1, size)))
print("Higher noise", pearsonr(x, x + np.random.normal(0, 10, size)))

举例2:计算各特征与label的相关系数,并画出直方图

x_cols = [col for col in train_csv.columns if col not in ['信用分'] if train_csv[col].dtype!='object']#处理目标的其他所有特征
labels = []
values = []
for col in x_cols:
    labels.append(col)
    values.append(np.corrcoef(train_csv[col].values, train_csv.信用分,values)[0, 1])
 
corr_df = pd.DataFrame({'col_labels':labels, 'corr_values':values})
corr_df = corr_df.sort_values(by = 'corr_values')
 
ind = np.arange(len(labels))
width = 0.5
fig,ax = plt.subplots(figsize = (12,40))
rects = ax.barh(ind, np.array(corr_df.corr_values.values), color='y')
 
ax.set_yticks(ind)
ax.set_yticklabels(corr_df.col_labels.values, rotation='horizontal')
ax.set_xlabel('Correlation coefficient')
ax.set_title('Correlation coefficient of the variables')

这里一般会不要太强的特征(>0.95),太弱的特征(<0.05)可以要 也可以不要。可能存在非线性关系

3.★距离相关系数

好的特征子集应该使得属于同一类的样本距离尽可能小,属于不同类的样本之间的距离尽可能远。同样基于此种思想的有fisher判别分类方法。常用的距离度量(相似性度量)包括欧氏距离、标准化欧氏距离、马氏距离等。

距离相关系数是为了克服Pearson相关系数的弱点而生的。在 x 和 x^2 这个例子中,即便Pearson相关系数是 0 ,我们也不能断定这两个变量是独立的(有可能是非线性相关);但如果距离相关系数是 0 ,那么我们就可以说这两个变量是独立的。

距离相关系数:研究两个变量之间的独立性,距离相关系数为0表示两个变量是独立的。克服了皮尔逊相关系数(Pearson)的弱点。pearson相关系数为0并不一定表示两个变量之间是独立的,也有可能是非线性相关的。  
                   在这里插入图片描述

距离相关系数是为了克服Pearson相关系数的弱点而生的。在 和 x^2 这个例子中,即便Pearson相关系数是 0,我们也不能断定这两个变量是独立的(有可能是非线性相关);但如果距离相关系数是 0,那么我们就可以说这两个变量是独立的。

尽管有MIC和距离相关系数在了,但当变量之间的关系接近线性相关的时候,Pearson相关系数仍然是不可替代的。第一、Pearson相关系数计算速度快,这在处理大规模数据的时候很重要。第二、Pearson相关系数的取值区间是[-1,1],而MIC和距离相关系数都是[0,1]。这个特点使得Pearson相关系数能够表征更丰富的关系,符号表示关系的正负,绝对值能够表示强度。当然,Pearson相关性有效的前提是两个变量的变化关系是单调的。

距离相关系数的计算依赖于距离协方差和距离方差,首先我们先了解下距离协方差的定义,假设有n维(X,Y)统计样本。

1. 首先计算包含的所有成对距离(即:数组间每行数据之间的范数距离)

                                       在这里插入图片描述
为了防止我没有描述清楚,直接上代码:

#生成一个3行2列的数组
X = np.random.randint(-100,100,(3,2))0.1
out:
array([[ 4.8, 7.7],
[-2.6, 6.8],
[ 5.9, 9. ]])
Y = X**2
#取数据集的行
col = X.shape[0]
#做成nn的零矩阵,用于盛放数据
a = np.zeros((col,col))
b = np.zeros((col,col))
A = np.zeros((col,col))
B = np.zeros((col,col))
#计算数组间每行数据之间的范数距离
for j in range(col):
    for k in range(col):
        a[j,k] = np.linalg.norm(X[j]-X[k])
        b[j,k] = np.linalg.norm(Y[j]-Y[k])
部分打印信息:
调试: X数据集索引为0的数据与索引为0的数据的范数距离为0
计算a列之间的距离: 0.0
计算b列之间的距离: 0.0
调试: X数据集索引为0的数据与索引为1的数据的范数距离为.
计算a列之间的距离: 8.174350127074325
计算b列之间的距离: 25.112168365157167
调试: X数据集索引为0的数据与索引为2的数据的范数距离为.
计算a列之间的距离: 8.229823813423955
计算b列之间的距离: 71.77571803890227

这里的a和b最后生成的都是对称矩阵。

2. 然后对所有的成对距离进行中心化处理
在这里插入图片描述其中aj. 是第j行平均值,ak.是第k列平均值,a…是X样本的距离矩阵的平均值

for m in range(col):
    for n in range(col):
        #计算a,b中心化的值,并赋值给A,B
        A[m,n] = a[m,n] - a[m].mean()-a[:,n].mean()+a.mean()
        B[m,n] = b[m,n] - a[m].mean()-b[:,n].mean()+b.mean()

3. 计算样本距离的平方协方差(标量)的算数平均:

                                  在这里插入图片描述

cov_xy=np.sqrt((1/(col**2))((AB).sum()))

4. 计算样本距离方差

在这里插入图片描述

cov_xx=np.sqrt((1/(col2))((AA).sum()))
cov_yy=np.sqrt((1/(col2))((BB).sum()))

5. 将两个随机变量的距离协方差除以它们的距离标准差的乘积,得到它们的距离相关性,即:
在这里插入图片描述

dcor = cov_xy/np.sqrt(cov_xx*cov_yy)

#写成函数形式如下:

import numpy as np
import pandas as pd
def dist_corr(x,y):#如果x,y是二维数组,应通过行矢量形成距离矩阵
    #获取数据集的行
    col=x.shape[0]
    #生成a、b、A、B三个colcol的0矩阵
    a=np.zeros((col,col))
    b=np.zeros((col,col))
    A=np.zeros((col,col))
    B=np.zeros((col,col))
    #通过双层循环计算出列之间的范数距离
    for j in range(col):
        for k in range(col):
            #求范数
            a[j,k]=linalg.norm(x[j]-x[k])
            b[j,k]=linalg.norm(y[j]-y[k])
            #print(a,b)
    #通过循环对其进行中心化处理
    for m in range(col):
        for n in range(col):
            A[m,n]=a[m,n]-a[m].mean()-a[:,n].mean()+a.mean()
            B[m,n]=b[m,n]-b[m].mean()-b[:,n].mean()+b.mean()
    #求协方差
    cov_xy=np.sqrt((1/(col**2))((AB).sum()))
    cov_xx=np.sqrt((1/(col**2))((AA).sum()))
    cov_yy=np.sqrt((1/(col**2))((BB).sum()))
return cov_xy/np.sqrt(cov_xxcov_yy)

4.斯皮尔曼等级相关系数

Spearman秩相关系数:是度量两个变量之间的统计相关性的指标,用来评估当前单调函数来描述俩个变量之间的关系有多好。 
在没有重复数据的情况下,如果一个变量是另一个变量的严格单调函数,二者之间的spearman秩相关系数就是1或+1 ,称为完全soearman相关. 
如果其中一个变量增大时,另一个变量也跟着增大时,则spearman秩相关系数时正的 
如果其中一个变量增大时,另一个变量却跟着减少时,则spearman秩相关系数时负的 
如果其中一个变量变化时,另一个变量没有变化,spearman秩相关系为0 
随着两个变量越来越接近严格单调函数时,spearman秩相关系数在数值上越来越大。

假设:
Spearman等级相关性测试对于分布没有做任何假设。Spearman rho相关的假设是数据必须至少是序数,一个变量上的分数必须与其他变量单调相关。

.10和.29之间表示小关联; 
.30和.49之间;
.50及以上的系数表示大的关联或关系

有序量表对待测量的项目进行排序,以指示它们是否具有更多,更少或相同量的被测量变量。序数量表使我们能够确定X> Y,Y> X,或者如果X = Y。一个例子是排序舞蹈比赛的参与者。排名第一的舞者是比排名第二的舞者更好的舞者。排名第二的舞者是比排名第三的舞者更好的舞者,等等。虽然这个规模使我们能够确定大于,小于或等于,但它仍然没有定义单位之间关系的大小。

5.去掉不相关的列

# 去掉日期列
def drop_date(data):
    columns = list(data.columns)
    not_date_columns = []
    for column in columns: 
        tmp_num = data[column].max()
        if str(tmp_num).find('2017') == -1 and str(tmp_num).find('2016') == -1:
            not_date_columns.append(column)
 
    return data[not_date_columns]
 
# 去掉object、int类型的列
def drop_non_number(data):
    data_types = data.dtypes.reset_index()
    data_types.columns = ['col','dtype']
    data_object = data_types[data_types.dtype=='object'].col.values
    data_object = data[data_object]
    data_object.to_csv('non_number.csv',index=False)
    col_val = data_types[data_types.dtype == 'float64'].col.values
    return data[col_val]

6.★互信息

7.★F检验

(四)数值特征与类别特征

1.卡方检验(类别对类别)

思想:

  • 先假设两个变量确实是独立的(“原假设”),然后观察实际值(观察值)与理论值(这个理论值是指“如果两者确实独立”的情况下应该有的值)的偏差程度,如果偏差足够小,我们就认为误差是很自然的样本误差,是测量手段不够精确导致或者偶然发生的,两者确确实实是独立的,此时就接受原假设;如果偏差大到一定程度,使得这样的误差不太可能是偶然产生或者测量不精确所致,我们就认为两者实际上是相关的,即否定原假设,而接受备择假设.                                                                                                    
  • 这个式子就是卡方检验使用的差值衡量公式。当提供了数个样本的观察值x1,x2,…xi,…xn之后,代入到式中就可以求得开方值,用这个值与事先设定的阈值比较,如果大于阈值(即偏差很大),就认为原假设不成立,反之则认为原假设成立。

使用方法:

  • 特征为连续型,可将其分箱,变成有序的类别型特征,然后和label计算卡方值;如果特征为类别型,不需要one-hot
  • 步骤:
    • 步骤1:做出H0,H1这对互斥的假设,计算出H0为真时的期望值,统计出实际的观测值,通过期望值和观测值求得chi-square(卡方),再通过卡方查表(知道自由度和alpha),得到p值。
    • 步骤2:根据p值与α(1-置信度)的比较,如果p-value<α,则拒绝(reject)H0,推出H1成立;如果p-value>α,则接受(accpet)H0,推出H1不成立
  • p值?为什么小于0.05就很重要?p值的作用?
    • p值可通过计算chi-square后查询卡方分布表得出,用于判断H0假设是否成立的依据。
    • 大部分时候,我们假设错误拒绝H0的概率为0.05,所以如果p值小于0.05,说明错误拒绝H0的概率很低,则我们有理由相信H0本身就是错误的,而非检验错误导致。大部分时候p-value用于检验独立变量与输入变量的关系,H0假设通常为假设两者没有关系,所以若p值小于0.05,则可以推翻H0(两者没有关系),推出H1(两者有关系)。
    • 当p值小于0.05时,我们就说这个独立变量重要(significant),因为这个独立变量与输出结果有关系。
    • p-value就是用来判断H0假设是否成立的依据。因为期望值是基于H0假设得出的,如果观测值与期望值越一致,则说明检验现象与零假设越接近,则越没有理由拒绝零假设。如果观测值与期望值越偏离,说明零假设越站不住脚,则越有理由拒绝零假设,从而推出对立假设的成立。
  • sklearn使用方法
  • sklearn源码
sklearn.feature_selection.chi2(X, y) 
参数: 
X:{array-like,sparse matrix}  shape = (n_samples,n_features) 
y:{array-like} shape=(n_samples,) 
返回: 
chi2:array,shape=(n_features,) 每个特征的卡方统计数据 
pval:array,shape=(n_features,) 每个特征的p值 
 
算法时间复杂度O(n_classes * n_features) 

举例:

non_neg_cate_feats = ['cardIndex', 'downNetwork','signalStrengthNum','signalQualityNum','mostGridLTE','mostGridLTEPlus',
  'signalPerformanceADDNum','signalPerformanceDIVNum','signalPerformanceMULNum']
 
 
# 卡方检验 用来检验两个样本or变量是否独立
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
 
X, y = offline_data_shuffle[non_neg_cate_feats], offline_data_shuffle.label
select_k_best = SelectKBest(chi2, k=6) # scores按升序排序,选择排前k名所对应的特征
X_new = select_k_best.fit_transform(X, y)
X_new.shape
 
p_scores = zip(select_k_best.scores_,select_k_best.pvalues_)
dict_p_scores = dict(zip(non_neg_cate_feats,p_scores))
 
>>>sorted(dict_p_scores.items(),key=lambda x:x[1],reverse=False)
[('signalQualityNum', (0.0047487364247874265, 0.9450604019371723)),
 ('cardIndex', (0.42794079034586147, 0.5130011047102445)),
 ('downNetwork', (4.232840836040372, 0.039649024714896966)),
 ('mostGridLTEPlus', (22.54372206267445, 2.0541471820820565e-06)),
 ('signalPerformanceADDNum', (83.2781756776784, 7.128224882894165e-20)),
 ('mostGridLTE', (108.06852404196152, 2.596443689456046e-25)),
 ('signalPerformanceDIVNum', (114.25902772721962, 1.1435127027103025e-26)),
 ('signalPerformanceMULNum', (118.46298229427805, 1.3729262834830412e-27)),
 ('signalStrengthNum', (176.53365084245885, 2.768884720816111e-40))]
 
results_indexs = select_k_best.get_support(True)
results = [non_neg_cate_feats[idx] for idx in results_indexs] # 卡方检验选出的6个特征
>>>print(results)
['signalStrengthNum', 'mostGridLTE', 'mostGridLTEPlus', 'signalPerformanceADDNum', 'signalPerformanceDIVNum', 'signalPerformanceMULNum']
 
卡方检验的结果显示:
p值小于0.05,说明拒绝原假设(原假设特征与label是独立的)
signalQualityNum、cardIndex与label是独立的;
['signalStrengthNum', 'mostGridLTE', 'mostGridLTEPlus', 'signalPerformanceADDNum', 'signalPerformanceDIVNum', 'signalPerformanceMULNum']与label相关

2.Fisher得分

Fisher Score为过滤式的特征选择算法,是一种衡量特征在两类之间分辨能力的方法。Fisher Score是特征选择的有效方法之一, 其主要思想是鉴别性能较强的特征表现为类内距离尽可能小, 类间距离尽可能大。公式:

      
其中i代表第i个特征,即每一个特征都会有一个F-score。没有 + 和 - 的 x平均值 是所有该特征值的平均数,而(+),(-)则分别代表所有阳性样本和阴性样本的特征值(的平均数)。代表k是对于具体第i个特征的每个实例,分母的两个sigma可以理解为阳性样本与阴性样本的特征值的方差。F-score越大说明该特征的辨别能力越强。

Fisher得分的改进版:

                                          

代码实现1:https://github.com/jundongl/scikit-feature/。

对于分类而言,好的特征应该是在同一个类别中的取值比较相似,而在不同类别之间的取值差异比较大;fisher得分越高,特征在不同类别中的差异性越大,在同一类别中的差异性越小,则特征越重要。这个又叫做LDA(线性判别分析)。其中矩阵原理参考:判别函数(三)之Fisher线性判别_fisher函数-CSDN博客

作用:通过线性判别分析压缩无监督数据,参考该博客 机器学习笔记之(4)——Fisher分类器(线性判别分析,LDA)-CSDN博客

LDA是一种可作为特征抽取的技术,它可以提高数据分析过程中的计算效率,同时,对于不适用于正则化的模型,它可以降低因维度灾难带来的过拟合。LDA的基本概念与PCA非常相似。PCA试图在数据集中找到方差最大的正交的主成分分量的轴,而LDA的目标是发现可以最优化分类的特征子空间。其中,PCA是无监督算法,而LDA是监督算法,因此,直观上,LDA比PCA更优越。如下图所示:

如图所示,在x轴方向(LD1),通过线性判定,可以很好地将呈正态分布的两个类分开。虽然沿y轴(LD2)方向的线性判定保持了数据集较大方差,但是沿此方向无法提供关于类别区分的任何信息,因此它不是一个好的线性判定。一个关于LDA的假设是:数据呈正态分布。此外,还假设各类别中数据具有相同的协方差矩阵,且样本的特征从统计上来讲是相互独立的。不过即使一个或多个假设没有满足,LDA仍旧可以很好的完成降维工作。

给出LDA数据降维和逻辑回归分类的Python代码如下:

#####################################定义一个画图函数###########################
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
 
def plot_decision_regions(X, y, classifier, resolution=0.02):
 
    # setup marker generator and color map
    markers = ('s', 'x', 'o', '^', 'v')
    colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
    cmap = ListedColormap(colors[:len(np.unique(y))])
 
    # plot the decision surface
    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
                           np.arange(x2_min, x2_max, resolution))
    Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
    Z = Z.reshape(xx1.shape)
    plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap)
    plt.xlim(xx1.min(), xx1.max())
    plt.ylim(xx2.min(), xx2.max())
 
    # plot class samples
    for idx, cl in enumerate(np.unique(y)):
        plt.scatter(x=X[y == cl, 0], 
                    y=X[y == cl, 1],
                    alpha=0.6, 
                    c=cmap(idx),
                    edgecolor='black',
                    marker=markers[idx], 
                    label=cl)
 
 
##############################数据的读入、划分、标准化###########################
import pandas as pd
#Python Data Analysis Library 或 pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。
#Pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具。
df_wine = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data',header=None)
#读入csv文件,形成一个数据框
#使用葡萄酒数据集
 
 
from sklearn.cross_validation import train_test_split
x, y = df_wine.iloc[:, 1:].values, df_wine.iloc[:, 0].values
x_train, x_test, y_train, y_test =train_test_split(x, y, test_size=0.3,stratify=y,random_state=0)
#葡萄酒数据集划分为训练集和测试集,分别占据数据集的70%和30%
 
#使用单位方差对数据集进行标准化
from sklearn.preprocessing import StandardScaler
sc=StandardScaler()
#注意,当改为from sklearn.preprocessing import StandardScaler as sc时,会报错
# fit_transform() missing 1 required positional argument: 'X'。这就是由于sc没有StandardScaler()而仅仅是StandardScaler
x_train_std=sc.fit_transform(x_train)
x_test_std=sc.fit_transform(x_test)
 
 
#####################################使用sklearn中的LDA类#######################
from sklearn.linear_model import LogisticRegression
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
lda = LDA(n_components=2)#选取两个主成分
#做降维处理
x_train_lda = lda.fit_transform(x_train_std, y_train)
x_test_lda=lda.transform(x_test_std)
 
#用逻辑回归进行分类(对训练数据进行处理)
lr=LogisticRegression()
lr.fit(x_train_lda,y_train)
plot_decision_regions(x_train_lda,y_train,classifier=lr)
plt.xlabel('LD 1')
plt.ylabel('LD 2')
plt.legend(loc='lower left')
plt.tight_layout()
plt.show()
 
#用逻辑回归进行分类(对测试数据进行处理)
lr=LogisticRegression()
lr.fit(x_train_lda,y_train)
plot_decision_regions(x_test_lda,y_test,classifier=lr)
plt.xlabel('LD 1')
plt.ylabel('LD 2')
plt.legend(loc='lower left')
plt.tight_layout()
plt.show()

结果如图所示:

3.★F检验(ANOVA)

作用: 用来判断特征与label的相关性的,F检验只能表示线性相关关系 这里推荐学习博客 特征选择-相关系数法F检验_相关系数用f检验-CSDN博客

p值含义:p值的计算是与假设检验有着密不可分的关系,p值为结果可信水平的一个递减指标,p值越大,我们越不能以为样本中变量的关联是总体中各变量关联的可靠指标。p值是将察看结果觉得有效即具有总体代表性的犯错概率。如p=0.05提醒样本中变量关联有5%的可能是由于偶然性造成的。即假设总体中任意变量间均无关联,我们反复相似试验,会发现约20个试验中有一个试验,我们所研讨的变量关联将等于或强于我们的实验结果。(这并不是说如果变量间存在关联,我们可得到5%或95%次数的雷同结果,当总体中的变量存在关联,反复钻研和发明关联的可能性与设计的统计学效率有关。)在许多钻研范畴,0.05的p值通常被以为是可接收过错的边界程度。
有3种常用的统计检验:

sklearn.feature_selection 提供了3个接口:

  • SelectKBest : 筛选k个相关性最高的特征,最常用。
  • SelectPercentile : 筛选得分排名前k分位数的特征,即保留最高得分的百分比特征。
  • GenericUnivariateSelect: 根据用户自定义评分函数进行筛选。

有3种常用的统计检验:

f_classif:方差分析(ANOVA),适用于分类问题,特征是数值变量,目标是分类变量。
chi2:差方分析,适用于分类问题,要求特征是计数或二元变量(正值)
f_regression:适用于回归问题,特征和目标变量均为数值变量。

所有检验都返回一个分值和p-value,分值和p-value越高表示特征与目标变量的关联程度越高。

sklearn中的两个选择数据函数的实现和参数解析:

* SelectKBest(score_func,k=)。保留评分最高得分的 K 个特征;
* SelectPercentile(score_func,percentile=)。保留最高得分的百分比特征;

score_func的选择:
(1)对于回归:
f_regression:相关系数,计算每个变量与目标变量的相关系数,然后计算出F值和P值;基于线性回归分析来计算统计指标,给出各 特征的回归系数,系数比较大的特征更重要。

mutual_info_regression:互信息;计算X和y之间的互信息,以便度量相关程度,适用于回归问题。

(2)对于分类
chi2:卡方检验;计算各特征的卡方统计量,适用于分类问题。
f_classif:方差分析,计算方差分析(ANOVA)的F值 (组间均方 / 组内均方);根据方差分析(ANOVA)的原理,以F-分布为依据,利用平方和与自由度所计算的祖居与组内均方估计出F值,适用于分类问题。
mutual_info_classif:互信息,适用于分类问题。  


注:chi2 , mutual_info_classif , mutual_info_regression 可以保持数据的稀疏性。

代码实现:

from sklearn.feature_selection import SelectKBest,f_classif
X=[
    [1,2,3,4,5],
    [5,4,3,2,1],
    [3,3,3,3,3],
    [1,1,1,1,1]
]
y=[0,1,0,1]
print('before transform:\n',X)
sel=SelectKBest(score_func=f_classif,k=3)
sel.fit(X,y)  #计算统计指标,这里一定用到y
print('scores_:\n',sel.scores_)
print('pvalues_:',sel.pvalues_)
print('selected index:',sel.get_support(True))
print('after transform:\n',sel.transform(X))

4.Kendall(肯德尔等级)相关系数(分类)

特征为类别型,标签为类别型

肯德尔相关系数是一个用来测量两个随机变量相关性的统计值。 

一个肯德尔检验是一个无参数假设检验,检验两个随机变量的统计依赖性。 
肯德尔相关系数的取值范围在-1到1之间,

当τ为1时,表示两个随机变量拥有一致的等级相关性;当τ为-1时,表示两个随机变量拥有完全相反的等级相关性;

当τ为0时,表示两个随机变量是相互独立的。

5.箱形图

使用画箱形图的方法,看类别变量取不同值,数值变量的均值与方差及取值分布情况。

如果,类别变量取不同值,对应的数值变量的箱形图差别不大,则说明,类别变量取不同值对数值变量的影响不大,相关性不高;反之,相关性高。

seaborn.boxplot

6.Relief(Relevant Features)

Relief 借用了“假设间隔”(hypothesis marginhypothesis margin)的思想,我们知道在分类问题中,常常会采用决策面的思想来进行分类,“假设间隔”就是指在保持样本分类不变的情况下,决策面能够移动的最大距离

当一个属性对分类有利时,则该同类样本在该属性上的距离较近(第一项越小),异常样本在该类属性上的距离较远(第二项越大),则该属性对分类越有利。

假设数据集D为(x1,y1),(x2,y2),...,(xm,ym),对每个样本xi,计算与xi同类别的最近邻xi,nh,称为是“猜中近邻”(near-heat),然后计算与xi非同类别的最近邻xi,nm,称为是“猜错近邻”(near-miss),具体点我

对离散型特征:

对连续型特征:

适用场景:二分类

举例:二分类 

7.Relief-F

适用场景:多分类

8.★互信息和最大互系数(非参数)

(1)互信息

作用:估计类别特征与label之间的相关性,互信息是非负值。当且仅当两个特征是独立的,它等于0,而更高的值意味着更高的依赖性

使用方法:

在sklearn中,可以使用mutual_info_classif(分类)和mutual_info_regression(回归)来计算各个输入特征和输出值之间的互信息。使用feature_selection库的SelectKBest类结合最大信息系数法来选择特征。

sklearn.feature_selection.mutual_info_classif(X, y, discrete_features=’auto’, n_neighbors=3, copy=True, random_state=None)

参数:

X:shape = (n_samples,n_features)

y:shape = (n_samples)

discrete_features: {'auto',bool,array_like},默认='auto'

n_neighbors:int,默认=3,用于连续变量的MI估计的邻居数量,较高的值会减少估算的方差,但是可能引入偏差

copy:bool,默认=True,是否复制给定数据,如果设置为False,则初始数据将被覆盖

random_state:int,RandomState实例或None,可选,默认=None,伪随机数发生器的种子,用于向连续变量添加小噪声以去除重复值。 如果是int,则random_state是随机数生成器使用的种子; 如果是RandomState实例,则random_state是随机数生成器; 如果为None,则随机数生成器是`np.random`使用的RandomState实例。

返回:

mi:ndarray,shape=(n_features)每个特征与目标之间的互信息

举例:

from sklearn.feature_selection import SelectKBest,mutual_info_classif
X=[
    [1,2,3,4,5],
    [5,4,3,2,1],
    [3,3,3,3,3],
    [1,1,1,1,1]
]
y=[0,1,0,1]
print('before transform:\n',X)
sel=SelectKBest(score_func=mutual_info_classif,k=3)
sel.fit(X,y)  #计算统计指标,这里一定用到y
print('scores_:\n',sel.scores_)
print('pvalues_:',sel.pvalues_)
print('selected index:',sel.get_support(True))
print('after transform:\n',sel.transform(X))

卡方检验和互信息的区别

  卡方检验对于出现次数较少的特征更容易给出高分。例如某一个特征就出现过一次在分类正确的数据中,则该特征会得到相对高的分数,而互信息则给分较低。其主要原因还是由于互信息在外部乘上了一个该类型出现的概率值,从而打压了出现较少特征的分数。

(2)最大信息系数

  想把互信息直接用于特征选择其实不是太方便,因为它不属于度量方式,也没有办法归一化,在不同数据及上的结果无法做比较;对于连续变量的计算不是很方便(X和 Y 都是集合, xi,y都是离散的取值),通常变量需要先离散化,而互信息的结果对离散化的方式很敏感。

  最大信息系数克服了这两个问题。它首先寻找一种最优的离散化方式,然后把互信息取值转换成一种度量方式,MIC值越大,两个特征间的相似程度越高。minepy提供了MIC功能。

MIC计算三步骤:参考

给定i、j,对XY构成的散点图进行i列j行网格化,并求出最大的互信息值

对最大的互信息值进行归一化

选择不同尺度下互信息的最大值作为MIC值

举例:

import numpy as np 
from minepy import MINE 
from numpy import array 
from sklearn.feature_selection import SelectKBest 
 
def mic(x, y): 
    m = MINE() 
    m.compute_score(x, y) 
    return (m.mic(), 0.5) # 选择 K 个最好的特征,返回特征选择后的数据 
 
mic_select = SelectKBest(lambda X,y: tuple(map(tuple,array(list(map(lambda x:mic(x, y), X.T))).T)), k=10) 
X_new= mic_select.fit_transform(X,y) # k个最好的特征在原特征中的索引 
mic_results_indexs = mic_select.get_support(True) # 得分 
mic_scores = mic_select.scores_ # 特征与最大信息系数的对应 
mic_results = [(features[idx],mic_scores[idx]) for idx in mic_results_indexs] 
mic_results

(五)KL散度(也叫相对熵)

Kullback-Leibler Divergence,即K-L散度,又称相对熵,是一种量化两种概率分布P和Q之间差异的方式,又叫相对熵。在概率学和统计学上,我们经常会使用一种更简单的、近似的分布来替代观察数据或太复杂的分布。K-L散度能帮助我们度量使用一个分布来近似另一个分布时所损失的信息量。根据计算公式,

对于离散分布:

                                

对于连续分布:

                           
可以发现,P 和 Q 中元素的个数不用相等,只需要两个分布中的离散元素一致。

案例:

两个离散分布分布分别为 P 和 Q
P 的分布为:{1,1,2,2,3}
Q 的分布为:{1,1,1,1,1,2,3,3,3,3}
我们发现,虽然两个分布中元素个数不相同,P 的元素个数为 5,Q 的元素个数为 10。但里面的元素都有 “1”,“2”,“3” 这三个元素。
当 x = 1时,在 P 分布中,“1” 这个元素的个数为 2,故 P(x = 1) = 2525 = 0.4,在 Q 分布中,“1” 这个元素的个数为 5,故 Q(x = 1) = 510510 = 0.5
同理,
当 x = 2 时,P(x = 2) = 2525 = 0.4 ,Q(x = 2) = 110110 = 0.1
当 x = 3 时,P(x = 3) = 1515 = 0.2 ,Q(x = 3) = 410410 = 0.4
把上述概率带入公式:

代码实现:

import numpy as np
import scipy.stats
p=np.asarray([0.65,0.25,0.07,0.03])
q=np.array([0.6,0.25,0.1,0.05])
def KL_divergence(p,q):
    return scipy.stats.entropy(p, q, base=2)
print(KL_divergence(p,q)) # 0.01693110139988926
print(KL_divergence(q,p)) # 0.019019266539324498

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值