Pandas数据可视化工具——Seaborn用法整理(下)


(lpl22) #1

本文是基于StackAbuse的一篇讲解Seaborn的文章 上编写。 附示例及实现代码,可直接前往文末 一键克隆代码 进行实践研究。

在前一篇文章 Pandas数据可视化工具——Seaborn用法整理(上),我们了解了如何使用这些Seaborn代码绘制分布图和分类图。在本文中,我们将继续讨论Seaborn提供的一些其他以绘制不同类型统计图的功能,我们将从矩阵图开始讨论。

矩阵图

矩阵图是一种以行和列的形式显示数据的图。Heat maps是矩阵图的一个典型例子。

Heat Maps

Heat Maps通常用于以矩阵形式绘制数值列之间的相关性。这里需要提到的是,要绘制矩阵图,需要有关于行和列的有价值的信息。延续上一篇文章的主题,我们将使用财报数据10-18年的数据,看看行和列标题是否都是有意义的信息。执行以下代码:

import pandas as pd  
import numpy as np
import matplotlib.pyplot as plt  
import seaborn as sns
df = DataSource('financial_statement_CN_STOCK_A').read(start_date='2010-04-01',end_date='2018-04-02')
df.head()

在输出中,您将看到如下结果:

从输出中可以看到,列标头包含有用的信息,如股票代码、日期、固定资产、营业利润等。而行标头只包含索引0、1、2等。一种方法是调用数据集上的corr()方法。函数的作用是:返回数据集中所有数字列之间的相关性。执行以下代码:

df_0 = df[['date','instrument','fs_operating_profit','fs_current_assets','fs_net_profit_ttm','fs_roe','fs_gross_profit_margin','fs_free_cash_flow']]
df_0.corr()

(这里为了使结果图简洁,只选择了六个统计量。)
在输出中,您将看到各列之间的相关系数,如下所示:

现在,要创建具有这些相关值的Heat Maps,需要调用heatmap()函数并将相关系数的DataFrame传递给它。请看下面的代码:

sns.heatmap(df_0.corr())

在输出中,您将看到如下结果:

从输出中可以看出,heatmap的基本功能是为行和列值的每个组合绘制一个框。图像的颜色取决于渐变。例如,在上面的图像中,如果两个特征之间有很高的相关性,对应的单元格或者方框是白偏向于色的,另一方面,如果没有相关性,对应的单元格是黑色的。

通过为传递参数annot为True,相关系数也可以绘制在heatmap上。执行下面的代码,看看这是否有效:

sns.heatmap(df_0.corr(), annot=True)  

您还可以通过给cmap传递参数来更改heatmap的颜色。现在,看看下面的代码:

sns.heatmap(df_0.corr(), cmap='winter')  

结果如下:

除了仅使用所有列之间的相关性之外,还可以使用pivot_table函数指定索引、列以及希望看到的与索引和列对应的值。为了展示pivot_table函数的运行情况,我们可以观察单个股票的情况。这里我们

执行以下代码导入数据集并查看数据集的前5行:

df_1 = df.ix[df['instrument']=='600760.SHA']#选出某一只股票单独作图(否则图像无意义)
df_2 = df_1.pivot_table(index='fs_quarter_index', columns='fs_quarter_year', values='fs_roe' )  
df_2.head()

输出:

(由于财报数据没有类似月份的列,我们选择的时间也相对较短,本图美观度有所欠缺,不过重在总结方法)

现在使用pivot_table函数,我们可以创建一个Heat Maps,显示在特定年份的特定季度特定股票的净资产收益率(fs_roe)。为此,我们将输入季度(fs_quarter_index)作为index参数的值。index属性对应于行。接下来,我们需要将输入年份(fs_quarter_year)作为列参数。最后对于values参数,我们将输入净资产收益率(fs_roe)。执行以下代码:

sns.heatmap(df_2)

结果如下

从结果可以明显看出,该股票在这段时间里净资产收益率的变化

有时候,您会发现方框或单元格是重叠的,单元格边界之间的区别不是很清楚。要在单元格之间创建清晰的边界,可以使用linecolor和linewidths参数。看看下面的代码:

sns.heatmap(df_2, linecolor='blue', linewidth=1)  

在上面的代码中,我们输入了“blue”作为linecolor参数的值,而line width参数被设置为1。在输出中,您将看到每个单元格的蓝色边界:

