python数据可视化(matplotlib,pandas绘图,直方图,散点图,柱状图,折线图,箱线图)
2016-10-09 15:58
896 查看
数据可视化
数据可视化对于数据描述以及探索性分析至关重,恰当的统计图表可以更有效的传递数据信息。在 Python 中已经有很多数据可视化方面的第三方程序包,例如:
matplotlibChaco
PyX
Bokeh
本节,我们将重点学习 matplotlib 的基础绘图功能以及 pandas 的高级可视化功能,这也是现在最为常用、最为稳健,同时功能也非常丰富的数据可视化的解决方案。
课程目标:
熟悉几种常用的数据可视化展示方式掌握散点图、直方图、箱线图等图像绘制方法
In [1]:
# 导入一些需要用到的包 import pandas as pd import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt %matplotlib inline # 配置 pandas pd.set_option('display.notebook_repr_html', False) pd.set_option('display.max_columns', 20) pd.set_option('display.max_rows', 25)
Matplotlib 绘图
In [2]:plt.plot(np.random.normal(size=100), np.random.normal(size=100), 'ro')
Out[2]:
[<matplotlib.lines.Line2D at 0x7f27e30e08d0>]
上图绘制了两组来自正态分布的随机数的散点图,“ro”是一个缩写参数,表示用“红色圆圈”绘图。这种绘图很简单,我们可以进一步通过拆分绘图流程来得到更加复杂的图像。
In [3]:
with mpl.rc_context(rc={'font.family': 'serif', 'font.weight': 'bold', 'font.size': 8}): fig = plt.figure(figsize=(6,3)) ax1 = fig.add_subplot(121) ax1.set_xlabel('some random numbers') ax1.set_ylabel('more random numbers') ax1.set_title("Random scatterplot") plt.plot(np.random.normal(size=100), np.random.normal(size=100), 'r.') ax2 = fig.add_subplot(122) plt.hist(np.random.normal(size=100), bins=15) ax2.set_xlabel('sample') ax2.set_ylabel('cumulative sum') ax2.set_title("Normal distrubution") plt.tight_layout() plt.savefig("normalvars.png", dpi=150)
fig = plt.figure(figsize=(6,3)),定义一个长为6宽为3英寸的画布 ax1 = fig.add_subplot(121),将画布分为1行2列,从左到右从上到下取第1块
matplotlib 是一个相对初级的绘图包,直接输出的结果布局并不是十分美观,但是使用者可以通过很多种灵活的方式来调试输出的图像。
Pandas 绘图
相对于 matplotlib 来讲,Pandas 支持 DataFrame 和 Series 两种比较高级的数据结构,可以想象得到用其绘制出图像的形式。In [4]:
normals = pd.Series(np.random.normal(size=10)) normals.plot()
Out[4]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f27e30f23d0>
可以发现,默认绘制的是折线图,并且有灰色的网格线。当然,这些都可以修改。
In [5]:
normals.cumsum().plot(grid=False)
Out[5]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f27df5a6090>
对于 DataFrame 结构的数据,也可以进行类似的操作:
In [6]:
variables = pd.DataFrame({'normal': np.random.normal(size=100), 'gamma': np.random.gamma(1, size=100), 'poisson': np.random.poisson(size=100)}) variables.cumsum(0).plot()
Out[6]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f27df4aa410>
Pandas 还支持这样的操作:利用参数“subplots”绘制 DataFrame 中每个序列对应的子图
In [7]:
variables.cumsum(0).plot(subplots=True)
Out[7]:
array([<matplotlib.axes._subplots.AxesSubplot object at 0x7f27df48c750>, <matplotlib.axes._subplots.AxesSubplot object at 0x7f27df321990>, <matplotlib.axes._subplots.AxesSubplot object at 0x7f27df2a66d0>], dtype=object)
或者,我们也可以绘制双坐标轴,将某些序列用次坐标轴展示,这样可以展示更多细节并且图像中没有过多空白。
In [8]:
variables.cumsum(0).plot(secondary_y='normal')
Out[8]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f27df4b4910>
如果你有更多的绘图要求,也可以直接利用 matplotlib 的 “subplots” 方法,手动设置图像位置:
In [9]:
fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(12, 4)) for i,var in enumerate(['normal','gamma','poisson']): variables[var].cumsum(0).plot(ax=axes[i], title=var) axes[0].set_ylabel('cumulative sum')
Out[9]:
<matplotlib.text.Text at 0x7f27deffc3d0>
柱状图
我们常用柱状图来展示和对比可测数据,比如计数或流量统计。在 Pandas 中,我们通过设置“plot”方法“kind='bar”参数,即可绘制柱状图。 下面我们以泰坦尼克数据集为例,进行相关绘图说明。In [10]:
titanic = pd.read_excel("data/titanic.xls", "titanic") titanic.head()
Out[10]:
pclass survived name sex \ 0 1 1 Allen, Miss. Elisabeth Walton female 1 1 1 Allison, Master. Hudson Trevor male 2 1 0 Allison, Miss. Helen Loraine female 3 1 0 Allison, Mr. Hudson Joshua Creighton male 4 1 0 Allison, Mrs. Hudson J C (Bessie Waldo Daniels) female age sibsp parch ticket fare cabin embarked boat body \ 0 29.0000 0 0 24160 211.3375 B5 S 2 NaN 1 0.9167 1 2 113781 151.5500 C22 C26 S 11 NaN 2 2.0000 1 2 113781 151.5500 C22 C26 S NaN NaN 3 30.0000 1 2 113781 151.5500 C22 C26 S NaN 135.0 4 25.0000 1 2 113781 151.5500 C22 C26 S NaN NaN home.dest 0 St Louis, MO 1 Montreal, PQ / Chesterville, ON 2 Montreal, PQ / Chesterville, ON 3 Montreal, PQ / Chesterville, ON 4 Montreal, PQ / Chesterville, ON
In [11]:
titanic.groupby('pclass').survived.sum().plot(kind='bar')
Out[11]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f27deaecc50>
In [12]:
titanic.groupby(['sex','pclass']).survived.sum().plot(kind='barh')
Out[12]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f27deb28250>
In [13]:
death_counts = pd.crosstab([titanic.pclass, titanic.sex], titanic.survived.astype(bool)) death_counts.plot(kind='bar', stacked=True, color=['black','gold'], grid=False)
Out[13]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f27dea6d290>
还可以通过除以该组的总人数来对比不同组之间的存活率
In [14]:
death_counts.div(death_counts.sum(1).astype(float), axis=0).plot(kind='barh', stacked=True, color=['black','gold'])
Out[14]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f27de9847d0>
直方图
在数据分析之前,频数/率可以帮助我们了解数据的分布情况。直方图是一种展示数据频数/率的特殊的柱状图,也就是说,y 轴是频数/率的度量,既可以是频数(计数)也可以是频率(占比)。比如,我们想知道泰坦尼克船票价格的分布情况:In [15]:
titanic.fare.hist(grid=False)
Out[15]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f27de7a5190>
“hist”方法默认将连续票价划分为 10 个区间,我们可以通过设置参数“bins”来设定区间个数(或者说设定直方图的宽度):
In [16]:
titanic.fare.hist(bins=30)
Out[16]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f27de7eca50>
有很多种计算最优区间个数的算法,且都会一定程度的随观测值个数变化。
In [17]:
sturges = lambda n: int(np.log2(n) + 1) square_root = lambda n: int(np.sqrt(n)) from scipy.stats import kurtosis doanes = lambda data: int(1 + np.log(len(data)) + np.log(1 + kurtosis(data) * (len(data) / 6.) ** 0.5)) n = len(titanic) sturges(n), square_root(n), doanes(titanic.fare.dropna())
Out[17]:
(11, 36, 14)
In [18]:
titanic.fare.hist(bins=doanes(titanic.fare.dropna()))
Out[18]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f27de69bc10>
和直方图类似,密度图也描述了数据的分布情况,可以看成将直方图区间无限细分后形成的平滑曲线。设置“plot”方法的参数 kind='kde',即可绘制密度图,其中 'kde' 表示“kernel density estimate”。
In [19]:
titanic.fare.dropna().plot(kind='kde', xlim=(0,600))
Out[19]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f27d810a950>
通常,直方图和密度图会绘制在同一张图里:
In [20]:
titanic.fare.hist(bins=doanes(titanic.fare.dropna()), normed=True, color='lightseagreen') titanic.fare.dropna().plot(kind='kde', xlim=(0,600), style='r--')
Out[20]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f27d8103350>
这里我们需要通过设置参数“normed=True”将直方图标准化处理,因为概率密度分布是标准化的,
箱线图
另外一种展示数据分布的可视化图形是箱线图,主要展示分位数,具体包括上四分位数、下四分位数、中位数以及上下5%的极值。In [21]:
titanic.boxplot(column='fare', by='pclass', grid=False)
Out[21]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f27d7fc8590>
可以将箱线图看成数据的分布图,图中“+”的点表示异常值。
可以将实际数据同时展示在箱线图中来丰富图像信息,这种做法比较适合观测值较少的数据集。
In [22]:
bp = titanic.boxplot(column='age', by='pclass', grid=False) for i in [1,2,3]: y = titanic.age[titanic.pclass==i].dropna() # 通过设置随机值,使观测值在x轴方向不重叠 x = np.random.normal(i, 0.04, size=len(y)) plt.plot(x, y, 'r.', alpha=0.2)
当数据分布非常稠密时,有以下两种方式来增强图形的可读性: 1、降低透明度,使数据点半透明 2、增加数据点 x 轴方向的随机距离,减少数据点之间的重叠
一个和箱线图相近但远不及箱线图的图像叫做“dynamite”图,本质上就是给出标准偏差的柱状图
In [23]:
titanic.groupby('pclass')['fare'].mean().plot(kind='bar', yerr=titanic.groupby('pclass')['fare'].std())
Out[23]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f27d7d22490>
为什么我们比较少用这种绘图方式呢?
柱状图覆盖的区域并没有实际含义
信息含量低,只反映了6个数值:三个均值和三个标准差
掩藏了原始数据的真实信息
相比之下,箱线图是更好的选择。
In [24]:
data1 = [150, 155, 175, 200, 245, 255, 395, 300, 305, 320, 375, 400, 420, 430, 440] data2 = [225, 380] fake_data = pd.DataFrame([data1, data2]).transpose() p = fake_data.mean().plot(kind='bar', yerr=fake_data.std(), grid=False)
In [25]:
fake_data = pd.DataFrame([data1, data2]).transpose() p = fake_data.mean().plot(kind='bar', yerr=fake_data.std(), grid=False) x1, x2 = p.xaxis.get_majorticklocs() plt.plot(np.random.normal(x1, 0.01, size=len(data1)), data1, 'ro') plt.plot([x2]*len(data2), data2, 'ro')
Out[25]:
[<matplotlib.lines.Line2D at 0x7f27d7c2c910>]
练习
用泰坦尼克数据集,绘制幸存者和死亡者年龄的密度图
散点图
下面以棒球数据集为例,讲解如何绘制散点图。In [26]:
baseball = pd.read_csv("data/baseball.csv") baseball.head()
Out[26]:
id player year stint team lg g ab r h ... rbi sb cs \ 0 88641 womacto01 2006 2 CHN NL 19 50 6 14 ... 2.0 1.0 1.0 1 88643 schilcu01 2006 1 BOS AL 31 2 0 1 ... 0.0 0.0 0.0 2 88645 myersmi01 2006 1 NYA AL 62 0 0 0 ... 0.0 0.0 0.0 3 88649 helliri01 2006 1 MIL NL 20 3 0 0 ... 0.0 0.0 0.0 4 88650 johnsra05 2006 1 NYA AL 33 6 0 1 ... 0.0 0.0 0.0 bb so ibb hbp sh sf gidp 0 4 4.0 0.0 0.0 3.0 0.0 0.0 1 0 1.0 0.0 0.0 0.0 0.0 0.0 2 0 0.0 0.0 0.0 0.0 0.0 0.0 3 0 2.0 0.0 0.0 0.0 0.0 0.0 4 0 4.0 0.0 0.0 0.0 0.0 0.0 [5 rows x 23 columns]
在探索变量之间的关系=时,可以绘制散点图。Series 或者 DataFrame 结构的数据并没有相应的绘制散点图的方法,必须使用 matplotlib 的“scatter”函数。
In [27]:
plt.scatter(baseball.ab, baseball.h) plt.xlim(0, 700); plt.ylim(0, 200)
Out[27]:
(0, 200)
可以通过赋予样本点不同的大小和颜色来展示更多的信息。
In [28]:
plt.scatter(baseball.ab, baseball.h, s=baseball.hr*10, alpha=0.5) plt.xlim(0, 700); plt.ylim(0, 200)
Out[28]:
(0, 200)
In [29]:
plt.scatter(baseball.ab, baseball.h, c=baseball.hr, s=40, cmap='hot') plt.xlim(0, 700); plt.ylim(0, 200);
可以使用“scatter_matrix”函数同时展示多个变量之间的散点图,最终会生成一个两两对应的散点图矩阵,可以选择在对角线展示直方图或者密度图。
In [30]:
_ = pd.scatter_matrix(baseball.loc[:,'r':'sb'], figsize=(12,8), diagonal='kde')
栅栏(trellis)图形
最近 Pandas 增加了利用 GofG 方法的绘图函数,使得栅栏图的绘制变得十分简单。栅栏图可以用于展示两个变量在不同条件下的关系,实现了利用平面图形展示高于两个维度的信息。下面利用泰坦尼克数据集绘制一个栅栏图来同时展示 4 个变量之间的关系,有以下 4 个步骤: 1、创建一个仅和数据集中两个变量有关的“RPlot” 2、利用“passenger class ”和“sex”两个变量的不同取值最为条件区分,添加网格 3、增加用于可视化的实际数据 4、可视化展示
In [31]:
from pandas.tools.rplot import * titanic = titanic[titanic.age.notnull() & titanic.fare.notnull()] tp = RPlot(titanic, x='age') tp.add(TrellisGrid(['pclass', 'sex'])) tp.add(GeomDensity()) _ = tp.render(plt.gcf())
/home/datartisan/.pyenv/versions/2.7.12/envs/datacademy-lesson-27/lib/python2.7/site-packages/ipykernel/__main__.py:1: FutureWarning: The rplot trellis plotting interface is deprecated and will be removed in a future version. We refer to external packages like seaborn for similar but more refined functionality. See our docs http://pandas.pydata.org/pandas-docs/stable/visualization.html#rplot for some example how to convert your existing code to these packages. if __name__ == '__main__':
利用张力障碍数据集,将“age”和“twstrs”两个变量之间的关系作为“week”和“treat”两个变量的函数,通过绘制散点图,我们可以同时探索不同情境下二者之间的关系,并进行拟合:
In [32]:
cdystonia = pd.read_csv("data/cdystonia.csv", index_col=None) cdystonia.head()
Out[32]:
patient obs week site id treat age sex twstrs 0 1 1 0 1 1 5000U 65 F 32 1 1 2 2 1 1 5000U 65 F 30 2 1 3 4 1 1 5000U 65 F 24 3 1 4 8 1 1 5000U 65 F 37 4 1 5 12 1 1 5000U 65 F 39
In [33]:
plt.figure(figsize=(12,12)) bbp = RPlot(cdystonia, x='age', y='twstrs') bbp.add(TrellisGrid(['week', 'treat'])) bbp.add(GeomScatter()) bbp.add(GeomPolyFit(degree=2)) _ = bbp.render(plt.gcf())
RPlot 不仅仅可以被用来绘制栅栏图,也可以通过使用不同的颜色、大小、形状等将多个变量绘制在一起。
In [34]:
cdystonia['site'] = cdystonia.site.astype(float)
In [35]:
plt.figure(figsize=(6,6)) cp = RPlot(cdystonia, x='age', y='twstrs') cp.add(GeomPoint(colour=ScaleGradient('site', colour1=(1.0, 1.0, 0.5), colour2=(1.0, 0.0, 0.0)), size=ScaleSize('week', min_size=10.0, max_size=200.0), shape=ScaleShape('treat'))) _ = cp.render(plt.gcf())
/home/datartisan/.pyenv/versions/2.7.12/envs/datacademy-lesson-27/lib/python2.7/site-packages/pandas/tools/rplot.py:167: FutureWarning: iget(i) is deprecated. Please use .iloc[i] or .iat[i] x = data[self.column].iget(index) /home/datartisan/.pyenv/versions/2.7.12/envs/datacademy-lesson-27/lib/python2.7/site-packages/pandas/tools/rplot.py:66: FutureWarning: iget(i) is deprecated. Please use .iloc[i] or .iat[i] x = data[self.column].iget(index) /home/datartisan/.pyenv/versions/2.7.12/envs/datacademy-lesson-27/lib/python2.7/site-packages/pandas/tools/rplot.py:208: FutureWarning: iget(i) is deprecated. Please use .iloc[i] or .iat[i] x = data[self.column].iget(index)
相关文章推荐
- Python数据可视化:Matplotlib 直方图、箱线图、条形图、热图、折线图、散点图。。。
- python数据分析——matplotlib生成折线图,散点图和直方图
- [转]用Matplotlib绘制 折线图 散点图 柱状图 圆饼图
- python绘图:matplotlib和pandas的应用
- Python中使用matPlotlib绘图-曲线图、柱状图、散列点
- 【python数据挖掘课程】十.Pandas、Matplotlib、PCA绘图实用代码补充
- Python绘图问题:Matplotlib中柱状图bar使用
- python使用matplotlib模块绘制多条折线图、散点图
- 使用python的matplotlib(pyplot)画折线图和柱状图
- python:matplotlib及pandas绘图(1)
- matplotlib 柱状图、饼图;直方图、盒图
- 使用matplotlib绘图(二)之柱状图
- python:matplotlib及pandas绘图(2)
- python数据挖掘学习笔记】十.Pandas、Matplotlib、PCA绘图实用代码补充
- Python 3基础教程48-Matplotlib绘制散点图和柱状图
- matplotlib绘制直方图【柱状图】
- 使用matplotlib绘图(四)之散点图
- python绘图:matplotlib和pandas的应用
- python绘图:matplotlib和pandas的应用
- matplotlib绘图系列----3D曲面图与散点图