
在pandas中,当我们希望将一个dataframe的新列添加到另一个dataframe时,常用的方法是 dataframe.join() 或 pd.merge()。这些函数的核心原理是基于一个或多个键(通常是索引或指定列)进行匹配,然后将匹配到的行合并。然而,当涉及的dataframe(尤其是用作主体的dataframe)包含重复索引时,这种基于键的匹配逻辑可能会导致意料之外的结果——产生笛卡尔积。
考虑以下场景:我们有一个初始DataFrame df,其索引 BS 包含重复值。我们希望添加一个新列 M2,这些新值与 df 的现有行一一对应。
import pandas as pd
# 初始DataFrame df
value_df = {'M1': [3.65, 3.58, 3.5], 'BS': [999, 999, 999], 'RAW':['A', 'B', 'C']}
df = pd.DataFrame(value_df).set_index('BS')
# 待添加新列的DataFrame df1
value_df1 = {'M2': [3.35, 3.38, 3.3], 'BS': [999, 999, 999]}
df1 = pd.DataFrame(value_df1).set_index('BS')
print("原始DataFrame df:")
print(df)
print("\n待添加列的DataFrame df1:")
print(df1)输出:
原始DataFrame df:
M1 RAW
BS
999 3.65 A
999 3.58 B
999 3.50 C
待添加列的DataFrame df1:
M2
BS
999 3.35
999 3.38
999 3.30如果我们尝试使用 df.join(df1, on='BS', how='outer') 来添加 M2 列:
# 尝试使用 join 操作
df_joined = df.join(df1, on='BS', how='outer')
print("\n使用 df.join(df1) 的结果:")
print(df_joined)输出:
使用 df.join(df1) 的结果:
M1 RAW M2
BS
999 3.65 A 3.35
999 3.65 A 3.38
999 3.65 A 3.30
999 3.58 B 3.35
999 3.58 B 3.38
999 3.58 B 3.30
999 3.50 C 3.35
999 3.50 C 3.38
999 3.50 C 3.30从结果可以看出,join 操作错误地生成了一个包含9行的DataFrame,而不是期望的3行。这是因为 join 默认会尝试基于索引(或指定的 on 列)进行匹配。当 df 和 df1 的索引 BS 都包含重复值 999 时,join 会将 df 中所有 BS=999 的行与 df1 中所有 BS=999 的行进行交叉匹配,从而导致笛卡尔积的产生。对于 df 中的每一行,它会与 df1 中的所有匹配行组合,这显然不是我们希望的“添加新列”行为。
当我们的目标是简单地将两个DataFrame按列拼接起来,并且它们的行顺序是对应关系(即使索引值重复),pd.concat 是一个更合适的选择。pd.concat 函数允许我们沿着指定的轴(行或列)堆叠或连接DataFrame。
要实现按列添加,我们需要将 axis 参数设置为 1。pd.concat(objs, axis=1) 会尝试根据索引对齐 objs 中的DataFrames,如果索引不唯一或无法完全对齐,它会退化到按位置对齐。在我们的例子中,df 和 df1 具有相同的行数和相同的索引结构(虽然索引值重复,但其顺序和数量是匹配的),因此 pd.concat(axis=1) 将完美地实现列的添加。
# 使用 pd.concat(axis=1) 添加新列
df_concatenated = pd.concat([df, df1], axis=1)
print("\n使用 pd.concat([df, df1], axis=1) 的结果:")
print(df_concatenated)输出:
使用 pd.concat([df, df1], axis=1) 的结果:
M1 RAW M2
BS
999 3.65 A 3.35
999 3.58 B 3.38
999 3.50 C 3.30这个结果正是我们所期望的:M2 列被正确地添加到了 df 中,并且保持了原始的行数和索引结构,没有产生任何冗余行。
pd.concat(axis=1) 的核心在于它执行的是“列向拼接”,而非“键值匹配合并”。它会尝试根据DataFrame的索引标签进行对齐。
示例:索引不完全匹配
# 假设 df1 只有两行
value_df1_partial = {'M2': [3.35, 3.38], 'BS': [999, 999]}
df1_partial = pd.DataFrame(value_df1_partial).set_index('BS')
df_concatenated_partial = pd.concat([df, df1_partial], axis=1)
print("\n使用 pd.concat([df, df1_partial], axis=1) 的结果 (df1行数不一致):")
print(df_concatenated_partial)输出:
使用 pd.concat([df, df1_partial], axis=1) 的结果 (df1行数不一致):
M1 RAW M2
BS
999 3.65 A 3.35
999 3.58 B 3.38
999 3.50 C NaN可以看到,第三行 M2 列被填充了 NaN,这符合预期行为。
总结:
当您需要将一个DataFrame的列添加到另一个DataFrame,并且这种添加是基于行的顺序对应关系(即使索引值重复),而非基于唯一的键匹配时,pd.concat(objs, axis=1) 是比 join 或 merge 更优、更准确的选择。它避免了因重复索引导致的笛卡尔积问题,提供了更直观和高效的列添加方式。在使用时,请确保源DataFrames的行顺序和数量符合您的预期,以便正确地对齐新旧数据。
以上就是如何在Pandas DataFrame中高效添加新列并处理重复索引的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号