如果需要更厚的边界,可以增加linewidth参数的值。

Cluster Map

除了Heat Map,另一个常用的矩阵图是Cluster Map。Cluster Map基本上使用层次聚类来对矩阵的行和列进行聚类。

让我们绘制一个Cluster Map,表示在特定季度和特定年份的净资产收益率。执行以下代码:

df_3 = df_1[['fs_quarter_index','fs_roe','fs_quarter_year']]
df_4 = df_3.pivot_table(index='fs_quarter_year', columns='fs_quarter_index', values='fs_roe')  
sns.clustermap(df_4)

要绘制集群映射,需要使用clustermap函数,与heat map函数一样,传递的数据集应该具有行和列的有意义的标题。上面代码的结果是这样的:

在输出中,您可以看到根据特定季度和特定年份聚集起来的净资产收益率。

至此,我们结束了关于矩阵图的讨论。在下一节中,我们将开始讨论Seaborn库的网格功能。

Seaborn网格

Seaborn中的网格允许我们根据图中使用的特性操作子图。

Pair Grid

在本系列文章的第1部分中,我们了解了如何使用pair plot绘制数据集中数字列的所有可能组合的散点图。

现在让我们在上述代码的基础上绘制Pair Plot。执行以下代码:

df_5 = df[['fs_account_payable','fs_account_receivable','fs_capital_reserves','fs_construction_in_process','fs_undistributed_profit']]
sns.pairplot(df_5) 

该代码输出是这样的:

现在我们来画Pair Grid看看Pair Grid和Pair Plot的区别。要创建对网格,只需将数据集传递给PairGrid函数,如下所示:

sns.PairGrid(df_5)

在输出中,您可以看到空网格。这就是pair grid函数的作用。它返回数据集中所有特性的空网格集。

接下来,您需要对pair grid函数返回的对象调用map函数,并将您希望在网格上绘制的绘图类型传递给它。让我们用对网格绘制一个散点图。

df_5 = df_5.dropna()
df_6 = sns.PairGrid(df_5)  
df_6.map(plt.scatter) 

输出是这样的:

您可以在看到df_5中所有列分别作x、y轴的散点图。

还可以在同一对网格上绘制不同类型的图。例如,如果您想在对角线上绘制“分布”图,在对角线的上半部分绘制“kdeplot”图,在对角线的下半部分绘制“散点”图,那么您可以分别使用map_diag、map_upper和map_lower函数。将绘制的绘图类型作为参数传递给这些函数。看看下面的代码:

grids = sns.PairGrid(df_5)  
grids.map_diag(sns.distplot)  
grids.map_upper(sns.kdeplot)  
grids.map_lower(plt.scatter)

代码结果如下:

从上面的图像中可以看出pair grid函数的真正威力。对角线上是分布图,上半部分是核密度图,下半部分是散点图。

Facet Grids

Facet Grid用于将两个或两个以上的分类特征与两个或两个以上的数字特征进行绘图。让我们画一个 Facet Grid来展示这几个统计量两两之间的关系。

在本节中,我们将再次使用财报数据的部分列。执行以下代码加载数据集:

df_6 = df[['fs_quarter_index','fs_roe','fs_quarter_year','fs_account_payable','fs_account_receivable','fs_capital_reserves','fs_construction_in_process','fs_undistributed_profit']]
df_6.head()


要绘制Facet Grid,使用FacetGrid()函数。函数的第一个参数是数据集,第二个参数col指定要在列上绘图的特性,而row参数指定行上的特性。函数的作用是:返回一个对象。与pair grid类似,您可以使用map函数指定要绘制的绘图类型。

执行以下脚本:(winsorize函数将df_6进行去极值处理,目的是使得结果更加具有表现力)

def winsorize(df, width=3):
    df = df.copy()
    factor_columns = set(df.columns).difference(['date','instrument'])
    for factor in factor_columns:
        mean = df[factor].mean()
        sigma = df[factor].std()
        df[factor] = df[factor].clip(mean-width*sigma,mean+width*sigma)
    return df
df_6 = winsorize(df_6)
grid = sns.FacetGrid(data=df_6, col='fs_quarter_year', row='fs_quarter_index')  
grid.map(sns.distplot, 'fs_roe') 

