动手学数据分析(4)——数据可视化

本文为Datawhale8月组队学习——动手学数据分析课程的系列学习笔记。

Datawhale-动手学数据分析

数据来源

Kaggle小白入门首选练手项目——Kaggle-泰坦尼克号存活率

Ch2-3 数据可视化

数据可视化既可以用于探索性分析(如识别离群点、辅助数据变形),也可用于建模结果的交互式展示。以图形呈现数据的分布和趋势,以视觉为辅助,能够加深我们对数据的理解。

最终呈现的图形既可以是静态的,也可以是动态的/可交互的

常用的第三方可视化库包含:

  • matplotlib:最常用,包含了常用的所有图形,功能很全
  • seaborn:基于matplotlib的API高级封装,相对前者语法更简单,使用更方便
  • pyecharts:基于百度的可视化JS工具Echarts,可以实现很多JS
  • ggplot/plotnine:语言结构继承自R的ggplot2,目前ggplot已被淘汰,一般选择plotnine
  • plotly/bokeh等前端交互可视化库

具体的可视化库对比可以参见可视化工具不知道怎么选?深度评测5大Python数据可视化工具

matplotlib/seaborn

课程主要介绍了关于matplotlib及其衍生库seaborn的基本使用方法。matplotlib的使用可以总结为三步:

  • 创建画布
  • 选择图表类型,绘制图象
  • 配置图例,完善信息

创建画布

画布(figure)和绘图对象(axes)

画布(figure),相当于绘图工具中的画板。所有图形(Axes)绘制在画布上,图形的大小需要依据画布的大小。

一个figure可以包含多个axes,此时每个axes可以理解为一个子图,也可以只包含一个axes。

换句话说,figure是axes的父容器,而axes是figure的内部元素,而我们常用的各种图表、图例、坐标轴等则又是axes的内部元素。

可以借助官方文档中的解构图进行理解:

创建画布的方法

创建画布,即创建figure和axes对象,Python for Data Analysis一书中主要介绍了2种方法:

  • plt.figure+fig.add_subplot():创建一个画布(figure),此时默认只有一个axes,按需要再往画布里添加axes。
  • plt.subplots():接收3个数字或1个3位数(自动解析成3个数字)作为子图的行数、列数和当前子图索引。该方法将直接创建一个包含多个axes的figure,返回一个figure对象和包含一组axes对象的ndarray。

其中,plt.subplots()包含参数sharexsharey,可以使所有子图的使用的x/y坐标系保持一致。

1
2
3
4
5
6
7
8
9
10
# fig即为返回的Figure对象,axes为以ndarray形式返回的一组AxesSubplot对象
fig, axes = plt.subplots(2, 2, sharex=True, sharey=True)

# 可以直接调用AxesSubplot对象的方法绘图
for i in range(2):
for j in range(2):
axes[i, j].hist(np.random.randn(500), bins=50, color='k', alpha=0.5)

# 用于调整子图的间距
plt.subplots_adjust(wspace=0, hspace=0)

得到以下无内部间距的图形:

上图中标签被遮挡住了,因此,在matplotlib中为了保证标签完整,须手动进行调整。

绘制图象

用Matplotlib绘制可视化图表,有3种形式:

  • plt:如常用的plt.plot(),不面向特定的实例对象,相当于在默认的画布上创建了一个虚拟的axes,在该axes上绘制图表。
  • 面向对象:指面向Figure和Axes两类对象创建图表,即通过调用Figure或Axes两类实例的方法完成绘图的过程。这种方法将plt中的图形赋值给一个Figure或Axes实例,方便后续调用操作。
  • 面向数据:直接调用DataFrame/Series/ndarray的方法绘图,该方法连同了pandas/numpy和matplotlib,直接基于数据绘制图象,方便快速可视化当前的数据
1
2
3
4
5
6
7
8
data = np.random.randn(50)
# plt绘图
plt.plot(data)
# 面向对象绘图
ax = plt.subplots(222)
ax.plot(data)
# 面向数据绘图
data.plot(ax=ax)

plt和面向数据方法适用于简单的单图绘制,使用足够方便。面向对象方法则更适用于复杂的多图绘制,拥有更多的自定义设置,自由度更高。

图表的选择

常用图表形式包括:

  • plot:折线图/点图
  • scatter:散点图,常用于表述两组数据间的分布关系,也可由特殊形式下的plot实现
  • bar/barh:条形图或柱状图,常用于表达一组离散数据的大小关系,默认竖直条形图,可选barh绘制水平条形图
  • hist:直方图,用于统计一组连续数据的分区间分布情况
  • pie:饼图,主要用于表达构成或比例关系

选择图表的思想可以总结为一张图:

图线的调整与美化

可以在之前提到的两种方法中添加图线的粗细(linewidth)、颜色(color)、标记(marker)、线型(linestyle)以及柱状图的宽度(width)等参数来进行图线的调整。不同图表含有的参数不同,需要查看相应绘图方法的参数介绍,这里不再详细叙述。

配置图例,完善图形

