如何有效地从python中的日期中减去年份?

Posted

技术标签:

【中文标题】如何有效地从python中的日期中减去年份?【英文标题】:How to efficiently subtract years from dates in python? 【发布时间】:2022-01-09 23:28:29 【问题描述】:

我在 Python 中从 date column 减去 years,感觉比 R 慢很多,通常情况并非如此,所以我想知道在 python 中是否有更快/更有效的方法?

(在 R 工作多年后,我将回到 python,所以我的 Python 技能不再好,正在寻找 Python 中的代码优化)。

python代码:

import numpy as np
import pandas as pd
import datetime as dt

import time

我在下面显示的数据只是用来说明我正在使用的date format行数在我的原始数据中是:466285)。

df = pd.DataFrame('date_str': ['Apr-84','Mar-66','May-85'])

df['date'] = pd.to_datetime(df['date_str'], format = '%b-%y')

由于我在年份方面得到了一些错误的日期,例如 year: 2066, 2085 等,所以写了一个小函数来根据我的需要更正日期:

# year subtraction function
def date_correction(x):
    if x > pd.to_datetime('2017-12-01'):
        x = (x - pd.to_timedelta(100 * 365.24, unit='d')) 
    else:
        x = x
        
    return x

start = time.time()
df['date'] = df['date'].apply(date_correction)
end = time.time()

print("Time taken: ", end - start)

Time taken: 32.958526611328125

我认为时间以秒为单位,因为完成此过程花费了很多时间,这使我也不得不在 R 中计时。

R代码:

library(tidyverse)
library(lubridate)
library(microbenchmark)
df = data.frame(date_str = c('Apr-84','Mar-66','May-85'))

df <- df %>% 
  mutate(date = lubridate::my(date_str)) 

减法和时间运算:

mbm <- microbenchmark( 'date_subt' = 
  df <- df %>% 
        mutate(date = if_else( 
                                         df$date > ymd('2017-12-01'),
                                         df$date %m-% years(100),
                                         df$date
                                        ))
                                      
                      )
mbm

结果:

Unit: milliseconds

expr      min      lq       mean     median    uq       max      neval
date_subt 324.3357 331.2416 372.4745 338.8745  396.3026 744.4625 100
autplot(mbm)

【问题讨论】:

我能看到的第一个优化是在函数之外计算 2017-12-01 和 100 年的日期时间对象。这样做会使计算速度提高 10 倍左右(使用数据框中的 100000 个元素进行测试)。 我只是在 python 中寻找 vectorized 方法,因为 R & python 时间执行存在巨大差异,这让我对我的方法感到好奇。 【参考方案1】:

您可以尝试使用 timedelta 运行您的代码吗?

像这样:

from datetime import timedelta
if dt > pd.to_datetime('2017-12-01'):
    dt -= timedelta(years=100)

【讨论】:

我在尝试 dt -= timedelta(years=100) 时遇到错误,因为没有参数年,所以尝试使用天数:x -= dt.timedelta(days=100 * 365.24) 又花了 Time taken: 32.42573404312134 秒。感谢您向我建议这种方法,但这也比 R 操作慢很多 好吧.. 我认为 Corralien 方法是最佳实践【参考方案2】:

使用布尔掩码和DateOffset的矢量化方式:

df.update(df.loc[df['date'] > '2017-12-01', 'date'] - pd.DateOffset(years=100)

更简洁的方式(不带update

df.loc[df['date'] > '2017-12-01', 'date'] -= pd.DateOffset(years=100)

【讨论】:

谢谢@Corralien,我想通过使用.apply() 我已经在python 中对其进行了矢量化,但我想我错了。再次感谢分享代码。感谢您的帮助! 不幸的是,apply 是一种方便的循环方式(几乎) 是的,你是对的!! 这次花了Time taken: 0.00697779655456543 秒。

以上是关于如何有效地从python中的日期中减去年份?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Java 8 Date API 中的回历日期中减去回历年份

如何从python中的日期时间索引中减去半秒? [复制]

如何解析日期以获取 Python 中的年份 [重复]

如何减去年份?

python - 如何将带有年份的周数转换为python pandas中的日期时间格式?

C# - 获取两个日期然后只减去年份[重复]