Pandas 删除每组中前几行包含 nan
Pandas drop the first few rows contain nan in each group
我有一个面板数据,我想删除每组中包含 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不对齐
有人可以帮我解决这个问题吗?谢谢
这是一种方法:
notnull = df.PRICE.notnull()
protected = df.index > df.PRICE.last_valid_index()
df[notnull | protected]
使用自定义排名的替代方法:
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
感谢您的帮助,但我认为这两个答案都不适合我的任务。
我自己想出了一个解决方案,方法是创建一个子索引列。
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
现在我可以 select 基于列 '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
我有一个面板数据,我想删除每组中包含 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不对齐
有人可以帮我解决这个问题吗?谢谢
这是一种方法:
notnull = df.PRICE.notnull()
protected = df.index > df.PRICE.last_valid_index()
df[notnull | protected]
使用自定义排名的替代方法:
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
感谢您的帮助,但我认为这两个答案都不适合我的任务。
我自己想出了一个解决方案,方法是创建一个子索引列。
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
现在我可以 select 基于列 '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