努力迭代数据框

Struggling with iterating through dataframes

我是 Python 的新手,在发帖寻求帮助之前,我已竭尽全力用尽所有资源。我整个周末和今天一整天都在尝试想出一个我认为应该使用两个数据帧编写代码的简单场景,但是,对于我的一生来说,我一直在转动轮子,没有取得任何重大进展。

情况是有一个数据框包含销售数据:

CUSTOMER  ORDER   SALES_DATE  SALES_ITEM_NUMBER  UNIT_PRICE  SALES_QTY
001871    225404  01/31/2018  03266465555        1           200
001871    225643  02/02/2018  03266465555        2           600
001871    225655  02/02/2018  03266465555        3           1000
001956    228901  05/29/2018  03266461234        2.2658      20

和第二个带有采购数据的数据框:

PO_DATE       PO_ITEM_NUMBER  PO_QTY  PO_PRICE
01/15/2017    03266465555     1000    1.55
01/25/2017    03266465555     500     5.55
02/01/2017    03266461234     700     4.44
02/01/2017    03266461234     700     2.22

我想做的就是找出销售订单数据框中每一行的最大值 PO_PRICE 是多少,因为我正在尝试最大化我购买的商品之间的差异它的用途,以及我卖它的价格。

当我第一次看到这个时,我想一个简单的嵌套 for 循环就可以解决问题,并增加计数器。但问题是我对数据框不够精通,所以我一直在尝试访问其中的元素。还要记住的是,我已经卖出了 1800 件第一件商品,但只买了其中的 1500 件。所以,当我遍历这个时:

对于第一个销售订单行,我卖出了 200 个。Max_PO_PRICE = $5.55 [对于其中的 500 个]。所以,我需要从 PO_QTY 数据框中减去 200,因为我现在已经计算了它们。

对于第二个销售订单行,我卖出了 600 个。还有 300 个我可以声称是我以 5.55 美元购买的,但是,我已经用完了所有这 500 个,所以我不能做的最好的事情是进入另一行,其中 Max_PO_PRICE = $1.55(其中 1,000 个)。所以对于这个,我可以以 5.55 美元的价格索取 300 美元,以 1.55 美元的价格索取另外 300 美元。我不能要求超过我买的。

这是我想出的代码,我想我可能做错了,但是,一些指导和建议将非常感谢和帮助。

我并不是要任何人为我编写代码,而只是建议您采用哪种方法,以及是否有更好的方法。我认为必须有....

提前感谢您的反馈和帮助。
-克莱尔

for index1,row1 in sales.iterrows():
    SalesQty = sales.loc[index1]["SALES_QTY"]
    for index2,row2 in purchases.iterrows():
        if (row1['SALES_ITEM_NUMBER']==row2['PO_ITEM_NUMBER']) and (row2['PO_QTY']>0):
           # Find the Maximum PO Price in the result set
               max_PO_Price = abc["PO_PRICE"].max()

            xyz = purchases.loc[index2]
            abc = abc.append(xyz)
    
           if(SalesQty <= Purchase_Qty):
              print("Before decrement, PO_QTY = ",??????? *<==== this is where I'm struggle busing****)
              print()
    +index2
    #Drop the data from the xyz DataFrame
    xyz=xyz.iloc[0:0]

    #Drop the data from the abc DataFrame
    abc=abc.iloc[0:0]
+index1

这看起来 SQL 可以通过分析函数优雅地处理。幸运的是 Pandas 提供了大部分(但不是全部)此功能,并且它比嵌套 iterrows 快得多。无论如何,我都不是 Pandas 专家,但我会试一试。如果我误解了这个问题,我深表歉意。

SALES_QTY 进行分组很有意义,我们将使用它来跟踪我们拥有的数量:

sales_grouped = sales.groupby(["SALES_ITEM_NUMBER"], as_index = False).agg({"SALES_QTY":"sum"})

让我们将 table 组合成一个,这样我们就可以迭代一个 table 而不是两个。我们可以在公共列 "PO_ITEM_NUMBER""SALES_ITEM_NUMBER" 上使用 JOIN 操作,或者 Pandas 喜欢称之为“合并”。当我们这样做时,让我们对按 "PO_ITEM_NUMBER" 分类的 table 进行排序,最昂贵的“PO_PRICE”在顶部,这是下一个代码块相当于 FN OVER PARTITION BY ORDER BY SQL 解析函数.

sorted_table = purchases.merge(sales_grouped, 
                            how = "left",
                            left_on = "PO_ITEM_NUMBER",
                            right_on = "SALES_ITEM_NUMBER").sort_values(by = ["PO_ITEM_NUMBER", "PO_PRICE"], 
                                                                        ascending = False)

让我们创建一个列 CUM_PO_QTY,其中包含 PO_QTY(partitioned/grouped 乘以 PO_ITEM_NUMBER)的总和。当我们超过最大值 SALES_QTY.

时,我们将使用它来标记
sorted_table["CUM_PO_QTY"] = sorted_table.groupby(["PO_ITEM_NUMBER"], as_index = False)["PO_QTY"].cumsum()

这是自定义部分的用武之地,我们可以集成自定义函数以使用 apply() 沿数据框应用 row-by-row(甚至按列)。我们正在创建两列 TRACKED_QTY,它只是 SALES_QTY 减去 CUM_PO_QTY,所以我们知道什么时候我们将 运行 变成负数,而 PRICE_SUM 最终会是获得或花费的最大价值。但现在:如果 TRACKED_QTY 小于 0,我们乘以 PO_QTY,否则乘以 SALES_QTY 以达到保护目的。

sorted_table[["TRACKED_QTY", "PRICE_SUM"]] = sorted_table.apply(lambda x: pd.Series([x["SALES_QTY"] - x["CUM_PO_QTY"], 
                                                                              x["PO_QTY"] * x["PO_PRICE"] 
                                                                              if x["SALES_QTY"] - x["CUM_PO_QTY"] >= 0 
                                                                              else x["SALES_QTY"] * x["PO_PRICE"]]), axis = 1)

为了处理尾随 TRACKED_QTY 负数,我们可以使用条件掩码过滤正数,groupby 负数仅显示最大 PRICE_SUM 值。 然后简单地追加这两个 table 并求和。

  evaluated_table = sorted_table[sorted_table["TRACKED_QTY"] >= 0]
evaluated_table = evaluated_table.append(sorted_table[sorted_table["TRACKED_QTY"] < 0].groupby(["PO_ITEM_NUMBER"], as_index = False).max())

    evaluated_table = evaluated_table.groupby(["PO_ITEM_NUMBER"], as_index = False).agg({"PRICE_SUM":"sum"})

希望这对你有用。