我有一个面板数据,我想删除每组中包含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对象创建的索引与原始数据框
不对齐有人可以帮我这个吗?谢谢
答案 0 :(得分:1)
这是一种方法:
notnull = df.PRICE.notnull()
protected = df.index > df.PRICE.last_valid_index()
df[notnull | protected]
答案 1 :(得分:0)
使用自定义排名的替代方法:
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
答案 2 :(得分: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
现在我可以根据列'subindex'选择每组的第n次观察,而不是在基于groupby的所有事情上做。
现在,如果我想放弃每组的'PRICE'的前两个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