Время и эффективность имеют значение
Pandas - одна из наиболее часто используемых библиотек для анализа и обработки данных в экосистеме науки о данных. Он предлагает множество функций и методов для выполнения эффективных операций.
Что мне больше всего нравится в Pandas, так это то, что почти всегда есть несколько способов выполнить данную задачу. Однако мы должны учитывать время и вычислительную сложность при выборе метода из доступных вариантов.
Недостаточно просто выполнить поставленную задачу. Мы должны сделать его максимально эффективным. Таким образом, очень важно иметь полное представление о том, как работают функции и методы.
В этой статье мы рассмотрим примеры для сравнения функций apply и applymap панд с векторизованными операциями. Функции apply и applymap подходят для многих задач. Однако по мере увеличения размера данных время становится проблемой.
Давайте создадим образец фрейма данных со 100 тыс. Строк. Сначала нам нужно импортировать необходимые библиотеки.
import numpy as np import pandas as pd import timeit df = pd.DataFrame({ 'cola':np.random.randint(1,100, size=100000), 'colb':np.random.randint(100,1000, size=100000), 'colc':np.random.random(100000) }) df.shape (100000, 3)
Мы будем использовать библиотеку timeit для измерения времени, необходимого для выполнения операции.
Функция apply выполняет операции по строкам или по столбцам, перебирая элементы в цикле. Функция applymap работает аналогичным образом, но выполняет заданную задачу для всех элементов в фрейме данных.
Следующий код возведет в квадрат каждое число в столбце «кола».
%%timeit df['cola'].apply(lambda x: x**2) best of 3: 54.4 ms per loop
Это занимает 54,4 миллисекунды. Давайте выполним ту же задачу векторизованной операцией.
%%timeit df['cola'] ** 2 best of 3: 1.15 ms per loop
Это примерно в 50 раз быстрее на 100 тыс. Строк.
Следующий пример включает задачу найти минимальное значение в каждой строке фрейма данных.
%%timeit df.apply(lambda x: x.min(), axis=1) best of 3: 3.01 s per loop
Выполнение функции применения занимает 3 секунды.
%%timeit df.min(axis=1) best of 3: 1.58 ms per loop
Это все еще на уровне миллисекунды с векторизованной операцией. Это огромная разница. Причина, по которой разница существенно увеличилась, заключается в том, что функция циклически перебирает каждый столбец для каждой строки.
Немного увеличим сложность операции. Мы хотим найти разницу между самым высоким и самым низким значениями в строке.
Операция выполняется с помощью функции применения, как показано ниже:
%%timeit df.apply(lambda x: x.max() - x.min(), axis=1) best of 3: 5.29 s per loop
Мы используем лямбда-выражение для вычисления разницы между наибольшим и наименьшим значениями. Для оси установлено значение 1, чтобы указать, что операция выполняется над строками. Эта операция занимает 5,29 секунды.
Эту же задачу можно решить двумя векторизованными операциями.
%%timeit df.max(axis=1) - df.min(axis=1) best of 3: 3.86 ms per loop
Мы используем функции max и min как векторизованные операции. Параметр оси равен 1, чтобы указать, что нам нужно минимальное или максимальное значение в строке. Если мы не указываем параметр оси как 1, возвращается минимальное или максимальное значение в столбце.
Для выполнения векторизованной версии требуется 3,86 миллисекунды, что более чем в тысячу раз быстрее.
В следующем примере функция applymap сравнивается с векторизованной операцией. Следующий код удваивает каждый элемент в фрейме данных.
%%timeit df.applymap(lambda x: x * 2) best of 3: 93.6 ms per loop
Это занимает 93,6 миллисекунды.
%%timeit df * 2 best of 3: 1.03 ms per loop
Та же операция занимает около 1 миллисекунды, что в 90 раз быстрее, чем функция applymap.
Заключение
Мы рассмотрели несколько примеров для сравнения векторизованных операций и функций apply и applymap.
Для данных небольшого размера разница во времени обычно незначительна. Однако по мере увеличения размера разница начинает становиться заметной. Скорее всего, мы будем иметь дело с огромным объемом данных, поэтому всегда следует учитывать время.
Функции apply и applymap заставляют их выполнять заданную задачу. Данная операция выполняется путем циклического перебора элементов, что замедляет выполнение по мере увеличения размера данных.
Спасибо за чтение. Пожалуйста, дайте мне знать, если у вас есть какие-либо отзывы.