シンギュラリティ実験ノート

購入した1000ドルPCで何がどこまでできるのか実験した記録です。

株価の成長率を求めるRスクリプトが欲しくてAIに頼んでみた

LOGEST関数によるカーブフィッティングという記事で、エクセルのLOGEST関数を使い株価の成長率(年利)を求め、グラフを描く方法を紹介した。今回はRスクリプトを使う方法を紹介したい。私はRを動作させる環境は持っているが、昔使ったことがあるというレベルで、自分でコーディングする自信はない。そこでAIに頼んでみることにした。最新のAIがどこまでコーディングできるのかも評価してみたいと思ったからだ。

Windows Copilotに頼んでみた

今のWindowsには標準でCopilotが付いているのでこれを使わない手はない。私がCopilotに頼んだ内容は以下の通りだ。

Rスクリプトで以下の処理をしてください。 CSVファイルから日付(Date)と株価終値(Close)を取得します。日付はYYYY-MM-DDのフォーマットになっています。日付が取得できたら先頭データの日付からの日数を365で割って実数での年数(year)に変換します。 年数をx、株価終値をyとしてy=b*m^xの式で最小二乗法で近似して誤差が最小となるbとmを求めます。bとmが求まったら、理論値ycalcを式ycalc=b*m^xで計算し、横軸をxとしてyとycalcを折線グラフで描いてください。

Copilotが正しい答えを返してくれるよう、できる限り具体的に依頼をしたつもりだ。するとCopilotはすぐに答えを返してくれた。手順を箇条書きにまとめ、コーディングもして、最後に参考サイトも表示してくれたのだが、

エラーが発生しました

と言って回答が全て消えてしまった(泣)。

何度試してもダメなので、一旦Copilotは諦め、別のLLMでローカルPC上で試すことにした。先日動かしたllama2.cppで、ELYZA-japanese-CodeLlama-7bを使い、こちらは何とか無事に動作するRスクリプトができた。本日その結果をブログにまとめようとし、その前にもう一度だけ試してみようとCopilotに同じ仕事を発注したところ、今回はちゃんと回答が返ってきた。以下の通りである。

もちろん、Rスクリプトで株価データの処理を行います。以下がステップごとのコードです。
1. データの準備:
株価データをCSVファイルから読み込みます。日付(Date)と株価終値(Close)の2つの列が必要です。日付は「YYYY-MM-DD」のフォーマットであることを確認してください。 例えば、オルトプラス(銘柄コード:3672)の株価データを使用します。
2. 日付の処理:
日付を実数の年数(year)に変換します。先頭データの日付からの日数を365で割ります。
3. 最小二乗法で近似:
株価終値(y)を理論式 y = b * m^x で近似します。 b と m を求めるために最小二乗法を使用します。
4. 理論値の計算とグラフ描画:
求めた b と m を使って理論値 ycalc を計算します。 横軸を x として、実際の株価終値 y と理論値 ycalc を折線グラフで描画します。
以下が具体的なRスクリプトです。オルトプラスの株価データを使用していますが、他の銘柄でも同様に適用できます。

# データの準備
code <- 3672  # オルトプラスの銘柄コード
start <- 2015
end <- 2017
x <- vector("numeric")  # 日付を格納するベクトル
y <- vector("numeric")  # 株価終値を格納するベクトル

for (n in start:end) {
  file_name <- sprintf("stocks_%d-T_1d_%d.csv", code, n)
  data <- read.csv(file_name, header = TRUE, encoding = "cp932")
  a <- as.Date(data$Date, format = "%Y-%m-%d")
  x <- c(x, a)
  b <- data$Close
  y <- c(y, b)
}

# 日付の処理
x_days <- as.numeric(x - x[1])  # 先頭データからの日数

# 最小二乗法で近似
fit <- lm(log(y) ~ x_days)
b <- exp(fit$coefficients[1])
m <- fit$coefficients[2]

# 理論値の計算
ycalc <- b * m^x_days

# グラフ描画
plot(x_days, y, type = "l", col = "blue", xlab = "Days since start", ylab = "Stock Price",
     main = sprintf("Alt Plus (%d)", code))
lines(x_days, ycalc, col = "red", lty = 2)
legend("topright", legend = c("Actual Price", "Theoretical Price"), col = c("blue", "red"), lty = c(1, 2))

ご確認のうえ、慎重にご使用ください。FAQ で詳細を確認。 このスクリプトは、オルトプラスの株価データを読み込み、最小二乗法で近似した理論値と実際の株価終値をグラフで表示します。他の銘柄に適用する場合は、銘柄コードやファイル名を適宜変更してください。

この後に詳細情報として参考サイトへのリンクもあったが割愛する。

作成されたRスクリプトは、数ヶ所おかしなところはあるが、ほぼ正しい処理をしている。おかしなところを指摘すると、以下の3ヶ所くらいだ。

  1. CSVファイルからデータを取得する処理
  2. 日付のデータから年数に変換する処理
  3. 近似した結果でmを受け取る処理

ELYZAのCode-Llamaで既に動作する処理を作成していたので、修正すべき点はすぐに分かった。ここから先は私が修正することにした。完成したRスクリプトは以下である。

# データの準備
code <- "AAPL"  # アップルのティッカー
x <- vector("numeric")  # 日付を格納するベクトル
y <- vector("numeric")  # 株価終値を格納するベクトル

