目录
2.4 提琴形图@数值特征-sns.violinplot()
3.1.2 散点图-plt.scatter()或sns.jointplot()
1、介绍
在机器学习领域中,可视化是十分重要的。在开始一项新任务时,通过可视化手段探索数据能更好地帮助人们把握数据的要点。在分析模型表现和模型报告的结果时,可视化能使分析显得更加生动鲜明。有时候,为了理解复杂的模型,我们还可以将高维空间映射为视觉上更直观的二维或三维图形。
总而言之,可视化是一个相对快捷的从数据中挖掘信息的手段。本文将使用 Pandas、Matplotlib、seaborn 等流行的库
2、单变量可视化
2.1 直方图@数值特征
直方图依照相等的间隔将值分组为柱,它的形状可能包含了数据分布的一些信息,如高斯分布、指数分布等。当分布总体呈现规律性,但有个别异常值时,你可以通过直方图辨认出来。当你使用的机器学习方法预设了某一特定分布类型(通常是高斯分布)时,知道特征值的分布是非常重要的。
2.1.1 DataFrame的hist()方法
最简单的查看数值变量分布的方法是使用 DataFrame 的hist() 方法绘制直方图。
DataFrame.hist(column=None, by=None, grid=True, xlabelsize=None, xrot=None, ylabelsize=None, yrot=None, ax=None, sharex=False, sharey=False, figsize=None, layout=None, bins=10, backend=None, legend=False, **kwargs)[source]
# 方法一:df.hist()
features = ["Total day minutes","Total intl calls"]
df[features].hist(figsize=(10,4))
# 方法二:df.plot()
df[features].plot(kind="hist")
上图表明,变量 Total day minutes 每日通话时长 呈高斯分布,而 Total intl calls 总国际呼叫数 显著右倾(它右侧的尾巴更长)。
2.1.2 seaborn的distploy()实现
sns.distplot(df['Total intl calls'],kde=False,bins=8)
2.1.3 matplotlib的dist()方法
plt.hist(df['Total intl calls'])
2.2 密度图@数值特征
密度图(density plots),也叫核密度图(KDE)是理解数值变量分布的另一个方法。它可以看成是直方图平滑的版本。相比直方图,它的主要优势是不依赖于柱的尺寸,更加清晰。
2.2.1 DataFrame的plot()实现
df[features].plot(kind="density",subplots=True,layout=(1, 2),
sharex=False,figsize=(10,4),legend=False,title=features)
2.2.2 seaborn的distploy()实现
使用 seaborn 的 distplot() 方法观测数值变量的分布。默认情况下,该方法将同时显示直方图和密度图。
seaborn.distplot(a=None, bins=None, hist=True, kde=True, rug=False, fit=None, hist_kws=None, kde_kws=None, rug_kws=None, fit_kws=None, color=None, vertical=False, norm_hist=False, axlabel=None, label=None, ax=None, x=None)
2.3 箱型图@数值特征-sns.boxplot()
箱形图的主要组成部分是箱子(box),须(whisker)和一些单独的数据点(离群值),分别简单介绍如下:
- 箱子显示了分布的四分位距,它的长度由 25𝑡ℎ(Q1,下四分位数) 和 75𝑡ℎ(Q3,上四分位数) 决定,箱中的水平线表示中位数 (50%)。
- 须是从箱子处延伸出来的线,它们表示数据点的总体散布,具体而言,是位于区间 (Q1−1.5⋅IQR,Q3+1.5⋅IQR)的数据点,其中 IQR=Q3−Q1,也就是四分位距。
- 离群值是须之外的数据点,它们作为单独的数据点,沿着中轴绘制。
使用 seaborn 的 boxplot() 方法绘制箱形图
sns.boxplot(x='Total intl calls', data=df)
sns.boxplot(df["Total intl calls"])
上图表明,在该数据集中,大量的国际呼叫是相当少见的。
sns.boxplot(x="International plan",y="Total intl calls",data=df,
hue="Voice mail plan",palette="Set3")
2.4 提琴形图@数值特征-sns.violinplot()
提琴形图和箱形图的区别是,提琴形图聚焦于平滑后的整体分布,而箱形图显示了单独样本的特定统计数据。
使用 violinplot() 方法绘制提琴形图。下图左侧是箱形图,右侧是提琴形图。
_, axes = plt.subplots(1,2,sharey=True, figsize=(6,4))
sns.boxplot(data=df["Total intl calls"], ax=axes[0])
sns.violinplot(data=df["Total intl calls"], ax=axes[1])
一般来说,小提琴图是一种绘制连续型数据的方法,可以认为是箱形图与核密度图的结合体
2.5 条形图@类别特征-sns.countplot()
频率表的图形化表示是条形图。创建条形图最简单的方法是使用 seaborn的 countplot() 函数。让我们来画出两个分类变量的分布。
seaborn.countplot(*, x=None, y=None, hue=None, data=None, order=None, hue_order=None, orient=None, color=None, palette=None, saturation=0.75, dodge=True, ax=None, **kwargs)
_, axes = plt.subplots(nrows=1,ncols=2,figsize=(12,4))
sns.countplot(x="Churn",data=df,ax=axes[0])
sns.countplot(x="Customer service calls", data=df, ax=axes[1])
条形图和直方图的区别如下:
- 直方图适合查看数值变量的分布,而条形图用于查看类别特征。
- 直方图的 X 轴是数值;条形图的 X 轴可能是任何类型,如数字、字符串、布尔值。
- 直方图的 X 轴是一个笛卡尔坐标轴;条形图的顺序则没有事先定义。
2.6 频率表@类别特征-value_counts()
df['Churn'].value_counts()
3、多变量可视化
多变量(multivariate)图形可以在单张图像中查看两个以上变量的联系,和单变量图形一样,可视化的类型取决于将要分析的变量的类型。
3.1 数值与数值特征
3.1.1 相关矩阵-corr()和heatmap()
相关矩阵可揭示数据集中的数值变量的相关性。这一信息很重要,因为有一些机器学习算法(比如,线性回归和逻辑回归)不能很好地处理高度相关的输入变量。
首先,我们使用 DataFrame 的 corr() 方法计算出每对特征间的相关性。接着,我们将所得的相关矩阵(correlation matrix)传给 seaborn 的 heatmap()方法,该方法根据提供的数值,渲染出一个基于色彩编码的矩阵。
seaborn.heatmap(data, vmin=None, vmax=None, cmap=None, center=None, robust=False, annot=None, fmt='.2g', annotkws=None, linewidths=0, linecolor='white', cbar=True, cbarkws=None, cbar_ax=None, square=False, ax=None, xticklabels=True, yticklabels=True, mask=None, **kwargs)
# 丢弃非数值变量
numerical = list(set(df.columns) -
set(['State', 'International plan', 'Voice mail plan',
'Area code', 'Churn', 'Customer service calls']))
# 计算和绘图
corr_matrix = df[numerical].corr()
sns.heatmap(corr_matrix,cmap="rainbow")
3.1.2 散点图-plt.scatter()或sns.jointplot()
散点图(scatter plot)将两个数值变量的值显示为二维空间中的笛卡尔坐标(Cartesian coordinate)。
3.1.2.1 matplotlib方法-plt.scatter()
通过 matplotlib 库的 scatter() 方法可以绘制散点图。
plt.scatter(df['Total day minutes'], df['Total night minutes'])
3.1.2.2 seaborn方法-sns.jointplot()
seaborn 库的 jointplot() 方法在绘制散点图的同时会绘制两张直方图,某些情形下它们可能会更有用。
sns.jointplot(x='Total day minutes', y='Total night minutes',
data=df, kind='scatter')
jointplot() 方法还可以绘制平滑过的散点直方图
sns.jointplot('Total day minutes', 'Total night minutes', data=df,
kind="kde", color="g")
上图基本上就是之前讨论过的核密度图的双变量版本。
3.1.3 散点图矩阵-sns.pairplot()
在某些情形下,我们可能想要绘制如下所示的散点图矩阵(scatterplot matrix)。它的对角线包含变量的分布,并且每对变量的散点图填充了矩阵的其余部分。
%config InlineBackend.figure_format = 'png'
sns.pairplot(df[numerical])
3.2 数值和类别的可视化
3.2.1 散点图-sns.lmplot()
为了让图形更有趣一点,可以尝试从数值和类别特征的相互作用中得到预测 Churn 的新信息,更具体地,让我们看看输入变量和目标变量 Churn 的关系。使用 lmplot() 方法的 hue 参数来指定感兴趣的类别特征。
sns.lmplot("Total day minutes", "Total night minutes",
data=df, hue="Churn", fit_reg=False)
3.2.2 箱线图-sns.boxplot()
3.2.3 提琴形图-sns.violinplot()
创建箱型图和提琴形图,查看忠实客户和不忠实客户的日通话分钟数。
_, axes = plt.subplots(1, 2, sharey=True, figsize=(10, 4))
sns.boxplot(x='Churn', y='Total day minutes', data=df, ax=axes[0])
sns.violinplot(x='Churn', y='Total day minutes', data=df, ax=axes[1])
3.3 类别与类别可视化
3.3.1 条形图-countplot()
使用 countplot() 方法查看客服呼叫数的分布,这次传入 hue=Churn 参数,以便在图形中加入类别维度。
sns.countplot(x="Customer service calls", hue="Churn", data=df)
3.3.2 交叉表-crosstab()
交叉表(cross tabulation),即使用表格形式表示多个类别变量的频率分布。通过它可以查看某一列或某一行以了解某个变量在另一变量的作用下的分布情况。
pd.crosstab(df["State"],df["Churn"]).T
3.3.3 类中统计值评估图-sns.catplot()
seaborn.catplot(*, x=None, y=None, hue=None, data=None, row=None, col=None, col_wrap=None, estimator=<function mean at 0x7ff320f315e0>, ci=95, n_boot=1000, units=None, seed=None, order=None, hue_order=None, row_order=None, col_order=None, kind='strip', height=5, aspect=1, orient=None, color=None, palette=None, legend=True, legend_out=True, sharex=True, sharey=True, margin_titles=False, facet_kws=None, **kwargs)
df_uniques
sns.catplot(x='variable', y='count', hue='value', data=df_uniques, kind='bar', height=12)
3.3.4 结构化多绘图网格-FacetGrid()
在探索中等维数据时,一种有用的方法是在数据集的不同子集上绘制同一图的多个实例。这种技术有时被称为“格子”或“格子”绘图,它与“小倍数”的概念有关。
FacetGrid当您想要在数据集的子集中分别可视化变量的分布或多个变量之间的关系时,该类非常有用。一个FacetGrid可以与多达三个维度可以得出:row,col,和hue。前两个与得到的轴阵列有明显的对应关系; 将色调变量视为沿深度轴的第三个维度,其中不同的级别用不同的颜色绘制
df.head()
sns.FacetGrid(df, hue="gender", height=12) \
.map(sns.kdeplot, "height").add_legend()
sns.FacetGrid(df, col="gluc",hue="gender", height=12) \
.map(sns.kdeplot, "height").add_legend()
4、全局数据集可视化
4.1 降维
大多数现实世界的数据集有很多特征,每一个特征都可以被看成数据空间的一个维度。因此,我们经常需要处理高维数据集,然而可视化整个高维数据集相当难。为了从整体上查看一个数据集,需要在不损失很多数据信息的前提下,降低用于可视化的维度。这一任务被称为降维(dimensionality reduction)。降维是一个无监督学习(unsupervised learning)问题,因为它需要在不借助任何监督输入(如标签)的前提下,从数据自身得到新的低维特征。
主成分分析(Principal Component Analysis, PCA)是一个著名的降维方法,我们会在之后的课程中讨论它。但主成分分析的局限性在于,它是线性(linear)算法,这意味着对数据有某些特定的限制。
与线性方法相对的,有许多非线性方法,统称流形学习(Manifold Learning)。著名的流形学习方法之一是 t-SNE。
4.2 t-SNE
它的基本思路很简单:为高维特征空间在二维平面(或三维平面)上寻找一个投影,使得在原本的 n 维空间中相距很远的数据点在二维平面上同样相距较远,而原本相近的点在平面上仍然相近。
该数据库创建一个 t-SNE 表示,首先加载依赖。
from sklearn.manifold import TSNE
from sklearn.preprocessing import StandardScaler
#去除 State 州 和 Churn 离网率 变量,然后用 pandas.Series.map() 方法将二元特征的「Yes」/「No」转换成数值。
X = df.drop(["State","Churn"],axis=1)
X['International plan'] = X['International plan'].map({'Yes': 1, 'No': 0})
X['Voice mail plan'] = X['Voice mail plan'].map({'Yes': 1, 'No': 0})
#使用 StandardScaler() 方法来完成归一化数据
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
tsne = TSNE(random_state=17)
tsne_repr = tsne.fit_transform(X_scaled)
plt.scatter(tsne_repr[:, 0], tsne_repr[:, 1],
c=df['Churn'].map({False: 'blue', True: 'orange'}), alpha=.5)
5、其他可视化
5.1 分类边界-plt.pcolormesh()
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_iris
iris = load_iris()
data = np.c_[iris.data,iris.target]
iris_feature = u'花萼长度', u'花萼宽度', u'花瓣长度', u'花瓣宽度',u'类别'
data = pd.DataFrame(data,columns=iris_feature)
data['类别']=pd.Categorical(data['类别']).codes
x_train = data[['花萼长度','花瓣长度']]
y_train = data['类别']
model = DecisionTreeClassifier(criterion='entropy', min_samples_leaf=3)
model.fit(x_train, y_train)
N, M = 500, 500 # 横纵各采样多少个值
x1_min, x2_min = x_train.min(axis=0)
x1_max, x2_max = x_train.max(axis=0)
t1 = np.linspace(x1_min, x1_max, N)
t2 = np.linspace(x2_min, x2_max, M)
x1, x2 = np.meshgrid(t1, t2) # 生成网格采样点
x_show = np.stack((x1.flat, x2.flat), axis=1) # 测试点
y_predict=model.predict(x_show)
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False
cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])
plt.xlim(x1_min, x1_max)
plt.ylim(x2_min, x2_max)
plt.pcolormesh(x1, x2, y_predict.reshape(x1.shape), cmap=cm_light)
plt.scatter(x_train['花萼长度'],x_train['花瓣长度'],c=y_train,cmap=cm_dark,marker='o',edgecolors='k')
plt.xlabel('花萼长度')
plt.ylabel('花瓣长度')
plt.title('鸢尾花分类')
plt.grid(True,ls=':')
plt.show()
5.2 绘制分类轮廓-plt.countour()
def plot_boundary(clf, X, y, grid_step=.01, poly_featurizer=None):
x_min, x_max = X[:, 0].min() - .1, X[:, 0].max() + .1
y_min, y_max = X[:, 1].min() - .1, X[:, 1].max() + .1
xx, yy = np.meshgrid(np.arange(x_min, x_max, grid_step),
np.arange(y_min, y_max, grid_step))
# 在 [x_min, m_max]x[y_min, y_max] 的每一点都用它自己的颜色来对应
Z = clf.predict(poly_featurizer.transform(np.c_[xx.ravel(), yy.ravel()]))
Z = Z.reshape(xx.shape)
plt.contour(xx, yy, Z, cmap=plt.cm.Paired)
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(degree=7)
X_poly = poly.fit_transform(X)
C = 1e-2
logit = LogisticRegression(C=C, random_state=17)
logit.fit(X_poly, y)
plot_boundary(logit, X, y, grid_step=.01, poly_featurizer=poly)
plt.scatter(X[y == 1, 0], X[y == 1, 1], c='blue', label='Released')
plt.scatter(X[y == 0, 0], X[y == 0, 1], c='orange', label='Faulty')
plt.xlabel("Test 1")
plt.ylabel("Test 2")
plt.title('2 tests of microchips. Logit with C=%s' % C)
plt.legend()
print("Accuracy on training set:",
round(logit.score(X_poly, y), 3))