У меня есть несколько фреймов данных, которые мне нужно объединить в один набор данных на основе уникального идентификатора (uid) и временной шкалы между датами в каждом фрейме данных.
Вот упрощенный пример фреймов данных:
df1
uid tx_date last_name first_name meas_1
0 60 2004-01-11 John Smith 1.3
1 60 2016-12-24 John Smith 2.4
2 61 1994-05-05 Betty Jones 1.2
3 63 2006-07-19 James Wood NaN
4 63 2008-01-03 James Wood 2.9
5 65 1998-10-08 Tom Plant 4.2
6 66 2000-02-01 Helen Kerr 1.1
df2
uid rx_date last_name first_name meas_2
0 60 2004-01-14 John Smith A
1 60 2017-01-05 John Smith AB
2 60 2017-03-31 John Smith NaN
3 63 2006-07-21 James Wood A
4 64 2002-04-18 Bill Jackson B
5 65 1998-10-08 Tom Plant AA
6 65 2005-12-01 Tom Plant B
7 66 2013-12-14 Helen Kerr C
В основном я пытаюсь объединить записи для одного и того же лица из двух отдельных источников, где существует связь между записями для уникальных лиц: «uid» и связь между строками (где она существует) для каждого индивида является нечеткой взаимосвязью между «tx_date» и «rx_date», которая (обычно) может быть согласована с заданной c дельтой времени. Не всегда будет точное или нечеткое соответствие между датами, данные могут отсутствовать в любом столбце, кроме 'uid', и каждый фрейм данных будет содержать различное, но пересекающееся подмножество 'uid's.
Мне нужно быть возможность объединять строки, в которых совпадают столбцы «uid», и где абсолютная дельта времени между «tx_date» и «rx_date» находится в заданном диапазоне (например, максимальная дельта 14 дней). В тех случаях, когда дельта времени находится за пределами этого диапазона или отсутствует одно из значений tx_date или rx_date или если uid существует только в одном из фреймов данных, мне все равно необходимо сохранить данные в этой строке. Конечный результат должен выглядеть примерно так:
uid tx_date rx_date first_name last_name meas_1 meas_2
0 60 2004-01-11 2004-01-14 John Smith 1.3 A
1 60 2016-12-24 2017-01-05 John Smith 2.4 AB
2 60 NaT 2017-03-31 John Smith NaN NaN
3 61 1994-05-05 NaT Betty Jones 1.2 NaN
4 63 2006-07-19 2006-07-21 James Wood NaN A
5 63 2008-01-03 NaT James Wood NaN NaN
6 64 2002-04-18 NaT Bill Jackson NaN B
7 65 1998-10-08 1998-10-08 Tom Plant 4.2 AA
8 65 NaT 2005-12-01 Tom Plant NaN B
9 66 2000-02-01 NaT Helen Kerr 1.1 NaN
10 66 NaT 2013-12-14 Helen Kerr NaN C
Похоже, pandas .merge_asof должно быть полезно здесь, но я не смог заставить его делать то, что я нужно.
Попробовав merge_asof на двух реальных фреймах данных, я выдал ошибку ValueError: left keys must be sorted
Согласно этому вопросу проблема была на самом деле из-за наличия NaT значения в столбце «дата» для некоторых строк. Я удалил строки со значениями NaT и отсортировал столбцы 'date' в каждом кадре данных, но результат все еще не совсем тот, который мне нужен.
В приведенном ниже коде показаны предпринятые шаги.
import pandas as pd
df1['date'] = df1['tx_date']
df1['date'] = pd.to_datetime(df1['date'])
df1['date'] = df1['date'].dropna()
df1 = df1.sort_values('date')
df2['date'] = df2['rx_date']
df2['date'] = pd.to_datetime(df2['date'])
df2['date'] = df2['date'].dropna()
df2 = df2.sort_values('date')
df_merged = (pd.merge_asof(df1, df2, on='date', by='uid', tolerance=pd.Timedelta('14 days'))).sort_values('uid')
Результат:
uid tx_date rx_date last_name_x first_name_x meas_1 meas_2
3 60 2004-01-11 2004-01-14 John Smith 1.3 A
6 60 2016-12-24 2017-01-05 John Smith 2.4 AB
0 61 1994-05-05 NaT Betty Jones 1.2 NaN
4 63 2006-07-19 2006-07-21 James Wood NaN A
5 63 2008-01-03 NaT James Wood 2.9 NaN
1 65 1998-10-08 1998-10-08 Tom Plant 4.2 AA
2 66 2000-02-01 NaT Helen Kerr 1.1 NaN
Это выглядит как левое соединение, а не как полное внешнее соединение, поэтому везде, где есть строка в df2 без совпадения по 'uid' и 'date' в df1, теряется (и это не очень ясно из этого упрощенного примера, но мне также нужно добавить строки туда, где дата была NaT).
Есть ли какой-нибудь способ добиться слияния без потерь, либо путем какого-либо внешнего соединения с merge_asof, либо с помощью какого-то другого подхода?