
本教程详细介绍了如何使用Pandas和NumPy高效地比较两个DataFrame。我们将学习如何判断DataFrame A中的每一行,其各列值是否都能在DataFrame B的对应列中找到,并据此为DataFrame A添加一个新列,根据匹配结果赋值为“Open”或“New”。
1. 引言
在数据分析和处理过程中,我们经常需要对比两个数据集,并根据对比结果更新或生成新的数据。pandas库提供了强大的工具来处理这类任务。本文将聚焦于一个具体场景:比较两个dataframe,判断第一个dataframe中的行数据是否在第二个dataframe中“存在”(具体定义为:该行的每个元素是否在其对应列中存在于第二个dataframe),并根据此结果为第一个dataframe添加一个新列进行标记。
2. 问题描述与示例数据
假设我们有两个DataFrame,df1 和 df2。我们的目标是为 df1 添加一个名为 new_col 的新列。如果 df1 中的某一行,其所有列的值都能在 df2 的对应列中找到,则 new_col 的值为 "Open";否则,为 "New"。
为了演示,我们创建以下示例数据:
import pandas as pd
import numpy as np
# DataFrame A (df1)
data1 = {
'A': [1, 2, 3, 4, 5],
'B': ['apple', 'banana', 'orange', 'apple', 'grape'],
'C': [10, 20, 30, 40, 50]
}
df1 = pd.DataFrame(data1)
print("原始 DataFrame df1:")
print(df1)
# DataFrame B (df2)
data2 = {
'A': [1, 2, 6],
'B': ['apple', 'banana', 'kiwi'],
'C': [10, 20, 60]
}
df2 = pd.DataFrame(data2)
print("\nDataFrame df2:")
print(df2)登录后复制
根据上述规则,期望的 df1 结果应为:
A B C new_col
0 1 apple 10 Open
1 2 banana 20 Open
2 3 orange 30 New
3 4 apple 40 New
4 5 grape 50 New
登录后复制
3. 解决方案:使用 isin() 和 all(axis=1)
Pandas的 isin() 方法与NumPy的 where() 函数结合使用,能够高效地解决这个问题。
3.1 核心思路
-
元素级存在性检查 (isin(other_dataframe)): df1.isin(df2) 会生成一个与 df1 形状相同的布尔型DataFrame。对于 df1 中的每个元素 df1.at[i, col_name],它会检查该元素的值是否存在于 df2 的 对应列 df2[col_name] 中。如果存在,则结果DataFrame中对应位置为 True,否则为 False。
-
行级所有元素匹配 (all(axis=1)): 在得到布尔型DataFrame后,我们使用 .all(axis=1) 方法。这会检查布尔型DataFrame的每一行,如果该行中的 所有 元素都是 True,则结果为 True,表示 df1 的该行所有值都在 df2 的对应列中找到了。
-
条件赋值 (np.where()): 最后,NumPy的 np.where(condition, value_if_true, value_if_false) 函数根据上一步生成的布尔系列,为 df1 的新列 new_col 赋值。
3.2 代码实现
# 应用解决方案
df1['new_col'] = np.where(df1.isin(df2).all(axis=1), 'Open', 'New')
print("\n更新后的 DataFrame df1:")
print(df1)登录后复制
3.3 结果解释
让我们逐步分析 df1.isin(df2).all(axis=1) 的执行过程:
-
df1.isin(df2):
- 对于 df1 的第一行 (1, 'apple', 10):
- 1 是否在 df2['A'] ([1, 2, 6]) 中?是 (True)。
- 'apple' 是否在 df2['B'] (['apple', 'banana', 'kiwi']) 中?是 (True)。
- 10 是否在 df2['C'] ([10, 20, 60]) 中?是 (True)。
- 因此,第一行对应的布尔结果为 [True, True, True]。
- 对于 df1 的第三行 (3, 'orange', 30):
- 3 是否在 df2['A'] 中?否 (False)。
- 'orange' 是否在 df2['B'] 中?否 (False)。
- 30 是否在 df2['C'] 中?否 (False)。
- 因此,第三行对应的布尔结果为 [False, False, False]。
- df1.isin(df2) 会生成一个布尔型DataFrame,例如:
A B C
0 True True True
1 True True True
2 False False False
3 False True False
4 False False False
登录后复制
-
.all(axis=1):
- 对于布尔型DataFrame的每一行,检查所有值是否都为 True。
- 第一行 [True, True, True] -> True
- 第二行 [True, True, True] -> True
- 第三行 [False, False, False] -> False
- 第四行 [False, True, False] -> False
- 第五行 [False, False, False] -> False
- 最终得到一个布尔型Series:[True, True, False, False, False]。
-
np.where(condition, 'Open', 'New'):
- 根据上述布尔型Series,将 df1['new_col'] 赋值。
- True 对应 Open,False 对应 New。
- 因此,new_col 的最终结果为 ['Open', 'Open', 'New', 'New', 'New'],这与我们的预期完全一致。
4. 注意事项与扩展
-
列名匹配: isin(other_dataframe) 方法要求两个DataFrame的列名必须匹配。它会根据列名进行元素级比较。如果 df1 中存在 df2 中没有的列,或者反之,这些不匹配的列在 isin 结果中将全部为 False。
-
性能: 对于大型DataFrame,isin() 方法通常比循环或合并操作更高效,因为它在底层使用了优化的C/Cython实现。
-
严格行匹配与当前方法的区别:
- 本教程的方法 (df1.isin(df2).all(axis=1)) 检查的是 df1 中某行的 每个元素 是否存在于 df2 的 对应列 中。
- 如果需要进行 严格的行匹配(即 df1 的某一行是否作为一个 完整的行 存在于 df2 中),则需要采取其他策略,例如:
- 将两个DataFrame转换为元组集合进行比较。
- 使用 pd.merge(df1, df2, how='left', indicator=True),然后根据 _merge 列的值判断。
- 将需要比较的列组合成一个唯一标识符(如字符串),然后使用 isin()。
- 请务必根据实际业务需求选择合适的比较逻辑。在本例中,提供的解决方案恰好符合题意和期望输出。
-
部分列比较: 如果只想比较 df1 和 df2 的部分列,可以在 isin() 之前先选择这些列,例如 df1[['A', 'B']].isin(df2[['A', 'B']]).all(axis=1)。
5. 总结
通过本教程,我们学习了如何利用Pandas的 isin() 方法结合NumPy的 np.where() 来实现DataFrame之间基于元素存在性的条件赋值。这种方法简洁高效,适用于需要根据复杂条件对DataFrame进行标记和分类的场景。理解 isin() 方法在接收DataFrame作为参数时的行为是关键,即它执行的是列与列之间的元素级匹配,再通过 all(axis=1) 聚合为行级判断。
以上就是Pandas DataFrame行级数据对比与条件赋值教程的详细内容,更多请关注php中文网其它相关文章!