#python #pandas
Вопрос:
Панды merge_asof не оправдывают ожиданий….пример ниже:
left = pd.DataFrame({'a': [5, 10], 'left_val': ['b', 'c']})
right = pd.DataFrame({'a': [3, 7], 'right_val': [6, 7]})
pd.merge_asof(left, right, on='a', direction='nearest')
Это дает:
a left_val right_val
0 5 b 6
1 10 c 7
Мои ожидания:
a left_val right_val
0 5 b 6
1 5 b 7
2 10 c 7
данные 3 и 7 равноудалены от 5…so мои ожидания.
Есть ли способ добиться этого?
ПРАВКА: В любом случае, чтобы достичь этого в подобных пандах, кроме как по состоянию на.
Комментарии:
1. asof выбирает ближайший/ближайший, а не диапазон. вы можете ознакомиться с документами для получения более подробной информации. вы, вероятно, имеете в виду неэквивалентные соединения, что не является тем, что делает asof
2. 3 ближе, чем 7, поэтому алгоритм выбирает строку для 3. двоичный поиск может помочь. В Pandas еще нет ни одной существующей функции для неэквивалентных соединений
3. взгляните на документы, чтобы понять обоснование.
4. @sammywemmy прав, но вы можете сделать это вручную. Проверьте мой ответ, если он соответствует вашим потребностям.
Ответ №1:
Используйте pd.merge
с how='cross'
для создания всех комбинаций из левого и правого фреймов данных и вычисления расстояния между a
и a_right
.
out = pd.merge(left, right, how='cross', suffixes=('', '_right'))
out['dist'] = out['a'].sub(out['a_right']).abs()
В этот момент:
>>> out
a left_val a_right right_val dist
0 5 b 3 6 2 # dist == dist.min() / group 5
1 5 b 7 7 2 # dist == dist.min() / group 5
2 10 c 3 6 7 # dist > dist.min() / group 10
3 10 c 7 7 3 # dist == dist.min() / group 10
Держите ряды там, где dist == dist.min()
:
>>> out.loc[out.groupby('a')['dist'].apply(lambda d: d == d.min()),
['a', 'left_val', 'right_val']]
a left_val right_val
0 5 b 6
1 5 b 7
3 10 c 7