Pandas多属性列左连接:标记匹配行及优化连接写法
问题说明
df1 以宽表形式存储产品属性,不同列对应不同属性维度;df2 以长表形式存储属性,所有属性值统一存在Attribute列。原实现通过多次左连接逐列匹配属性,存在重复代码多、无法标记df2匹配行的问题,以下是对应解决方案。
实现方案
1. 核心优化思路
放弃逐属性循环merge的写法,先通过melt将df1从宽表转为长表,仅需一次连接即可完成所有属性的匹配,既减少重复代码,也能在连接过程中直接收集df2的命中行索引,实现匹配状态标记。
2. 完整实现代码
import pandas as pd # 初始化示例数据 d1 = {"Product": ["product1", "product1", "product2", "product1", "product2", "product1", "product3"], "Store": ["Store1", "Store2", "Store1", "Store1", "Store1", "Store2", "Store2"], "Attribute1": pd.Series(["red", "green", "green", "blue"], index=[0, 2, 5, 6]), "Attribute2": pd.Series(["red", "green", "red"], index=[1, 3, 4])} df1 = pd.DataFrame(data=d1) d2 = {"Product": ["product1", "product1", "product2", "product1", "product2", "product1", "product3", "product3", "product2"], "Store": ["Store1", "Store2", "Store1", "Store1", "Store1", "Store2", "Store2", "Store1", "Store2"], "Attribute": ["red", "red", "green", "green", "red", "green", "blue", "blue", "red"], "Package": ["type1", "type2", "type3", "type4", "type5", "type6", "type2", "type4", "type2"]} df2 = pd.DataFrame(data=d2) # ========== 配置区:后续新增属性列只需要修改这个列表 ========== attr_columns = ["Attribute1", "Attribute2"] # 步骤1:将df1宽表转长表,每个属性单独一行 df1_long = df1.melt( id_vars=["Product", "Store"], value_vars=attr_columns, var_name="attr_type", value_name="attr_val" ).dropna(subset=["attr_val"]) # 过滤空属性行,避免无效匹配 # 步骤2:单次连接完成所有属性匹配,同时保留df2原始行号用于标记匹配状态 merge_result = pd.merge( df1_long, df2.reset_index().rename(columns={"index": "df2_rowid"}), how="left", left_on=["Product", "Store", "attr_val"], right_on=["Product", "Store", "Attribute"] ) # 解决问题1:给df2新增列标记是否参与过连接匹配 matched_row_ids = set(merge_result["df2_rowid"].dropna().unique()) df2["is_matched"] = df2.index.isin(matched_row_ids) # 步骤3:聚合拼接Package字段,和原逻辑输出完全对齐 package_agg = merge_result.sort_values("attr_type").groupby(["Product", "Store"])["Package"].agg( lambda x: "".join(x.dropna()) # 自动跳过空值,不需要手动替换nan ).reset_index(name="Package") # 拼回原df1得到最终结果 df3 = pd.merge(df1, package_agg, on=["Product", "Store"], how="left")
3. 方案优势
- 代码可扩展性强:后续新增属性维度(如Attribute3、Attribute4),仅需将列名加入
attr_columns列表即可,不需要重复编写merge、删列逻辑 - 性能更优:仅需执行一次merge操作,数据量较大时性能提升明显
- 鲁棒性更好:聚合时自动跳过空值,不需要手动做字符串转义、nan替换操作,避免出现
"nan"拼接残留的问题 - 匹配标记准确:直接通过连接过程中收集的df2原始行号标记匹配状态,不会出现多轮merge后标记冲突、遗漏的问题
内容的提问来源于stack exchange,提问作者Andrey Nikitin
相关产品推荐
相关产品推荐

