如何根据另一个DataFrame中的数据删除DataFrame的行?

6
我刚接触pandas,正在尝试解决这个场景: 我有一个包含两个产品的示例DataFrame。df =
  Product_Num     Date   Description  Price 
          10    1-1-18   Fruit Snacks  2.99
          10    1-2-18   Fruit Snacks  2.99
          10    1-5-18   Fruit Snacks  1.99
          10    1-8-18   Fruit Snacks  1.99
          10    1-10-18  Fruit Snacks  2.99
          45    1-1-18         Apples  2.99 
          45    1-3-18         Apples  2.99
          45    1-5-18         Apples  2.99
          45    1-9-18         Apples  1.49
          45    1-10-18        Apples  1.49
          45    1-13-18        Apples  1.49
          45    1-15-18        Apples  2.99 

我还有另一个小数据框,长这样(显示相同产品的促销价格):df2=
  Product_Num   Price 
          10    1.99
          45    1.49 

请注意,df2不包含“Date”和“Description”列。我想要做的是使用df1中的数据,删除所有在促销期间的日期(对于所有在促销期间的日期),从df1中删除所有促销价格。最好的方法是什么?
所以,我想看到这个:
  Product_Num     Date   Description  Price 
          10    1-1-18   Fruit Snacks  2.99
          10    1-2-18   Fruit Snacks  2.99
          10    1-10-18  Fruit Snacks  2.99
          45    1-1-18         Apples  2.99 
          45    1-3-18         Apples  2.99
          45    1-5-18         Apples  2.99
          45    1-15-18        Apples  2.99 

我在考虑对价格和产品编号这两列进行合并,然后再从那里开始思考。但是由于有多个日期,我感到有些困惑。

df[df.Price == 2.99] - thomas.mac
在我的大型DataFrame中,价格不会全部都是2.99 @thomas.mac - Hana
4个回答

9

isin&的使用

df.loc[~((df.Product_Num.isin(df2['Product_Num']))&(df.Price.isin(df2['Price']))),:]
Out[246]: 
    Product_Num     Date  Description  Price
0            10   1-1-18  FruitSnacks   2.99
1            10   1-2-18  FruitSnacks   2.99
4            10  1-10-18  FruitSnacks   2.99
5            45   1-1-18       Apples   2.99
6            45   1-3-18       Apples   2.99
7            45   1-5-18       Apples   2.99
11           45  1-15-18       Apples   2.99

更新

df.loc[~df.index.isin(df.merge(df2.assign(a='key'),how='left').dropna().index)]
Out[260]: 
    Product_Num     Date  Description  Price
0            10   1-1-18  FruitSnacks   2.99
1            10   1-2-18  FruitSnacks   2.99
4            10  1-10-18  FruitSnacks   2.99
5            45   1-1-18       Apples   2.99
6            45   1-3-18       Apples   2.99
7            45   1-5-18       Apples   2.99
11           45  1-15-18       Apples   2.99

2
这样写会不会也匹配到 (product=10 and price=1.49)? - jpp
我喜欢这个解决方案。你能解释一下 df2.assign(a='key') 是做什么的吗? - jpp
是的,我和 @jp_data_analysis 有同样的问题 :) - Hana
1
@jp_data_analysis 添加一个新的键,因为df2列是df的子集,如果我们进行左合并,它将不会改变任何东西:-),我们为df2构建一个新列,然后进行左合并,然后我们可以通过NAN过滤未匹配的内容。 - BENY
@Hana,当列df = df2且df2是df的子集时,df.merge(df2,how='left')返回df,仅当df和df2在列上不同时,我们才知道哪个来自df的与df2不匹配,然后我们可以将其过滤掉。 - BENY

2

使用Product_Num作为两个数据帧的索引,您可以从df1中删除索引,然后将数据帧连接起来:

import pandas as pd

df1 = pd.DataFrame({'Product_Num':[1,2,3,4], 'Date': ['01/01/2012','01/02/2013','02/03/2013','04/02/2013'], 'Price': [10,10,10,10]})
df1 = df1.set_index('Product_Num')
df2 = pd.DataFrame({'Product_Num':[2], 'Date':['03/3/2012'], 'Price': [5]})
df2 = df2.set_index('Product_Num')

拖放和连接:

df_new = df1.drop(df2.index)
df_new = pd.concat([df_new, df2])

结果:

               Date  Price
Product_Num                   
1            01/01/2012     10
3            02/03/2013     10
4            04/02/2013     10
2             03/3/2012      5

1
你可以将 df2 转换成字典,然后过滤掉 df1 中的值。
df[df[df2.columns].isin(df2.to_dict('list')).sum(1) <= 1]

产出
      Date   Description  Price  Product_Num
0    1-1-18  Fruit Snacks   2.99           10
1    1-2-18  Fruit Snacks   2.99           10
4   1-10-18  Fruit Snacks   2.99           10
5    1-1-18        Apples   2.99           45
6    1-3-18        Apples   2.99           45
7    1-5-18        Apples   2.99           45
11  1-15-18        Apples   2.99           45

0

可爱易读

promo_prices = df2['Price']
promo_prods = df2['Product_Num']

no_pro = df

for price, prod in zip(promo_prices, promo_prods):
    no_pro = no_pro.where(df != (price or prod)).dropna()

除非没有其他解决方案,否则在Pandas中使用循环不被认为是一种好的实践,因为它非常缓慢且占用内存。 - Kami

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