Pandas Merge操作中CampCount列被UnitCount覆盖的问题排查
问题描述
需求是统计单元总数、标记为'Y'的活动单元数,并计算两者的比值。但执行merge操作时,CampCount列出现NaN值,还存在匹配错误(如CAMPAIGN_PROFILE_x为'N'但CAMPAIGN_PROFILE_y为'Y')。
使用的代码如下:
def campaign_sorter(x, y): new_df = x[['VFMFRC', 'VFUNIT', 'IS_MONTH', 'IS_DAYS_GROUP', 'CAMPAIGN_PROFILE']].copy() # Counting distinct unit numbers by IS_MONTH, IS_DAYS_GROUP, and other columns unit_count = new_df.groupby(['IS_MONTH', 'IS_DAYS_GROUP', 'VFMFRC', 'CAMPAIGN_PROFILE']).agg({'VFUNIT': 'nunique'}).reset_index() unit_count.columns = ['IS_MONTH', 'IS_DAYS_GROUP', 'VFMFRC', 'CAMPAIGN_PROFILE', 'UnitCount'] # Counting distinct comp code values by IS_MONTH, IS_DAYS_GROUP, and other columns camp_count = new_df[new_df['CAMPAIGN_PROFILE'] == 'Y'].groupby(['IS_MONTH', 'IS_DAYS_GROUP', 'VFMFRC', 'CAMPAIGN_PROFILE']).agg({'VFUNIT': 'nunique'}).reset_index() camp_count.columns = ['IS_MONTH', 'IS_DAYS_GROUP', 'VFMFRC', 'CAMPAIGN_PROFILE', 'CampCount'] # Merging the unit counts and comp code counts DataFrames merged_df = pd.merge(unit_count, camp_count, on=['IS_MONTH', 'IS_DAYS_GROUP', 'VFMFRC', 'CAMPAIGN_PROFILE'], how='left', suffixes=('_unit', '_comp')) # Calculating the RPU (Ratio of Unit Count to Comp Code Count) # merged_df['RPU'] = merged_df['UnitCount'] / merged_df['CampCount'] # Merging the RPU values with the original dataframe # new_df = pd.merge(new_df, merged_df[['IS_MONTH', 'IS_DAYS_GROUP', 'VFMFRC', 'CAMPAIGN_PROFILE', 'RPU']], on=['IS_MONTH', 'IS_DAYS_GROUP', 'VFMFRC', 'CAMPAIGN_PROFILE'], how='left') # Dropping unnecessary columns and removing duplicates # new_df = new_df.drop(columns=['IS_MONTH']).drop_duplicates() return merged_df
已知unit_count输出60行,camp_count输出24行。
问题分析与解决
错误原因
- 分组键逻辑偏差:统计
unit_count时,你把CAMPAIGN_PROFILE加入了分组键,导致unit_count被拆分为CAMPAIGN_PROFILE='Y'和='N'的子组;而camp_count只筛选了CAMPAIGN_PROFILE='Y'的数据并按该字段分组,merge时unit_count中CAMPAIGN_PROFILE='N'的行无法匹配,直接出现CampCount=NaN。 - 需求匹配错误:你的核心需求是每个分组(IS_MONTH/IS_DAYS_GROUP/VFMFRC)下的总单元数和该分组内标记为Y的单元数,但原代码按
CAMPAIGN_PROFILE拆分统计,完全偏离了需求逻辑。
修正方案
- 统计
unit_count时,仅按IS_MONTH、IS_DAYS_GROUP、VFMFRC分组,计算该分组下所有唯一单元的总数。 - 统计
camp_count时,同样按上述三个字段分组,计算该分组内CAMPAIGN_PROFILE='Y'的唯一单元数,无需将CAMPAIGN_PROFILE加入分组键。 - merge时仅用三个核心分组键连接,确保每组的总单元数和Y单元数正确匹配。
修改后的代码
def campaign_sorter(x, y): new_df = x[['VFMFRC', 'VFUNIT', 'IS_MONTH', 'IS_DAYS_GROUP', 'CAMPAIGN_PROFILE']].copy() # 统计每个分组下的总唯一单元数(不区分CAMPAIGN_PROFILE) unit_count = new_df.groupby(['IS_MONTH', 'IS_DAYS_GROUP', 'VFMFRC']).agg({'VFUNIT': 'nunique'}).reset_index() unit_count.columns = ['IS_MONTH', 'IS_DAYS_GROUP', 'VFMFRC', 'UnitCount'] # 统计每个分组下标记为'Y'的唯一单元数 camp_filtered = new_df[new_df['CAMPAIGN_PROFILE'] == 'Y'] camp_count = camp_filtered.groupby(['IS_MONTH', 'IS_DAYS_GROUP', 'VFMFRC']).agg({'VFUNIT': 'nunique'}).reset_index() camp_count.columns = ['IS_MONTH', 'IS_DAYS_GROUP', 'VFMFRC', 'CampCount'] # 按核心分组键合并,缺失的CampCount填充为0(表示该分组无Y标记的单元) merged_df = pd.merge(unit_count, camp_count, on=['IS_MONTH', 'IS_DAYS_GROUP', 'VFMFRC'], how='left').fillna({'CampCount': 0}) # 计算比值(避免除以0,将0替换为NaN) merged_df['RPU'] = merged_df['UnitCount'] / merged_df['CampCount'].replace(0, float('nan')) return merged_df
额外说明
- 用
fillna({'CampCount':0})处理无Y标记的分组,避免后续计算报错;计算比值时用replace(0, float('nan')),避免出现无穷大值。 - 若需要将结果合并回原数据,直接用
new_df和merged_df按三个分组键merge即可,无需保留CAMPAIGN_PROFILE作为连接键。
内容的提问来源于stack exchange,提问作者TedM
相关产品推荐
相关产品推荐

