Python

[可视化]探索性数据3 多变量

2020-01-27  本文已影响0人  DDuncan
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sb

引例:优秀案例

门票售卖可视化:额外编码
  • 横轴:票供应的量
  • 纵轴::票价
  • 第三个变量:线的走向随着day而变化
  • 特殊标记:start,end
  • 不同年份:分面表示(标签置顶)
    可以看出:
    1). 2014年票的供应最多
    2). 最高价,最低价的分布

一、多变量

提纲

数据类型
数值变量*3 散点图+非位置编码
数值变量*2+分类变量 散点图+非位置编码
数值变量+分类变量*2
分类变量*3
  • 非位置编码:针对散点图
    1). 颜色
    非位置编码最容易的方式
    2). 形状
    对于分类变量,是一个很好的编码方式
    3). 大小
    更多用于定性判断上
技巧
分面:降维描述 sb.FacetGrid()
调整后的双变量图 条形图
sb.countplot()
sb.barplot()
sb.pointplot()
二维直方图(数据格式==热图)
plt.hist2d()
二维条形图
sb.heatmap()
分组条形图
sb.barplot(, hue= )
箱线图
sb.boxplot(, hue= )
折线图
plt.errorbar(, y= )
图表矩阵 sb.PairGrid()
.map_diag(plt.hist)
.map_offdiag(plt.scatter)
相关系数矩阵 sb.heatmap(df.corr())
特征工程

1 非位置编码(针对散点图)

1.1 颜色

非位置编码最容易实现的方式

plt.colorbar()  #Matplotlib  
sb.FacetGrid(, palette= )  #Seaborn
plt.scatter(data = fuel_econ_subset, x='displ', y='comb', c='co2', cmap='viridis_r')
plt.colorbar(label='CO2 (g/mi)')
plt.xlabel('Displacement (l)')
plt.ylabel('Combined Fuel Eff. (mpg)');
散点图+颜色编码

Seaborn

sb.color_palette()
sb.FacetGrid(, palette=)
1). 无序(默认的调色板)
sb.palplot(sb.color_palette(n_colors=9))

调色板:无序 色调不同,亮度和饱和度相同

2). 有序

sb.palplot(sb.color_palette('viridis', 9)) "viridis"表示用深色表示低值,浅色表示高值
低数值:较明亮,不饱和的颜色;
高数值:较暗,饱和的颜色

调色板:有序

3). 发散
有意义的零点或者存在一个中心值
sb.palplot(sb.color_palette('vlag', 9))

调色板:发散 可能会用到 "vmin" 和 "vmax" 这两个参数将数据的中心点设为调色板的中间色
对于 heatmap,发散型调色板非常有用,因为有一个 "center" 中心值

matplotlib

plt.scatter(, cmap=)

小结:

大多数情况下,使用 Matplotlib 的内置调色板表格或者 ColorBrewer 中的前几个调色板(“viridis” 等)就可以了
所有这些字符串,如果加上 '_r' 就会将调色板的颜色颠倒


常用调色板

当我们不能用位置进行编码的时候,我们用颜色编码
注意色盲:选择饱和度/亮度低一些的颜色

注意透明度:尽量避免使用

plt.figure(figsize=[5, 5])

#left: qualitative points
plt.scatter(0, 0.5, s=1e4, c=sb.color_palette()[0], alpha=0.5)
plt.scatter(0, -0.5, s=1e4, c=sb.color_palette()[1], alpha=0.5)

#right: quantitative points
plt.scatter(1, 0.5, s=1e4, c=sb.color_palette('Blues')[2], alpha=0.5)
plt.scatter(1, -0.5, s=1e4, c=sb.color_palette('Blues')[4], alpha=0.5)

#set axes for point overlap
plt.xlim(-0.5, 1.5)
plt.ylim(-3.5, 3.5)
plt.xticks([])
plt.yticks([])
避免使用透明度

1.2 形状

对于分类变量,是很好的编码方式
plt.scatter()sb.regplot()函数都不能自动为不同的类别分配不同的形状,需要自己编写循环来多次调用绘图函数,通过类别来区分数据点,并为每次调用传入不同的marker参数

cat_markers = [['A', 'o'], ['B', 's']]  #也可改为元组列表
for cat, marker in cat_markers:
    df_cat = df[df['cat_var1'] == cat]
    plt.scatter(data=df_cat, x='num_var1', y='num_var2', marker=marker)
plt.legend(['A', 'B'])
#设置颜色,要使用 scatter 里的 “c” 参数,或者 regplot 里的 “color” 参数
非位置编码:形状(默认含颜色)

1.3 大小

大小编码更多用于定性判断上

plt.scatter(data=df, x='num_var1', y='num_var2', s='num_var3')

#dummy series for adding legend
sizes = [20, 35, 50]
base_color = sb.color_palette()[0]
legend_obj = []
for s in sizes:
    legend_obj.append(plt.scatter([], [], s=s, color=base_color))
