グリッドサーチ結果の可視化
春がもう少しで来そうでなかなか来ないもどかしい季節ですね。こんばんは。
最近Rのパッケージの関数を見るのが面白いなと感じる様になりました。
私はあまりコーディングをしないので得意ではないのですが、
下手なりに色々書き換えたりして、自分の欲求を満たすものに作り変えていくのは
なかなか悪くない趣味だなと思っています。
というところで、以前id:hoxo_mさんのブログ
SVM のチューニングのしかた(2) - ほくそ笑む
を読んでtune.plotカッコいいなあ、
もっと汎用的に使えたら嬉しいなぁと思ったのを思い出し、
勉強がてら色々書き換えてみました。
本当は元のe1071で行っている様にfilled.contourを使いたかったのですが、
私の力不足で図の配置が上手くコントロールできなかったため断念しました。
そのためカッコよさは激減しています。
グラフィックパラメータ周り難しい。。
library(e1071) plot.tune.mat <- function(data,#scoreを指定しない場合最も右の列を評価値 score = NULL, error = TRUE,#評価値が小さいほど良い場合はTRUE main = NULL, xlab = NULL, ylab = NULL, transform = NULL,#パラメータ全体を変換する関数 color.palette = hsv_palette(), nlevels = 20, ...){ param <- as.data.frame(data) k <- ncol(param) if(is.null(score)){ score <- param[,k] param <- param[,-k] k <- ncol(param) } if (!is.null(transform)) param <- transform(param) if(!error){ col <- rev(color.palette(n =nlevels)) } else{ col <- (color.palette(n =nlevels)) } #グラフィックパラメータ設定 plot.new() par(mfcol=c(k,k)) par(mar=par("mar")/sqrt(k-1)) par(mgp=c(1.5,0.5,0)) #描画 lapply(1:ncol(param),function(i){ lapply(1:ncol(param),function(j){ paramtab <- tapply(score,param[,c(i,j)],mean) if (is.null(xlab)) xl <- colnames(param)[i] if (is.null(ylab)) yl <- colnames(param)[j] image(x=as.double(rownames(paramtab)), y=as.double(colnames(paramtab)), z=paramtab, xlab=xl,ylab=yl, col = col) })}) #グラフィックパラメータを初期化 on.exit(par(mfcol=c(1,1))) on.exit(par(mgp=c(3,1,0))) on.exit(par(mar=c(5.1,4.1,4.1,2.1))) }
使い方としてはこんな感じです。
plot.tune.mat(data,error=T,transform=log2,nlevels=10)
結果
濃いところが良いところです。
濃さのスケールは全プロットで共通です。
表示したデータ
> data p1 p2 p3 error_rate 1 100 5 100 0.06585525 2 100 5 100 0.06455118 3 100 5 100 0.06302978 4 100 5 200 0.05520539 5 100 5 200 0.05498805 6 100 5 200 0.05629211 7 100 5 400 0.04694632 8 100 5 400 0.04803304 9 100 5 400 0.04542491 10 100 5 800 0.04629428 11 100 5 800 0.04759835 12 100 5 800 0.04520756 13 100 10 100 0.06020430 14 100 10 100 0.06346446 15 100 10 100 0.06042165 16 100 10 200 0.05390133 17 100 10 200 0.05107585 18 100 10 200 0.05455336 19 100 10 400 0.04629428 20 100 10 400 0.04694632 21 100 10 400 0.04303412 22 100 10 800 0.04868507 23 100 10 800 0.04542491 24 100 10 800 0.04846772 25 100 20 100 0.05824821 26 100 20 100 0.05933493 27 100 20 100 0.06259509 28 100 20 200 0.05129320 29 100 20 200 0.05107585 30 100 20 200 0.05346664 31 100 20 400 0.04998913 32 100 20 400 0.04694632 33 100 20 400 0.04955444 34 100 20 800 0.04998913 35 100 20 800 0.04694632 36 100 20 800 0.04672897 37 100 40 100 0.06216040 38 100 40 100 0.05824821 39 100 40 100 0.05976962 40 100 40 200 0.05346664 41 100 40 200 0.05085851 42 100 40 200 0.05346664 43 100 40 400 0.05107585 44 100 40 400 0.05433601 45 100 40 400 0.05368398 46 100 40 800 0.05020648 47 100 40 800 0.05194523 48 100 40 800 0.05107585 49 200 5 100 0.06476853 50 200 5 100 0.06302978 51 200 5 100 0.06433384 52 200 5 200 0.05737883 53 200 5 200 0.05585742 54 200 5 200 0.05629211 55 200 5 400 0.04781569 56 200 5 400 0.04651163 57 200 5 400 0.04607694 58 200 5 800 0.04607694 59 200 5 800 0.04499022 60 200 5 800 0.04585960 61 200 10 100 0.06107368 62 200 10 100 0.05998696 63 200 10 100 0.06129102 64 200 10 200 0.05194523 65 200 10 200 0.05129320 66 200 10 200 0.05172789 67 200 10 400 0.04694632 68 200 10 400 0.04672897 69 200 10 400 0.04738100 70 200 10 800 0.04651163 71 200 10 800 0.04716366 72 200 10 800 0.04672897 73 200 20 100 0.05911758 74 200 20 100 0.05890024 75 200 20 100 0.05911758 76 200 20 200 0.04977179 77 200 20 200 0.05107585 78 200 20 200 0.05151054 79 200 20 400 0.04977179 80 200 20 400 0.04651163 81 200 20 400 0.04803304 82 200 20 800 0.04759835 83 200 20 800 0.04716366 84 200 20 800 0.04781569 85 200 40 100 0.06107368 86 200 40 100 0.06042165 87 200 40 100 0.06063899 88 200 40 200 0.05129320 89 200 40 200 0.05064116 90 200 40 200 0.05281461 91 200 40 400 0.05042382 92 200 40 400 0.05020648 93 200 40 400 0.04846772 94 200 40 800 0.04977179 95 200 40 800 0.05129320 96 200 40 800 0.05107585 97 400 5 100 0.06324712 98 400 5 100 0.06324712 99 400 5 100 0.06324712 100 400 5 200 0.05585742 101 400 5 200 0.05303195 102 400 5 200 0.05390133 103 400 5 400 0.04520756 104 400 5 400 0.04651163 105 400 5 400 0.04455553 106 400 5 800 0.04716366 107 400 5 800 0.04651163 108 400 5 800 0.04672897 109 400 10 100 0.05955227 110 400 10 100 0.05976962 111 400 10 100 0.06129102 112 400 10 200 0.05237992 113 400 10 200 0.05172789 114 400 10 200 0.05303195 115 400 10 400 0.04542491 116 400 10 400 0.04651163 117 400 10 400 0.04651163 118 400 10 800 0.04564225 119 400 10 800 0.04694632 120 400 10 800 0.04585960 121 400 20 100 0.05803086 122 400 20 100 0.06042165 123 400 20 100 0.05868290 124 400 20 200 0.05151054 125 400 20 200 0.05020648 126 400 20 200 0.04933710 127 400 20 400 0.04846772 128 400 20 400 0.04694632 129 400 20 400 0.04781569 130 400 20 800 0.04803304 131 400 20 800 0.04629428 132 400 20 800 0.04716366 133 400 40 100 0.06042165 134 400 40 100 0.06107368 135 400 40 100 0.05998696 136 400 40 200 0.05216257 137 400 40 200 0.05151054 138 400 40 200 0.05194523 139 400 40 400 0.04977179 140 400 40 400 0.04933710 141 400 40 400 0.05107585 142 400 40 800 0.05085851 143 400 40 800 0.05129320 144 400 40 800 0.05172789 145 800 5 100 0.06433384 146 800 5 100 0.06216040 147 800 5 100 0.06129102 148 800 5 200 0.05455336 149 800 5 200 0.05433601 150 800 5 200 0.05411867 151 800 5 400 0.04672897 152 800 5 400 0.04433819 153 800 5 400 0.04629428 154 800 5 800 0.04455553 155 800 5 800 0.04629428 156 800 5 800 0.04477288 157 800 10 100 0.06020430 158 800 10 100 0.05998696 159 800 10 100 0.06129102 160 800 10 200 0.05346664 161 800 10 200 0.05216257 162 800 10 200 0.05324929 163 800 10 400 0.04520756 164 800 10 400 0.04607694 165 800 10 400 0.04607694 166 800 10 800 0.04542491 167 800 10 800 0.04672897 168 800 10 800 0.04651163 169 800 20 100 0.05998696 170 800 20 100 0.05737883 171 800 20 100 0.05976962 172 800 20 200 0.05042382 173 800 20 200 0.05085851 174 800 20 200 0.04977179 175 800 20 400 0.04672897 176 800 20 400 0.04672897 177 800 20 400 0.04629428 178 800 20 800 0.04672897 179 800 20 800 0.04738100 180 800 20 800 0.04759835 181 800 40 100 0.05868290 182 800 40 100 0.05955227 183 800 40 100 0.06063899 184 800 40 200 0.05107585 185 800 40 200 0.05151054 186 800 40 200 0.05129320 187 800 40 400 0.04998913 188 800 40 400 0.04933710 189 800 40 400 0.05172789 190 800 40 800 0.04955444 191 800 40 800 0.05064116 192 800 40 800 0.04998913
現時点ではテストもほとんどしていないので
色々不具合あると思います。
(lapplyの2重ループもなんか気持ち悪いので書き換えたいし)
そのうち修正していくと思います。
そもそもこんな関数caretとかにありそうな気がするがどうなのでしょうか。
今回のブログを書くにあたってこの辺りを参考にしました。
http://cse.naro.affrc.go.jp/takezawa/r-tips/r/52.html
http://cse.naro.affrc.go.jp/takezawa/r-tips/r/53.html
http://cse.naro.affrc.go.jp/takezawa/r-tips/r/55.html
ブログのタイトルを変えました。
どうも明けましておめでとうございます。
昨年末は少々やらかしてしまって散々な目にあいましたが
この流れを断ち切って2015年は健康で安心に過ごせると良いなと思っています。
皆様今年もどうぞよろしくお願いします。
で、本題。当ブログのタイトルを変更しました。
以前は「SE採用の新入社員がデータサイエンティストになるまで」というタイトルでした。
4月を迎えれば入社4年目ですし、そろそろ新入社員という言葉にも違和感があるなと感じていました。また、2014年様々な社外の活動に参加して、
私は「データサイエンティスト」になりたかったのではないという認識が強まりました。
私は現職(データ分析コンサルの様なもの)で、「ビジネスとしての価値を出す」ことが最重要であると考えて取り組んでいます。
その中で行う分析は事実に基づいてビジネスや課題を理解するということが
目的であることが多く、クロス集計や単純な可視化といったものが基本となります。
お客様に見せるかどうかは別にして主成分分析や一般化線形モデルなども使ったりしますが、精々その程度のことしかしません。
高度な統計学や機械学習アルゴリズムの知識などは業務ではほとんど使っていない様に思います。
案外その様な知識よりも、私のバックグラウンドでもある実験心理学の様な
データ取得に関するバイアスに気付いたり、それを生じさせない様にする工夫などの方が役立っている様な気さえします。
この様に複雑なアルゴリズムや手法を使わず、また、ディープラーニングなど最新の研究成果にも疎い私は
とても「データサイエンティスト」であるとは思えないし、これからもきっとなれないのだろうと感じています。
一方で、私は今の仕事や働き方に対してある程度満足しています。
上でも述べましたが、私は「ビジネスとしての価値を出す」ということが最重要であると考えています。
「データサイエンティスト」でなければ出せない価値はもちろんありますが、
そうでなくてもデータをしっかり見て理解することで生み出せる価値もあると考えています。
私の当面の目標としては、データ活用によって価値が生まれるという体験を
草の根的に広げていける人間になりたいと考えています。
そのためには、予め多くの業界や業種に対する理解を深めていたり
海外のビジネスやソリューションの知識を得て持ち球を増やしたりということが
狭義の分析力を高めるよりも必要なことだと感じています。
もはや、データにこだわる必要ももしかしたらないのかもしれませんが、
私個人としては事実(データはこの一部)に基づいて理解を深めていくというプロセスを重視したいのでこれからもデータにこだわっていきたいと思います。
kNN関連パッケージの紹介
皆様こんばんは。
今回、https://atnd.org/events/58648 13日目の記事を担当することになったので
久しぶりのブログを書いています。
本記事でご紹介するのはRでkNN(k最近傍法)を実行するためのパッケージです。
kNNについて知らない方はwikipediak近傍法 - Wikipediaに簡単にまとまっているので見てもらうと良いと思います。
要は、入力データに似ているものを訓練データの中からk個探してきて、
それらの多数決で出力を決めるアルゴリズムです。
個人的な印象としては検索のイメージが強く、
例えば、訓練データの中から似ているレコード(商品やユーザー、事例など)を引っ張ってくるときに使ったりしています。
それでは早速パッケージの紹介に入ります。
{class}パッケージ
RでkNNをやろうとすると最初に見つかるのがこのパッケージだと思います。
とりあえずkNNで分類をやってみるという意味ではこのパッケージで十分です。
本記事では{kernlab}パッケージのspamデータセットを使って実行してみます。
因みにこのデータセットは約5000件のe-mailに対してスパムかどうかを判定したものです。
各レコードは各ワードや記号などの出現回数から作った特徴量(1~54列目)と
大文字に関する単語の長さなどから作った特徴量(55~57列目)と
スパムかどうかのクラス(58列目)から成っており、
今回は話を単純にするために1~54列目と58列目を対象としています。
library(kernlab) data(spam) data <- spam[,-(55:57)] #55列目がクラスになる library(class) i <- 1 classres <- class::knn(train=data[-i,-55],test=data[i,-55],cl=data[-i,55],k=100,prob=T)
実行結果:
> classres [1] spam attr(,"prob") [1] 0.74 Levels: nonspam spam
trianとtestをセットし、求めるクラスを決めてあげると実行できます。
probで確率値を出力する様に設定でき、設定すると
勝ったクラスの割合がどのくらいだったかが分かります。
ただ、今回の場合の様に2クラスの場合は良いのですが、
3クラス以上の分類で2位以下の確率値が分からないのは残念です。
上記は1レコードに対してknnを実行する方法でしたが
全レコードに対してknnを実行する(leave-one-out)する場合は以下の様にします。
classrescv <- class::knn.cv(train=data[,-55],cl=data[,55],k=100,prob=T)
実行結果:
> head(classrescv) [1] spam spam spam nonspam nonspam spam Levels: nonspam spam > head(attr(classrescv,"prob")) [1] 0.74 0.90 0.93 0.58 0.58 0.50
{class}パッケージのknnは各レコードごとに全探索を行っている様で、
spamデータぐらいではなんとも感じませんが、
データ量が大きくなってくるとパフォーマンスは辛くなってきます。
そこで、{FNN}パッケージです。
{FNN}パッケージ
FNNのFはFastのFなのですが、探索アルゴリズムを選択できる様になっており
全レコードに対してknnを実行する場合はこちらが速いです。
デフォルトのアルゴリズムであるkd_treeで実施した場合の計算時間は
理論的にはO(NlogN)となるそうです。
#classパッケージで実行 system.time(classrescv <- class::knn.cv(train=data[,-55],cl=data[,55],k=1,prob=T)) #FNNパッケージ"kd_tree"で実行 system.time(FNNrescv <- FNN::knn.cv(train=data[,-55],cl=data[,55],k=1,prob=T,algorithm="kd_tree"))
実行結果:
> system.time(classrescv <- class::knn.cv(train=data[,-55],cl=data[,55],k=1,prob=T)) user system elapsed 3.40 0.00 3.43 > system.time(FNNrescv <- FNN::knn.cv(train=data[,-55],cl=data[,55],k=1,prob=T,algorithm="kd_tree")) user system elapsed 2.69 0.00 2.70
spamデータぐらいの規模では大きな差はでませんが、数十万件を超える様なデータですと明確な差がでてきます。
補足:この記事を書いていて気付きましたが、kの数を大きくするとそれほど計算時間の差は出なくなってくるみたいです。
アルゴリズムと実装について理解が追い付いていないので原因は不明です。
{FNN}パッケージはkd_treeを設定した場合、Approximate Near Neighbor(ANN)というC++のライブラリを呼んでいますが、
このパッケージにおいては近似していないとマニュアルに書いてあるので、
その辺り調整できればkの数が増えても差が保てるのかもしれません。
この調整を行うには{RANN}のnn2や{yaImpute}のannを使わないと難しそうです。私はまだ試していません。。
{FNN}を使う利点はもう1つあります。(他にもありそうですが)
FNNのknn.cvは最近傍k個のレコードのインデックスを返してくれるので、
本記事冒頭で述べた様に似ているレコードを引っ張ってくることができます。
また、引っ張ってきたレコードのクラスを集計すれば2位以下のクラスの確率値を知ることも可能です。
FNNrescv <- FNN::knn.cv(train=data[,-55],cl=data[,55],k=3,prob=T,algorithm="kd_tree") i <- 1 data[c(i,attr(FNNrescv,"nn.index")[i,]),]
実行結果:
> data[c(i,attr(FNNrescv,"nn.index")[i,]),] make address all num3d our over remove internet order mail receive will people report addresses 1 0 0.64 0.64 0 0.32 0 0 0 0 0 0 0.64 0 0 0 13 0 0.69 0.34 0 0.34 0 0 0 0 0 0 0.69 0 0 0 312 0 0.68 0.34 0 0.34 0 0 0 0 0 0 0.68 0 0 0 168 0 0.71 0.35 0 0.35 0 0 0 0 0 0 0.71 0 0 0 free business email you credit your font num000 money hp hpl george num650 lab labs telnet num857 1 0.32 0 1.29 1.93 0 0.96 0 0 0 0 0 0 0 0 0 0 0 13 0.34 0 1.39 2.09 0 1.04 0 0 0 0 0 0 0 0 0 0 0 312 0.34 0 1.37 1.72 0 1.03 0 0 0 0 0 0 0 0 0 0 0 168 0.35 0 1.42 1.77 0 1.06 0 0 0 0 0 0 0 0 0 0 0 data num415 num85 technology num1999 parts pm direct cs meeting original project re edu table 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 312 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 168 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 conference charSemicolon charRoundbracket charSquarebracket charExclamation charDollar charHash type 1 0 0 0.000 0 0.778 0 0 spam 13 0 0 0.056 0 0.786 0 0 spam 312 0 0 0.055 0 0.718 0 0 spam 168 0 0 0.058 0 0.700 0 0 spam
上記、knn.cvを利用しましたが、インデックスが欲しいだけならば、
同パッケージ内のget.knnを使った方が速いです。
system.time(FNNrescv <- FNN::knn.cv(train=data[,-55],cl=data[,55],k=3,prob=F,algorithm="kd_tree")) system.time(FNNresget <- FNN::get.knn(data=data[,-55],k=3,algorithm="kd_tree"))
> system.time(FNNrescv <- FNN::knn.cv(train=data[,-55],cl=data[,55],k=3,prob=F,algorithm="kd_tree")) user system elapsed 3.07 0.00 3.12 > system.time(FNNresget <- FNN::get.knn(data=data[,-55],k=3,algorithm="kd_tree")) user system elapsed 0.76 0.00 0.76
因みにget.knnの方はattrではなく、リストで値を返してくるのでご注意を。
{kknn}パッケージ
そして、最後に{kknn}パッケージの紹介をしようと思っていましたが、
長くなってしまったので省略します。
多数決を行う時に最近傍k個の重みを調整できたり
クロスバリデーションの機能が充実していたりするのですが、
実務的にはややオーバースペックな印象で、私は使ったことがないです。
本記事では割愛しましたが、多数決の重みやkの数の調整よりも
特徴量自体の正規化や重み付けの方が効くことが多いのかなと思っています。
それでは皆様、来年も宜しくお願い致します。
※間違い等ありましたらご指摘いただけますと幸いです。
TokyoR(第43回)でLTしてきました
半年以上空いての更新となってしまいました。
文章としてアウトプットする習慣がなかなかつかないです。
本題。昨日TokyoRでLTをしてきました。
内容はRのrandomForestの説明と、
使えるメモリに制限がある場合の工夫の仕方についてです。
今回の発表の準備を通して、randomForestが返すオブジェクトの
中の見方が分かったりしたので個人的には非常に有意義でした。
ご指摘もありましたが、さっさとOSを64bitにするというのが私もベストだと思います。(プライベートで使うPCへの投資はなかなか億劫。。)
ですが、ちょっとした工夫で省メモリになったり、高速になったりすることに喜びを感じる私の様な方も少なくないと思いますので、この資料がその様な方々のお役に立てば幸いです。
丸一年経ちました
また久しぶりの更新となってしまいました。
最近は、webサイトのクローリングをちょこちょこ行っています。
これについてはまた改めて書くかも、しれません。
データサイエンティストという言葉を知り、目指し始めたのが去年のこの頃だったと思うので、一年間の振り返りと今年の抱負などを書いてみたいと思います。
■データ整形
当時はまだ、ほとんどperlも触ったことがなくデータ整形を行うのにも非常に時間を費やしていましたが、現在はサクサクと手が動く様になりました。
ただ、複雑なデータ構造を扱うときに、稀にハマるのでまだまだスピード向上の余地があると思っています。
また、モジュールについての知識が全然ないので、今年は便利そうなモジュールはどんどん使ってみる様にしたいです。
■分析
学生の頃行っていた分析はExcel+SPSSだったのですが、SPSSは会社で使っていないのでKnimeとRを主に使うことになりました。
最初は、集計や可視化を行うのも一苦労でしたが、現在は一先ず自分で確認する分には十分になりました。今年は、クライアントさんにそのままお見せできる様な綺麗な可視化、カッコいい可視化ができる様になりたいです。
また、モデリングに関してはlogistic regressionやrandom forestを中心として色々行ってきたので、一応なんとか使えるレベルにはなったと思っています。ただ、変数の作り方やチューニングの仕方についてはまだまだなので、今年はもっと上手くできる様に勉強したいと思います。
■理論
・機械学習
最初は全然理解できないことばかりでしたが、繰り返し繰り返し同じことについて説明している多数の資料を見ることで概念についてはなんとなく理解できる様になってきたと思っています。(数式アレルギーも徐々に克服中)
今年は概念だけでなく、情報理論や確率過程など基礎となる理論についても少しずつ理解を深めていきたいと考えています。
・統計学
統計学は学生時代から使っていたので、他部署の方に仮説検定などについて説明する機会があり、少しは役立てたのではないかと考えています。しかし、基礎的な検定であるχ2乗検定を行うことがあり、その時にすぐ計算ができなくて困ったことがありました。基礎的なものこそ当たり前の様に計算できなければならないと思うので、時間を作って一度振り返りたいものです。
以上、1年間の振り返りと今年の抱負でした。
組織的な色々な問題もあるのですが、環境に振り回されず着実にレベルアップしていきたいと思います。
pythonについて
業務で使う必要があったのでpython始めました。
ソースの可読性が高いなと早速感じていて
一人で勉強するのに向いているなと思います。勉強します。
CentOSに入れようとしたら依存関係の解決が色々面倒だったので断念して、
Windowsに入れました。
本体は本家(http://www.python.org/)から、
パッケージは先輩から教えてもらったところ(http://www.lfd.uci.edu/~gohlke/pythonlibs/)から落として入れました。
バイナリで入れられるので非常に楽でした。裏技みたいな感じ。
たまにここに上がっているバージョンじゃダメだったりするので適宜その場合はアンインストールして入れなおす感じの様です。
近況について
7月末からお盆辺りにかけて担当していた案件が忙しくブログの更新をサボっていました。何となく罪悪感があります。すみません。
最近は仕事が落ち着いたので、為替のデータに対して機械学習を行って儲けられないかとか色々やってました。そのうち結果が出たらブログにまとめようと考えています。
なかなか予測精度が上がらないので「どうして予測できないのかについて」語る可能性が高いですが。
昨日は恒例のTokyo.Rに参加してきました。
細かい感想や意見などは割愛しますが、アカデミア、ビジネスの各方面で活躍されている方々の話は面白かったです。
彼らの話についていくためには休んでいる暇はないなと感じました。努力を続けます。
とりあえず、生きていますということで。