写点什么

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

  • 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:128050
用户头像

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

关注

评论

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

EMQX +计算巢:构建云上物联网平台,轻松实现百万级设备连接

阿里云弹性计算

物联网 计算巢

一文带你认识AscendCL

华为云开发者联盟

人工智能 昇腾 企业号九月金秋榜

亿级别搜索系统架构与总结

goodrain

Java elasticsearch

NFT数字藏品是什么?NFT数字藏品有什么前景?

开源直播系统源码

NFT 数字藏品 数字藏品开发 数字藏品系统

跟我学Python图像处理丨何为图像的灰度非线性变换

华为云开发者联盟

Python 人工智能 图片处理 企业号九月金秋榜

Aptos VS Sui,盘点两大 Move 系新公链的创新异同

TinTinLand

区块链 公链 编程语言‘ Move

Linkerd 流量拆分方案

CTO技术共享

JPEX如期推出VISA借记卡,预计第四季度发放实体卡

股市老人

公链开发功能详细分析

开发微hkkf5566

【云原生 | Docker】腾讯云部署Django项目 (服务器选型、git配置、docker三分钟部署)

计算机魔术师

8月月更

ArkID:开源IDaaS系统插件OAuth2轻松实现单点登录高效进行应用服务集成

龙归科技

oauth2.0 SSO Idaas

NodeJs小试牛刀--聊天室搭建

zxhtom

9月月更

LeetCode两数之和的两种JavaScript解题方法比较|前端学算法

大师兄

JavaScript 算法 9月月更

室友只用了一把王者的时间就入门了「C语言」

Albert Edison

c++ C语言 函数 循环 9月月更

还晓得吗,Redis 的 zset 怎么实现的?

知识浅谈

9月月更

Go 言 Go 语,一文看懂 Go 语言文件操作

梦想橡皮擦

Python Go 9月月更

2022年最受工程师欢迎的10款抓包工具有哪些?不止Wireshark和Tcpdump哦!

wljslmz

Wireshark fiddler 网络技术 网络抓包 9月月更

谈谈我对云原生与软件供应链安全的思考

阿里巴巴中间件

阿里云 云原生 容器服务

Containerlab + Kind 部署 Cilium BGP

CTO技术共享

Python 教程之数据分析(4)—— 使用 Python 进行数据分析和可视化 | 第 1 套

海拥(haiyong.site)

Python pandas 9月月更

云原生(三十三) | Kubernetes篇之平台存储系统部署

Lansonli

云原生 9月月更

HAVE FUN | SOFA 飞船——Layotto 星球登陆计划

SOFAStack

#开源

日拱算法:典例-快慢指针解“环形链表”

掘金安东尼

前端 9月月更

直播回顾|应用上容器的最佳实践技术沙龙

BoCloud博云

云计算 容器 云原生

FinClip 8 月例行汇报,这个月干了啥

FinClip

二本4年Java经验,五面阿里(定薪45K)

退休的汤姆

Java 程序员 阿里 面经 秋招

Web3的流支付代表Zebec,熊市布局的价值逻辑

股市老人

LeetCode最长快乐字符串使用JavaScript解题

大师兄

JavaScript 面试 算法 前端 9月月更

[Go WebSocket] 你的第一个Go WebSocket服务: echo server

HullQin

Go golang 后端 websocket 9月月更

jsp入门解析

楠羽

笔记 jsp 9月月更

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