利用Python进行数据分析-可视化

  |  

摘要: 《利用Python进行数据分析》可视化部分笔记

【对算法,数学,计算机感兴趣的同学,欢迎关注我哈,阅读更多原创文章】
我的网站:潮汐朝夕的生活实验室
我的公众号:算法题刷刷
我的知乎:潮汐朝夕
我的github:FennelDumplings
我的leetcode:FennelDumplings


  • 帮助识别异常值,为建模提供想法
  • 国建网络交互式可视化可能是最终目标
  • Python 有很多第三方库做静态或动态的可视化文件
  • matplotlib 为基础库
  • seaborn 是 matplotlib 的附加工具包
  • 在 Jupyter Notebook 中交互式绘图: %matplotlib notebook
  • 高级功能的最佳学习资源:作品库和文档

简单 matplotlib API

seaborn 和 pandas 內建绘图函数可以处理大部分绘图的普通细节。

图片与子图

Matplotlib 绘制的图片位于 Figure 对象中。可以用 plt.figure 生成。

不能用空白的 Figure 对象上绘图,需要用 add_subplot 创建一个或多个子图。以下代码中 fig 是图片,ax 是子图。

1
2
3
4
fig = plt.figure()
ax1 = fig.add_subplot(2, 2, 1)
ax2 = fig.add_subplot(2, 2, 2)
ax3 = fig.add_subplot(2, 2, 3)

add_subplot 的 3 个参数 (m, n, idx),前两个表示图片是 m * n 的,idx 表示当前选中的子图编号(从1计数)。

  • Jupyter Notebook/Ipython 的细节:每个单元格运行后,图表被重置,因此对于复杂图表需要将所有绘图命令放在单个 Cell 中。
  • plt.plot(...) 会在最后一个 Figure 对象和子图上进行绘制(如果需要的话就创建一个),从而隐藏图片和子图的创建
  • fig.add_subplot 返回的是 Axes Subplot 对象。
1
2
3
plt.plot(np.random.randn(50).cumsum(), "k--")
_ = ax1.hist(np.random.randn(100), bins=20, color="k", alpha=0.3)
ax2.scatter(np.arange(30), np.arange(30) + 3 * np.random.randn(30))

子图网络

plt.subplots 创建新的图片,返回包含已生成子图对象的 Numpy 数组

1
fig, axes = plt.subplots(2, 3)
  • axes 可以想二维数组那样索引。例如 axes[2, 0]
  • 可以用 sharex, sharey 表明子图分别有相同的 X 轴或 y 轴
subplots 参数 描述
nrows 子图行数
ncols 子图列数
sharex 所有子图用相同的 x 轴刻度(调整 xlim 影响所有子图)
sharey 所有子图用相同的 y 轴刻度(调整 ylim 影响所有子图)
subplot_kw 传入 add_subplot 的关键字参数字典,用于生成子图
**fig_kw 生成图片时使用的额外关键字参数,
例如 plt.subplots(2, 2, figsize=(8, 6))

调整子图周围的间距

1
2
plt.subplots_adjust(left=None, bottom=None, right=None, top=None,
wspace=None, hspace=None)

wspace 与 hspace 控制宽度百分比和高度百分比,用作子图间距

1
2
3
4
5
fig, axes = plt.subplots(2, 2, sharex=True, sharey=True)
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 并不检查标签是否重叠,因此需要通过显式指定刻度位置和刻度标签的方法修复标签。

颜色、标记和线类型

plt.plot 接收带有 x 轴和 y 轴的数组以及一些可选的字符串缩写参数来指定颜色和线类型。以下两种写法等价。

1
2
ax.plot(x, y, "g--")
ax.plot(x, y, linestyle="--", color="g")

折线图还可以有标记,用来凸显实际数据点, marker 参数。例如

1
2
plt.plot(y, "ko--")
plt.plot(y, linestyle="dashed", color="k", marker="o")

改变插值方法, drawstyle 参数,例如:

1
plt.plot(y, "k--", drawstyle="steps-post")

