【问题标题】:What is the most efficient way to create inventory history创建库存历史记录的最有效方法是什么
【发布时间】:2019-08-14 13:54:02
【问题描述】:

我正在尝试获取一年中每一天的库存汽车数量,以及该日期每辆车的库存天数。

我有完整的移动历史记录(每辆车进出库存的时间戳 - 出租、出售、维修等)。像这样:

car             in          out        status_id    operation
PZR4010 08/02/2018 08:55    08/02/2018 16:29    12  out_stock
QRX0502 07/02/2018 09:00    07/02/2018 10:28    7   in_stock
PYR8269 06/02/2018 17:10    09/02/2018 21:22    12  in_stock
QRG6455 06/02/2018 12:39                        8   sold
QRU1867 08/02/2018 08:00    09/02/2018 11:07    12  in_stock
PZR8528 06/02/2018 17:51    07/02/2018 07:46    10  out_stock
PZR7184 06/02/2018 16:00    08/02/2018 12:10    7   in_stock
PZR0386 08/02/2018 09:02    14/02/2018 14:53    10  out_stock
PZR8600 06/02/2018 16:00    07/02/2018 07:34    7   in_stock
PZR1787 06/02/2018 17:02    20/02/2018 17:33    12  in_stock

因此,对于每辆车,我必须加入它的整个连续库存时间,以了解它处于该状态的时间。

例如:

car     in                 out          status_id   operation
QRX0502 08/02/2018 08:55    09/02/2018 16:29    7   in_stock
QRX0502 07/02/2018 09:00    08/02/2018 08:55    7   in_stock
QRX0502 06/02/2018 17:10    07/02/2018 09:00    7   in_stock

将变得简单:

car          in                 out            status_id    operation
QRX0502 06/02/2018 17:10    09/02/2018 16:29    7   in_stock

捕获“in”列中的最小时间戳和“out”列中的最大时间戳。

我尝试过使用 groupby + shift:

#'mov' is the dataframe with all the stock movements
# I create a columns to better filter on the groupby

mov['aux']=mov['car']+" - "+mov['operation']

#creating the base dataframe to be the output

hist_mov=pd.DataFrame(columns=list(mov.columns))

for line, operation in mov.groupby(mov['aux'].ne(mov['aux'].shift()).cumsum()):
    g_temp=operation.groupby(['car','operation',
        'aux']).agg({'in':'min','out':'max'}).reset_index()
    hist_mov=hist_mov.append(g_temp,sort=True)

问题是整个数据库运行大约需要 16 个小时,而且我必须每天运行它来更新库存状态。

我想构建类似的东西:

添加到历史记录的每一行都会检查它是否与我的新基础 (hist_mov) 中的任何一行连续。如果是这样,请更新该行。如果没有,请添加为新行。

有什么想法吗?谢谢!

【问题讨论】:

    标签: python pandas pandas-groupby


    【解决方案1】:

    我认为这样的事情可能是你所追求的:

    cols = ["car", "operation"]
    pd.merge(df.groupby(cols)["in"].min().reset_index(), 
             df.groupby(cols)["out"].max().reset_index(), on=cols, how="outer")
    

    编辑:

    希望这可以缓解 cmets 中概述的问题,使用 trans_id 列来识别汽车进出的单独实例:

    df['trans_id'] = df['operation'].ne(df['operation'].shift()).astype(int) + df.index
    cols = ["car", "trans_id", "operation"]
    df_grouped = pd.merge(df.groupby(cols)["in"].min().reset_index(), 
             df.groupby(cols)["out"].max().reset_index(), on=cols, how="outer")
    df_grouped.drop('trans_id', axis=1, inplace=True)
    df_grouped
    

    【讨论】:

    • status_id 在这一点上并不重要。仅用于确定操作。合并解决方案不起作用,因为汽车可能有很长时间的库存,然后缺货,然后有库存,等等。我想捕捉整个动作。使用此解决方案,每辆车将只有一行“in_stock”和一行“out_stock”。感谢您的帮助!
    • 不幸的是它没有。我认为它仍然需要循环,因为一个 in_stock 可以链接到另一个,然后另一个等等,直到我找到每辆车在每个状态下的最大连续间隔
    • @您如何知道一个 in_stock 是否与另一个相关联?
    • 如果时间戳输出等于其他行的时间戳输入: 所以这里:car in out status_id operation QRX0502 08/02/2018 08:55 09/02/2018 16:29 7 in_stock QRX0502 07 /02/2018 09:00 08/02/2018 08:55 7 in_stock QRX0502 06/02/2018 17:10 07/02/2018 09:00 7 in_stock 我知道从 06/02 到 09 有货/02 因为时间戳正在形成一个序列:“out”等于以下“in”(并且仍然具有 in_stock 状态)。如果是 out_stock 在它应该打破链接
    • 我无法在此处粘贴为表格,但我在“所以,例如:....”上使用了相同的问题示例,直到“将变得简单”
    【解决方案2】:

    我找到了答案!

    我第一次发布的代码几乎是正确的,但它有一个不必要的循环。

    1- 首先我按汽车和状态变化数据对项目进行排序:

        mov=mov.sort_values(['car','in'],ascending=False)
    

    2- 然后我开车和操作集群:

        mov['aux']=mov['car']+" - "+mov['operation']
        mov['cluster']=(mov.aux != mov.aux.shift()).cumsum()
    

    3- 最后我可以按这个集群 ID 分组,并获得最小“输入”值和最大“输出”值:

        hist_mov=mov.groupby(['cluster','car','operation']).agg({'in':'min',
              'out':'max'}).reset_index().copy()
    

    【讨论】:

      猜你喜欢
      • 2021-04-24
      • 1970-01-01
      • 2018-06-16
      • 2011-02-07
      • 1970-01-01
      • 1970-01-01
      • 2010-12-17
      • 2016-03-09
      • 1970-01-01
      相关资源
      最近更新 更多