基于条件更新不同长度DataFrame指定列值的实现问题
解决DataFrame按条件匹配替换列值的问题
问题背景
现有两个Pandas DataFrame:
import pandas as pd import numpy as np df1 = pd.DataFrame({ 'Yes/No': ['Yes', 'No', 'No', 'No'], 'ID': [11, 22, 33, 44], 'Expiration': ['2023', '2022', '2022', '2024'], 'Code': ['B11', 'A11', 'D11', 'C11'], 'Number': [303, 202, 301, 222] }) df2 = pd.DataFrame({ 'Yes_No': ['No', 'Yes', 'Yes'], 'ExpiryDate': ['2026', '2027', '2028'], 'UniqueCode': ['A22', 'B11', 'C11'] })
需求:当满足以下两个条件时,将df1的Yes/No和Expiration列分别替换为df2的Yes_No和ExpiryDate列的值:
- df1的
Number值为303或301 - df1的
Code值与df2的UniqueCode值相等
预期更新后的df1:
# 输出结果 Yes/No ID Expiration Code Number 0 Yes 11 2023 B11 303 1 No 22 2027 A11 202 2 Yes 33 2028 C11 301 3 No 44 2024 D11 222
原代码的问题
尝试的代码:
df1['Yes/No'] = np.where(((df1['Number'] == 301) | (df1['Number'] == 303)) & df1['Code'] == df2['UniqueCode'], df2['Yes_No'], df1['Yes/No']) df1['Expiration'] = np.where(((df1['Number'] == 301) | (df1['Number'] == 303)) & df1['Code'] == df2['UniqueCode'], df2['ExpiryDate'], df1['Expiration'])
出现的错误:
Can only compare identically-labeled Series objectsValueError: Series lengths must match to compare
错误原因:df1和df2的行数不同,直接用df1['Code'] == df2['UniqueCode']会尝试逐行匹配,但Pandas无法对齐长度不一致的Series,导致比较失败。
正确实现方法
方法一:构建映射字典替换
先从df2中创建Code到目标值的映射字典,再结合条件批量替换:
# 从df2生成Code与Yes_No、ExpiryDate的映射字典 yes_no_map = df2.set_index('UniqueCode')['Yes_No'].to_dict() expiry_map = df2.set_index('UniqueCode')['ExpiryDate'].to_dict() # 定义匹配条件:Number为303/301,且Code存在于映射字典中 match_condition = df1['Number'].isin([303, 301]) & df1['Code'].isin(yes_no_map.keys()) # 替换符合条件的行 df1.loc[match_condition, 'Yes/No'] = df1.loc[match_condition, 'Code'].map(yes_no_map) df1.loc[match_condition, 'Expiration'] = df1.loc[match_condition, 'Code'].map(expiry_map)
方法二:通过临时合并更新
将df1和df2按Code/UniqueCode合并,再基于条件更新列值:
# 临时合并两个DataFrame,保留匹配的列 temp_merge = df1.merge(df2, left_on='Code', right_on='UniqueCode', how='left') # 定义匹配条件:Number为303/301,且合并后存在对应的df2值 match_condition = df1['Number'].isin([303, 301]) & temp_merge['Yes_No'].notna() # 替换列值 df1.loc[match_condition, 'Yes/No'] = temp_merge.loc[match_condition, 'Yes_No'] df1.loc[match_condition, 'Expiration'] = temp_merge.loc[match_condition, 'ExpiryDate']
内容的提问来源于stack exchange,提问作者dom159
相关产品推荐
相关产品推荐

