作者|Bex T.
编译|VK
起源|Towards Datas Science

介绍

我很喜爱DataCamp上的“Seaborn两头数据可视化”(Intermediate Data Visualization with Seaborn)这个课程。它教给老手十分棒的图表和办法。但说到热图,课程的老师不知怎么地引入了一个全新的pandas函数crosstab。而后,很快说:“crosstab是一个计算穿插表的有用函数…”

我就在那里不了解了。显然,我的第一反馈是查看函数的文档。我刚开始感觉我能够解决Matplotlib的任何文档,然而…我错了。.

在我练习之后,我晓得这是他人也会挣扎的事件。所以,我在这里写了一整篇文章。

在本文的最初一部分中,我探讨了为什么有些课程不教你像crosstab这样的高级函数。因为如果不在具体的环境下很难应用这样的函数,同时又放弃示例的初学者级别。

此外,大多数课程应用小型或玩具数据集。在更简单的数据迷信环境中,这些简单函数的益处更为显著,并且常常被更有教训的pandas用户应用。

在这篇文章中,我将教你如何应用crosstab以及如何在其余相似函数中抉择它。

目录

  • 简介
  • 设置
  • crosstab基础知识
  • Pandas crosstab()与pivot_table()和groupby()的比拟
  • Pandas crosstab()的进一步定制
  • Pandas crosstab(),多个组

你能够在这个GitHub repo上下载本文的notebook:https://github.com/BexTuychie...

设置

# 导入必要的库import pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsimport numpy as np# 疏忽正告import warningswarnings.filterwarnings('ignore')# 启用多单元输入from IPython.core.interactiveshell import InteractiveShellInteractiveShell.ast_node_interactivity = 'all'

对于示例数据,我将应用Seaborn内置的diamonds数据集。它足够大,并且有一些能够用crosstab()的变量:

diamonds = sns.load_dataset('diamonds')diamonds.head()

crosstab()基础知识

与许多计算分组汇总统计信息的函数一样,crosstab()能够解决分类数据。它可用于将两个或多个变量分组,并为每组的给定值执行计算。当然,应用groupby()或pivot_table()能够执行此类操作,但正如咱们稍后将要看到的,crosstab()为你的日常工作流程带来了许多益处。

函数承受两个或多个列表、pandas series 或dataframe,默认状况下返回每个组合的频率。我总是喜爱从一个例子开始,这样你能够更好地了解定义,而后我将持续解释语法。

crosstab()总是返回一个数据帧,上面是一个例子。dataframe是diamonds中两个变量的穿插表:cut和color。穿插表示意取一个变量,将其组显示为index,取另一个变量,将其组显示为columns。

pd.crosstab(index=diamonds['cut'], columns=diamonds['color'])

语法相当简略。index用于对变量进行分组,并将其显示为index(行),对于列也是如此。如果没有给定聚合函数,则每个单元格将计算每个组合中的察看数。例如,左上角的单元格通知咱们,有2834颗颜色代码为D而且是现实切割的钻石,。

接下来,咱们要查看每个组合的平均价格。crosstab()提供values参数来引入第三个要聚合的数值变量:

pd.crosstab(index=diamonds['cut'],            columns=diamonds['color'],            values=diamonds['price'],            aggfunc=np.mean).round(0)

当初,每个单元格蕴含了cut和color组合的平均价格。为了阐明咱们要计算平均价格,咱们将price列传递给values。请留神,始终必须同时应用values和aggfunc。否则,你将失去一个谬误。我还应用round()将答案四舍五入。

只管它有点高级,然而当你将crosstab()表传递到seaborn的热图中时,你将充分利用crosstab()表的长处。让咱们在热图中看到上表:

cross = pd.crosstab(index=diamonds['cut'],                    columns=diamonds['color'],                    values=diamonds['price'],                    aggfunc=np.mean).round(0)sns.heatmap(cross, cmap='rocket_r', annot=True, fmt='g');

