首页 > sklearn 阅读数:28

scikit-learn准备数据集

准备数据集就是将数据采集中所收集到的数据样本用二维数组或矩阵表示,其中每一行表示一个样本的数据,每一列表示样本的特定定量信息(特征值)。二维数组的形状为 [n_samples,n_features],n_samples 表示数据集中样本总数,n_features 表示数据集中特征个数。

然后确定数据集中的特征矩阵和目标数据,并进行特征归一化和数据清洗。最后,将整个数据集划分为训练集和测试集。

1. Iris 数据集

Iris 数据集是常用的分类实验数据集,它是由著名的英国统计学家和生物学家 Ronald Fisher 在1936 发表的论文中提出的。Iris 也称鸢尾花卉数据集,在这个数据集中,包括了三类不同的鸢尾属植物:Iris Setosa、Iris Versicolour、Iris Virginica。每类鸢尾属植物收集 50 个样本,整个数据集一共包含了 150 个样本。

每个样本包含有 4 个特征,分别如下:
  • sepal_length(花萼长度);
  • sepal_width(花萼宽度);
  • petal_length(花瓣长度);
  • petal_width(花瓣宽度)。

以上 4 个特征的单位都是厘米(cm)。通常使用 m 表示样本量的大小,n 表示每个样本所具有的特征数。因此在该数据集中,m=150,n=4。

通过 Iris 数据集中的 150 个样本测量数据,根据样本数据中的 4 个特征,通过机器学习建立数据模型,用于预测鸢尾花卉属于 Iris Setosa(山鸢尾)、Iris Versicolour(杂色鸢尾),以及 Iris Virginica(弗吉尼亚鸢尾)中的哪一个种类。

Iris 数据集(部分数据)文本格式如下。

sepal_length,sepal_width,petal_length,petal_width,class
5.1,3.5,1.4,0.2,Iris-setosa
4.9,3,1.4,0.2,Iris-setosa
4.7,3.2,1.3,0.2,Iris-setosa
4.6,3.1,1.5,0.2,Iris-setosa
5,3.6,1.4,0.2,Iris-setosa
5.4,3.9,1.7,0.4,Iris-setosa
4.6,3.4,1.4,0.3,Iris-setosa

其中,第一行表示数据属性名称,从第二行开始表示样本数据。

2. 特征矩阵

在 Iris 数据集中,特征是 sepal_length、sepal_width、petal_length 和 petal_width 等,特征矩阵就是由 150 样本和 4 列特征数据组成的矩阵。

3. 目标数组

在 Iris 数据集中,class 列是由鸢尾花分类的名称(也称为标签的名称)组成的一维数组。在 scikit-learn 中,需要将标签的名称 [Iris-setosa,Iris-versicolour,Iris-virginica] 分别用数字 0、1、2 表示,即将 class 列由标签的名称组成的一维数组转换成由数字标签组成的一维数组,由数字标签组成的一维数组称为目标数组。

4. 特征归一化

在机器学习中,提取某个样本特征的过程,称为特征工程。在同一个样本中,由于各特征的评价指标不同,往往会使各特征具有不同的量纲和量纲单位,从而造成各特征的数值大小范围不一致。为了消除指标之间的量纲影响,需要对数据进行归一化处理,以解决数据指标之间的可比性问题。

所谓特征归一化,就是将各特征的数值进行缩放,使特征的数值大小范围转换为相同的区间。在 sklearn 中最常用的特征归一化方法有 MinMaxScaler() 和 StandardScaler()。

另外,在特征归一化时,还需要使用 sklearn 库中数据预处理函数 fit_transform() 和 transform(),其中,fit_transform() 是先拟合数据,再进行数据标准化,而 transform() 则是直接进行数据标准化。所以,fit_transform() 一般用于训练集数据,而 transform() 则用于测试集数据。

1) 归一化

在 sklearn 中,MinMaxScaler() 可单独地缩放和转换每个特征,使这些特征值能转变到训练集所给定的范围内,即在 0 和 1 之间,从而实现特征归一化。

① MinMaxScaler() 的语法格式如下:

sklearn.preprocessing.MinMaxScaler(feature_range=(0,1),copy=True)

参数说明如下:
  • feature_range:接收tuple(min,max),默认=(0,1),表示期望的转换数据范围;
  • copy:接收 boolean,可选项,默认为 True。设置为 False 表示不创建副本。

② MinMaxScaler() 归一化的公式如下:

