読者です 読者をやめる 読者になる 読者になる

eizoo3010の日記

社畜の備忘録

■点列の補間

Python ql R

ある点列があってその間の値をどうにかして求めるいわゆる内挿を行いたい。できれば外挿まで簡単にできると嬉しい。

線形補間やスプライン補間ぐらいだったらscipy初めいろんなライブラリに実装されているけど、

他の補間方法を使いたい時もある。そんな時に以下のコードが役に立つかもしれない。

import QuantLib as ql
import numpy as np
import matplotlib.pyplot as plt
def interpolate(x, y, target, type):
  funct = type(x, y)
  return map(lambda target_: funct(target_, True), target)

if __name__ == '__main__':
  dict = {"BackwardFlatInterpolation"      : ql.BackwardFlatInterpolation,
          "ForwardFlatInterpolation"       : ql.ForwardFlatInterpolation,
          "LinearInterpolation"            : ql.LinearInterpolation,
          "LogLinearInterpolation"         : ql.LogLinearInterpolation,
          "CubicNaturalSpline"             : ql.CubicNaturalSpline,
          "LogCubicNaturalSpline"          : ql.LogCubicNaturalSpline,
          "MonotonicCubicNaturalSpline"    : ql.MonotonicCubicNaturalSpline,
          "MonotonicLogCubicNaturalSpline" : ql.MonotonicLogCubicNaturalSpline,
          "KrugerCubic"                    : ql.KrugerCubic,
          "KrugerLogCubic"                 : ql.KrugerLogCubic,
          "Parabolic"                      : ql.Parabolic,
          "LogParabolic"                   : ql.LogParabolic,
          "MonotonicParabolic"             : ql.MonotonicParabolic,
          "MonotonicLogParabolic"          : ql.MonotonicLogParabolic,
          "FritschButlandCubic"            : ql.FritschButlandCubic,
          "FritschButlandLogCubic"         : ql.FritschButlandLogCubic}
  x = np.linspace(1, 10, 10).tolist()
  y = (np.sin(x) + 10).tolist()
  target = np.linspace(1, 11, 200).tolist()
  plt.plot(x, y, "ro", markersize=8)
  for key in dict.keys():
    plt.plot(target, interpolate(x, y, target, dict[key]))
  label = dict.keys(); label.insert(0, "raw data")
  plt.legend(label, "lower left")

f:id:eizoo3010:20151107231122p:plain
いちいちtolist()してるのは、そうしないと受け付けてくれないから。あと外挿フラグをTrueにしとくと外挿もいける。

直近の値の横置きで補間するBackwardFlatInterpolationとかはよく使うと思われる。

BicubicSplineとかBilinearInterpolationを使えば2次元の補間もできるし、

ボラティリティサーフェスに特化した補間もあるのでその辺はC++のソース読むと良い。




Rで同じようなことするには以下のようなコードを書くもんだと思ってるんだけど、補間手法別に

異なる型を指定しないといけなくてうまい書き方が思いついていない・・・。

#include <Rcpp.h>
#include <ql/math/all.hpp>
using namespace Rcpp;
using namespace QuantLib;
// [[Rcpp::depends(RQuantLib)]]
// [[Rcpp::plugins(openmp, cpp11)]]

template <typename T>
NumericVector interpolate(const NumericVector &x, const NumericVector &y, 
                          const NumericVector &target) {
  std::shared_ptr<T> funct(new T(x.begin(), x.end(), y.begin()));
  NumericVector vec(target.size());
  std::transform(target.begin(), target.end(), vec.begin(),
                 [funct](double x) -> double {return funct->operator()(x, true);});
  return vec;
}

// [[Rcpp::export]]
NumericVector f(const NumericVector x, const NumericVector y,
                const NumericVector target) {
  return interpolate<CubicNaturalSpline>(x, y, target);
}