簡體   English   中英

按其他數據框列過濾熊貓行

[英]filter pandas rows by other dataframe columns

我有3個dataframes p_id已經按日期和p_id排序,沒有null值,如:

第一個數據框

df1 = pd.DataFrame([['2018-07-05',8.0,1],
                    ['2018-07-15',1.0,1],
                    ['2018-08-05',2.0,1],
                    ['2018-08-05',2.0,2]],
      columns=["purchase_date", "qty", "p_id"])

第二個DataFrame

df2 = pd.DataFrame([['2018-07-15',2.0,1],
                    ['2018-08-04',7.0,1],
                    ['2018-08-15',1.0,2]], 
      columns=["sell_date", "qty", "p_id"])

第三數據框

df3 = pd.DataFrame([['2018-07-25',1.0,1],
                    ['2018-08-15',1.0,1]],
      columns=["expired_date", "qty", "p_id"])

dataframe看起來像:

第一名:( 持有購買詳情)

    purchase_date   qty     p_id
0   2018-07-05      8.0     1
1   2018-07-15      1.0     1
2   2018-08-05      2.0     1
3   2018-08-05      2.0     2

第二名:( 持有銷售明細)

    sell_date   qty    p_id
0   2018-07-15  2.0    1
1   2018-08-04  7.0    1
2   2018-08-15  1.0    2

第三名:( 保留有效期的詳細信息)

    expired_date    qty   p_id
0   2018-07-25      1.0   1
1   2018-08-15      1.0   1

現在,我想做的是查找已過期產品的購買時間
以下FIFO (先購買的產品將先失效)


說明:考慮ID為1的產品

截止日期2018-07-15

我們有8 + 1的購買數量和-2的銷售數量,即庫存中總共有8 + 1-2數量, -ve符號表示數量扣減

截止日期2018-07-25

1個數量已過期,因此新的when_product_expired dataframe when_product_expired第一個條目將為:

purchase_date     expired_date    p_id
2018-07-05        2018-07-25      1


然后用於下一個到期條目

截止日期2018-08-04

已售完7個數量,所以當前數量為8 + 1-2-7 = 0

截止日期2018-08-05

購買了2個數量,所以當前數量為0 + 2

截止日期2018-08-15

1個數量已過期

因此,新的最終條目將是:

purchase_date     expired_date    p_id
2018-07-05        2018-07-25      1
2018-08-05        2018-08-15      1

這次產品過期是在2018-07-25購買的產品

實際上我有約會時間,所以買賣時間永遠不會相等(您可能會假設),而且在買賣和到期之前,總會有一定數量的庫存產品,即數據是一致的
並預先感謝您:-)

更新

我現在想的是將所有日期字段重命名為相同的字段名稱,並在購買,出售,過期的dataframe框后加上負號,但這對我沒有幫助

df2.qty = df2.qty*-1
df3.qty=df3.qty*-1
new = pd.concat([df1,df2, df3],sort=False)
      .sort_values(by=["purchase_date"],ascending=True)
      .reset_index(drop=True)

您本質上想要的是此FIFO庫存清單。 以我的經驗,大熊貓不是將不同行彼此關聯的正確工具。 工作流程應為“拆分應用”組合。 如果您將其拆分,卻沒有真正找到將其重新拼合的方法,則可能是一個格式錯誤的問題。 您仍然可以通過groupby來完成很多工作,但這是我不會嘗試通過一些巧妙的熊貓技巧來解決的。 即使您使它起作用,也很難維護。

我不知道您的問題對性能有多重要(即您的數據框有多大)。 如果只有10000個條目,則可以顯式循環遍歷熊貓行(警告:這很慢),並手動構建fifo列表。

我為此整理了一些代碼。 您建議的DateFrame在其中。 我遍歷所有行,並記賬有多少庫存。 這在隊列q完成,隊列q中包含每個項目的元素,並且該元素方便地是purchase_date。

import queue

import pandas as pd

from pandas import Series, DataFrame

# modified (see text)
df1 = pd.DataFrame([['2018-07-05',8.0,1],
                    ['2018-07-15',3.0,1],
                    ['2018-08-05',2.0,1],
                    ['2018-08-05',2.0,2]],
      columns=["purchase_date", "qty", "p_id"])

df2 = pd.DataFrame([['2018-07-15',2.0,1],
                    ['2018-08-04',7.0,1],
                    ['2018-08-15',1.0,2]], 
      columns=["sell_date", "qty", "p_id"])

df3 = pd.DataFrame([['2018-07-25',1.0,1],
                    ['2018-08-15',1.0,1]],
      columns=["expired_date", "qty", "p_id"])


df1 = df1.rename(columns={'purchase_date':'date'})

df2 = df2.rename(columns={'sell_date':'date'})

df3 = df3.rename(columns={'expired_date' : 'date'})

df3['qty'] *= -1

df2['qty'] *= -1

df = pd.concat([df1,df2])\
      .sort_values(by=["date"],ascending=True)\
      .reset_index(drop=True)

# Necessary to distinguish between sold and expried items while looping
df['expired'] = False
df3['expired'] = True

df = pd.concat([df,df3])\
      .sort_values(by=["date"],ascending=True)\
      .reset_index(drop=True)

#date  qty  p_id  expired
#7-05  8.0     1    False
#7-15  1.0     1    False
#7-15 -2.0     1    False
#7-25 -1.0     1     True
#8-04 -7.0     1    False
#8-05  2.0     1    False
#8-05  2.0     2    False
#8-15 -1.0     2    False
#8-15 -1.0     1     True

# Iteratively build up when_product_expired
when_product_expired = []

# p_id hardcoded here
p_id = 1

# q contains purchase dates for all individual items 'currently' in stock
q = queue.Queue()

for index, row in df[df['p_id'] == p_id].iterrows():
    # if items are bought, put as many as 'qty' into q
    if row['qty'] > 0:
        for tmp in range(int(round(row['qty']))):
            date = row['date']
            q.put(date)
    # if items are sold or expired, remove as many from q. 
    # if expired additionaly save purchase and expiration date into when_product_expired
    elif row['qty'] < 0:
        for tmp in range(int(round(-row['qty']))):
            purchase_date = q.get()
            if row['expired']:
                print 'item p_id 1 was bought on', purchase_date
                when_product_expired.append([purchase_date, row['date'], p_id])

when_product_expired = DataFrame(when_product_expired, columns=['purchase_date', 'expired_date', 'p_id'])

幾點評論:

  • 我依靠你的保證人

    在銷售和到期之前,總會有一定數量的產品庫存

    您的示例DataFrames沒有給出此信息。 在2018-07-25之前,有9個項目的p_id 1已購買且9被出售。 沒有什么庫存可以過期。 我修改了df1,以便購買了11件。

  • 如果違反此假設,則Queue將嘗試獲取不存在的項目。 在我的機器上,這導致無休止的循環。 您可能想捕獲異常。
  • 隊列的執行效率最低。 如果庫存很多,數據量將增加一倍。
  • 您可以通過將所有內容放入函數和.groupby('p_id').apply(function)或在df['p_id'].unique()循環將其推廣到更多p_id df['p_id'].unique()

因此,盡管這不是可擴展的解決方案,但我希望它能對您有所幫助。 好看

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM