拉风小宇 2018-09-12
通常,当我们获得数据集时,我们可能会在数据集中找到大量的特征。我们在数据集中找到的所有特征可能在构建机器学习模型以进行必要的预测时没有用。使用某些特征甚至可能会使预测变得更糟。因此,特征选择在构建机器学习模型中起着巨大的作用。
在本文中,我们将探讨两种可以用于数据的度量,以选择正确的特征。
相关性是统计术语,其在通常使用中是指两个变量彼此之间具有线性关系的接近程度。
例如,两个线性相关的变量(比如x和y, x = 2y相互依赖)比两个非线性相关的变量(比如u和v, u = v2相互依赖)具有更高的相关性
相关性如何帮助选择特征?
具有高相关性的特征更依赖于线性,因此对因变量具有几乎相同的影响。因此,当两个特征具有高度相关性时,我们可以删除这两个特征中的一个。
在我们尝试了解p值之前,我们需要了解零假设。
零假设是一种普遍的说法,即两种测量现象之间没有关系。
在推论统计学中,零假设(英语:null hypothesis,又译虚无假设、原假设,符号:H0)是做统计检验时的一类假设。零假设的内容一般是希望能证明为错误的假设,或者是需要着重考虑的假设。在相关性检验中,一般会取“两者之间无关联”作为零假设,而在独立性检验中,一般会取“两者之间非独立”作为零假设。
什么是p值?
P值(P value)就是当原假设为真时所得到的样本观察结果或更极端结果出现的概率。如果P值很小,说明原假设情况的发生的概率很小,而如果出现了,根据小概率原理,我们就有理由拒绝原假设,P值越小,我们拒绝原假设的理由越充分。总之,P值越小,表明结果越显著。但是检验的结果究竟是“显著的”、“中度显著的”还是“高度显著的”需要我们自己根据P值的大小和实际问题来解决。
p值如何帮助选择特征?
从数据集中删除不同的特征将对数据集的p值产生不同的影响。我们可以删除不同的特征并测量每种情况下的p值。这些测量的p值可用于决定是否保留特征。
导入必要的Python库
import numpy as np import pandas as pd import seaborn as sns import matplotlib.pyplot as plt from sklearn.preprocessing import LabelEncoder, OneHotEncoder import warnings warnings.filterwarnings("ignore") from sklearn.model_selection import train_test_split from sklearn.svm import SVC from sklearn.metrics import confusion_matrix np.random.seed(123)
numpy.random.seed()使随机数可预测,并用于可再现性
数据集
这里使用的数据集是乳腺癌威斯康星(诊断)数据集(https://www.kaggle.com/uciml/breast-cancer-wisconsin-data)。
该数据集包含569个记录和32个特征(包括Id)。该特征代表各种参数可能如果肿瘤是恶性的还是良性在预测有用。
加载数据集
data = pd.read_csv('../input/data.csv')
删除Id和未命名列
data = data.iloc[:,1:-1]
接下来,我们编码分类变量
label_encoder = LabelEncoder() data.iloc[:,0] = label_encoder.fit_transform(data.iloc[:,0]).astype('float64')
根据相关性选择特征
生成相关矩阵
corr = data.corr()
生成相关热图
sns.heatmap(corr)
数据集的相关热图
接下来,我们比较特征之间的相关性,并删除两个相关性高于0.9的特征之一,Python实现如下:
columns = np.full((corr.shape[0],), True, dtype=bool) for i in range(corr.shape[0]): for j in range(i+1, corr.shape[0]): if corr.iloc[i,j] >= 0.9: if columns[j]: columns[j] = False selected_columns = data.columns[columns] data = data[selected_columns]
现在,数据集只有那些相关性小于0.9的列
根据p值选择列
接下来,我们将根据它们对p值的影响来选择列。我们是删除diagnosis列,因为它是我们试图预测的列,Python代码如下:
selected_columns = selected_columns[1:].values import statsmodels.formula.api as sm def backwardElimination(x, Y, sl, columns): numVars = len(x[0]) for i in range(0, numVars): regressor_OLS = sm.OLS(Y, x).fit() maxVar = max(regressor_OLS.pvalues).astype(float) if maxVar > sl: for j in range(0, numVars - i): if (regressor_OLS.pvalues[j].astype(float) == maxVar): x = np.delete(x, j, 1) columns = np.delete(columns, j) regressor_OLS.summary() return x, columns SL = 0.05 data_modeled, selected_columns = backwardElimination(data.iloc[:,1:].values, data.iloc[:,0].values, SL, selected_columns)
将结果移动到新的Dataframe
result = pd.DataFrame() result['diagnosis'] = data.iloc[:,0]
使用p值和相关性创建包含所选列的Dataframe
data = pd.DataFrame(data = data_modeled, columns = selected_columns)
可视化选定的特征
绘制数据以显示其分布,Python代码如下:
fig = plt.figure(figsize = (20, 25)) j = 0 for i in data.columns: plt.subplot(6, 4, j+1) j += 1 sns.distplot(data[i][result['diagnosis']==0], color='g', label = 'benign') sns.distplot(data[i][result['diagnosis']==1], color='r', label = 'malignant') plt.legend(loc='best') fig.suptitle('Breast Cance Data Analysis') fig.tight_layout() fig.subplots_adjust(top=0.95) plt.show()
所选特征的分布图
用选定的特征构建机器学习模型
我们使用带有 Gaussian Kernel的支持向量机分类器进行预测。我们将在训练数据上对机器学习模型进行训练,并使用测试数据计算模型的精度
svc=SVC() # The default kernel used by SVC is the gaussian kernel svc.fit(x_train, y_train)
进行预测并计算准确性
prediction = svc.predict(x_test)
我们在这里使用混淆矩阵
cm = confusion_matrix(y_test, prediction) sum = 0 for i in range(cm.shape[0]): sum += cm[i][i] accuracy = sum/x_test.shape[0] print(accuracy)
获得的准确度为0.9298245614035088
构建没有特征选择的模型并比较结果
接下来,我们重复除特征选择之外的所有上述步骤,它们是:
Python代码如下:
data = pd.read_csv('../input/data.csv') result = pd.DataFrame() result['diagnosis'] = data.iloc[:,1] data = data.iloc[:,2:-1] label_encoder = LabelEncoder() data.iloc[:,0] = label_encoder.fit_transform(data.iloc[:,0]).astype('float64') x_train, x_test, y_train, y_test = train_test_split(data.values, result.values, test_size = 0.2) svc = SVC() svc.fit(x_train, y_train) prediction = svc.predict(x_test) cm = confusion_matrix(y_test, prediction) sum = 0 for i in range(cm.shape[0]): sum += cm[i][i] accuracy = sum/x_test.shape[0] print(accuracy)
获得的准确度为0.7017543859649122
在这里我们可以看到,当执行适当的特征选择时,预测的准确性更好