Rを使ったたくさんの系列に対する相関分析

たくさんの系列に対して相関を計算したいということがあります。
たとえば商品000から商品999までの1000種類の商品の売上データが日次であったときに、どの商品の組み合わせが売上に相関があるのかが分かれば、売上の構造を理解する上で役に立つでしょう。
業務上この種の分析をする必要があって、少し工夫が必要だったのでtipsとしてメモを残しておきます。

データはみずほ銀行から取ってきた為替データを使うことにします。
様々な通貨の値動きの間にどのような相関があるのでしょうか?

quote

#R
> library(dplyr)
> library(tidyr)
> q <- read.csv("quote.csv")
> head(q)
      date    USD    GBP    EUR   CAD   CHF   SEK   DKK   NOK   AUD   NZD   ZAR    BHD IDR.100.   CNY   HKD  INR   MYR  PHP   SGD KRW.100.
1 2002/4/1 133.15 189.79 116.12 83.48 79.28 12.87 15.63 15.08 71.14 58.80 11.76 353.65    ***** ***** 17.07 2.73 ***** 2.61 72.21    10.12
2 2002/4/2 133.20 191.78 117.18 83.38 80.15 13.00 15.77 15.24 71.02 58.86 11.78 353.78    ***** ***** 17.08 2.73 ***** 2.62 72.18    10.12
3 2002/4/3 133.20 191.26 116.96 83.65 80.02 12.95 15.75 15.23 71.14 58.81 11.89 353.78    ***** ***** 17.08 2.74 ***** 2.62 72.12    10.03
4 2002/4/4 133.10 191.13 117.15 83.72 80.18 12.93 15.77 15.33 70.81 58.52 12.02 353.52    ***** ***** 17.06 2.73 ***** 2.61 72.26    10.02
5 2002/4/5 132.30 189.74 116.32 82.96 79.47 12.87 15.65 15.22 70.33 58.36 11.83 351.39    ***** ***** 16.96 2.71 ***** 2.60 71.85    10.03
6 2002/4/8 131.55 188.54 115.69 82.80 79.00 12.82 15.57 15.13 69.76 57.43 11.92 349.40    ***** ***** 16.87 2.70 ***** 2.58 71.76      9.9
   THB    KWD   SAR   AED   MXN   PGK   HUF   CZK   PLN RUB TRY  X IDR.100..1 CNY.1 MYR.1 KRW.100..1  TWD
1 3.07 434.14 35.52 36.26 14.81 ***** ***** ***** *****  NA  NA NA       1.37 16.09 *****      ***** 3.82
2 3.06 435.01 35.53 36.27 14.80 ***** ***** ***** *****  NA  NA NA       1.38 16.09 *****      ***** 3.82
3 3.04 436.58 35.53 36.27 14.77 ***** ***** ***** *****  NA  NA NA       1.37 16.09 *****      ***** 3.82
4 3.05 435.11 35.50 36.24 14.75 ***** ***** ***** *****  NA  NA NA       1.37 16.08 *****      ***** 3.82
5 3.04 432.21 35.29 36.03 14.66 ***** ***** ***** *****  NA  NA NA       1.37 15.98 *****      ***** 3.80
6 3.03 429.62 35.09 35.81 14.62 ***** ***** ***** *****  NA  NA NA       1.38 15.89 *****      ***** 3.77

合計37種類の通貨の日本円に対する価格が時系列で入っています。
とりあえずdata cleansingとして、すべての値が入っていない列を除き、謎の*****をNAに置き換え、全列を数値型に変換します。
加えてなぜかCNY(人民元)とKRW100(韓国ウォン)は二列に分かれて登録されているので統合しておきます。
また役に立つのか分かりませんが日付を日付型に変えておきます。

