如何在Python中按指定天级时间差高效移动DataFrame中的年度营收列?
高效实现基于天级时间差的营收列数值转移
看起来你需要根据每行的Time Shift天数,将某年度的营收按比例拆分到下一年度。这里提供一个向量化、高效的pandas解决方案,避免逐行循环,适合处理大规模数据。
核心思路
- 从「基准发布日期」提取源年份(即需要拆分营收的年度)
- 计算转移比例:
Time Shift / 365(按平年计算,若需兼容闰年可调整逻辑) - 批量计算各行列的转移金额,同步更新源年份列和目标年份列(源年份+1)
代码实现
首先导入pandas并读取你的输入数据:
import pandas as pd # 构造输入数据 data = [ ["2022-06-01", "2022-06-01", 4, 0, 0, 115.98, 122.93, 119.22, 35.31], ["2025-02-01", "2025-02-01", 4, 0, 0, 0, 0, 0, 66.18859318], ["2022-09-01", "2022-09-01", 4, 49.42, 254.86, 191.12, 248.80, 206.53, 98.22], ["2025-01-01", "2025-01-01", 4, 0, 0, 0, 0, 14.47, 54.24], ["2022-06-01", "2022-06-01", 4, 0, 0, 50.25, 53.26, 51.65, 15.30], ["2025-02-01", "2025-02-01", 4, 0, 0, 0, 0, 0, 28.67], ["2022-09-01", "2022-09-01", 4, 148.20, 758.22, 535.45, 676.73, 545.42, 251.83], ["2025-01-01", "2025-01-01", 4, 0, 0, 0, 0, 38.23, 139.07], ["2022-06-01", "2022-06-01", 4, 0, 0, 140.78, 144.88, 136.41, 39.23] ] cols = ["发布日期", "基准发布日期", "Time Shift", "2020", "2021", "2022", "2023", "2024", "2025"] df = pd.DataFrame(data, columns=cols) # 转换日期列格式 df["基准发布日期"] = pd.to_datetime(df["基准发布日期"])
接下来执行核心转移逻辑:
# 1. 提取源年份(基准发布日期所在年份) df["源年份"] = df["基准发布日期"].dt.year.astype(str) # 2. 计算转移比例 df["转移比例"] = df["Time Shift"] / 365 # 3. 批量计算转移金额 # 获取源列对应的营收金额 df["源列金额"] = df.lookup(df.index, df["源年份"]) # 计算需要转移的金额 df["转移金额"] = df["源列金额"] * df["转移比例"] # 4. 批量更新源列和目标列(优化版:按年份分组更新,减少循环次数) unique_src_years = df["源年份"].unique() for src_year in unique_src_years: target_year = str(int(src_year) + 1) # 跳过目标年份不存在的情况(比如2025的下一年2026不在列中) if target_year not in df.columns: continue # 筛选当前源年份的行 mask = df["源年份"] == src_year # 批量更新数值 transfer_amount = df.loc[mask, src_year] * df.loc[mask, "转移比例"] df.loc[mask, src_year] -= transfer_amount df.loc[mask, target_year] += transfer_amount # 可选:删除中间辅助列,保持数据整洁 df = df.drop(["源年份", "转移比例", "源列金额", "转移金额"], axis=1)
效果验证
以第一行为例,处理后:
- 2022列的数值变为:
115.98 - (115.98 * 4/365) ≈ 114.71 - 2023列的数值变为:
122.93 + (115.98 * 4/365) ≈ 124.20
和你举例的1.27转移金额完全一致(115.98*4/365≈1.27)。
边界情况处理
如果基准发布日期是2025年,目标年份2026不在你的DataFrame列中,可根据业务需求选择:
- 忽略该转移(如上述代码逻辑)
- 新增2026列并初始化为0后再执行转移
- 将转移金额保留在2025列中(若业务允许)
内容的提问来源于stack exchange,提问作者akash bais




