ラベル Shiny の投稿を表示しています。 すべての投稿を表示
ラベル Shiny の投稿を表示しています。 すべての投稿を表示

2019-12-31

Rで株価を扱う 〜 stock-explorer の公開

対象銘柄および関連業界のいくつかの銘柄の株価情報を使って学習させ、明日の取引の始値を予測するプログラム stock-explorer を GitHub に公開しました。いままで Bitbucket にリポジトリを作って非公開で開発をしていましたが、ある程度の成果を確認できたのでリポジトリを移して公開し、時間をかけて汎用的用途に使えるように機能を実装していこうと考えています。

もともと、2018 年 12 月 19 日にソフトバンクグループの国内通信子会社、ソフトバンクが東京証券取引所第1部に上場したこと [1] を契機に、当日までの株価の情報だけで明日(未来)の株価を、機械学習でどこまで予測できるか評価したいと思ったことが、開発を始めた動機です。

※ 新しく始まる株価データを使って機械学習をする、という意味で契機と捉えました。

一年あまりの期間、毎晩 Yahoo!ファイナンスの株価情報をダウンロードして、そのうちいくつかの銘柄を数種類の機械学習のアルゴリズムで学習させ、仮想的に 100 万円を単純な投資アルゴリズムで運用してみました。その結果、2019 年末時点で、予測精度はともかく、PLS のアルゴリズムで予測したヤフーの運用結果が際立って良かったのでスクリーンショットを下記に載せました。

※ 人力で毎晩処理をするのは大変なので、24 時間稼働させられる安価でファンレスな PC を買って cron で毎晩決まった時間に処理するようにしています。

stock-explorer の実行例

GitHub の下記のサイトにリポジトリを公開しています。

ソースを入手するには下記のように git でクローンしてください。

[bitwalk@fedora-pc ダウンロード]$ git clone https://github.com/bitwalk123/stock-explorer.git
Cloning into 'stock-explorer'...
remote: Enumerating objects: 43, done.
remote: Counting objects: 100% (43/43), done.
remote: Compressing objects: 100% (32/32), done.
remote: Total 43 (delta 16), reused 28 (delta 9), pack-reused 0
Unpacking objects: 100% (43/43), done.
[bitwalk@fedora-pc ダウンロード]$ 

プログラムの詳細は、これから上記 GitHub のサイトに詳しく説明して行く予定ですが、まだできていません。ただ、日々の株価データを取得し、学習・予測し、データベースを更新する処理は support/update.R が担っています。スクリプトの中身はハードコーディングしている箇所がまだ数多く残っています。本体の stock-explorer はデータベースから読み取ってブラウザ上にプロットを表示するだけの Shiny アプリです。

雑感

R の caret パッケージ [2] を利用すると、簡単に機械学習のアルゴリズムを利用できるので、専用のサーバーを用意して何種類もの機械学習のアルゴリズムをチューニングなしで試してみました。RMSE を精度の基準と考えるならば、'bridge' (Bayesian Ridge Regression) が試した中では一番精度が良いと言えます。精度で二番手になるのが多くの場合、PLS でした。利用できる CPU の性能と学習にかかる計算時間を考えると、欲張ったデータ量を学習させようとすれば PLS が現実的な解になるのかもしれません。ただし、まだまだ試すべきアルゴリズムはたくさんありますので、結論にはできません、

株価予測のモニターを始めた当初は、株価のだいたい 1% ぐらいの精度 (RMSE) で次の取引の始値を予測できれば上出来だと思っていましたが、期間を含めてデータが多くなってくればそのぐらいの精度で予測できそうな様子です。しかし(当然ですが)外的要因を加味することができていません。

例えば、ヤフーと LINE の統合についての報道 [3] が 11 月 13 日の夜に出たときに、翌日のヤフーの株価は急騰しましたが、現状ではその情報を予測に反映させる術がありません。そのため、予測が実際のトレンドに一日遅れで追従することになります。これでは精度としての RMSE がそこそこ良くても、まだまだ使い物になりません。

そこで、ウェブスクレイピングを応用して、予測に寄与する情報を収集できればと試行錯誤を始めています。

参考サイト

  1. ソフトバンク上場、終値1282円 公開価格を15%下回る  :日本経済新聞 [2018-12-19]
  2. The caret Package
  3. ヤフーとLINE経営統合へ ネット国内首位に  :日本経済新聞 [2019-11-13]
  4. bitWalk's: Rで株価を扱う 〜 始値を予測してみた [2019-02-03]
  5. bitWalk's: Rで株価を扱う 〜 quantmod パッケージ [2019-01-16]

 

ブログランキング・にほんブログ村へにほんブログ村

2019-11-09

R Shiny のプロットにツールチップを表示する (2)

Shiny は R のパッケージの一つで、 このパッケージを使うと R を用いて対話的に操作する Web アプリケーションを作成することができます。Web 上のユーザーインタフェース部分を司る ui.R と、内部動作を司る server.R の二つの R 言語スクリプトで、サーバーサイドのコンテンツを作成できることが大きな特徴です。

RjpWiKi より引用

UI のレイアウトを変えるとツールチップの表示がズレる!

ブログ記事 [1] で、プロットされたデータ点にマウスのポインタを近づけると、データ点に関係する情報をツールチップで表示する、という機能が実装できて喜んだのも束の間、問題を出ました。

 ツールチップを表示した例(参考サイト [1]) 

レイアウトを変えてプロットの上にウィジェットを配置すると、ツールチップが表示される位置がとんでもなくズレてしまうのです(下図)。

 レイアウトを変えてツールチップを表示した例 

