机器学习项目中,通俗地讲,一般70%以上的时间会被用于数据的处理,20%的时间用于训练,10%的时间用于评估结果,可见数据处理在机器学习中的重要性。有句话说的很好,数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。因此这里对数据处理的一些工具和方法做一下记录。本文使用的数据集是UCI的Breast Cancer Wisconsin (Diagnostic) ,该数据集用于二分类,使用sklearn.datasets中的load_breast_cancer函数可以方便地加载它。本文基于这个数据集,介绍一些常用的数据预处理方法。
1 数据的加载
该数据集有569个样本,30个特征,scikit-learn提供方便的函数来加载该数据集,代码如下:
from sklearn.datasets import load_breast_cancer
import pandas as pd
import numpy as np
bundle = load_breast_cancer()
X = bundle.data
y = bundle.target
X[11:21, 1] = np.NAN #制造缺失值
c = ['mean_radius', 'mean_texture', 'mean_perimeter', 'mean_area',
'mean_smoothness', 'mean_compactness', 'mean_concavity',
'mean_concave', 'mean_symmetry', 'mean_fractal', 'standard_radius',
'standard_texture', 'standard_perimeter', 'standard_area',
'standard_smoothness', 'standard_compactness', 'standard_concavity',
'standard_concave', 'standard_symmetry', 'standard_fractal', 'worst_radius',
'worst_texture', 'worst_perimeter', 'worst_area', 'worst_smoothness',
'worst_compactness', 'worst_concavity', 'worst_concave', 'worst_symmetry', 'worst_fractal']
dataset = pd.DataFrame(X, columns = c)
dataset_part = dataset[c[0:10]]
由于特征较多,方便展示结果,这里只选取前10个特征。为了模拟具有缺失值的数据集,这里我手动把第11到20个样本的'mean_texture'特征值删去了。
2 数据的初步探索
2.1 快速查看
1. 查看前五行
dataset_part.head()
结果如下:
2. 查看某个特征的值的个数,由于篇幅限制,这里只展示前10行:
dataset_part['mean_radius'].value_counts().iloc[0 : 10]
结果如下:
3. 查看该数据集的简单描述,比如总行数、每个属性的类型和非控制的数量等
dataset_part.info()
结果如下:
4. 显示属性的摘要,包括总数、中位数、均值等
dataset_part.describe()
结果如下:
5. 绘制每个特征的直方图,横轴是特征值的范围,纵轴是实例的数量
%matplotlib inline
import matplotlib.pyplot as plt
dataset_part.hist(bins=50, figsize=(20,15))
plt.show()
结果如下所示:
2.2 特征之间的相关性
方法一
如果数据集不大,可以直接使用DataFrame的corr()方法,它会计算特征两两之间的标准相关系数(皮尔逊相关系数)。相关系数的范围从-1到1,越接近1,表示有越强的正相关性,接近-1,则表示有强烈的负相关性。对dataset_part使用corr()函数,得到下表:
可以看到各个特征与其它特征的相关度,比如mean_radius就与mean_perimeter具有很强烈的正相关性,而与mean_smoothness则相关度不高。
方法二
另一种方法是使用Pandas的scatter_matrix函数,它会绘制每个数值属性相对于其他数值属性的相关性。比如以下代码:
%matplotlib inline
from pandas.plotting import scatter_matrix
attr = ['mean_radius', "mean_texture", "mean_perimeter", "mean_area"]
scatter_matrix(dataset_part[attr], figsize=(20,12))
结果如下所示:结果一目了然,可以看到mean_radius与mean_perimeter和mean_area有较强的正相关性,而与mean_texture则相关性很低。同一个特征则展示该特征的分布直方图,否则会是一条毫无价值的主对角线。
3 数据的清理
对于缺失值的处理,有三种选择:
1. 放弃这些样本。Scikit-Learn提供以下方法:
df = dataset_part.dropna(subset=['mean_texture'])
print(len(dataset_part), len(df))
输出:(569, 559)
2. 放弃这个特征。Scikit-Learn提供以下方法:
df = dataset_part.drop('mean_texture', axis=1)
df
输出如下,可以看到,mean_texture列已经不见了:
3. 将缺失的值设置为某个值(0、平均值或者中位数等都可以)。Scikit-Learn提供以下方法:
median = dataset_part['mean_texture'].median()
dataset_part['mean_texture'].fillna(median)[0:21]
输出如下:
这里scikit-learn还提供了另外一种方便的方法来处理缺失值,那就是Imputer。Imputer调用fit()方法之后,会将均值存放在statistics_成员变量中,调用transform()方法会产生一个np.ndarray对象,使用方法如下:
from sklearn.impute import SimpleImputer
imputer = SimpleImputer(strategy='median')
imputer.fit(dataset_part)
imputer.statistics_
X = imputer.transform(dataset_part)
pd.DataFrame(X).iloc[11:21]
4 测试数据集的划分
一般我们可以将数据集划分为20%的测试数据集和80%的训练数据集,scikit-learn提供了方便的划分函数,使用如下:
from sklearn.model_selection import train_test_split
train_set, test_set = train_test_split(dataset_part, test_size=0.2, random_state=42)
print(len(train_set), len(test_set))
输出:(455, 114)
也提供了根据某一特征进行分层抽样的数据分割方法。什么是分层抽样呢?比如我们想预测大盘用户对某类保险产品的购买意愿,假设用户的收入水平对这类保险的意愿有很大的影响,用户的收入水平被划分成A、B、C、D四个层次,已知大盘用户收入水平的占比依次是20%、40%、30%、10%,研究方法是从大盘中抽出10W个用户进行训练,我们当然希望这10W个用户的收入水平分布和大盘用户的一致,这就是分层抽样。同理,我们对数据集进行划分,也希望训练集和测试集对某一特征的分布是一致的,这时就可以使用Scikit-Learn提供的StratifiedShuffleSplit类,使用方法如下:
dataset_part["radius_cat"] = np.ceil(dataset_part['mean_radius'] / 3)
from sklearn.model_selection import StratifiedShuffleSplit
sss = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42)
for train_index, test_index in sss.split(dataset_part, dataset_part['radius_cat']):
strat_train_set = dataset_part.loc[train_index]
strat_test_set = dataset_part.loc[test_index]
print(len(strat_train_set), len(strat_test_set))
输出:(455, 114)
StratifiedShuffleSplit允许对数据集进行多次划分,产生多组train/test对,以进行交叉验证。在这个例子中,我们只进行一次分割。
5 总结
数据处理在机器学习项目中是很大的工程,且涉及很多的内容和知识,本文介绍的方法只是冰山一角,后续有更多内容会继续加进来。