Ускорьте функцию apply в pandas (python)

#python #pandas

Вопрос:

Я работаю с фреймом данных, содержащим дату в строковом формате. Даты выглядят так: 19620201, так что сначала год, затем месяц, затем день.

Я хочу преобразовать эти даты в дату и время. Я пытался использовать это: pd.to_datetime(df.Date)

Но это не работает, потому что у какой-то даты есть день до «00», иногда это месяц, а иногда даже год.

Я не хочу отказываться от этих дат, потому что у меня все еще есть годы или месяцы.

Поэтому я попытался написать функцию, подобную этой:

 def handle_the_00_case(date):
    try:
        if date.endswith("0000"):
            return pd.to_datetime(date[:-4], format="%Y")
        elif date.endswith("00"):
            return pd.to_datetime(date[:-2], format="%Y%m")

        return pd.to_datetime(date, format="%Y%m%d")
    except ValueError:
        return
 

И используйте следующее утверждение:
df.Date.apply(handle_the_00_case)

Но это действительно слишком долго для вычислений.

У вас есть идеи о том, как я могу улучшить скорость этого ? Я попробовал библиотеку np.vectorize() и более быструю библиотеку, но это не работает, я знаю, что должен изменить способ написания функции, но я не знаю как.

Спасибо, если вы можете мне помочь ! 🙂

Ответ №1:

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

 date = df['Date'].str.replace('0000


Комментарии:

1. Да, спасибо тебе ! Я только что попробовал, на данный момент это самый быстрый метод, который я пробовал. Это действительно здорово работает ! Большое вам спасибо :)

2. @ClementHuriaux - Что такое время в ваших данных? Это быстрее, как np.where ?

3. @jezrael Да, это так, если я возьму время инициализации (я имею в виду назначение d1, d2 и т.д.). np.where намного быстрее вычисляется (4,9 мс), но общее время составляет 2,8 с, когда я использовал все время. Решение Даниэля требует больше времени для вычислений, но в конце общее время составляет 1,6 с, так что это немного быстрее

Ответ №2:

Первая идея состоит в том, чтобы использовать векторизованное решение с пропуском столбца в to_datetime и генерированием выходного столбца с помощью numpy.where :

 d1 = pd.to_datetime(df['Date'].str[:-4], format="%Y", errors='coerce')
d2 = pd.to_datetime(df['Date'].str[:-2], format="%Y%m", errors='coerce')
d3 = pd.to_datetime(df['Date'], format="%Y%m%d", errors='coerce')

m1 = df['Date'].str.endswith("0000")
m2 = df['Date'].str.endswith("00")

df['Date_out'] = np.where(m1, d1, np.where(m2, d2, d3)) 
 

Комментарии:

1. Большое вам спасибо, это так хорошо работает. Только что попробовал свои 650000 строк. С применением потребовалось 67 секунд. С np.где это заняло 4,9 мс. Я собираюсь прочитать документы о np.куда идти дальше. Еще раз большое вам спасибо ! 🙂

,'0101')
date = date.str.replace('00

Комментарии:

1. Да, спасибо тебе ! Я только что попробовал, на данный момент это самый быстрый метод, который я пробовал. Это действительно здорово работает ! Большое вам спасибо 🙂

2. @ClementHuriaux - Что такое время в ваших данных? Это быстрее, как np.where ?

3. @jezrael Да, это так, если я возьму время инициализации (я имею в виду назначение d1, d2 и т.д.). np.where намного быстрее вычисляется (4,9 мс), но общее время составляет 2,8 с, когда я использовал все время. Решение Даниэля требует больше времени для вычислений, но в конце общее время составляет 1,6 с, так что это немного быстрее

Ответ №2:

Первая идея состоит в том, чтобы использовать векторизованное решение с пропуском столбца в to_datetime и генерированием выходного столбца с помощью numpy.where :


Комментарии:

1. Большое вам спасибо, это так хорошо работает. Только что попробовал свои 650000 строк. С применением потребовалось 67 секунд. С np.где это заняло 4,9 мс. Я собираюсь прочитать документы о np.куда идти дальше. Еще раз большое вам спасибо ! 🙂

,'01')
date = pd.to_datetime(date, format="%Y%m%d")

Комментарии:

1. Да, спасибо тебе ! Я только что попробовал, на данный момент это самый быстрый метод, который я пробовал. Это действительно здорово работает ! Большое вам спасибо 🙂

2. @ClementHuriaux — Что такое время в ваших данных? Это быстрее, как np.where ?

3. @jezrael Да, это так, если я возьму время инициализации (я имею в виду назначение d1, d2 и т.д.). np.where намного быстрее вычисляется (4,9 мс), но общее время составляет 2,8 с, когда я использовал все время. Решение Даниэля требует больше времени для вычислений, но в конце общее время составляет 1,6 с, так что это немного быстрее

Ответ №2:

Первая идея состоит в том, чтобы использовать векторизованное решение с пропуском столбца в to_datetime и генерированием выходного столбца с помощью numpy.where :


Комментарии:

1. Большое вам спасибо, это так хорошо работает. Только что попробовал свои 650000 строк. С применением потребовалось 67 секунд. С np.где это заняло 4,9 мс. Я собираюсь прочитать документы о np.куда идти дальше. Еще раз большое вам спасибо ! 🙂