merge
в течение года и удалите все тикеры, которые слились с собой. Затем определите абсолютную разницу в 'total_assets'
. Сортируя и отбрасывая дубликаты, мы сохраняем только самое близкое совпадение для каждого ['тикера', 'года'] в исходном кадре данных.
Пример данных
year ticker tot_assets return
0 1999 AAPL 10.345 0.1294
1 2000 AAPL 10.988 0.1577
34521 1999 GMBO 0.893 0.2209
34522 2000 GMBO 1.206 0.1001
200344 1999 ZZ 3.789 0.0032
200344 2000 ZZ 3.021 -0.0346
Код
df = df.merge(df, on='year', suffixes=['', '_closest']).query('ticker != ticker_closest')
df['diff'] = (df['tot_assets'] - df['tot_assets_closest']).abs()
df = df.sort_values('diff').drop_duplicates(['year', 'ticker'])
Вывод:
year ticker tot_assets return ticker_closest tot_assets_closest return_closest diff
14 2000 GMBO 1.206 0.1001 ZZ 3.021 -0.0346 1.815
16 2000 ZZ 3.021 -0.0346 GMBO 1.206 0.1001 1.815
5 1999 GMBO 0.893 0.2209 ZZ 3.789 0.0032 2.896
7 1999 ZZ 3.789 0.0032 GMBO 0.893 0.2209 2.896
2 1999 AAPL 10.345 0.1294 ZZ 3.789 0.0032 6.556
11 2000 AAPL 10.988 0.1577 ZZ 3.021 -0.0346 7.967
Выше будет очень большое слияние. Другой альтернативой является использование pd.merge_asof
с allow_exact_matches=False
. Becasue tot_assets
- это число с плавающей точкой, поэтому маловероятно, что два разных тикера будут иметь одинаковое значение, поэтому allow_exact_matches=False
, по существу, предотвращает слияние одного и того же тикера с самим собой. Однако, если есть другой тикер с точно таким же Tot_assets, мы пропустим это с помощью этого метода.
df = df.sort_values('tot_assets')
df = (pd.merge_asof(df, df.add_suffix('_closest'),
left_by='year', right_by='year_closest',
left_on='tot_assets', right_on='tot_assets_closest',
direction='nearest',
allow_exact_matches=False)
.drop(columns='year_closest'))