在Python中,将数据与日期间隔合并

时间:2017-08-27 08:57:09

标签: python pandas dataframe merge left-join

我有两个数据框,每个数据框包含一个date_from和一个date_to,表示数据的有效时间间隔,还有一个id,表示哪些数据属于一起。

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的最小值作为新{{{}来对这两个表进行内部联接1}},并且只关注那些date_to的条目,我以正确的间隔得到想要的结果。

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

我也无法使用普通的sql生成此结果。我所知道的一个可能的解决方案是在数据之前和之后使用空间隔“填充” 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 。但这有其自身的问题,所以我想避免篡改df_b

感谢所有帮助。谢谢。

1 个答案:

答案 0 :(得分:0)

在加入并添加 date_from date_to 变量后,可以使用一条简单的线条来模拟&#39;你之后加入的那种具有预期效果的那种:

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

它说&#34; date_from 小于 date_to ,将 data_b 设置为null&#34;。

然后,删除最后一行中的约束,该约束删除其中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']]

如果这不能产生预期的结果,请告诉我!