在Python中,根据另一个数据框选择行。

18

我有以下数据框:

import pandas as pd
import numpy as np
df1 = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(),
                   'B': 'one one two three two two one three'.split(),
                   'C': np.arange(8), 'D': np.arange(8) * 2})
print(df1)

    A      B   C   D
0  foo    one  0   0
1  bar    one  1   2
2  foo    two  2   4
3  bar  three  3   6
4  foo    two  4   8
5  bar    two  5  10
6  foo    one  6  12
7  foo  three  7  14
我希望通过下述方式,从df2中选择df1的行:

df2 = pd.DataFrame({'A': 'foo bar'.split(),
                   'B': 'one two'.split()
                   })
print(df2)

     A    B
0  foo  one
1  bar  two

这是我在Python中尝试过的方法,但我想知道是否还有其他方法。谢谢。

df = df1.merge(df2, on=['A','B'])
print(df)

这是预期的输出。

    A      B   C   D
0  foo    one  0   0
1  bar    two  5  10
2  foo    one  6  12

如何使用pandas从数据框中选择两个不同列的行?

根据另一个数据框选择数据框的列


当前方法有什么问题? - meW
3
我认为这是一个好的解决方案。 - jezrael
1
对不起,也许我问了一个愚蠢的问题。 - ah bon
有效的代码应该放在代码审查中。但是说实话,我不认为审查会有多大作用,我认为你做得很好了。 - Diane M
同意jezrael和Arthur的观点,这很好。 - Mehrdad Pedramfar
显示剩余2条评论
3个回答

21

最简单的方法是使用内部连接merge

另一种解决方案是使用过滤:

arr = [np.array([df1[k] == v for k, v in x.items()]).all(axis=0) for x in df2.to_dict('r')]
df = df1[np.array(arr).any(axis=0)]
print(df)
     A    B  C   D
0  foo  one  0   0
5  bar  two  5  10
6  foo  one  6  12

或者创建MultiIndex并使用Index.isin进行筛选:

df = df1[df1.set_index(['A','B']).index.isin(df2.set_index(['A','B']).index)]
print(df)
     A    B  C   D
0  foo  one  0   0
5  bar  two  5  10
6  foo  one  6  12

对于在这里提供评论和帮助的 Python 大师们,我向您表示最真挚的感谢和崇高的敬意!!;) - ah bon
4
@ahbon - 是的,而且超棒的是有很多pandas大师,所以很多问题都已经得到了解答。开心编程! - jezrael
你的第二个解决方案太棒了!只需一行代码就能解决问题,而且得到了期望的答案。 - ah bon
@ahbon - 是的,这样更好 :) - jezrael

2
方法 #4. .apply + key 函数:
>>> key = lambda row: (row.A, row.B)
>>> df1[df1.apply(key, axis=1).isin(df2.apply(key, axis=1))]
     A    B  C   D
0  foo  one  0   0
5  bar  two  5  10
6  foo  one  6  12

方法#5:使用.join函数:
>>> df1.join(df2.set_index(['A', 'B']), on=['A', 'B'], how='right')
     A    B  C   D
0  foo  one  0   0
6  foo  one  6  12
5  bar  two  5  10

已经提到的方法:

  1. .merge@ahbon提出
  2. 使用 .to_dict('records') 进行过滤,由@jezrael提出(最快)
  3. Index.isin@jezrael提出

性能比较(从快到慢):

>>> %%timeit
>>> df1[np.array([np.array([df1[k] == v for k, v in x.items()]).all(axis=0) for x in df2.to_dict('records')]).any(axis=0)]
1.62 ms ± 15.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

>>> key = lambda row: (row.A, row.B)
>>> %%timeit
>>> df1[df1.apply(key, axis=1).isin(df2.apply(key, axis=1))]
2.96 ms ± 408 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

>>> %%timeit
>>> df1.merge(df2, on=['A','B'])
3.15 ms ± 472 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

>>> %%timeit
>>> df1.join(df2.set_index(['A', 'B']), on=['A', 'B'], how='right')
3.97 ms ± 341 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

>>> %%timeit
>>> df1[df1.set_index(['A','B']).index.isin(df2.set_index(['A','B']).index)]
6.55 ms ± 391 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

1
# The .merge method performs an inner join by default. 
# The resulting dataframe will only have rows where the 
# merge column value exists in both dataframes

x = df_only_english.merge(train_orders.assign(id=train_orders.id))
x

Unnamed: 0  language    score   id  iso_language_name   is_en   cell_order
0   0   en  0.999998    00015c83e2717b  English English 2e94bd7a 3e99dee9 b5e286ea da4f7550 c417225b 51e3cd89 2600b4eb 75b65993 cf195f8b 25699d02 72b3201a f2c750d3 de148b56...
1   1   en  0.999999    0001bdd4021779  English English 3fdc37be 073782ca 8ea7263c 80543cd8 38310c80 073e27e5 015d52a4 ad7679ef 7fde4f04 07c52510 0a1a7a39 0bcd3fef 58bf360b
2   2   en  0.999996    0001daf4c2c76d  English English 97266564 a898e555 86605076 76cc2642 ef279279 df6c939f 2476da96 00f87d0a ae93e8e6 58aadb1d d20b0094 986fd4f1 b4ff1015...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接