Pandas: Как объединить два фрейма данных по ближайшему совпадению индекса?

1

У меня есть два df1, df2 с индексами одного типа, но с небольшим, если таковые имеются, одинаковыми совпадениями. Индексы также могут иметь дубликаты. Столбцы A и B будут состоять из уникальных внутренних значений. Все индексы и столбцы упорядочены, но не в одном направлении. df1.index является убывающим, а df1['A'] восходящим. df2.index возрастает, а df2['B'].

df1: (числа слева - безымянные индексы кадров данных)

            A
80 -13.545215
76 -12.270691
73 -11.274724
65  -8.280187
38  -7.965972
13  -7.788130
10  -6.690969
6   -5.273063

df2:

            B
8  -13.827641
10 -12.283885
14 -11.459951
62 -11.067622
64 -10.745988
87 -10.661594
95  -9.816053
97  -7.740810

Я хотел бы объединить кадры данных таким образом, чтобы значения в df2['B'] помещались в ближайший соответствующий индекс из df2 в df1, так что желаемый вывод принимает форму:

            B         A
8  -13.827641 -6.690969
10 -12.283885 -6.690969
14 -11.459951 -7.965972
62 -11.067622 -8.280187
64 -10.745988 -8.280187
87 -10.661594  NaN
95  -9.816053  NaN
97  -7.740810  NaN

Если ближайший индекс A в абсолютном выражении ниже, чем индекс B, то верхнее значение индекса A является правильным соответствием. Если индекс B не имеет соответствующего соответствия в индексе A, который выше, то NaN является правильным соответствием.

До сих пор я использовал pd.merge() и fillna() для проведения необходимого анализа. Но некоторые могут посчитать "неестественным" проводить анализ интерполированных/синтетических данных. Во всяком случае, как я это делал:

Пример неполного кода для pd.merge() и dropna():

# outer merge
df3 = pd.merge(df1,df2, how = 'outer', left_index = True, right_index = True)
#df4 = df3.interpolate(method = 'linear')[1:]
df4 = df3.interpolate(method = 'linear').dropna()
df4

Выход:

            A          B
8   -5.982016 -13.827641
10  -6.690969 -12.283885
13  -7.788130 -11.871918
14  -7.877051 -11.459951
38  -7.965972 -11.263787
62  -8.070710 -11.067622
64  -8.175448 -10.745988
65  -8.280187 -10.729109
73 -11.274724 -10.712230
76 -12.270691 -10.695352
80 -13.545215 -10.678473
87 -13.545215 -10.661594
95 -13.545215  -9.816053
97 -13.545215  -7.740810

Участок:

Изображение 174551

Полные данные и пример кода

#imports
import numpy as np
import pandas as pd

# Some sample data
np.random.seed(1)
df1_index = sorted(np.random.randint(1,101,8), reverse = True)
df1info = {'A':sorted((np.random.normal(10, 2, 8))*-1)}

df2_index = sorted(np.random.randint(1,101,8))
df2info = {'B':sorted(np.random.normal(10, 2, 8)*-1)}

# Two dataframes
df1 = pd.DataFrame(df1info, index = df1_index)
df2 = pd.DataFrame(df2info, index = df2_index)

# outer merge
df3 = pd.merge(df1,df2, how = 'outer', left_index = True, right_index = True)

# interpolate missing values
df4 = df3.interpolate(method = 'linear').dropna()

# plot
df4.plot()

Спасибо за любые предложения!

Изменить 1: Дублировать сценарий 1:

Если df2.index имеет точное совпадение в df1.index, а df1.index имеет дубликат, то правильное совпадение является самым низким df1.index. Я надеюсь, что в этом есть смысл. Если по какой-то причине это окажется бессмысленным, я открыт для других предложений!

  • 1
    Что происходит с дублированием индекса? Должно ли оно совпадать со всеми точными дубликатами / ближайшими дубликатами?
Показать ещё 6 комментариев
Теги:
pandas

1 ответ

2

Не "Pythonic", а O(n) решение

df2_index.sort()
df1_index.sort()

a = 0
b = 0
mapping = [[],[]]
while b < len(df2_index) and a < len(df1_index):
    if df1_index[a] == df2_index[b]:
        mapping[0].append(df2_index[b])
        mapping[1].append(df1.loc[df1_index[a], "A"]) 
        b += 1
        a += 1
    elif df1_index[a] > df2_index[b]:
        mapping[0].append(df2_index[b])
        mapping[1].append(df1.loc[df1_index[a], "A"])           
        b += 1
    else:
        a += 1

df = pd.DataFrame({'A': mapping[1]}, index = mapping[0])
df2.merge(df, left_index=True, right_index=True, how='outer')

Выход

     B              A
8   -13.827641  -6.690969
10  -12.283885  -6.690969
14  -11.459951  -7.965972
62  -11.067622  -8.280187
64  -10.745988  -8.280187
87  -10.661594  NaN
95  -9.816053   NaN
97  -7.740810   NaN
  • Оба индекса отсортированы в порядке возрастания
  • b указывает на B и a указывает на индекс
  • В любой момент времени дайте b мы находим следующий максимум a и сохраняем его, когда находим
  • если b == a то мы закончили с этими записями, поэтому мы идем вперед
  • если a > b тогда мы находим значение b поэтому перемещаем b. Мы не двигаем, потому что это также может быть кандидатом на следующие a b
  • если a < b мы перемещаем a потому что кандидат на b будет где-то после текущего a потому что он отсортирован.
  • 0
    Спасибо за ответ! Я также был бы очень заинтересован в других вариациях той же установки. Вы не возражаете против последующего вопроса, или вы бы предпочли ответить на него в новом вопросе?
  • 0
    @vestland Followup вопрос в порядке
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню