Pandas drop前几行在每个组中包含nan

b09cbbtk  于 2023-05-27  发布在  其他
关注(0)|答案(3)|浏览(150)

我有一个面板数据,我想删除第一(几)行(S),其中包含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不对齐
有人能帮我吗?谢谢你

js81xvg6

js81xvg61#

这是一种方法:

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

df[notnull | protected]

3ks5zfa0

3ks5zfa02#

使用自定义排名的替代方法:

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
zpqajqem

zpqajqem3#

谢谢你的帮助,但我认为这两个答案都不适合我的任务。
我自己想出了一个解决方案,通过创建一个子索引列。

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执行所有操作。
现在,如果我想删除每个组的前两个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

相关问题