从列表中查找最接近给定日期且不晚于给定日期的日期
Find the closest date from a list to a given date that is not after the given date
我有一个用于每周培训 session 的数据框和一个用于参加者在这些培训 session 中提交的评估的数据框。
每个数据框都有一个日期列 - sessions,它是 session 发生的日期。对于评估,这是提交评估的日期。预计与会者将参加多次 session,因此将提交多次评估。
我需要将每个评估与特定的 session 联系起来。他们可能在 session 的同一天提交了评估,在这种情况下匹配很容易。但他们可以在下一次培训前的任何一天提交评估 session。
对于评估df中的每个日期,我需要return最接近评估日期但不晚于评估日期的session日期。
示例session 日期:
22 年 2 月 3 日、22 年 2 月 10 日、22 年 2 月 17 日
具有所需输出的示例评估日期:
2/3/22(应匹配 2/3/22)、2/4/22(应匹配 2/3/22)、2/11/22(应匹配 2/10/22)
这是一种方法。
在 sessions
数据框中,将 date
列设置为索引:
sessions = sessions.set_index('date')
按索引(即按日期)对会话进行排序:
sessions = sessions.loc[sessions.index.sort_values()]
向评估添加 session_evaluated
列,其中将包含评估适用的会话日期。我们通过首先在评估的 date
列上调用 sessions.index.get_indexer()
并将 method
参数设置为 'pad' 来计算这一点,因此我们在 non-matching 日期“向下舍入”,然后在会话索引(包含会话日期)中查找这些整数索引值:
evaluations['session_evaluated'] = pd.Series([sessions.index.to_list()[i]
for i in sessions.index.get_indexer(evaluations['date'], method='pad')])
下面是它与示例输入放在一起的样子:
import pandas as pd
sessions = pd.DataFrame({
'date' : ['2022-02-01', '2022-03-01', '2022-04-01', '2022-05-01', '2022-01-01'],
'topic' : ['Easy 1', 'Easy 2', 'Intermediate', 'Advanced', 'Intro']
})
evaluations = pd.DataFrame({
'date' : [
'2022-01-05', '2022-01-10', '2022-01-15', '2022-01-20', '2022-01-25',
'2022-02-01', '2022-02-05', '2022-02-28',
'2022-03-01', '2022-03-15', '2022-03-31',
'2022-04-01', '2022-04-15'
],
'rating' : [9,8,7,8,9,5,4,3,10,10,10,2,4]
})
sessions['date'] = pd.to_datetime(sessions['date'])
evaluations['date'] = pd.to_datetime(evaluations['date'])
sessions = sessions.set_index('date')
sessions = sessions.loc[sessions.index.sort_values()]
print(sessions)
print(evaluations)
evaluations['session_evaluated'] = pd.Series([sessions.index.to_list()[i]
for i in sessions.index.get_indexer(evaluations['date'], method='pad')])
print(evaluations)
结果:
topic
date
2022-01-01 Intro
2022-02-01 Easy 1
2022-03-01 Easy 2
2022-04-01 Intermediate
2022-05-01 Advanced
date rating
0 2022-01-05 9
1 2022-01-10 8
2 2022-01-15 7
3 2022-01-20 8
4 2022-01-25 9
5 2022-02-01 5
6 2022-02-05 4
7 2022-02-28 3
8 2022-03-01 10
9 2022-03-15 10
10 2022-03-31 10
11 2022-04-01 2
12 2022-04-15 4
date rating session_evaluated
0 2022-01-05 9 2022-01-01
1 2022-01-10 8 2022-01-01
2 2022-01-15 7 2022-01-01
3 2022-01-20 8 2022-01-01
4 2022-01-25 9 2022-01-01
5 2022-02-01 5 2022-02-01
6 2022-02-05 4 2022-02-01
7 2022-02-28 3 2022-02-01
8 2022-03-01 10 2022-03-01
9 2022-03-15 10 2022-03-01
10 2022-03-31 10 2022-03-01
11 2022-04-01 2 2022-04-01
12 2022-04-15 4 2022-04-01
更新:
这是使用 merge_asof()
函数的另一种方法。它不需要日期列作为索引(尽管它确实要求两个数据框参数都按 date
排序):
sessions['date'] = pd.to_datetime(sessions['date'])
evaluations['date'] = pd.to_datetime(evaluations['date'])
evaluations = pd.merge_asof(
evaluations.sort_values(by=['date']),
sessions.sort_values(by=['date'])['date'].to_frame().assign(session_evaluated=sessions['date']),
on='date')
print(evaluations)
输出:
date rating session_evaluated
0 2022-01-05 9 2022-01-01
1 2022-01-10 8 2022-01-01
2 2022-01-15 7 2022-01-01
3 2022-01-20 8 2022-01-01
4 2022-01-25 9 2022-01-01
5 2022-02-01 5 2022-02-01
6 2022-02-05 4 2022-02-01
7 2022-02-28 3 2022-02-01
8 2022-03-01 10 2022-03-01
9 2022-03-15 10 2022-03-01
10 2022-03-31 10 2022-03-01
11 2022-04-01 2 2022-04-01
12 2022-04-15 4 2022-04-01
更新#2:
上面代码中对 assign()
的调用也可以使用 **kwargs
语法编写,以防我们想要使用带空格的列名或者不是有效的 python 标识符(而是session_evaluated
)。例如:
evaluations = pd.merge_asof(
evaluations.sort_values(by=['date']),
sessions.sort_values(by=['date'])['date'].to_frame()
.assign(**{'Evaluated Session (Date)' : lambda x: sessions['date']}),
on='date')
输出:
date rating Evaluated Session (Date)
0 2022-01-05 9 2022-01-01
1 2022-01-10 8 2022-01-01
2 2022-01-15 7 2022-01-01
3 2022-01-20 8 2022-01-01
4 2022-01-25 9 2022-01-01
5 2022-02-01 5 2022-02-01
6 2022-02-05 4 2022-02-01
7 2022-02-28 3 2022-02-01
8 2022-03-01 10 2022-03-01
9 2022-03-15 10 2022-03-01
10 2022-03-31 10 2022-03-01
11 2022-04-01 2 2022-04-01
12 2022-04-15 4 2022-04-01
我有一个用于每周培训 session 的数据框和一个用于参加者在这些培训 session 中提交的评估的数据框。
每个数据框都有一个日期列 - sessions,它是 session 发生的日期。对于评估,这是提交评估的日期。预计与会者将参加多次 session,因此将提交多次评估。
我需要将每个评估与特定的 session 联系起来。他们可能在 session 的同一天提交了评估,在这种情况下匹配很容易。但他们可以在下一次培训前的任何一天提交评估 session。
对于评估df中的每个日期,我需要return最接近评估日期但不晚于评估日期的session日期。
示例session 日期: 22 年 2 月 3 日、22 年 2 月 10 日、22 年 2 月 17 日
具有所需输出的示例评估日期: 2/3/22(应匹配 2/3/22)、2/4/22(应匹配 2/3/22)、2/11/22(应匹配 2/10/22)
这是一种方法。
在 sessions
数据框中,将 date
列设置为索引:
sessions = sessions.set_index('date')
按索引(即按日期)对会话进行排序:
sessions = sessions.loc[sessions.index.sort_values()]
向评估添加 session_evaluated
列,其中将包含评估适用的会话日期。我们通过首先在评估的 date
列上调用 sessions.index.get_indexer()
并将 method
参数设置为 'pad' 来计算这一点,因此我们在 non-matching 日期“向下舍入”,然后在会话索引(包含会话日期)中查找这些整数索引值:
evaluations['session_evaluated'] = pd.Series([sessions.index.to_list()[i]
for i in sessions.index.get_indexer(evaluations['date'], method='pad')])
下面是它与示例输入放在一起的样子:
import pandas as pd
sessions = pd.DataFrame({
'date' : ['2022-02-01', '2022-03-01', '2022-04-01', '2022-05-01', '2022-01-01'],
'topic' : ['Easy 1', 'Easy 2', 'Intermediate', 'Advanced', 'Intro']
})
evaluations = pd.DataFrame({
'date' : [
'2022-01-05', '2022-01-10', '2022-01-15', '2022-01-20', '2022-01-25',
'2022-02-01', '2022-02-05', '2022-02-28',
'2022-03-01', '2022-03-15', '2022-03-31',
'2022-04-01', '2022-04-15'
],
'rating' : [9,8,7,8,9,5,4,3,10,10,10,2,4]
})
sessions['date'] = pd.to_datetime(sessions['date'])
evaluations['date'] = pd.to_datetime(evaluations['date'])
sessions = sessions.set_index('date')
sessions = sessions.loc[sessions.index.sort_values()]
print(sessions)
print(evaluations)
evaluations['session_evaluated'] = pd.Series([sessions.index.to_list()[i]
for i in sessions.index.get_indexer(evaluations['date'], method='pad')])
print(evaluations)
结果:
topic
date
2022-01-01 Intro
2022-02-01 Easy 1
2022-03-01 Easy 2
2022-04-01 Intermediate
2022-05-01 Advanced
date rating
0 2022-01-05 9
1 2022-01-10 8
2 2022-01-15 7
3 2022-01-20 8
4 2022-01-25 9
5 2022-02-01 5
6 2022-02-05 4
7 2022-02-28 3
8 2022-03-01 10
9 2022-03-15 10
10 2022-03-31 10
11 2022-04-01 2
12 2022-04-15 4
date rating session_evaluated
0 2022-01-05 9 2022-01-01
1 2022-01-10 8 2022-01-01
2 2022-01-15 7 2022-01-01
3 2022-01-20 8 2022-01-01
4 2022-01-25 9 2022-01-01
5 2022-02-01 5 2022-02-01
6 2022-02-05 4 2022-02-01
7 2022-02-28 3 2022-02-01
8 2022-03-01 10 2022-03-01
9 2022-03-15 10 2022-03-01
10 2022-03-31 10 2022-03-01
11 2022-04-01 2 2022-04-01
12 2022-04-15 4 2022-04-01
更新:
这是使用 merge_asof()
函数的另一种方法。它不需要日期列作为索引(尽管它确实要求两个数据框参数都按 date
排序):
sessions['date'] = pd.to_datetime(sessions['date'])
evaluations['date'] = pd.to_datetime(evaluations['date'])
evaluations = pd.merge_asof(
evaluations.sort_values(by=['date']),
sessions.sort_values(by=['date'])['date'].to_frame().assign(session_evaluated=sessions['date']),
on='date')
print(evaluations)
输出:
date rating session_evaluated
0 2022-01-05 9 2022-01-01
1 2022-01-10 8 2022-01-01
2 2022-01-15 7 2022-01-01
3 2022-01-20 8 2022-01-01
4 2022-01-25 9 2022-01-01
5 2022-02-01 5 2022-02-01
6 2022-02-05 4 2022-02-01
7 2022-02-28 3 2022-02-01
8 2022-03-01 10 2022-03-01
9 2022-03-15 10 2022-03-01
10 2022-03-31 10 2022-03-01
11 2022-04-01 2 2022-04-01
12 2022-04-15 4 2022-04-01
更新#2:
上面代码中对 assign()
的调用也可以使用 **kwargs
语法编写,以防我们想要使用带空格的列名或者不是有效的 python 标识符(而是session_evaluated
)。例如:
evaluations = pd.merge_asof(
evaluations.sort_values(by=['date']),
sessions.sort_values(by=['date'])['date'].to_frame()
.assign(**{'Evaluated Session (Date)' : lambda x: sessions['date']}),
on='date')
输出:
date rating Evaluated Session (Date)
0 2022-01-05 9 2022-01-01
1 2022-01-10 8 2022-01-01
2 2022-01-15 7 2022-01-01
3 2022-01-20 8 2022-01-01
4 2022-01-25 9 2022-01-01
5 2022-02-01 5 2022-02-01
6 2022-02-05 4 2022-02-01
7 2022-02-28 3 2022-02-01
8 2022-03-01 10 2022-03-01
9 2022-03-15 10 2022-03-01
10 2022-03-31 10 2022-03-01
11 2022-04-01 2 2022-04-01
12 2022-04-15 4 2022-04-01