信息可视化,即绘图,主要学习 matplotlib 及以其为基础的库
1. 简明 matplotlib 入门
% matplotlib notebook
import matplotlib. pyplot as plt
import numpy as np
data = np. arange( 10 )
plt. plot( data)
1.1 图片与子图
matplotlib所绘制的图片位于 Figure 对象中,可以使用 plt.figure 生成一个图片,但该图片是一个空白; 使用 add_subplot 创建一个或多个子图; 输入绘图命令 plt.plot 后,默认在最后一个图片和子图上进行绘制; fig.add_subplot 返回的是 Axes Subplot 对象,因此可以直接在其他空白的子图上调用对象的实例方法进行绘图;
fig = plt. figure( )
ax1 = fig. add_subplot( 2 , 2 , 1 )
ax2 = fig. add_subplot( 2 , 2 , 2 )
ax3 = fig. add_subplot( 2 , 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,返回新的 Figure 对象和子图对象组成的数组,该数组可以像二维数组一样进行索引(如 axes[0, 1]) 调整子图周围的间距:subplots_adjust
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( left= None , bottom= None , right= None , top= None , wspace= 0 , hspace= 0 )
pyplot.subplots 选项:
参数 描述 nrows 子图的行数 ncols 子图的列数 sharex 所有子图使用相同的 x 轴刻度 sharey 所有子图使用相同的 y 轴刻度 subplot_kw 传入 add_subplot 的关键字参数字典,用于生成子图**fig_kw生成图片时使用的额外关键字参数,例如 plt.subplots(2, 2, figsize=(8, 6))
1.2 颜色、标记和线类型
既可以使用如 “k–” 这样的字符串来指定颜色和线类型等,也可以使用参数名更显式地表达:
plt. plot( np. random. randn( 30 ) . cumsum( ) , 'ko--' )
plt. plot( np. random. randn( 30 ) . cumsum( ) , color= 'k' , linestyle= '--' , marker= 'o' )
plt. plot( np. random. randn( 30 ) . cumsum( ) , color= 'k' , linestyle= 'dashed' , marker= 'o' )
对于折线图,后续的点默认是线性内插的,可以通过 drawstyle 进行更改; 要生成图例,必须调用 plt.legend,无论是否传递了 label
data = np. random. randn( 30 ) . cumsum( )
plt. plot( data, 'k--' , label= 'Default' )
plt. plot( data, 'k-' , drawstyle= 'steps-post' , label= 'steps-post' )
plt. legend( loc= 'best' )
1.3 刻度、标签和图例
pyplot 的刻度等方法有两种方式:在没有传递函数参数 的时候为获取 当前参数值(如 plt.xlim() 返回当前 x 轴绘图范围);在传入函数参数 的时候为设定 参数值(如 plt.xlin([0, 10]) 会将 x 轴的范围设置为 0 到 10) pyplot 的每个方法都对应于 subplot 实例的两个方法,如 xlim 对应于 ax.get_xlim 和 ax.set_xlim; 设置标题、轴标签、刻度和刻度标签示例:
fig = plt. figure( )
ax = fig. add_subplot( 1 , 1 , 1 )
ax. plot( 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 first matplotlib plot' )
ax. set_xlabel( 'Stages' )
轴类型的 set 方法允许批量设置绘图属性:
props = {
'title' : 'My first matplotlib plot' ,
'xlabel' : 'Stages'
}
ax. set ( ** props)
添加图例:添加每个图标时传递 label 参数(若不要图例中的元素,则不要传递 label 参数),并调用 ax.legend() 或 plt.legend():
fig = plt. figure( )
ax = fig. add_subplot( 1 , 1 , 1 )
ax. plot( randn( 1000 ) . cumsum( ) , 'k' , label= 'one' )
ax. plot( randn( 1000 ) . cumsum( ) , 'k--' , label= 'two' )
ax. plot( randn( 1000 ) . cumsum( ) , 'k.' , label= 'three' )
ax. legend( )
1.4 注释与子图加工
在图表上绘制自己的注释,其中可能包含文本(text)、箭头(arrow)以及其他图形。注释可以同时绘制文本和箭头,以 2007 年以来标普 500 的收盘价为例,在图标中标注从 2008 年到 2009 年金融危机中的重要日期:
from datetime import datetime
fig = plt. figure( )
ax = fig. add_subplot( 1 , 1 , 1 )
data = pd. read_csv( r'C:\Users\Raymone\Data Analysis\examples\spx.csv' ,
index_col= 0 , parse_dates= True )
spx = data[ '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 , width= 2 , 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' )
matplotlib 含有多种常见图形的对象,这些对象的引用是 matplotlib.patches。想要在图标中添加图形时,需要生成 patch (补丁)对象 shp,并调用 ax.add_patch(shp)将它加入到子图中:
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)
1.5 将图片保存到文件
保存至硬盘:
plt. savefig( 'figpath.png' , dpi= 400 , bbox_inches= 'tight' )
保存至文件型对象,如 BytesIO:
from io import BytesIO
buffer = BytesIO( )
plt. savefig( buffer )
plot_data = buffer . getvalue( )
figure.savefig 选项:
参数 描述 fname 包含文件路径或Python文件型对象的字符串。图片格式是从文件扩展名中推断出来的 dpi 每英寸点数的分辨率,默认为100 facecolor, edgecolor 子图之外的图形背景颜色,默认情况下是 ‘w’ 白色 format 文件格式 bbox_inches 要保存的图片范围,如果传递 tight,则去掉图片周围空白的部分
1.6 matplotlib 设置
设置全局参数来定制图片,包括图形大小,子图间距,颜色,字体大小和网格样式等:
plt. rc( 'figure' , figsize= ( 10 , 10 ) )
font_options = { 'family' : 'monospace' , 'weight' : 'bold' , 'size' : 'small' }
plt. rc( 'font' , ** font_options)
2. 使用 pandas 和 seaborn 绘图
2.1 折线图
Series 和 DataFrame 都有一个 plot 方法,用于绘制基本图形,默认绘制折线图:
s = pd. Series( np. random. randn( 10 ) . cumsum( ) , index= np. arange( 0 , 100 , 10 ) )
s. plot( )
df = pd. DataFrame( np. random. randn( 10 , 4 ) . cumsum( 0 ) ,
columns= [ 'A' , 'B' , 'C' , 'D' ] , index= np. arange( 0 , 100 , 10 ) )
df. plot( )
Series.plot 方法参数
参数 描述 label 图例标签 ax 绘图所用的 matplotlib 子图对象,如果没有传值,则使用当前活动的 matplotlib 子图 style 传给 matplotlib 的样式字符串,如 ‘ko–’ alpha 图片不透明度(从 0 到 1) kind 可以是 ‘area’, ‘bar’, ‘barh’, ‘density’, ‘hist’, ‘kde’, ‘line’, ‘pie’ logy 在 y 轴上使用对数缩放 use_index 使用对象索引刻度标签,默认为 True rot 刻度标签的旋转(0~360) xticks 用于 x 轴刻度的值 yticks 用于 y 轴刻度的值 xlim x 轴范围 ylim y 轴范围 grid 展示轴网格,默认打开
DataFrame 的 plot 参数:
参数 描述 subplots 将 DataFrame 的每一列绘制在独立的子图中 sharex 若 subplots=True,则共享相同的 x 轴、刻度和范围 sharey 若 subplots=True,则共享相同的 y 轴 figsize 用于生成图片尺寸的元组 title 标题字符串 legend 添加子图图例,默认为 True sort_columns 按字母顺序绘制各列,默认情况下使用已有的列顺序
2.2 柱状图
plot.bar()和plot.barh()可以分别绘制垂直和水平柱状图,Series 或 DataFrame 的索引将会被用作 x 轴刻度(bar)或 y轴刻度(barh)
fig, axes = plt. subplots( 2 , 1 )
data = pd. Series( np. random. rand( 16 ) , index= list ( 'abcdefghijklmnop' ) )
data. plot. bar( ax= axes[ 0 ] , color= 'k' , alpha= 0.7 )
data. plot. barh( ax= axes[ 1 ] , color= 'k' , alpha= 0.7 )
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 )
绘制一个堆积柱形图,用于展示每个派对在每天的数据点占比:
tips = pd. read_csv( r'C:/Users/Raymone/Data Analysis/examples/tips.csv' )
party_counts = pd. crosstab( tips[ 'day' ] , tips[ 'size' ] )
party_counts = party_counts. loc[ : , 2 : 5 ]
party_pcts = party_counts. div( party_counts. sum ( 1 ) , axis= 0 )
party_pcts. plot. bar( )
对于绘图前需要聚合或汇总的数据,使用 seaborn 包可以使工作更为简单,如下示例使用 seaborn 进行按星期日期计算小费百分比:
import seaborn as sns
tips[ 'tip_pct' ] = tips[ 'tip' ] / ( tips[ 'total_bill' ] - tips[ 'tip' ] )
sns. barplot( x= 'tip_pct' , y= 'day' , data= tips)
sns. barplot( x= 'tip_pct' , y= 'day' , hue= 'time' , data= tips)
2.3 直方图和密度图
直方图是一种条形图,用于给出值频率的离散显示。数据点被分成均匀的离散的箱,并绘制每个箱中数据点的数量。使用 plot.hist 方法制作小费占总费用百分比的直方图:
tips[ 'tip_pct' ] . plot. hist( bins= 50 )
密度图是一种与直方图相关的图标类型,通过计算可能产生观测数据的连续概率分布估计而产生。通常的做法是将这种分布近似为“内核”的混合,也就是像正态分布那样简单的分布。因此密度图也称为内核密度估计图(KDE):
tips[ 'tip_pct' ] . plot. density( )
sns.distplot 方法可以绘制直方图和连续密度估计,如下为两个不同标准正态分布组成的双峰分布:
comp1 = np. random. normal( 0 , 1 , size= 200 )
comp2 = np. random. normal( 10 , 2 , size= 200 )
values = pd. Series( np. concatenate( [ comp1, comp2] ) )
sns. distplot( values, bins= 100 , color= 'k' )
2.4 散点图或点图
点图或散点图可以用于检验两个一维数据之间的关系,使用seaborn 的 regplot 方法,该方法可以绘制散点图,并拟合出一条线性回归线。如下为计算数据集中一些变量的对数差:
macro = pd. read_csv( r'C:/Users/Raymone/Data Analysis/examples/macrodata.csv' )
data = macro[ [ 'cpi' , 'm1' , 'tbilrate' , 'unemp' ] ]
trans_data = np. log( data) . diff( ) . dropna( )
sns. regplot( 'm1' , 'unemp' , data= trans_data)
plt. title( 'Changes in log %s versus log %s' % ( 'm1' , 'unemp' ) )
使用 pairplot 绘制成对图(或散点图矩阵),其中在对角线上放置的是每个变量的直方图或密度估计值:
sns. pairplot( trans_data, diag_kind= 'kde' , plot_kws= { 'alpha' : 0.2 } )
2.5 分面网格和分类数据
分面网格是利用多种分组变量对数据进行可视化的方式:
sns. catplot( x= 'day' , y= 'tip_pct' , hue= 'time' , col= 'smoker' , kind= 'bar' ,
data= tips[ tips. tip_pct < 1 ] )
sns. catplot( x= 'day' , y= 'tip_pct' , row= 'time' , col= 'smoker' , kind= 'bar' ,
data= tips[ tips. tip_pct < 1 ] )
sns. catplot( x= 'tip_pct' , y= 'day' , kind= 'box' , data= tips[ tips. tip_pct < 0.5 ] )