2017-08-27 27 views
0

我有兩個數據幀,每個數據幀包含一個date_fromdate_to(指示數據的有效時間間隔),以及一個id(指示哪些數據屬於一起)。在Python中,數據與日期間隔合併

from datetime import datetime 
import pandas as pd 
import numpy as np 

df_a = pd.DataFrame({'id' : [1, 1, 1, 1, 2], 
        'date_from' : [datetime(2012, 1, 1), datetime(2012, 6, 1), 
            datetime(2013, 1, 1), datetime(2013, 6, 1), 
            datetime(2012, 1, 1)], 
        'date_to' : [datetime(2012, 6, 1), datetime(2013, 1, 1), 
            datetime(2013, 6, 1), datetime(2014, 1, 1), 
            datetime(2013, 1, 1)], 
        'data_a' : [1, 2, 3, 4, 5]}) 

df_b = pd.DataFrame({'id' : [1, 1], 
        'date_from' : [datetime(2012, 8, 1), datetime(2013, 4,1)], 
        'date_to' : [datetime(2013, 4,1), datetime(2013, 8, 1)], 
        'data_b' :['A','B']}) 

如果我做一個內部聯接使用date_from的最大的爲新date_from和最小的date_to的「爲新date_to這幫兩個表,並kepping只有那些條目,其中date_from < date_to,我以正確的時間間隔得到想要的結果。

df = pd.merge(df_a, df_b, suffixes=['_a','_b'],on='id', how='inner') 
df['date_from'] = df[['date_from_a', 'date_from_b']].max(axis=1) 
df['date_to'] = df[['date_to_a', 'date_to_b']].min(axis=1) 
df[['id', 'date_from', 'date_to', 'data_a','data_b']][(df['date_from']<df['date_to'])] 

Out[2]: 
    id date_from date_to data_a data_b 
2 1 2012-08-01 2013-01-01  2  A 
4 1 2013-01-01 2013-04-01  3  A 
5 1 2013-04-01 2013-06-01  3  B 
7 1 2013-06-01 2013-08-01  4  B 

萬歲!

但是,現在來了困難的部分,我不是真的想要一個內部連接,我想要一個左連接。重複上述步驟,左合併我得到

df = pd.merge(df_a, df_b, suffixes=['_a','_b'],on='id', how='left') 
df['date_from'] = df[['date_from_a', 'date_from_b']].max(axis=1) 
df['date_to'] = df[['date_to_a', 'date_to_b']].min(axis=1) 
df[['id', 'date_from', 'date_to', 'data_a','data_b']][(df['date_from']<df['date_to'])] 
Out[3]: 
    id date_from date_to data_a data_b 
2 1 2012-08-01 2013-01-01  2  A 
4 1 2013-01-01 2013-04-01  3  A 
5 1 2013-04-01 2013-06-01  3  B 
7 1 2013-06-01 2013-08-01  4  B 
8 2 2012-01-01 2013-01-01  5 NaN 

有什麼不對的這幅畫你說......好了的事情是我想從df_a有還的情況下的數據,其中有沒有重疊的區間。基本上我想要這個結果

id date_from date_to data_a data_b 
0 1 2012-01-01 2012-06-01  1 NaN 
1 1 2012-06-01 2012-08-01  2 NaN 
2 1 2012-08-01 2013-01-01  2  A 
3 1 2013-01-01 2013-04-01  3  A 
4 1 2013-04-01 2013-06-01  3  B 
5 1 2013-06-01 2013-08-01  4  B 
6 1 2013-08-01 2014-01-01  4 NaN 
7 2 2012-01-01 2013-01-01  5 NaN 

我不能用普通的sql產生這個結果。我知道的一種可能的解決方案是在數據前後填充df_b空間隔。但這有它自己的問題,所以我想避免篡改df_b

所有幫助表示讚賞。謝謝。

+1

嗨,我想我有一個解決方案,但在發佈之前,你可以確保你的「結果」數據框正確嗎?我認爲你錯過了一個額外的行,其中id == 1和data_b,A和B的位置在索引值3,4,5,6中,當它們應該位於索引位於[0,1, 3,6]。基本上沒有意義的是,在前兩個數據幀中,A和B在行2,4,5和7中,但在結果數據幀中,它們在3,4,5和6. – tompiler

+0

您好!如果你有一個很棒的解決方案! :)不要擔心索引。我只是把東西放在那裏而沒有真正思考。 – mortysporty

回答

0

後,加入和date_fromDATE_TO變量,簡單的線條「模擬」的那種加入你之後有希望的效果的加入:

df.loc[(df['date_from']<df['date_to']), 'data_b'] = np.NaN 

跟它「date_from is less than date_to,set data_b to null」。

然後,刪除最後一行中刪除約束的行,其中id在df_b中沒有公共關鍵字。這是初始化兩個數據集後的最終代碼:

df = pd.merge(df_a, df_b, suffixes=['_a','_b'],on='id', how='left') 
df['date_from'] = df[['date_from_a', 'date_from_b']].max(axis=1) 
df['date_to'] = df[['date_to_a', 'date_to_b']].min(axis=1) 
df.loc[(df['date_from']<df['date_to']), 'data_b'] = np.NaN 
df[['id', 'date_from', 'date_to', 'data_a','data_b']] 

讓我知道如果這不會產生所需的結果!

+0

嗯。我似乎無法得到它的工作...我已經取代了我的所有代碼,除了用你的代碼初始化'df_a'和'df_b'。這並不是我所希望的。不知何故,我認爲我們走在了正確的軌道上,但有一些錯誤......我想。 – mortysporty

+0

運氣好嗎?你能更詳細地瞭解剩下的問題嗎? – tompiler

+0

嗯..沒有運氣。我很抱歉地說你的解決方案根本不會產生我想要的結果:|這就是我粘貼你的代碼'Out [8]: id date_from date_to data_a data_b 0 1 2012-08-01 2012-06-01 1 A 1 1 2013-04-01 2012-06-01 1 B 2 1 2012-08-01 2013-01-01 2 NaN 3 1 2013-04-01 2013-01-01 2 B 4 1 2013-01-01 2013-04-01 3 NaN 5 1 2013 -04-01 2013-06-01 3 NaN 6 1 2013-06-01 2013-04-01 4 A 7 1 2013-06-01 2013-08-01 4 NaN 8 2 2012-01-01 2013 -01-01 5 NaN' – mortysporty