Python中如何将Dekad(旬)转换为起止日期并添加至DataFrame
解决方案
核心思路
Dekad(10天周期)的规则是每月3个周期:第1个周期为当月1-10日,第2个为11-20日,第3个为21日至当月月末。我们可以通过数学计算推导月份和周期段,结合pandas的日期处理能力自动生成起止日期,完全避免硬编码。
方法一:高效矢量化实现(推荐)
适合大数据量场景,无需循环或apply,性能更优:
import pandas as pd # 示例DataFrame df = pd.DataFrame({ 'CEI': [160.004352, 0.0, 0.0, 0.0, 0.0], 'Dekad': [1, 2, 3, 4, 5] }) # 1. 计算每个Dekad所属的月份和当月内的周期序号 df['month'] = (df['Dekad'] - 1) // 3 + 1 df['dekad_segment'] = (df['Dekad'] - 1) % 3 + 1 # 2. 生成起始日 df['start_day'] = df['dekad_segment'].map({1: 1, 2: 11, 3: 21}) # 3. 生成结束日:前两个周期固定为10/20日,第三个周期取当月月末 df['end_day'] = df['dekad_segment'].map({1: 10, 2: 20}) # 针对第三个周期,获取对应月份的总天数作为结束日 mask = df['dekad_segment'] == 3 df.loc[mask, 'end_day'] = pd.to_datetime(df.loc[mask, 'month'], format='%m').dt.days_in_month # 4. 构造起止日期并拼接成目标字符串(这里默认年份为2023,可按需修改) target_year = 2023 df['start_date'] = pd.to_datetime(f"{target_year}-" + df['month'].astype(str) + "-" + df['start_day'].astype(str)) df['end_date'] = pd.to_datetime(f"{target_year}-" + df['month'].astype(str) + "-" + df['end_day'].astype(str)) df['date_range_dekad'] = df['start_date'].dt.strftime('%Y-%m-%d') + ' 至 ' + df['end_date'].dt.strftime('%Y-%m-%d') # 清理中间辅助列 df.drop(['month', 'dekad_segment', 'start_day', 'end_day', 'start_date', 'end_date'], axis=1, inplace=True) print(df)
执行后输出结果:
CEI Dekad date_range_dekad 0 160.004352 1 2023-01-01 至 2023-01-10 1 0.000000 2 2023-01-11 至 2023-01-20 2 0.000000 3 2023-01-21 至 2023-01-31 3 0.000000 4 2023-02-01 至 2023-02-10 4 0.000000 5 2023-02-11 至 2023-02-20
方法二:自定义函数+apply实现(适合小数据量/逻辑更直观)
如果数据量不大,用apply结合自定义函数更易理解和调试:
import pandas as pd from datetime import datetime, timedelta def get_dekad_range(dekad_num, year=2023): # 计算所属月份 month = (dekad_num - 1) // 3 + 1 # 计算当月内的周期序号 segment = (dekad_num - 1) % 3 + 1 if segment == 1: start, end = 1, 10 elif segment == 2: start, end = 11, 20 else: # 获取当月最后一天 last_day = datetime(year, month, 1) + pd.DateOffset(months=1) - timedelta(days=1) start, end = 21, last_day.day start_date = datetime(year, month, start).strftime('%Y-%m-%d') end_date = datetime(year, month, end).strftime('%Y-%m-%d') return f"{start_date} 至 {end_date}" # 应用到DataFrame df['date_range_dekad'] = df['Dekad'].apply(get_dekad_range)
关键说明
- 年份可按需修改:上述代码默认使用2023年,若需要动态年份,可将年份作为参数传入,或从DataFrame的其他列读取。
- 月末自动适配:通过
pd.to_datetime(...).dt.days_in_month或日期偏移计算,自动处理不同月份的天数差异(如2月的28/29天、31天的大月等)。
内容的提问来源于stack exchange,提问作者user308827
相关产品推荐
相关产品推荐

