熊猫:如何有效地创建子索引?

时间:2014-03-26 20:48:59

标签: python performance pandas

我想根据索引为我的数据框创建一个子索引。例如,我有一个这样的数据框:

      Content        Date
ID                       
Bob  birthday  2010.03.01
Bob    school  2010.04.01
Tom  shopping  2010.02.01
Tom      work  2010.09.01
Tom   holiday  2010.10.01

我想为我的ID创建子索引,结果数据框如下所示:

               Content        Date
ID  subindex                      
Bob 1         birthday  2010.03.01
    2           school  2010.04.01
Tom 1         shopping  2010.02.01
    2             work  2010.09.01
    3          holiday  2010.10.01

要做到这一点,我需要先创建我的subindex列表。我在帮助文档中搜索,似乎最简洁的方法是使用transform

subindex = df['Date'].groupby(df.index).transform(lambda x: np.arange(1, len(x) + 1))

然而,它真的很慢。我环顾四周,发现apply也可以做这项工作:

subindex = df['Date'].groupby(df.index).apply(lambda x: np.arange(1, len(x) + 1))

当然subindex需要展平,因为这是列表。这比transform方法快得多。然后我用我自己的for loop进行了测试:

subindex_size = df.groupby(df.index, sort = False).size()
subindex = []
for i in np.arange(len(subindex_size)):
    subindex.extend(np.arange(1,subindex_size[i]+1))

它甚至更快。使用我更大的数据集(大约90k行),transform方法在我的计算机上大约需要44秒,apply大约需要2秒,而for loop只需要大约1秒。我需要处理更大的数据集,因此即使applyfor loop之间的时差也会对我产生影响。但是,for loop看起来很丑,如果我需要创建其他基于组的变量,可能不会轻易应用。

所以我的问题是,为什么应该做正确事情的内置函数更慢?我在这里遗漏了什么或者有什么理由吗?有没有其他方法可以改善这个过程?

1 个答案:

答案 0 :(得分:3)

您可以使用cumcount执行此操作:

In [11]: df.groupby(level=0).cumcount()
Out[11]: 
ID
Bob    0
Bob    1
Tom    0
Tom    1
Tom    2
dtype: int64

In [12]: df['subindex'] = df.groupby(level=0).cumcount()  # possibly + 1 here.

In [13]: df.set_index('subindex', append=True)
Out[13]: 
               Content        Date
ID  subindex                      
Bob 0         birthday  2010.03.01
    1           school  2010.04.01
Tom 0         shopping  2010.02.01
    1             work  2010.09.01
    2          holiday  2010.10.01

要从1开始(而不是0),只需在cumcount的结果中加1。