Слияние таблиц по условию в Pandas
Есть два датафрейма: с пульсом и давлением
df_hr = pandas.DataFrame(
{'time': [datetime(2022,1,1,7,40),
datetime(2022,1,1,9,50),
datetime(2022,1,1,10,1)],
'hr': [60, 90, 100]}
)
df_bp = pandas.DataFrame(
{'time': [datetime(2022,1,1,10),
datetime(2022,1,1,8)],
'bp': [140, 120]}
)
HR:
time hr
0 2022-01-01 07:40:00 60
1 2022-01-01 09:50:00 90
2 2022-01-01 10:01:00 100
BP:
time bp
0 2022-01-01 10:00:00 140
1 2022-01-01 08:00:00 120
Нужно создать третий датафрейм так, чтобы для каждого замера давления в той же строке содержится время и значение ближайшего замера сердечного ритма, если он был сделан обязательно до замера давления и не раньше, чем за 15 минут.
Чтобы получилось типа такого:
time_hr hr time_bp bp
0 2022-01-01 09:50:00 90 2022-01-01 10:00:00 140
Ответы (2 шт):
Автор решения: CrazyElf
→ Ссылка
Как-то сложно получилось:
- объединяем данные по ритму и давлению
- сортируем по
time - заполняем
NAвперёд для ритма, чтобы сопоставить с давлением - применяем условие про 15 минут: что не подходит под него, то превращаем обратно в
NA - оставляем только строки с давлением
import pandas as pd
from datetime import datetime
df_hr = pd.DataFrame(
{'time': [datetime(2022,1,1,7,40),
datetime(2022,1,1,9,50),
datetime(2022,1,1,10,1)],
'hr': [60, 90, 100]}
)
df_bp = pd.DataFrame(
{'time': [datetime(2022,1,1,10),
datetime(2022,1,1,8)],
'bp': [140, 120]}
)
# нужна отдельная колонка, чтобы можно было её заполнять вперёд
df_hr['time_hr'] = df_hr['time']
# объединяем данные, с сортировкой по времени
df = pd.concat([df_hr, df_bp]).sort_values('time')
# заполняем NA данные по ритму вперёд
df.loc[:, ['hr','time_hr']] = df.loc[:, ['hr','time_hr']].ffill()
# условие про 15 минут
df.loc[(df['time'] - df['time_hr']).dt.seconds//60 > 15, ['hr', 'time_hr']] = pd.NA
# оставляем только строки с давлением (и присоединённый к ним найденный по условиям ритм)
df = df.loc[~df['bp'].isna()]
df
Вывод:
time hr time_hr bp
1 2022-01-01 08:00:00 <NA> NaT 120.0
0 2022-01-01 10:00:00 90.0 2022-01-01 09:50:00 140.0
Автор решения: strawdog
→ Ссылка
Воспользуйтесь методом merge_asof:
res = pd.merge_asof(df_hr.sort_values("time"),
df_bp.rename(columns={'time':'time_bp'}).sort_values("time_bp"),
left_on="time", right_on="time_bp",
direction='forward',
tolerance=pd.Timedelta(minutes=15)).dropna()
res:
time hr time_bp bp
1 2022-01-01 09:50:00 90 2022-01-01 10:00:00 140.0