
在数据处理中,我们经常面临需要根据一个数据框(例如 df2)中的匹配键(如列 a 和 b),来更新另一个数据框(例如 df1)中相应行特定列(如列 c)的值。一个常见的直觉性尝试是先设置索引,然后使用 .loc 进行赋值。
考虑以下两个 Pandas DataFrame:
import pandas as pd
df1 = pd.DataFrame({'a':(1,2,3,4),'b':(10,20,30,40),'c':(100,200,300,400)})
df2 = pd.DataFrame({'a':(1,2,3),'b':(10,20,30),'c':(1111,2222,3333)})
print("df1:")
print(df1)
print("\ndf2:")
print(df2)输出:
df1: a b c 0 1 10 100 1 2 20 200 2 3 30 300 3 4 40 400 df2: a b c 0 1 10 1111 1 2 20 2222 2 3 30 3333
我们期望通过 df2 的 a, b 列匹配 df1,并将 df2.c 的值赋给 df1.c。一个常见的尝试是:
# 错误的尝试
df1.set_index(['a', 'b']).loc[df2.set_index(['a', 'b']).index, 'c'] = df2.c
print("\n错误的尝试后 df1:")
print(df1)然而,这段代码并不会按照预期修改 df1。df1 仍然保持不变:
错误的尝试后 df1: a b c 0 1 10 100 1 2 20 200 2 3 30 300 3 4 40 400
失败原因解析:
df1.set_index(['a', 'b']) 操作会返回一个 新的 DataFrame 视图或副本,而不是对 df1 进行原地修改。当您对这个临时生成的 DataFrame 进行 .loc[...] = ... 赋值时,修改的是这个临时对象,而不是原始的 df1。一旦该行代码执行完毕,这个临时对象就会被丢弃,因此 df1 保持不变。为了实现原地修改,我们需要采用更间接或 Pandas 特定的方法。
以下提供两种推荐的解决方案,它们能够有效地实现目标。
这种方法适用于当您需要将 df2 的更新合并到 df1 中,同时保留 df1 中未被 df2 匹配到的行的原始值。它通过 merge 操作将 df2 的相关信息引入 df1,然后利用 combine_first 智能地填充新值。
# 重置 df1 以便演示
df1 = pd.DataFrame({'a':(1,2,3,4),'b':(10,20,30,40),'c':(100,200,300,400)})
# 步骤1: 合并 df1 的匹配键和 df2 的更新值
# 使用 'left' 合并确保 df1 的所有行都被保留
merged_df = df1[['a', 'b']].merge(df2, on=['a', 'b'], how='left', suffixes=('_df1', '_df2'))
# 步骤2: 使用 combine_first 将 df2 的 'c' 值优先合并到 df1 的 'c'
# combine_first 会用调用者(即 df1 的 c 列)的值填充 NaN
# 为了简化,我们可以直接让 df2 的 c 列覆盖 df1 的 c 列
# 更直接的做法是创建一个新的 'c' 列,然后替换
# 这里我们直接创建期望的 'c' 列
updated_c = merged_df['c_df2'].combine_first(df1['c'])
# 将更新后的 'c' 列赋值回 df1
df1['c'] = updated_c
print("\n方法一:使用 merge 和 combine_first 更新后的 df1:")
print(df1)输出:
方法一:使用 merge 和 combine_first 更新后的 df1: a b c 0 1 10 1111.0 1 2 20 2222.0 2 3 30 3333.0 3 4 40 400.0
解释:
此方法更加灵活,尤其适用于需要精确控制更新逻辑,并希望在原始 DataFrame 上进行原地赋值的场景。它利用 merge 获取更新值,并通过 reset_index 和 set_index 巧妙地将结果对齐回原始 DataFrame 的索引。
# 重置 df1 以便演示
df1 = pd.DataFrame({'a':(1,2,3,4),'b':(10,20,30,40),'c':(100,200,300,400)})
# 步骤1: 将 df1 的索引重置为普通列,以便进行合并
# 步骤2: 与 df2 进行左合并,获取更新的 'c' 值
# 步骤3: 将合并结果的索引重新设置为原始索引,以便与 df1 对齐
# 步骤4: 使用 fillna 填充未匹配行的 'c' 值(保留 df1 原始值)
updated_c_series = (df1[['a', 'b']].reset_index()
.merge(df2, on=['a', 'b'], how='left')
.set_index('index')['c'] # 这里的 'c' 是 df2 的 'c'
.fillna(df1['c'])
)
# 将更新后的 Series 赋值回 df1 的 'c' 列
df1['c'] = updated_c_series
print("\n方法二:结合 merge、reset_index 和 fillna 更新后的 df1:")
print(df1)输出:
方法二:结合 merge、reset_index 和 fillna 更新后的 df1: a b c 0 1 10 1111.0 1 2 20 2222.0 2 3 30 3333.0 3 4 40 400.0
解释:
在 Pandas 中更新数据框的子集行是一个常见的任务,但直接使用 set_index().loc[...] 可能会因为操作的是临时视图而失败。为了实现高效且正确的更新,我们应采用 merge 和 combine_first 或 merge、reset_index 和 fillna 的组合方法。这些方法不仅能够正确地将外部数据合并到现有 DataFrame 中,还能灵活地处理未匹配项,并支持原地更新,是 Pandas 数据操作中的重要技巧。选择哪种方法取决于您的具体需求,例如是否需要保留原始索引、是否需要处理未匹配项,以及对数据类型和性能的考量。
以上就是Pandas 数据框子集行更新:高效赋值与常见陷阱解析的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号