X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))
X_scaled = X_std * (max - min) + min

公式中的变量说明如下:
  • X:表示矩阵;
  • X_std:表示将 X 归一化到 [0,1] 之间;
  • X.min(axis=0):表示列最小值;
  • max,min:表示 MinMaxScaler() 中参数 feature_range 的取值范围,即转换后最终结果的大小范围。

示例代码 example1.py 如下。
# -*- coding: utf-8 -*-
import numpy as np
from sklearn.preprocessing import MinMaxScaler
data=[[1100,8],[1567,2],[1348,4],[1671,7]]
scaler = MinMaxScaler()
X_train = scaler.fit_transform(data)  #转换成[0,1]之间的归一化数值
print(X_train)

运行结果如下:

[[0.           1.         ]
 [0.8178634    0.          ]
 [0.43432574   0.33333333]
 [1.           0.83333333]]

2) 标准化

在 sklearn 中,StandardScaler() 是通过删除均值和缩放到单位方差来标准化特征的。

① StandardScaler() 的语法格式如下:

sklearn.preprocessing.StandardScaler(copy=True,with_mean=True,with_std=True)

参数说明如下:
  • copy:接收 boolean,默认为 True。如果为 True,表示创建数据副本,为 False,表示不复制只进行缩放;
  • with_mean:接收 boolean,默认为 True。如果为 True,则在缩放之前将数据居中。当在稀疏矩阵上尝试时不起作用(并且会引发异常);
  • with_std:接收 boolean,默认为 True。如果为 True,则将数据缩放为单位方差或单位标准差。

② StandardScaler() 标准化的方式是用每个特征减去列均值,再除以列标准差。

示例代码 example2.py 如下。
# -*- coding: utf-8 -*-
import numpy as np
from sklearn.preprocessing import StandardScaler
data=[[1100,8],[1567,2],[1348,4],[1671,7]]
scaler = StandardScaler()
X_train = scaler.fit_transform(data) #转换标准化数值
print(X_train)

运行结果如下:
[[-1.46673356  1.15311332]
 [ 0.66379388 -1.36277029]
 [-0.33531856 -0.52414242]
 [ 1.13825824  0.73379939]]

5. 数据清洗

Iris 数据集的数据清洗主要是查找缺失值和异常值,然后判断是否需要对数据集进行修补或剔除。下面通过 Jupyter Notebook 进行数据清洗操作。

Iris 数据集的数据清洗步骤及相关代码如下。

1) 导入相关库和 Iris 数据集

In [1]: import pandas as pd
        import matplotlib.pyplot as plt
        import seaborn as sns
In [2]: iris_df= pd.read_csv('d:\data\iris.txt',sep=',
In [3]: iris_df

2) 查看缺失值的数量

In [4]: iris_df.isnull().sum()
从输出结果中发现 petal_width_cm 列中有 5 个缺失值。

3) 通过 describe() 寻找缺失值、异常值数据所在项

In [5]: iris_df.describe()
从输出结果中,观察统计函数中 count、min、max 参数。

4) 通过 lmplot() 线性回归模型,寻找 class (种类)项中的异常值

In [6]: sns.lmplot(x='sepal_length', y='sepal_width', col='class', data=iris_df)
从输出结果中发现原本只有 3 种鸢尾花,但却出现了 5 种,其中出现两个错误编码,即 Iris-setossa 和 versicolor。同时,发现 sepal_width 和 sepal_length 有异常值。

5) 处理 class( 种类)项中的异常值

将错误编码 Iris-setossa 和 versicolor 用正确编码 Iris-setosa 和 Iris-versicolor 替换。
In [7]: iris_df.loc[iris_df['class'] == 'versicolor', 'class'] ='Iris-versicolor'
        iris_df.loc[iris_df['class'] == 'Iris-setossa', 'class'] ='Iris-setosa'
In [8]: sns.lmplot(x='sepal_length', y='sepal_width', col='class',data=iris_df)

6) 处理 sepal_width(花萼宽度)小于 2.5 厘米的异常值

处理方法如下:
  • 通过直方图查看 Iris Setosa(山鸢尾)这一种类花的 sepal_width(花萼宽度)的数据分布;
  • 发现 sepal_width(花萼宽度)有小于 2.5 厘米异常值;
  • 删除花萼宽度小于 2.5 厘米的异常值,并用直方图查看处理后的数据分布。