为每条线添加图例

1
2
plt.plot(y, "k--", drawstyle="steps-post", label="steps-post")
plt.legend(loc="best")

刻度、标签和图例

图表修饰工作两种主要方式

  • pyplot 接口
  • 面向对象的原生 matplotlib API

pyplot 接口的方法:

xlim: 绘图范围
xticks: 刻度位置
xticklabels: 刻度标签

可以再两种方式中使用

  1. 没有函数参数的情况下调用,返回当前参数值,例如 plt.xlim()
  2. 传入参数的情况下调用,并设置参数值,例如 plt.xlim([0, 10])

这些方法都会在当前活动的,或最近创建的 AxesSubplot 上生效。
这些plt接口每个都对应于子图的两个方法,例如 plt.xlim() 对应 ax.get_xlim(), ax.set_xlim()

title: 标题
xlabel: 轴标签

1
2
3
4
5
6
7
8
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(np.random.randn(1000).cumsum())
ticks = ax.set_xticks([0, 250, 500, 750, 1000])
labels = ax.set_xticklabels(["one", "two", "three", "four", "five"], rotation=30, fontsize="small")

ax.set_title("My Plot")
ax.set_xlabel("Stages")

还可以用以下写法,这种写法可以批量传递 ax 的 set 方法

1
2
3
4
5
6
7
8
9
10
11
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(np.random.randn(1000).cumsum())
ticks = ax.set_xticks([0, 250, 500, 750, 1000])
labels = ax.set_xticklabels(["one", "two", "three", "four", "five"], rotation=30, fontsize="small")

props = {
"title": "My Plot",
"xlabel": "Stages"
}
ax.set(**props)

注释与子图加工

绘制注释: 文本、箭头、其他图形

text
arrow
annote

例如

1
ax.text(x, y, "Hello World!", family="monospace", fontsize=10)

例子

绘制标普500指数从2007年以来的收盘价并标出2008~2009 金融危机中的重要日期

1
2
3
4
5
6
7
8
from datetime import datetime
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
df = pd.read_csv("examples/spx.csv", index_col=0, parse_dates=True)

读取数据后的 df 如下

1
2
3
4
5
6
7
8
9
10
11
12
13
                SPX                     
Date
1990-02-01 328.79
1990-02-02 330.92
1990-02-05 331.85
1990-02-06 329.66
1990-02-07 333.75
... ...
2011-10-10 1194.89
2011-10-11 1195.54
2011-10-12 1207.25
2011-10-13 1203.66
2011-10-14 1224.58
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
spx = df["SPX"]                                                    
spx.plot(ax=ax, style="k-")

crisis_data = [
(datetime(2007, 10, 11), "Peak of bull market"),
(datetime(2008, 3, 12), "Bear Stearns Fails"),
(datetime(2008, 9, 15), "Lehman Bankruptcy")
]

for date, label in crisis_data:
ax.annotate(label, xy=(date, spx.asof(date) + 75)
,xytext=(date, spx.asof(date) + 225)
,arrowprops=dict(facecolor="black", headwidth=4, headlength=4)
,horizontalalignment="left"
,verticalalignment="top"
)


ax.set_xlim(["1/1/2007", "1/1/2011"])
ax.set_ylim([600, 1800])
ax.set_title("Important dates in the 2008-2009 financial crisis")

fig.show()

matplotlib 有表示多种常见图形的对象,patches。一些图形可以在 matplotlib.pyplot 中找到,例如 Rectangle, Circle。图形的全集在 matplotlib.patches

生成图形的过程:
step1: 生成 patch(补丁)对象 shp
step2: 调用 ax.add_patch(shp)

1
2
3
4
5
6
7
8
9
10
11
12
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)

rect = plt.Rectangle((0.2, 0.75), 0.4, 0.15, color="k", alpha=0.3)
circ = plt.Circle((0.7, 0.2), 0.15, color="b", alpha=0.3)
pgon = plt.Polygon([[0.15, 0.15], [0.35, 0.4], [0.2, 0.6]], color="g", alpha=0.5)

