Как найти ближайшие значения одного столбца фрейма данных и вернуть значение столбца и положение другого фрейма данных

#python #pandas #dataframe

Вопрос:

У меня есть два кадра данных, как показано ниже. Я не мог придумать, как найти ближайшее значение столбца df2 — «T» из df1 и найти Pos, Sr и ближайшее значение из df1 и добавить в df2 в соответствии с выводом ниже.

введите описание изображения здесь

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

 import pandas as pd
 
df1 = pd.DataFrame({
        'Sr':[1000, 1002, 1004, 1009],
        'W1':[20.1, 20.3, 19.1, 18.5],
        'W2':[45.155, 45.180, 19.115, 19.126],
        'W3':[20, 22, 19, 18]
        })

df2 = pd.DataFrame({
        'W':["W1", "W2", "W3"],
        'T':[20.2, 19.119, 18.1]
        })

print(df1)

df2["sr"] = df2["W"].apply(lambda x: df1[x].sub(df2['T']).abs().idxmin())
df2["Pos"] = df2["W"].apply(lambda x: df1[x].sub(df2['T']).abs().idxmin())

print(df2)
 

Ответ №1:

Вот трубопровод, который выполняет эту работу. Таким образом, хитрость заключается в том, чтобы melt сначала выбрать df1, затем merge оба кадра данных и использовать разницу в значениях, чтобы получить наиболее близкое совпадение. Большая часть остального предназначена для форматирования.

 (df2.merge((df1.rename_axis('df1_Pos')          # reshape df1 to long format
               .reset_index()                   #
               .melt(id_vars=['df1_Pos', 'Sr'], #
                     var_name='W',              #
                     value_name='T')            #
           ),
           on=['W'],                            # merge with df2 on "W"
           suffixes=['', '1'])
    .assign(diff=lambda d: abs(d['T']-d['T1'])) # compute the diff of "T"
    .rename(columns={'T1': 'df1Closest_Val',
                     'Sr': 'df1_Sr'})
    .sort_values(by='diff')                     # sort diff to have min diff first
    .drop('diff', axis=1)
    .groupby('W').first()                       # keep first row per group (= min diff)
    .reset_index()
)
 

выход:

     W       T  df1_Pos  df1_Sr  df1Closest_Val
0  W1  20.200        0    1000          20.100
1  W2  19.119        2    1004          19.115
2  W3  18.100        3    1009          18.000
 

Разрушение

Изменение формы df1:

 >>> df1b = df1.reset_index().melt(id_vars=['index', 'Sr'], var_name='W', value_name='T')
>>> df1b

    index    Sr   W       T
0       0  1000  W1  20.100
1       1  1002  W1  20.300
2       2  1004  W1  19.100
3       3  1009  W1  18.500
4       0  1000  W2  45.155
5       1  1002  W2  45.180
6       2  1004  W2  19.115
7       3  1009  W2  19.126
8       0  1000  W3  20.000
9       1  1002  W3  22.000
10      2  1004  W3  19.000
11      3  1009  W3  18.000
 

Слияние:

 >>> df2b = df2.merge(df1b, on=['W'], suffixes=['', '1']).assign(diff=lambda d: abs(d['T']-d['T1']))
>>> df2b

     W       T  index    Sr      T1    diff
0   W1  20.200      0  1000  20.100   0.100
1   W1  20.200      1  1002  20.300   0.100
2   W1  20.200      2  1004  19.100   1.100
3   W1  20.200      3  1009  18.500   1.700
4   W2  19.119      0  1000  45.155  26.036
5   W2  19.119      1  1002  45.180  26.061
6   W2  19.119      2  1004  19.115   0.004
7   W2  19.119      3  1009  19.126   0.007
8   W3  18.100      0  1000  20.000   1.900
9   W3  18.100      1  1002  22.000   3.900
10  W3  18.100      2  1004  19.000   0.900
11  W3  18.100      3  1009  18.000   0.100
 

Сортировка значений, группировка и учет минимальной разницы:

 >>> df2b.sort_values(by='diff').groupby('W').first().reset_index()

    W       T  index    Sr      T1   diff
0  W1  20.200      0  1000  20.100  0.100
1  W2  19.119      2  1004  19.115  0.004
2  W3  18.100      3  1009  18.000  0.100
 

Комментарии:

1. Это немного сложно понять, не могли бы вы упростить его и опубликовать весь код, так как я получаю ошибку при его запуске.

2. @OO7 Я представил разбивку по 3 основным шагам