改良版

マウスのポインタの座標を取得する仕組みを理解できておらず、どのようにすれば解決できるのかが皆目判らなかったので、とにかく他の方々がどのようにツールチップを表示させているのかをインターネットで探し続けると、参考サイト [2] にヒントがありました。

ui.R を下記に示しました。プロットを表示するブロックに、CSS のスタイル position: relative; を加えることでズレを解消できました。

リスト:ui.R 
fluidPage(
    fluidRow(
        titlePanel("Iris explorer"),
        selectInput(
            inputId = "varX",
            label = "Select the X variable",
            choices = get.choices()),
        selectInput(
            inputId = "varY",
            label = "Select the Y variable",
            choices = get.choices(), selected = 2)
    ),
    hr(),
    fluidRow(
        style = "position: relative;",
        plotOutput(
            outputId = "plot",
            dblclick = "plot_dblclick",
            brush = brushOpts(
                id = "plot_brush",
                resetOnNew = TRUE
            ),
            hover = hoverOpts("plot_hover", delay = 100, delayType = "debounce")
        ),
        uiOutput("hover_info")
    )
)

server.R を下記に示しました(参考サイト [1] と同じ)。

リスト:server.R 
function(input, output) {
    ranges <- reactiveValues(x = NULL, y = NULL)
    var.x <- reactive(iris[, as.numeric(input$varX)])
    var.y <- reactive(iris[, as.numeric(input$varY)])
    label.x <- reactive(names(iris[as.numeric(input$varX)]))
    label.y <- reactive(names(iris[as.numeric(input$varY)]))
    
    output$plot <- renderPlot({
        ggplot(iris, aes(x = var.x(), y = var.y(), colour = Species)) +
            xlab(label.x()) + ylab(label.y()) + 
            coord_cartesian(xlim = ranges$x, ylim = ranges$y, expand = FALSE) +
            geom_point(size = 4) + gtheme
    })
    
    observeEvent(input$plot_dblclick, {
        brush <- input$plot_brush
        if (!is.null(brush)) {
            ranges$x <- c(brush$xmin, brush$xmax)
            ranges$y <- c(brush$ymin, brush$ymax)
        } else {
            ranges$x <- NULL
            ranges$y <- NULL
        }
    })
    
    output$hover_info <- renderUI({
        hover <- input$plot_hover
        point <- nearPoints(iris, hover, xvar = label.x(), yvar = label.y(), threshold = 5, maxpoints = 1, addDist = TRUE)
        if (nrow(point) == 0) return(NULL)
        
        wellPanel(
            style = get.style(hover),
            p(HTML(paste0("<b> Species: </b>", point$Species, "<br/>",
                          "<b> ", label.x(), ": </b>", point[, label.x()], "<br/>",
                          "<b> ", label.y(), ": </b>", point[, label.y()], "<br/>")))
        )
    })
}

global.R を下記に示しました(参考サイト [1] と同じ)。

リスト:global.R 
library(shiny)
library(ggplot2)

gtheme <- theme(
    axis.title = element_text(size = 16),
    axis.text = element_text(size = 16),
    axis.line = element_line(),
    legend.title =  element_text(size = 14),
    legend.text = element_text(size = 14),
    panel.grid.major = element_line(colour="grey",size = rel(0.5)), 
    panel.grid.minor = element_blank(), 
    panel.background = element_rect(fill = "whitesmoke")
)

get.choices <- function() {
    part.iris <- list()
    for (item in names(iris)) {
        if (item != "Species") {
            part.iris[[item]] <- grep(item, names(iris))
        }
    }
    return(part.iris)
}

get.left_px <-  function(hover) {
    left_pct <- (hover$x - hover$domain$left) / (hover$domain$right - hover$domain$left)
    left_px <- hover$range$left + left_pct * (hover$range$right - hover$range$left)
    return(left_px)
}

get.top_px <-  function(hover) {
    top_pct <- (hover$domain$top - hover$y) / (hover$domain$top - hover$domain$bottom)
    top_px <- hover$range$top + top_pct * (hover$range$bottom - hover$range$top)
    return(top_px)
}

get.style <- function(hover) {
    style <- paste0("position: absolute; z-index: 100; ",
                    "left:", get.left_px(hover) + 2, "px; ",
                    "top:", get.top_px(hover) + 2, "px; ",
                    "background-color: rgba(245, 245, 245, 0.75); ",
                    "font-family: monospace;")
    return(style)
}

下記に実行例を示しました。

 ツールチップを表示した例(改良版) 

無事解決できましたが、正直、なんとなくコツをつかめたというレベルです。

参考サイト

  1. bitWalk's: R Shiny のプロットにツールチップを表示する [2019-10-10]
  2. Shiny でマウスの位置に応じてプロットにツールチップを表示する | Atusy's blog [2019-08-06]

 

 

ブログランキング・にほんブログ村へにほんブログ村

2019-10-10

R Shiny のプロットにツールチップを表示する

Shiny は R のパッケージの一つで、 このパッケージを使うと R を用いて対話的に操作する Web アプリケーションを作成することができます。Web 上のユーザーインタフェース部分を司る ui.R と、内部動作を司る server.R の二つの R 言語スクリプトで、サーバーサイドのコンテンツを作成できることが大きな特徴です。

RjpWiKi より引用

ggplot2 でツールチップを表示する

