2014-03-26 69 views
6

我想根据索引为我的数据框创建一个子索引。例如,我有这样一个数据帧:熊猫:如何高效创建子索引?

 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看起来很难看,并且可能不容易应用。

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

回答

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),只需添加1〜cumcount的结果。

+0

我觉得应该有一个更好的API来追加一个水平提高到一个多指标......不觉得有(又)。 –

+0

谢谢! 'cumcount'很好地工作!然而'set_index'似乎不适合我。我从字面上复制了'12'和'13'行,但'set_index'被程序忽略,这很奇怪。我必须使用df.index来重置索引。但是'cumcount'比上面提到的任何方法都快得多! –

+0

@ ZhenSun你需要做的:'df = df.set_index('subindex',append = True)',或'df.set_index('subindex',append = True,inplace = True)'实际改变df! –