【问题标题】:Equivalent of R's tapply() in Python PandasPython Pandas 中 R 的 tapply() 等价物
【发布时间】:2014-01-03 14:21:13
【问题描述】:

我有一个数据集,其中包含 3 只动物的喂养数据,包括动物的标签 ID (1,2,3)、每顿饭的饲料类型 (A,B) 和数量 (kg) ':

Animal   FeedType   Amount(kg)
Animal1     A         10
Animal2     B         7
Animal3     A         4
Animal2     A         2
Animal1     B         5
Animal2     B         6
Animal3     A         2

在base R中,我可以很容易地输出下面的矩阵,下面的矩阵有unique('Animal')作为它的行,unique('FeedType')作为它的列,并且使用tapply()在矩阵的相应单元格中累积Amount (kg)如下

out <- with(mydf, tapply(Amount, list(Animal, FeedType), sum))

         A  B
Animal1 10  5
Animal2  2 13
Animal3  6 NA

Python Pandas 数据框是否有等效功能?在 Pandas 中实现这一目标的最优雅和最快的方法是什么?

附:我希望能够指定在哪个列(在本例中为 Amount)执行聚合。

提前致谢。

编辑:

我在两个答案中都尝试了这两种方法。我的 216,347 行和 15 列的实际 Pandas 数据框的性能结果:

start_time1 = timeit.default_timer()
mydf.groupby(['Animal','FeedType'])['Amount'].sum()
elapsed_groupby = timeit.default_timer() - start_time1

start_time2 = timeit.default_timer()
mydf.pivot_table(rows='Animal', cols='FeedType',values='Amount',aggfunc='sum')
elapsed_pivot = timeit.default_timer() - start_time2

print ('elapsed_groupby: ' + str(elapsed_groupby))
print ('elapsed_pivot: ' + str(elapsed_pivot))

给予:

elapsed_groupby: 10.172213
elapsed_pivot: 8.465783

所以在我的例子中,pivot_table() 工作得更快。

【问题讨论】:

    标签: python r pandas tapply


    【解决方案1】:

    首先我读入你的数据:

    In [7]: df = pd.read_clipboard(sep="\s+", index_col=False)
    
    In [8]: df
    Out[8]:
        Animal FeedType  Amount(kg)
    0  Animal1        A          10
    1  Animal2        B           7
    2  Animal3        A           4
    3  Animal2        A           2
    4  Animal1        B           5
    5  Animal2        B           6
    6  Animal3        A           2
    

    然后我可以按两列分组进行聚合:

    In [9]: df.groupby(['Animal','FeedType']).sum()
    Out[9]:
                      Amount(kg)
    Animal  FeedType
    Animal1 A                 10
            B                  5
    Animal2 A                  2
            B                 13
    Animal3 A                  6
    

    要获得相同的格式,我可以unstackdataframe

    In [10]: df.groupby(['Animal','FeedType']).sum().unstack()
    Out[10]:
              Amount(kg)
    FeedType           A   B
    Animal
    Animal1           10   5
    Animal2            2  13
    Animal3            6 NaN
    

    【讨论】:

    • 感谢您的回答!我如何指定:df.groupby(['Animal','FeedType']).sum() 专门总结 'Amount'?我在同一个数据框中还有其他浮点列,我只对 'Amount' 值感兴趣。
    • df.groupby(['Animal','FeedType'])['Amount'].sum()
    • 是的,很抱歉,我在写完评论后才知道这一点。但这是否意味着我首先按不在 ['Animal', 'FeedType'] 中的所有列进行分组?我没有在我的问题中指定这一点以保持简短和重点,但我确实有很多列,并且希望尽可能将操作限制为单个列。
    【解决方案2】:

    @Zelazny7 使用groupbyunstack 的方法当然没问题,但为了完整起见,您也可以直接使用pivot_table 执行此操作(参见doc)[版本0.13 及以下]:

    In [13]: df.pivot_table(rows='Animal', cols='FeedType', values='Amount(kg)', aggfunc='sum')
    Out[13]:
    FeedType   A   B
    Animal
    Animal1   10   5
    Animal2    2  13
    Animal3    6 NaN
    

    在较新版本的 Pandas(0.14 及更高版本)中,pivot_table 的参数已更改:

    In [13]: df.pivot_table(index='Animal', columns='FeedType', values='Amount(kg)', aggfunc='sum')
    Out[13]:
    FeedType   A   B
    Animal
    Animal1   10   5
    Animal2    2  13
    Animal3    6 NaN
    

    【讨论】:

    • 谢谢,这比groupBy()快吗?我不知道如何在groupBy() 方法中指定Amount 列。我觉得按整个数据框进行分组是不必要的,并且可能会带来性能问题。我想在聚合时专门使用df$Amount
    • 一些快速的timeit 结果显示 groupby 方法稍微快一些(2.44ms 与 100 个循环的 3.28ms)
    • @Zelazny7,我按照您的建议使用timeit 测试了这两种方法。 pivot_table() 在我的情况下更快,因为我添加了我的问题。不过我还是很感谢你的回答。
    • @Zhubarb 如果您使用的是 IPython,对于计时我发现使用%timeit 更容易(例如%timeit mydf.groupby(['Animal','FeedType'])['Amount'].sum()
    猜你喜欢
    • 1970-01-01
    • 2015-08-16
    • 1970-01-01
    • 1970-01-01
    • 2022-07-28
    • 2020-09-14
    • 2018-07-18
    • 2016-06-14
    • 2016-05-23
    相关资源
    最近更新 更多