【问题标题】:Grouping By and Referencing Shifted Values分组依据和引用移位值
【发布时间】:2018-10-09 08:51:51
【问题描述】:

我正在尝试随着时间的推移跟踪单个商品的库存水平 比较预计的出站和可用性。有时间在 预计出站超过可用性以及何时 发生我希望Post Available 为 0。我正在尝试创建 Pre AvailablePost Available 列如下:

 Item  Week  Inbound  Outbound  Pre Available  Post Available 
 A        1      500       200            500             300 
 A        2        0       400            300               0 
 A        3      100         0            100             100 
 B        1       50        50             50               0 
 B        2        0        80              0               0 
 B        3        0        20              0               0 
 B        4       20        20             20               0 

我试过下面的代码:

def custsum(x):

      total = 0
      for i, v in x.iterrows():
         total += df['Inbound'] - df['Outbound']
         x.loc[i, 'Post Available'] = total
         if total < 0:
            total = 0
      return x

df.groupby('Item').apply(custsum)

但我收到以下错误消息:

ValueError: Incompatible indexer with Series

我是 Python 的相对新手,因此我们将不胜感激。 谢谢!

【问题讨论】:

  • 请复制并粘贴Data Set Mockup as text,以便我们轻松复制您的DataFrame。
  • 如何添加为文本?当我尝试这样做时,这些信息看起来很奇怪
  • tem 周 入站 出站 预可用 后可用 A 1 500 200 500 300 A 2 0 400 300 0 A 3 100 0 100 0 B 1 50 50 50 0 B 2 0 80 0 0 B 3 0 20 0 0 B 4 20 20 20 0
  • @Charles 添加到您的问题类型编辑中
  • Pre Available 应该是前一周发布可用 + 当前行的入站。我还想确保 Post Available 的最小值永远不会低于 0。谢谢!

标签: python pandas methods cumulative-sum


【解决方案1】:

不需要自定义函数,可以使用groupby+shift创建PreAvailable,使用clip(设置下边界为0)创建PostAvailable

df['PostAvailable']=(df.Inbound-df.Outbound).clip(lower=0)
df['PreAvailable']=df.groupby('item').apply(lambda x  : x['Inbound'].add(x['PostAvailable'].shift(),fill_value=0)).values
df
Out[213]: 
  item  Week  Inbound  Outbound  PreAvailable  PostAvailable
0    A     1      500       200         500.0            300
1    A     2        0       400         300.0              0
2    A     3      100         0         100.0            100
3    B     1       50        50          50.0              0
4    B     2        0        80           0.0              0
5    B     3        0        20           0.0              0
6    B     4       20        20          20.0              0

【讨论】:

    【解决方案2】:

    你可以使用

    import numpy as np
    import pandas as pd
    df = pd.DataFrame({'Inbound': [500, 0, 100, 50, 0, 0, 20],
                       'Item': ['A', 'A', 'A', 'B', 'B', 'B', 'B'],
                       'Outbound': [200, 400, 0, 50, 80, 20, 20],
                       'Week': [1, 2, 3, 1, 2, 3, 4]})
    df = df[['Item', 'Week', 'Inbound', 'Outbound']]
    
    
    def custsum(x):
        total = 0
        for i, v in x.iterrows():
            total += x.loc[i, 'Inbound'] - x.loc[i, 'Outbound']
            if total < 0:
                total = 0
            x.loc[i, 'Post Available'] = total
        x['Pre Available'] = x['Post Available'].shift(1).fillna(0) + x['Inbound']
        return x
    
    result = df.groupby('Item').apply(custsum)
    result = result[['Item', 'Week', 'Inbound', 'Outbound', 'Pre Available', 'Post Available']]
    print(result)
    

    产生

      Item  Week  Inbound  Outbound  Pre Available  Post Available
    0    A     1      500       200          500.0           300.0
    1    A     2        0       400          300.0             0.0
    2    A     3      100         0          100.0           100.0
    3    B     1       50        50           50.0             0.0
    4    B     2        0        80            0.0             0.0
    5    B     3        0        20            0.0             0.0
    6    B     4       20        20           20.0             0.0
    

    此代码与您发布的代码的主要区别在于:

    total += x.loc[i, 'Inbound'] - x.loc[i, 'Outbound']
    

    x.loc 用于选择由i 索引的行中的numeric 值和 InboundOutbound 列。所以区别是数字和total 仍然是数字。相比之下,

    total += df['Inbound'] - df['Outbound']
    

    将整个系列添加到total。这导致后来的ValueError。 (有关发生这种情况的更多信息,请参见下文)。


    条件式

    if total < 0:
        total = 0
    

    已移至 x.loc[i, 'Post Available'] = total 上方,以确保 Post Available 始终为非负数。

    如果你不需要这个条件,那么整个for-loop可以被替换为

    x['Post Available'] = (df['Inbound'] - df.loc['Outbound']).cumsum()
    

    由于按列算术和cumsum 是矢量化操作,因此计算可以更快地执行。 不幸的是,条件使我们无法消除 for-loop 并将计算向量化。


    在您的原始代码中,错误

    ValueError: Incompatible indexer with Series
    

    出现在这一行

    x.loc[i, 'Post Available'] = total
    

    因为total(有时)是一个系列而不是一个简单的数值。熊猫是 试图将右侧的系列与左侧的索引器(i, 'Post Available') 对齐。索引器(i, 'Post Available') 获取 转换为像 (0, 4) 这样的元组,因为 Post Available 是位于 索引 4。但(0, 4) 不是一维系列的合适索引 在右手边。

    您可以通过将print(total) 放入您的for-loop 中来确认total 是系列, 或注意到

    的右侧
    total += df['Inbound'] - df['Outbound']
    

    是一个系列。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-28
      • 1970-01-01
      • 2020-04-28
      • 1970-01-01
      • 1970-01-01
      • 2020-07-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多