亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

合并數據框并根據開始/結束日期填充空白值

合并數據框并根據開始/結束日期填充空白值

一只萌萌小番薯 2023-09-12 16:45:43
我有 pandas 數據框(df),其開始日期和結束日期為特定值(在本例中為“貨幣”)。我需要將其與另一個數據框 (tbl) 合并,并根據第一個 DF 的開始/結束日期填充空白貨幣行。NULL 意味著沒有結束日期 - 所以一切都在繼續。在這種情況下,2020 年 1 月 11 日之后的所有內容均為美元。來自 SQL 的數據因此為 NULL。df = pd.DataFrame(data={        'port': 'PortA'        'currency': ['USD', 'CAD', 'EUR', 'USD'],        'start_date': ['01/01/2020', '01/04/2020', '01/06/2020', '01/11/2020'],        'end_date': ['01/04/2020', '01/06/2020', '01/11/2020', '01/15/2020']        })df[['start_date', 'end_date']] = df[['start_date', 'end_date']].apply(pd.to_datetime, errors='ignore')tbl = pd.DataFrame(data={        'port': 'PortA',        'as_of_date': [x for x in pd.date_range(start='01/01/2020', end='01/15/2020')]        })這就是我需要的df_merge 是我需要的最終外觀。第二個問題 - 如果我沒有第二個數據框(tbl)要合并怎么辦?有沒有一種簡單的方法來“拆開”現有的 df,使其看起來與 df_merge 相同?謝謝。
查看完整描述

2 回答

?
浮云間

TA貢獻1829條經驗 獲得超4個贊

  1. 首先在數據框中創建一個as_of_datepd.date_range,該列是每行開始日期和結束日期之間的日期列表lambda x:(刪除重復項并保留最后一個)。

  2. 分解 上的數據幀,as_of_date準備在date和上進行合并port

  3. 只需合并數據框(根據您的第二個問題,您可以簡單地排除此步驟)。


第 1 步:創建日期范圍列

df['as_of_date'] = df.apply(lambda x: list(pd.date_range(x['start_date'], x['end_date'], freq='d')), axis=1)

df

Out[1]: 

    port currency start_date   end_date  \

0  PortA      USD 2020-01-01 2020-01-04   

1  PortA      CAD 2020-01-04 2020-01-06   

2  PortA      EUR 2020-01-06 2020-01-11   

3  PortA      USD 2020-01-11 2020-01-15   


                                          as_of_date  

