首页 > 解决方案 > 如何在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

有谁知道更好的方法来做到这一点?

标签: pythonpandasnumpydataframe

解决方案


如果速度不是问题并且您想要一些易于阅读的代码,您可以简单地遍历数据帧并为每一行运行一个简单的函数。

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)

就是这样。


推荐阅读