[英]Find the closest date from a list to a given date that is not after the given date
我有一個 dataframe 用於每周的培訓課程,還有一個數據框架用於參加者在這些培訓課程中提交的評估。
每個 dataframe 都有一個日期列 - 對於會話,它是 session 發生的日期。 對於評估,這是提交評估的日期。 預計與會者將參加多個會議,因此將提交多個評估。
我需要將每個評估與特定的 session 聯系起來。他們可能在與 session 同一天提交了評估,在這種情況下匹配很容易。 但他們可以在下一次培訓 session 之前的任何一天提交評估。
對於評估 df 中的每個日期,我需要返回最接近評估日期但不晚於評估日期的 session 日期。
例如 session 日期:2/3/22、2/10/22、2/17/22
示例評估日期與所需的 output:2/3/22(應匹配 2/3/22)、2/4/22(應匹配 2/3/22)、2/11/22(應匹配 2/10/22 )
這是一種方法。
在sessions
dataframe 中,將date
列設置為索引:
sessions = sessions.set_index('date')
按索引(即按日期)對會話進行排序:
sessions = sessions.loc[sessions.index.sort_values()]
將session_evaluated
列添加到評估中,其中將包含評估適用的 session 的日期。 我們通過首先在評估的date
列上調用sessions.index.get_indexer()
並將method
參數設置為“pad”來計算這一點,因此我們在不匹配的日期上“向下舍入”,然后查找這些 integer 索引值在會話索引中(包含 session 日期):
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()
function 的另一種方法。它不需要日期列作為索引(盡管它確實要求 dataframe arguments 都按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)
Output:
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')
Output:
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.