查找df1('col1')中的值是否等于df2('col3')中的任何值,并在条件为True时从df1中删除行[Python]
查找df1('col1')中的值是否等于df2('col3')中的任何值,并在条件为True时从df1中删除行[Python]
我有两个pandas数据框,其中一些行是相同的。\n假设dataframe2是dataframe1的子集。\n我如何获得dataframe1中不在dataframe2中的行?\n
df1 = pandas.DataFrame(data = {'col1' : [1, 2, 3, 4, 5], 'col2' : [10, 11, 12, 13, 14]}) df2 = pandas.DataFrame(data = {'col1' : [1, 2, 3], 'col2' : [10, 11, 12]})
\ndf1\n
col1 col2 0 1 10 1 2 11 2 3 12 3 4 13 4 5 14
\ndf2\n
col1 col2 0 1 10 1 2 11 2 3 12
\n期望的结果:\n
col1 col2 3 4 13 4 5 14
问题:如何根据df1('col1')中的值是否与df2('col3')中的任何值相等,从df1中移除相应的行?
在解决这个问题之前,我们需要做一些假设。假设数据框df1和df2的索引是一致的(不考虑实际的列值)。
解决方法:使用索引的差集操作。
代码如下:
df1[~df1.index.isin(df2.index)]
这行代码的作用是,根据df1的索引是否在df2的索引中,来选择是否保留该行。如果索引在df2中不存在,则保留该行;如果索引在df2中存在,则移除该行。
通过使用`~df1.index.isin(df2.index)`,我们得到了一个布尔值的Series,其中为True的位置表示该行在df1中的索引不在df2中的索引中。
最后,我们使用`df1[~df1.index.isin(df2.index)]`来选择保留在df1中索引不在df2中的索引中的行,从而实现了根据df1('col1')的值是否与df2('col3')的值相等来移除行的目的。
值得注意的是,以上代码只考虑了索引是否一致,没有考虑实际的列值。如果需要考虑列值是否相等来决定是否移除行,可以使用类似的方法。
问题出现的原因是需要从df1中找出col1列的值与df2中col3列的任何值相等的行,并将这些行从df1中删除。解决方法有两种:
方法一:
1. 使用内连接将df1和df2进行合并,将合并结果存储在common变量中。
2. 通过筛选出col1和col2列的值不在common中的行来得到结果。
方法二:
1. 使用isin函数判断df1中的每个元素是否在df2中。
2. 将isin函数的结果取反,并使用dropna函数删除含有NaN值的行。
然而,如果df2中的行与df1的行的顺序不同,则第二种方法将无法得到正确结果。可以使用dropna函数的参数how='all'来解决这个问题。
另外,~符号在代码df1[~df1.isin(df2)]中表示取反操作,即选择不在df2中的元素。
根据不同的需求选择合适的方法来解决问题。
这个问题的出现是因为当前选择的解决方案产生了错误的结果。为了正确解决这个问题,我们可以将df1左连接到df2上,确保首先获得df2的唯一行。
首先,我们需要修改原始的DataFrame,添加包含数据[3, 10]的行。
df1 = pd.DataFrame(data = {'col1' : [1, 2, 3, 4, 5, 3], 'col2' : [10, 11, 12, 13, 14, 10]}) df2 = pd.DataFrame(data = {'col1' : [1, 2, 3], 'col2' : [10, 11, 12]}) df1 col1 col2 0 1 10 1 2 11 2 3 12 3 4 13 4 5 14 5 3 10 df2 col1 col2 0 1 10 1 2 11 2 3 12
执行左连接操作,消除df2中的重复行,以便df1的每一行与df2的一行进行连接。使用参数indicator返回一个额外的列,指示该行来自哪个表。
df_all = df1.merge(df2.drop_duplicates(), on=['col1','col2'], how='left', indicator=True) df_all col1 col2 _merge 0 1 10 both 1 2 11 both 2 3 12 both 3 4 13 left_only 4 5 14 left_only 5 3 10 left_only
创建一个布尔条件:
df_all['_merge'] == 'left_only' 0 False 1 False 2 False 3 True 4 True 5 True Name: _merge, dtype: bool
为什么其他解决方案是错误的
一些解决方案犯了同样的错误 - 它们只检查每个值是否独立存在于每个列中,而不是同时存在于同一行中。添加最后一行,该行是唯一的,但包含了来自df2的两列的值,暴露了这个错误:
common = df1.merge(df2,on=['col1','col2']) (~df1.col1.isin(common.col1))&(~df1.col2.isin(common.col2)) 0 False 1 False 2 False 3 True 4 True 5 False dtype: bool
这个解决方案得到了相同的错误结果:
df1.isin(df2.to_dict('l')).all(1)
但是,我想,他们假设col1是唯一的索引(问题中没有提到,但是显而易见)。所以,如果从来没有这样的情况,即对于相同的col1值有两个col2值(不能有两个col1=3的行),上述答案是正确的。
这当然不是显而易见的,所以你的观点是无效的。我的解决方案推广到了更多的情况。
问题,创建一个切片是否比创建一个布尔数组更容易?因为目标是获得行。
使用`df_all[df_all['_merge'] == 'left_only']`来得到包含结果的DataFrame。
对于新来的人来说,添加没有解释的额外行是令人困惑的。然后使这个解决方案更好。此外,我建议使用`how='outer'`,这样`_merge`列就会有left/right/both,当未来的读者尝试将解决方案应用到他们的问题时更容易理解。
有可能获得"left-only"的计数吗?
为什么需要`.drop_duplicates()`?我没有看到DF中有任何重复的行。