参考サイト [1] に、ggplot2 で描画したプロットのデータポイントにマウスのポインタを持っていくと、データポイントの内容をツールチップで表示するスクリプトが紹介されていました。これはインタラクティブにデータ解析をするのに是非活用できるようにしたい機能です。そこで、前回のブログ記事 [2] で紹介した簡単な Shiny アプリ iris-explorer にこのツールチップ機能を加えてみました。

ui.R を下記に示しました。

リスト:ui.R 
fluidPage(
    titlePanel("Iris explorer"),
    sidebarLayout(
        sidebarPanel(
            selectInput(
                inputId = "varX",
                label = "Select the X variable",
                choices = get.choices()),
            selectInput(
                inputId = "varY",
                label = "Select the Y variable",
                choices = get.choices(), selected = 2)
        ),
        mainPanel(
            plotOutput(
                "plot",
                dblclick = "plot_dblclick",
                brush = brushOpts(
                    id = "plot_brush",
                    resetOnNew = TRUE
                ),
                hover = hoverOpts("plot_hover", delay = 100, delayType = "debounce")
            ),
            uiOutput("hover_info")
        )
    )
)

server.R を下記に示しました。

リスト:server.R 
function(input, output) {
    ranges <- reactiveValues(x = NULL, y = NULL)
    var.x <- reactive(iris[, as.numeric(input$varX)])
    var.y <- reactive(iris[, as.numeric(input$varY)])
    label.x <- reactive(names(iris[as.numeric(input$varX)]))
    label.y <- reactive(names(iris[as.numeric(input$varY)]))

    output$plot <- renderPlot({
        ggplot(iris, aes(x = var.x(), y = var.y(), colour = Species)) +
            xlab(label.x()) + ylab(label.y()) + 
            coord_cartesian(xlim = ranges$x, ylim = ranges$y, expand = FALSE) +
            geom_point(size = 4) + gtheme
    })

    observeEvent(input$plot_dblclick, {
        brush <- input$plot_brush
        if (!is.null(brush)) {
            ranges$x <- c(brush$xmin, brush$xmax)
            ranges$y <- c(brush$ymin, brush$ymax)
        } else {
            ranges$x <- NULL
            ranges$y <- NULL
        }
    })

    output$hover_info <- renderUI({
        hover <- input$plot_hover
        point <- nearPoints(iris, hover, xvar = label.x(), yvar = label.y(), threshold = 5, maxpoints = 1, addDist = TRUE)
        if (nrow(point) == 0) return(NULL)
        
        wellPanel(
            style = get.style(hover),
            p(HTML(paste0("<b> Species: </b>", point$Species, "<br/>",
                          "<b> ", label.x(), ": </b>", point[, label.x()], "<br/>",
                          "<b> ", label.y(), ": </b>", point[, label.y()], "<br/>")))
        )
    })
}

global.R を下記に示しました。

リスト:global.R 
library(shiny)
library(ggplot2)

gtheme <- theme(
    axis.title = element_text(size = 16),
    axis.text = element_text(size = 16),
    axis.line = element_line(),
    legend.title =  element_text(size = 14),
    legend.text = element_text(size = 14),
    panel.grid.major = element_line(colour="grey",size = rel(0.5)), 
    panel.grid.minor = element_blank(), 
    panel.background = element_rect(fill = "whitesmoke")
)

get.choices <- function() {
    part.iris <- list()
    for (item in names(iris)) {
        if (item != "Species") {
            part.iris[[item]] <- grep(item, names(iris))
        }
    }
    return(part.iris)
}

get.left_px <-  function(hover) {
    left_pct <- (hover$x - hover$domain$left) / (hover$domain$right - hover$domain$left)
    left_px <- hover$range$left + left_pct * (hover$range$right - hover$range$left)
    return(left_px)
}

get.top_px <-  function(hover) {
    top_pct <- (hover$domain$top - hover$y) / (hover$domain$top - hover$domain$bottom)
    top_px <- hover$range$top + top_pct * (hover$range$bottom - hover$range$top)
    return(top_px)
}

get.style <- function(hover) {
    style <- paste0("position: absolute; z-index: 100; ",
                    "left:", get.left_px(hover) + 2, "px; ",
                    "top:", get.top_px(hover) + 2, "px; ",
                    "background-color: rgba(245, 245, 245, 0.75); ",
                    "font-family: monospace;")
    return(style)
}

下記に実行例を示しました。

 ツールチップを表示した例 

まだ十分に使いこなせるレベルにありませんが、shiny の web アプリでデータ解析をするときに、ズームと併せて必須の機能だと思っていますので、備忘録としてまとめました。

参考サイト

  1. Custom interactive CSS/HTML tooltips with ggplot, shiny and R (ggvis like). ($16220) · Snippets · GitLab
  2. bitWalk's: R Shiny でプロットのズーム [2019-10-09]

 

 

ブログランキング・にほんブログ村へにほんブログ村

2019-10-09

R Shiny でプロットのズーム

Shiny は R のパッケージの一つで、 このパッケージを使うと R を用いて対話的に操作する Web アプリケーションを作成することができます。Web 上のユーザーインタフェース部分を司る ui.R と、内部動作を司る server.R の二つの R 言語スクリプトで、サーバーサイドのコンテンツを作成できることが大きな特徴です。

RjpWiKi より引用

ggplot2 でズームをできるようにする

参考サイト [1] の Shiny のデモギャラリーに ggplot2 で描画したプロットをズームする例があります。プロットのズームしたいエリアをマウスでドラッグしてダブルクリックしてズームする機能はとても便利なので、この部分だけ取り出して、以前のブログ記事 [2] で紹介した簡単な Shiny アプリ iris-explorer にズーム機能を加えてみました。