在上面的代码中,我们在小平面网格上绘制了净资产收益率分布图。输出是这样的:

从输出中,您可以看到4×9个图,单个图上展示了各个股票在特定年份特定季度的净资产收益率(fs_roe)的分布,这由FacetGrid()函数指定。

对于不同的子图之间,子图的位置决定了该子图的时间:第一行第一列的图为2009年第一季度的净资产收益率的分布图,以此类推

除了为一个特征绘制分布图外,我们还可以绘制包含面网格上两个特征的散点图。

例如,下面的代码为年份和季度绘制了应付账款(fs_account_payable)和资本公积金(fs_capital_reserves)的散点图。

grid = sns.FacetGrid(data=df_6, col='fs_quarter_year', row='fs_quarter_index')  
grid.map(sns.scatterplot, 'fs_account_payable','fs_capital_reserves') 

输出结果如下:

回归图

回归图,顾名思义,是用来进行两个或多个变量之间的回归分析。

在这一节中,我们将研究线性模型图,它根据数据绘制出两个变量之间的线性关系以及最佳拟合回归线。

为了绘制线性模型,使用lmplot()函数。第一个参数是要在x轴上绘制的特征,第二个变量是要在y轴上绘制的特征。最后一个参数是数据集。执行以下代码:

sns.lmplot(x='fs_account_payable', y='fs_capital_reserves', data=df_6)  

您还可以根据分类特征绘制多个线性模型。特性名作为值传递给hue参数。例如,如果要绘制不同季度的时候应付账款(fs_account_payable)和资本公积金(fs_capital_reserves)之间关系的多个线性模型,根据不同季度的情况,可以使用lmplot函数如下:

sns.lmplot(x='fs_account_payable', y='fs_capital_reserves', data=df_6,hue='fs_quarter_index')  

结果如下

020119

从输出可以看出,对于理想切割的钻石,克拉与价格之间的线性关系是最陡的,而对于合理切割的钻石,线性模型是最浅的。

除了为不同色调的cut feature绘制数据外,我们还可以为每个cut绘制一个plot。为此,需要将列名传递给col属性。看看下面的脚本:

sns.lmplot(x='fs_account_payable', y='fs_capital_reserves', data=df_6,col='fs_quarter_index')  

在输出中,您将看到钻石数据集的cut列中的每个值都有一个单独的列,如下所示:

您还可以使用aspect和size参数更改绘图的大小和纵横比。看看下面的代码:

sns.lmplot(x='fs_account_payable', y='fs_capital_reserves', data=df_6,col='fs_quarter_index',aspect = 0.5,size = 8)  

aspect参数定义宽度和高度之间的纵横比。长宽比为0.5意味着宽度是输出中所示高度的一半。

可以看出,图的大小已经发生了变化,字体大小仍然很小。在下一节中,我们将看到如何控制Seaborn图的字体和样式。

图像样式

Seaborn库提供了多种样式选项。在本节中,我们将讲解其中一些。

设置风格

函数的作用是:设置网格的样式。您可以将darkgrid、whitegrid、dark、white和tick作为参数传递给set_style函数。

在本节中,我们将再次使用df_6。执行以下代码以查看darkgrid样式。

df_6 = df_6.dropna()
sns.set_style('darkgrid')  
sns.distplot(df_6['fs_roe'])  

输出如下:

020122

在输出中,您可以看到我们有带有网格的黑色背景。让我们看看whitegrid是什么样子。执行以下代码:

sns.set_style('whitegrid')  
sns.distplot(df_6['fs_roe']) 

输出如下:

020123

现在你可以看到我们仍然有网格在背景中,但深灰色的背景是不可见的。我建议您尝试使用其他选项,看看哪种风格适合您。

改变图大小

由于Seaborn在后台使用Matplotlib函数,您可以使用Matplotlib的pyplot包来更改图形大小,如下图所示:

plt.figure(figsize=(8,4))  
sns.distplot(df_6['fs_roe'])  

在上面的代码中,我们将情节的宽度和高度分别设置为8英寸和4英寸。上面脚本的输出是这样的:

020124

设置 Context

您可以使用theset_context()函数,并将poster作为惟一的属性传递给它,如下所示:

sns.set_context('poster')  
sns.distplot(df_6['fs_roe'])  