在绘制好图象后,还需要进一步添加各种元素,例如设置标题、坐标轴、文字说明等,常用元素如下:

  • title:设置图表标题
  • axis/xlim/ylim:设置相应坐标轴范围。axis是对xlim和ylim的集成,接受4个参数分别作为x和y轴的范围参数
  • grid:添加网格线
  • legend:添加label图例参数后,通过legend进行显示
  • xlabel/ylabel:用于设置x、y轴标题
  • xticks/yticks:用于自定义坐标轴刻度显示
  • text/arrow/annotation:在图例指定位置添加文字、箭头和标记

借用官方教程的一张图来介绍图象的各部分元素:

添加这些元素的方法也分为plt方法面向对象方法,具体使用参考官方文档:

  • plt.plot()——axes.plot()
  • plt.legend()——axes.legend()
  • plt.axes()——fig.add_axes()
  • plt.subplot()——fig.add_subplot()
  • plt.xlabel()——axes.set_xlabel()
  • plt.ylabel()——axes.set_ylabel()
  • plt.xlim()——axes.set_xlim()
  • plt.ylim()——axes.set_ylim()
  • plt.title()——axes.set_title()

此外,书中还介绍了一种类似json的元素设置方法,利用了axes对象的set(**props)方法,可以避免繁琐书写函数/方法的过程:

1
2
3
4
5
props = {
'title': 'My first matplotlib plot',
'xlabel': 'Stages'
}
ax.set(**props)

Seaborn

Seaborn是对Matplotlib的高级封装,具有更美观的图形样式/颜色配置、更方便的语法结构。Seaborn有以下特点:

  • API封装使得接口调用方便,少量参数就可以做出很不错的图表
  • 图表类别更细,相比matplotlib更有指向性,具有统计学含义
  • 配色、线型等,看起来更为优雅端庄
  • 针对不同的展示环境(notebook/paper/poster/talk)提供了不同的绘图风格,方便使用

很有意思的点在于seaborn的缩写写作sns,并不是sbn。

Seaborn使用心得:

  • 绝大多数绘图接口名——XXplot

  • 绘图接口隐式参数常使用DataFrame,此时只需在x/y/hue三个参数中传入列名即可绘制图象;此外也支持numpy数组与list。

具体的使用参见官方API文档和gallery的examples,这里不作过多阐述。

举一个简单的例子:

1
2
3
4
5
6
7
fig,axes = plt.subplots(1,2,figsize = (20,4))
sns.lineplot(x=index,y=age_survived,ax=axes[0],label='Survived')
sns.lineplot(x=index,y=age_unsurvived,ax=axes[1],label='Unsurvived')
for ax in axes:
ax.set_xlim([0,index.max()])
ax.set_title('The distribution of survival among different age')
plt.show()

pyecharts

在matplotlib之外,稍微探索了一下pyecharts的使用,这里参考官方文档做一个简单介绍。

pyecharts的使用方式类似sklearn,完全面向对象。每个图表都是一个对象,创建图表首先需要实例化对应类的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pyecharts.charts import Bar
from pyecharts import options as opts

# 01 一般调用方法
bar = Bar()
bar.add_xaxis(["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"])
bar.add_yaxis("商家A", [5, 20, 36, 10, 75, 90])
# render 会生成本地 HTML 文件,默认会在当前目录生成 render.html 文件
# 也可以传入路径参数,如 bar.render("mycharts.html")

# 02 链式调用方法,pyecharts 所有方法均支持链式调用
bar = (
Bar()
.add_xaxis(["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"])
.add_yaxis("商家A", [5, 20, 36, 10, 75, 90])
.set_global_opts(title_opts=opts.TitleOpts(title="主标题", subtitle="副标题"))
# 或者直接使用字典参数
# .set_global_opts(title_opts={"text": "主标题", "subtext": "副标题"})
)

bar.render()

传入的数据格式必须为Python的原生格式,pyecharts基于echarts可视化库,不支持pandas/numpy等数据格式,因此需要进行数据格式的转换:

1
2
3
4
5
6
7
8
# for int
[int(x) for x in your_numpy_array_or_something_else]
# for float
[float(x) for x in your_numpy_array_or_something_else]
# for str
[str(x) for x in your_numpy_array_or_something_else]
# 对于Series可以直接使用tolist()方法
Series.tolist()

pyecharts默认生成html文件,需要通过渲染器渲染为静态图像

1
2
3
4
5
6
7
8
9
10
from pyecharts.charts import Bar
from pyecharts.render import make_snapshot
# 使用 snapshot-selenium 渲染图片
from snapshot_selenium import snapshot

bar = ...
...

# 生成png图象
make_snapshot(snapshot, bar.render(), "bar.png")

Jupyter中的渲染只需将最后的render()方法改为render_notebook()

参考资料

[1] Python for Data Analysis, 2nd Edition

[2] Matplotlib入门详细教程(附导图)

[3] Matplotlib Official Tutorial

[4] python数据科学系列:seaborn入门详细教程

[5] pyecharts官方文档

评论