ui.R を下記に示しました。

リスト:ui.R 
fluidPage(
    titlePanel("Iris explorer"),
    sidebarLayout(
        sidebarPanel(
            selectInput(
                inputId = "varX",
                label = "Select the X variable",
                choices = get.choices()),
            selectInput(
                inputId = "varY",
                label = "Select the Y variable",
                choices = get.choices(), selected = 2)
        ),
        mainPanel(
            plotOutput(
                "plot",
                dblclick = "plot_dblclick",
                brush = brushOpts(
                    id = "plot_brush",
                    resetOnNew = TRUE
                )
            )
        )
    )
)

server.R を下記に示しました。

リスト:server.R 
function(input, output) {
    ranges <- reactiveValues(x = NULL, y = NULL)
    var.x <- reactive(iris[, as.numeric(input$varX)])
    var.y <- reactive(iris[, as.numeric(input$varY)])
    label.x <- reactive(names(iris[as.numeric(input$varX)]))
    label.y <- reactive(names(iris[as.numeric(input$varY)]))

    output$plot <- renderPlot({
        ggplot(iris, aes(x = var.x(), y = var.y(), colour = Species)) +
            xlab(label.x()) + ylab(label.y()) + 
            coord_cartesian(xlim = ranges$x, ylim = ranges$y, expand = FALSE) +
            geom_point(size = 4) + gtheme
    })

    observeEvent(input$plot_dblclick, {
        brush <- input$plot_brush
        if (!is.null(brush)) {
            ranges$x <- c(brush$xmin, brush$xmax)
            ranges$y <- c(brush$ymin, brush$ymax)
        } else {
            ranges$x <- NULL
            ranges$y <- NULL
        }
    })
}

今回は global.R も使ってコード全体を少しだけ整理しています。

リスト:global.R 
library(shiny)
library(ggplot2)

gtheme <- theme(
    axis.title = element_text(size = 16),
    axis.text = element_text(size = 16),
    axis.line = element_line(),
    legend.title =  element_text(size = 14),
    legend.text = element_text(size = 14),
    panel.grid.major = element_line(colour="grey",size = rel(0.5)), 
    panel.grid.minor = element_blank(), 
    panel.background = element_rect(fill = "whitesmoke")
)

get.choices <- function() {
    part.iris <- list()
    for (item in names(iris)) {
        part.iris[[item]] <- grep(item, names(iris))       
    }
    return(part.iris)
}

下記に実行例を示しました。

プロット上、マウスでドラッグしてズームしたいエリア(薄青の矩形エリア)を決めます。

指定した矩形エリア上にマウスのポインタを移動して、ダブルクリックします。

指定したエリアにズームされます。

何も指定していないプロットの上でダブルクリックすると元のプロットに戻ります。

参考サイト

  1. Shiny - Plot interaction - zoom
  2. bitWalk's: R Shiny を使ってみる (2)

 

 

ブログランキング・にほんブログ村へにほんブログ村

2019-09-02

R Shiny の actionButton (2)

Shiny は R のパッケージの一つで、 このパッケージを使うと R を用いて対話的に操作する Web アプリケーションを作成することができます。Web 上のユーザーインタフェース部分を司る ui.R と、内部動作を司る server.R の二つの R 言語スクリプトで、サーバーサイドのコンテンツを作成できることが大きな特徴です。

参考サイト [1] より引用

変数が複数ある場合に actionButton を使う

先のブログ記事 [1] で紹介した actionButton を用いたサンプルは、スライダのひとつの値を server.R 側の eventReactive で受け取り、ヒストグラムに反映させるという単純なものでした。複数の条件でプロットを作成する場合は、server.R 側で observeEvent を使います。

簡単なサンプルですが、二変数で生成するプロットに対して actionButton を用いたサンプルを紹介します。使用した環境は以下の通りです。

OS Fedora 30 (x86_64)
R R-core-3.6.0-1.fc30.x86_64
RStudio rstudio-1.2.1335-1.x86_64
shiny 1.3.2

以下にサンプルを示しました。

リスト: ui.R 
fluidPage(
    titlePanel("Iris explorer"),
    sidebarLayout(
        sidebarPanel(
            selectInput(
                inputId = "varX",
                label = "Select the X variable",
                choices = getChoices()),
            selectInput(
                inputId = "varY",
                label = "Select the Y variable",
                choices = getChoices(),
                selected = 2),
            actionButton("goButton", "Plot")
        ),
        mainPanel(
            plotOutput("plot")
        )
    )
)
リスト: server.R 
function(input, output) {
    observeEvent(input$goButton, {
        value.x <- iris[, as.numeric(input$varX)]
        value.y <- iris[, as.numeric(input$varY)]
        label.x <- names(iris[as.numeric(input$varX)])
        label.y <- names(iris[as.numeric(input$varY)])
        
        output$plot <- renderPlot({
            p <- ggplot(iris, aes(x = value.x, y = value.y, colour = Species)) + 
                xlab(label.x) + ylab(label.y) + 
                geom_point(size = 4) + gtheme
            plot(p)
        })
    })
}

サンプルをなるべく単純にしたかったので、ここで global.R を使いたくなかったのですが、使った方が全体がシンプルになるので結局使うことにしました。

リスト: global.R 
library(shiny)
library(ggplot2)

gtheme <- theme(
  axis.title = element_text(size = 16),
  axis.text = element_text(size = 16),
  axis.line = element_line(),
  legend.title =  element_text(size = 14),
  legend.text = element_text(size = 14),
  panel.grid.major = element_line(colour="grey",size = rel(0.5)), 
  panel.grid.minor = element_blank(), 
  panel.background = element_rect(fill = "whitesmoke")
)

