Панды применяют функцию к нескольким столбцам со скользящим окном

Мне нужно рассчитать некоторую метрику, используя скользящее окно по фрейму данных. Если бы для метрики требовался только 1 столбец, я бы использовал rolling. Но как-то не работает с 2+ колонками. Ниже показано, как я рассчитываю метрику, используя обычный цикл.

def mean_squared_error(aa, bb):
    return np.sum((aa - bb) ** 2) / len(aa)

def rolling_metric(df_, col_a, col_b, window, metric_fn):
    result = []
    for i, id_ in enumerate(df_.index):
        if i < (df_.shape[0] - window + 1):
            slice_idx = df_.index[i: i+window-1]
            slice_a, slice_b = df_.loc[slice_idx, col_a], df_.loc[slice_idx, col_b]
            result.append(metric_fn(slice_a, slice_b))
        else:
            result.append(None)
    return pd.Series(data = result, index = df_.index)

df = pd.DataFrame(data=(np.random.rand(1000, 2)*10).round(2), columns = ['y_true', 'y_pred'] )

%time df2 = rolling_metric(df, 'y_true', 'y_pred', window=7, metric_fn=mean_squared_error)

Это занимает около секунды всего для 1000 строк.

Пожалуйста, предложите более быстрый векторизованный способ вычисления такой метрики по скользящему окну.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В этом конкретном случае:

Вы можете заранее рассчитать квадрат ошибки, а затем использовать .Rolling.mean():

df['sq_error'] = (df['y_true'] - df['y_pred'])**2

%time df['sq_error'].rolling(6).mean().dropna()

Обратите внимание, что в вашем примере фактический размер окна равен 6 (напечатайте длину фрагмента), поэтому я установил его на 6 в своем фрагменте.

Можно даже так написать:

%time df['y_true'].subtract(df['y_pred']).pow(2).rolling(6).mean().dropna()

В целом:

Если вы не можете уменьшить его до одного столбца, начиная с pandas 1.3.0 вы можете использовать параметр method='table, чтобы применить функцию ко всему DataFrame. Однако для этого есть следующие требования:

  • Это реализовано только при использовании движка numba. Итак, вам нужно установить engine='numba' в apply и установить его.
  • Вам нужно установить raw=True в apply: это означает, что в вашей функции вы будете работать с массивами numpy вместо DataFrame. Это следствие предыдущего пункта.

Таким образом, ваши вычисления могут быть примерно такими:

WIN_LEN = 6

def mean_sq_err_table(arr, min_window=WIN_LEN):
    if len(arr) < min_window:
        return np.nan
    else:
        return np.mean((arr[:, 0] - arr[:, 1])**2)
    
df.rolling(WIN_LEN, method='table').apply(mean_sq_err_table, engine='numba', raw=True).dropna()

Поскольку он использует numba, это также относительно быстро.

это работает, но только для одного случая из моего примера, сводя проблему к случаю с одним столбцом. Однако мне нужно иметь возможность использовать несколько других показателей. Есть ли способ сделать прокрутку + применить к нескольким столбцам?

Poe Dator 09.05.2022 23:27

@PoeDator Понятно, пожалуйста, проверьте мою правку!

user2246849 10.05.2022 05:35

Спасибо, @user2246849! Это близко к тому, что я ожидал. Пользоваться пока не очень удобно — надеюсь, что в ближайших релизах панд этот функционал улучшится. Что касается скорости - я заметил одинаковое время работы для 1000 строк (около 1 секунды), но с numba оно остается почти одинаковым для 10k и 100k строк, что приятно.

Poe Dator 10.05.2022 18:01

Другие вопросы по теме