[英]In Python left merge of data with date-intervals
我有两个数据date_to
,每个数据date_to
包含一个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
的最小值作为新的date_to
进行这两个表的内部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
获取数据。 基本上我想要这个结果
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
。
感谢所有帮助。 谢谢。
在联接并添加了date_from和date_to变量之后,一条简单的行“模拟”您想要的联接类型便具有所需的效果:
df.loc[(df['date_from']<df['date_to']), 'data_b'] = np.NaN
这是说“ date_from小于date_to时 ,请将data_b设置为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']]
让我知道这是否无法达到预期的效果!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.