我的数据按ID分组。在每个组中,它按colB排序。我需要实现的逻辑如下:
如果colA为空,且colD为(2,3或4), 然后创建一个名为'flag'的列,并在colC的最后一个非零行中设置flag = 1。在该组的所有其他行中将该标志设置为0,其中colC为非零。 删除该特定分组的行(colA为空,colC为0)。
对所有其他'id'组重复上述步骤。
(对于colA非空白的行,我可以将标志设置为我需要的。)
以下是我的数据:
id colA ColB colC colD
1 10 1352.23 2
1 11 706.87 2
1 12 1116.6 2
1 13 0 2
1 14 0 2
1 15 0 2
2 2 6884.03 3
2 3 2235.97 3
2 4 3618.04 3
2 5 11745.42 3
3 2013 1 345.98 0
这是我在处理它之后想要获得的。
id colA ColB colC colD flag
1 10 1352.23 2 0
1 11 706.87 2 0
1 12 1116.6 2 1
2 2 6884.03 3 0
2 3 2235.97 3 0
2 4 3618.04 3 0
2 5 11745.42 3 1
3 2013 1 345.98 0 0
该数据包含数千个此类分组。我希望有人可以帮我弄清楚上面处理的Python代码是什么样的。我对groupby函数有一个基本的了解,但是没有能够弄清楚如何做到这一点。
这是我尝试使用的代码。代码给出了错误: “AttributeError:'str'对象没有属性'id'。”
当我在colC中检测到我最终要删除的零时,我试图将“标志”设置为NaN,因此我可以在稍后的步骤中轻松删除它们。
def setFlag(grouped):
for name, group in grouped:
for i in range(group.id.size):
drop_candidate = (
pd.isnull(group.iloc[i]['colA'])&
( (group.iloc[i]['colD'] == 2) |
(group.iloc[i]['colD'] == 3) |
(group.iloc[i]['colD'] == 4) )
)
last_nonZero = group[group != 0].index[-1]
if ( (drop_candidate & (group.iloc[i]['colC'] == 0)) ):
group['flag'] = np.nan
elif ((drop_candidate & (group.iloc[i]['colC'] != 0)) & (last_nonZero != i)):
group['flag'] = 0
elif last_nonZero == i:
group['flag'] = 1
return grouped
df.groupby('id').apply(setFlag)
以下是重新创建测试数据帧的代码:
import pandas as pd
import numpy as np
df = pd.DataFrame.from_items([
('id', [1,1,1,1,1,1,2,2,2,2,3]),
('colA', [np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,2013]),
('colB', [10,11,12,13,14,15,2,3,4,5,1]),
('colC', [1352.23,706.87,1116.6,0,0,0,6884.03,2235.97,3618.04,11745.42,345.98]),
('colD', [2,2,2,2,2,2,3,3,3,3,0]),
('flag', [np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,]),
])
答案 0 :(得分:0)
您的流程看起来有三个部分:
1)摆脱colA为null且colC == 0的行。先减少数据帧
如果是AND逻辑:
reduced_df = df.loc[(df.colA.notnull()) & (df.colC != 0), :].copy()
如果是OR逻辑:
reduced_df = df.loc[(df.colA.notnull()) | (df.colC != 0), :].copy()
id colA colB colC colD flag
0 1 NaN 10 1352.23 2 NaN
1 1 NaN 11 706.87 2 NaN
2 1 NaN 12 1116.60 2 NaN
6 2 NaN 2 6884.03 3 NaN
7 2 NaN 3 2235.97 3 NaN
8 2 NaN 4 3618.04 3 NaN
9 2 NaN 5 11745.42 3 NaN
10 3 2013 1 345.98 0 NaN
2)现在您已准备好处理标记组的最后一列的第二部分。由于默认标志值为0,因此以
开头 reduced_df.loc[:, 'flag'] = 0
3)您可以使用duplicated
找到重复的值,然后确保colA为空
reduced_df.loc[~reduced_df.colD.duplicated(keep='last') & reduced_df.colA.isnull(), 'flag'] = 1
reduced_df
id colA colB colC colD flag
0 1 NaN 10 1352.23 2 0
1 1 NaN 11 706.87 2 0
2 1 NaN 12 1116.60 2 1
6 2 NaN 2 6884.03 3 0
7 2 NaN 3 2235.97 3 0
8 2 NaN 4 3618.04 3 0
9 2 NaN 5 11745.42 3 1
10 3 2013 1 345.98 0 0
答案 1 :(得分:0)
这是我使用apply
方法提出的。我认为它符合您的要求:
df['flag'] = df['colD'].shift(-1) #use as a placeholder to compare consecutive 'colD' vals
df['flag'] = df.apply(lambda x: 1 if (x['flag']!=x['colD']) &
(np.isnan(x['colA'])) & (x['colD']>0) else 0, axis=1)
如果有效,请告诉我! (你需要将numpy作为np导入的btw)。此外,如果您想将此限制仅限于2,3& 4,您必须将最后一部分从(x['colD']>0)
更改为(x['colD']>1) & (x['colD'] < 5)