You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

优化商户每日用户增长率计算代码:解决连续零销量问题

问题

需要为DataFrame添加「商户每日用户增长率」列,已编写相关代码,但部分商户存在连续零销量的情况(0→0无有效增长率),导致代码运行异常,请求优化建议。

当前使用的代码如下:

# 筛选日期范围和订单类型
df_wk = df.loc[(df['Booked at'] >= '2023-01-01') & (df['Booked at'] <= '2023-05-31')]

# 筛选Eats类型订单
df_eats = df_wk.loc[df_wk['Job Type'] == 'Eats']

# 创建包含所有商户和日期的空DataFrame
dates = pd.date_range('2023-01-01', '2023-05-31', freq='D')
merchants = df_eats['Merchant Name'].unique()
index = pd.MultiIndex.from_product([dates, merchants], names=['Booked at', 'Merchant Name'])
all_sales = pd.DataFrame(index=index).reset_index()

# 按日期和商户分组,统计每日独立用户数
eats_users = df_eats.groupby(['Booked at', 'Merchant Name']).agg({'Customer Name': lambda x: x.nunique()})
eats_users.rename(columns={'Customer Name': 'Total Unique Users'}, inplace=True)

# 按日期排序
eats_users.sort_values('Booked at', inplace=True)

# 合并数据,填充零销量日期的用户数为0
unique_users = pd.merge(all_sales, eats_users, on=['Booked at', 'Merchant Name'], how='left')
unique_users.fillna(0, inplace=True)

# 再次按日期排序
unique_users.sort_values('Booked at', inplace=True)

# 计算每日用户增长率
previous_users = {}
for index, row in unique_users.iterrows():
    current_users = row['Total Unique Users']
    merchant = index[1]  # 尝试从索引元组获取商户名(此处存在错误)
    if pd.isna(current_users):
        unique_users.at[index, 'Daily Growth Rate for Unique Users'] = pd.NA
    else:
        if merchant in previous_users:
            previous_users_count = previous_users[merchant]
            growth_rate = (current_users / previous_users_count - 1) * 100
            unique_users.at[index, 'Daily Growth Rate for Unique Users'] = growth_rate
        else:
            unique_users.at[index, 'Daily Growth Rate for Unique Users'] = pd.NA
        previous_users[merchant] = current_users

期望输出示例:

Booked at Merchant Name  Total Unique Users  
0   2023-01-01    Merchant A                  38   
1   2023-01-01    Merchant B                  75   
2   2023-01-01    Merchant C                  74   
3   2023-01-02    Merchant A                  33   
4   2023-01-02    Merchant B                  71   
..         ...           ...                 ...   
447 2023-05-30    Merchant A                  75   
449 2023-05-30    Merchant C                  13   
451 2023-05-31    Merchant B                  76   
450 2023-05-31    Merchant A                  52   
452 2023-05-31    Merchant C                   2   

     Daily Growth Rate for Unique Users  
0                                   NaN  
1                                   NaN  
2                                   NaN  
3                            -13.157895  
4                             -5.333333  
..                                  ...  
447                            5.633803  
449                          -45.833333  
451                           13.432836  
450                          -30.666667  
452                          -84.615385  

[453 rows x 4 columns]
优化方案

原代码核心问题

  1. 索引处理错误:iterrows()返回的index是整数行号,不是创建的MultiIndex,因此merchant = index[1]会直接报错。
  2. 除数为零异常:当商户连续零销量时,previous_users_count为0,执行除法会触发ZeroDivisionError。
  3. 循环效率低下:用iterrows()遍历大DataFrame速度慢,不符合pandas向量化操作逻辑。

优化后代码

import pandas as pd

# 筛选日期范围和订单类型
df_wk = df.loc[(df['Booked at'] >= '2023-01-01') & (df['Booked at'] <= '2023-05-31')]
df_eats = df_wk.loc[df_wk['Job Type'] == 'Eats']

# 创建包含所有商户和日期的全量索引
dates = pd.date_range('2023-01-01', '2023-05-31', freq='D')
merchants = df_eats['Merchant Name'].unique()
index = pd.MultiIndex.from_product([dates, merchants], names=['Booked at', 'Merchant Name'])

# 按日期和商户统计独立用户数,自动填充零销量日期为0
eats_users = df_eats.groupby(['Booked at', 'Merchant Name'])['Customer Name'].nunique()
unique_users = eats_users.reindex(index, fill_value=0).reset_index()
unique_users.rename(columns={'Customer Name': 'Total Unique Users'}, inplace=True)

# 按商户分组,获取前一日的用户数
unique_users['Previous Day Users'] = unique_users.groupby('Merchant Name')['Total Unique Users'].shift(1)

# 计算增长率:处理除数为0的情况
def calculate_growth(row):
    prev = row['Previous Day Users']
    curr = row['Total Unique Users']
    if pd.isna(prev) or prev == 0:
        # 首日或前一日用户数为0时,无有效增长率
        return pd.NA
    return (curr / prev - 1) * 100

unique_users['Daily Growth Rate for Unique Users'] = unique_users.apply(calculate_growth, axis=1)

# 按日期+商户排序(保证输出顺序一致)
unique_users.sort_values(['Booked at', 'Merchant Name'], inplace=True)
unique_users.reset_index(drop=True, inplace=True)

关键改进点

  1. 用reindex替代合并填充:直接通过reindex生成全量日期+商户的DataFrame,自动填充零销量为0,代码更简洁。
  2. 分组移位获取前一日数据:用groupby('Merchant Name').shift(1)代替循环存储previous_users,避免索引错误,效率更高。
  3. 除数为零逻辑处理:
    • 首日数据(无前置数据):设为pd.NA
    • 前一日用户数为0:无论今日是否为0,均设为pd.NA(0→0或0→N都无有效增长率)
  4. 向量化操作替代循环:抛弃iterrows()遍历,大幅提升大数据集的运行效率。

输出验证

优化后的代码会生成符合期望的输出,所有无效增长率场景(首日、0→0、0→N)都会被标记为NaN,有效场景正常计算增长率。

内容的提问来源于stack exchange,提问作者Mark Yu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 16:07:10