Динамические оконные функции, более быстрое применение и многое другое.
pandas 1.0 был выпущен 29 января 2020 года. Версия подскочила с 0.25 до 1.0, никаких кардинальных изменений, как ожидают некоторые пользователи pandas, не произошло. Увеличение версии просто отражает зрелость библиотеки обработки данных.
Революционных изменений не так много, но есть некоторые, о которых вам следует знать.
Вот несколько ссылок, которые могут вас заинтересовать:
- Labeling and Data Engineering for Conversational AI and Analytics - Data Science for Business Leaders [Course] - Intro to Machine Learning with PyTorch [Course] - Become a Growth Product Manager [Course] - Deep Learning (Adaptive Computation and ML series) [Ebook] - Free skill tests for Data Scientists & Machine Learning Engineers
Некоторые из приведенных выше ссылок являются партнерскими, и если вы перейдете по ним, чтобы совершить покупку, я буду получать комиссию. Имейте в виду, что я связываю курсы из-за их качества, а не из-за комиссии, которую я получаю от ваших покупок.
Чтобы улучшить свою игру Pandas, прочтите:
1. Динамический размер окна с функциями прокрутки
Функции скользящего окна очень полезны при работе с данными временных рядов (например, расчет скользящего среднего). Предыдущая версия pandas требовала, чтобы мы передавали параметр размера окна, например. рассчитать скользящую среднюю по 3 периодам. С помощью pandas 1.0 мы можем обойти это требование, как показано в примере ниже.
Давайте посчитаем скользящее среднее значений до тех пор, пока текущее число не станет больше 10. Сначала мы создаем DataFrame с 3 значениями, большими или равными 10.
df = pd.DataFrame({'col1': [1, 2, 3, 10, 2, 3, 11, 2, 3, 12, 1, 2]})
df
Функция окна должна расширяться до тех пор, пока не будет достигнуто значение больше или равное 10.
use_expanding = (df.col1 >= 10).tolist() use_expanding
# output[False, False, False, True, False, False, True, False, False, True, False, False]
Для оконных функций с динамическим размером нам нужно реализовать собственный индексатор, который наследуется от класса BaseIndexer pandas. В классе BaseIndexer есть функция get_window_bounds, которая вычисляет начало и конец каждого окна.
from pandas.api.indexers import BaseIndexer
class CustomIndexer(BaseIndexer):
def get_window_bounds(self, num_values, min_periods, center, closed): start = np.empty(num_values, dtype=np.int64) end = np.empty(num_values, dtype=np.int64) start_i = 0 for i in range(num_values): if self.use_expanding[i]: start[i] = start_i start_i = end[i] = i + 1 else: start[i] = start_i end[i] = i + self.window_size print('start', start) print('end', end) return start, end
indexer = CustomIndexer(window_size=1, use_expanding=use_expanding)
Мы помещаем класс индексатора в функцию прокрутки и вычисляем среднее значение для каждого окна. Мы также можем наблюдать за начальным и конечным индексами каждого окна.
df.rolling(indexer).mean()
2. Применение Faster Rolling
Pandas использует Cython в качестве механизма выполнения по умолчанию с применением прокатки. В pandas 1.0 мы можем указать Numba в качестве механизма выполнения и получить приличное ускорение.
Следует отметить несколько моментов:
- Необходимо установить зависимость Numba: pip install numba,
- первый раз, когда функция запускается с использованием движка Numba, будет медленным, так как Numba будет иметь некоторые накладные расходы на компиляцию функций. Однако скользящие объекты будут кэшировать функцию, и последующие вызовы будут быстрыми,
- движок Numba работает с большим количеством точек данных (например, более 1 миллиона),
- необработанный аргумент должен быть установлен в True, что означает, что функция будет получать numpy объектов вместо серии pandas для достижения лучшей производительности.
Давайте создадим DataFrame с 1 миллионом значений.
df = pd.DataFrame({"col1": pd.Series(range(1_000_000))})
df.head()
some_function вычисляет сумму значений и добавляет 5.
def some_function(x):
return np.sum(x) + 5
Давайте измерим время выполнения с помощью механизма выполнения Cython.
%%timeit
df.col1.rolling(100).apply(some_function, engine='cython', raw=True)
4.03 s ± 76.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Cython потребовалось 4,03 секунды для вычисления функции. Нумба быстрее? Давай попробуем.
%%timeit
df.col1.rolling(100).apply(some_function, engine='numba', raw=True)
500 ms ± 11.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Мы видим, что на этом игрушечном примере Numba работает в 8 раз быстрее.
3. Новое значение NA
pandas 1.0 представляет новое экспериментальное значение pd.NA для представления скалярных пропущенных значений.
Я знаю, о чем вы думаете - еще одно нулевое значение? Уже есть nan, None и NaT!
Цель pd.NA - обеспечить согласованность между типами данных. В настоящее время он используется типами данных Int64, boolean и new string.
Давайте создадим серию целых чисел с параметром None.
s = pd.Series([3, 6, 9, None], dtype="Int64")
s
Что меня удивляет, так это то, что NA == NA дает NA, а np.nan == np.nan дает False.
s.loc[3] == s.loc[3]
# output<NA>
np.nan == np.nan
# outputFalse
4. Новый тип String
В pandas 1.0 наконец-то есть специальный (экспериментальный) строковый тип. До версии 1.0 строки хранились как объекты, поэтому мы не могли быть уверены, содержит ли серия только строки или она смешана с другими типами данных, как я демонстрирую ниже.
s = pd.Series(['an', 'ban', 'pet', 'podgan', None])
s
Сохранение строк в виде объектов становится проблемой, когда мы непреднамеренно смешиваем их с целыми числами или числами с плавающей запятой - тип данных остается объектом.
s = pd.Series(['an', 'ban', 5, 'pet', 5.0, 'podgan', None])
s
Чтобы протестировать новую строку dtype, нам нужно установить dtype = ’string’.
Новый строковый тип данных возвращает исключение с целыми числами или числами с плавающей запятой в серии. Отличное улучшение!
s = pd.Series(['an', 'ban', 'pet', 'podgan', None], dtype='string')
s
5. Игнорировать индекс в отсортированном DataFrame.
Когда мы сортируем DataFrame по определенному столбцу, индекс также сортируется. Иногда мы этого не хотим. В pandas 1.0 функция sort_values принимает индекс игнорирования, что соответствует названию аргумента.
df = pd.DataFrame({"col1": [1, 3, 5, 2, 3, 7, 1, 2]})
df.sort_values('col1')
df.sort_values('col1', ignore_index=True)
Заключение
Это были 5 самых интересных функций панд, основанные на моем мнении. В долгосрочной перспективе новый NA для отсутствующих значений может внести большую ясность в pandas. Например. как функции обрабатывают пропущенные значения, пропускают они их или нет.
Также изменилась политика устаревания:
- устаревшие версии будут добавлены в второстепенные выпуски (например, 1.1.0),
- устаревшие и критические изменения API будут применяться в основных выпусках (например, 2.0.0). Стоит ли нам обновлять или оставаться с текущей версией pandas
Новая политика устаревания ставит вопрос: Следует ли мне обновлять панды? легче ответить. Также кажется, что в будущем мы можем ожидать более частых крупных выпусков. Чтобы узнать больше о новых функциях в pandas 1.0, прочтите Что нового в 1.0.0.
Прежде чем ты уйдешь
Следуйте за мной в Twitter, где я регулярно пишу твиты о Data Science и машинном обучении.