红帽白皮书新鲜出炉!点击获取,让你的云战略更胜一筹! 了解详情
写点什么

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

  • 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 年首先提出,用来描述以下事实:许多在低维空间表现很好的算法,当输入数据是高维度时,计算就变得不可行。但在机器学习领域的意义:随着样本维度(即特征数目)的增长,正确泛化的难度会以指数级增加,究其原因是同等规模的训练集只能覆盖越来越少的输入空间比例。

公众号推荐:

2024 年 1 月,InfoQ 研究中心重磅发布《大语言模型综合能力测评报告 2024》,揭示了 10 个大模型在语义理解、文学创作、知识问答等领域的卓越表现。ChatGPT-4、文心一言等领先模型在编程、逻辑推理等方面展现出惊人的进步,预示着大模型将在 2024 年迎来更广泛的应用和创新。关注公众号「AI 前线」,回复「大模型报告」免费获取电子版研究报告。

AI 前线公众号
2016-07-11 17:127838
用户头像

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

关注

评论

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

哭了,我居然回答不出来女同事的问题:索引为什么能提供查询性能---

Java 程序员 后端

万文讲解知乎实时数仓架构演进

大数据老哥

双非本科七面成功入职阿里面经分享!(附面试原题+复盘笔记)

Java 程序员 后端

【Redis源码分析专题】(1)从本质分析你写入Redis中的数据为什么不见了?

洛神灬殇

redis Redis 核心技术与实战 11月日更 缓存驱逐

吐血总结——90%程序员面试都用得上的索引优化手册

Java 程序员 后端

发量能决定一个程序员的水平吗

Java 程序员 后端

同一份数据,Redis为什么要存两次

Java 程序员 后端

吊打 ThreadLocal,谈谈FastThreadLocal为啥能这么快?

Java 程序员 后端

双非本科毕业的我,为何能在金九银十期间斩获京东、字节、快手的offer

Java 程序员 后端

企业数字化转型的起手式是什么?

百度大脑

人工智能 百度

Apache Pulsar 在 BIGO 的性能调优实战(下)

Apache Pulsar

分布式 中间件 BIGO Apache Pulsar 消息系统 Apache BookKeeper

哪有什么中年危机,不过是把定目标当成了有计划

Java 程序员 后端

可以回答一下:Redis和mysql数据是怎么保持数据一致的嘛?(1)

Java 程序员 后端

可以回答一下:Redis和mysql数据是怎么保持数据一致的嘛?

Java 程序员 后端

双非本科进不了大厂?阿里技术四面+交叉面+HR面,成功拿到offer

Java spring 程序员 mybatis

同程内网流传的分布式凤凰缓存系统手册,竟遭GitHub强行开源下载

Java 程序员 后端

听我讲完GET、POST原理,面试官给我倒了杯卡布奇诺

Java 程序员 后端

喝了杯咖啡,我突然对MySQL锁、事务、MVCC-有了新的认识!

Java 程序员 后端

原来书中说的JVM默认垃圾回收器是错的!

Java 程序员 后端

如何避免企业在碳排放数据上造假?

石云升

学习笔记 碳中和 碳交易

【高并发】SimpleDateFormat类到底为啥不是线程安全的?(附六种解决方案,建议收藏)

冰河

Java 并发编程 多线程 高并发 异步编程

网络安全漏洞复现与分析

网络安全学海

网络安全 信息安全 渗透测试 WEB安全 漏洞挖掘

同事问我如何Java实现,搞定分析栈和队列数据结构的实现过程不就好了

Java 程序员 后端

数据服务基础能力之元数据管理

数据分析 数据 元数据 数据管理 业务数据

四、StringRedisTemplate 和RedisTemlate有什么不同

Java 程序员 后端

工作五年之后,对技术和业务的思考

程序员 技术 职场 互联网人 业务

又一巅峰神作!14年工作经验大佬出品“JVM&G1 GC深入学习手册”

Java 程序员 后端

活动预告|ArchSummit全球架构师峰会

第四范式开发者社区

因为一次 Kafka 宕机,我明白了 Kafka 高可用原理!

Java 程序员 后端

史上最全Java面试266题:算法+缓存+TCP+JVM

Java 程序员 后端

同一个Spring-AOP的坑,我一天踩了两次,深坑啊

Java 程序员 后端

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