ax.add_patch(rect)
ax.add_patch(circ)
ax.add_patch(pgon)

fig.show()

将图片保存到文件

将活动图片保存到文件,文件类型从文件扩展名推断

1
plt.savefig("filename.svg")

一些参数:
dpi: 控制每英寸点数的分辨率
bbox_inches: 修剪实际图形的空白
facecolor, edgecolor: 子图之外的图形背景颜色,默认 w(百色)
format: 文件格式
bbox_inched: 要保存的图片范围,tight 回去出图片周围空白的部分
fname: 包含文件路径或 Python 文件型对象的字符串,格式是由文件扩展名推断出来的

1
2
# 得 png 图片,用最小的空白,有 400dpi
plt.savefig("filename.png", dpi=400, bbox_inches="tight")

savefig 可以将图片写入所有文件型对象中,例如 BytesIO

1
2
3
4
5
6
from io import BytesIO

buffer = BytesIO()
plt.savefig(buffer)
plt.savefig(buffer)
plt_data = buffer.getvalue()

matplotlib 设置

图形大小、子图间距、颜色、字体大小、网格样式

rc 方法是 Python 编程修改配置的一种方式

1
plt.rc("figure", figsize=(10, 10))

rc 第一个参数是像自定义的组件,例如 figure, axes, stick, ytick, “grid”, “legend”

matplotlib 配置参考 .matplotlibrc 该文件在 matplotlib/mpl-data

pandas 绘图与 seaborn 绘图

matplotlib: 用基本组件组装图表

  • 线
  • 散点图
  • 轮廓
  • 图例
  • 标题
  • 刻度

折线图

1
2
series.plot()
df.plot()
  • series.plot 传入 Series 对象的索引作为 x 轴,可以 use_index=False 禁用
series.plot 选项 描述
label 图例标签
ax 所用 matplotlib 子图对象,没传值则用当前活动子图
style 样式字符串,例如 ko--
alpha 不透明度
kind 可以是 area, bar, barh, density, hist, kde, line, pie
logy use_index
rot 刻度标签的旋转(0~360)
xticks 用于 x 轴刻度的值
yticks 用于 y 轴刻度的值
xlim x 轴范围
ylim y 轴范围
grid 展示轴网络(默认开)
df.plot 选项 描述
subplots 将 DataFrame 每一列绘制在独立的子图中。
sharex True: 共享相同的 x 轴,刻度和范围
sharey True: 共享相同的 y 轴
figsize 用于生成图片尺寸的元组
legend 添加子图图例(默认 True)
sort_columns 按字母顺序绘制各列,默认原顺序

柱状图

1
2
df.plot.bar()
df.plot.barh()

Series 例子

1
2
3
4
fig, axes = plt.subplots(2, 1)
series = pd.Series(np.random.randn(16), index=list("abcdefghijklmnop"))
series.plot.bar(ax=axes[0], color="k", alpha=0.7)
series.plot.barh(ax=axes[1], color="k", alpha=0.7)

DataFrame 中,柱状图将每一行中的值分组到并排的柱子中的一组

1
2
3
4
5
df = pd.DataFrame(np.random.rand(6, 4)
,index=["one", "two", "three", "four", "five", "six"]
,columns=pd.Index(["A", "B", "C", "D"], name="Genus"))
df.plot.bar()
df.plot.barh(stacked=True, alpha=0.5)


  • 列名会用做图例标题
  • 可以传递 stacked=True 生成堆积柱状图
  • series.value_counts().plot.bar() 可以对 Series 的值频率进行可视化

sns.barplot

对于绘图前需要聚合或汇总的数据,用 seaborn 会使工作更简单

  • sns.barplot(data=df) 的柱状图展示的是各个列的平均值,黑线是 95% 置信区间

  • 可以传入 x="key1", y="key2"。例如 sns.barplot(x=”key1”, y=”key2”, data=df, origin=”h”)

直方图与密度图

