【问题标题】:Extracting just Month and Year separately from Pandas Datetime column从 Pandas 日期时间列中分别提取月份和年份
【发布时间】:2014-09-28 13:07:05
【问题描述】:

我有一个数据框 df,其中包含以下列:

df['ArrivalDate'] =
...
936   2012-12-31
938   2012-12-29
965   2012-12-31
966   2012-12-31
967   2012-12-31
968   2012-12-31
969   2012-12-31
970   2012-12-29
971   2012-12-31
972   2012-12-29
973   2012-12-29
...

列的元素是pandas.tslib.Timestamp。

我只想包括年份和月份。我以为会有简单的方法来做到这一点,但我想不通。

这是我尝试过的:

df['ArrivalDate'].resample('M', how = 'mean')

我收到以下错误:

Only valid with DatetimeIndex or PeriodIndex 

然后我尝试了:

df['ArrivalDate'].apply(lambda(x):x[:-2])

我收到以下错误:

'Timestamp' object has no attribute '__getitem__' 

有什么建议吗?

编辑:我有点想通了。

df.index = df['ArrivalDate']

然后,我可以使用索引重新采样另一列。

但我仍然想要一种重新配置整个列的方法。有什么想法吗?

【问题讨论】:

标签: python pandas datetime


【解决方案1】:

df['date_column'] 必须是日期时间格式。

df['month_year'] = df['date_column'].dt.to_period('M')

您还可以将D 用于Day,2M 用于2 个月等不同的采样间隔,如果有带有时间戳的时间序列数据,我们可以使用精细的采样间隔,例如45Min 45 分钟,15Min 15 分钟采样等。

【讨论】:

  • 请注意,结果列不再属于 datetime64 dtype。使用df.my_date_column.astype('datetime64[M]'),如@Juan's answer 转换为代表每个月的第一天的日期。
【解决方案2】:

然后我尝试了:

df['ArrivalDate'].apply(lambda(x):x[:-2])

我认为这里正确的输入应该是字符串。

df['ArrivalDate'].astype(str).apply(lambda(x):x[:-2])

【讨论】:

  • 这是一个可行的解决方案,但容易出错。最好是使用已经可用的库作为日期和时间
【解决方案3】:

单行:添加带有“年-月”对的列: ('pd.to_datetime'操作前先将列dtype改为date-time)

df['yyyy-mm'] = pd.to_datetime(df['ArrivalDate']).dt.strftime('%Y-%m')


相应地增加一个“年”或“月”列:

df['yyyy'] = pd.to_datetime(df['ArrivalDate']).dt.strftime('%Y')

df['mm'] = pd.to_datetime(df['ArrivalDate']).dt.strftime('%m')


【讨论】:

  • 这正是我想要的。谢谢!
  • .dt.strftime('%Y-%m') 与.dt.year + "-" + .dt.month中的切片和添加相比,速度非常慢,尤其是在数百万条记录上。
  • 好吧,这是一个有用的见解。我将它用于一些 100000 行的文件,效果很好,但它是一个有用的替代方案。
【解决方案4】:

@KieranPC's solution 是 Pandas 的正确方法,但对于任意属性不容易扩展。为此,您可以在生成器理解中使用 getattr 并使用 pd.concat 组合:

# input data
list_of_dates = ['2012-12-31', '2012-12-29', '2012-12-30']
df = pd.DataFrame({'ArrivalDate': pd.to_datetime(list_of_dates)})

# define list of attributes required    
L = ['year', 'month', 'day', 'dayofweek', 'dayofyear', 'weekofyear', 'quarter']

# define generator expression of series, one for each attribute
date_gen = (getattr(df['ArrivalDate'].dt, i).rename(i) for i in L)

# concatenate results and join to original dataframe
df = df.join(pd.concat(date_gen, axis=1))

print(df)

  ArrivalDate  year  month  day  dayofweek  dayofyear  weekofyear  quarter
0  2012-12-31  2012     12   31          0        366           1        4
1  2012-12-29  2012     12   29          5        364          52        4
2  2012-12-30  2012     12   30          6        365          52        4

