如何用Pandas基于多列对比DataFrame行并标记数据不一致?
问题:标记DataFrame中同组内数据不一致的行
示例数据集
df1 = pd.DataFrame( data=[['Afghanistan','2015','5.1'], ['Afghanistan','2015','6.1'], ['Bahrain','2020',''], ['Bahrain','2020','32'], ['Bahrain','2021','32'], ['Bahrain','2022','32']], columns=['Country', 'Reference Year', 'value'])
需求说明
按Country和Reference Year分组,当同一组内的value存在不同值时,该组所有行标记为invalid;其余情况标记为valid。
尝试的错误代码及问题
执行以下代码时触发维度不匹配错误:
df1['Validity'] = np.where((df1[['Country', 'Reference Year']] == df1[['Country', 'Reference Year']]) & df1['value'] != df1['value'],'Valid','Invalid')
错误提示:ValueError: Expected a 1D array, got an array with shape (6, 8)
期望输出
行1、行2、行3、行4标记为invalid,行5、行6标记为valid。
解决方案
你的代码逻辑存在维度问题:df1[['Country', 'Reference Year']] == df1[['Country', 'Reference Year']]会生成一个二维布尔DataFrame,和后续一维的value条件组合后,无法被np.where识别,导致报错。
正确思路是先按分组统计每组内value的唯一性,再将结果映射到每一行,以下是两种可行方法:
方法一:使用groupby+transform快速标记
import pandas as pd import numpy as np # 将空字符串转为NaN,确保空值被视为独立类别 df1['value'] = df1['value'].replace('', np.nan) # 分组后判断组内value的唯一值数量,广播到每一行 df1['Validity'] = df1.groupby(['Country', 'Reference Year'])['value'].transform( lambda x: 'invalid' if x.nunique(dropna=False) > 1 else 'valid' ) print(df1)
输出结果:
Country Reference Year value Validity 0 Afghanistan 2015 5.1 invalid 1 Afghanistan 2015 6.1 invalid 2 Bahrain 2020 NaN invalid 3 Bahrain 2020 32 invalid 4 Bahrain 2021 32 valid 5 Bahrain 2022 32 valid
方法二:先计算组状态再合并
如果需要更清晰的步骤拆分,可以先单独计算每组的有效性,再合并回原DataFrame:
import pandas as pd import numpy as np df1['value'] = df1['value'].replace('', np.nan) # 计算每组的value唯一值数量,并标记有效性 group_status = df1.groupby(['Country', 'Reference Year'])['value'].nunique(dropna=False).reset_index() group_status['Validity'] = np.where(group_status['value'] > 1, 'invalid', 'valid') # 合并回原表 df1 = df1.merge(group_status[['Country', 'Reference Year', 'Validity']], on=['Country', 'Reference Year'])
关键说明
- 处理空字符串:将空值转为
NaN后,nunique(dropna=False)会把空值当作一个独立值,和非空值区分开,符合需求中“空值和32视为不同”的逻辑 - 广播标记:
transform方法会把组内的判断结果自动映射到组内每一行,无需手动对齐索引
内容的提问来源于stack exchange,提问作者khushbu
相关产品推荐
相关产品推荐

