Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python pandas-按行元素按另一个dataframe筛选dataframe_Python_Pandas_Dataframe - Fatal编程技术网

Python pandas-按行元素按另一个dataframe筛选dataframe

Python pandas-按行元素按另一个dataframe筛选dataframe,python,pandas,dataframe,Python,Pandas,Dataframe,我有一个数据帧df1,看起来像: c k l 0 A 1 a 1 A 2 b 2 B 2 a 3 C 2 a 4 C 2 d 还有一个叫做df2的类似: c l 0 A b 1 C a 我想过滤df1只保留df2中没有的值。要筛选的值应为(A,b)和(C,A)元组。到目前为止,我尝试应用isin方法: d = df[~(df['l'].isin(dfc['l']) & df['c'].isin(dfc['c']))] 这在我看

我有一个数据帧df1,看起来像:

   c  k  l
0  A  1  a
1  A  2  b
2  B  2  a
3  C  2  a
4  C  2  d
还有一个叫做df2的类似:

   c  l
0  A  b
1  C  a
我想过滤
df1
只保留
df2
中没有的值。要筛选的值应为
(A,b)
(C,A)
元组。到目前为止,我尝试应用
isin
方法:

d = df[~(df['l'].isin(dfc['l']) & df['c'].isin(dfc['c']))]
这在我看来太复杂了,它返回:

   c  k  l
2  B  2  a
4  C  2  d
但我期待着:

   c  k  l
0  A  1  a
2  B  2  a
4  C  2  d

您可以在由所需列构造的多索引上使用
isin
高效地执行此操作:

df1 = pd.DataFrame({'c': ['A', 'A', 'B', 'C', 'C'],
                    'k': [1, 2, 2, 2, 2],
                    'l': ['a', 'b', 'a', 'a', 'd']})
df2 = pd.DataFrame({'c': ['A', 'C'],
                    'l': ['b', 'a']})
keys = list(df2.columns.values)
i1 = df1.set_index(keys).index
i2 = df2.set_index(keys).index
df1[~i1.isin(i2)]

我认为这比@IanS的类似解决方案有所改进,因为它不采用任何列类型(即,它可以处理数字和字符串)


(以上答案为编辑,以下为我的初始答案)

有趣!这是我以前从未遇到过的事情。。。我可能会通过合并两个数组来解决这个问题,然后删除定义了
df2
的行。下面是一个使用临时数组的示例:

df1 = pd.DataFrame({'c': ['A', 'A', 'B', 'C', 'C'],
                    'k': [1, 2, 2, 2, 2],
                    'l': ['a', 'b', 'a', 'a', 'd']})
df2 = pd.DataFrame({'c': ['A', 'C'],
                    'l': ['b', 'a']})

# create a column marking df2 values
df2['marker'] = 1

# join the two, keeping all of df1's indices
joined = pd.merge(df1, df2, on=['c', 'l'], how='left')
joined

也许有一种不用临时数组的方法可以做到这一点,但我想不出一种。只要你的数据不是很大,上述方法应该是一个快速而充分的答案。

怎么样:

df1['key'] = df1['c'] + df1['l']
d = df1[~df1['key'].isin(df2['c'] + df2['l'])].drop(['key'], axis=1)

避免创建额外列或进行合并的另一个选项是在df2上执行groupby以获得不同的(c,l)对,然后使用该对过滤df1

gb = df2.groupby(("c", "l")).groups
df1[[p not in gb for p in zip(df1['c'], df1['l'])]]]

对于这个小示例,它实际上似乎比基于pandas的方法运行得快一些(在我的机器上是666µs,而在我的机器上是1.76 ms),但我怀疑它在更大的示例上可能会慢一些,因为它正在进入纯Python。

这非常简洁,效果很好:

df1 = df1[~df1.index.isin(df2.index)]

我认为这是一种非常简单的方法,当您希望基于另一个数据帧中的多个列或甚至基于自定义列表过滤数据帧时

df1 = pd.DataFrame({'c': ['A', 'A', 'B', 'C', 'C'],
                    'k': [1, 2, 2, 2, 2],
                    'l': ['a', 'b', 'a', 'a', 'd']})
df2 = pd.DataFrame({'c': ['A', 'C'],
                    'l': ['b', 'a']})

#values of df2 columns 'c' and 'l' that will be used to filter df1
idxs = list(zip(df2.c.values, df2.l.values)) #[('A', 'b'), ('C', 'a')]

#so df1 is filtered based on the values present in columns c and l of df2 (idxs)
df1 = df1[pd.Series(list(zip(df1.c, df1.l)), index=df1.index).isin(idxs)]
使用&: 更优雅的方法是使用参数
indicator=True
进行
left join
,然后使用
query
过滤所有
left\u
行:

d = (
    df1.merge(df2, 
              on=['c', 'l'],
              how='left', 
              indicator=True)
    .query('_merge == "left_only"')
    .drop(columns='_merge')
)

print(d)
   c  k  l
0  A  1  a
2  B  2  a
4  C  2  d
indicator=True
返回一个数据帧,其中包含一个额外的列
\u merge
,该列仅标记每一行
左行,两行,右行

df1.merge(df2, on=['c', 'l'], how='left', indicator=True)

   c  k  l     _merge
0  A  1  a  left_only
1  A  2  b       both
2  B  2  a  left_only
3  C  2  a       both
4  C  2  d  left_only

c
l
这两列的值串联起来,并将其用作键,怎么样?感谢您的属性:)我认为您应该将您的编辑变成一个新的答案,希望是可以接受的答案。我一定会投赞成票!我将编辑更改为主要答案。谢谢好方法!多亏了大家的帮助,我觉得这样做比较容易@jakevdp,谢谢,我试过了,对这个案子很有效。我有一个稍微复杂一点的schenario,其中
df2=pd.DataFrame({'c':['a',*],'l':[*,'a']})
,我指的是通配符,所以值可以是任何值。因此,
df1[~i1.isin(i2)]
的输出应该是:
pd.DataFrame({'c':['c'],'k':[2],'l':['d']})
。这可以通过修改上述内容来实现吗?您的初始答案会创建一个标记列,但pd.merge()现在包含一个参数,即“indicator”。如果选择indicator=True,则会添加一个额外的列(称为“_merge”),它本身就是新创建的合并df上的一个标记。然后你会过滤加入的[''u merge']=='left'u only'。我想你的答案会更有力一些,因为有了更多的信息。您是否可以在这个答案中包含一些关于为什么有人应该使用这种方法的信息,或者至少这段代码实现了什么?如果你无法提出任何细节,请考虑一个场景:如果我将代码盲目地复制粘贴到我的应用程序中,有什么值得我担心的边缘情况吗?我什么时候应该避免使用这种方法?虽然这段代码可能会回答这个问题,但提供关于它如何和/或为什么解决问题的附加上下文将提高答案的长期价值。请阅读这篇文章以提供高质量的答案。这只是因为示例数据是对齐的,如果键没有对齐,这在任何意义上都会失败。不知道这是怎么得到14票的。
df1.merge(df2, on=['c', 'l'], how='left', indicator=True)

   c  k  l     _merge
0  A  1  a  left_only
1  A  2  b       both
2  B  2  a  left_only
3  C  2  a       both
4  C  2  d  left_only