在机器学习领域中,可视化并不仅仅用来制作漂亮的报表。项目的各个阶段都大量使用可视化技术。
在开始一项新任务时,通过可视化手段探索数据往往是任务的第一步。我们通过图表汇总数据,放弃无关紧要的细节。相比直接阅读许多行原始数据,可视化能更好地帮助人类把握数据的要点。令人惊叹的是,仅仅通过可视化工具创建一些看上去再简单不过的图表,就能获得大量洞见。
接着,在分析模型表现和模型报告的结果时,我们也常常使用可视化。有时候,为了理解复杂的模型,我们需要将高维空间映射为视觉上更直观的二维或三维图形。
总而言之,可视化是一个相对快捷的从数据中获取新知的手段。因此,学习这一极为重要的技术,并将其纳入你的日常机器学习工具箱,是至关重要的。
本文将使用pandas、matplotlib和seaborn等流行的库,带你上手可视化。
概览
数据集
单变量可视化数量和类型分布
多变量可视化变量间的相互作用
全数据集一窥高维空间
作业二
1.数据集
首先初始化环境:
importnumpyasnp
importpandasaspd
#禁用Anaconda警告
importwarnings
#在JupyterNotebook内部显示图形
%matplotlibinline
importmatplotlib.pyplotasplt
#我们将使用Seaborn库
importseabornassns
sns.set()
#SVG格式的图像更清晰
#增加默认的绘图尺寸
df.head()
数据集的特征:
2.单变量可视化
下面我们将考虑不同统计类型的变量,以及相应的可视化工具。
2.1数量特征
数量特征(quantitativefeature)的值为有序数值。这些值可能是离散的,例如整数,也可能是连续的,例如实数,通常用于表示技术和度量。
直方图和密度图
df[features].hist(figsize=(12,4));
直方图依照相等的范围将值分组为柱。直方图的形状可能包含了数据分布的线索:高斯、指数,等等。当分布基本上很有规律,但有一些异常值时,你也可以通过直方图辨认出形状的歪斜之处。当你使用预设某一特定分布类型(通常是高斯)的机器学习方法时,知道特征值的分布是非常重要的。
在以上图形中,我们看到变量Totaldayminutes(每日通话时长)呈正态分布(译者注:正态分布即高斯分布),而Totalintlcalls(总国际呼叫数)显著右倾(它右侧的尾巴更长)。
除了直方图,理解分布的另一个(经常更清楚的)方法是密度图(densityplots),也叫(更正式的名称)核密度图(KernelDensityPlots)。它们可以看成是直方图平滑过的版本。相比直方图,它们的主要优势是不依赖于柱的尺寸。让我们为上面两个变量创建密度图:
layout=(1,2),sharex=False,figsize=(12,4));
我们也可以使用seaborn的distplot()方法绘制观测数据的分布。例如,Totaldayminutes(每日通话时长)的分布。默认情况下,图形将同时显示直方图和核密度估计(kerneldensityestimation,KDE)。
这里直方图的柱形的高度已经归一过了,表示的是密度而不是样本数。
箱形图
箱形图(boxplot)是另一种有用的可视化图形。使用seaborn绘制箱形图:
_,ax=plt.subplots(figsize=(3,4))
箱形图的主要组成部分是箱子(box)(显然,这是它被称为箱形图的原因),须(whisker)和一些单独的数据点(离群值)。
箱子显示了分布的四分位距;它的长度由25%(Q1,下四分位数)和75%(Q3,上司分位数)决定。箱中的水平线表示中位数(50%)。
从箱子处延伸出来的线被称为须。它们表示数据点的总体散布,具体而言,是位于区间(Q1-1.5xIQR,Q3+1.5xIQR)的数据点,其中IQR=Q3-Q1,也就是四分位距。
离群值是须之外的数据点,它们作为单独的数据点,沿着中轴绘制。
我们可以看到,在我们的数据中,大量的国际呼叫是相当少见的。
提琴形图
我们最后考虑的分布图形是提琴形图(violinplot)。
下图左侧是箱形图,右侧是提琴形图。
_,axes=plt.subplots(1,2,sharey=True,figsize=(6,4))
箱形图和提琴形图的区别是,箱形图显示了单独样本的特定统计数据,而提琴形图聚焦于平滑后的整体分布。
describe()
图形工具之外,我们可以使用DataFrame的describe()方法来获取分布的精确数值统计:
df[features].describe()
describe()的输出基本上是自解释性的。
2.2类别和二元特征
类别特征(categoricalfeaturestake)具有固定数目的值。每个值将一个观测数据分配到相应的组,这些组称为类别(category)。类别反映了样本的某个定性属性。二元(binary)变量是一个重要的类别变量的特例,其中类别的可能值正好为2.如果类别变量的值具有顺序,称为有序(ordinal)类别变量。
频率表
让我们查看下数据集的分类平滑:目标变量离网率的分布。首先,我们使用value_counts()得到一张频率表:
False2850
True483
Name:Churn,dtype:int64
默认情况下,频率由高到低排列。
条形图
频率表的图形化表示是条形图。创建条形图最简单的方法是使用seaborn的countplot()函数。seaborn中还有一个函数,起了一个令人困惑的名字(barplot()),barplot()绝大部分情况下用于表示以某个类别特征分组的数值变量的一些基本统计数据。
_,axes=plt.subplots(nrows=1,ncols=2,figsize=(12,4))
尽管条形图和上面提到的直方图看起来很像,它们是不一样的:
直方图用于查看数值变量的分布,而条形图用于类别特征。
直方图的X轴是数值;条形图的X轴可能是任何类型:数字、字符串、布尔值。
直方图的X轴是一根笛卡尔坐标轴;条形的顺序没有事先定义。不过,值得注意的是,条形经常按照高度排序,也就是值的频率。同时,当我们考虑有序变量(例如Customerservicecalls(客服呼叫数))时,条形通常按照变量的值排序。
3.多变量可视化
多变量(multivariate)图形让我们得以在单张图像中查看两个以上变量的联系。和单变量图形一样,可视化的类型取决于将要分析的变量的类型。
3.1数量——数量
我们先来看看数量变量之间的相互作用。
#丢弃非数值变量
numerical=list(set(df.columns)-
#计算和绘图
corr_matrix=df[numerical].corr()
sns.heatmap(corr_matrix);
numerical=list(set(numerical)-
散点图
散点图(scatterplot)将两个数值变量的值显示为二位空间中的笛卡尔坐标(Cartesiancoordinate)。还有三维的散点图。
让我们试下matplotlib库的scatter()方法:
seaborn库创建的散点图有一个略微奇特的选项:
jointplot()函数绘制了两张直方图,某些情形下它们可能会有用。这一函数还可以让我们绘制平滑过的jointplot:
data=df,kind="kde",color="g");
这个基本上是我们之前讨论过的核密度图的双变量版本。
散点图矩阵
在某些情形下,我们可能想要绘制如下所示的散点图矩阵(scatterplotmatrix)。它的对角线包含变量的分布,而每对变量的散点图填充了矩阵的其余部分。
#使用SVG格式可能导致pairplot变得非常慢
sns.pairplot(df[numerical]);
有时候,这样的可视化可能帮我们从数据中得出一些结论。
3.2数量——类别
在这一小节中,让我们的图形更有趣一点。我们将尝试从数值和类别特征的相互作用中得到离网预测的新洞见。
更具体地,让我看看输入变量和目标变量离网的关系。
现在,让我们创建箱形图,以可视化两个互斥分组中的数值变量分布的统计数据:忠实客户(Churn=False)和离网客户(Churn=True)。
#有时我们可以将有序变量作为数值变量分析
fig,axes=plt.subplots(nrows=3,ncols=4,figsize=(10,7))
foridx,featinenumerate(numerical):
ax=axes[int(idx/4),idx%4]
ax.set_ylabel(feat)
fig.tight_layout();
从这一图表中,我们可以看到,两组之间分歧最大的分布是这三个变量:Totaldayminutes(日通话分钟数)、Customerservicecalls(客服呼叫数)、Numbervmailmessages(语音邮件数)。在后续的课程中,我们将学习如何使用随机森林(RandomForest)或梯度提升(GradientBoosting)来判定特征对分类的重要性;那时我们将看到,前两个特征对于离网预测而言确实非常重要。
让我们分别看下忠实客户和不忠实客户的日通话分钟数。我们将创建箱形图和提琴形图。
_,axes=plt.subplots(1,2,sharey=True,figsize=(10,4))
data=df,ax=axes[0]);
data=df,ax=axes[1]);
当我们想要一次分析两个类别维度下的数量变量时,可以用seaborn库的factorplot()函数。例如,在同一图形中可视化Totaldayminutes(日通话分钟数)和两个类别变量的相互作用:
kind="box",col_wrap=4,size=3,aspect=.8);
从上图我们可以总结出,从4次呼叫开始,Totaldayminutes(日通话分钟数)可能不再是客户离网的主要因素。也许,除了我们之前猜测的话费,有些客户因为其他问题对服务不满意,或许这导致了日通话分钟数较少。
3.3类别——类别
正如我们之前提到的,变量Customerservicecalls(客服呼叫数)的唯一值极少,因此,既可以看成数值变量,也可以看成有序类别变量。我们已经通过计数图(countcplot)查看过它的分布了。现在我们感兴趣的是这一有序特征和目标变量Churn(离网)之间的关系。
让我们再一次使用计数图看下客服呼叫数的分布。这次,我们同时传入hue=Churn参数,以便在图形中加入类别维度:
观察:呼叫客服达到4次以上后,离网率显著增加了。
现在让我们看下Churn(离网)和二元特征Internationalplan(国际套餐)、Voicemailplan(语音邮件套餐)的关系。
观察:开通国际套餐后,离网率会高很多;使用国际套餐是一个强烈的特征。我们在语音邮件套餐上没有观察到相同的效应。
列联表
让我们通过交叉制表看看Churn(离网)和类别变量State(州)的关系:
State(州)的不同值很多:51.我们看到每个周只有少量数据点——每个州只有3到17个客户抛弃了运营商。让我们暂时忽略这一点,计算每个州的离网率,由高到低排列:
agg([np.mean]).
4.全数据集
4.1幼稚方法
上面我们查看了数据集的不同刻面(facet),猜测感兴趣的特征,每次选择其中的一小部分进行可视化。我们一次仅仅处理两到三个变量,能比较容易地观察到数据的结构和关系。但是,如果我们想一下子显示所有特征呢?如何确保最终的可视化仍然是可解释的?
我们可以为整个数据集使用hist()或者pairplot()方法,同时查看所有的特征。不过,当特征数目足够多的时候,这样的可视化分析很快就变得缓慢和低效。另外,我们其实仍然可以成对地分析变量,而不用一下子分析所有变量。
4.2降维
大多数现实世界的数据集有很多特征,有时有上万个特征。每一个特征都可以被看成数据点空间的一维。因此,我们经常需要处理高维数据集,可视化整个高维数据集相当难。
为了从整体上查看一个数据集,我们需要在不损失很多数据信息的前提下,降低用于可视化的维度。这一任务称为降维(dimensionalityreduction)。降维是一个无监督学习(unsupervisedlearning)问题,因为我们需要在不借助任何监督输入的前提下,从数据自身得到新的低维特征。
有许多非线性方法,统称流形学习(ManifoldLearning)。最著名的流形学习方法之一是t-SNE。
4.3t-SNE
让我们为离网数据创建一个t-SNE表示。
这一方法的名字看起来很复杂,有些吓人:t分布随机近邻嵌入(t-distributedStohasticNeighborEmbedding)。它的数学也很令人印象深刻(我们不会在这里深究数学,勇敢的读者可以阅读LaurensvanderMaaten和GeoffreyHinton在JMLR上发表的原论文)。它的基本思路很简单:为高维特征空间在二维平面(或三维超平面,不过基本上总是使用二维空间)上寻找一个投影,使得在原本的n维空间中相距很远的数据点在屏幕上同样相距较远。而原本相近的点在平面上仍然相近。
本质上,近邻嵌入寻找保留了样本的邻居关系的新的维度较低的数据表示。
现在让我们做些练习。首先,加载类:
fromsklearn.manifoldimportTSNE
fromsklearn.preprocessingimportStandardScaler
我们去除State(州)和离网(Churn)变量,然后用pandas.Series.map()方法将二元特征的“Yes”/“No”转换成数值:
我们同样需要归一化数据。我们从每个变量中减去均值,然后除以标准差。这些都可以使用StandardScaler来完成。
scaler=StandardScaler()
现在可以构建t-SNE表示了:
tsne=TSNE(random_state=17)
tsne_repr=tsne.fit_transform(X_scaled)
然后可视化它的图形:
plt.scatter(tsne_repr[:,0],tsne_repr[:,1]);
让我们根据离网情况给t-SNE表示加上色彩(绿色表示忠实用户,红色表示不忠实用户)。
plt.scatter(tsne_repr[:,0],tsne_repr[:,1],
我们可以看到,离网的客户集中在低维特征空间的一小部分区域。
为了更好地理解这一图像,我们可以使用剩下的两个二元特征给图像着色:Internationalplan(国际套餐)和Voicemailplan(语音邮件套餐)。绿色代表相应的二元特征是正值。
_,axes=plt.subplots(1,2,sharey=True,figsize=(12,5))
axes[i].scatter(tsne_repr[:,0],tsne_repr[:,1],
axes[i].set_title(name)
现在很清楚了,许多退订的不满意客户集中在西南聚类(表示开通了国际套餐但没有开通语音邮件套餐)。
最后,让我们了解下t-SNE的缺陷:
高计算复杂度。scikit-learn的实现在真实任务中往往不太管用。如果你有大量样本,你应该转而使用Multicore-TSNE(多核)。
偶尔,t-SNE可以让你从数据中得到非常好的直觉。下面的论文展示了一个这样的例子:VisualizingMNIST(可视化MNIST)。
有时t-SNE真的能够帮助你更好地理解数据,有时t-SNE能够帮助你画出圣诞树玩具:-)
用t-SNE)
原文标题:机器学习开放课程(二):使用Python可视化数据
长沙市望城经济技术开发区航空路6号手机智能终端产业园2号厂房3层(0731-88081133)