如何根据 df1 中的日期在 df2 中跨两列的日期范围值之间查找单独数据框 (df2) 中的数据

How to look up data in a separate dataframe (df2) based on date in df1 falling between date range values across two columns in df2

情况: 我有两个数据框 df1 和 df2,其中 df1 有一个基于天的日期时间索引,df2 有两个日期列 'wk start' 和 'wk end' 是每周范围以及一个数据列 'statistic'存储对应于周范围的数据。

我想做的事情: 在 df1 中添加 'statistic' 的列,由此我查找每个日期(每天,即每一行)并尝试根据该日期所在的星期找到相应的 'statistic'。

我认为答案需要将 df2 合并到 df1 中,但我不知道之后如何进行。

感谢您提供的任何帮助!谢谢!

df1:(注意:我跳过了 2019-06-12 和 2019-06-16 之间的行以保持示例简短。)

年龄
日期
2019-06-10 20
2019-06-11 21
2019-06-17 19
2019-06-18 18

df2:

周开始 周结束 统计数据
2019-06-10 2019-06-14 102
2019-06-17 2019-06-21 100
2019-06-24 2019-06-28 547
2019-07-02 2019-07-25 268

期望的输出:

年龄 统计数据
日期 :--- :--------
2019-06-10 20 102
2019-06-11 21 102
2019-06-17 19 100
2019-06-18 18 100

数据帧 d1 和 d2 的代码

import pandas as pd

import datetime

data1 = {'date': ['2019-06-10', '2019-06-11', '2019-06-17', '2019-06-18'], 'age': [20, 21, 19, 18]}

data1['date']=pd.to_datetime(data1['date'])

df1 = pd.DataFrame(data1)

df1.set_index('date', inplace=True)

data2 = {'wk start': ['2019-06-10', '2019-06-17', '2019-06-24', '2019-07-02'], 'wk end':[ '2019-06-14', '2019-06-21', '2019-06-28', '2019-07-05'], 'height': [120,121, 119, 118]}

data2['wk start']=pd.to_datetime(data2['wk start'])

data2['wk end']=pd.to_datetime(data2['wk end'])

df2 = pd.DataFrame(data2)

您可以循环遍历数据帧并在进行时对第二个数据帧进行子集化。

import pandas as pd

import datetime

data1 = {'date': ['2019-06-10', '2019-06-11', '2019-06-17', '2019-06-18'], 'age': [20, 21, 19, 18]}

data1['date']=pd.to_datetime(data1['date'])

df1 = pd.DataFrame(data1)

df1.set_index('date', inplace=True)

data2 = {'wk start': ['2019-06-10', '2019-06-17', '2019-06-24', '2019-07-02'], 'wk end':[ '2019-06-14', '2019-06-21', '2019-06-28', '2019-07-05'], 'height': [120,121, 119, 118]}

data2['wk start']=pd.to_datetime(data2['wk start'])

data2['wk end']=pd.to_datetime(data2['wk end'])

df2 = pd.DataFrame(data2)

# Loop
list1 = []
for row in df1.iterrows():
    subdf = df2[(df2['wk start'] <= index) & (df2['wk end'] >= index)]
    list1.append(subdf['height'].tolist()[0])
df1['height'] = list1
print(df1)

这些值与您上面显示的table(统计值)有点不同,因为您提供的代码具有不同的值和高度而不是统计值,但原理是相同的。

df[df.some_date.between(start_date, end_date)] 你可以像这样在日期列上使用 isin 方法 df[df[“日期”].isin(pd.date_range(start_date, end_date))] 按照这个 看看这个 Assign values in one dataframe if date is in date range in another dataframe and projects are equal

您可以先reset_index() on df1 to get the date row index back to data column. Then, cross join df1 and df2 by .merge() with how='cross' and then filter the result by date field is between wk start and wk end using .between(),如下;

df_merge = df1.reset_index().merge(df2, how='cross')   
df_out = df_merge[df_merge['date'].between(df_merge['wk start'], df_merge['wk end'])]

或者,如果您的 Pandas 版本小于 1.2.0(2020 年 12 月发布)

df_merge = df1.reset_index().assign(key=1).merge(df2.assign(key=1), on='key').drop('key', axis=1) 
df_out = df_merge[df_merge['date'].between(df_merge['wk start'], df_merge['wk end'])]

结果:

print(df_out)


         date  age   wk start     wk end  height
0  2019-06-10   20 2019-06-10 2019-06-14     120
4  2019-06-11   21 2019-06-10 2019-06-14     120
9  2019-06-17   19 2019-06-17 2019-06-21     121
13 2019-06-18   18 2019-06-17 2019-06-21     121

您可以进一步删除 2 列 wk start wk end 并将列 date 设置为索引:

df_out = df_out.drop(['wk start', 'wk end'], axis=1).set_index('date')

结果:

print(df_out)

            age  height
date                   
2019-06-10   20     120
2019-06-11   21     120
2019-06-17   19     121
2019-06-18   18     121

笛卡尔积通常很快(如果数据不是那么大),但也会消耗大量内存(在某些情况下效率很低);另一种选择是 intervalIndex :

interval_index = pd.IntervalIndex.from_tuples([*zip(df2['wk start'], df2['wk end'])])

index_position = interval_index.get_indexer(df1.index)

df1.assign(statistic = df2.height[index_position].array)

            age  statistic
date                      
2019-06-10   20        120
2019-06-11   21        120
2019-06-17   19        121
2019-06-18   18        121