2016-07-29 5 views
2

У меня есть данные панели, я бы хотел сбросить первые (несколько) строки, содержащие NaN в каждой группе. (Или какой-нибудь общий метод, который может упасть на основе индекса в группе и других условий.)Pandas drop первые несколько строк содержат nan в каждой группе

df = pd.DataFrame(
{'ID': [10001, 10001, 10001, 10002, 10002, 10002, 10003, 10003, 10003, 10003], 
'PRICE': [None, 11.5, 14.31, 15.125, 14.44, None, None, None, None, 23.55], 
'date': [19920103, 19920106, 19920107, 19920108, 19920109, 19920110, 
      19920113, 19920114, 19920115, 19920116]}, 
index = range(1,11)) 

Эти данные будут выглядеть следующим образом:

ID  PRICE date 
1 10001 NaN  19920103 
2 10001 11.500 19920106 
3 10001 14.310 19920107 
4 10002 15.125 19920108 
5 10002 14.440 19920109 
6 10002 NaN  19920110 
7 10003 NaN  19920113 
8 10003 NaN  19920114 
9 10003 NaN  19920115 
10 10003 23.550 19920116 

Я хотел бы отказаться от линии 1 и 7, но не строка 9, так как линия 9 не одна из первых недостающих наблюдений, я попытался

def mask_first_missing(x): 
    result = x.notnull() & x.rank()==1 
    return result 

mask = df.groupby(['ID'])['PRICE'].transform(mask_first_missing).astype(bool) 
print(df[mask]) 

но она была удалена строка 1, 7 и 9, по-видимому, ряд 9 не первое наблюдение в группе 3,

Если я это

df[df.groupby('ID', as_index=False)['PRICE'].nth(0).notnull()] 

Тогда индекс, созданный объект GroupBy не совпадает с оригинальным dataframe

Может кто-нибудь помочь мне с этим? Спасибо

+1

Что такое правило, которое определяет которые NaN должны держать и капли? – piRSquared

ответ

0

благодарственное вы за свою помощь, но я думаю, что ни один из ответов не соответствовал моей задаче.

Я сам вычислил решение, создав колонку с индексом.

df = pd.DataFrame(
{'ID': [10001, 10001, 10001, 10001, 10002, 10002, 10002, 10003, 10003, 10003, 10003], 
'PRICE': [None, 11.5, None, 14.31, 15.125, 14.44, None, None, None, None, 23.55], 
'date': [19920103, 19920106, 19920107, 19920108, 19920109, 19920110, 
      19920113, 19920114, 19920115, 19920116, 19920122]}, 
index = range(1,12)) 

df.loc[:, 'subindex'] = df.groupby('ID').cumcount() 

Тогда один получит

ID  PRICE date subindex 
1 10001 NaN  19920103 0 
2 10001 11.500 19920106 1 
3 10001 NaN  19920107 2 
4 10001 14.310 19920108 3 
5 10002 15.125 19920109 0 
6 10002 14.440 19920110 1 
7 10002 NaN  19920113 2 
8 10003 NaN  19920114 0 
9 10003 NaN  19920115 1 
10 10003 NaN  19920116 2 
11 10003 23.550 19920122 3 

Вместо того чтобы делать все на основе GroupBy, теперь я могу выбрать п-е наблюдение каждой группы на основе столбца 'субиндекс.

Теперь, если я хочу бросить первые два наблюдения NaN из «цены» каждой группы, я могу создать маску

mask_first_few_nan = (df.loc[:, 'PRICE'].isnull()) & (df.loc[:, 'subindex'] <= 1) 
df[~mask_first_few_nan] 

В результате

ID  PRICE date subindex 
2 10001 11.500 19920106 1 
3 10001 NaN  19920107 2 
4 10001 14.310 19920108 3 
5 10002 15.125 19920109 0 
6 10002 14.440 19920110 1 
7 10002 NaN  19920113 2 
10 10003 NaN  19920116 2 
11 10003 23.550 19920122 3 
1

Это способ сделать это:

notnull = df.PRICE.notnull() 
protected = df.index > df.PRICE.last_valid_index() 

df[notnull | protected] 

enter image description here

+0

Большое вам спасибо, но у меня есть панель, я хочу отбросить первые несколько отсутствующих наблюдений каждой группы. Метод здесь не работает. Возможно, это моя вина, что я должен сделать свой вопрос более ясным. – GrumpyJun

+0

Я обновил данные образца, я попробовал метод, он не работает хорошо – GrumpyJun

0

alternatve подход с использованием пользовательского рейтинга:

In [49]: %paste 
df[df.assign(x=np.where(pd.isnull(df.PRICE), 1, np.nan)) 
    .groupby('ID').x.cumsum().fillna(np.inf) > 1 
] 
## -- End pasted text -- 
Out[49]: 
     ID PRICE  date 
2 10001 11.500 19920106 
3 10001 14.310 19920107 
4 10002 15.125 19920108 
5 10002 14.440 19920109 
6 10002 14.120 19920110 
8 10003 16.500 19920114 
9 10003  NaN 19920115 

Пояснение:

In [50]: df.assign(x=np.where(pd.isnull(df.PRICE), 1, np.nan)) 
Out[50]: 
     ID PRICE  date x 
1 10001  NaN 19920103 1.0 
2 10001 11.500 19920106 NaN 
3 10001 14.310 19920107 NaN 
4 10002 15.125 19920108 NaN 
5 10002 14.440 19920109 NaN 
6 10002 14.120 19920110 NaN 
7 10003  NaN 19920113 1.0 
8 10003 16.500 19920114 NaN 
9 10003  NaN 19920115 1.0 

In [51]: df.assign(x=np.where(pd.isnull(df.PRICE), 1, np.nan)).groupby('ID').x.cumsum().fillna(np.inf) 
Out[51]: 
1 1.000000 
2   inf 
3   inf 
4   inf 
5   inf 
6   inf 
7 1.000000 
8   inf 
9 2.000000 
Name: x, dtype: float64 

In [52]: df.assign(x=np.where(pd.isnull(df.PRICE), 1, np.nan)).groupby('ID').x.cumsum().fillna(np.inf) > 1 
Out[52]: 
1 False 
2  True 
3  True 
4  True 
5  True 
6  True 
7 False 
8  True 
9  True 
Name: x, dtype: bool