0  [2020-01-01 00:00:00, 2020-01-02 00:00:00, 202...  

1  [2020-01-04 00:00:00, 2020-01-05 00:00:00, 202...  

2  [2020-01-06 00:00:00, 2020-01-07 00:00:00, 202...  

3  [2020-01-11 00:00:00, 2020-01-12 00:00:00, 202...  

第 2 步:分解數據框并刪除重復項


df = df.explode('as_of_date').drop_duplicates('as_of_date', keep='last')

df

Out[2]: 

    port currency start_date   end_date as_of_date

0  PortA      USD 2020-01-01 2020-01-04 2020-01-01

0  PortA      USD 2020-01-01 2020-01-04 2020-01-02

0  PortA      USD 2020-01-01 2020-01-04 2020-01-03

1  PortA      CAD 2020-01-04 2020-01-06 2020-01-04

1  PortA      CAD 2020-01-04 2020-01-06 2020-01-05

2  PortA      EUR 2020-01-06 2020-01-11 2020-01-06

2  PortA      EUR 2020-01-06 2020-01-11 2020-01-07

2  PortA      EUR 2020-01-06 2020-01-11 2020-01-08

2  PortA      EUR 2020-01-06 2020-01-11 2020-01-09

2  PortA      EUR 2020-01-06 2020-01-11 2020-01-10

3  PortA      USD 2020-01-11 2020-01-15 2020-01-11

3  PortA      USD 2020-01-11 2020-01-15 2020-01-12

3  PortA      USD 2020-01-11 2020-01-15 2020-01-13

3  PortA      USD 2020-01-11 2020-01-15 2020-01-14

3  PortA      USD 2020-01-11 2020-01-15 2020-01-15

步驟 3:合并兩個數據框(根據您的第二個問題 - 如果您沒有數據框,您可以忽略此步驟tbl。相反,只需運行df = df[['port', 'as_of_date', 'currency']]以保留并重新排序您需要的列:


df_merge = pd.merge(df[['port', 'currency', 'as_of_date']], tbl, how='left', on=['as_of_date', 'port'])

df_merge

Out[3]: 

     port currency as_of_date

0   PortA      USD 2020-01-01

1   PortA      USD 2020-01-02

2   PortA      USD 2020-01-03

3   PortA      CAD 2020-01-04

4   PortA      CAD 2020-01-05

5   PortA      EUR 2020-01-06

6   PortA      EUR 2020-01-07

7   PortA      EUR 2020-01-08

8   PortA      EUR 2020-01-09

9   PortA      EUR 2020-01-10

10  PortA      USD 2020-01-11

11  PortA      USD 2020-01-12

12  PortA      USD 2020-01-13

13  PortA      USD 2020-01-14

14  PortA      USD 2020-01-15

完整代碼:


df = pd.DataFrame(data={

        'port': ['PortA','PortA','PortA','PortA'],

        'currency': ['USD', 'CAD', 'EUR', 'USD'],

        'start_date': ['01/01/2020', '01/04/2020', '01/06/2020', '01/11/2020'],

        'end_date': ['01/04/2020', '01/06/2020', '01/11/2020', '01/15/2020']

        })

df[['start_date', 'end_date']] = df[['start_date', 'end_date']].apply(pd.to_datetime, errors='ignore')

tbl = pd.DataFrame(data={

        'port': 'PortA',

        'as_of_date': [x for x in pd.date_range(start='01/01/2020', end='01/15/2020')]

        })

df['as_of_date'] = df.apply(lambda x: list(pd.date_range(x['start_date'], x['end_date'], freq='d')), axis=1)

df = df.explode('as_of_date').drop_duplicates('as_of_date', keep='last')

df_merge = pd.merge(df[['port', 'currency', 'as_of_date']], tbl, how='left', on=['as_of_date', 'port'])

df_merge


查看完整回答
反對 回復 2023-09-12
?
慕萊塢森

TA貢獻1810條經驗 獲得超4個贊

pd.date_range您可以使用,explode和這樣做merge:


df_dates = df.assign(dates=[pd.date_range(i, j + pd.Timedelta(days=-1), freq='D') 

                             for i, j in zip(df['start_date'], df['end_date'])])\

             .explode('dates')


bl.merge(df_dates[['port','dates','currency']], 

         left_on=['port', 'as_of_date'], 

         right_on=['port', 'dates'])

輸出:


     port as_of_date      dates currency

0   PortA 2020-01-01 2020-01-01      USD

1   PortA 2020-01-02 2020-01-02      USD

2   PortA 2020-01-03 2020-01-03      USD

3   PortA 2020-01-04 2020-01-04      CAD

4   PortA 2020-01-05 2020-01-05      CAD

5   PortA 2020-01-06 2020-01-06      EUR

6   PortA 2020-01-07 2020-01-07      EUR

7   PortA 2020-01-08 2020-01-08      EUR

8   PortA 2020-01-09 2020-01-09      EUR

9   PortA 2020-01-10 2020-01-10      EUR

10  PortA 2020-01-11 2020-01-11      USD

11  PortA 2020-01-12 2020-01-12      USD

12  PortA 2020-01-13 2020-01-13      USD

13  PortA 2020-01-14 2020-01-14      USD

注意: pd.Timedelta(days=-1) 處理多行上的重復日期。結束日期與下一行的開始日期重疊。


更改代碼以修復最后日期:


d = pd.Timedelta(days=-1)

l = pd.date_range #To shorten typing

df_dates = df.assign(dates=[l(i, j + d) if j != df.iloc[-1, df.columns.get_loc('end_date')] 

                               else l(i, j) for i, j in zip(df['start_date'], df['end_date'])])\

             .explode('dates')


print(tbl.merge(df_dates[['port','dates','currency']], left_on=['port', 'as_of_date'], right_on=['port', 'dates']))



查看完整回答
反對 回復 2023-09-12
  • 2 回答
  • 0 關注
  • 134 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號