data <- read.csv("./AAPL.tsv", header = TRUE, encoding = "cp932", sep="\t")
a <- as.Date(data$Date, format = "%Y-%m-%d")
x <- c(x, a)
b <- data$Close
y <- c(y, b)

# 日付の処理
firstyear <- as.numeric(format(a[1], "%Y"))
x_year <- as.numeric((x - x[1]) / 365)  # 先頭データからの年数

# 最小二乗法で近似
fit <- lm(log(y) ~ x_year)
b <- exp(fit$coefficients[1])
m <- exp(fit$coefficients[2])
ratio <- (m -1) * 100

# 理論値の計算
ycalc <- b * m^x_year

# グラフ描画
plot(x_year+firstyear, y, type = "l", col = "blue", xlab = "西暦", ylab = "株価",
     main = sprintf("Appleの株価"))
lines(x_year+firstyear, ycalc, col = "red", lty = 2)
legend("topleft", legend = c(code, sprintf("R=%.1f r2=%.3f",ratio,summary(fit)$r.squared)), col = c("blue", "red"), lty = c(1, 2))

実行すると以下のグラフが表示された。

Copilot作成のRスクリプトを修正して表示したグラフ

ELYZA-japanese-CodeLlama-7bに頼んでみた

「Code Llama」をベースとした商用利用可能な日本語LLM「ELYZA-japanese-CodeLlama-7b」が公開されている。

zenn.dev

8bit量子化版も公開されているので、そちらをダウンロードし、llama.cppで実行した。実行方法は先日のELYAZAの紹介記事とほぼ同じなので割愛する。

ELYZAとのやり取りは以下の通りだ。

Rスクリプトで以下の処理をしてください。 CSVファイルから日付(Date)と株価終値(Close)を取得します。日付はYYYY-MM-DDのフォーマットになっています。日付が取得できたら先頭データの日付からの日数を365で割って実数での年数(year)に変換します。 年数をx、株価終値をyとしてy=b*m^xの式で最小二乗法で近似して誤差が最小となるbとmを求めます。bとmが求まったら、理論値ycalcを式ycalc=b*m^xで計算し、横軸をxとしてyとycalcを折線グラフで描いてください。

入力されたCSVファイルをRスクリプトで処理します。

# CSVファイルを読み込む
data <- read.csv("株価データ.csv", header=TRUE, sep=",")

# 日付と株価終値を取り出す
date = data$Date
close = data$Close

# 最初の日付からの日数を求めて年数に変換する
firstdate = as.POSIXct(date[1], format="%Y-%m-%d")
datediff = difftime(date, firstdate)
years = datediff/365

# 最小二乗法でのbとmの求め方
fit <- lm(close ~ years)
summary(fit)

# y軸をclose、x軸をyearsに設定して折線グラフを作成する
plot(close, years, xlab="年数", ylab="株価")
lines(years, close)

横軸は年数、縦軸は株価です。折れ線グラフには株価の推移を表しています。

こちらもほぼ正しそうである。CSVファイルの指定部分のみ修正して実行するとこんなグラフになった。

ELYZA-code-llamaが作成したグラフ

Copilot同様に何箇所かおかしな部分がある。

  1. 日付のデータを年数に変換する処理
  2. 近似した結果でbとmを受け取る処理
  3. グラフ表示でxとyを逆に指定しているところ

この辺を私が修正したスクリプトがこちらだ。

# CSVファイルを読み込む
data <- read.csv("~/AAPL.tsv", header=TRUE, sep="\t")

# 日付と株価終値を取り出す
date <- data$Date
close <- data$Close

# 最初の日付からの日数を求めて年数に変換する
firstdate <- as.POSIXct(date[1], format="%Y-%m-%d")
firstyear <- as.integer(format(firstdate, "%Y"))
datediff <- difftime(date, firstdate, units="days")
years <- as.numeric(datediff/365)

# 最小二乗法でのbとmの求め方
fit <- lm(log(close) ~ years)
coefficients <- coef(fit) # 回帰係数の推定値を取得
b <- exp(coefficients[1])
m <- exp(coefficients[2])
ycalc <- b*m^years
ratio <- (m -1) * 100

# y軸をclose、x軸をyearsに設定して折線グラフを作成する
plot(years+firstyear, close, xlab="西暦", ylab="Apple|の株価", type="l", col="blue")
lines(years+firstyear, ycalc, col="red", lty = 2)
legend("topleft", legend = c(code, sprintf("R=%.1f r2=%.3f",ratio,summary(fit)$r.squared)), col = c("blue", "red"), lty = c(1, 2))

完成したグラフはこちらだ。

ELYZA作成のRスクリプトを修正して表示したグラフ

まとめ

私のおおまかな指示を聞いて直ぐにこれだけのコーディングを返してくれるのだから、CopilotもELYZA-code-llamaもたいしたものだ。100点満点で採点すると60点~70点くらいだろうか。おかしな点を指摘して直してくれるのなら仕事にも使えそうな気がする。残念ながら今回試したELYZA-code-llamaは一問一答式で、前のやりとり(文脈)を把握したうえでの回答はしてくれない(できるのかもしれないが、まだ方法が分かっていない)。Copilotは文脈把握ができそうな気がするが、今回はそこは試していない。

コーディングに関してはGoogle先生に聞くよりも、AIに教えてもらった方が早い時代になっているようだ。

公開したRスクリプトはAIが作成してR初心者の私がレビューしたものだ。自由に使っていただいて結構だが、おかしなところはまだあると思う。その点はご容赦いただきたい。