2014-03-26 24 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! –