#R
> library(magrittr)
> library(lubridate)
> q %<>% select(-IDR.100., -MYR, -X)
> q[q == "*****"] <- NA
> q %<>% mutate(date = ymd(date))
> q[(sapply(q, class) == "factor")] %<>% lapply(as.numeric)
> q %<>% mutate(KRW.100. = coalesce(KRW.100., 0) + coalesce(KRW.100..1)) %>% select(-KRW.100..1)
> q %<>% mutate(CNY = coalesce(CNY, 0) + coalesce(CNY.1, 0)) %>% select(-CNY.1)
> summary(q)
      date                 USD              GBP             EUR              CAD              CHF              SEK             DKK
 Min.   :2002-04-01   Min.   : 75.76   Min.   :117.5   Min.   : 94.23   Min.   : 70.45   Min.   : 76.16   Min.   :10.43   Min.   :12.67
 1st Qu.:2006-02-26   1st Qu.: 94.88   1st Qu.:141.4   1st Qu.:119.85   1st Qu.: 82.02   1st Qu.: 86.29   1st Qu.:12.62   1st Qu.:16.11
 Median :2010-01-27   Median :107.78   Median :174.3   Median :131.92   Median : 86.64   Median : 91.66   Median :14.21   Median :17.72
 Mean   :2010-01-25   Mean   :104.80   Mean   :172.4   Mean   :130.97   Mean   : 89.45   Mean   : 96.81   Mean   :14.10   Mean   :17.59
 3rd Qu.:2013-12-21   3rd Qu.:116.80   3rd Qu.:197.8   3rd Qu.:138.72   3rd Qu.: 96.20   3rd Qu.:106.57   3rd Qu.:15.18   3rd Qu.:18.62
 Max.   :2017-11-27   Max.   :133.20   Max.   :250.6   Max.   :169.62   Max.   :124.98   Max.   :136.89   Max.   :18.49   Max.   :22.75

      NOK             AUD              NZD             ZAR             BHD             CNY             HKD             INR
 Min.   :11.81   Min.   : 56.56   Min.   :45.28   Min.   : 6.62   Min.   :201.2   Min.   :  2.0   Min.   : 9.76   Min.   :1.400
 1st Qu.:14.17   1st Qu.: 79.09   1st Qu.:64.76   1st Qu.: 9.66   1st Qu.:252.1   1st Qu.:116.0   1st Qu.:12.24   1st Qu.:1.720
 Median :15.87   Median : 84.19   Median :74.39   Median :11.76   Median :286.4   Median :215.5   Median :13.84   Median :1.940
 Mean   :15.96   Mean   : 84.59   Mean   :73.34   Mean   :12.41   Mean   :278.5   Mean   :208.9   Mean   :13.48   Mean   :2.095
 3rd Qu.:17.06   3rd Qu.: 91.52   3rd Qu.:81.15   3rd Qu.:15.99   3rd Qu.:310.7   3rd Qu.:288.0   3rd Qu.:15.02   3rd Qu.:2.500
 Max.   :21.80   Max.   :107.66   Max.   :97.61   Max.   :19.69   Max.   :353.8   Max.   :479.0   Max.   :17.08   Max.   :3.070

      PHP             SGD           KRW.100.          THB             KWD             SAR             AED             MXN
 Min.   :1.740   Min.   :58.14   Min.   :  2.0   Min.   :2.420   Min.   :274.6   Min.   :20.21   Min.   :20.63   Min.   : 5.050
 1st Qu.:1.950   1st Qu.:64.71   1st Qu.:180.0   1st Qu.:2.720   1st Qu.:332.8   1st Qu.:25.31   1st Qu.:25.85   1st Qu.: 6.740
 Median :2.210   Median :70.41   Median :402.0   Median :2.910   Median :369.5   Median :28.75   Median :29.35   Median : 7.850
 Mean   :2.197   Mean   :72.26   Mean   :366.1   Mean   :3.003   Mean   :362.2   Mean   :27.96   Mean   :28.54   Mean   : 8.423
 3rd Qu.:2.362   3rd Qu.:79.25   3rd Qu.:578.0   3rd Qu.:3.230   3rd Qu.:399.0   3rd Qu.:31.17   3rd Qu.:31.81   3rd Qu.:10.310
 Max.   :2.810   Max.   :92.58   Max.   :666.0   Max.   :4.130   Max.   :436.6   Max.   :35.53   Max.   :36.27   Max.   :14.810
                                 NA's   :471
      PGK              HUF             CZK              PLN            RUB             TRY          IDR.100..1        MYR.1
 Min.   :   2.0   Min.   : 2.00   Min.   :   2.0   Min.   :   2   Min.   :1.410   Min.   :28.26   Min.   :0.760   Min.   :   2.0
 1st Qu.: 344.0   1st Qu.:11.00   1st Qu.: 204.0   1st Qu.: 384   1st Qu.:1.920   1st Qu.:39.17   1st Qu.:0.870   1st Qu.: 233.0
 Median : 610.0   Median :15.00   Median : 437.0   Median : 650   Median :2.500   Median :45.27   Median :0.960   Median : 412.0
 Mean   : 638.1   Mean   :17.31   Mean   : 467.3   Mean   : 669   Mean   :2.404   Mean   :44.00   Mean   :1.047   Mean   : 464.8
 3rd Qu.: 928.8   3rd Qu.:20.00   3rd Qu.: 627.0   3rd Qu.: 907   3rd Qu.:2.870   3rd Qu.:49.49   3rd Qu.:1.230   3rd Qu.: 709.0
 Max.   :1324.0   Max.   :45.00   Max.   :1266.0   Max.   :1453   Max.   :3.300   Max.   :58.52   Max.   :1.470   Max.   :1034.0
 NA's   :450      NA's   :1006    NA's   :1006     NA's   :1006   NA's   :2089    NA's   :2089                    NA's   :471
      TWD
 Min.   :2.510
 1st Qu.:2.947
 Median :3.390
 Mean   :3.296
 3rd Qu.:3.570
 Max.   :4.050

