Использование pandas применяется со смещением дат и дат - PullRequest
3 голосов
/ 16 июня 2020

У меня есть DataFrame с датами ниже:

               Daycount   
Date                                                                       
2020-05-01         0      
2020-06-01         0        
2020-07-01         0          
2020-08-01         0         
2020-09-01         0            

Я пытаюсь извлечь количество дней с одного дня на следующий, используя следующую формулу:

def days360(start_date, end_date, method_eu=False):
        start_day = start_date.day
    start_month = start_date.month
    start_year = start_date.year
    end_day = end_date.day
    end_month = end_date.month
    end_year = end_date.year

    if start_day == 31 or (method_eu is False and start_month == 2 and (start_day == 29 or (start_day == 28 and calendar.isleap(start_year) is False))):
        start_day = 30

    if end_day == 31:
        if method_eu is False and start_day != 30:
            end_day = 1

            if end_month == 12:
                end_year += 1
                end_month = 1
            else:
                end_month += 1
        else:
            end_day = 30

    return end_day + end_month * 30 + end_year * 360 - start_day - start_month * 30 - start_year * 360

Однако Я пробовал использовать функцию apply, как показано ниже, но получаю следующую ошибку:

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

При передаче только одного набора значений в DataFrame он работает, поэтому моя формула определенно верна. Создание еще одного столбца со смещенными датами и последующее применение формулы сработало, но я ищу более чистый способ. Я не уверен насчет функции применения. Я должен получить 30 дней на весь дневной счет.

hypo["Daycount"] = hypo.apply(lambda x: days360(x.index,x.index.shift(-1)))

Целевой результат должен быть в таблице ниже:

        Date  Daycount
0 2020-05-01      30.0
1 2020-06-01      30.0
2 2020-07-01      30.0
3 2020-08-01      30.0
4 2020-09-01      30.0

Ответы [ 2 ]

1 голос
/ 16 июня 2020

Используйте, pd.to_datetime, чтобы преобразовать серию в datetime, например series, затем используйте Series.dt для доступа к свойствам datetime серии, затем используйте Series.diff по компонентам year, month и day, чтобы получить желаемые результаты:

df = df.reset_index()
dates = pd.to_datetime(df['Date'])
df['Daycount'] = (
    (dates.dt.year.diff() * 360 + dates.dt.month.diff() * 30 + dates.dt.day.diff()).fillna(0)
)

# print(df)
         Date  Daycount
0  2020-05-01       0.0
1  2020-06-01      30.0
2  2020-07-01      30.0
3  2020-08-01      30.0
4  2020-09-01      30.0

Рассмотрим другой пример с более сложным фреймом данных:

# Given dataframe
# print(df)
            Daycount
Date                
2020-05-01         0
2020-06-03         0
2020-07-01         0
2021-07-02         0
2022-08-03         0

# Desired result
# print(df)
         Date  Daycount
0  2020-05-01       0.0
1  2020-06-03      32.0
2  2020-07-01      28.0
3  2021-07-02     361.0
4  2022-08-03     391.0
0 голосов
/ 16 июня 2020

Если вы хотите использовать .apply, вам необходимо изменить свою функцию (или добавить другую на основе уже имеющейся) для работы с объектами Series (а не с их элементами). См. pandas DataFrame apply docstring «Объекты, переданные в функцию, являются объектами Series, индекс которых либо ...»

Вы можете избежать использования .apply и lambda, используя понимание списка

df['derived'] = [ yourfunction(a,b) for a,b in zip(df.index, df.index.shift(-1)) ]

Я уверен, что есть другой способ векторизовать вашу функцию, но это, по крайней мере, должно заставить ваш код работать. Было время, когда ключевое лицо python решительно возражало против лямбда-выражений, и их предлагали удалить, поскольку это всегда можно сделать другим способом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...