如果 2 个 pandas 数据帧在 python 中具有相同的条目,请执行一些操作

Perform some operation if 2 pandas dataframe have same entries in python

提问人:spectre 提问时间:4/16/2023 最后编辑:spectre 更新时间:4/16/2023 访问量:61

问:

我有 2 个数据帧(购买销售),如下所示:

购买:

名字 项目 凭证 Amt 数量
一个 项目1 购买 10000 100
B 项目2 购买 500 50
B 项目1 购买 2000 20
C 项目3 购买 1000 100
D 项目4 购买 500 100
一个 项目3 购买 5000 50

销售:

名字 项目 凭证 Amt 数量
一个 项目1 销售 5300 50
B 项目2 销售 450 40
B 项目1 销售 1675 15
C 项目3 销售 1800 100

我想要一个输出数据帧,如果该人 () 出售了一件商品,则应从购买数据帧中扣除 and,并且应使用剩余的 and 创建一个新的数据帧,如下所示:NameAmtQtyAmtQty

输出数据帧:

名字 项目 凭证 Amt 数量
一个 项目1 剩余 4700 50
一个 项目3 剩余 5000 50
B 项目2 剩余 50 10
B 项目1 剩余 325 5
C 项目3 剩余 -800 0
D 项目4 剩余 500 100

请注意,已从购买数据帧中扣除人员 () 已售出的任何项目,其余项目 ( 和 ) 存储在新的输出数据帧中。此外,即使如此,人们也从未出售过任何物品,因此它应该包含在输出数据帧中。NameAmtQtyD

提前致谢!

数据帧

import pandas as pd

Purchases = {
    "Name": ["A", "B", "B", "C", "D", "A"],
    "item": ["Item1", "Item2", "Item1", "Item3", "Item4", "Item3"],
    "voucher": ["Purchase", "Purchase", "Purchase", "Purchase", "Purchase", "Purchase"],
    "Amt": [10000, 500, 2000, 1000, 500, 5000],
    "Qty": [100, 50, 20, 100, 100, 50],
}

Purchases = pd.DataFrame(Purchases)

Sales = {
    "Name": ["A", "B", "B", "C"],
    "item": ["Item1", "Item2", "Item1", "Item3"],
    "voucher": ["Sales", "Sales", "Sales", "Sales"],
    "Amt": [5300, 450, 1675, 1800],
    "Qty": [50, 40, 15, 100],
}

Sales = pd.DataFrame(Sales)
Python Pandas DataFrame 数据整理

评论

0赞 Corralien 4/16/2023
我认为您的输入数据帧中有错误:(C,item3)应该是 800 而不是 1800。
0赞 Laurent B. 4/16/2023
@Corralien我看不出在哪里,似乎是 1800 年
0赞 Corralien 4/16/2023
在 SALES 数据帧中。结果是 200,所以减法应该是 1000 - 800 而不是 1000 - 1800

答:

2赞 Laurent B. 4/16/2023 #1
Purchases = Purchases.set_index(['Name', 'item'])
Sales = Sales.set_index(['Name', 'item'])
Purchases['Amt'].update(Purchases['Amt'].sub(Sales['Amt']))
Purchases['Qty'].update(Purchases['Qty'].sub(Sales['Qty']))
Purchases = Purchases.reset_index().sort_values(by=['Name'])

print(Purchases)
  Name   item   voucher   Amt  Qty
0    A  Item1  Purchase  4700   50
5    A  Item3  Purchase  5000   50
1    B  Item2  Purchase    50   10
2    B  Item1  Purchase   325    5
3    C  Item3  Purchase  -800    0
4    D  Item4  Purchase   500  100

评论

0赞 Laurent B. 4/16/2023
感谢您提供此信息 Corralien,将在下一个 Pandas 版本(即 Pandas 2)中被弃用。所以现在必须养成良好的习惯;-)ìnplace
0赞 Corralien 4/16/2023
可能也会被弃用。(我希望:-))。我认为所有方法都应该始终返回一个副本(显式比隐式更好)。只有 、 和其他项赋值应就地修改 DataFrame/Series,因为它们是显式的。恕我直言:-)update.loc.iloc
0赞 Laurent B. 4/16/2023
是的,当然它会更可取,但在 Pandas 2 : pandas.pydata.org/docs/reference/api/pandas.Series.update.html (版本 2.0.0(稳定版))中未被弃用。但我必须承认,即使非常有用,我也不喜欢返回 None 的方法(buggs 的来源)。updateupdate
2赞 Corralien 4/16/2023 #2

您可以使用:merge

# dfP = PURCHASE dataframe
# dfS = SALES dataframe
out = (Purchases.merge(Sales.drop(columns='voucher'), on=['Name', 'item'],
                 suffixes=(None, '_'), how='left')
                .assign(Amt=lambda x: x['Amt'] - x.pop('Amt_').fillna(0).astype(int),
                        Qty=lambda x: x['Qty'] - x.pop('Qty_').fillna(0).astype(int),
                        voucher='Remaining'))

输出:

>>> out
  Name   item    voucher   Amt  Qty
0    A  Item1  Remaining  4700   50
1    B  Item2  Remaining    50   10
2    B  Item1  Remaining   325    5
3    C  Item3  Remaining  -800    0
4    D  Item4  Remaining   500  100
5    A  Item3  Remaining  5000   50
2赞 mozway 4/16/2023 #3

使用良好的旧索引对齐方式:

tmp = Purchases.set_index(['Name', 'item'])
out = (tmp
       .sub(Sales.set_index(['Name', 'item'])[['Amt', 'Qty']])
       .combine_first(tmp).assign(voucher='Remaining')
       .reset_index()[Purchases.columns]
      )

输出:

  Name   item    voucher     Amt    Qty
0    A  Item1  Remaining  4700.0   50.0
1    A  Item3  Remaining  5000.0   50.0
2    B  Item1  Remaining   325.0    5.0
3    B  Item2  Remaining    50.0   10.0
4    C  Item3  Remaining  -800.0    0.0
5    D  Item4  Remaining   500.0  100.0

评论

0赞 Laurent B. 4/16/2023
我不知道我是爱你还是讨厌你哈哈;-p
0赞 mozway 4/16/2023
@LaurentB。那就宁愿爱我吧,这个世界上的仇恨已经够多了:p
0赞 Laurent B. 4/16/2023
好吧,这就是我的骰子指示我的:-p