直方图用于给出值频率的离散显示。数据点被分成离散的,均匀间隔的箱,且绘制箱中数据点的数量。

1
series.plot.hist()

密度图是一种与直方图相关的图表类型。通过计算可能产生观测数据的连续概率分布估计而产生。

通常的做法是阿静这种分布近似为内核的混合,因此密度图也成为内核密度估计图(KDE)。

1
2
series.plot.kde()
series.plot.density()

DataFrame 可以直接用 hist 方法得到所有列的直方图 df.hist()

sns.distplot() 可以绘制直方图和连续密度估计。

1
sns.distplot(series, bins=100, color="k")

散点图或点图

散点图或点图用于检验两个一维数据序列之间的关系。

sns.regplot(x="key1", y="key2", data=df) 绘制散点图并拟合出一条线性回归线

在探索性数据分析中,查看一组变量的所有散点图,对应的图表叫成对图或散点图矩阵,可以用 sns.pairplot() 画散点图矩阵,其中对角线是变量的直方图或密度估计。

1
sns.pairplot(data, diag_kind="kde", plot_kws={"alpha": 0.2})

sns.pairplot() 常用参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
hue: 针对某一字段进行分类
例如 sns.pairplot(df, hue="key");

kind: 用于控制非对角线上的图的类型,可选"scatter"与"reg"
diag_kind: 控制对角线上的图的类型,可选"hist"与"kde"
例如 sns.pairplot(diabetes,kind="reg",diag_kind="kde")

palette:控制色调
例如 sns.pairplot(df,hue="种类",palette="husl")

markers:控制散点的样式
例如 sns.pairplot(df,hue="Outcome",markers=["+", "s", "D"])

单独用 vars 参数选择两种属性
例如: sns.pairplot(df, vars=["key1","key2"])

用 x_vars 和 y_vars 参数指定,需要同时指定
sns.pairplot(df, x_vars=["key1","key2"],
y_vars=["key3","key4"])

分面网格和分类数据

如果数据集有额外的分组维度。用分面网络是利用多种分组变量对数据进行可视化的方式。

考虑以下 tips 数据

1
2
3
4
5
6
7
8
9
10
11
12
     total_bill   tip smoker   day    time  size   tip_pct
0 16.99 1.01 No Sun Dinner 2 0.063204
1 10.34 1.66 No Sun Dinner 3 0.191244
2 21.01 3.50 No Sun Dinner 3 0.199886
3 23.68 3.31 No Sun Dinner 2 0.162494
4 24.59 3.61 No Sun Dinner 4 0.172069
.. ... ... ... ... ... ... ...
239 29.03 5.92 No Sat Dinner 3 0.256166
240 27.18 2.00 Yes Sat Dinner 2 0.079428
241 22.67 2.00 Yes Sat Dinner 2 0.096759
242 17.82 1.75 No Sat Dinner 2 0.108899
243 18.78 3.00 No Thur Dinner 2 0.190114
1
2
sns.factorplot(x="day", y="tip_pct", hue="time", 
col="smoker", kind="bar", data=df[df.tip_pct < 1])

除了根据 time 在一个面内将不同的柱分组为不同的颜色,还可以通过每个时间值添加一行来扩展分面网络

1
2
sns.factorplot(x="day", y="tip_pct", row="time", 
col="smoker", kind="bar", data=df[df.tip_pct < 1])

factorplot 支持很多有用的图类型:例如箱型图(显示中位数、四分位数、异常值)

1
2
sns.factorplot(x="tip_pct", y="day",
kind="box", data=df[df.tip_pct < 0.5])

还可以用 sns.FacetGrid 类创建分面网格图。

热度图

heatmap 热度图是 seaborn 中常用的图

  • 拿到一批数据一般会求特征之间的相关系数(pd.curr()),然后放到 heatmap,可以很清楚的看到两个特征的相关程度
1
sns.heatmap(df.corr(), annot=True, cmap="YlGnBu");

其它 Python 可视化工具

  • bokeh, plotly: 在 web 浏览器中创建动态的,交互式图像的工作

Share