(原创)(一) 机器学习之数据探索

<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.10/require.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script> href="custom.css" rel="stylesheet"> <script src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML"></script> <script type="text/x-mathjax-config"> MathJax.Hub.Config({ tex2jax: { inlineMath: [ ['$','$'], ["\\(","\\)"] ], displayMath: [ ['$$','$$'], ["\\[","\\]"] ], processEscapes: true, processEnvironments: true }, // Center justify equations in code and markdown cells. Elsewhere // we use CSS to left justify single line equations in code cells. displayAlign: 'center', "HTML-CSS": { styles: {'.MathJax_Display': {"margin": 0}}, linebreaks: { automatic: true } } }); </script>

机器学习的一般步骤

1.确定特征
(1)数据探索
(2)数据预处理
2.确定模型
(1)确定目标函数
3.模型训练
(1)确定优化算法,估计模型参数
4.模型选择
选择不同参数下的模型。
5.模型评估
对所选择的模型进行评估:估计模型在未知数据上的性能(泛化能力).

以上5个过程不断迭代,直到寻找到一个最优的模型和其参数。

以下,以波士顿房价预测为例,先简单讲讲数据探索。
一般我们拿到一堆数据之后,并不知道数据有何规律,为了了解数据特征的规律(概率分布),我们第一个步骤就是数据探索,探索数据的特征有何规律或者分布,为模型选择奠定基础。

数据探索

数据探索包括:
(1) 数据规模。
(2) 数据类型,确定是否需要进一步编码。
(3) 数据是否有缺失值,如果有则进行数据填补。
(4) 查看数据分布,是否有异常数据点,如果有则进行离群点处理。
(5) 查看是否需要降维:查看两两特征之间的关系,看数据是否有相关(冗余)。

1. 导入必要的工具包

数据处理工具包为:Numpy,SciPy,pandas,其中SciPy,pandas是基于Numpy进一步的封装
数据可视化工具包为:Matplotlib,Seaborn,其中Seaborn是基于Matplotlib进一步的封装

In [38]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

#将matplotlib的图表直接嵌入到Notebook之中
%matplotlib inline

%matplotlib inline :

将matplotlib的图表直接嵌入到Notebook之中.
IPython提供了许多魔法命令。魔法命令都以%或者%%开头,以%开头的成为行命令,%%开头的称为单元命令。行命令只对命令所在的行有效,而单元命令则必须出现在单元的第一行,对整个单元的代码进行处理。执行%magic可以查看关于各个命令的说明,而在命令之后添加?可以查看该命令的详细说明:
%matplotlib?

2.读取结构化数据

pandas.read_csv(filepath_or_buffer,...,header='infer', names=None,..., encoding=None, ...)

read_csv与to_csv 是一对输入输出的工具,read_csv直接返回pandas.DataFrame,而to_csv只要执行命令即可写文件
header: 表示数据中是否存在列名,如果在第0行就写就写0,并且开始读数据时跳过相应的行数,不存在可以写none。
names: 表示要用给定的列名来作为最终的列名。
encoding:表示数据集的字符编码,通常而言一份数据为了方便的进行文件传输都以utf-8作为标准。

In [39]:
dpath = './data/'
data = pd.read_csv(dpath + "boston_housing.csv") #返回的是DataFrame类型

3.数据概览

df.head(n):查看DataFrame对象的前n行,默认是5行
data.tail(n):查看DataFrame对象的后n行,默认是5行
data.info(): 查看索引、数据类型和内存信息
data.isnull():检查DataFrame对象中的空值,并返回一个Boolean数组   data.describe():查看数值型列的汇总统计  