getChoices <- function() {
  return(c("Sepal.Length" = 1, "Sepal.Width" = 2, "Petal.Length" = 3, "Petal.Width" = 4))  
}

このアプリを実行した直後は右側にプロットは表示されません。

左側の Plot ボタンをクリックすると、右側にプロットが表示されます。

左側の 'Select the Y variable' の selectInput の選択値を変更しても右のプロットは変化しません。

左側の Plot ボタンをクリックすると、右側のプロットに、二つの selectInput で設定した二軸のデータが反映されます。

参考サイト

  1. bitWalk's: R Shiny の actionButton [2019-09-01]

 

ブログランキング・にほんブログ村へにほんブログ村

2019-09-01

R Shiny の actionButton

Shiny は R のパッケージの一つで、 このパッケージを使うと R を用いて対話的に操作する Web アプリケーションを作成することができます。Web 上のユーザーインタフェース部分を司る ui.R と、内部動作を司る server.R の二つの R 言語スクリプトで、サーバーサイドのコンテンツを作成できることが大きな特徴です。

参考サイト [1] より引用

actionButton のニーズ

Shiny で作る Web アプリはウィジェットを操作して動的にプロットなどに反映させることができます。しかし複数の selectInput などを選択する必要があって、かつ個々のプロットを描画するのにデータ量や計算量の関係で少々時間がかかるような時には、描画条件を選択する度にプロットが更新され、目的のプロットを描画するまでに待たされてイライラすることがあります。

そんな時には条件を全て選択して更新ボタンをクリックするようにすれば、イライラを解消できます。Shiny ではこのような時のために submitButton というウィジェットが用意されています。しかしこのボタンは単純な用途に用いる時には有効ですが、より複雑で汎用な用途には actionButton を使うことが推奨されています。

そこで簡単なサンプルですが、actionButton を用いたサンプルを作って備忘録としました。使用した環境は以下の通りです。

OS Fedora 30 (x86_64)
R R-core-3.6.0-1.fc30.x86_64
RStudio rstudio-1.2.1335-1.x86_64
shiny 1.3.2

以下に actionButton を使ったサンプルを示しました。これは RStudio で新規に Shiny Web App を作成した時に生成されるスケルトンに少々手を加えたものです。

リスト: ui.R 
library(shiny)

shinyUI(fluidPage(
    titlePanel("Old Faithful Geyser Data"),
    sidebarLayout(
        sidebarPanel(
            sliderInput("bins",
                        "Number of bins:",
                        min = 1,
                        max = 50,
                        value = 30),
            actionButton("goButton", "Plot")
        ),
        mainPanel(
            plotOutput("distPlot")
        )
    )
))
リスト: server.R 
library(shiny)

shinyServer(function(input, output) {
    nbins <- eventReactive(input$goButton, {
        input$bins
    })
    output$distPlot <- renderPlot({
        x    <- faithful[, 2]
        bins <- seq(min(x), max(x), length.out = nbins() + 1)
        hist(x, breaks = bins, col = 'darkgray', border = 'white')
    })
})

このアプリを実行した直後は右側にヒストグラムは表示されません。

左側の Plot ボタンをクリックすると、右側にヒストグラムが表示されます。

左側のスライダの値を変更しても右のヒストグラムは変化しません。

左側の Plot ボタンをクリックすると、右側にヒストグラムにスライダに設定した値の bin が反映されます。

参考サイト

  1. Shiny - Using Action Buttons

 

ブログランキング・にほんブログ村へにほんブログ村

2019-08-17

機械学習と株価

R の quantmod (Quantitative Financial Modelling Framework) パッケージは、クオンツ取引 (qualitative trading) [1] において、統計的手法に基づいた取引モデルの構築、検証および運用の支援ができるように提供されています [2] [3]。このパッケージの getSymbols() 関数を使うと、例えば Yahoo!ファイナンス のサイトから指定した証券コードの株価データを取得することができます。

株価予測に機械学習を応用

今年初めにこのパッケージを使ってみて、株価を大量に取得できることを知って大いに驚きました。これは機械学習の応用分野に最適だと考え、予測モデルを作ることに取り組むことにしました [4] [5]。手始めに以下のようなテーマを掲げました。

当日の株関連情報を用いて、翌日(次回)のソフトバンク株式会社 (9434.T) の始値を予測せよ。

ソフトバンクグループ (SBG) の国内通信子会社、ソフトバンク株式会社 (9434.T) に注目した理由は、昨年 12 月 19 日に東京証券取引所第1部に上場したからです [6]。これでデータの取得開始日を 2019-12-19 に設定することができました。当日株価を取得してデータベースに追加、データを学習させて次回の始値を予測するという R スクリプトを作成し、毎晩そのスクリプトを実行して予測パフォーマンスを評価していました。

私は平日のほとんどが出張でホテル暮らしです。会社から支給されたノート PC の他に、プライベートで使用する Linux をインストールしたノート PC も携行し、仕事から戻って毎晩、株価データを更新、翌日の始値の予測値を算出していました。しばらく続けると当然データが増えてくるので、それだけ毎日の学習データが増えます。計算に時間がかかるようになりましたが、その分、予測トレンドがもっともらしくなってきました。

スクリプトのアプリ化