さて、これらの変数の相関を分析しましょう。
伝統的にはRの関数corを使って

#R
> cor(q$USD, q$EUR)
[1] 0.5968693

などと相関係数を計算するのが基本です。
相関係数は-1から+1までの値をとり、0で相関無し、プラスで正の相関(片側が増えるともう片方も増える)、マイナスで負の相関(片側が減るともう片方は減る)を表します。
MS ExcelのCORREL関数でもできます。

ペアの数がとても多いため、一つ一つ相関係数を計算していると日が暮れてしまいます。
関数corは全列についてまとめて相関係数を計算することもできます。

#R
> cor.mat <- cor(q[-1], use = "pairwise.complete.obs")
> head(cor.mat)
          USD        GBP       EUR       CAD        CHF       SEK       DKK         NOK       AUD       NZD        ZAR       BHD       CNY
USD 1.0000000 0.76205994 0.5968693 0.4394818 0.36087383 0.5586853 0.6000448 0.430630618 0.1516916 0.4825496  0.3311073 0.9999528 0.8059158
GBP 0.7620599 1.00000000 0.8494347 0.6831803 0.07097254 0.8550133 0.8514437 0.831942153 0.3543722 0.4926574  0.7406858 0.7645785 0.6181070
EUR 0.5968693 0.84943467 1.0000000 0.8409271 0.30158952 0.9292839 0.9999236 0.871721688 0.5926856 0.6445288  0.5374152 0.5990845 0.6630682
CAD 0.4394818 0.68318034 0.8409271 1.0000000 0.40409698 0.8569756 0.8377927 0.810019337 0.8263449 0.7561333  0.3997182 0.4422811 0.6397249
CHF 0.3608738 0.07097254 0.3015895 0.4040970 1.00000000 0.3146755 0.2973663 0.004469995 0.6037538 0.7613429 -0.4557025 0.3582459 0.5806195
SEK 0.5586853 0.85501331 0.9292839 0.8569756 0.31467547 1.0000000 0.9285071 0.904197421 0.7013551 0.7236436  0.5548614 0.5606035 0.5810282
          HKD        INR       PHP       SGD    KRW.100.       THB       KWD       SAR       AED        MXN       PGK        HUF       CZK
