Что касается этого ответа , существует ли быстрый способ вычисления медиан по массиву, в котором есть группы с неодинаковым числом элементов?
Например:
data = [1.00, 1.05, 1.30, 1.20, 1.06, 1.54, 1.33, 1.87, 1.67, ... ]
index = [0, 0, 1, 1, 1, 1, 2, 3, 3, ... ]
И затем я хочу вычислить разницу между числом и медианой на группу (например, медиана группы 0
- 1.025
первый результат 1.00 - 1.025 = -0.025
). Таким образом, для массива выше, результаты будут выглядеть так:
result = [-0.025, 0.025, 0.05, -0.05, -0.19, 0.29, 0.00, 0.10, -0.10, ...]
Так np.median.reduceat
как не существует (пока), есть ли другой быстрый способ достичь этого? Мой массив будет содержать миллионы строк, поэтому скорость имеет решающее значение!
Можно считать, что индексы являются смежными и упорядоченными (их легко преобразовать, если они не являются).
Пример данных для сравнения производительности:
import numpy as np
np.random.seed(0)
rows = 10000
cols = 500
ngroup = 100
# Create random data and groups (unique per column)
data = np.random.rand(rows,cols)
groups = np.random.randint(ngroup, size=(rows,cols)) + 10*np.tile(np.arange(cols),(rows,1))
# Flatten
data = data.ravel()
groups = groups.ravel()
# Sort by group
idx_sort = groups.argsort()
data = data[idx_sort]
groups = groups[idx_sort]
python
performance
numpy
median
numpy-ufunc
Жан-Поль
источник
источник
scipy.ndimage.median
предложение в связанном ответе? Мне не кажется, что для каждого ярлыка нужно одинаковое количество элементов. Или я что-то пропустил?Ответы:
Иногда вам нужно написать неидиоматический код Numpy, если вы действительно хотите ускорить вычисления, чего вы не можете сделать с помощью Numpy.
numba
компилирует ваш код Python в низкоуровневый C. Поскольку большая часть numpy обычно работает так же быстро, как C, это в основном оказывается полезным, если ваша проблема не поддается нативной векторизации с numpy. Это один пример (где я предположил, что индексы смежны и отсортированы, что также отражено в данных примера):И вот некоторые моменты использования
%timeit
магии IPython :Используя обновленные данные примера в вопросе, эти числа (т. Е. Время выполнения функции python по сравнению с временем выполнения функции, ускоряемой JIT)
Это составляет 65-кратное ускорение в меньшем случае и 26-кратное ускорение в большем случае (по сравнению с медленным зацикливанием кода, конечно) с использованием ускоренного кода. Другим преимуществом является то, что (в отличие от типичной векторизации с нативной нативой) нам не требовалась дополнительная память для достижения этой скорости, все дело в оптимизированном и скомпилированном низкоуровневом коде, который в конечном итоге запускается.
Вышеприведенная функция предполагает, что
int64
по умолчанию используются пустые массивы int , чего нет в Windows. Таким образом, альтернативой является удаление подписи из вызова tonumba.njit
, запускающей правильную сборку точно в срок. Но это означает, что функция будет скомпилирована во время первого выполнения, что может повлиять на результаты синхронизации (мы можем либо выполнить функцию один раз вручную, используя репрезентативные типы данных, либо просто принять, что первое выполнение синхронизации будет намного медленнее, что должно быть проигнорированным). Это именно то, что я пытался предотвратить, указав сигнатуру, которая запускает преждевременную компиляцию.Во всяком случае, в надлежащем случае JIT декоратор нам нужен просто
Обратите внимание, что приведенные выше моменты времени, которые я показал для функции jit-compiled, применяются только после того, как функция была скомпилирована. Это может происходить либо при определении (с готовой компиляцией, когда передается явная подпись
numba.njit
), либо во время первого вызова функции (с отложенной компиляцией, когда подпись не передаетсяnumba.njit
). Если функция будет выполняться только один раз, то время компиляции также должно учитываться для скорости этого метода. Как правило, компиляция функций имеет смысл только в том случае, если общее время выполнения + компиляции меньше, чем некомпилированное время выполнения (что на самом деле верно в вышеупомянутом случае, когда собственная функция python очень медленная). В основном это происходит, когда вы часто вызываете скомпилированную функцию.Как max9111 отмечена в комментариях, одна важная особенностью
numba
являетсяcache
ключевым словом , чтобыjit
. Передачаcache=True
tonumba.jit
сохранит скомпилированную функцию на диск, так что во время следующего выполнения данного модуля python функция будет загружена оттуда, а не перекомпилирована, что снова может сэкономить вам время выполнения в долгосрочной перспективе.источник
index
данные roganjosh . Я оставлю записку об этом, спасибо :)cache=True
чтобы избежать перекомпиляции при каждом перезапуске интерпретатора.Один из подходов состоит в том, чтобы использовать
Pandas
здесь исключительно для использованияgroupby
. Я немного увеличил размеры входных данных, чтобы лучше понять время (так как при создании DF возникают накладные расходы).Дает следующее
timeit
:Для того же размера выборки я получаю изощренный подход Арье :
Однако, если мы увеличим входные данные еще в 10 раз, время станет:
Тем не менее, за счет некоторой надежности, ответ Дивакара с использованием чистого numpy приходит в:
В свете нового набора данных (который действительно должен был быть установлен в начале):
источник
Может быть, вы уже сделали это, но если нет, посмотрите, достаточно ли это быстро:
Вывод:
источник
np.vectorize
это очень тонкая оболочка для цикла, поэтому я не ожидаю, что этот подход будет особенно быстрым.data
и ,index
какnp.array
с , как в этом вопросе.Вот подход, основанный на NumPy, чтобы получить усредненное значение для положительных значений bin / index -
Чтобы решить наш конкретный случай вычтенных -
источник
df.groupby('index').transform('median')
?