そろそろ手作業でやっている部分を自動化したいと思うようになり、R の Shiny パッケージを使って Web のアプリ化に取りかかり始めたのが先月のことです。今週一週間、夏休みにすることができたので、じっくり手を入れてひとまず使えそうな UI に仕上げる事ができました(下図)。

 stock-explorer 0.2 の実行例 

簡単な売買シミュレーション

予測パフォーマンスを眺めているだけでは飽きますので、簡単な投資シミュレーションの機能を付けてみました。予測モデルの精度が高いことはもちろん望ましいことですが、それだけでは投資ができないので、次のテーマに進むことにしたわけです。

とりあえず想定上 100 万円を元手に 2019 年 2 月 1 日に対象銘柄の株を 100 株単位で買えるだけ買って、そこから売買のシミュレーションをしています。証券会社に支払う手数料や税金はまだ考慮していません。

現在の売買基準は、予測した次の取引の始値が購入価格より高ければ売却し、本日の始値より安ければ(買えるだけ)購入するという保守的でシンプルなものです。投機的攻めの売買基準ではないので取引頻度は低いのですが、幸い、シミュレーションでは対象としている銘柄はどれも利益を出しています。ただ、手数料などを考慮に入れれば、利益は小遣い程度にしかならないでしょう。いまのところ、実現可能な投資資金をターゲットにして、アルゴリズムに工夫を加えて利益を高めるためのシミュレーションを重ねます。単一銘柄への投資方法がある程度固まったら、(同一の資金で)複数銘柄を扱うシミュレーションができるようにしたいです。

環境の整備

この夏休みに向けて、家庭内 LAN につなげて常時稼動させるサーバーを導入しようとあれこれ品定めをしていたのですが、ぴったりな PC が Amazon.jp にあったので 8 月に入って早々に買ってしまいました [7] [8]。8 月になったら CentOS 8 の RC (Release Cendidate) 版が公開されるだろうと踏んでいて、この新しいサーバーにインストールしようと思っていました。しかし予測が外れてしまったので、現行の CentOS 7 をインストールして使い始めています。

このサーバーの用途のひとつに、本件の株価データ更新分および翌日の始値の予測値の自動算出があります。crontab コマンドで毎日午後 8 時(後に午後 7 時に変更)に更新用のプログラムを起動するように設定して、この一週間(と言っても 4 日しかありませんでしたが)問題なく動作することを確認しました [9]。

今後

現在、このアプリ (stock-explore) はバージョン 0.2 です。まだまだ先の話ですが、誰でも使えるように汎用化を進めて、正式リリース (1.0) の目処が立って、需要がありそうだと見込めれば github に公開したいなあと思っています。

参考サイト

  1. 【WSJで学ぶ経済英語】第280回 クオンツ投資 - WSJ
  2. quantmod: Quantitative Financial Modelling Framework
  3. CRAN - Package quantmod
  4. bitWalk's: Rで株価を扱う 〜 quantmod パッケージ [2019-01-16]
  5. bitWalk's: Rで株価を扱う 〜 始値を予測してみた [2019-02-03]
  6. ソフトバンク上場、終値1282円 公開価格を15%下回る:日本経済新聞 [2018-12-19]
  7. bitWalk's: Skynew m2s (1) [2019-08-03]
  8. bitWalk's: Skynew m2s (2) [2019-08-04]
  9. bitWalk's: crontab を使う [2019-08-15]

一番左は、R のパッケージ Shiny について書かれた邦書の入門書が少ない中で書かれた意欲的な著作です。しかし、実際に買って読んでみると Shiny について体系的にまとめるにはページ数が足りなかったという印象を持ちます。もし英文を読むのが苦でなければ、残り三冊の中から何冊かを副読本として読むことをオススメします。

ブログランキング・にほんブログ村へにほんブログ村

2019-06-30

R Shiny を使ってみる (6)

Shiny は R のパッケージの一つで、 このパッケージを使うと R を用いて対話的に操作する Web アプリケーションを作成することができます。Web 上のユーザーインタフェース部分を司る ui.R と、内部動作を司る server.R の二つの R 言語スクリプトで、サーバーサイドのコンテンツを作成できることが大きな特徴です。

参考サイト [1] より引用

今回は、Shiny Server をインストールして LAN 内の他の PC のインターネットブラウザから Shiny のアプリケーションにアクセスできるようにしました。

本記事で使用している動作環境は次の通りです。

使用している環境 
$ lsb_release -d
Description: CentOS Linux release 7.6.1810 (Core) 
$ rpm -qa | grep "R-core"
R-core-devel-3.6.0-1.el7.x86_64
R-core-3.6.0-1.el7.x86_64
$ rpm -q shiny-server
shiny-server-1.5.9.923-1.x86_64
$ rpm -q rstudio-server
rstudio-server-1.2.1335-1.x86_64
$ 

Shiny Server のインストール

Shiny Server のインストールは、参考サイト [2] の 'RedHat / CentOS 6&7' タブの手順に従って進めれば良いのですが、ルート権限で R の shiny パッケージをインストールする際に、あとでインストールすることになるであろう rmarkdown も一緒にインストールしてしまいます。

Shiny Server をインストールする前の準備 
$ sudo su - -c "R -e \"install.packages('shiny', repos='https://cran.rstudio.com/')\""
  ...
(途中省略)
  ...
$ sudo su - -c "R -e \"install.packages('rmarkdown', repos='https://cran.rstudio.com/')\""
  ...
(途中省略)
  ...
$ 