USD 0.9997775  0.6096070 0.7304784 0.5600240 -0.30656638 0.6044274 0.9671973 0.9999840 0.9999964  0.6532370 0.4886445 0.48913348 0.5259166
GBP 0.7580171  0.8776082 0.5521960 0.2794907 -0.44612393 0.4823254 0.8594739 0.7632925 0.7626140  0.8407558 0.4819123 0.86846379 0.8389925
EUR 0.5946944  0.6820544 0.5969793 0.4544359 -0.36662186 0.6443944 0.7460352 0.5978563 0.5974655  0.5776496 0.5259229 0.92395907 0.9484355
CAD 0.4405665  0.4891724 0.6712803 0.5791502 -0.42633472 0.7544195 0.5924247 0.4405225 0.4400617  0.4120189 0.7040986 0.83316707 0.8484266
CHF 0.3684809 -0.3171833 0.6689649 0.9278963 -0.07652239 0.7502027 0.3383748 0.3597361 0.3603325 -0.2877545 0.5239799 0.01975703 0.1824147
SEK 0.5556455  0.6417100 0.6038944 0.4722520 -0.32818359 0.6351107 0.7115537 0.5597420 0.5591138  0.6159664 0.6174204 0.85457022 0.8913903
          PLN        RUB        TRY IDR.100..1     MYR.1       TWD
USD 0.6246446 -0.5523782 -0.3662776  0.5611693 0.6162010 0.9291313
GBP 0.8914202 -0.1264157  0.1329910  0.7705100 0.7946820 0.6768677
EUR 0.9674216  0.0131228  0.1096664  0.4806632 0.8214926 0.6094884
CAD 0.8891701  0.2622262  0.3738414  0.3036294 0.9083139 0.5548154
CHF 0.2729844 -0.3892517 -0.2418079 -0.4188600 0.3556017 0.6015147
SEK 0.9162069  0.3072239  0.3630964  0.5267619 0.8794299 0.6193319

と、でっかい行列として相関係数が手に入ります。
オプションのuse = “pairwise.complete.obs” はNAが有ったら除いて相関係数を計算するという意味です。
このオプションを指定しなければNAが存在する列はすべてNAになります。

さて、ここまでは基本関数の機能です。
我々が知りたいのは相関係数が大きいペアが何なのかということ。
このままでは行列が大きすぎてよくわからないのでソートしたいですね。
そのためこの行列をデータフレームに変換してソートすることにします。

#R
> cor.df <- cor.mat %>% data.frame %>% mutate(x = row.names(.)) %>% gather(y, cor, -x)
> head(cor.df)
    x   y     cor
1 USD USD 1.0000000
2 GBP USD 0.7620599
3 EUR USD 0.5968693
4 CAD USD 0.4394818
5 CHF USD 0.3608738
6 SEK USD 0.5586853

これでスッキリ見やすく分析しやすくなりましたね。
あとは相関が大きなペアでソートするだけですが、自分との相関(必ず1になる)と重複するペアを除きます。

#R
> cor.df %>% filter(x > y) %>% arrange(desc(cor)) %>% head
    x   y       cor
1 USD AED 0.9999964
2 SAR AED 0.9999874
3 USD SAR 0.9999840
4 SAR BHD 0.9999622
5 BHD AED 0.9999592
6 USD BHD 0.9999528

たかっ!!

落ち着け、これは相場が管理されているに違いない。
なになにAEDはUAEディルハムで、ドルペッグ通貨と。やっぱりね。
これらは我々が知りたいものではないので除かねばならぬ。

