今週も特にありません

進捗どうですか?

一般化線形モデル周りのRのパッケージと関数まとめ

(GLM、GLMM周りを中心に)統計モデリングのためのパッケージと関数のメモになります。使い方の詳しい説明、利用事例等を見つけたら、順次追加予定です。

lm {stats} Fitting Linear Models

線形モデル

nls {stats} Nonlinear Least Squares

非線形モデル

glm {stats} Fitting Generalized Linear Models

一般化線形モデル。線形回帰、ロジスティクス回帰、ポアソン回帰等の推定が可能。 cv.glm {boot}でクロスバリデーションを実行可能

glm.nb {MASS} Fit a Negative Binomial Generalized Linear Model

負の二項分布を仮定する場合の一般化線形モデル

gam {mgcv} Generalized additive models with integrated smoothness estimation

一般化加法モデル

gamm {mgcv} Generalized Additive Mixed Models

一般化加法混合モデル

plm {plm} Panel Data Estimators

パネルデータに対する線形モデル

polr {MASS} Ordered Logistic or Probit Regression

順序ロジット。プロビットモデルも可。polrは比例オッズモデルから来ている

mlogit {mlogit} Multinomial logit model

多項ロジットモデル。プロビットモデルも利用可能。(Kenneth Train's exercises using the mlogit package for R

mnlogit {mnlogit} Fast estimation of multinomial logit models

多項ロジットモデル。パッケージ作者による詳しい説明あり(Fast Estimation of Multinomial Logit Models: R Package mnlogit

npmlt {mixcat} Mixed effects cumulative link and logistic regression models

多項ロジットモデル

multinom {nnet} Fit Multinomial Log-linear Models

多項ロジットモデル

gmnl {gmnl} Estimate Multinomial Logit Models with Observed and Unobserved Individual Heterogeneity.

多項ロジットモデル。詳しい説明はこちら(gmnl package in R - Mauricio Sarrias

lmer {lme4} Fit Linear Mixed-Effects Models

線形混合モデル。ランダム効果を複数指定可能。Journal of Statistical Softwareにパッケージの詳しい説明あり(Fitting Linear Mixed-Effects Models Using lme4 | Bates | Journal of Statistical Software

glmer {lme4} Fitting Generalized Linear Mixed-Effects Models

一般化線形混合モデル。ランダム効果を複数指定可

nlmer {lme4} Fitting Nonlinear Mixed-Effects Models

非線形混合モデル

glmer.nb {lme4} Fitting GLMM's for Negative Binomial

負の二項分布を仮定する場合の一般化線形混合モデル

glmmML {glmmML} Generalized Linear Models with random intercept

一般化線形混合モデル。ランダム効果は一つのみ指定可

glmnet {glmnet} fit a GLM with lasso or elasticnet regularization

lasso、ridge、elastic netによる正則化付き一般化線形モデル。線形回帰、ポアソン回帰、(多項)ロジスティクス回帰等の推定が可能。group lassoなども追加されてきている。cv.glmnet {glmnet}でクロスバリデーションを実行可能

glmreg {mpath} fit a GLM with lasso (or elastic net), snet or mnet regularization

正則化付き一般化線形モデル。lasso、scad、mcpなどを用いることができる
cv.glmreg {mpath}でクロスバリデーションを実行可能

zeroinfl {pscl} Zero-inflated Count Data Regression

Zero-inflatedモデル

vglm {VGAM} Fitting Vector Generalized Linear Models

ベクトル一般化線形モデル。Version 1.0-1の時点で「Currently only fixed-effects models are implemented, i.e., no random-effects models.」ということで、ランダム効果は考慮できない。Springerの本をもとにしている(Vector Generalized Linear and Additive Models - With an Implementation in R | Thomas W. Yee | Springer

vgam {VGAM} Fitting Vector Generalized Additive Models

ベクトル一般化加法モデル

xtsでmatplotのようなプロット

最近はdplyrやtidyrとの相性で、ほぼggplot2を使うようになり、めっきりmatplotを使う機会が無くなってきています。

しかし、時系列データを扱う際にdata.frameよりもxtsを使いたい場合もあり、その時にxtsのままでmatplotのような感じのプロットするにはどうするのがいいのか?と思っていたので調べたメモします。結局、xtsとxtsExtraをセットで使うのが良さそうということがわかりました。

まず、データとして、複数時系列データをQuandlから取ってきます。この時に、Quandl関数でtypeにxtsを指定すれば、xtsクラスでデータを取って来れますが、一旦、ggplot2でプロットするためにdata.frameで取って来ることにします。

library(Quandl)

rate_df <- Quandl("MOFJ/INTEREST_RATE_JAPAN", trim_start = "2015-01-01")

このデータをggplot2でプロットします。

library(dplyr)
library(tidyr)
library(ggplot2)
library(scales)

rate_df %>% gather(maturity, rate, -Date) %>% 
  ggplot(aes(x = Date, y = rate, colour = maturity)) + geom_line(size = 1) +
  scale_x_date(labels = date_format("%m/%d"))

f:id:masaqol:20151206233544p:plain

その他、色々と付け足していけば、思いどおりのプロットができるでしょう。しかし、本題はデータをdata.frameではなくxtsクラスで扱いたい場合です。まわりくどいですが、Quandlの中でやっている処理と同じようにdata.frameからxtsに変換します。

rate_xts <- xts(rate_df[, -1], order.by = rate_df[, 1])

ここで、そのままplotすれば複数系列を一辺にプロットしてくれると思いきや、警告メッセージとともに残念なプロットがされます。

> plot(rate_xts)
Warning message:
In plot.xts(rate_xts) : only the univariate series will be plotted

f:id:masaqol:20151206234012p:plain

matplotならばどうかというと、xtsプロットの良い部分は完全に失われます。

> matplot(rate_xts, type = "l")

f:id:masaqol:20151206234802p:plain

xtsはzooクラスとしても扱えるのだから、plot.zooで良い感じにプロットされるのではないかと思い、やってみるとmatplotとほぼ変わりません…

> plot.zoo(rate_xts, plot.type = "single")

f:id:masaqol:20151206235744p:plain

というところまで試してみて、CRANには上がっていないxtsExtraを使うのが一番良さそうということが分かり、使ってみるとxtsプロットの良い部分もあり、matplotのような複数系列のプロットが簡単にできました。

library(devtools)
devtools::install_github("joshuaulrich/xtsExtra")
library(xtsExtra)

plot(rate_xts, col = 1:15)

f:id:masaqol:20151207004738p:plain

ただ、デフォルトでplotするだけでは12系列までしかプロットされないようなので、色の指定を系列数分に増やす、または、addSeriesを使って追加する必要があるようです。matplotしたものの軸ラベル等をxtsプロット風に頑張って変更するよりも、断然xtsExtraを使うのが良さそうです。

pforeachで最尤推定した漸近分布を確認する

最尤推定で推定したパラメータの漸近分布をシミュレーションによって確認する
繰り返し推定を行う際にpforeach(hoxo-m/pforeach · GitHub)を使う

CIRモデルのパラメータ推定と関数もパラメータの設定も同じとする

r0 <- 0.01
n <- 1000
delta <- 1/52
kappa <- 0.2
mu <- 0.03
sigma <- 0.08
initparam <- c(kappa, mu, sigma)

パスを発生させ、パラメータ推定を繰り返す。収束しなかったものは取り除く

ggplot2で推定したパラメータの分布をプロットしたいので、最終的にdata.frameで返ってくるようにする

.c = data.frameとして、data.frameのまま結合してもパラメータの名前がついたdata.frameが返って来なかったため、rbindで結果を結合したあとにdata.frameに変換している(これが最適な方法なのかについては…)

library(sde)
library(dplyr)
library(pforeach)

est <- pforeach(i = 1:1000, .c = rbind)({
  sde.sim(X0 = r0, N = n, delta = delta, 
          theta = c(kappa * mu, kappa, sigma), model = "CIR") %>%
  CIRMLE(initparam, delta)
}) %>% as.data.frame %>% filter(convergence != 1)

foreachの少し込み入った使い方に面倒くささを感じていたが、pforeachを使えば簡単、簡潔に記述できる

replicateを使う場合には、データを発生させて、パラメータを推定してという一連の処理を書いた関数を書いておいて、その関数を繰り返すということをしなければならないが、pforeachではループの中にザッと処理を書いておくだけで繰り返し推定が行える。返り値もあるので、その後一度に加工して扱える。素晴らしい

推定したパラメータの分布をプロットする

library(ggplot2)

ggplot(est, aes(x = kappa)) + geom_histogram(binwidth = 0.1)
ggplot(est, aes(x = mu)) + geom_histogram(binwidth = 0.005)
ggplot(est, aes(x = sigma)) + geom_histogram(binwidth = 0.0001)

平均回帰パラメータkappaの分布のみここでは確認する。推定された値の平均を計算すると真値よりも大きい値となる。そして、プロットしても上方に推定するバイアスが生じることが確認できる(TRUE = 0.2)

f:id:masaqol:20150831010738p:plain

CIRモデルのパラメータ推定

CIRモデルについてもVasicekモデルと同様にシンプルに最尤推定でモデルのパラメータを推定できる関数を用意しておく

# maximum likelihood estimation for CIR model
#
# rate      : interest rate
# param     : model parameter
# delta     : time step
# initparam : initial parameter
#
CIRloglik <- function(rate, param, delta) {
  n <- length(rate)
  c <- 4 * param[1] / (param[3] ^ 2 * (1 - exp(-param[1] * delta)))
  df <- 4 * param[1] * param[2] / (param[3] ^ 2)
  ncp <- c * rate[1:(n - 1)] * exp(-param[1] * delta)
  sum(dchisq(c * rate[2:n], df = df, ncp = ncp, log = TRUE) + log(c))
}

CIRMLE <- function(rate, initparam, delta) {
  opt <- optim(initparam, CIRloglik, rate = rate, delta = delta, control = list(fnscale = -1))
  c(kappa = opt$par[1], mu = opt$par[2], sigma = opt$par[3], loglik = opt$value, convergence = opt$convergence)
}

パラメータを設定して、パスを発生させる

library(sde)

r0 <- 0.01
n <- 500
delta <- 1/52
kappa <- 0.2
mu <- 0.03
sigma <- 0.08
initparam <- c(kappa, mu, sigma)
set.seed(12345)
rate <- sde.sim(X0 = r0, N = n, delta = delta, theta = c(kappa * mu, kappa, sigma), model = "CIR")

推定結果を確認する

> CIRMLE(rate, initparam, delta)
       kappa           mu        sigma       loglik  convergence 
2.789964e-01 6.105776e-02 8.106622e-02 2.376850e+03 0.000000e+00

初期値の与え方にもよるが、Vasicekモデルと比べて多少パラメータの推定値にバイアスが出ることになります。 特に平均回帰パラメータkappaについては上方に推定する傾向にあります

Rからアメリカ雇用統計データ収集

FXをやっている人なら誰しも気になる経済統計といえば、アメリカの雇用統計。 【米国】雇用統計 - 経済指標 - Yahoo!ファイナンスでも直近の数年間のデータを詳しく見ることができますが、簡単にRから直接データを収集して、分析したいという人はblsAPIパッケージを使ってみるのが良さそうです

こちらmikeasilva/blsAPI · GitHubにもサンプルがありますが、発表時に一番注目される非農業部門雇用者数と失業率のデータを使った例がないようなので、そのデータを取得してから可視化するところまでをメモ

使い方は簡単で、パッケージに唯一含まれているblsAPIという関数に欲しいデータのIDコードを与えてやればデータを取って来れます。その他、list形式でパラメータを指定してやれば、いろいろと自由にデータ収集可能です

library(rjson)
library(blsAPI)
library(dplyr)

payload <- list(
  'seriesid' = c('CES0000000001', 'LNS14000000'),
  'startyear' = 2007,
  'endyear' = 2015)

response <- blsAPI(payload) %>% fromJSON()

これだけで、2007年から2015年までの雇用者数と失業率のデータが取って来れます。 responseの中に2系列入っており、年月についても整形してdata.frameに変換してやります

series1 <- response$Results$series[[1]]$data
series2 <- response$Results$series[[2]]$data

date_str <- 0
value1 <- value2 <- 0
for (i in 1:length(series1)) {
  date_str[i] <- paste(series1[[i]]$year, sub('M', '', series1[[i]]$period), "01", sep = "-")
  value1[i] <- series1[[i]]$value
  value2[i] <- series2[[i]]$value
}

date <- as.Date(date_str[order(date_str)])[-1]
data1 <- diff(as.numeric(value1[order(date_str)]))
data2 <- as.numeric(value2[order(date_str)])[-1]
df <- data.frame(date, data1, data2)

データを確認します

> head(df)
        date data1 data2
1 2007-02-01    88   4.5
2 2007-03-01   188   4.4
3 2007-04-01    78   4.5
4 2007-05-01   145   4.4
5 2007-06-01    71   4.6
6 2007-07-01   -34   4.7

> tail(df)
          date data1 data2
95  2014-12-01   329   5.6
96  2015-01-01   201   5.7
97  2015-02-01   266   5.5
98  2015-03-01   119   5.5
99  2015-04-01   221   5.4
100 2015-05-01   280   5.5

前月比で雇用者数の変化を棒グラフにする

library(ggplot2)
library(scales)

df %>% ggplot(aes(x = date)) +
  geom_bar(aes(y = data1), stat = "identity", fill = "blue") + 
  theme_bw() + theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  scale_x_date(labels = date_format("%m/%y"), breaks = date_breaks("6 months")) +
  scale_y_continuous(breaks = seq(-1000, 1000, by = 200)) + ylab("1-Month Net Change")

f:id:masaqol:20150630011930p:plain

失業率もプロットする

df %>% ggplot(aes(x = date)) +
  geom_line(aes(y = data2), size = 1, colour = "red") +
  theme_bw() + theme(axis.text.x = element_text(angle = 45, hjust = 1)) + 
  scale_x_date(labels = date_format("%m/%y"), breaks = date_breaks("6 months")) + 
  scale_y_continuous(breaks = seq(0, 12, by = 1)) + ylab("Unemployment Rate")

f:id:masaqol:20150630011941p:plain

Vasicekモデルのパラメータ推定

SMFI5パッケージでもVasicekモデルのパラメータ推定はできるが、参考程度にパラメータを推定する際、シンプルに最尤推定できるものを用意しておいて、簡単に使い回せるようにしておきたい

# maximum likelihood estimation for Vasicek model
#
# rate      : interest rate
# param     : Vasicek model parameter
# delta     : time step
# initparam : initial parameter
#
Vasicekloglik <- function(rate, param, delta) {
  n <- length(rate)
  m <- param[2] + (rate[1:(n-1)] - param[2]) * exp(-param[1] * delta)
  v <- param[3]^2 * (1 - exp(-2 * param[1] * delta)) / (2 * param[1])
  sum(dnorm(rate[2:n], mean = m, sd = sqrt(v), log = TRUE))
}
  
VasicekMLE <- function(rate, initparam, delta) {
  opt <- optim(initparam, Vasicekloglik, rate = rate, delta = delta, control = list(fnscale = -1))
  c(kappa = opt$par[1], mu = opt$par[2], sigma = opt$par[3], loglik = opt$value, convergence = opt$convergence)
}

optimhessian = TRUEを足したり、2つの関数を1つにしてしまったりということもできる

sdeパッケージを使ってパスを発生させ、パラメータ推定する

library(sde)

r0 <- 0.01
n <- 500
delta <- 1/52
kappa <- 0.2
mu <- 0.03
sigma <- 0.01
initparam <- c(kappa, mu, sigma)
set.seed(123)
rate <- sde.sim(X0 = r0, N = n, delta = delta, theta = c(kappa * mu, kappa, sigma), model = "OU")

結果を確認する

> VasicekMLE(rate, initparam, delta)
       kappa           mu        sigma       loglik  convergence 
5.670395e-01 3.114274e-02 9.740629e-03 2.596687e+03 0.000000e+00 

最適化の初期値に真の値を入れていることもあり、良い値に推定できています

金利の平均回帰速度kappaはだいぶ真の値よりも上方に推定されていますが、推定バイアスを改善させましょうというような論文がいくつかありますので、この辺をじっくり読むというのも大変面白いです

Rの金利期間構造パッケージ ycinterextra

金利の期間構造関連パッケージを使ってみるシリーズ。今回はycinterextraを調査。このパッケージもこれといった情報がないので、普通にパッケージの説明書を読んで、日本の金利データに適用してみる

パッケージの中身は、CRAN Task View: Empirical Financeにも書かれている通り、Nelson-Siegelモデル等の様々なモデルでイールドカーブの補間と補外を行うことができるパッケージだと言うこと

主な関数はycinterとycextraで、その他ユーティリティ的な関数が用意されている

ycinter(yM = NULL, p = NULL, matsin, matsout,
  method = c("NS", "SV", "SW", "HCSPL"), 
  typeres = c("rates", "prices"))

ycextra(yM = NULL, p = NULL, matsin, matsout,
  method = c("NS", "SV", "SW"), 
  typeres = c("rates", "prices"), UFR, T_UFR = NULL)

ycinterとycextraともに、ゼロクーポン債価格とゼロクーポンイールドを対象としているので、クーポン債に適用したい場合にはその前に処理しておく必要がある

まず、財務省国債金利情報ページからデータを持って来る

jgbcme <- read.csv("http://www.mof.go.jp/english/jgbs/reference/interest_rate/jgbcme.csv", skip = 1)
JGB_rate <- as.numeric(jgbcme[1, -1]) / 100
maturity <- c(1:10, 15, 20, 25, 30, 40)

Nelson-SiegelモデルとSvenssonモデルをデータに適用していく

library(ycinterextra)

NSyc <- ycinter(yM = JGB_rate, matsin = maturity, matsout = 1:40, method = "NS", typeres = "rates")
SVyc <- ycinter(yM = JGB_rate, matsin = maturity, matsout = 1:40, method = "SV", typeres = "rates")

求まったパラメータの値は次の通り

> coeffs(NSyc)
[1]  0.01847065 -0.01415590 -0.03796077  3.00000000
> coeffs(SVyc)
[1]  0.02019232 -0.02168073  0.04297268 -0.07961120  2.01990134  3.00000000

3.00000000と出ていることからも上手く最適化できていない可能性が高そうです…
ycplotを使って、当てはまりの診断を見てみる

> ycplot(NSyc)
> ycplot(SVyc)

Nelson-Siegelモデル f:id:masaqol:20150430002854p:plain Svenssonモデル f:id:masaqol:20150430002905p:plain

残差が本当に正規なのというところは疑問が残るところですが、それなりに補間は上手く行っているようです

(method = "HCSPL"を指定すれば、Hermite cubic splineによる補間もできるのだが、上と同じようにしてもエラーが出てなぜか上手く適用できなかった…)

同じように補外の方も1年から60年までの設定で試してみる
ここで、UFRの値は上のパラメータの値から0.02を設定している

NSyc <- ycextra(yM = JGB_rate, matsin = maturity, matsout = 1:60, method = "NS", typeres = "rates", UFR = 0.02) 
SVyc <- ycextra(yM = JGB_rate, matsin = maturity, matsout = 1:60, method = "SV", typeres = "rates", UFR = 0.02) 

求まったパラメータの値は次の通り

> coeffs(NSyc)
[1]  0.02000000 -0.01457810 -0.04355021  3.00000000
> coeffs(SVyc)
[1]  0.02000000 -0.02162734  0.03623047 -0.07322875  1.90287193  3.00000000

やはり、上手く最適化できていないようです…

こちらもycplotで確認

> ycplot(NSyc)
> ycplot(SVyc)

Nelson-Siegelモデル f:id:masaqol:20150430005532p:plain Svenssonモデル f:id:masaqol:20150430005541p:plain

少々、簡単でしたがycinterextraパッケージの関数を使って、実際データに適用してみました。今の日本の金利データがこれらのモデルに適用するというのが難しい面もありそうですが、パラメータを求めるあたりはあまり上手くいっていないようです。このパッケージでは、これらのモデル以外にも、Smith-Wilson methodも使えるのでお手軽に試してみたいという時は良さそうです