快手、孩子王、华为等专家分享大模型在电商运营、母婴消费、翻译等行业场景的实际应用 了解详情
写点什么

可视化方法对机器学习至关重要(系列)之一

  • 2016-07-11
  • 本文字数:6264 字

    阅读完需:约 21 分钟

–视觉诊断让你对机器学习了如指掌。

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 机器学习仓库

下面给出简单的 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(下篇文章将会阐述)对鉴别最大预测特征的最小集合是非常有用的工具。利用像箱线图、直方图和散点图矩阵的工具和统计方法一起来可视化分析特征。可视化特征帮助我们洞察数据,这对开始机器学习是非常有用的。

通过对上面房间入住数据集、信用卡支付数据集和混凝土数据集的可视化,我们确定了什么是要预测的?什么特征能够用来做预测?通过特征分析的实践过程,可视化工具引导我们选择正确的机器学习算法。在本系列文章的第二部分,将继续以三种数据集来讨论可视化如何来促进模型选择的过程。

译者介绍:侠天,专注于大数据、机器学习和数学相关的内容,并有个人公众号:bigdata_ny 分享相关技术文章。

若发现以上文章有任何不妥,请联系我。

查看英文原文: Visual Diagnostics for More Informed Machine Learning: Part 1

备注:

一. 维度灾难(curse of dimensionality):这一概念是由贝尔曼(Bellman)在 1961 年首先提出,用来描述以下事实:许多在低维空间表现很好的算法,当输入数据是高维度时,计算就变得不可行。但在机器学习领域的意义:随着样本维度(即特征数目)的增长,正确泛化的难度会以指数级增加,究其原因是同等规模的训练集只能覆盖越来越少的输入空间比例。

2016-07-11 17:127994
用户头像

发布了 43 篇内容, 共 28.4 次阅读, 收获喜欢 7 次。

关注

评论

发布
暂无评论
发现更多内容

第七周命题作业

orchid9

三周学习总结

水浴清风

第七周作业

极客大学架构师训练营

第8周作业

静海

Architecture Phase1 Week7:HomeWork

phylony-lu

极客大学架构师训练营

第七周总结

睁眼看世界

极客大学架构师训练营

第七周架构师训练学习笔记

郎哲158

极客大学架构师训练营

一期二班-吴水金-第五课总结

吴水金

手写单例

落朽

架构师训练营 - 第 7 周课后作业 -性能压测

树森

「架构师训练营第 1 期」第七周作业

张国荣

架构师训练营第三周作业-手写单例模式

张浩

架构训练营第三周作业

小兵

架构师训练营第三周总结

张浩

架构师训练营—第七周学习总结

orchid9

架构师训练营第 1 期 week7 总结

张建亮

极客大学架构师训练营

架构师训练营第七周作业

郎哲158

极客大学架构师训练营

架构师 01 期,第七周课后作业

子文

性能压测的时候,随着并发压力的增加,系统响应时间和吞吐量如何变化,为什么?

知行合一

工厂方法模式

猴子胖胖

设计模式 Go 语言

架构是训练营-第三周总结

架构师训练营-单例模式

架构师训练营week07总结

FG佳

训练营第七周作业2

仲夏

极客时间 - 架构师一期 - 第七周作业

_

极客大学架构师训练营 第七周作业

第七周作业(作业一)

Geek_83908e

极客大学架构师训练营

第三周作业

皮蛋

架构师

架构师训练营-第七周

袭望

服务器性能监控神器nmon使用介绍

MySQL从删库到跑路

Linux nmon 性能监控

架构师训练营 Week03 作业-手写单例模式

训练营第七周作业 1

仲夏

极客大学架构师训练营

可视化方法对机器学习至关重要(系列)之一_语言 & 开发_Rebecca Bilbro_InfoQ精选文章