plt.legend(legend_obj, sizes)
非位置编码:大小
对数据大小做过调整:在某些情况下,你可能也需要应用缩放系数,放大差异
尤其是当你的第三变量包含负数的时候,颜色编码可能是个更好的可视化方式

2 分面图

1)当分类数多于2个时,考虑分面
2)重点关注对象放在x横轴上:更明显

g = sb.FacetGrid(data = df, col = 'cat_var2', row = 'cat_var1', size = 2.5,
                margin_titles = True)
g.map(plt.scatter, 'num_var1', 'num_var2')
#参数margin_titles = True 可以将两个变量的标签分别放到图表右方和上方

#分面箱线图
g = sb.FacetGrid(data = df, col = 'cat_var1', size = 4)
g.map(sb.boxplot, 'cat_var2', 'num_var2')

#分面散点图
g = sb.FacetGrid(data = df, col = 'cat_var2', row = 'cat_var1', size = 2.5,
                margin_titles = True)
g.map(plt.scatter, 'num_var1', 'num_var2')
原始数据 转变为分面图:第三变量为分类 转变为分面图(多变量):行/列多增加一种分类

3 基于双变量图的调整

3.1 条形图(单变量)

sb.countplot()
sb.barplot()
sb.pointplot()

ax = sb.pointplot(data = df, x = 'cat_var1', y = 'num_var2', hue = 'cat_var2',dodge = 0.3, linestyles = "")
#参数linestyles  是否连线
#参数dodge 同一组错开表示(如图低中高同一组的三类错开表示)
#参数hue 第三个变量;结合参数dodge 错开表示该分类变量 
#参数ci 统计量
调整后的双变量条形图 分类变量*2+数值变量

第二变量的均值、中位数或者其他统计量画在纵轴上
这种调整方式也可以用于双变量图表中,比如热图、分组条形图以及折线图,使双变量图表也可以描绘多变量数据

3.2 二维直方图(数据格式==热图)

plt.hist2d()
描绘第三个变量的均值,你需要修改 hist2d 函数的 weights 参数

xbin_edges = np.arange(0.25, df['num_var1'].max()+0.5, 0.5)
ybin_edges = np.arange(7, df['num_var2'].max()+0.5, 0.5)

# count number of points in each bin
@说明:将数据按照分组限制edges进行划分,不包括右边界,包括最小值,索引labels改为数值索引,数据类型改为int
xbin_idxs = pd.cut(df['num_var1'], xbin_edges, right = False,
                    include_lowest = True, labels = False).astype(int)
ybin_idxs = pd.cut(df['num_var2'], ybin_edges, right = False,
                    include_lowest = True, labels = False).astype(int)
@分组汇总:最后一列是汇总后统计值
pts_per_bin = df.groupby([xbin_idxs, ybin_idxs]).size()

@多重索引:需要更改索引
@生成二维表格Dataframe:行索引是index, 列索引是columns,values就是表格的具体值==(汇总)统计样本的个数
pts_per_bin = pts_per_bin.reset_index()
pts_per_bin = pts_per_bin.pivot(index = 'num_var1', columns = 'num_var2').values
@平均值:该组对应的样本值-第三个变量num_var3/该组统计样本的个数(以前两个变量num_var1和num_var2作为分组单位)
z_wts = df['num_var3'] / pts_per_bin[xbin_idxs, ybin_idxs]

# plot the data using the calculated weights——>数量相加等于第三个变量的均值 == 面积相加后等于是第三个变量的总数量
plt.hist2d(data = df, x = 'num_var1', y = 'num_var2', weights = z_wts,
           bins = [xbin_edges, ybin_edges], cmap = 'viridis_r', cmin = 0.5);
plt.xlabel('num_var1')
plt.ylabel('num_var2');
plt.colorbar(label = 'mean(num_var3)');
调整后的二维直方图 数值变量*3(颜色)

例子中的数据点很少,以及第三个变量的分布非常干净,调整热图的工作量有点大。
再次,考虑到之前观察到的数据比较简单,使用颜色和大小进行编码的散点图其实就已足够描绘数据了。
如果有很多的数据需要聚合,可能会考虑使用热图。

3.3 二维条形图

sb.heatmap()

  • 预备工作

  1. groupby
  2. 统计值取名
  3. 形成Dataframe
  4. 生成heatmap
@只针对['num_var2']进行mean的统计
cat_means = df.groupby(['cat_var1', 'cat_var2']).mean()['num_var2']
@统计值作为新的一列,取一个列的名字
cat_means = cat_means.reset_index(name = 'num_var2_avg')
@形成Dataframe——直接对应热图
cat_means = cat_means.pivot(index = 'cat_var2', columns = 'cat_var1',
                            values = 'num_var2_avg')
sb.heatmap(cat_means, annot = True, fmt = '.3f',
           cbar_kws = {'label' : 'mean(num_var2)'})

