这一篇博客主要来如何介绍从数据集中抽取合适的特征。html
咱们知道,在数据挖掘中,数据的训练算法很重要,可是一样咱们对于数据的前置处理也不可忽视。由于咱们对某个数据集的描述是使用特征来表示的。在前面的博客中不管咱们是得到商品交易的相关性关系,仍是使用决策树去对Iris进行分类,咱们都是使用了数据集中全部的特征。可是实际上咱们获取的数据真的有这么好吗?python
举个例子,咱们对西瓜进行分类,可是西瓜的编号实际上与训练毫无关系,所以咱们会训练以前将去掉西瓜的编号。咱们之因此去掉编号,是由于咱们知道这个编号与西瓜的好坏毫无关系。可是若是给你一个陌生的数据集,有着成百上千的特征,咱们又如何去除无关的数据特征获得有用的特征而后进行训练?git
凭感受?这里有两个问题:github
这里说一下第二个问题。举个例子,西瓜的好坏与西瓜的颜色有关,可是若是你的数据集中西瓜的颜色所有同样,你还要不要使用这个特征进行训练呢?算法
确定有人说,要!!可是若是这种特征取值类似的特征有1000个,你还要不要呢?在前面的博客中,咱们能够看到使用Apriori
算法进行计算,一旦\(K\)的值增大,基本上轻薄本就算不动这个数据了!api
经过前面的学习咱们知道,不管是交易数据,仍是Iris数据,他们都是一个一个的实体(视频,声音,文本也是),咱们会经过选择一个一个的特征来描述某一个实体,这能够说是建模,同时这个模型的表示可以让数据挖掘的算法可以理解。数组
如何选择一些好的特征,这个也就是这篇博客要讨论的话题(本篇博客是探讨探讨如何从已有的特征中选择好的特征【也就是简化模型】,而不是本身去从数据集中(好比说声音)去寻找特征)。网络
这样作有什么好处呢?最简单的一个就是它可以下降真实世界的复杂度。好比说我要描述一个苹果长什么样,我确定不须要去了解苹果是从哪里买的。可是一样也有缺点,由于咱们在简化的过程当中,可能会忽略某一些特征,可是这些特征可能恰好有着某一些有用的信息。app
特征能够初略的分为两个类型:框架
对于数值型特征来讲,若是两个特征值相差很小,则能够认为这两个特征很类似,可是对于类别型的特征值而言,没办法说他们是否类似,由于他们要不相同,要不不相同。由于名义特征没办法进行数学上的计算,所以咱们能够将它们进行二值化变成数值特征。
一样反过来,数值型特征也能够经过离散化变成类别特征,好比说花瓣长度大于某一个值为类别0,反之则为类别1。可是很明显,这样会丢失一些数据细节。
下面将以不一样的数据集为例,介绍一些用来简化模型的算法。
数据集来自这里,一样在个人GIthub中也存在这个数据集。咱们下载以下的数据集:
在adult.data
中的部分数据以下,每一行表明的是一我的的数据,每一列表示的特征属性值(至于特征是什么,这个在adult.name
文件中有介绍):
🆗,如今咱们就可使用python来加载数据集了。使用pandas,这个前面已经介绍了。
import pandas as pd adult_data = pd.read_csv("Data/adult.data",header=None,names=["age","workclass","fnlwgt","education","education_num","marital-status","occupation","relationship","race","sex","capital-gain","capital-loss","hours-per-week","native-country","money"])
names
表示的就是每个特征的名字。adult_data
的数据以下。特征表明什么意思,基本上经过特征名就能够理解了。若是不理解的能够看adult.name
文件。最后一个特征为money
,他是分类结果,含义是他每一年的收入是否大于50K
。
一样咱们能够得到某一个特征的一些数学量(好比说平均值,标准差,等等),以hours-per-week
为例:
一样咱们能够得到方差:
也能够得到方差:
数据分布以下:
一样,咱们能够获得某一个特征的全部取值状况,在这里咱们查看职业“occupation”的取值有哪一些:
?
表明数据缺失。
如何选择一个好的特征,这个是一门技术活,一样也是一门艺术活,由于特征的选择不是惟一的,也不是维持不变的,它须要根据咱们的需求发生改变。好比说咱们判断一我的的成绩好很差,确定不须要知道他的名字。特征有不少,咱们弱水三千,只取一瓢,缘由以下:
特征的选择有不少方法,下面介绍一些经常使用的简单的方法。
咱们能够很容易的理解,若是某一个特征的特征值都同样,或者说相互之间都很类似,那么咱们能够理解为这个特征并无提供什么有用的信息给咱们,所以咱们能够去掉这一个特征。那么如何判断是否特征值是否类似,emm,方差
能够作到这个。
在scikit-learn中提供了VarianceThreshold
转换器用来去除方差小于某一个阈值的列,具体的使用能够看官网。使用示例以下:
import numpy as np X = np.arange(30).reshape((10, 3))
建立一个\(10 \times 3\)的矩阵。
而后咱们对矩阵进行更改,将第二列的全部值都设为1:
X[:,1] = 1
而后咱们使用转换器对数据集进行处理:
from sklearn.feature_selection import VarianceThreshold # threshold表明的就是阈值,默认是0.0 vt = VarianceThreshold(threshold=0.0) Xt = vt.fit_transform(X)
转换后的数据以下:
咱们能够看到第二列的已经被去除了。
在VarianceThreshold
有两个重要的函数:fit
和transform
,这些说明官网都有,这里稍微的啰嗦如下。fit
函数是去计算array的方差,而transform
函数就是去转换array数组,将反差小于阈值的去除。
咱们能够经过variances_
去查看具体的方差是多少。
以上面的adult.data
数据为例,咱们只使用数值类型数据对money
进行预测。
首先,咱们使用原始的数据进行预测:
在下面X的数据所有都是数值类型的数据。而后构建一个决策树,而后使用交叉验证获得预测的准确度。
X = adult_data[["age","education_num","capital-gain","capital-loss","hours-per-week"]] Y = adult_data["money"] from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import cross_val_score dtc = DecisionTreeClassifier(random_state=14) score = cross_val_score(dtc, X, Y, scoring='accuracy') score.mean()
结果为:
而后咱们使用转换器去除阈值小于200
的方差。而后再构建一个决策树。
from sklearn.feature_selection import VarianceThreshold X = adult_data[["age","education_num","capital-gain","capital-loss","hours-per-week"]].values Y = adult_data["money"] vt = VarianceThreshold(threshold=200) Xt = vt.fit_transform(X) # 构建决策树 from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import cross_val_score dtc = DecisionTreeClassifier(random_state=14) score = cross_val_score(dtc, Xt, Y, scoring='accuracy') score.mean()
最后预测的准确度为:
比不处理特征提升了\(2\%\)左右,还行。不错不错~~
如何选择最佳的几个特征,在Apriori
算法中咱们已经见识到了,同时寻找几个最佳的特征仍是挺耗费计算资源的,所以咱们能够换一个方向,一次寻找一个特征(单变量),而后再选择几个比较好的特征。
在scikit-learn中提供了几个用于选择单变量特征的选择器。
下面将以几个选择方法来举例说明。
卡方验证是什么,若是不知道的话很是建议看一看这一位博主的博客:结合平常生活的例子,了解什么是卡方检验。简单点来讲,就是能够验证咱们的假设是否正确。
计算公式以下:
而后咱们就能够根据自由度
,\(X^2\),经过卡方表去判断咱们假设的置信度。总的来讲,\(X^2\)越小(在自由度相同的状况下),表示错误决策假设的几率越低。
卡方表以下,\(\alpha\)表示的是错误拒绝假设的几率(\(1-\alpha\)也就是假设成立的几率),\(n\)表示的是自由度,红色框框表示就是\(X^2\)
仍是以上面的数值型数据举例:
咱们使用卡方验证从里面选取前3个最好的特征。在sklearn中的卡方验证,作出的\(H_0\)假设(The null hypothesis)默认表明两个变量之间相互独立(解释来自stackoverflow)。这样也就是说\(X^2\)的值越大也就表明着变量之间越相互依赖,也就是对数据挖掘的做用越大。more userful
X = adult_data[["age","education_num","capital-gain","capital-loss","hours-per-week"]].values Y = adult_data["money"] from sklearn.feature_selection import SelectKBest # 导入卡方验证 from sklearn.feature_selection import chi2 # 选取前3个最好的节点 transformer = SelectKBest(score_func=chi2,k=3) X_chi2 = transformer.fit_transform(X,Y) transformer.scores_
卡方验证计算的结果以下:
一样,咱们能够获得卡方验证的最大值的三个特征(也就是第1,3,4项特征)去构建决策树。
from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import cross_val_score dtc = DecisionTreeClassifier(random_state=14) score = cross_val_score(dtc, X_chi2, Y, scoring='accuracy') score.mean()
最后的精准度为:
emm,比方差的方法稍微差了一点。
皮尔逊相关系数具体是什么能够参考百度百科,或者其余博主的博客。在这里只简单的介绍一下。 皮尔逊系数主要是描述X与Y之间的关系,其值介于\(-1与1\)之间。
计算公式以下:
至于怎么实现这个咱们可使用Scipy库。具体使用以下:
from scipy.stats import pearsonr def pearsonr_fit(x,y): scores=[] p_values = [] for column in range(X.shape[1]): # cur_p表示的双侧p值,x[:,column]表示的是X中的某一列 # 而后计算X中的某一列与y之间获得关系,返回相关系数和p_value cur_score,cur_p = pearsonr(x[:,column],y) # 由于相关系数可能为负数,因此取绝对值 scores.append(abs(cur_score)) p_values.append(cur_p) return (np.array(scores),np.array(p_values))
而后咱们经过调用这个函数就能够得到X中的每一列与y之间的关系,而后返回最佳的几个特征。
import numpy as np X = adult_data[["age","education_num","capital-gain","capital-loss","hours-per-week"]].values # 这里不使用">50K"等字符串是由于pearsonr不接受字符串数据。 Y = adult_data["money"] == " >50K" transformer = SelectKBest(score_func=pearsonr_fit,k=3) X_pearsonr = transformer.fit_transform(X,Y)
具体的皮尔逊系数以下:
在这里皮尔逊系数越大,表明两个变量越相关,也就是对于数据挖掘越有做用。所以咱们选择第1,2,5项特征。
最后构建决策树:
from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import cross_val_score dtc = DecisionTreeClassifier(random_state=14) score = cross_val_score(dtc, X_pearsonr, Y, scoring='accuracy') score.mean()
获得的结果为:
emm,更低了。
在前面的几个方法中,咱们都是从已有的特征中选择最佳的一个(或者几个)特征而后进行数据挖掘进行训练。可是咱们没有考虑一个问题,若是特征之间联系紧密怎么办(好比说性别能够由两个特征表示,一个特征表示是不是男的,另一个特征表示是不是女)?有人会说,这个有什么关系,都进行训练就好了。这样作确实是没有关系,可是咱们不得不考虑计算机的计算能力是有限的,若是咱们可以使用最少的信息(去除某一些类似的特征)尽量的描述数据集的特征,这样必将大大的下降数据集的冗余程度。
这里咱们使用广告的数据集:http://archive.ics.uci.edu/ml/machine-learning-databases/internet_ads/,一样在个人GIthub中也有这个数据集。稍微的解释一下这个数据集:
这个数据集从0到1557 都是一些网络图像的特征好比说URL,长宽,ALT等等特征(这些特征有不少类似的特征),而后第1558表明着这个图片是否是广告。
首先咱们仍是从处理数据集开始:
import pandas as pd import numpy as np from collections import defaultdict def convert_number(x): try: return float(x) except ValueError: return np.nan converters = defaultdict() for i in range(1559 -1): converters[i] = convert_number converters[1558] = lambda x:1 if x.strip() == "ad." else 0 ads_data = pd.read_csv("Data/ad.data",header=None,converters=converters)
首先咱们将数据从字符串转成float类型,而后将"ad."转换成1表明有广告,0表明没有广告。可是这里有一个问题,那就是在前面的一些特征可能缺失了(使用❓表示),所以咱们使用NaN表示缺失的数据。
处理后的数据集以下:
而后咱们去除为NaN的数据:
data = ads_data.dropna(axis=0,how='any') X = data.drop(1558,axis=1).values Y = data[1558]
取出后的X数据集大小为:
首先咱们什么特征都不去除,使用决策树进行预测:
from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import cross_val_score dtc = DecisionTreeClassifier(random_state=14) score = cross_val_score(dtc, X, Y, scoring='accuracy') print("准确度是:{}".format(score.mean()))
结果为:
前面咱们介绍过这个ad的数据集里面确定有不少的冗余信息,那么咱们如何去除冗余信息,这里咱们选择PCA算法(主成分分析算法Principal Component Analysis),目的是用较少的信息描述数据集的特征组合。具体的PCA算法能够看一下这个博主的博客:主成分分析(PCA)原理详解。
至于使用,咱们可使用sklearn中自带的库进行操做。
from sklearn.decomposition import PCA # n_components 表示的组成分的数量,默认返回数据集中全部的特征 pca = PCA(n_components=5) Xd = pca.fit_transform(X)
返回的结果就是主成分,根据方差的大小从大到小排序。方差越大,表明着这个特征越可以解释数据集中的大部分信息。咱们能够查看每一个特征的方差:
pca.explained_variance_ratio_
其中第一个特征的方差对数据集整体方差的贡献率为\(85.36\%\)。后面的依次递减。
用PCA算法处理数据一个很差的地方在于,获得的主成分每每是其余几个特征的复杂组合,
例如,上述第一个特征就是经过为原始数据集的1558个特征(虽然不少特征值为0)分别乘以不
同权重获得的,前三个特征的权重依次为- 0.09二、 - 0.995和- 0.024。通过某种组合获得的特征,
若是没有丰富的研究经验,理解起来很困难。 ——《Python数据挖掘入门与实践》
而后是用决策树进行分类:
from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import cross_val_score dtc = DecisionTreeClassifier(random_state=14) score = cross_val_score(dtc, Xd, Y, scoring='accuracy') print("准确度是:{}".format(score.mean()))
结果为:
比使用全部特征的准确度稍微差了一点(差了约\(0.3 \%\)),可是使用的特征却大大的减小了(一个是使用了1557个特征,一个是只使用了5个特征)。总的来讲结果仍是不错的。
咱们也能够经过画图来表示前三个特征与ad
和noad
的关系:
from matplotlib import pyplot as plt from mpl_toolkits.mplot3d import Axes3D data = ads_data.dropna(axis=0,how='any') Y = data[1558] classes = set(Y) colors = ['red', 'green'] fig = plt.figure() ax = Axes3D(fig) for cur_class, color in zip(classes, colors): mask = (Y == cur_class).values ax.scatter(Xd[mask,0], Xd[mask,1],Xd[mask,2],color=color, label=int(cur_class),marker='o') plt.legend() plt.show()
这篇博客主要是介绍怎么从数据集种提取出好的特征下降数据集的复杂度和冗余度。涉及了:
看起来实现并不难,那是由于有了不少优秀的框架已经帮咱们作好了这些事情。这样节约了咱们写代码的时间,避免重复造轮子,可是这样并不表明咱们会用就行 ,咱们真正应该作的是理解里面的原理和背后的数学知识,知其因此然。
项目地址:GitHub