seaborn能够主动将crosstab()表转换为热图。我将正文设置为True,并用色彩条显示热图。seaborn还为列和索引名增加了款式(fmt='g' 将数字显示为整数而不是迷信计数)。

热图更容易解释。你不想让你的最终用户看到一张满是数字的表格。因而,我将在须要时将每个crosstab()后果放入热图中。为了防止反复,我创立了一个有用的函数:

def plot_heatmap(cross_table, fmt='g'):    fig, ax = plt.subplots(figsize=(8, 5))    sns.heatmap(cross_table,                annot=True,                fmt=fmt,                cmap='rocket_r',                linewidths=.5,                ax=ax)    plt.show();

Pandas crosstab()与pivot_table()和groupby()的比拟

在咱们持续探讨更乏味的内容之前,我想我须要廓清计算分组摘要统计的三个函数之间的区别。

我在本文的第一局部介绍了pivot_table()和groupby()的区别。对于crosstab(),这三者之间的区别在于语法和后果的形态。让咱们应用这三种办法计算:

# 应用 groupby()>>> diamonds.groupby(['cut', 'color'])['price'].mean().round(0)cut        colorIdeal      D        2629.0           E        2598.0           F        3375.0           G        3721.0           H        3889.0           I        4452.0           J        4918.0Premium    D        3631.0           E        3539.0           F        4325.0           G        4501.0           H        5217.0           I        5946.0           J        6295.0Very Good  D        3470.0           E        3215.0           F        3779.0           G        3873.0           H        4535.0           I        5256.0           J        5104.0Good       D        3405.0           E        3424.0           F        3496.0           G        4123.0           H        4276.0           I        5079.0           J        4574.0Fair       D        4291.0           E        3682.0           F        3827.0           G        4239.0           H        5136.0           I        4685.0           J        4976.0Name: price, dtype: float64# 应用 pivot_table()diamonds.pivot_table(values='price',                     index='cut',                     columns='color',                     aggfunc=np.mean).round(0)# 应用 crosstab()pd.crosstab(index=diamonds['cut'],            columns=diamonds['color'],            values=diamonds['price'],            aggfunc=np.mean).round(0)

以上是pivot_table的输入

以上是crosstab的输入

我想你曾经晓得你最喜爱的了。grouppy()返回一个序列,而另两个返回雷同的数据帧。然而,能够将groupby系列转换为雷同的数据帧,如下所示:

grouped = diamonds.groupby(['cut', 'color'])['price'].mean().round(0)grouped.unstack()

如果你不理解pivot_table()和unstack()的语法,我强烈建议你浏览本文的第一局部。

说到速度,crosstab()比pivot_table()快,但都比groupby()慢得多:

%%timeitdiamonds.pivot_table(values='price',                     index='cut',                     columns='color',                     aggfunc=np.mean)11.5 ms ± 483 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)%%timeitpd.crosstab(index=diamonds['cut'],            columns=diamonds['color'],            values=diamonds['price'],            aggfunc=np.mean)10.8 ms ± 344 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)%%timeitdiamonds.groupby(['cut', 'color'])['price'].mean().unstack()4.13 ms ± 39.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

