在ID
内,我需要删除第value > 0
行,并删除数据帧中所有有序日期列的行。我认为最简单的方法是创建一个新的flag
列以将这些行标记为要删除。
我想出了以下内容来标记每个ID
中的第一个日期行(排序后),但是我很难弄清楚如何继续将我的标志移动到并包括{{ 1}}:
value > 0
哪个会吸引我:
df['flag'] = np.where((df.date == df.groupby('id')['date'].transform('flag')),1,0)
但最终结果应该是:
id date value flag
114 2016-01-01 0 1
114 2016-02-01 0 0
114 2016-03-01 200 0
114 2016-04-01 300 0
114 2016-05-01 100 0
220 2016-01-01 0 1
220 2016-02-01 0 0
220 2016-03-01 0 0
220 2016-04-01 0 0
220 2016-05-01 400 0
220 2016-06-01 200 0
答案 0 :(得分:2)
df = pd.DataFrame(data={"id": [114, 114, 114, 114, 114, 220, 220, 220, 220, 220, 220],
"date": ['2016-01-01', '2016-02-01', '2016-03-01', '2016-04-01', '2016-05-01',
'2016-01-01', '2016-02-01', '2016-03-01', '2016-04-01', '2016-05-01', '2016-06-01'],
'value': [0, 0, 200, 300, 100, 0, 0, 0, 0, 400, 200]})
df.sort_values(by=['id', 'date'], ascending=[True, True], inplace=True)
df['flag'] = 0
df.loc[df['value'].ne(0).groupby(df['id']).idxmax(),'flag']=1
df['flag'].replace({0:np.nan},inplace=True)
df['flag'] = df.groupby(['id'],as_index=False)['flag'].transform(pd.Series.bfill)
df['flag'].fillna(0,inplace=True)
print(df)
id date value flag
0 114 2016-01-01 0 1.0
1 114 2016-02-01 0 1.0
2 114 2016-03-01 200 1.0
3 114 2016-04-01 300 0.0
4 114 2016-05-01 100 0.0
5 220 2016-01-01 0 1.0
6 220 2016-02-01 0 1.0
7 220 2016-03-01 0 1.0
8 220 2016-04-01 0 1.0
9 220 2016-05-01 400 1.0
10 220 2016-06-01 200 0.0
我希望它能解决您的问题
答案 1 :(得分:2)
您无需创建中间flag
变量就可以实现
假设您的数据如下所示:
id date value
0 114 2016-01-01 0
1 114 2016-02-01 100
2 114 2016-03-01 200
3 114 2016-04-01 300
4 115 2016-01-01 0
5 115 2016-02-01 0
6 115 2016-03-01 100
7 115 2016-04-01 200
8 116 2016-01-01 100
9 116 2016-02-01 0 <-- notice the 0 value in the middle here
10 116 2016-03-01 330
11 116 2016-04-01 400
方法1
此方法假定不需要所有的0值,并且每个id
组中的第一个实数值都将以0开头。
我们要做的只是删除所有零,然后对id
进行分组并仅删除数据的第一行。这具有删除第一个实际行及其之前所有内容(假定为0)的作用
df1 = df[df['value'] > 0]
df1.sort_values('date').groupby('id', group_keys=False).apply(lambda g: g.iloc[1:])
id date value
0 114 2016-03-01 200
1 114 2016-04-01 300
2 115 2016-04-01 200
3 116 2016-03-01 330
4 116 2016-04-01 400
方法2
如果每个id
组的中间都为零(如上面数据中的第9行)怎么办?
从您的问题中不清楚在这种情况下您想做什么。按照您的描述,我假设您要进行的操作是找到第一个实际行(第8行),将其以及所有先前的内容(在这种情况下,没有先前的数据)删除,然后将0保留为空
此处的关键是使用first_valid_index()
获取非NA / null的第一行数据,并将其用作.iloc
中的索引
def remove_prev(g):
out = g.replace({0: np.nan}).reset_index(drop=True)
return out.iloc[out['value'].first_valid_index()+1:].fillna(0)
df.groupby('id', group_keys=False).apply(remove_prev).reset_index(drop=True)
id date value
0 114.0 2016-03-01 200.0
1 114.0 2016-04-01 300.0
2 115.0 2016-04-01 200.0
3 116.0 2016-02-01 0.0
4 116.0 2016-03-01 330.0
5 116.0 2016-04-01 400.0
标记方法
如果您确实要设置标志变量,则可以再次使用first_valid_index()
确定要设置flag=1
的行:
def flag_prev(g):
out = g.replace({0: np.nan})
out.loc[:out['value'].first_valid_index(), 'flag'] = 1
return out.fillna(0)
df.groupby('id', group_keys=False).apply(flag_prev).reset_index(drop=True)
id date value flag
0 114.0 2016-01-01 0.0 1.0
1 114.0 2016-02-01 100.0 1.0
2 114.0 2016-03-01 200.0 0.0
3 114.0 2016-04-01 300.0 0.0
4 115.0 2016-01-01 0.0 1.0
5 115.0 2016-02-01 0.0 1.0
6 115.0 2016-03-01 100.0 1.0
7 115.0 2016-04-01 200.0 0.0
8 116.0 2016-01-01 100.0 1.0
9 116.0 2016-02-01 0.0 0.0
10 116.0 2016-03-01 330.0 0.0
11 116.0 2016-04-01 400.0 0.0