根据另一个数据框的列值过滤数据框

11

我有两个数据框

df1

Company           SKU   Sales
Walmart           A     100
Total             A     200
Walmart           B     200
Total             B     300
Walmart           C     400
Walmart           D     500

df2

 Company             SKU   Sales
 Walmart             A     400
 Total               B     300
 Walmart             C     900
 Walmart             F     400
 Total               G     500

我希望得到一个结果数据框(df2),其中只包含df1和df2中SKU匹配的记录。

df2

Company       SKU   Sales 
Walmart       A     400
Total         B     300
Walmart       C     900

我只想在df2中找到 df1 中唯一的 (公司 + SKU) 值。

有没有好的方法实现这个需求?

3个回答

24

更新

你可以使用一个简单的掩码:

m = df2.SKU.isin(df1.SKU)
df2 = df2[m]
你需要使用内连接(inner join)。尝试这样做:
df3 = df1.merge(df2, on=['SKU','Sales'], how='inner')

#  SKU  Sales
#0   A    100
#1   B    200
#2   C    300

或者这个:

df3 = df1.merge(df2, on='SKU', how='inner')

#  SKU  Sales_x  Sales_y
#0   A      100      100
#1   B      200      200
#2   C      300      300

嗨 Anton,感谢您的回答。 销售额并不是我的重点。 它可能是任何值。 - Ahamed Moosa
@AhamedMoosa,我不太明白你想要什么。我提出的当前解决方案可以给你所需的结果。好的,抱歉你改变了名字。 - Anton vBR
您更新的答案符合我的需求。谢谢。 我可以在多个列上使用isin吗? - Ahamed Moosa
@AhamedMoosa 抱歉回复晚了。您是否仍在寻找如何在多个列上执行此操作的答案? - Anton vBR
我已经找到了解决这个问题的方法,我使用了你的解决方案,并对我的用例进行了一些改进。谢谢。 - Ahamed Moosa
@AhamedMoosa 好的,太棒了 :) - Anton vBR

5

一种方法是对齐索引,然后使用掩码。

# align indices
df1 = df1.set_index(['Company',  'SKU'])
df2 = df2.set_index(['Company',  'SKU'])

# calculate & apply mask
df2 = df2[df2.index.isin(df1.index)].reset_index()

重置索引不是必需的,但需要将 公司SKU 提升为列。


1
谢谢jpp,我做了类似的事情。我已经将公司和SKU列连接起来,然后应用了掩码。 - Ahamed Moosa

3

解决方案1:

# First identify the common SKU's    
temp = list(set(list(df1.SKU)).intersection(set(list(df2.SKU))))

# Filter df2 using the list of common SKU's
df3 = df2[df2.SKU.isin(temp)]
print(df3)

   SKU  Sales
0   A   400
1   B   300
2   C   900

解决方案2:一行解决方案。
df3 = df2[df2.SKU.isin(list(df1.SKU))]

编辑1: 对于更新后的问题的解决方案(不是最优的方式,但可以回答您的问题)

# reading data for df1
df1= pd.read_clipboard(sep='\\s+')
df1
    Company SKU Sales
0   Walmart A   100
1   Total   A   200
2   Walmart B   200
3   Total   B   300
4   Walmart C   400
5   Walmart D   500

# reading data for df2
df2= pd.read_clipboard(sep='\\s+')
df2
Company SKU Sales
0   Walmart A   400
1   Total   B   300
2   Walmart C   900
3   Walmart F   400
4   Total   G   500

# Using intersect and zip to create a list of tuples matching in the data frames
temp = list(set(list(zip(df1.Company,df1.SKU))).intersection(set(list(zip(df2.Company,df2.SKU)))))
temp
[('Walmart', 'A'), ('Walmart', 'C'), ('Total', 'B')]

# Creating a helper variable in df2 to lookup in the temp list
df2["temp"] = list(zip(df2.Company,df2.SKU))
df2= df2[df2["temp"].isin(temp)]
del(df2["temp"])
df2
    Company SKU Sales
0   Walmart A   400
1   Total   B   300
2   Walmart C   900

欢迎提出建议改进此代码


嗨Ram,感谢你的回答。以防万一,如果我有多个列需要相交怎么办? - Ahamed Moosa
那么你可以选择解决方案1,因为temp是一个列表,你可以进一步与另一个列表进行交集运算。 - Ram
嗨Ram,我已经编辑了我的问题,请问您的第一个解决方案是否可实现? - Ahamed Moosa
1
在我看来,list() 转换并不必要,而且可能会很耗费资源。 - jpp
完全同意你的观点。谢谢! - Ram

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