如你所见,即便应用unstack()链接,groupby()也比其余两个快3倍。这阐明如果你只想分组和计算摘要统计信息,那么应该应用雷同的groupby()。当我链接其余办法(如simple round()时,速度差甚至更大。

其余的比拟次要是对于pivot_table()和crosstab()。如你所见,这两个函数的后果的形态是雷同的。两者之间的第一个区别是crosstab()能够解决任何数据类型。

它能够承受任何相似数组的对象,比方列表、numpy数组、数据帧列(pandas series)。然而,pivot_table()只对dataframe无效。在一个很有帮忙的StackOverflow中,我发现如果在数据帧上应用crosstab(),它会在后盾调用pivot_table()。

接下来是参数。有些参数只存在于一个参数中,反之亦然。第一个最风行的是crosstab()的normalize。normalize承受以下选项(来自文档):

  • 如果传递了all或True,则将规范化所有值。
  • 如果传递index,将规范化每一行。
  • 如果传递columns,将规范化每个列。

让咱们看一个简略的例子:

cross = pd.crosstab(index=diamonds['cut'],                    columns=diamonds['color'],                    normalize='all')plot_heatmap(cross, fmt='.2%')

如果传递all,对于每个单元格,pandas计算总金额的百分比:

# 证实所有值加起来约等于1>>> pd.crosstab(diamonds['cut'],                 diamonds['color'],                 normalize='all').values.sum()                1.0000000000000002

如果传递index或columns,则按列或按行执行雷同的操作:

cross = pd.crosstab(diamonds['cut'],                     diamonds['color'],                     normalize='index')plot_heatmap(cross, fmt='.2%')

以上是按行规范化

cross = pd.crosstab(diamonds['cut'], diamonds['color'], normalize='columns')plot_heatmap(cross, fmt='.2%')

以上是按列规范化

在crosstab()中,还能够应用行名和列名间接在函数内更改索引和列名。之后不用手动执行。当咱们一次按多个变量分组时,这两个参数十分有用,你将在前面看到。

参数fill_value只存在于pivot_table()中。有时,当你按许多变量分组时,不可避免地会呈现不统一。在pivot_table()中,能够应用fill_value将它们更改为自定义值:

diamonds.pivot_table(index='color',                      columns='cut',                      fill_value=0)

然而,如果应用crosstab(),则能够通过在dataframe上链接fillna()来实现雷同的成果:

pd.crosstab(diamonds['cut'], diamonds['color']).fillna(0)

Pandas crosstab()的进一步定制

crosstab()的另外两个有用参数是margins和margins_name(两者都存在于pivot_table()中)。设置为True时,边界计算每行和每列的和。咱们来看一个例子:

pd.crosstab(index=diamonds['cut'],             columns=diamonds['clarity'],              margins=True)

pandas主动增加最初一行和最初一列,默认名称为All。margins_name能够管制名字:

pd.crosstab(index=diamonds['cut'],            columns=diamonds['clarity'],            margins=True,            margins_name='Total Number')

右下角的单元格将始终蕴含察看的总数,或者如果“normalize”设置为True,则为1:

pd.crosstab(index=diamonds['cut'],            columns=diamonds['clarity'],            margins=True,            margins_name='Total Percentage',            normalize=True)

请留神,如果将margins设置为True,则热图是无用的。

Pandas crosstab(),多组

对于index和columns参数,能够传递多个变量。后果将是一个具备多级索引的数据帧。这次咱们插入所有的分类变量:

pd.crosstab(index=[diamonds['cut'], diamonds['clarity']],            columns=diamonds['color'])

对于index,我传递了color和cut。如果我把它们传递给列,后果将是一个蕴含40列的数据帧。如果你留神的话,多级索引如预期的那样命名为cut和clear。对于存在多级索引或列名的状况,crosstab()有不便的参数来更改它们的名称:

pd.crosstab(index=[diamonds['cut'], diamonds['clarity']],            columns=diamonds['color'],             rownames=['Diamond Cut', 'Clarity']).head()

传递相应名称的列表,以将索引名称更改为行名称。这个过程对于管制列名的colnames是雷同的。

有一件事让我很诧异,如果你把多个函数传递给aggfunc,pandas就会抛出一个谬误。同样,StackOverflow上的伙计们认为这是一个bug,而且曾经有6年多没有解决过了。

最初要留神的是,在pivot_table()和crosstab()中,都有一个dropna参数,如果设置为True,则会删除蕴含所有nan的列或行。

原文链接:https://towardsdatascience.co...

欢送关注磐创AI博客站:
http://panchuang.net/

sklearn机器学习中文官网文档:
http://sklearn123.com/

欢送关注磐创博客资源汇总站:
http://docs.panchuang.net/