代码如下。
In [9]: iris_df.loc[iris_df['class'] == 'Iris-setosa','sepal_width'].hist()
In [10]: iris_df = iris_df.loc[(iris_df['class'] != 'Iris-setosa') | (iris_df['sepal_width'] >= 2.5)]
In [11]: iris_df.loc[iris_df['class'] == 'Iris-setosa', 'sepal_width'].hist()

7) 处理 sepal_length(花萼长度)接近于 0 的异常值

处理方法如下:
  • 列出 Iris-versicolor(弗吉尼亚鸢尾)这一种类花的 sepal_length(花萼长度)接近于 0 的数值;
  • 这些接近于 0 的数值的计量单位为“米”,要转换为“厘米”,因此,将它们乘 100;
  • 通过直方图查看数据分布。

代码如下。
In [12]: iris_df.loc[(iris_df['class'] == 'Iris-versicolor') &(iris_df['sepal_length'] < 1.0)]
In [13]: iris_df.loc[(iris_df['class'] == 'Iris-versicolor') &(iris_df['sepal_length'] < 1.0),\
                     'sepal_length'] *= 100.0
In [14]: iris_df.loc[iris_df['class'] == 'Iris-versicolor', 'sepal_length'].hist()

8) 处理缺失值

  • 列出缺失值的样本
In [15]: iris_df.loc[(iris_df['sepal_length'].isnull()) | (iris_df['sepal_width'].isnull()) |\
                     (iris_df['petal_length'].isnull()) | (iris_df['petal_width'].isnull())]
观察输出结果,发现缺失值都属于 Iris-setosa 类的 petal_width(花瓣宽度)属性,因此,可以用 petal_width(花瓣宽度)的平均值来填补缺失值。

  • 用平均值来填补缺失值。
In [16]:  avg_value = iris_df.loc[iris_df['class'] == 'Iris-setosa','petal_width'].mean()
          iris_df.loc[(iris_df['class'] == 'Iris-setosa') &
                      (iris_df['petal_width'].isnull()),
                      'petal_width'] = avg_value
          iris_df.loc[(iris_df['class'] == 'Iris-setosa') &
                      (iris_df['petal_width'] == avg_value)]

  • 删除缺失值。
In [17]:  iris_df.dropna(inplace=True)

9)将标签名称转换成标签

In [18]:  class_mapping = {'Iris-setosa':0,
                           'Iris-versicolor':1,
                           'Iris-virginica':2}
          iris_df['class'] = iris_df['class'].map(class_mapping)

10)保存处理后的数据

In [19]:  iris_df.to_csv('d:/data/iris-clean.csv', index=False)
数据清洗的要点如下:
① 数据编码方式要正确。
② 数据取值范围要在合理的区间。
③ 处理缺失值可采用替换或删除方法。
④ 不要手工整理数据,因为这很难重现。
⑤ 使用程序代码可较好地记录数据处理的过程。
⑥ 除了用图表展示数据外,还可用图表发现异常数据。

6. 划分 trainset(训练集)和 testset(测试集)

在 sklearn 中,使用 train_test_split() 函数可以很方便地将数据划分为 trainset(训练集)和 testset(测试集)。该函数的功能是从样本中随机按比例选取训练集和测试集。函数的调用形式如下:

X_train,X_test,y_train,y_test = train_test_split(train_data,train_target,
test_size=0.3,random_state=0)

参数说明如下。
  • train_data:表示训练集的特征矩阵。
  • train_target:表示训练集的目标数组。
  • test_size:表示样本占比。如果为整数表示全部样本数量。
  • random_state:表示随机数生成器的种子。相同的种子,产生的随机数相同。不同的种子,产生不同的随机采样结果。设置该参数可确保每次随机分割得到相同的结果。
  • X_train、y_train:表示训练集中的特征矩阵和目标数组。
  • X_test、y_test:表示测试集中的特征矩阵和目标数组。

注意:调用 train_test_split() 函数时,需要导入相应的软件包,其代码如下:
from sklearn.model_selection import train_test_split, cross_val_score

其示例代码 example3.py 如下。
# -*- coding: utf-8 -*-
import numpy as np
from sklearn.model_selection import train_test_split, cross_val_scor
X, y = np.arange(18).reshape((6, 3)), range(6)

X_train, X_test, y_train, y_test = \
    train_test_split(X, y, test_size=0.3,random_state=32)
print('训练集特征矩阵',X_train,'\n测试集特征矩阵',X_test)
print('训练集目标数组',y_train,'\n测试集目标数组',y_test)