株価とかのデータ分析をしようと思ったときに、少し苦労したので備忘録も兼ねて手順を記載しておきます。
~目次~
下準備:株価データの入手サイトと方法
少し調べた感じだと、無料で入手できるのは以下のサイトがありました。
特徴を以下にざっくりまとめました。
自分は、為替データも含めて欲しかったのと、時系列データが必要だったのでinvestingから入手しました。
登録 | 時系列データ | 同一日の複数銘柄の株価取得 | データの種類 | |
investing | 必要 | 有り。過去データがあるものは数十年分まとめて取得可能 | 無し。 | かなり豊富。国内株式・海外株式だけでなく、為替やBTCもある。 |
株式投資メモ | 不要 | 有り。ただし、1年毎しかファイル取得できない。 | 無し。 | ほぼ国内株式のみ。 |
無尽蔵 | 不要 | 無し。 | 有り。過去含めて、当該日の全ての株化データの取得が可能 | 日本株に加えて、海外の主要指数などもある。 |
手順1:csvファイルをdata.frameに落とし込む
とりあえず何も考えずに、read.csvを使って読み込みます。
※stringsAsFactors = F を忘れると全てfactor型になってしまい、以下の手順がうまくいかなくなるので必ずつけてください。
以下は日経225のデータになります。
> N225<-read.csv("N225_date.csv", header=T, stringsAsFactors = F)
> head(N225)
日付け 終値 始値 高値 安値 出来高 前日比.
1 2019年01月25日 20,773.56 20,598.64 20,844.31 20,598.64 705.06M 0.97%
2 2019年01月24日 20,574.63 20,506.24 20,620.72 20,467.59 633.32M -0.09%
3 2019年01月23日 20,593.72 20,453.44 20,686.29 20,438.22 612.83M -0.14%
4 2019年01月22日 20,622.91 20,770.06 20,805.93 20,558.30 588.60M -0.47%
5 2019年01月21日 20,719.33 20,848.38 20,892.68 20,678.26 630.65M 0.26%
6 2019年01月18日 20,666.07 20,472.81 20,682.12 20,454.13 666.63M 1.29%
ぱっと見の問題は以下。
- 余計な文字が入っている(カンマ(,))ので、数字が全てcharacter型になっている
- 日付 もDate型ではなくcharacter型
- 単位(M)が入っているので変換が必要。ただ消すだけではダメ(他の行にはkやB(10^9))
- 以下のように出来高が"-"の日がある
> N225[331:333,]
日付け 終値 始値 高値 安値 出来高 前日比.
331 2017年09月25日 20,397.58 20,439.43 20,454.29 20,367.03 854.46M -0.15%
332 2017年09月24日 20,427.50 20,427.50 20,427.50 20,425.00 - 0.65%
333 2017年09月22日 20,296.45 20,413.61 20,417.07 20,249.24 984.15M -0.25%
順番に直していきます。
手順2:余計な文字の除去と数値(numeric)型への変換
初めはシェルコマンドでやろうと思ったら、カンマは、csvの区切り文字にも使われてるので、sedで消そうとすると区切り文字も消えるという問題が発覚(csvなので当たり前)。
参考:csvをテキストで読むと以下の形です。
"2019年01月25日","20,773.56","20,598.64","20,844.31","20,598.64","705.06M","0.97%"
"2019年01月24日","20,574.63","20,506.24","20,620.72","20,467.59","633.32M","-0.09%"
"2019年01月23日","20,593.72","20,453.44","20,686.29","20,438.22","612.83M","-0.14%"
なので、素直にRの関数であるgsubを使います。gsubは特定の文字列を別の文字列に変換する関数で、使い方は以下です。
gsub(pattern, replacement, x, ignore.case = FALSE, perl = FALSE,
fixed = FALSE, useBytes = FALSE)
#シンプルに使うと以下
gsub(変更する文字列, 変換後の文字列, 対象のデータ)
今回は変換というよりは、特定文字を消去したいので変換後の文字列は""(空文字)になります。邪魔なカンマを消してやりましょう。
> N225_rev1.0 <- as.data.frame(gsub(",", "", as.matrix(N225)), stringsAsFactors=F)
> N225_rev1.0[,2:5] <- sapply(N225_rev1.0[,2:5], as.numeric) #型変換(character→numeric)
> class(N225_rev1.0[2,2])
[1] "numeric"
1行目でas.matrixをつけている理由は下記を参考ください。
【R言語の備忘録】data.frameでデータの置換(gsub)を行う方法について
手順3:文字列のDate型への変換
lapplyとas.Dateを組み合わせて以下のようになります。
> N225_rev1.0[1] <- lapply(N225_rev1.0[1], as.Date, format="%Y年%m月%d日")
> class(N225_rev1.0[1,1])
[1] "Date"
> N225_rev1.0[1,1]
[1] "2019-01-25"
基本的にdata.frameに直接関数を適用できません。lapplyを省くと以下のエラーになるので気をつけて下さい。
> N225_rev1.0[1] <- as.Date(N225_rev1.0[1], format="%Y年%m月%d日")
as.Date.default(x, ...) でエラー:
do not know how to convert 'x' to class “Date”
また、lapplyではなくaspplyにすると、numeric型になってしまいます。
もう一度as.DateするとDate型になりますが、あまり美しくはないですね。
> head(sapply(N225_rev1.0[1], as.Date, format="%Y年%m月%d日"))
日付け
[1,] 17921
[2,] 17920
[3,] 17919
[4,] 17918
[5,] 17917
[6,] 17914
> as.Date(head(sapply(N225_rev1.0[1], as.Date, format="%Y年%m月%d日")))
[1] "2019-01-25" "2019-01-24" "2019-01-23" "2019-01-22" "2019-01-21" "2019-01-18"
おまけ:サンプルコード
単位が文字列の修正や、出来高の-の修正もあるのですが、それらも含めたコードを最後に載せておきます。
簡単なものなので、ご自由にお使いください。
read_stock_csv <- function(Filename){
library(stringr)
N225<-read.csv(Filename, header=T, stringsAsFactors=F)
#余分な文字を削除。
N225 <- as.data.frame(gsub(",|K|%", "", as.matrix(N225)), stringsAsFactors=F)#"%"は前日比のをついでに消す
#csvファイルに"出来高"がある場合、単位を修正する。全て"k(10^3)"にしています。
if("出来高" %in% colnames(N225)){
for (i in 1:length(N225$出来高)){
if(str_sub(N225$出来高[i],-1) == "M"){
#str_subで単位以外(最後の文字)の値を抽出して、それをnumericにして、1000をかける
N225$出来高[i] <- as.numeric(str_sub(N225$出来高[i],1,-2))*1000
}
if(str_sub(N225$出来高[i],-1) == "B"){
#str_subで単位以外(最後の文字)の値を抽出して、それをnumericにして、1000000をかける
N225$出来高[i] <- as.numeric(str_sub(N225$出来高[i],1,-2))*1000000
}
}
}
#日付型への変換
N225[1] <- lapply(N225[1], as.Date, format="%Y年%m月%d日")
#出来高が"-"の日があるので、as.numeric用に-1に変換
N225[,-1] <- as.data.frame(gsub("-", "-1", as.matrix(N225[,-1])))
#numeric型へ変換
len <- length(N225[1,])
N225[2:len] <- apply(N225[2:len],2,as.numeric)
return(N225)
}