在输出中,您应该看到一个符合海报标准的图,如下所示。例如,您可以看到字体比正常的图形大得多。

020125

小结

Seaborn库是用于数据可视化的高级Python库。本文是关于在Python中使用Seaborn实现数据可视化的系列文章的第2部分。在这篇文章中,我们看到了如何在Seaborn中绘制回归图和矩阵图。我们还了解了如何更改绘图样式和使用网格函数来操作子图。

克隆策略
In [1]:
import pandas as pd  
import numpy as np
import matplotlib.pyplot as plt  
import seaborn as sns
df = DataSource('financial_statement_CN_STOCK_A').read(start_date='2010-04-01',end_date='2018-04-02')
df.head()
Out[1]:
date instrument fs_account_payable fs_account_receivable fs_bps fs_capital_reserves fs_paicl_up_capital fs_cash_ratio fs_construction_in_process fs_deducted_profit ... fs_gross_revenues fs_total_profit fs_undistributed_profit fs_common_equity fs_eps_yoy fs_net_profit_yoy fs_operating_revenue_yoy fs_quarter fs_quarter_year fs_quarter_index
944 2010-04-01 600019.SHA 1.858261e+10 5.566287e+09 5.43 3.731431e+10 1.751200e+10 0.180692 1.374683e+10 5.465000e+09 ... 1.485253e+11 7.294556e+09 2.258399e+10 9.513690e+10 -10.810811 -9.954500 -25.959600 20091231 2009 4
945 2010-04-01 600487.SHA 3.750471e+08 4.569786e+08 7.77 5.960868e+08 1.661200e+08 0.535326 3.288308e+08 1.709535e+08 ... 1.887089e+09 2.585105e+08 4.387083e+08 1.291265e+09 72.698906 72.677597 31.261299 20091231 2009 4
946 2010-04-01 600449.SHA 3.622475e+08 5.332511e+07 10.60 9.614160e+08 1.951339e+08 1.039663 7.006000e+08 4.352370e+08 ... 1.810370e+09 5.422183e+08 8.237846e+08 2.068234e+09 47.127178 65.019501 30.862900 20091231 2009 4
947 2010-04-01 002277.SZA 3.383952e+08 1.517427e+07 7.76 9.431603e+08 1.940000e+08 1.393711 1.589278e+06 1.502409e+08 ... 2.746569e+09 2.020876e+08 3.111152e+08 1.505070e+09 8.849982 24.596701 23.756001 20091231 2009 4
948 2010-04-01 600199.SHA 1.160557e+08 3.396244e+07 2.50 4.568716e+08 2.607215e+08 0.961907 1.066648e+07 6.674769e+07 ... 1.045632e+09 9.454158e+07 -1.035893e+08 6.525847e+08 237.500000 227.058395 58.021198 20091231 2009 4

5 rows × 63 columns

