【问题标题】:pandas: convert datetime to end-of-monthpandas:将日期时间转换为月末
【发布时间】:2013-08-14 13:28:48
【问题描述】:

我已经编写了一个函数来将 pandas 日期时间日期转换为月末:

import pandas
import numpy
import datetime
from pandas.tseries.offsets import Day, MonthEnd

def get_month_end(d):
    month_end = d - Day() + MonthEnd() 
    if month_end.month == d.month:
        return month_end # 31/March + MonthEnd() returns 30/April
    else:
        print "Something went wrong while converting dates to EOM: " + d + " was converted to " + month_end
        raise

这个功能似乎很慢,我想知道是否有更快的替代方案?我注意到它很慢的原因是我在具有 50'000 个日期的数据框列上运行它,并且我可以看到自从引入该函数以来代码要慢得多(在我将日期转换为月末之前)。

df = pandas.read_csv(inpath, na_values = nas, converters = {open_date: read_as_date})
df[open_date] = df[open_date].apply(get_month_end)

我不确定这是否相关,但我正在阅读以下日期:

def read_as_date(x):
    return datetime.datetime.strptime(x, fmt)

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    修改后,转换为句点,然后返回时间戳就可以了

    In [104]: df = DataFrame(dict(date = [Timestamp('20130101'),Timestamp('20130131'),Timestamp('20130331'),Timestamp('20130330')],value=randn(4))).set_index('date')
    
    In [105]: df
    Out[105]: 
                   value
    date                
    2013-01-01 -0.346980
    2013-01-31  1.954909
    2013-03-31 -0.505037
    2013-03-30  2.545073
    
    In [106]: df.index = df.index.to_period('M').to_timestamp('M')
    
    In [107]: df
    Out[107]: 
                   value
    2013-01-31 -0.346980
    2013-01-31  1.954909
    2013-03-31 -0.505037
    2013-03-31  2.545073
    

    请注意,这种类型的转换也可以这样完成,不过上面会稍微快一些。

    In [85]: df.index + pd.offsets.MonthEnd(0) 
    Out[85]: DatetimeIndex(['2013-01-31', '2013-01-31', '2013-03-31', '2013-03-31'], dtype='datetime64[ns]', name=u'date', freq=None, tz=None)
    

    【讨论】:

    • 这仅适用于每月有 1 个条目的情况?我不认为安妮的所有 50000 个条目都是独特的月份。 :)
    • 这就是为什么resample 可能是正确的解决方案,除非她想要复制
    • 谢谢!为什么在重新索引结束时需要.values
    • @Jeff 在第 85 行的输出在 v.17 中是否仍然正确?当我运行它时,我得到DatetimeIndex(['2012-12-31', '2012-12-31', '2013-02-28', '2013-02-28'], dtype='datetime64[ns]', name=u'date', freq=None)
    • 看来Period 类的性能非常慢...我也有一个 50k 行数据帧,df[df.period == some_period] 之类的东西大约需要 14 秒,同时遵循上述说明和转换周期回到 datetime 大约需要 0.3 秒,就像速度提高了 100 倍。什么给了?
    【解决方案2】:
    import pandas as pd
    import numpy as np
    import datetime as dt    
    
    df0['Calendar day'] = pd.to_datetime(df0['Calendar day'], format='%m/%d/%Y')
    df0['Calendar day'] = df0['Calendar day'].apply(pd.datetools.normalize_date)    
    df0['Month Start Date'] = df0['Calendar day'].dt.to_period('M').apply(lambda r: r.start_time)
    

    这段代码应该可以工作。日历日是一列,其中日期以 %m/%d/%Y 格式给出。例如:12/28/2014 是 2014 年 12 月 28 日。输出为 2014-12-01 类 'pandas.tslib.Timestamp' 类型。

    【讨论】:

    • 你用的是什么版本的 Python?
    【解决方案3】:

    如果日期不在index 中而是在另一列中(适用于 Pandas 0.25.0):

    import pandas as pd
    import numpy as np
    
    df = pd.DataFrame(dict(date = [pd.Timestamp('20130101'), 
                                   pd.Timestamp('20130201'), 
                                   pd.Timestamp('20130301'), 
                                   pd.Timestamp('20130401')], 
                           value = np.random.rand(4)))
    print(df.to_string())
    
    df.date = df.date.dt.to_period('M').dt.to_timestamp('M')
    print(df.to_string())
    

    输出:

        date     value
    0 2013-01-01  0.295791
    1 2013-02-01  0.278883
    2 2013-03-01  0.708943
    3 2013-04-01  0.483467
    
            date     value
    0 2013-01-31  0.295791
    1 2013-02-28  0.278883
    2 2013-03-31  0.708943
    3 2013-04-30  0.483467
    

    【讨论】:

      【解决方案4】:

      你也可以使用 numpy 来做的更快:

      import numpy as np
      date_array = np.array(['2013-01-01', '2013-01-15', '2013-01-30']).astype('datetime64[ns]')
      month_start_date = date_array.astype('datetime64[M]')
      

      【讨论】:

        【解决方案5】:

        如果日期列是日期时间格式并设置为月份的开始日期,这将添加一个月的时间:

        df['date1']=df['date'] + pd.offsets.MonthEnd(0) 
        

        【讨论】:

          【解决方案6】:

          您正在寻找的可能是:

          df.resample('M').last()

          @Jeff 之前说的另一种方法:

          df.index = df.index.to_period('M').to_timestamp('M')

          【讨论】:

            猜你喜欢
            • 2021-12-06
            • 2017-12-12
            • 2017-01-28
            • 1970-01-01
            • 2017-11-24
            • 2023-03-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多