
在 LeetCode 等受限环境中,直接对 datetime64[ns] 列调用 .dt.to_period('M') 并赋值回原列,可能因底层 JSON 序列化时无法处理 Period 类型而触发递归溢出错误;解决方案是显式转为字符串。
在 leetcode 等受限环境中,直接对 `datetime64[ns]` 列调用 `.dt.to_period('m')` 并赋值回原列,可能因底层 json 序列化时无法处理 `period` 类型而触发递归溢出错误;解决方案是显式转为字符串。
LeetCode 的评测环境在输出结果前会调用 DataFrame.to_json(orient='split') 进行序列化,而 pandas.Period 类型(如 2018-12)在某些旧版 pandas + ujson 组合中存在序列化缺陷,导致无限递归并抛出 OverflowError: Maximum recursion level reached。这不是代码逻辑错误,而是环境兼容性问题。
根本原因在于:.dt.to_period('M') 返回的是 PeriodIndex 或 Period 类型列,该类型在 LeetCode 使用的 pandas 版本(常为 1.3–1.5)中与 to_json() 不完全兼容,尤其当列被直接赋值并参与后续自动序列化时。
✅ 正确且稳健的解决方式是:将 Period 显式转换为字符串格式 YYYY-MM,避免任何 Period 类型残留:
import pandas as pd
def monthly_transactions(transactions: pd.DataFrame) -> pd.DataFrame:
# 确保 trans_date 是 datetime 类型(LeetCode 输入可能是 object)
transactions['trans_date'] = pd.to_datetime(transactions['trans_date'])
# 转为 Period → 再转为字符串,得到 '2018-12' 这样的纯文本
transactions['trans_date'] = transactions['trans_date'].dt.to_period('M').astype(str)
return transactions
? 补充说明与最佳实践:
-
无需新建列:上述方案直接覆盖原
'trans_date'列,符合题目输出要求(仅需YYYY-MM字符串),且节省内存; -
类型安全优先:即使输入已是
datetime64[ns],显式pd.to_datetime()可增强鲁棒性(兼容object类型的日期字符串输入); -
避免
.dt.strftime('%Y-%m')? 虽然strftime也能实现,但.to_period('M').astype(str)更语义清晰(明确表达“按月截断”意图),且在时区/边界日期(如月末)处理上更可靠; -
验证示例:
data = [[121, 'US', 'approved', 1000, '2018-12-18'], [122, 'US', 'declined', 2000, '2018-12-19']] df = pd.DataFrame(data, columns=['id','country','state','amount','trans_date']) print(monthly_transactions(df)) # 输出: # id country state amount trans_date # 0 121 US approved 1000 2018-12 # 1 122 US declined 2000 2018-12
⚠️ 注意事项:
- 切勿省略
.astype(str)—— 这是规避OverflowError的关键; - 在本地开发时可能不报错,是因为本地环境的 pandas/ujson 版本或序列化配置不同,务必以 LeetCode 实际运行结果为准;
- 若需保留原始日期列,可先
copy()或新增列(如'month'),但本题标准解法推荐直接覆盖。
总结:在竞赛平台使用 pandas 处理日期格式时,应优先选择不可序列化风险低、语义明确、跨环境稳定的字符串输出路径 —— to_period('M').astype(str) 是兼顾正确性、可读性与兼容性的最优解。











