[可视化]探索性数据2 双变量
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sb
一、双变量
提纲
数据类型 数值变量 vs 数值变量 散点图scatterplots plt.scatter()sb.regplot()数值变量 vs 分类变量 小提琴图violin plot sb.violinplot()
箱线图box plotsb.boxplot()分类变量 vs 分类变量 分组条形图clustered bar charts(基于单变量条形图) sb.countplot(, hue=)二维直方图/条形图 热图heat maps plt.hist2d()
技巧 分面:降维描述 sb.FacetGrid()调整后的条形图bar charts 使用第二个变量的平均值而非数据统计 sb.barplot(, x= , y=, ci= )sb.pointplot(, x=, y=)调整后的直方图 plt.hist(, x=, weights=)折线图line plots plt.errorbar()
补充图形 Q-Q 图 当数据分布不符合正态分布时 蜂群图Swarm Plots sb.swarmplot()轴须图Rug Plot sb.rugplot()带状图Strip Plot sb.stripplot()叠嶂图Ridgeline Plot g = sb.FacetGrid()g.map()堆积图 前提:总量保持一致(比如100%)
1.1 散点图(数值 vs 数值)
plt.scatter(data = df, x = 'num_var1', y = 'num_var2')
plt.scatter(x, y, s=None, c=None, marker=None,
cmap=None, norm=None, vmin=None, vmax=None, alpha=None,
linewidths=None, verts=None, edgecolors=None, hold=None,
data=None, **kwargs)
#参数c:颜色,可以设置颜色列表 'blue' 'red'
#参数s:图片缩放比例
#参数**kwargs
#参数label="Luck" 幸运三叶草
sb.regplot(data = df, x = 'num_var1', y = 'num_var2')
#线性相关性:皮尔逊相关系数r
#参数reg_fit 回归拟合
sb.regplot(x, y, data=None, x_estimator=None, x_bins=None,
x_ci='ci', scatter=True, fit_reg=True, ci=95, n_boot=1000, units=None,
order=1, logistic=False, lowess=False, robust=False, logx=False,
x_partial=None, y_partial=None, truncate=False, dropna=True,
x_jitter=None, y_jitter=None, label=None, color=None, marker='o',
scatter_kws=None, line_kws=None, ax=None)
#seaborn的散点图高端了一点,包含了可以绘制拟合线和置信区间等额外功能
#参数color:设置颜色
#参数fit_reg:是否绘制拟合线和执行区间,注意并非课程中的reg_fit哦
#参数scatter:是否显示散点
#参数ci:执行区间大小 [0, 100]
可以创建具有回归拟合的散点图,默认的回归函数是线性回归,并且包含回归估计置信区间(阴影部分)sb.regplot()
- 问题:数据重叠overplotting
1). 透明度
plt.scatter(alpha= )
sb.regplot(scatter_kws = {'alpha' : 1/3})
2). 抖动
sb.regplot(x_jitter = 0.2, y_jitter = 0.2)
每个点在真实值的 ±0.2 范围内抖动
3). 随机减少采样点
1.2 热图(直方图: 数值 vs 数值; 条形图: 分类 vs 数值)
直方图的二维版本,可以替代散点图
和散点图一样,要绘制的两个数值变量位于两个坐标轴上
和直方图类似,图表区域被划分为网格,累计每个网格的数据点数量
因为没有空间表示条形的高度,因此用网格颜色表示计数
plt.hist2d(data, x, y, bins, cmap, cmin)
#参数cmin 单元格要绘制出来的数据的下限值(关注核心数据)
#单元格添加注释 plt.text(x轴位置,y轴位置,数值, ha, va, color)
plt.hist2d(data = df, x = '', y ='', bins=[bins_x, bins_y], cmap, cmin)
plt..hist2d(x, y, bins=10, range=None, normed=False, weights=None, cmin=None, cmax=None, hold=None, data=None, **kwargs)
#返回一个2d数组h2d[0](热图颜色值),和两个1d的分组边界值h2d[1]、h2d[2],plt.QuadMesh h2d[3]
#h2d[0].shape[0] x轴==行方向
#h2d[0].shape[1] y轴==列方向
#h2d[0][i][j]表示二维图(i, j)位置的数值(颜色值)
#参数x,y, bins(设置方式也跟hist一致,只是是二维,因为要设置x和y的bins)
#参数cmin:设置多少count以下记为空,那么就不会被填充颜色
#参数cmax:就是大于多少就会被记为空,不填充颜色
plt.colorbar(mappable=None, cax=None, ax=None, **kw)
#只对当前图表生效,所以要想多个生效就得每个图表下跟一个
如果散点太离散,或者数据点的数据量太密集,透明度已经不足以使用的情况下,可以用热图:
热图:优秀示例
sb.heatmap(data_adjusted, annot = True, fmt = 'd')
#参数annot = True 可以在每个单元格中显示注释
#参数fmt = 'd' 表示注释将变成整数形式;为了避免有些类别没有数量,要显示出 NaN 值,你可以设置 fmt = '.0f'
seaborn.heatmap(data, vmin=None, vmax=None, cmap=None,
center=None, robust=False, annot=None, fmt='.2g', annot_kws=None,
linewidths=0, linecolor='white', cbar=True, cbar_kws=None,
cbar_ax=None, square=False, xticklabels='auto', yticklabels='auto',
mask=None, ax=None, **kwargs)
#参数annot = True 显示统计标号
#参数fmt 标号格式,比如"d"就是整数的形式
#参数data:dataframe
#参数vmin, vmax:界限,决定不被标注颜色的部分
#参数cmap:老样子,选颜色映射表
#参数centor:改变颜色映射的趋势
#参数linewidths linecolor :格子的分割线的颜色和宽度
- 准备工作
.groupby()
.reset_index(name='count')count为数据表中新的一列,便于.pivot()
.pivot(index='VClass', columns='trans_type', values='count' )heatmap 数据整理成二维表格
2.1 小提琴图(分类 vs 数值)
sb.violinplot(data = df, x = 'cat_var', y = 'num_var', color= , inner= )
#参数inner = 'quartile’绘制三条虚线分别表示三个四分位数 Q1-Q3 Q2表示中位数
sb.violinplot(x=None, y=None, hue=None, data=None, order=None,
hue_order=None, bw='scott', cut=2, scale='area', scale_hue=True,
gridsize=100, width=0.8, inner='box', split=False, dodge=True,
orient=None, linewidth=None, color=None, palette=None,
saturation=0.75, ax=None, **kwargs)
#参数:x y hue是选定的数据列,x一般是定性变量,y一般是定量变量,hue一般是另外一个分割x的定性变量
#参数split:如果设定为True,hue对比的那两个小提琴图就会合并成一个小提琴图,好做对比
#参数inner:有以下几种选择 {“box”, “quartile”, “point”, “stick”, None}
散点图与小提琴图
2.2 箱线图(分类 vs 数值)
箱线图是比小提琴图更清晰的数据汇总。使用箱线图更容易比较不同组的统计值
另一方面,箱线图对数据分布的细节描绘没有小提琴图清晰:无法在 Alpha 级别的值中看到微弱的双峰性。
小提琴图可能更适合探索数据,尤其因为 seaborn 还默认地在小提琴图中包含了箱线图
sb.boxplot(data = df, x = 'cat_var', y = 'num_var', color= , inner=)
sb.boxplot(x=None, y=None, hue=None,
data=None, order=None, hue_order=None,
orient=None, color=None, palette=None,
saturation=0.75, width=0.8, dodge=True,
fliersize=5, linewidth=None, whis=1.5,
notch=False, ax=None, **kwargs)
#参数x y hue是选定的数据列,x一般是定性变量,y一般是定量变量,hue一般是另外一个分割x的定性变量,比如,什么学历x大概赚多少钱y,那么想观察什么学历下,性别分类大概赚多少钱,Hue就是性别(有点groupby的意思)
#参数data:老样子是dataframe
#参数color:是设置所有图案的颜色
#参数palette:是seaborn.color_palette得来的
#参数linewidth:线的宽度
#参数orient:也可以直接调整绘图方向。"h"和“v”
#参数dodge:默认是True,设置为False的话,hue的图形就不会调整顺序和宽度跑到对比格子旁边去了。
#参数order, hue_order 是决定输出顺序,一般是以一个列表作为排序
3 分组条形图(簇状条形图) (分类 vs 分类)
基于单变量条形图
ax = sb.countplot(data = df, x = 'cat_var1', hue = 'cat_var2')
#横轴是x
#第二变量是分类/分组hue
#纵轴是统计量:比如频数
ax.legend(loc = 8, ncol = 3, framealpha = 1, title = 'cat_var2')
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)
分组条形图
热图和分组条形图
4 序列-折线图
plt.errorbar(data = df, x = 'num_var1', y = 'num_var2')
#参数误差线yerr 设置为标准差
#参数c 线的颜色
#参数linestyle 线的格式
plt.errorbar(x, y, yerr=None, xerr=None, fmt='', ecolor=None, elinewidth=None, capsize=None, barsabove=False, lolims=False, uplims=False, xlolims=False, xuplims=False, errorevery=1, capthick=None, hold=None, data=None, **kwargs)
#参数x, y定义数据位置
#参数xerr, yerr定义了errorbar的size大小
每个唯一 x 值或 x 值的分组区间仅绘制一个点
如果一个 x 分组区间中有多个观测值,那么该点在折线图中绘制的 y 值将为该数据点在分组中的概括统计值(例如均值或中位数)
如果 x 变量表示时间,则数据的折线图通常称之为时间序列图表
通常,在每个时间段内,我们只有一个观测值,例如股票图表或货币汇率图表
- 问题
plt.errorbar(data = df, x = 'num_var1', y = 'num_var2')
原始折线图:无序
- 解决方法:数据有序化
1). 设置分组边界和中心点:有序序列
xbin_edges = np.arange(0.5, df['num_var1'].max()+0.25, 0.25)
xbin_centers = (xbin_edges + 0.25/2)[:-1]
2).pd.cut():将原始数据归类到有序序列
data_xbins = pd.cut(df['num_var1'], xbin_edges, right = False, include_lowest = True)
3).pd.groupby():汇总统计值,作为y轴数据
y_means = df['num_var2'].groupby(data_xbins).mean()
y_sems = df['num_var2'].groupby(data_xbins).sem()
4). 绘制图表
plt.errorbar(x = xbin_centers, y = y_means, yerr = y_sems)参数误差线 yerr 设置为标准差
折线图
- 变式:平均移动的折线图(Moving average)
df_window = df.sort_values('num_var1').rolling(n)
x_winmean = df_window.mean()['num_var1']
y_median = df_window.median()['num_var2']
y_q1 = df_window.quantile(.25)['num_var2']
y_q3 = df_window.quantile(.75)['num_var2']
plt.scatter(data=df, x='num_var1', y='num_var2')
plt.errorbar(x=x_winmean, y=y_median, c=line_color)
plt.errorbar(x=x_winmean, y=y_q1, c=line_color, linestyle='--')
plt.errorbar(x=x_winmean, y=y_q3, c=line_color, linestyle='--')
plt.savefig('Lineplot3.png')
折线图:移动平均
- 变式:多变量折线图
对每个分类级别绘制一条折线
g = sb.FacetGrid(data=df, hue='', size=)
g.map(plt.hist, '', bins=, histtype='step')
g.add_legend()
多变量折线图
遗憾的是,“Alpha” 曲线是被其他三条曲线覆盖了,因为计数相对较低,导致出现很多重叠的地方
5.1 调整后的条形图(分类+统计量)
调整后的长条高度不再代表每个值的数量,而用来表示第二个变量的均值或其他统计量
sb.barplot(data = df, x = 'cat_var', y = 'num_var', color = base_color)
#参数errwidth 默认包含误差线:表示基于方差和样本大小的均值不确定性
#参数 ci = 'sd' 统计数据点的标准差,而非均值
sb.pointplot(x=None, y=None, hue=None, data=None, order=None, hue_order=None, estimator=<function mean>, ci=95, n_boot=1000, units=None, markers='o', linestyles='-', dodge=False, join=True, scale=1, orient=None, color=None, palette=None, errwidth=None, capsize=None, ax=None, **kwargs)
#使用散点图显示点估计和置信区间,跟上面相比是将平均值绘制为点,而不是长条。
#seaborn.pointplot擅长总结定量变量和定性变量之间的关系。
#参数join:如果设为True,就会画那个点和点之间的估计线,设为False就不画
#参数linestyles:设置线的格式,可以设置为虚线等等"- -",当然设置为" "空格的话就是没有线
调整后的条形图
sb.pointplot(data = df, x = 'cat_var', y = 'num_var', linestyles = "")
#参数 linestyles = "" 删除折线 默认情况下,pointplot 将用折线连接值
将平均值绘制为点,而不是长条
调整后的点图
如果数值变量本身是二元变量,值仅包括 0 和 1,那么箱线图或小提琴图将无法呈现足够的信息,而调整后的条形图最适合显示这些数据
针对二值分类变量
5.2 调整后的直方图(数值+统计量)
plt.hist(data=df, x='num_var', bins=bin_edges, weights=num_var_wts)
#参数weights 使长条高度表示除数据点数量以外的其他值
调整后的直方图
结果:每一个x轴分组的面积(权重*组内的数据数量)==y变量在该组内的“平均结果”
6.1 补充 Q-Q 图
当数据分布不符合正态分布时
- 方法1)使用 scipy 的 shapiro 函数来进行 Shapiro-Wilk 检验
- 方法2)使用Q-Q 图来进行可视化的直观检验
预期值:norm.ppf()
对于标准正态分布(mean = 0, standard deviation = 1)来说,ppf(0.25) = -0.674 ppf(0.5)=0 ppf(0.75)=0.674
n_points = 120
bin_size=0.5
plt.subplot(1,2,1)
unif_data = np.random.uniform(, n_points)
plt.hist(x=unif_data, bins=)
samp_mean = unif_data.mean()
samp_std = unif_data.std()
x=np.linspace()
y=norm.pdf(x, samp_mean, samp_std)
plot(x, y)
plt.subplot(1,2,2)
qq_data = (np.arange(n_points) - 0.5) / n_points
expected_scores = norm.pdf(qq_data)
data_scores = (np.sort(unif_data) - samp_mean) /sam_std
plt.scatter(expected_scores, data_scores)
plt.axis('equal')
plt.xlabel('Expected Standard Scores')
plt.ylabel('Observed Standard Scores')
Q-Q图
看到一条 S 形曲线。曲线中间部分值的趋势近似为线性,但斜率比期望的 y = x 更陡。同时在边缘上,斜率非常缓,因为均匀分布固定在有限范围内,但正态分布值的尾部预期会更远
可以在左侧图中的叠加分布线中看到这一点,即使在数据的边缘,理论上的正态曲线仍然有相当高的高度。所有这些都导致随机生成的均匀分布数据不能与正态分布近似贴合
6.2 蜂群图Swarm Plots
和散点图类似,每个数据点根据在两个变量上的值确定在图表中的位置。点放置在尽量接近真实值的位置,不允许有任何重叠现象,不是像在正常散点图中那样随机抖动数据点
sb.swarmplot(data=df, x='cat_var', y='num_var', color=)
seaborn.swarmplot(x=None, y=None, hue=None,
data=None, order=None, hue_order=None,
dodge=False, orient=None, color=None,
palette=None, size=5, edgecolor='gray', linewidth=0, ax=None, **kwargs)
蜂群图
虽然由于位置抖动而出现一些变形,但是我们也可以确切地了解每个点实际位于何处,消除了小提琴图中可能出现的长尾。
但是,只有数据量很少或适中时,才适合使用蜂群图。如果有太多的数据点,那么不能重叠的限制将导致变形严重,或者需要很多空间才能很好地绘制数据
此外,数据点太多实际上会分散注意力,使我们更难发现图表中的关键规律
6.3 轴须图Rug Plot
边缘分布是变量的单变量分布,忽略任何其他变量的值
g = sb.JointGrid(data=df, x='num_var1', y='num_var2')
g.plot_joint(plt.scatter)
g.plot_marginals(sb.rugplot, height = 0.25)
#参数height 指定轴须图的刻度为边缘轴大小高度(相邻刻度的距离)的 0.25 倍
轴须图
此例中,轴须图很合适,因为数据并不多或过于密集。在其他情形下,直方图或密度曲线可能更合适
6.4 带状图Strip Plot
本质:分类散点图
sb.stripplot(data=df, x='num_var', y='cat_var', color=base_color)
注意右边小提琴图中的竖线:越黑表示越密集
带状图
6.5 叠嶂图Ridgeline Plot
近年来最热门的新型可视化类型之一
叠嶂图
- 原始数据(分面直方图)
group_means = df.groupby(['many_cat_var']).mean()
group_order = froup_means.sort_values(['num_var'], ascending=False).index
g = sb.FacetGrid(data=df, col='many_cat_var', col_wrap=5, size=2, col_order=group_order)
g.map(plt.hist, 'num_var', bins=np.arange(5, 15+1, 1))
g.set_titles('{col_name}')
#索引排序:按照均值下降趋势(上述直方图的顺序有问题:R10均值最大)
sb.FacetGrid(data, row=None,
col=None, hue=None, col_wrap=None,
sharex=True, sharey=True, size=3, aspect=1,
palette=None, row_order=None, col_order=None,
hue_order=None, hue_kws=None, dropna=True,
legend_out=True, despine=True,
margin_titles=False, xlim=None, ylim=None, subplot_kws=None, gridspec_kws=None)
#参数data:往常一样,dataframe
#参数row, col, hue : 不是会建立几个小图表吗,row就是行拆分是拆分了什么分类,col就是列拆分拆分了什么,hue就是一个表内部的分类(常用不同颜色区分不同分类)
#参数col_wrap:在每行的分类下,来决定一列放几个
#参数size,aspect,又看到这两了,还是同样,每个子图表高度和宽高比,
#参数col,row,hue_order 决定了图表输出中列,行,hue的顺序,所以一般是列表形式
原始数据(分面直方图)
待处理
1). 将分布图的形式从直方图改为核密度估计,使叠嶂图中的每个“山峰”更平滑
2). 需要按行划分级别,以便这些“山峰”堆叠在一起
group_means = df.groupby(['many_cat_var']).mean()
group_order = froup_means.sort_values(['num_var'], ascending=False).index
g = sb.FacetGrid(data=df, row='many_cat_var', size=0.5, aspect=12, row_order=group_order, gridspec_kws={'hspace': -0.2})
g.map(sb.kdeplot, 'num_var', shade=True)
g.set(yticks=[])
g.despine(left=True)
#set the transparency of each subplot to full
g.map(lambda **kwargs: plt.gca().patch.set_alpha(0))
#remove subplot titles and write in new labels
def label_text(x, **kwargs):
plt.text(4, 0.02, x.iloc[0], ha='center', va='bottom')
g.map(label_text, 'many_cat_var')
g.set_xlabels('num_var')
g.set_titles('')
#参数gridspec_kws:通过 Matplotlib 的 GridSpec 类调整网格中子图的排列
#将 "hspec" 参数设置为负值,可以使子图的轴边界垂直重叠
#通过g.set()移除刻度
#通过g.despine()来移除 y 轴
#利用了 FacetGrid 对象的 map函数来完成图表修改
#使用map应用透明度:设置了一个匿名 lambda 函数,该函数获取当前的 Axes 对象 (gca) , 选择其背景 (patch),将该背景的透明度设置满(set_alpha(0))
#map 的第二个参数,它将一个 pandas Series 发送到第一个参数指定的函数。这个 Series 是筛选出来的仅包含第二个 map 参数指定的列,只有适用于每个分面的行
#map 也会自动向指定的函数发送一些像 ‘color’ 这样的通用关键字参数。因此尽管这里我并没有指定这样的参数,仍然需要 **kwargs 来捕获关键字参数
#me-理解 g.map(plot, 'column') 第二个参数是第一个参数的的对象
6.6 堆积图
前提:总量保持一致(比如100%)
错误示例:总量不一致
堆积图:错误示例
7 补充
7.1 sb.factorplot()
sb.factorplot(x=None, y=None, hue=None,
data=None, row=None, col=None,
col_wrap=None, estimator=<function mean>,
ci=95, n_boot=1000, units=None, order=None,
hue_order=None, row_order=None,
col_order=None, kind='point', size=4, aspect=1,
orient=None, color=None, palette=None,
legend=True, legend_out=True, sharex=True,
sharey=True, margin_titles=False,
facet_kws=None, **kwargs)
#它是seaborn下的一个方法,有点类似FacetGrid,它合并了FacetGrid和定性-定量的图表(柱状,小提琴,箱线等),使用上,比FacetGrid方便点
7.2 sb.lmplot()
sb.lmplot(x, y, data, hue=None, col=None,
row=None, palette=None, col_wrap=None, size=5,
aspect=1, markers='o', sharex=True, sharey=True,
hue_order=None, col_order=None,
row_order=None, legend=True, legend_out=True,
x_estimator=None, x_bins=None, x_ci='ci',
scatter=True, fit_reg=True, ci=95, n_boot=1000,
units=None, order=1, logistic=False,
lowess=False, robust=False, logx=False,
x_partial=None, y_partial=None, truncate=False,
x_jitter=None, y_jitter=None, scatter_kws=None,
line_kws=None)
#跟上面的factorplot很相似,不过组合的是FacetGrid和 seaborn.regplot散点图(定量-定量)
7.3 折线图 sb.tsplot()
sb.tsplot(data, time=None, unit=None,
condition=None, value=None, err_style='ci_band',
ci=68, interpolate=True, color=None, estimator=
<function mean>, n_boot=5000, err_palette=None,
err_kws=None, legend=True, ax=None, **kwargs)
#参数err_style: {ci_band, ci_bars, boot_traces, boot_kde, unit_traces, unit_points}
#参数err的图样,默认就是一个曲线,常用还有ci_bars表示误差线
#参数ci: float or list of floats in [0, 100] or “sd” or None跟上面的误差线很像,要么表示置信区间,要么表示标准差,None就是没有误差线
#参数interpolate :True或者False,表示两点间是否画上插值的线
#参数condition :大概就是说会根据不同条件来绘制不同的折线
sb.regplot()
heatmap 数据整理成二维表格
原始折线图:无序
折线图