динамическая конкатенация столбцов для нахождения max

#python #pandas

#питон #панды

Вопрос:

Вот мои данные —

 ID,Pay1,Pay2,Pay3,Low,High,expected_output
1,12,21,23,1,2,21
2,21,34,54,1,3,54
3,74,56,76,1,1,74
 

Цель состоит в том, чтобы вычислить максимальное Pay значение каждой строки в соответствии Pay с индексом столбца, указанным в Low и High столбцы.

Например, для строки 1 вычислите max of Pay1 и Pay2 столбцы как Low и High равны 1 и 2.

Я попытался создать динамическую строку, а затем использовать eval функцию, которая работает плохо.

Ответ №1:

Идея заключается в том, чтобы фильтровать только Pay столбцы, а затем с помощью numpy broadcasting выбирать столбцы по Low и High столбцам, передавать DataFrame.where и получать в последний раз max :

 df1 = df.filter(like='Pay')

m1  = np.arange(len(df1.columns)) >= df['Low'].to_numpy()[:, None] - 1
m2  = np.arange(len(df1.columns)) <= df['High'].to_numpy()[:, None] - 1

df['expected_output'] = df1.where(m1 amp; m2, 0).max(axis=1)
print (df)
   ID  Pay1  Pay2  Pay3  Low  High  expected_output
0   1    12    21    23    1     2               21
1   2    21    34    54    1     3               54
2   3    74    56    76    1     1               74
 

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

1. Спасибо @jezrael! Сократил время выполнения с 13 секунд до 64 мс на выборке из 12 тыс. строк!

Ответ №2:

Альтернатива; Я ожидаю, что решение @jezrael будет быстрее, поскольку оно находится в numpy и pd.wide_to_long не особенно быстрое:

 grouping = (
    pd.wide_to_long(df.filter(regex="^Pay|Low|High"), 
                   i=["Low", "High"], 
                   stubnames="Pay", 
                   j="num")
    .query("Low==num or High==num")
    .groupby(level=["Low", "High"])
    .Pay.max()
)

grouping

Low  High
1    1       74
     2       21
     3       54
Name: Pay, dtype: int64


df.join(grouping.rename("expected_output"), on=["Low", "High"])

    ID  Pay1    Pay2    Pay3    Low     High    expected_output
0   1   12  21  23  1   2   21
1   2   21  34  54  1   3   54
2   3   74  56  76  1   1   74