【问题标题】:For loop that adds and deducts from pandas columns从 Pandas 列中添加和减去的 for 循环
【发布时间】:2021-12-24 09:41:05
【问题描述】:

所以我有这个 df

SUPPLIER   PRODUCTID   STOREID   BALANCE   AVG_SALES   TO_SHIP
SUP1       P1          STR1      50        5           18
SUP1       P1          STR2      6         7           18
SUP1       P1          STR3      74        4           18
SUP2       P4          STR1      35        3           500
SUP2       P4          STR2      5         4           500
SUP2       P4          STR3      54        7           500

始终按供应商和产品 ID 分组。 TO_SHIP 列对于该组是唯一的。因此,例如,我有 18 个产品要发送给带有 P1 的 SUP1。然后我添加新列:

  • 计算 Wk_bal = (BALANCE / AVG_SALES)
  • 按供应商id-productid 组对 Wk_bal 进行排名
  • 组的最低 Wk_bal:SEND_PKGS = +1
  • 然后再次计算 Wk_bal,但添加 pkg sent = ((BALANCE+SEND_PKGS) / AVG_SALES)
  • 如此循环,直到所有 TO_SHIP 都已分发给最需要的商店

可视化运行:

第一个输出(计算wk_bal,然后发送1 pkg到最低):

SUPPLIER   PRODUCTID   STOREID   BALANCE   AVG_SALES   TO_SHIP   Wk_Bal     SEND_PKGS
SUP1       P1          STR1      50        5           18        10         0           
SUP1       P1          STR2      6         4           18        1.5        1
SUP1       P1          STR3      8         4           18        2          0
SUP2       P4          STR1      35        3           500       11.67      0
SUP2       P4          STR2      5         4           500       1.25       1
SUP2       P4          STR3      54        7           500       7.71       0

第二个输出(计算更新的wk_bal,发送一个 pkg到最低):

SUPPLIER   PRODUCTID   STOREID   BALANCE   AVG_SALES   TO_SHIP   Wk_Bal     SEND_PKGS 
SUP1       P1          STR1      50        5           17        10         0           
SUP1       P1          STR2      8         4           17        1.75       2
SUP1       P1          STR3      8         4           17        2          0
SUP2       P4          STR1      35        3           499       11.67      0
SUP2       P4          STR2      7         4           499       1.5        2
SUP2       P4          STR3      54        7           499       7.71       0

以此类推……直到剩下 to_ship 为止,计算-排名-给一个 pkg。这个过程的原因是我想确保 wk_balance 最低的商店首先拿到包。 (还有很多其他原因)

我最初是在 SQL 上构建的,但由于复杂性,我转向了 python。不幸的是,我的 python 在提出具有多个条件的循环方面并不是很好,尤其是在 pandas df 上。到目前为止,我已经尝试过(但失败了):

df['Wk_Bal'] = 0
df['TO_SHIP'] = 0

for i in df.groupby(["SUPPLIER", "PRODUCTID"])['TO_SHIP']:
    if i > 0:
          df['Wk_Bal'] = df['BALANCE'] / df['AVG_SALES']
          df['TO_SHIP'] = df.groupby(["SUPPLIER", "PRODUCTID"])['TO_SHIP']-1
          df['SEND_PKGS'] = + 1
          df['BALANCE'] = + 1
    else:
         df['TO_SHIP'] = 0

我怎样才能做得更好?

【问题讨论】:

    标签: python pandas loops if-statement iteration


    【解决方案1】:

    希望我已了解您的所有要求。这是您的原始数据:

    df = pd.DataFrame({'SUPPLIER': ['SUP1', 'SUP1', 'SUP1', 'SUP2', 'SUP2', 'SUP2'],
              'PRODUCTID': ['P1', 'P1', 'P1', 'P4', 'P4', 'P4'],
              'STOREID': ['STR1', 'STR2', 'STR3', 'STR1', 'STR2', 'STR3'],
              'BALANCE': [50, 6, 74, 35, 5, 54],
              'AVG_SALES': [5, 4, 4, 3, 4, 7],
              'TO_SHIP': [18, 18, 18, 500, 500, 500]})
    

    这是我的方法:

    df['SEND_PKGS'] = 0
    df['Wk_bal'] = df['BALANCE'] / df['AVG_SALES']
      
    while (df['TO_SHIP'] != 0).any():
      lowest_idx = df[df['TO_SHIP'] > 0].groupby(["SUPPLIER", "PRODUCTID"])['Wk_bal'].idxmin()
      df.loc[lowest_idx, 'SEND_PKGS'] += 1
      df['Wk_bal'] = (df['BALANCE'] + df['SEND_PKGS']) / df['AVG_SALES']
      df.loc[df['TO_SHIP'] > 0, 'TO_SHIP'] -= 1
    

    我继续更新df,直到TO_SHIP 列全为零。然后我增加SEND_PKGS,它对应于每组中最低的Wk_bal。然后更新 Wk_bal 并减少任何非零的 TO_SHIP 列。

    我最终得到:

        SUPPLIER    PRODUCTID   STOREID BALANCE AVG_SALES   TO_SHIP SEND_PKGS   Wk_bal
    0   SUP1        P1          STR1    50      5           0          0            10.000000
    1   SUP1        P1          STR2    6       4           0         18            6.000000
    2   SUP1        P1          STR3    74      4           0          0            18.500000
    3   SUP2        P4          STR1    35      3           0         92            42.333333
    4   SUP2        P4          STR2    5       4           0        165            42.500000
    5   SUP2        P4          STR3    54      7           0        243            42.428571
    

    编辑:在有多个Wk_bal最小值的情况下,我们可以根据AVG_SALES的最小值进行选择:

    def find_min(x):
      num_mins = x["Wk_bal"].loc[x["Wk_bal"] == x["Wk_bal"].min()].shape[0]
      if num_mins == 1:
        return(x["Wk_bal"].idxmin())
      else:
        min_df = x.loc[x["Wk_bal"] == x["Wk_bal"].min()]
      return(min_df["AVG_SALES"].idxmin())
    

    然后,或多或少和以前一样:

    df['SEND_PKGS'] = 0
    df['Wk_bal'] = df['BALANCE'] / df['AVG_SALES']
    
    while (df['TO_SHIP'] != 0).any():
      lowest_idx = df[df['TO_SHIP'] > 0].groupby(["SUPPLIER", "PRODUCTID"])[['Wk_bal', 'AVG_SALES']].apply(find_min)
      df.loc[lowest_idx, 'SEND_PKGS'] += 1
      df['Wk_bal'] = (df['BALANCE'] + df['SEND_PKGS']) / df['AVG_SALES']
      df.loc[df['TO_SHIP'] > 0, 'TO_SHIP'] -= 1
    

    【讨论】:

    • 现在我看到你已经在这里问过这个问题stackoverflow.com/q/69966974/3763302
    • 你如何在这种方法中处理类似的 Wk_bal ?只是想知道你会怎么做。
    • 所以现在,它正在查看 Wk_bal 我在想如果两者相似,我将查看 AVG Sales。但不知道如何注入。
    • 是的,如果Wk_bal 的最小值不止一个,那么idxmin 将返回最小值第一次出现的索引,因此最小值行中的哪一个将是任意的递增。如果您想选择AVG_SALES,请查看更新的答案
    猜你喜欢
    • 2021-10-18
    • 2019-06-07
    • 2021-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-30
    相关资源
    最近更新 更多