机器学习之特征工程

来源:互联网 发布:八字奶 知乎 编辑:程序博客网 时间:2024/05/20 05:30

前言

之前照着kaggle上的几个大神的帖子对“泰坦尼克存活率”的例子进行了学习和模仿,发现特征工程真的很重要,特征工程有一定的套路,这里的套路我更想理解为是一些必备的处理数据的步骤。当我们手上拿到了一组数据的时候,为了“让数据说话”(当然数据不会说话,我们做特征工程就是为了让数据说话),使用这些常规套路,能够让我们更快地去了解这些陌生的数据,进而加上我们对这批数据的理解,发散思维,去完成对数据的处理。

废话不多说,下面直接进入正题

step1:将后续所需要的包导入,包括:pandas,numpy,matplotlib,sklearn等

import pandas as pd   import numpy as npfrom pandas import Series,DataFrameimport matplotlib.pyplot as pltfrom sklearn.ensemble import RandomForestRegressorfrom sklearn import cross_validation

step2:导入数据,没有数据你去捣鼓谁去。这里数据分为两个,训练集和测试集,具体怎么下载可以直接上kaggle官网下或者自行百度下载。

这里可以使用read_csv或者read_table来读取数据,针对你存储数据文件的类型选取合适的方法。

data_train = pd.read_csv("train.csv")data_test = pd.read_csv("test.csv")


step3:查看数据的信息,包括数据的每列的数量(查看是否有缺失值),查看每列数据的表达形式,是数字还是字符串。


step4:针对不同的数据类型,我们有不同的处理方法,主要有以下几大类:

(1)有限个数的关系型,也就是在这一列中只有这么几个选项,对于这种数据,我们通常采用one-hot encoder.

(2)数字:几乎任何一个数据集都会存在数据缺失的问题,现在,我们先来讨论一下如何处理缺失值。

step5:通常遇到缺值的情况,我们会有几种常见的处理方式

  • 如果缺值的样本占总数比例极高,我们可能就直接舍弃了,作为特征加入的话,可能反倒带入noise,影响最后的结果了
  • 如果缺值的样本适中,而该属性非连续值特征属性(比如说类目属性),那就把NaN作为一个新类别,加到类别特征中
  • 如果缺值的样本适中,而该属性为连续值特征属性,有时候我们会考虑给定一个step(比如这里的age,我们可以考虑每隔2/3岁为一个步长),然后把它离散化,之后把NaN作为一个type加到属性类目中。
  • 有些情况下,缺失的值个数并不是特别多,那我们也可以试着根据已有的值,拟合一下数据,补充上。
方法一:
在这个例子中,Age这个feature的缺失值大概100多个,不是很多,而且年龄对于最终的获救率是十分重要的,因此不能轻易的舍弃,而应该努力进行补全操作,在众多拟合算法中我们可以挑选一个去进行补全。
#首先将年龄为空和不为空的数据分开age_df = data_train[['Age','Fare', 'Parch', 'SibSp', 'Pclass']]#将数据集以这几个feature为内容提取出来know_age = age_df.Age.notnull()  #得到一个Seriesknow_age = age_df[know_age].as_matrix()#将年龄不为空的那部分数据提取出来  然后将DataFrame格式变为array的矩阵格式:as_matrixunknow_age = age_df[age_df.Age.isnull()].as_matrix()
这样我们就获得了新的两个数据集,将age非空的数据集作为训练集,空集为待预测集,接下来就可以使用拟合算法了(想用什么就用什么,这我就不管了,不过一般推荐随机森林)。
方法二:
将年龄离散化:求得训练集和测试集年龄的均值和方差,在(均值-方差,均值+方差)的范围内随机生成年龄将其填充进去。
#计算titanic_df中Age这一列的均值,方差和空值的个数average_age_titanic = titanic_df['Age'].mean()std_age_titanic = titanic_df['Age'].std()count_nan_age_titanic = titanic_df['Age'].isnull().sum()#计算test_df中Age这一列的均值,方差和空值的个数average_age_test = test_df['Age'].mean()std_age_test = test_df['Age'].std()count_nan_age_test = test_df['Age'].isnull().sum()#以均值为基准,方差为波动范围,用这个范围内的随机数去填充缺失的年龄值rand_1 = np.random.randint(average_age_titanic - std_age_titanic, average_age_titanic + std_age_titanic, size = count_nan_age_titanic)rand_2 = np.random.randint(average_age_test - std_age_test, average_age_test + std_age_test, size = count_nan_age_test)
dataset['Age'][np.isnan(dataset['Age'])] = rand1

step6:有的feature是字符串表示,只有这么几个选项的,这时就用one-hot encoder,可以使用pd.get_dummies
dummies_Cabint = pd.get_dummies(data_test['Cabin'],prefix='Cabin')
这样,feature就变成了用0 1表示的了,会多出几列。







step6:在一组数据中,数字类型的feature往往占大多数,因此我们可以先简单看一下数字类型的数据分布。


通过这个命令可以看到所有是数字类型的feature的简单的统计数据:各个feature的含有数据的个数,他们的均值,方差,最小值,四分之一值,中值,四分之三值以及最大值是多少。

step6:毕竟数据量都很大,光看数字还是很抽象的,什么也看不出来,接下来是重头戏,将数据直观化:画图

  画图一般会用到两个包:matplotlib和seaborn,下面先说说matplotlib。

  在matplotlib画图的时候,能画很多种图,可以使用kind参数来控制:

  kind参数 : 'line', 'bar', 'barh', 'kde',其中:

  bar:柱状图(竖着的) 可以画出某一个feature的数量对比;

  barh:也是柱状图,只不过把柱状图横过来了;

  kde:与直方图相关的一种类型图,是通过计算“可能会产生观测数据的连续概率分布的估计”而产生的;

  line:折线图 横轴是序号 纵轴是表中的数值 连起来得到的。

  在使用matplotlib画图的时候,我们通常要定义一个存放图的布,可以理解为画布,这张画布的大小我们可以控制,一幅画布上有多少张图也由我们来定。

fig, (axis1,axis2,axis3) = plt.subplots(1,3,figsize=(15,5))
我们采用这种方法,一句话就定义了画布fig,画布上三个子图axis1,axis2,axis3,而且还可以顺带着把画布的大小一起定义了,多么省事。