In [40]:
data.head(5) #查看DataFrame对象的前5行数据
Out[40]:
CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT MEDV
0 0.00632 18 2.31 0 0.538 6.575 65.2 4.0900 1 296 15 396.90 4.98 24.0
1 0.02731 0 7.07 0 0.469 6.421 78.9 4.9671 2 242 17 396.90 9.14 21.6
2 0.02729 0 7.07 0 0.469 7.185 61.1 4.9671 2 242 17 392.83 4.03 34.7
3 0.03237 0 2.18 0 0.458 6.998 45.8 6.0622 3 222 18 394.63 2.94 33.4
4 0.06905 0 2.18 0 0.458 7.147 54.2 6.0622 3 222 18 396.90 5.33 36.2
In [41]:
data.tail(5) #查看DataFrame对象的后5行数据
Out[41]:
CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT MEDV
501 0.06263 0 11.93 0 0.573 6.593 69.1 2.4786 1 273 21 391.99 9.67 22.4
502 0.04527 0 11.93 0 0.573 6.120 76.7 2.2875 1 273 21 396.90 9.08 20.6
503 0.06076 0 11.93 0 0.573 6.976 91.0 2.1675 1 273 21 396.90 5.64 23.9
504 0.10959 0 11.93 0 0.573 6.794 89.3 2.3889 1 273 21 393.45 6.48 22.0
505 0.04741 0 11.93 0 0.573 6.030 80.8 2.5050 1 273 21 396.90 7.88 11.9
In [42]:
data.info() #查看索引、数据类型和内存信息
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 506 entries, 0 to 505
Data columns (total 14 columns):
CRIM       506 non-null float64
ZN         506 non-null int64
INDUS      506 non-null float64
CHAS       506 non-null int64
NOX        506 non-null float64
RM         506 non-null float64
AGE        506 non-null float64
DIS        506 non-null float64
RAD        506 non-null int64
TAX        506 non-null int64
PTRATIO    506 non-null int64
B          506 non-null float64
LSTAT      506 non-null float64
MEDV       506 non-null float64
dtypes: float64(9), int64(5)
memory usage: 55.4 KB
In [43]:
data.isnull().sum() #检查DataFrame对象中的是否存在空值
Out[43]:
CRIM       0
ZN         0
INDUS      0
CHAS       0
NOX        0
RM         0
AGE        0
DIS        0
RAD        0
TAX        0
PTRATIO    0
B          0
LSTAT      0
MEDV       0
dtype: int64
In [44]:
data.describe() #查看数值型列的汇总统计
Out[44]:
CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT MEDV
count 506.000000 506.000000 506.000000 506.000000 506.000000 506.000000 506.000000 506.000000 506.000000 506.000000 506.000000 506.000000 506.000000 506.000000
mean 3.613524 11.347826 11.136779 0.069170 0.554695 6.284634 68.574901 3.795043 9.549407 408.237154 18.083004 356.674032 12.653063 22.532806
std 8.601545 23.310593 6.860353 0.253994 0.115878 0.702617 28.148861 2.105710 8.707259 168.537116 2.280574 91.294864 7.141062 9.197104
min 0.006320 0.000000 0.460000 0.000000 0.385000 3.561000 2.900000 1.129600 1.000000 187.000000 12.000000 0.320000 1.730000 5.000000
25% 0.082045 0.000000 5.190000 0.000000 0.449000 5.885500 45.025000 2.100175 4.000000 279.000000 17.000000 375.377500 6.950000 17.025000
50% 0.256510 0.000000 9.690000 0.000000 0.538000 6.208500 77.500000 3.207450 5.000000 330.000000 19.000000 391.440000 11.360000 21.200000
75% 3.677082 12.000000 18.100000 0.000000 0.624000 6.623500 94.075000 5.188425 24.000000 666.000000 20.000000 396.225000 16.955000 25.000000
max 88.976200 100.000000 27.740000 1.000000 0.871000 8.780000 100.000000 12.126500 24.000000 711.000000 22.000000 396.900000 37.970000 50.000000

此处得到各属性的样本数目、均值、标准差、最小值、1/4分位数(25%)、中位数(50%)、3/4分位数(75%)、最大值 可初步了解各特征的分布

4.以数据可视化的方式查看各属性的统计特征

(1) 直方图distplot

seaborn.distplot(a, bins=None, ..., kde=True,....)

a:数据, bins:箱子数,kde:是否进行核密度估计

In [45]:
from matplotlib.font_manager import FontProperties   #添加相关包,指定相关字体
font_set = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=12)

# 房价(即目标)的直方图
sns.distplot(data.MEDV.values, bins=30,kde=True)
plt.xlabel(u"房价分布",fontproperties=font_set)
plt.show()
In [46]:
# 犯罪率的直方图
sns.distplot(data.CRIM.values, bins=30, kde=False)
plt.xlabel(u"犯罪率直方图", fontproperties=font_set)
plt.show()

犯罪率特征的分布是长尾分布,和指数分布比较接近。大部分城镇的犯罪率很低,极少数样本的犯罪率高。从常理看,该数值应该比较准确,可以不予处理。

(2)散点图scatter

In [47]:
# 房价(即目标)的散点图
plt.scatter(range(data.shape[0]), data.MEDV.values, color='purple')
plt.title(u"房价的散点分布",fontproperties=font_set)
Out[47]:
<matplotlib.text.Text at 0x10afe7b8>

可以看出,数据大多集中在均值附近,和正态分布比较接近。但最大值50的样本数目偏多,可能是原始数据将所有大于50的样本的值都设置为50(猜测),在模型训练时也可以考虑将y等于50的样本当成outliers(离群点)去掉。

(3)计数图countplot

计数图,可将它认为一种应用到分类变量的直方图,用以统计不同的类别的计数值:

seaborn.countplot(x=None, y=None, hue=None, data=None, order=None, ...)

order:控制变量绘图的顺序

In [30]:
#sns.countplot(data.ZN)
#sns.countplot(data.CHAS, order=[0,1]) #与下面等价
sns.countplot(data.CHAS)
Out[30]:
<matplotlib.axes._subplots.AxesSubplot at 0xc5dd780>
In [48]:
sns.countplot(data.RAD)
Out[48]:
<matplotlib.axes._subplots.AxesSubplot at 0x11be3898>

5.两两特征之间的相关性

a.希望特征与标签之间强相关
b.如果特征和特征之间强相关,说明信息冗余,可常用处理方法:
1)两个特征之间只保留其中一个特征。
2)采用组成分析(PCA)等进行降维。
3)在模型的正则项采用L1正则。

