python - 如何在Python中按组更改值的计数器
问题描述
我正在尝试创建一个计数器,仅当它与前一行或我按更改分组的 ID 不同时才会更改值
假设我有以下数据框:
ID Flag New_Column
A NaN 1
A 0 1
A 0 1
A 0 1
A 1 2
A 1 2
A 1 2
A 0 3
A 0 3
A 0 3
A 1 4
A 1 4
A 1 4
B NaN 1
B 0 1
我想创建 New_Column ,每次标志值更改时,我都会将 New_Column 增加一,如果 ID 更改,它将重置为一并重新开始
这是我尝试使用 np.select 做的,但它不起作用
df['New_Column'] = None
df['Flag_Lag'] = df.sort_values(by=['ID', 'Date_Time'], ascending=True).groupby(['ID'])['Flag'].shift(1)
df['ID_Lag'] = df.sort_values(by=['ID', 'Date_Time'], ascending=True).groupby(['ID'])['ID'].shift(1)
conditions = [((df['Flag'] != df['Flag_Lag']) & (df['ID'] == df['ID_Lag'])),
((df['Flag'] == df['Flag_Lag']) & (df['ID'] == df['ID_Lag'])),
((df['Flag_Lag'] == np.nan) & (df['New_Column'].shift(1) == 1)),
((df['ID'] != df['ID_Lag']))
]
choices = [(df['New_Column'].shift(1) + 1),
(df['New_Column'].shift(1)),
(df['New_Column'].shift(1)),
1]
df['New_Column'] = np.select(conditions, choices, default=np.nan)
使用此代码,New_Column 的第一个值为 1,第二个为 NaN,其余为 None
有谁知道更好的方法来做到这一点?
解决方案
如果速度不是问题并且您想要一些易于阅读的代码,您可以简单地遍历数据帧并为每一行运行一个简单的函数。
def f(row):
global previous_ID, previous_flag, previous_count
if previous_ID == False: #let's start the count
row['New_Column'] = 1
elif previous_ID != row['ID']: #let's start the count over
row['New_Column'] = 1
elif previous_flag == row['Flag']: #same ID, same Flag
row['New_Column'] = previous_count
else: #same ID, different Flag
row['New_Column'] = previous_count + 1
previous_ID = row['ID']
previous_flag = row['Flag']
previous_count = row['New_Column']
您应该用 0 填充您的 NaN 值,或者在函数中为其添加特殊情况。
您可以通过以下方式运行该函数:
previous_ID, previous_flag, previous_count = False, False, False
df['New_Columns'] = []
for i, row in df.iterrows():
f(row)
就是这样。