#参数"cbar_kws" 为 colorbar 提供了额外的参数
#参数annot 单元格显示注释
#参数fmt 小数点后位数
#参数cbar_kws 其余关键字中添加标签字典
调整后的二维条形图 分类变量*2+数值变量(数值/颜色)

3.4 分组条形图

sb.barplot()(单变量)

ax = sb.barplot(data = df, x = 'cat_var1', y = 'num_var2', hue = 'cat_var2')
ax.legend(loc = 8, ncol = 3, framealpha = 1, title = 'cat_var2')
#参数hue 第三个变量
#参数ci = 'sd'

@添加图例
#loc 位置的代码
#ncol 列的数量
调整后的分组条形图 分类变量*2+数值变量
"hue" 参数也可以在函数 boxplot, violinplot 和 pointplot 中完成一样的功能,以分组显示的方式添加第三个分类变量

3.5 箱线图

sb.boxplot(data=fuel_econ, x='VClass', y='comb', hue='trans_type');
plt.xticks(rotation=15)
plt.ylabel('Avg. combined efficiency (mpq)');
调整后的箱线图 分类变量*2+数值变量

3.6 折线图

plt.errorbar(x, y, **kwargs)
#x:数据中心点
#y:统计量
#**kwargs:表示其他参数-这些参数照搬函数传入的形参

def mean_poly(x, y, bins = 10, **kwargs):
    """ Custom adapted line plot code. """  
    
    # set bin edges if none or int specified
    if type(bins) == int:
        bins = np.linspace(x.min(), x.max(), bins+1)
    bin_centers = (bin_edges[1:] + bin_edges[:-1]) / 2

    # compute counts
    data_bins = pd.cut(x, bins, right = False,
                       include_lowest = True)
    means = y.groupby(data_bins).mean()

    # create plot
    plt.errorbar(x = bin_centers, y = means, **kwargs)


bin_edges = np.arange(0.25, df['num_var1'].max()+0.5, 0.5)
g = sb.FacetGrid(data = df, hue = 'cat_var2', size = 5)

@mean_poly是数据源
g.map(mean_poly, "num_var1", "num_var2", bins = bin_edges)
g.set_ylabels('mean(num_var2)')
g.add_legend()

自定义了一个函数传入 FacetGrid 对象的 map 函数里,来计算每个分组的均值,然后再用 errorbar 函数画出折线图

调整后的折线图 数值变量*2(x轴数值序列化)+分类变量

4 图表矩阵

g = sb.PairGrid(data = df, vars = ['num_var1', 'num_var2', 'num_var3'])
#var参数不设定,则默认所有变量

@区别设置对角线(直方图),非对角线(散点图)
g.map_diag(plt.hist)
g.map_offdiag(plt.scatter)

默认情况下,PairGrid 只能展示数值变量,并且 PairGrid 在纵轴和横轴上展示的变量顺序相同

图表矩阵:数值变量*2

对于其他关系,比如我们想要观察数据中数值变量和分类变量之间的关系:

g = sb.PairGrid(data = df, x_vars = ['num_var1', 'num_var2', 'num_var3'],
                y_vars = ['cat_var1','cat_var2'])
g.map(sb.violinplot, inner = 'quartile')
#cat_var1的分类是A和B
#cat_var2的分类是Low Medium High
图表矩阵:分类变量+数值变量

如果增加变量的数量,最终呈现的图表数量会以指数方式增加。
此外,增加变量的数量也意味着矩阵上每个子图的宽度将减小,因为总体图表的宽度不变。
一种推荐的方法是随机抽取数据的子集用来绘制图表矩阵。建议使用图表矩阵发现有趣的变量组合,然后在全部数据上绘制针对这些变量的独立图表

5 相关系数矩阵

sb.heatmap(df.corr(), annot = True, fmt = '.2f', cmap = 'vlag_r', center = 0)
#针对数值变量:只表示线性相关关系的强度
#.corr()
#也可以选取重点的几个列:df[列名的list].corr()
#参数 vmin = 0:小于0的数不显示

默认的调色板是有序型的,但最好使用发散型的调色板,并且把中心数设为 0。这样的话,你就可以通过颜色的色调来判断两个变量之间是正相关还是负相关,并且能从色调的强度来判断这种关系的强弱

相关系数矩阵:基于热图 嵌套.corr()

6 特征工程

  1. 在探索数据的时候,你有时候会发现两个变量在某种程度上存在一定的关联,对这两个变量进行相加、相减、相乘或者相除得到的新特征能够更好地回答你的研究问题
    比如你有一个变量代表犯罪数量, 第二个变量代表人群总数量,那么你可能想要把这两个变量进行相除,得到有关人群中的犯罪率。这样得出的犯罪率比较可信,排除了因为人口多而导致犯罪数量高的可能性

  2. 拆分数据集
    使用 cut 函数将数值变量分为有序的组,通过分面画图,体现有序组的差异


二、Tips

  1. 相关关系:转化为常数、线性关系
    比如:接近反函数1/X,尝试相乘为常数
上一篇下一篇

猜你喜欢

热点阅读