参考サイト [2] に従って、wget コマンドでパッケージをダウンロードして yum コマンドでインストールします。この時の Shiny Server のバージョンは 1.5.9.923 でしたが、ダウンロードするときにバージョンが更新されている可能がありますので、その都度、参考サイト [2] をご確認ください。

Shiny Server のダウンロードとインストール 
$ wget https://download3.rstudio.org/centos6.3/x86_64/shiny-server-1.5.9.923-x86_64.rpm

$ sudo yum install --nogpgcheck shiny-server-1.5.9.923-x86_64.rpm

Shiny Server はデフォルトでポート 3838 番を使うようになっていますので、ファイアウォールを通るように設定します。

ファイアウォールの設定 
$ sudo firewall-cmd --add-port=3838/tcp --permanent
success
$ sudo systemctl restart firewalld
$

早速、他の PC から、Shiny Server をインストールしたサーバー (192.168.0.22) へアクセスしてみます。ブラウザへ入力する URL は http://192.168.0.22:3838/ のようにします。Shiny Server のトップページは下記のようになっています。右側に簡単なサンプルが示されていて、インタラクティブに操作ができます。

 Shiny Server のトップページ 

Shiny アプリのデプロイ

Shiny Server のトップページで表示されるファイルは /srv/shiny-server 内に配置されています。よく見てみると、Shiny Server がインストールされている /opt/shiny-server/ の中からシンボリックリンクされています。

Shiny Server アプリケーションのデプロイ先 
$ ls /srv/shiny-server
index.html  sample-apps
$ ll /srv/shiny-server
合計 0
lrwxrwxrwx. 1 root root 38  6月 29 21:25 index.html -> /opt/shiny-server/samples/welcome.html
lrwxrwxrwx. 1 root root 37  6月 29 21:25 sample-apps -> /opt/shiny-server/samples/sample-apps
$ 

RStudio の Server 版も Shiny Server と同じサーバーで利用できるのであれば、個別アカウントで RStidio にログインして、そこで Shiny の Web アプリを開発し、最終的にシンボリックリンクを張ってブラウザで動作確認ができます [3][4]。RStudio の Server 版を利用していなければ、個別に Shiny アプリを開発後、Shiny Server をインストールしてあるサーバーの /srv/shiny-server 内にフォルダーごとコピーします。

ここでは以前 Shiny の紹介記事で扱ったサンプル用の Web アプリ iris-explorer(参考サイト [5])をデプロイしてみます。このサンプルは、Fedora 上の RStudio で作成したのですが、Shiny Server をインストールした CentOS 7 のサーバーへ移しました (/home/bitwalk/shiny-app/iris-explorer)。

RStudio で /home/bitwalk/shiny-app/iris-explorer 内のファイル global.R, server.R, ui.R のいずれか、あるいは全てのファイルを読み込みます。

RStudio のエディタペイン右上に表示されている「  Run App 」をクリックします。下記のように RStudio のブラウザのウィンドウがあらわれて iris-explorer が実行されます。

 RStudio 上で実行した iris-explorer 

動作確認出来たので、Shiny Server へデプロイします。と言っても、シンボリックリンクを張るだけです。

iris-explorer のデプロイ 
$ sudo ln -s /home/bitwalk/shiny-app/iris-explorer /srv/shiny-server/iris-explorer
[sudo] bitwalk のパスワード:
$

Shiny Server で動作確認をする前に、パッケージがインストールされるグローバルな領域に、使用するパッケージをインストールしておきます。この例では shinydashboard と ggplot2 をインストールしました。

グローバルな領域へのパッケージインストール 
$ sudo su - -c "R -e \"install.packages('shinydashboard', repos='https://cran.rstudio.com/')\""
  ...
(途中省略)
  ...
$ sudo su - -c "R -e \"install.packages('ggplot2', repos='https://cran.rstudio.com/')\""
  ...
(途中省略)
  ...
$

他の PC でインターネットブラウザを起動、http://192.168.0.22:3838/iris-explorer/ にアクセスして、iris-explorer が実行されることを確認します。

 デプロイした iris-explorer の実行例 

Shiny Server のログ

エラーや期待したどおりに動作しない場合、まず、サーバーログを確認しましょう。ログは /var/log/shiny-server/ にあります。ルート権限で内容を確認できます。

