关于人工智能:Pandas的crosstab函数

7次阅读

共计 6523 个字符,预计需要花费 17 分钟才能阅读完成。

作者 |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 pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

# 疏忽正告
import warnings
warnings.filterwarnings('ignore')

# 启用多单元输入
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.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        color
Ideal      D        2629.0
           E        2598.0
           F        3375.0
           G        3721.0
           H        3889.0
           I        4452.0
           J        4918.0
Premium    D        3631.0
           E        3539.0
           F        4325.0
           G        4501.0
           H        5217.0
           I        5946.0
           J        6295.0
Very Good  D        3470.0
           E        3215.0
           F        3779.0
           G        3873.0
           H        4535.0
           I        5256.0
           J        5104.0
Good       D        3405.0
           E        3424.0
           F        3496.0
           G        4123.0
           H        4276.0
           I        5079.0
           J        4574.0
Fair       D        4291.0
           E        3682.0
           F        3827.0
           G        4239.0
           H        5136.0
           I        4685.0
           J        4976.0
Name: 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()慢得多:

%%timeit
diamonds.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)

%%timeit
pd.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)

%%timeit
diamonds.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/

正文完
 0