首页 > 解决方案 > 如何计算每行具有动态条件的 Pandas df 元素(=countif)

问题描述

我很想在 Pandas 中做一些相当于 COUNTIF 的事情。我正在努力解决这个问题groupby,但我很挣扎,因为我的逻辑分组条件是动态的。

假设我有一份客户名单,以及他们访问的日期。我想根据 2 个逻辑条件识别新客户

如果满足这两个条件,他们就是回头客。如果不是,它们是新的(因此newby = 1-...要识别新客户。

我设法通过一个for循环来做到这一点,但显然性能很糟糕,这与 Pandas 的逻辑相悖。

如何将以下代码包装成比循环更智能的东西?

for i in range (0, len(df)):
    newby = 1-np.sum((df["Day"] == df.iloc[i]["Day"]-1) & (df["Guest ID"] == df.iloc[i]["Guest ID"]))

这篇文章没有帮助,因为条件是静态的。我想避免引入“虚拟列”,例如转置df,因为我将有很多类别(很多客户名称)并且想构建更复杂的逻辑语句。我不想冒着得到许多辅助列的风险

我有以下输入

df
   Day     Guest ID
0  3230    Tom
1  3230    Peter
2  3231    Tom
3  3232    Peter
4  3232    Peter

并期待这个输出

df
   Day     Guest ID      newby
0  3230    Tom           1
1  3230    Peter         1
2  3231    Tom           0
3  3232    Peter         1
4  3232    Peter         1

请注意,元素3不一定4是重复的 - 因为可能有额外的、不同的列(例如它们的顺序)。

标签: pythonpandaspandas-groupbycountif

解决方案


做:

# ensure the df is sorted by date 
df = df.sort_values('Day')

# group by customer and find the diff within each group
df['newby'] = (df.groupby('Guest ID')['Day'].transform('diff').fillna(2) > 1).astype(int)
print(df)

输出

    Day Guest ID  newby
0  3230      Tom      1
1  3230    Peter      1
2  3231      Tom      0
3  3232    Peter      1

更新

如果每天允许多次访问,您可以执行以下操作:

# only keep unique visits per day
uniques = df.drop_duplicates()

# ensure the df is sorted by date
uniques = uniques.sort_values('Day')

# group by customer and find the diff within each group
uniques['newby'] = (uniques.groupby('Guest ID')['Day'].transform('diff').fillna(2) > 1).astype(int)

# merge the uniques visits back into the original df
res = df.merge(uniques, on=['Day', 'Guest ID'])

print(res)

输出

    Day Guest ID  newby
0  3230      Tom      1
1  3230    Peter      1
2  3231      Tom      0
3  3232    Peter      1
4  3232    Peter      1

作为替代方案,无需排序或合并,您可以执行以下操作:

lookup = {(day + 1, guest) for day, guest in df[['Day', 'Guest ID']].value_counts().to_dict()}
df['newby'] = (~pd.MultiIndex.from_arrays([df['Day'], df['Guest ID']]).isin(lookup)).astype(int)
print(df)

输出

    Day Guest ID  newby
0  3230      Tom      1
1  3230    Peter      1
2  3231      Tom      0
3  3232    Peter      1
4  3232    Peter      1

推荐阅读