Shiny Server のログ 
$ ls /var/log/shiny-server
iris-explorer-shiny-20190630-173444-41788.log  rmd-shiny-20190630-094622-43528.log
rmd-shiny-20190630-091930-37985.log            rmd-shiny-20190630-094741-44562.log
rmd-shiny-20190630-094602-42135.log
$ tail /var/log/shiny-server/iris-explorer-shiny-20190630-173444-41788.log
tail: `/var/log/shiny-server/iris-explorer-shiny-20190630-173444-41788.log' を 読み込み用に開くことが出来ません: 許可がありません
$ sudo tail /var/log/shiny-server/iris-explorer-shiny-20190630-173444-41788.log
[sudo] bitwalk のパスワード:
su: ignore --preserve-environment, it's mutually exclusive to --login.

Attaching package: ‘shinydashboard’

The following object is masked from ‘package:graphics’:

    box


Listening on http://127.0.0.1:41788
$ 

Shiny Server のより詳細な情報は、参考サイト [6] を参照してください。

参考 サイト

  1. Shiny - RjpWiki
  2. Download Shiny Server - RStudio
  3. Download RStudio - RStudio
  4. bitWalk's: RStudio Server と SELinux (Fedora) [2019-08-10]
  5. bitWalk's: R Shiny を使ってみる (5) [2018-09-30]
  6. Shiny Server Configuration Reference

 

ブログランキング・にほんブログ村へにほんブログ村

2018-09-30

R Shiny を使ってみる (5)

Shiny は R のパッケージの一つで、 このパッケージを使うと R を用いて対話的に操作する Web アプリケーションを作成することができます。Web 上のユーザーインタフェース部分を司る ui.R と、内部動作を司る server.R の二つの R 言語スクリプトで、サーバーサイドのコンテンツを作成できることが大きな特徴です。

参考サイト [1] より引用

RStudio 上で Shiny による Web アプリケーションを作り始めたので、理解したことを備忘録としてまとめたことを不定期に紹介していきます。

自分が R を使って解析したい特定の分野について、Web アプリケーションを作成し、参考サイト [2] にある Shiny Server を Linux で稼働させて、作った Web アプリケーションを利用できるようにすることが目標です。しかし現時点では、その Web アプリケーションを作るだけの知識が伴っていないので、しばらくの間、簡単なサンプルで試行錯誤を続けて、判ったことをまとめていきたいと思います。

本記事で使用している動作環境は次の通りです。

  • OS: Fedora 29 beta (x86_64)
  • R: R-core-3.5.1-1.fc29.x86_64, R-core-devel-3.5.1-1.fc29.x86_64
  • RStudio: rstudio-server-1.1.456-1.x86_64

Web App の作成 : Iris explorer ver. 3.0

前回の Shiny の記事 [3] で紹介した Iris explorer ver. 2.1 をベースにして、shinydashboard パッケージを用いたレイアウトに変更してみました。

まず、実行例を以下に示しました。

Iris explorer ver. 3.0 の実行例

shinydashboard パッケージによるレイアウト

shinydashboard パッケージによるレイアウトの基本構成は以下のようになっています。

リスト:ダッシュボードの基本構成 (ui.R) 
library(shiny)
library(shinydashboard)

dashboardPage(
  dashboardHeader(),  # ヘッダー部分
  dashboardSidebar(), # サイドバー部分
  dashboardBody()     # ボディー(メイン)部分
)
Shiny Dashboard の基本構成

ヘッダー部分は、このアプリケーションではアプリケーション名を文字列で定義しているだけです。

リスト:ダッシュボードのヘッダー部分 
dashboardPage(
  dashboardHeader(title = "..."),
    ...
    ...
)

ちなみに、ヘッダーのタイトル右側にある ☰ をクリックするとサイドバーの部分を非表示/表示にすることができます。

サイドバーの表示/非表示

左側のサイドバーの部分には、メニュー (sideBarMenu) を利用してメニューアイテム (menuItem) とその下にサブメニュー (menuSubItem) を定義しています。このサブメニューで、サブメニューに表示する文字列と、サブメニューをクリックした時にボディー(メイン)の部分に表示するタブの名前を定義しています。このタブの名前は、ボディーの部分で対応させます。

リスト:ダッシュボードのサイドバー部分 〜 メニューのタブの設定 
dashboardPage(
    ...
  dashboardSidebar(
    sidebarMenu(
      menuItem(
        "Menu Name",
        menuSubItem("Sub Menu Name 1", tabName = "Tab Name 1"),
        menuSubItem("Sub Menu Name 2", tabName = "Tab Name 2"),
           ...
           ...
        menuSubItem("Sub Menu Name N", tabName = "Tab Name N")
      )
    )
  ),
    ...
)

ボディーの部分には、サイドバーで定義したタブの名前に対応するタブアイテム (tabItem) を定義して、そこに表示するプロットやウィジェットのレイアウトを記載します。

リスト:ダッシュボードのボディー部分 〜 タブ画面のレイアウト 
dashboardPage(
     ...
     ...
  dashboardBody(
    tabItems(
      tabItem(
        "Tab Name 1",
           ...
           ...
      ),
      tabItem(
        "Tab Name 2",
           ...
           ...
      ),
         ...
         ...
      tabItem(
        "Tab Name N",
           ...
           ...
      )
    )
  )
)

サンプルコード

このサンプルのコードを紹介します。今回は global.R を加えた以下の三種類のファイルです。この global.R はアプリケーションが起動する前に実行されます。global.R で生成されたオブジェクトは ui.R と server.R からアクセスできます [4]。

  1. global.R
  2. ui.R
  3. server.R

global.R を以下に示しました。パッケージのロードとアプリケーションのバージョン情報および ggplot2 で使用する共通のテーマを記載しています。

リスト:global.R 

ui.R を以下に示しました。

リスト:ui.R 

server.R を以下に示しました。この部分は、前回の Shiny の記事 [3] で紹介した Iris explorer ver. 2.1 の server.R と同じ内容です。

リスト:server.R 

まとめ

以上、簡単なサンプルでも shinydashboard パッケージを利用すれば、格好の良いレイアウトで簡単に実行できるようになるので、もしかしたら自分でも実用的なスバラシいアプリを作ることができるかもしれない、という幻想を抱かせてくれます…もとい、開発意欲を駆り立ててくれます。

実際に本格的なアプリケーションを構築しようとすれば、いろいろな問題に直面することが予想されますが、とにかく業務で使っている R のコードを Shiny で動くようにすることを検討しています。ひきつづき本ブログ記事では、関連する情報を簡単なサンプルを使って備忘録的にまとめていきたいと考えています。

参考サイト

  1. Shiny - RjpWiki
  2. Download Shiny Server - RStudio
  3. bitWalk's: R Shiny を使ってみる (4)
  4. An introduction to global.R - Learning Shiny

 

ブログランキング・にほんブログ村へ
にほんブログ村