Время и эффективность имеют значение

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 заставляют их выполнять заданную задачу. Данная операция выполняется путем циклического перебора элементов, что замедляет выполнение по мере увеличения размера данных.

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