(1)热力图heatmap

seaborn.heatmap(data, vmin=None, vmax=None, cmap=None, center=None, robust=False, annot=None, fmt='.2g', annotkws=None, linewidths=0, linecolor='white', cbar=True, cbarkws=None, cbar_ax=None, square=False, ax=None, xticklabels=True, yticklabels=True, mask=None, **kwargs)

data:矩阵数据集,可以使numpy的数组(array),如果是pandas的dataframe,则dataframe的index/column信息会分别对应到heatmap的columns和rows。
linewidths:热力图矩阵之间的间隔大小。
vmax,vmin:图例中最大值和最小值的显示值,没有该参数时默认不显示。
annot : bool or rectangular dataset, optional,If True, write the data value in each cell,显示数值。
mask : boolean array or DataFrame, optional。If passed, data will not be shown in cells where mask is True.
cbar : boolean, optionalWhether to draw a colorbar.

In [49]:
plt.subplots(figsize=(13,9)) #指定窗口尺寸(单位英尺)
data_corr=data.corr().abs() #返回列与列之间的相关系数

#数据为相关系数,显示数值,显示颜色条
sns.heatmap(data_corr, annot=True)
Out[49]:
<matplotlib.axes._subplots.AxesSubplot at 0x111510b8>

(2)打印出两两特征之间的相关系数

sorted(list, key=lambda x: -abs(x[0]))

参数key是关键词, lambda是一个隐函数,是固定写法,表示按照列表x的-abs(x[0])这个值进行排序,其中x可为任意名称,指代前面的列表list。

DataFrame.iloc[i,j]:按位置选取数据

In [35]:
cols = data.columns #获取列的名称
corr_list = []
size = data.shape[1]

for i in range(0, size):
    for j in range(i+1, size):
        if(abs(data_corr.iloc[i,j])>= 0.5):
            corr_list.append([data_corr.iloc[i,j], i, j]) #data_corr.iloc[i,j]:按位置选取数据
                      
sorted_corr_list = sorted(corr_list, key=lambda xx:-abs(xx[0]))

for v,i,j in sorted_corr_list:
    print("%s and %s = %.2f" % (cols[i], cols[j],v)) # cols: 列名           
RAD and TAX = 0.91
NOX and DIS = 0.77
INDUS and NOX = 0.76
AGE and DIS = 0.75
LSTAT and MEDV = 0.74
NOX and AGE = 0.73
INDUS and TAX = 0.72
INDUS and DIS = 0.71
RM and MEDV = 0.70
NOX and TAX = 0.67
ZN and DIS = 0.66
INDUS and AGE = 0.64
CRIM and RAD = 0.63
RM and LSTAT = 0.61
NOX and RAD = 0.61
INDUS and LSTAT = 0.60
AGE and LSTAT = 0.60
INDUS and RAD = 0.60
NOX and LSTAT = 0.59
CRIM and TAX = 0.58
ZN and AGE = 0.57
TAX and LSTAT = 0.54
DIS and TAX = 0.53
ZN and INDUS = 0.53
ZN and NOX = 0.52
AGE and TAX = 0.51
PTRATIO and MEDV = 0.51

通常认为相关系数大于0.5的为强相关,可以看出相关系数大于0.5的特征较多,可对数据进行降维处理,例如去掉一个特征,或者使用主成分分析(PCA),L1正则等进行处理。

(3)呈现数据集中成对的关系pairplot

seaborn.pairplot(data, hue=None, hue_order=None, palette=None, vars=None, x_vars=None, y_vars=None, kind='scatter', diag_kind='hist', markers=None, size=2.5, aspect=1, dropna=True, plot_kws=None, diag_kws=None, grid_kws=None)

数据指定:
vars : 与data使用,否则使用data的全部变量。参数类型:numeric类型的变量list。
{x, y}_vars : 与data使用,否则使用data的全部变量。参数类型:numeric类型的变量list。即指定x,y数据。
dropna : 是否剔除缺失值。参数类型:boolean, optional.

特殊参数: kind : {‘scatter’, ‘reg’}, optional Kind of plot for the non-identity relationships.
diag_kind : {‘hist’, ‘kde’}, optional。Kind of plot for the diagonal subplots.

基本参数:
size : 默认 6,图的尺度大小(正方形)。参数类型:numeric
hue : 使用指定变量为分类变量画图。参数类型:string (变量名).
hue_order : list of strings Order for the levels of the hue variable in the palette.
palette : 调色板颜色.
markers : 使用不同的形状。参数类型:list.
aspect : scalar, optional。Aspect * size gives the width (in inches) of each facet.
{plot, diag, grid}_kws : 指定其他参数。参数类型:dict
返回:
PairGrid 对象.

In [37]:
for v,i,j in sorted_corr_list:
    sns.pairplot(data, size=6, x_vars=cols[i], y_vars=cols[j]) #绘制x_vars列和y_vars列特征之间的关系,看是否有线性关系
    plt.show()

猜你喜欢

转载自blog.csdn.net/tantanweiwei/article/details/78350397
今日推荐