#R
> library(ggplot2)
> cor.df %>%
   filter(x > y) %>% 
   arrange(desc(cor)) %>%
   head(50) %>%
   ggplot(aes(x = reorder(paste(x, y, sep="."), cor), y = cor))
     + geom_col()
     + theme(axis.text.x = element_text(angle = 90, hjust = 1))
相関が大きすぎる通貨たち

これによれば11位の 香港ドル×バーレーン・ディナール までが相関1に張り付いているように見えます。
よって12位の クウェート・ディナール×人民元 が通貨相関ランキングトップか?
と思いきや調べてみると人民元はドルペッグですし、クウェート・ディナールは今はドルペッグではないものの元ドルペッグという中途半端な存在みたいです。
管理するならちゃんと管理してほしい・・・
相関分析によって為替相場を分析しようするのならば管理通貨は省いて分析する必要があるみたいです。

それでは逆の相関を見てみるのはどうでしょうか。
ペッグによって為替の相関が人為的に高められることはあっても、逆相関を狙って管理することはないだろうという推測です。

#R
> library(ggplot2)
> cor.df %>%
   filter(x > y, !is.na(cor)) %>% 
   arrange(desc(cor)) %>%
   tail(20) %>%
   ggplot(aes(x = reorder(paste(x, y, sep="."), cor), y = cor)) +
     geom_col() +
     theme(axis.text.x = element_text(angle = 90, hjust = 1))
             x        y        cor
477        PGK KRW.100. -0.3763303
478   KRW.100.      HUF -0.3878410
479        RUB      CHF -0.3892517
480        NOK KRW.100. -0.3921878
481   KRW.100.      CNY -0.3932136
482   KRW.100.      INR -0.4140101
483        TWD      RUB -0.4163571
484        PLN KRW.100. -0.4175296
485 IDR.100..1      CHF -0.4188600
486      MYR.1 KRW.100. -0.4261504
487        RUB      KWD -0.4262207
488   KRW.100.      CAD -0.4263347
489        MXN KRW.100. -0.4344132
490   KRW.100.      GBP -0.4461239
491        ZAR      CHF -0.4557025
492        RUB      HKD -0.5487266
493        SAR      RUB -0.5523163
494        RUB      AED -0.5523384
495        USD      RUB -0.5523782
496        RUB      BHD -0.5537118

相関が小さすぎる通貨たち

逆相関も結構高い奴らがいますね。
一位はロシアルーブル × タイバーツ で相関係数は-0.55と中々高いです。
二位もロシアルーブル × 米ドル とそれ以下もロシアルーブルの登場率が高いです。
これはつまりタイバーツは日本円と相関が高く、特にロシアルーブルに対する日本円の強さと関連が強いことに由来しているのではないかと推測します。
なぜならばロシアルーブルが上がるというのはロシアルーブルに対する日本円の価値が下がっているという意味なのであって、それとタイバーツは同じ動きをするということだからです。

三位以下は米ドルペッグ通貨が並び、6位に南アランド × スイスフラン。
よくわからないのですが、スイスフランが日本円と似ており、南アランドがロシア・ルーブル的な位置づけかな?

正相関のデータよりもこっちの方が色々と示唆が得られそうですね。
私は経済学には明るくないですが、次のことを推測しました。

  • 韓国ウォン(KRW)、タイバーツ(BHD)、と一部の東アジア通貨は日本円と相関が強い。米ドル(USD)やスイスフラン(CHF)など安定通貨たちともそれなりの相関。
  • ロシアルーブル(RUB)、南アランド(ZAR)といった発展途上資源国通貨は日本円と逆相関がある。

これらのことを上記の数字だけで示すことができたとは到底思えないですが、ストーリーを作るのには役に立つかもしれないですね。

7位に韓国ウォン × 英ポンドが入っているけど、英ポンドってもはやルーブルとかランド寄りなの?ww

つづく。

コメントを残す