【讨论】:

    【解决方案5】:

    如果你想要月份和年份的唯一对,使用 apply 非常简单。

    df['mnth_yr'] = df['date_column'].apply(lambda x: x.strftime('%B-%Y')) 
    

    在一列中输出月-年。

    之前别忘了先把格式改成日期时间,我一般都忘记了。

    df['date_column'] = pd.to_datetime(df['date_column'])
    

    【讨论】:

    • 你也可以避免使用 lambda 函数:df['month_year'] = df['date_column'].dt.strftime('%B-%Y')
    【解决方案6】:

    有两个步骤可以在不使用方法 apply 的情况下为所有数据框提取年份。

    第一步

    将列转换为日期时间:

    df['ArrivalDate']=pd.to_datetime(df['ArrivalDate'], format='%Y-%m-%d')
    

    第二步

    使用DatetimeIndex()方法提取年份或月份

     pd.DatetimeIndex(df['ArrivalDate']).year
    

    【讨论】:

      【解决方案7】:

      您可以直接访问yearmonth属性,或请求datetime.datetime

      In [15]: t = pandas.tslib.Timestamp.now()
      
      In [16]: t
      Out[16]: Timestamp('2014-08-05 14:49:39.643701', tz=None)
      
      In [17]: t.to_pydatetime() #datetime method is deprecated
      Out[17]: datetime.datetime(2014, 8, 5, 14, 49, 39, 643701)
      
      In [18]: t.day
      Out[18]: 5
      
      In [19]: t.month
      Out[19]: 8
      
      In [20]: t.year
      Out[20]: 2014
      

      结合年份和月份的一种方法是对它们进行整数编码,例如:201408 表示 2014 年 8 月。在整个列中,您可以这样做:

      df['YearMonth'] = df['ArrivalDate'].map(lambda x: 100*x.year + x.month)
      

      或其许多变体。

      不过,我不太喜欢这样做,因为它会使日期对齐和算术在以后变得很痛苦,对于那些在没有相同约定的情况下遇到您的代码或数据的其他人来说尤其痛苦。更好的方法是选择月份中的某天约定,例如最后一个非美国假日工作日或第一天等,然后将数据保留为具有所选日期约定的日期/时间格式。

      calendar 模块可用于获取特定日期的数值,例如最后一个工作日。然后你可以这样做:

      import calendar
      import datetime
      df['AdjustedDateToEndOfMonth'] = df['ArrivalDate'].map(
          lambda x: datetime.datetime(
              x.year,
              x.month,
              max(calendar.monthcalendar(x.year, x.month)[-1][:5])
          )
      )
      

      如果您碰巧正在寻找一种方法来解决将日期时间列格式化为某种字符串化表示的简单问题,那么您可以使用datetime.datetime 类中的strftime 函数,就像这样:

      In [5]: df
      Out[5]: 
                  date_time
      0 2014-10-17 22:00:03
      
      In [6]: df.date_time
      Out[6]: 
      0   2014-10-17 22:00:03
      Name: date_time, dtype: datetime64[ns]
      
      In [7]: df.date_time.map(lambda x: x.strftime('%Y-%m-%d'))
      Out[7]: 
      0    2014-10-17
      Name: date_time, dtype: object
      

      【讨论】:

      • 性能可能很差,因此最好尽可能地使用辅助函数、矢量化操作和pandas split-apply-combine 技术。我的上述建议并不意味着认可它们是您案例中性能最高的方法——只是它们在风格上是一系列案例中有效的 Pythonic 选择。
      • @KieranPC 下面的答案要快得多
      • 最好的答案显然是.. df['mnth_yr'] = df.date_column.dt.to_period('M') 来自@jaknap32
      • 你应该在df['YearMonth'] = df['ArrivalDate'].map(lambda x: 1000*x.year + x.month)中乘以100。
      • @zthomas.nc 我认为它们作为两个单独的答案可以更好地发挥作用,因为它们提供了两种截然不同的方法来解决它。
      【解决方案8】:

      从 ['2018-03-04'] 中提取年份说

      df['Year'] = pd.DatetimeIndex(df['date']).year  
      

      df['Year'] 创建一个新列。而如果你想提取月份,只需使用 .month

      【讨论】:

      • 谢谢,真的很有帮助 date_1 = pd.DatetimeIndex(df['date']) --year = date_1.year # 年份-- --month = date_1.month # 几个月-- --dy = date_1.day # 几天--
      【解决方案9】:

      感谢jaknap32,我想根据年份和月份汇总结果,所以这工作:

      df_join['YearMonth'] = df_join['timestamp'].apply(lambda x:x.strftime('%Y%m'))
      

      输出很整洁:

      0    201108
      1    201108
      2    201108
      

      【讨论】:

        【解决方案10】:

        您可以首先使用pandas.to_datetime 转换您的日期字符串,这样您就可以访问所有numpy datetime and timedelta 工具。例如:

        df['ArrivalDate'] = pandas.to_datetime(df['ArrivalDate'])
        df['Month'] = df['ArrivalDate'].values.astype('datetime64[M]')
        

        【讨论】:

        • 这对我来说非常有效,因为我正在寻找类似于 pyspark 的 trunc 的功能。 astype('datetime64[M]') 约定是否有任何文档?
        【解决方案11】:
        df['year_month']=df.datetime_column.apply(lambda x: str(x)[:7])
        

        这对我来说很好用,没想到 pandas 会将生成的字符串日期解释为日期,但是当我制作情节时,它非常清楚我的议程和正确排序的字符串 year_month ......一定要喜欢 pandas!

        【讨论】:

          【解决方案12】:

          如果您希望新列分别显示年份和月份,您可以这样做:

          df['year'] = pd.DatetimeIndex(df['ArrivalDate']).year
          df['month'] = pd.DatetimeIndex(df['ArrivalDate']).month
          

          或者...

          df['year'] = df['ArrivalDate'].dt.year
          df['month'] = df['ArrivalDate'].dt.month
          

          然后您可以将它们组合起来或按原样使用它们。

          【讨论】:

          • 有没有办法在一行中做到这一点?我想避免多次遍历同一列。
          • 使用timeit 进行的一些快速基准测试表明DatetimeIndex 方法比.map/.apply.dt 快得多。
          • 最好的答案显然是.. df['mnth_yr'] = df.date_column.dt.to_period('M') 来自@jaknap32
          • pd.Datetimeindex 究竟做了什么?
          • 我有时会这样做:df['date_column_trunc'] = df[date_column'].apply(lambda s: datetime.date(s.year, s.month, 1)
          猜你喜欢
          • 2018-10-15
          • 2021-11-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-02
          相关资源
          最近更新 更多