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

如何用Power Query M对多数据子集执行线性插值生成新表?

多利率曲线线性插值的Power Query M实现方案

核心逻辑

  • 按CurveName分组,为每条曲线的原始数据单独生成完整日期序列
  • 针对每组独立执行线性插值计算,最后合并所有结果

分步实现代码

1. 按曲线分组

先将原始数据按CurveName分组,保留每组的日期和利率数据为嵌套表:

let
    源 = 你的数据源,
    // 按CurveName分组,保留每组的原始日期与利率数据
    分组处理 = Table.Group(源, {"CurveName"}, {{"原始曲线数据", each _, type table [BusinessDays=date, InterestRate=number]}})
in
    分组处理

2. 为每组生成完整日期并插值

添加自定义列,对每个嵌套表生成完整日期序列并完成线性插值:

let
    源 = 你的数据源,
    分组处理 = Table.Group(源, {"CurveName"}, {{"原始曲线数据", each _, type table [BusinessDays=date, InterestRate=number]}}),
    // 对每组曲线执行插值计算
    添加插值结果 = Table.AddColumn(分组处理, "插值后数据", (当前行) =>
        let
            原始表 = 当前行[原始曲线数据],
            // 获取当前曲线的起止日期
            起始日 = List.Min(原始表[BusinessDays]),
            结束日 = List.Max(原始表[BusinessDays]),
            // 生成起止日之间的所有日期序列
            完整日期列表 = List.Dates(起始日, Duration.Days(结束日 - 起始日) + 1, #duration(1,0,0,0)),
            完整日期表 = Table.FromList(完整日期列表, Splitter.SplitByNothing(), {"BusinessDays"}),
            // 合并原始数据与完整日期表
            合并表 = Table.FullOuterJoin(完整日期表, {"BusinessDays"}, 原始表, {"BusinessDays"}, {"BusinessDays", "原始日期", "InterestRate"}),
            // 清理冗余列并重命名
            清理列 = Table.RenameColumns(Table.RemoveColumns(合并表, {"原始日期"}), {{"BusinessDays", "BusinessDays"}}),
            // 按日期排序
            排序表 = Table.Sort(清理列, {{"BusinessDays", Order.Ascending}}),
            // 执行线性插值(Power Query内置函数,需版本支持)
            线性插值 = Table.Interpolate(sortTable, "InterestRate", InterpolationMethod.Linear)
        in
            线性插值
    ),
    // 展开插值后的嵌套表
    展开结果 = Table.ExpandTableColumn(添加插值结果, "插值后数据", {"BusinessDays", "InterestRate"}, {"BusinessDays", "InterestRate"}),
    // 按曲线名称和日期排序最终结果
    最终排序 = Table.Sort(展开结果, {{"CurveName", Order.Ascending}, {"BusinessDays", Order.Ascending}})
in
    最终排序

3. 兼容低版本的手动插值逻辑

如果你的Power Query版本不支持Table.Interpolate,可以替换为手动计算逻辑:

// 替换上述代码中的"线性插值"步骤
// 填充前后非空值
  填充前后值 = Table.FillDown(排序表, {"InterestRate"}),
  填充后前值 = Table.FillUp(填充前后值, {"InterestRate"}),
  // 获取所有非空利率的行索引和对应值
  非空行索引 = List.PositionOf(填充后前值[InterestRate], each _ <> null, Occurrence.All),
  非空利率值 = List.RemoveNulls(填充后前值[InterestRate]),
  非空日期 = List.RemoveNulls(填充后前值[BusinessDays]),
  // 遍历每行计算插值
  手动插值 = Table.FromRecords(List.Transform(Table.ToRecords(填充后前值), (行) =>
      if row[InterestRate] <> null then row
      else
          let
              当前日期 = row[BusinessDays],
              // 找到当前日期前后最近的非空日期索引
              前索引 = List.Last(List.Select(非空行索引, each _ < List.PositionOf(填充后前值[BusinessDays], 当前日期))),
              后索引 = List.First(List.Select(非空行索引, each _ > List.PositionOf(填充后前值[BusinessDays], 当前日期))),
              前日期 = 非空日期{前索引},
              后日期 = 非空日期{后索引},
              前利率 = 非空利率值{前索引},
              后利率 = 非空利率值{后索引},
              // 计算线性插值
              插值结果 = 前利率 + (后利率 - 前利率) * Duration.Days(当前日期 - 前日期) / Duration.Days(后日期 - 前日期)
          in
              Record.ReplaceFields(row, {"InterestRate", 插值结果})
  ))

结果验证

处理完成后,每条CurveName会包含从其首个BusinessDay到最后一个BusinessDay的所有日期的插值利率值,可匹配示例中3条曲线总计820行、SOFR曲线376行的输出要求。

内容的提问来源于stack exchange,提问作者C H

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 04:47:10