объединить фреймы данных панд на основе идентификатора и диапазона дат - PullRequest
0 голосов
/ 04 июня 2018

Мне нужно выполнить слияние, чтобы сопоставить новый набор идентификаторов со старым набором идентификаторов.Мои начальные данные выглядят так:

lst = [10001, 20001, 30001]
dt = pd.date_range(start='2016', end='2018', freq='M')
idx = pd.MultiIndex.from_product([dt,lst],names=['date','id'])
df = pd.DataFrame(np.random.randn(len(idx)), index=idx)

In [94]: df.head()
Out[94]:
                         0
date       id
2016-01-31 10001 -0.512371
           20001 -1.164461
           30001 -1.253232
2016-02-29 10001 -0.129874
           20001  0.711938

И я хочу сопоставить id с newid, используя данные, которые выглядят так:

df1 = pd.DataFrame({'id': [10001, 10001, 10001, 10001],
'start_date': ['2015-11-31', '2016-02-01', '2016-05-16', '2017-02-16'],
'end_date': ['2016-01-31', '2016-05-15', '2017-02-15', '2018-04-02'],
'new_id': ['ABC123', 'XYZ789', 'HIJ456', 'LMN654']},)
df2 = pd.DataFrame({'id': [20001, 20001, 20001, 20001],
'start_date': ['2015-10-07', '2016-01-08', '2016-06-02', '2017-02-13'],
'end_date': ['2016-01-07', '2016-06-01', '2017-02-12', '2018-03-017'],
'new_id': ['CBA321', 'ZYX987', 'JIH765', 'NML345']},)
df3 = pd.DataFrame({'id': [30001, 30001, 30001, 30001],
'start_date': ['2015-07-31', '2016-02-23', '2016-06-17', '2017-05-12'],
'end_date': ['2016-02-22', '2016-06-16', '2017-05-11', '2018-01-05'],
'new_id': ['CCC333', 'XXX444', 'HHH888', 'III888']},)
df_ranges = pd.concat([df1,df2,df3])
In [95]: df_ranges.head()
Out[95]:
   index    end_date     id  new_id  start_date
0      0  2016-01-31  10001  ABC123  2015-11-31
1      1  2016-05-15  10001  XYZ789  2016-02-01
2      2  2017-02-15  10001  HIJ456  2016-05-16
3      3  2018-04-02  10001  LMN654  2017-02-16
4      0  2016-01-07  20001  CBA321  2015-10-07

В основном, мои данные ежемесячныеданные панели и новые данные имеют диапазоны дат, для которых допустимо определенное отображение из A-> B.Итак, в строке 1 данных сопоставления указано, что с 2016-01-31 по 2015-211-31 идентификатор 10001 отображается на ABC123.

Ранее я делал это в SAS / SQL с помощью следующего предложения:

SELECT a.*, b.newid FROM df as a, df_ranges as b 
WHERE a.id = b.id AND b.start_date <= a.date < b.end_date

Несколько замечаний по поводу данных:

  1. это должно быть1: 1 сопоставление идентификатора с новым.
  2. диапазоны дат не перекрываются

Хорошим началом может служить решение: Объединение фреймов данных на основе диапазона дат

Этоэто именно то, что я ищу, за исключением того, что он сливается только по датам, а не дополнительно id.Я играл с groupby () и этим решением, но не нашел способа заставить его работать.Еще одна идея, которая у меня возникла, заключалась в том, чтобы отменить укладку () данных отображения (df_ranges) для соответствия измерениям / частоте времени df, но, похоже, это просто переосмысливает существующую проблему.

1 Ответ

0 голосов
/ 04 июня 2018

Возможно, я получил отрицательное голосование, потому что это было слишком просто, но я нигде не мог найти ответ, поэтому я просто опубликую его здесь: вы должны использовать merge_asof (), который обеспечивает нечеткое сопоставление дат.Сначала необходимо отсортировать данные:

df_ranges.sort_values(by=['start_date','id'],inplace=True)
df.sort_values(by=['date','id'],inplace=True)

Затем выполните объединение:

pd.merge_asof(df,df_ranges, by='id', left_on='date', right_on='start_date')

Вывод:

In [30]: pd.merge_asof(df,df_ranges, by='id', left_on='date', right_on='start_date').head()
Out[30]:
        date     id         0 start_date    end_date  new_id
0 2016-01-31  10001  0.120892 2015-11-30  2016-01-31  ABC123
1 2016-01-31  20001 -0.576096 2016-01-08  2016-06-01  ZYX987
2 2016-01-31  30001  0.543597 2015-07-31  2016-02-22  CCC333
3 2016-02-29  10001  0.316212 2016-02-01  2016-05-15  XYZ789
4 2016-02-29  20001 -0.625878 2016-01-08  2016-06-01  ZYX987
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...