2015-07-05 130 views
7

刪除第一行,我有以下的大數據幀(df),看起來像這樣:的Python:熊貓 - 由

ID  date  PRICE  
1 10001 19920103 14.500  
2 10001 19920106 14.500  
3 10001 19920107 14.500  
4 10002 19920108 15.125  
5 10002 19920109 14.500 
6 10002 19920110 14.500  
7 10003 19920113 14.500 
8 10003 19920114 14.500  
9 10003 19920115 15.000 

問題:什麼是最有效的方式來刪除(或刪除)每個ID的第一行?我想這一點:

 ID  date  PRICE  
    2 10001 19920106 14.500  
    3 10001 19920107 14.500  
    5 10002 19920109 14.500 
    6 10002 19920110 14.500  
    8 10003 19920114 14.500  
    9 10003 19920115 15.000 

我可以做一個循環每個獨特ID並刪除第一行,但我相信這不是很有效。

回答

10

您可以使用groupby/transform準備布爾掩碼,對於您想要的行爲True,對於不需要的行爲False。一旦你有這樣的布爾面膜,可以使用df.loc[mask]選擇子數據幀:

import numpy as np 
import pandas as pd 

df = pd.DataFrame(
    {'ID': [10001, 10001, 10001, 10002, 10002, 10002, 10003, 10003, 10003], 
    'PRICE': [14.5, 14.5, 14.5, 15.125, 14.5, 14.5, 14.5, 14.5, 15.0], 
    'date': [19920103, 19920106, 19920107, 19920108, 19920109, 19920110, 
       19920113, 19920114, 19920115]}, 
    index = range(1,10)) 

def mask_first(x): 
    result = np.ones_like(x) 
    result[0] = 0 
    return result 

mask = df.groupby(['ID'])['ID'].transform(mask_first).astype(bool) 
print(df.loc[mask]) 

產生

 ID PRICE  date 
2 10001 14.5 19920106 
3 10001 14.5 19920107 
5 10002 14.5 19920109 
6 10002 14.5 19920110 
8 10003 14.5 19920114 
9 10003 15.0 19920115 

既然你感興趣的效率,這裏是一個風向標:

import timeit 
import operator 
import numpy as np 
import pandas as pd 

N = 10000 
df = pd.DataFrame(
    {'ID': np.random.randint(100, size=(N,)), 
    'PRICE': np.random.random(N), 
    'date': np.random.random(N)}) 

def using_mask(df): 
    def mask_first(x): 
     result = np.ones_like(x) 
     result[0] = 0 
     return result 

    mask = df.groupby(['ID'])['ID'].transform(mask_first).astype(bool) 
    return df.loc[mask] 

def using_apply(df): 
    return df.groupby('ID').apply(lambda group: group.iloc[1:, 1:]) 

def using_apply_alt(df): 
    return df.groupby('ID', group_keys=False).apply(lambda x: x[1:]) 

timing = dict() 
for func in (using_mask, using_apply, using_apply_alt): 
    timing[func] = timeit.timeit(
     '{}(df)'.format(func.__name__), 
     'from __main__ import df, {}'.format(func.__name__), number=100) 

for func, t in sorted(timing.items(), key=operator.itemgetter(1)): 
    print('{:16}: {:.2f}'.format(func.__name__, t)) 

報告

using_mask  : 0.85 
using_apply_alt : 2.04 
using_apply  : 3.70 
+0

哇令人印象深刻!謝謝 – Plug4

8

另一條線路編碼爲df.groupby('ID').apply(lambda group: group.iloc[1:, 1:])

Out[100]: 
      date PRICE 
ID      
10001 2 19920106 14.5 
     3 19920107 14.5 
10002 5 19920109 14.5 
     6 19920110 14.5 
10003 8 19920114 14.5 
     9 19920115 15.0 
+0

比第一個答案簡單千倍!我感謝你 –