如何用Pythonic方式将Pandas Datetime索引转换为分类变量?
优雅实现基于Pandas Datetime索引的分类变量创建
你原来的字典+lambda思路方向没错,但问题出在字典的键不能直接用lambda函数——map会把每个日期对象和lambda对象本身做匹配,而不是执行lambda的判断逻辑,所以才会失败。下面给你几个更Pythonic、高效的实现方案:
方案1:用pd.cut()(最简洁高效)
pd.cut()是Pandas专门用于分箱的工具,天生适合这种按时间区间分类的场景,代码简洁且性能优异:
import pandas as pd # 创建日期序列 date_series = pd.date_range(start='2010-12-31', end='2018-12-31', freq='M') # 定义时间区间边界和对应标签 bins = [pd.Timestamp('2000-01-01'), pd.Timestamp('2012-01-01'), pd.Timestamp('2014-01-01'), pd.Timestamp('2020-01-01')] labels = ['before 2012', '2012 - 2014', 'after 2014'] # 生成分类结果,include_lowest确保左边界被包含 regime = pd.cut(date_series, bins=bins, labels=labels, include_lowest=True) # 组合成目标数据集 df = pd.DataFrame({'date': date_series, 'regime': regime}) # 查看部分结果 print(df.head())
输出示例:
date regime 0 2010-12-31 before 2012 1 2011-01-31 before 2012 2 2011-02-28 before 2012 3 2011-03-31 before 2012 4 2011-04-30 before 2012
方案2:用np.select()(灵活处理复杂条件)
如果你的时间区间逻辑更复杂(比如非连续区间、特殊规则),np.select()会更灵活,它支持定义多组条件与对应结果:
import pandas as pd import numpy as np date_series = pd.date_range(start='2010-12-31', end='2018-12-31', freq='M') # 定义条件列表和对应的结果列表 conditions = [ date_series < '2012-01-01', (date_series >= '2012-01-01') & (date_series < '2014-01-01'), date_series >= '2014-01-01' ] choices = ['before 2012', '2012 - 2014', 'after 2014'] # 匹配条件生成分类结果 regime = np.select(conditions, choices) # 组合成数据集并查看指定行 df = pd.DataFrame({'date': date_series, 'regime': regime}) print(df.iloc[[0, 28, 96]])
输出示例:
date regime 0 2010-12-31 before 2012 28 2013-04-30 2012 - 2014 96 2018-12-31 after 2014
补充:为什么原来的方法失效?
你之前的字典键是lambda函数对象,date_series.map(regime_splitter)会尝试把每个日期对象作为键去字典里查找,而不是执行lambda的判断逻辑,自然找不到匹配项。如果想用类似函数映射的思路,也可以封装一个简单函数用apply(),但性能不如前两种方案:
def get_regime(date): if date < '2012-01-01': return 'before 2012' elif '2012-01-01' <= date < '2014-01-01': return '2012 - 2014' else: return 'after 2014' regime = date_series.apply(get_regime)
内容的提问来源于stack exchange,提问作者dgomzi
相关产品推荐
相关产品推荐

