You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决DataFrame日期列转Period('M')报错及分组聚合问题

问题:将DataFrame日期列转换为月度周期(Period('M'))并执行分组

我知道示例代码看起来效率不高,但实际场景中需要对某列应用正则函数,因此必须通过iterrows处理。现在的问题是:如何将data3 DataFrame的date列转换为Period('M')类型,以正常执行groupby操作?

相关代码

import pandas as pd
import datetime as dt
ts = dt.datetime.now()

data = pd.DataFrame({
    'status' :  ['pending', 'pending','pending'],
    'brand' : ['brand_1', 'brand_2', 'brand_3'],
    'date' : [pd.Timestamp(dt.datetime.now()),pd.Timestamp(dt.datetime.now()),pd.Timestamp(dt.datetime.now())]})

data2 = list()
for index, row in data.iterrows():
    a = row['status']
    b = row['brand']
    c = row['date'].date()
    data2.append((a,b,c))

data3 = pd.DataFrame(data=data2,columns=['status','brand','date'])

data3数据展示

status    brand        date
0  pending  brand_1  2023-08-04
1  pending  brand_2  2023-08-04
2  pending  brand_3  2023-08-04

报错的分组代码

a = data3.groupby([data3['date'].dt.to_period('M')], observed=True).aggregate({'brand':'count'})

报错信息

AttributeError                            Traceback (most recent call last)
Cell In[26], line 1
----> 1 a = data3.groupby([data3['date'].dt.to_period('M')], observed=True).aggregate({'brand':'count'})
      2 a

File c:\Users\fabio\AppData\Local\Programs\Python\Python311\Lib\site-packages\pandas\core\generic.py:5989, in NDFrame.__getattr__(self, name)
   5982 if (
   5983     name not in self._internal_names_set
   5984     and name not in self._metadata
   5985     and name not in self._accessors
   5986     and self._info_axis._can_hold_identifiers_and_holds_name(name)
   5987 ):
   5988     return self[name]
-> 5989 return object.__getattribute__(self, name)

File c:\Users\fabio\AppData\Local\Programs\Python\Python311\Lib\site-packages\pandas\core\accessor.py:224, in CachedAccessor.__get__(self, obj, cls)
    221 if obj is None:
    222     # we're accessing the attribute of the class, i.e., Dataset.geo
    223     return self._accessor
-> 224 accessor_obj = self._accessor(obj)
    225 # Replace the property with the accessor object. Inspired by:
    226 # https://www.pydanny.com/cached-property.html
    227 # We need to use object.__setattr__ because we overwrite __setattr__ on
    228 # NDFrame
...
    577 elif is_period_dtype(data.dtype):
    578     return PeriodProperties(data, orig)
-> 580 raise AttributeError("Can only use .dt accessor with datetimelike values")

AttributeError: Can only use .dt accessor with datetimelike values

问题原因

data3的date列存储的是Python原生datetime.date对象,而非pandas的datetime64类型,因此无法使用.dt访问器来转换周期。

解决方案

方案1:构建data3时保留pandas Timestamp类型

如果不需要将日期转成原生date对象,直接保留原有的pandas Timestamp:

data2 = list()
for index, row in data.iterrows():
    a = row['status']
    b = row['brand']
    c = row['date']  # 不调用.date(),保留Timestamp类型
    data2.append((a,b,c))

data3 = pd.DataFrame(data=data2,columns=['status','brand','date'])
# 直接执行分组
a = data3.groupby(data3['date'].dt.to_period('M'), observed=True).agg({'brand':'count'})

方案2:先将date列转换为pandas datetime类型

如果必须保留原生date对象的处理步骤,后续可以通过pd.to_datetime转换为pandas支持的日期类型:

# 转换date列为datetime64类型
data3['date'] = pd.to_datetime(data3['date'])
# 执行分组
a = data3.groupby(data3['date'].dt.to_period('M'), observed=True).agg({'brand':'count'})

方案3:直接将原生date对象转为Period

通过apply和pd.Period直接构造月度周期列:

# 添加月度周期列
data3['month_period'] = data3['date'].apply(lambda x: pd.Period(x, freq='M'))
# 按新列分组
a = data3.groupby('month_period', observed=True).agg({'brand':'count'})

内容的提问来源于stack exchange,提问作者FábioRB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 04:02:33