Python和high level的机器学习/深度学习库,比如Scikit-learn,TensorFlow,NLTK,PyBrain,Theano和MLPY让机器学习走进“大众”(开发社区)视野。随着这些工具的开源,现在有了越来越多的机器学习从业者。与此同时,机器学习的份额并没有增加。预测工具正在成为各行各业(从商业,艺术,和工程到教育,法律和国防)的决策驱动。
当我们使用几行Python代码来示例和拟合一个模型时,如何才能确保我们的预测结果是可信的和健壮的?
from sklearn.linear_model import LinearRegression
model = LogisticRegression()
model.fit(X,y)
model.predict(X)
选择什么样的初始模型?使用哪些特征?哪些特征需要归一化?如何来甄别一些问题(比如,局部极小值和过拟合)?从弱模型可以得到优化模型吗?
为了帮助我们解决以上问题,让我们来看一下以下4个二维数组,为每个生成预测模型:
import numpy as np
i = np.array([
[10.0, 8.0, 13.0, 9.0, 11.0, 14.0, 6.0, 4.0, 12.0, 7.0, 5.0],
[8.04, 6.95, 7.58, 8.81, 8.33, 9.96, 7.24, 4.26, 10.84, 4.82, 5.68]
])
ii = np.array([
[10.0, 8.0, 13.0, 9.0, 11.0, 14.0, 6.0, 4.0, 12.0, 7.0, 5.0],
[9.14, 8.14, 8.74, 8.77, 9.26, 8.10, 6.13, 3.10, 9.13, 7.26, 4.74]
])
iii = np.array([
[10.0, 8.0, 13.0, 9.0, 11.0, 14.0, 6.0, 4.0, 12.0, 7.0, 5.0],
[7.46, 6.77, 12.74, 7.11, 7.81, 8.84, 6.08, 5.39, 8.15, 6.42, 5.73]
])
iv = np.array([
[8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 19.0, 8.0, 8.0, 8.0],
[6.58, 5.76, 7.71, 8.84, 8.47, 7.04, 5.25, 12.50, 5.56, 7.91, 6.89]
])
我们应该使用哪种模型来拟合数据呢?首先,为每个数组计算统计属性:平均值、方差、相关系数以及线性回归的斜率和截距。
from scipy import stats
def get_stats(twoDarray):
print(np.mean(twoDarray[0]))
print(np.mean(twoDarray[1]))
print(np.var(twoDarray[0]))
print(np.var(twoDarray[1]))
print(np.corrcoef(twoDarray[0],twoDarray[1]))
print(stats.linregress(twoDarray[0],twoDarray[1]))
for data in (i, ii, iii, iv):
get_stats(data)
当你运行上面的代码,你会发现四组数组中有相同的描述统计属性。这可能导致我们决定为每个数组使用单个模型(比如,sklearn.linear_model.LinearRegression)。但是,如果我们把数据集绘制成图表,我们将看到跟我们想象的不一样:
def make_plot(a, b, c, d):
fig, ((axa, axb), (axc, axd)) = plt.subplots(2, 2, sharex='col', sharey='row')
for arr, ax in ((a, axa), (b, axb), (c, axc), (d, axd)):
x = arr[0]
y = arr[1]
ax.scatter(x, y, c='g')
m,b = np.polyfit(x, y, 1)
X = np.linspace(ax.get_xlim()[0], ax.get_xlim()[1], 100)
ax.plot(X, m*X+b, '-')
plt.show()
make_plot(i, ii, iii, iv)
更重要的是,一个简单的线性回归模型并不能对这个四个数组都满足。我们能看到 i 和 iii 是线性关系,但是它们的回归线又是那么的不同。在 ii 的图表中,我们看到变量是相关的,但又不是线性相关的,也不是完全的正太分布。并且,图表 iii 和 iv 都包含比较明显的异常点,严重地影响到相关系数。
统计学家弗朗西斯·安斯库姆(Francis Anscombe)于1973年构造出安斯库姆四重奏(Anscombe’s quartet),它包含四组基本的统计特性一致的数据,目的是用来说明在分析数据前先绘制图表的重要性,以及离群值对统计的影响之大。所以,有时数据集的可视化对机器学习至关重要。在数据科学中,视觉诊断是一种强大的但常常又被低估的工具。可视化不应该在数据管道的结尾处。当我们直接在原始数据集中看不到什么规律时,绘制图表可以帮助我们找到模型/模式。静态输出结果和表格数据不能使得模型/模式显现的地方,人类视觉分析能够洞察,并能获得健壮的程序和更好的数据产品。
在机器学习中,许多因素(比如,杂乱的数据,过度训练数据集,过度调优,维度灾难((curse of dimensionality)[备注一]等)会引起问题。视觉诊断可以辨别出“损毁”的模型和正常预测的模型。在系列文章《视觉诊断让你对机器学习了如指掌》中,将向你展示可视化工具是如何在机器学习过程的几个关键阶段(特征工程,模型选择,参数调优)提供帮助的?如何有效利用Scikit-Learn库和Matplotlib库(包括但不限于Pandas,Bokeh和 Seaborn)。
样本数据集
为了在不同的领域讲解可视化方法,这里将使用不同的数据集,来自于UCI机器学习仓库:
-
从light,humidity,CO2等特征中预测房屋入住;
-
从sex,education,marital status,age和payment history几个特征中预测信用卡默认支付;
-
从混凝土生产年限和材料来预测混凝土抗压强度。
下面给出简单的Python脚本,使用Python的requests模块去UCI获取所有三个数据集:
import os
import zipfile
import requests
OCCUPANCY = ('http://bit.ly/ddl-occupancy-dataset', 'occupancy.zip')
CREDIT = ('http://bit.ly/ddl-credit-dataset', 'credit.xls')
CONCRETE = ('http://bit.ly/ddl-concrete-data', 'concrete.xls')
def download_data(url, name, path='data'):
if not os.path.exists(path):
os.mkdir(path)
response = requests.get(url)
with open(os.path.join(path, name), 'w') as f:
f.write(response.content)
def download_all(path='data'):
for href, name in (OCCUPANCY, CREDIT, CONCRETE):
download_data(href, name, path)
# Extract the occupancy zip data
z = zipfile.ZipFile(os.path.join(path, 'occupancy.zip'))
z.extractall(os.path.join(path, 'occupancy'))
path='data'
download_all(path)
运行脚本后,你会在当前工作目录下发现一个名为data文件夹,包含两个XLS文件(Excel),一个zip文件和一个包含房间入住数据的未压缩文件夹。
特征分析和选择
特征选择是机器学习的关键。对于三个样本数据集来说比较简单,因为这些数据集在上传到UCI仓库之前就已经做好了部分特征选择。但是当我们自己做机器学习时,还是必须使用统计和其它方法(比如,和领域专家交流,可视化分析)结合的方式来做特征选择。在现实情况中,我们期待可能只有几个属性需要预测而不用管其它的属性。我们也期待有些属性是冗余的(比如,两种属性的线性组合)。
在特征选择这步,我们的目标是能够找到合适的最小特征集合来达到最好的预测值。为什么呢?首先,减小特征的数量能够降低模型的复杂度,相应的也减小偏差。第二,低维度的数据集消耗更少的计算时间。最后,实践证明,基于更小的变量数据的模型更容易解释。统计方法,比如,平均值和方差,在特征拆解中是非常有用第一步。获得数据后,我们导入pandas模块,加载数据进入data frame,粗略扫一眼:
import pandas as pd
# Load the room occupancy dataset
occupancy = os.path.join('data','occupancy_data','datatraining.txt')
occupancy = pd.read_csv(occupancy, sep=',')
occupancy.columns = [
'date', 'temp', 'humid', 'light', 'co2', 'hratio', 'occupied'
]
# View the occupancy details
print(occupancy.head())
print(occupancy.describe())
# Load the credit card default dataset
credit = os.path.join('data','credit.xls')
credit = pd.read_excel(credit, header=1)
credit.columns = [
'id', 'limit', 'sex', 'edu', 'married', 'age', 'apr_delay', 'may_delay',
'jun_delay', 'jul_delay', 'aug_delay', 'sep_delay', 'apr_bill', 'may_bill',
'jun_bill', 'jul_bill', 'aug_bill', 'sep_bill', 'apr_pay', 'may_pay', 'jun_pay',
'jul_pay', 'aug_pay', 'sep_pay', 'default'
]
# View the credit details
print(credit.head())
print(credit.describe())
# Load the concrete compression data set
concrete = pd.read_excel(os.path.join('data','concrete.xls'))
concrete.columns = [
'cement', 'slag', 'ash', 'water', 'splast',
'coarse', 'fine', 'age', 'strength'
]
# View the concrete details
print(concrete.head())
print(concrete.describe())
从上面.describe() 语句的输出结果可以开始对三个数据集的不同有个大概的认识。例如,对于房间入住数据集,light和CO2释放的标准差比temperature和humidity的标准差多两个数量级。这意味着可能有必要进行归一化处理。在信用卡默认支付的数据集中,打标签(label,0代表信用卡持有者没有默认支付;1代表有默认支付)数据的分布不均衡,这意味着分类可能不平衡。
然而,如果你仅仅只是基于描述的表格来选择特征,而没有相关领域专家的指导,这个数据预测将是非常艰难的。一般在这种情况下,有过预测模型训练经验的人员经常会可视化数据集,这样他们可以清晰地看到不同特征向量的行为。下面我们将用一些常规的方法来可视化前面的三种数据集:
-
箱线图(Boxplot/violinplot);
-
直方图(histogram);
-
散点图矩阵(scatter plot matrice/splom);
-
径向坐标可视化(radviz);
-
平行坐标图(parallel coordinate);
-
双标图(jointplot)
我们将绘制图表,找出特征信号(比如,模式,可分性,特征和目标之间的关系,不同特征间的关系等等)和波动(比如,噪声量,数据分布等)。
箱线图
箱线图可以看出数据的集中趋势、分布和异常点。
import seaborn as sns
import matplotlib.pyplot as plt
sns.set_style('whitegrid')
def box_viz(df):
ax = sns.boxplot(df)
plt.xticks(rotation=60)
plt.show()
box_viz(concrete)
在上面的例子中,混凝土数据集的每个特征作为x轴,对于每个特征,我们得到了可视化的数据行为。箱线图包含数据的最大和最小四分位,箱子中间的黑线代表中指中位数,边缘线代表最大值和最小值(异常点除外),菱形代表异常点。在混凝土的数据集的箱线图中,我们可以看出大部分特征都是相似的尺度,除了“coarse” 和 “fine”。这意味着我们在开始模型训练之前进行特征的标准化预处理。
Violinplot提供了的传统箱线图,除了提供前面的信息,也反映相对密度估计,这对判断特征的可分性很有用。violin的两边显示了分类变量的分布,这对二分类特有用。使用sns.violinplot代替sns.boxplot即可绘制Violinplot图。
直方图
直方图显示根据每个特征的组距值放入不同的直条,并根据每个直条的频率来计算直条值。下面绘制信用卡默认支付数据集的年龄特征的直方图,代码如下:
def hist_viz(df,feature):
ax = sns.distplot(df[feature])
plt.xlabel(feature)
plt.show()
hist_viz(credit,'age') # We need to specify a feature vector
从上面的直方图可以看出大部分代表性的人都在40岁以下。
散点图矩阵
散点图矩阵是非常值得推荐的特征分析工具。我们在散点图中把所有特征配对(每两两特征组合画在一个矩阵中)绘制,对角一般留白或者用来显示核密度估计、直方图或者特征标注。散点图矩阵可以检查两两不同特征之间的关系。我们从散点图矩阵中找出协方差,线性关系、二次关系或者指数关系,同方差或者异方差(代表特征之间分散的程度)。下面混凝土数据集的散点图矩阵,我们可以发现 strength 和 cement 两特征间是异方差。
注意到Seaborn功能可以绘制散点图矩阵,调用sns.pairplot即可:
def splom_viz(df, labels=None):
ax = sns.pairplot(df, hue=labels, diag_kind='kde', size=2)
plt.show()
splom_viz(concrete)
径向坐标可视化(radviz)
径向坐标可视化是基于弹簧张力最小化算法。它把数据集的特征映射成二维目标空间单位圆中的一个点,点的位置由系在点上的特征决定。把实例投入圆的中心,特征会朝圆中此实例位置(实例对应的归一化数值)“拉”实例。
截至目前,径向坐标可视化在Seaborn中并未实现,所以我们结合Pandas的radviz函数和Seaborn的sns.color_palette来绘制:
from pandas.tools.plotting import radviz
def rad_viz(df,labels):
fig = radviz(df, labels, color=sns.color_palette())
plt.show()
rad_viz(occupancy.ix[:,1:],'occupied') # Specify which column contains the labels
从上面房间入住数据集的径向坐标可视化,我们能看到被标注为入住和空缺的房间有些明显的分离。并且,它显示出temperature是可预测的特征之一,因为绿色的点(空缺房间)被拉向圆中的temperature。
平行坐标图
平行坐标图,类似于radviz图,是可视化数据集聚类的方法。数据点表示为可连接的线段,x轴的单位没有实际意义,每个竖直线代表一个属性。连接线段的一个集合代表一个实例。紧挨着的点聚成一类,相同颜色的线意味着好的分散性。
跟径向坐标可视化一样,我们使用Pandas函数parallel_coordinates来绘制:
from pandas.tools.plotting import parallel_coordinates
def pcoord_viz(df, labels):
fig = parallel_coordinates(df, labels, color=sns.color_palette())
plt.show()
pcoord_viz(occupancy.ix[:,1:],'occupied') # Specify which column contains the labels
随着数据集维度的增加,即使对于专家,特征分析的挑战也会变大。坦率地讲,没有多少工具可以处理高维数据集。在Python的实现中,径向坐标可视化和radviz图对高维数据集都不是特别好扩展。
双标图(jointplot)
一般来讲,维度数目必须通过技术(比如,层次聚合,降维(例如,PCA和LDA)和维度裁剪)来减少。对于维度裁剪,可以使用散点图矩阵生成小倍数的特征。另外一种可行的办法是用双标图来检测每两两特征间的相关性。
在下面的双标图,我们检测到每个人四月份第一笔支付和九月最后一笔支付的关系。
def joint_viz(feat1,feat2,df):
ax = sns.jointplot(feat1, feat2, data=df, kind='reg', size=5)
plt.xticks(rotation=60)
plt.show()
joint_viz('apr_bill','sep_bill',credit)
结论
特征分析湿机器学习的关键步骤,随着潜在特征数量的增加,特征分析的复杂性也显著提高。但是,通过本文展示出特征选择也不是那么神秘。统计工具(比如,相关系数)和LASSO(下篇文章将会阐述)对鉴别最大预测特征的最小集合是非常有用的工具。利用像箱线图、直方图和散点图矩阵的工具和统计方法一起来可视化分析特征。可视化特征帮助我们洞察数据,这对开始机器学习是非常有用的。
通过对上面房间入住数据集、信用卡支付数据集和混凝土数据集的可视化,我们确定了什么是要预测的?什么特征能够用来做预测?通过特征分析的实践过程,可视化工具引导我们选择正确的机器学习算法。在本系列文章的第二部分,将继续以三种数据集来讨论可视化如何来促进模型选择的过程。
参考:
[1]: https://en.wikipedia.org/wiki/Anscombe%27s_quartet
[2]: http://archive.ics.uci.edu/ml/
[3]: https://stanford.edu/~mwaskom/software/seaborn/generated/seaborn.violinplot.html
[4]: https://en.wikipedia.org/wiki/Homoscedasticity
[5]: https://en.wikipedia.org/wiki/Heteroscedasticity
[6]: http://blog.districtdatalabs.com/visual-diagnostics-for-more-informed-machine-learning-part-1
备注:
一. 维度灾难(curse of dimensionality):这一概念是由贝尔曼(Bellman)在1961年首先提出,用来描述以下事实:许多在低维空间表现很好的算法,当输入数据是高维度时,计算就变得不可行。但在机器学习领域的意义:随着样本维度(即特征数目)的增长,正确泛化的难度会以指数级增加,究其原因是同等规模的训练集只能覆盖越来越少的输入空间比例。
侠天,专注于大数据、机器学习和数学相关的内容,并有个人公众号:bigdata_ny分享相关技术文章。
转载自链接:http://mp.weixin.qq.com/s?__biz=MzI0MDIxMDM0MQ==&mid=2247483684&idx=1&sn=428cf35632b2408e1dc7d36dff497c53&scene=21#wechat_redirect