In [2]:
df_0 = df[['date','instrument','fs_operating_profit','fs_current_assets','fs_net_profit_ttm','fs_roe','fs_gross_profit_margin','fs_free_cash_flow']]
df_0.corr()
Out[2]:
fs_operating_profit fs_current_assets fs_net_profit_ttm fs_roe fs_gross_profit_margin fs_free_cash_flow
fs_operating_profit 1.000000 0.547343 0.925979 0.012149 0.005188 0.133059
fs_current_assets 0.547343 1.000000 0.581674 0.007263 -0.022115 -0.233778
fs_net_profit_ttm 0.925979 0.581674 1.000000 0.010928 0.009337 0.080613
fs_roe 0.012149 0.007263 0.010928 1.000000 0.014537 0.000473
fs_gross_profit_margin 0.005188 -0.022115 0.009337 0.014537 1.000000 -0.037902
fs_free_cash_flow 0.133059 -0.233778 0.080613 0.000473 -0.037902 1.000000
In [3]:
sns.heatmap(df_0.corr())
Out[3]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f0b655c9f98>
In [4]:
sns.heatmap(df_0.corr(), annot=True)  
Out[4]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f0b5d59ca20>
In [5]:
sns.heatmap(df_0.corr(), cmap='winter')  
Out[5]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f0b5d6cad68>
In [6]:
df_1 = df.ix[df['instrument']=='600760.SHA']#选出某一只股票单独作图(否则图像无意义)
df_2 = df_1.pivot_table(index='fs_quarter_index', columns='fs_quarter_year', values='fs_roe' )  
df_2.head()
Out[6]:
fs_quarter_year 2010 2011 2012 2013 2014 2015 2016 2017
fs_quarter_index
1 2.7498 0.7075 -3.2262 -0.5574 -3.490400 -6.022500 -6.7528 -2.3352
2 3.5863 1.5894 -7.4195 -4.3701 -7.598500 -13.096000 -11.1244 -6.3778
3 3.3280 -1.8983 -10.4987 -8.4629 -12.274000 -20.780899 -4.5150 -9.3514
4 5.2545 -22.7731 -4.8134 2.3886 -20.903099 -44.125099 6.6687 18.6679
In [7]:
sns.heatmap(df_2)
Out[7]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f0b5d5e20b8>
In [8]:
sns.heatmap(df_2, linecolor='blue', linewidth=1)  
Out[8]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f0b14387550>
In [9]:
df_3 = df_1[['fs_quarter_index','fs_roe','fs_quarter_year']]
df_4 = df_3.pivot_table(index='fs_quarter_year', columns='fs_quarter_index', values='fs_roe')  
sns.clustermap(df_4)
Out[9]:
<seaborn.matrix.ClusterGrid at 0x7f0b14358eb8>
In [10]:
df_5 = df[['fs_account_payable','fs_account_receivable','fs_capital_reserves','fs_construction_in_process','fs_undistributed_profit']]
sns.pairplot(df_5)
Out[10]:
<seaborn.axisgrid.PairGrid at 0x7f0b5d6866d8>
In [11]:
sns.PairGrid(df_5)
Out[11]:
<seaborn.axisgrid.PairGrid at 0x7f0b0d576c50>
In [12]:
df_5 = df_5.dropna()
df_6 = sns.PairGrid(df_5)  
df_6.map(plt.scatter) 
Out[12]:
<seaborn.axisgrid.PairGrid at 0x7f0b0d6a31d0>
In [13]:
grids = sns.PairGrid(df_5)  
grids.map_diag(sns.distplot)  
grids.map_upper(sns.kdeplot)  
grids.map_lower(plt.scatter)
Out[13]:
<seaborn.axisgrid.PairGrid at 0x7f0b032a3b00>
In [14]:
df_6 = df[['fs_quarter_index','fs_roe','fs_quarter_year','fs_account_payable','fs_account_receivable','fs_capital_reserves','fs_construction_in_process','fs_undistributed_profit']]
df_6.head()
Out[14]:
fs_quarter_index fs_roe fs_quarter_year fs_account_payable fs_account_receivable fs_capital_reserves fs_construction_in_process fs_undistributed_profit
944 4 6.2174 2009 1.858261e+10 5.566287e+09 3.731431e+10 1.374683e+10 2.258399e+10
945 4 15.1226 2009 3.750471e+08 4.569786e+08 5.960868e+08 3.288308e+08 4.387083e+08
946 4 23.7960 2009 3.622475e+08 5.332511e+07 9.614160e+08 7.006000e+08 8.237846e+08
947 4 15.0875 2009 3.383952e+08 1.517427e+07 9.431603e+08 1.589278e+06 3.111152e+08
948 4 11.6040 2009 1.160557e+08 3.396244e+07 4.568716e+08 1.066648e+07 -1.035893e+08
In [15]:
def winsorize(df, width=3):
    df = df.copy()
    factor_columns = set(df.columns).difference(['date','instrument'])
    for factor in factor_columns:
        mean = df[factor].mean()
        sigma = df[factor].std()
        df[factor] = df[factor].clip(mean-width*sigma,mean+width*sigma)
    return df
df_6 = winsorize(df_6)
grid = sns.FacetGrid(data=df_6, col='fs_quarter_year', row='fs_quarter_index')  
grid.map(sns.distplot, 'fs_roe') 
Out[15]:
<seaborn.axisgrid.FacetGrid at 0x7f0b02c02400>
In [16]:
grid = sns.FacetGrid(data=df_6, col='fs_quarter_year', row='fs_quarter_index')  
grid.map(sns.scatterplot, 'fs_account_payable','fs_capital_reserves') 
Out[16]:
<seaborn.axisgrid.FacetGrid at 0x7f0b5d6bf940>