くりーむわーかー

プログラムとか。作ってて ・試しててハマった事など。誰かのお役に立てば幸いかと。 その他、いろいろエトセトラ。。。

R

R SVMのあれこれ

RでSVMの分類器作るときの段取りまとめ。kernlabとe1071を使用。

いつものアイリスデータで。。。

##################################################################################################
#アイリスデータセットを使用
d <- iris

#学習データと検証データを作る
set.seed(256)
id.random <- sample(nrow(d),nrow(d)/2)
d.train <- d[id.random,]
d.test <- d[setdiff(1:nrow(d),id.random),]

##################################################################################################
#とりあえずデフォのパラメータでSVMをやる
library( kernlab )
#学習データでSVMの分類器を作る
d.ksvm <- ksvm(Species ~.,type="C-svc", kernel="rbfdot",data=d.train,cross=5,prob.model=TRUE)

#トレーニングエラー
d.ksvm@error
#交差検証エラー
d.ksvm@cross

#検証データで精度を確認
d.pred <- predict(d.ksvm, newdata=d.test)
rt <- table(d.pred, d.test$Species)
rt

#正答率
before_tune <- as.integer(rt[1]+rt[5]+rt[9]) / as.integer(length(d.pred))
before_tune

そしたら、SVMのパラメータの値をチューニングしてく。


##################################################################################################
#チューニング1回目(適当にコストとガンマの範囲を決めて、1刻みくらいでやる)
library(e1071)
t <- tune.svm(Species ~.,data=d.train,gamma=10^(seq(-10,10,1)),cost=10^(seq(-10,10,1)),tunecontrol=tune.control(sampling="cross",cross=5))
#コストの一番いい値
t$best.parameters$cost
#ガンマの一番いい値
t$best.parameters$gamma
#一番いいパフォーマンス
100-100*tuning$best.performance
#プロット x軸:gamma y軸:cost
plot(t,transform.x=log10,transform.y=log10)

プロットすると↓の感じのグラフが出る。 sample01
そしたら、青い部分が濃い辺りの範囲を再度指定してチューニングを実行する。(ちょっと時間かかる)

##################################################################################################
#チューニング2回目
#1回目のプロットで濃い青になってる辺りを中心に今度は0.1刻みで実行
library(e1071)
t <- tune.svm(Species ~.,data=d.train,gamma=10^(seq(-4,1,0.1)),cost=10^(seq(1,6,0.1)),tunecontrol=tune.control(sampling="cross",cross=5))
#コストの一番いい値
t$best.parameters$cost
#ガンマの一番いい値
t$best.parameters$gamma
#一番いいパフォーマンス
100-100*tuning$best.performance
#プロット x軸:gamma y軸:cost
plot(t,transform.x=log10,transform.y=log10)

プロットしたら↓の感じのが出る。 sample02
もういいでしょ。というこーとで、「best.parameters$cost」の値をSVMのパラメータに入れて実行する。

##################################################################################################
#チューニングしたコストを指定して実行。kparは"automatic"にしておけば勝手にやるらしい。
library( kernlab )
#学習データでSVMの分類器を作る
d.ksvm <- ksvm(Species ~.,type="C-svc", kernel="rbfdot",C=t$best.parameters$cost, kpar="automatic",data=d.train,cross=5,prob.model=TRUE)

#トレーニングエラー
d.ksvm@error
#交差検証エラー
d.ksvm@cross

#検証データで確認
d.pred <- predict(d.ksvm, newdata=d.test)
rt <- table(d.pred, d.test$Species)
rt
after_tune <- as.integer(rt[1]+rt[5]+rt[9]) / as.integer(length(d.pred))
after_tune

自分のPCでは正答率は↓の感じになった。

チューニング前:93.3%
チューニング後:96%

精度は上がった模様。

おまけ。”probabilities”の引数渡すとそれぞれの所属確率を出してくれる。↓の感じ。

d.allprob <- predict(d.ksvm,newdata=d,type="probabilities")
head(d.allprob)
        setosa versicolor  virginica
[1,] 0.9770838 0.01094580 0.01197041
[2,] 0.9563003 0.01973656 0.02396311
[3,] 0.9708821 0.01357799 0.01553994

そしたら、元データにくっつけてCSVあたりに吐けば、個別データを吟味しやすい。

#元データに結合(列)
d.withprob <- cbind(d,d.allprob)
#CSVに出力
write.csv(d.withprob, "iris_withprob.csv")

CSVに出すと↓の感じ。 sample03

RでLDA

タイトルまま。形態素解析した結果のCSV読み込んでやる。色々あると思いますがとりあえず↓の感じ。

#ライブラリ
library(text2vec)
library(LDAvis)

#ワーキングディレクトリ
setwd("C:\\tmp\\hoge")
wdata <- read.csv("data1.csv",header=F,stringsAsFactors=F)
wdata.ids <- as.list(wdata[,1])
wdata.word <- read.csv("data2.csv",header=F,stringsAsFactors=F)

it <- itoken(wdata.word$V1, ids = as.character(wdata.ids))
v = create_vocabulary(it)

#これ!!!
v$term <- iconv(v$term,from="cp932",to="UTF-8")
dtm = create_dtm(it, vocab_vectorizer(v))
lda_model = LDA$new(n_topics = 9)
ldaRes = lda_model$fit_transform(dtm, n_iter = 500)
lda_model$plot()

text2vecを使ったんですが、日本語でやる場合、create_vocabularyのところで、中のtermがunicodeのエスケープ文字に変換されてしまい、そのあとの関数が軒並みダメになる。なので、「iconv(v$term,from="cp932",to="UTF-8")」で文字を戻す必要あり。

最初、utf-8に変換されてるのかと思い、「iconv(v$term,from="UTF-8",to="cp932")」←こう書いてたんだけど上手くいかず。読み込みデータの文字コード色々変えたり試行錯誤した結果、逆だったという事です。はまった。

あと、CSV読み込むときは、「stringsAsFactors=F」←これ付けないと、factor扱いになって、後続の関数が動かない。要留意。

C#からRを使う

この前、Rを外部から実行するっていうの書いたけど、C#から呼ぶためのライブラリが普通にあったので、書き直し。探し方が悪かったかしらね。。。

R.Netっていうのを使う。NuGetからインスコ。「R.NET.Community」っていうのもあるんだけど、何が違うんだろうか?リンク先とかも一緒なんだけど。。。あー、もちろん使う場合は端末にR本体がインストールされてる必要あり。

そしたらとりあえず、呼び出しサンプル。

using RDotNet;
static void Main(string[] args)
{
    REngine.SetEnvironmentVariables();//これは省略可。
    using (REngine engine = REngine.GetInstance())
    {
        engine.Evaluate("sample.data <- iris");
        engine.Evaluate("str(sample.data)");
    }
    Console.WriteLine("おしまい");
    Console.ReadLine();
}

↑は呼び方的には公式のチュートリアルのまま。

まず、32bitか64bitでビルド変えないとだめかも。64bitでやる場合はプロジェクトのプロパティ⇒ビルドで「32ビットを優先」のチェックを外さないとだめそうですね。あと、使うR.dllのフォルダも設定が必要。さらに、Rのパスを通してない場合は、実行時に環境変数のPATHにRのパスを追加しておいた方が良さげ。で、色々したのが↓。パスを編集するメソッドはさすがのすたっくおーばーふろーがサンプル。

static void Main(string[] args)
{
    string rpath = SetupPath("R-3.4.2");//インストールしたバージョンを指定
    REngine.SetEnvironmentVariables(rpath);
    using (REngine engine = REngine.GetInstance())
    {
        engine.Initialize();//最近はこれがいるらしい
        engine.AutoPrint = false;//これ付けないと代入してる式で中身が丸ごと出てきてうざい
        engine.Evaluate("sample.data <- iris");
        engine.Evaluate("str(sample.data)");
    }
    Console.WriteLine("おしまい");
    Console.ReadLine();
}
public static string SetupPath(string Rversion)
{
    string rDllPath = Environment.Is64BitProcess ?
                    string.Format(@"C:\Program Files\R\{0}\bin\x64", Rversion) :
                    string.Format(@"C:\Program Files\R\{0}\bin\i386", Rversion);
    //DLLのフォルダが無かったら例外
    if (!Directory.Exists(rDllPath))
    {
        throw new DirectoryNotFoundException(string.Format("Not found : {0}", rDllPath));
    }   
    var newPath = string.Format("{0}{1}{2}", rDllPath, System.IO.Path.PathSeparator, Environment.GetEnvironmentVariable("PATH"));
    Environment.SetEnvironmentVariable("PATH", newPath);
    return rDllPath;
}

でだ、ここまでやっても何故だか実行時に「Rlapack.dllがありません」みたいなエラーが出る端末が稀にいる。意味が分からん。どう見てもあるんだけどね。。。プローブ?がおかしいのだろうか。そういう時はとりあえず、実行ファイルと同じフォルダに「Rlapack.dll」をRのインストール先からコピーしてあげると動くようになる。なんだろね。

ほいで、あとは色々な呼び出し。

static void Main(string[] args)
{
    string rpath = SetupPath("R-3.4.2");
    REngine.SetEnvironmentVariables(rpath);

    using (REngine engine = REngine.GetInstance())
    {
        engine.Initialize();
        engine.AutoPrint = false;

        ////////////////////////////////////////
        //arulesでアソシエーション分析
        ////////////////////////////////////////

        //ライブラリの読み込み
        engine.Evaluate("library(arules)");
        //アソシエーション分析
        engine.Evaluate("data(\"Adult\")");
        engine.Evaluate("rules <- apriori(Adult,parameter=list(minlen=2, maxlen=4, support=0.5, confidence=0.9))");
        //結果のサマリー
        engine.Evaluate("summary(rules)");
        //結果の表示
        engine.Evaluate("inspect(rules)");
        //RのデータフレームをC#で扱えるデータにする
        var dd = engine.Evaluate("Adult@itemInfo").AsDataFrame();
        //つまみ食い
        Console.WriteLine(dd[1, 1]);


        ////////////////////////////////////////
        //kmeansの結果を取得
        ////////////////////////////////////////
        //irisデータ使う(いつものやつ)
        engine.Evaluate("iriswk <- iris[1:150, 1:4]");
        engine.Evaluate("iriswk.km <- kmeans(iriswk, 2)");
        engine.Evaluate("iriswk.km");
        engine.Evaluate("iriswk.km$cluster");
        var kmlist = engine.Evaluate("iriswk.km$cluster").AsNumeric();

        ////////////////////////////////////////
        //Plotの画像をファイルにはく
        ////////////////////////////////////////
        var path = Path.Combine(Path.GetTempPath(), Path.GetTempFileName() + ".png");
        string Code = @"plot(1:10, pch=1:10, col=1:10, cex=seq(1, 2, length=10))";
        engine.Evaluate(string.Format("png('{0}', {1}, {2})", path.Replace('\\', '/'), 420, 420));
        engine.Evaluate(Code);
        engine.Evaluate("dev.off()");
        
    }
    Console.WriteLine("おしまい");
    Console.ReadLine();

}

R 外部から実行

Rをターミナル使わずに、外部からスクリプト呼んで動かしたい場合。コマンドで動かせるから外部から呼べる。OSはWindows。

R CMD BATCH HOGEScript.R

ただ、デフォだとパスが通ってないと思うので、Rはフルパスで書かないとだめ。それかパス通す。

で、とりあずこれで動くんだけど、何も指定してないと色々微妙。普通に動かすとまず、コンソールに出る出力結果が.Routっていうテキストに出力される。これいらない。必要なときもあるかもね。

あと、終了する時に作業領域が勝手に保存される。すごく邪魔。なので今は↓の感じで読んでる。

R --vanilla --quiet --file=HogeScript.R

あと、スクリプトの中で「q(save="no")」最後に入れたほうがいいかも。

マニュアルの「Invoking R」に書いてあるまま。CMD BATCHって何がいいのかよくわからない。出力をテキストに出してくれるってことなんかな。

で、調べてみたけど、コマンド以外で呼ぶことはできないのかしら。サービスみたいな感じに動かせないものか。。。

R アソシエーション分析用のデータを作るあれこれ

すぐ忘れるのでひとまずメモ。

データ分析にアソシエーション分析(バスケット分析)っていうのがある。Rを使ってやるんですが、これをやるとき、元ネタデータの整形をどうするかいっつも忘れるので特筆。

基本的には↓感じのデータを使う想定。

1課	2課	3課	4課	5課	6課	7課	8課	9課
1	1	1	0	0	0	0	0	0
0	0	0	1	1	0	0	0	0
0	0	0	0	0	1	1	1	1

で、これをRのアソシエーション分析(arules)で使う場合、最終的に↓の感じに変換する。

1課,2課,3課
4課,5課
6課,7課,8課,9課

こんな感じのデータをトランザクションデータというらしい。

Rでこれをやる場合、トランザクションデータをそのまま読む場合は↓の感じ。

hoge.tran <- read.transactions("test.csv",sep=",",format="basket")

トランザクションデータの場合はこのままaruleに食わせられる。

hoge.ar <- apriori(hoge.tran)
inspect(hoge.ar)

↓のタイプのデータを読む場合は

1課	2課	3課	4課	5課	6課	7課	8課	9課
1	1	1	0	0	0	0	0	0
0	0	0	1	1	0	0	0	0
0	0	0	0	0	1	1	1	1

R上は↓の感じで読む

#CSVから読み込み
hoge <- read.table("test.csv",header=TRUE,sep=",",row.names=1)
#行列に変換
hoge.mat <- as(hoge,"matrix")
#トランザクションに変換
hoge.tran <- as (hoge.mat,"transactions")
#あとは一緒
hoge.ar <- apriori(hoge.tran)
inspect(hoge.ar)

データフレームからは直で変換できないっぽいので行列に一回変換する。

まー結局、Rに食わせる用のデータ形式を色々準備しないとね。基本的にはアンケートの選択肢とか、商品のマスタとかマスタを全部横に並べて、0か1のON・OFFデータを作るのが一番楽かな。

数値系のデータは値の範囲でコード化してON/OFFのデータを作らないとダメかしらね。

Rでワードクラウド その2

ワードクラウドを作るおおまか手順。
  1. テキストを単語にバラし、単語の出現数(率)を集計する
  2. Rで集計結果を読み込んでwordcloudでプロット
単語の出現数を求められればあとはそれをwordcloudに喰わせるだけ。

単語をバラすのにMeCabを使う。MeCabをRから呼び出すRMeCabのライブラリを使ってもできる。ただ、簡単な文章はよいのだけれども、多少量があるとなんかの制限にかかって動かない。なので、Rubyとかテキトーなスクリプトなりプログラムなりで自分でカウントする方がてっとりばやい。

私はMeCabに解析させたいテキストファイルを食わせて結果を取得⇒カウントしてCSVに保存⇒Rで読み込んでプロットしてる。あとで色々使い回したいから、MySqlにMeCabの解析結果をつっこんで、Rubyで拾って集計してる。集計部分はまた今度載せるとして、Rで読み込みプロットする部分。

↓の感じで「単語,出現数」の集計結果のCSVを準備
・・・
項,2
通り,3
否定,2
対,61
懐疑,3
ECB,17
国債,11
購入,5
・・・
そしたらRでCSVを読み込む
data1 <- read.csv("C:\\R\\wordcount.csv",header=FALSE,row.names=1)
このまま使ってもいいけど、出現数が10回以上の単語だけ出すみたいな事をしたい場合は↓の感じで絞る
data1sub <- subset(data1, data1[, 1] >= 10)
プロットする際の色を決める
Color <- brewer.pal(9, "Blues") #文字色
Color <- Color[-(1:3)] #薄い色を消す
プロット
wordcloud(row.names(data1sub), data1sub[, 1], scale=c(6,.2),random.order = T, rot.per = .15, colors = Color)
ライブラリの読み込みからまとめて書くと↓の感じ
library("RColorBrewer")
library("wordcloud")
data1 <- read.csv("C:\\R\\wordcount.csv",header=FALSE,row.names=1)
data1sub <- subset(data1, data1[, 1] >= 10)
Color <- brewer.pal(9, "Blues") #文字色
Color <- Color[-(1:3)] #薄い色を消す
wordcloud(row.names(data1sub), data1sub[, 1], scale=c(6,.2),random.order = T, rot.per = .15, colors = Color)

Rでワードクラウド作るのはいい感じなんだけど画像なのがまれに傷。FlashとかJQueryのプラグインとかでなんかかっこいいのないかなーって探してみたけど、グッとくるものがない。さらにJSONとかでデータ渡せると胸が熱くなると思う。じゃ作れとか言われそうですが。 見た感じはRのこのwordcloudっぽく。ホイールクリクリしたら中まで入っていけたり、文字をクリックでリンクしてみたりとかを夢見てみる。

Rでワードクラウド

テキストマイニングで単語の出現率を出すけど、いまいちエクセル的な一覧だとぱっとしない。なんかぱっと見、ふーんで終わってしまう。なんかいい表現方法がないものかと思ってワードクラウドに行きついた。

↓の感じ。

plot

↑はとある為替関係のサイトのアナリストさんのRSSを単語の出現率でワードクラウド表示してみたもの。

こういう見せ方をするとなーんか傾向が見えてきそうなモヤモヤ感が出てくるじゃない。。。

Rのwordcloudを使って作る。

具体例はまた今度。

Rでplot結果を画像に出力する方法

wikiにも載ってるけど、Rでplotを結果を画像に出力する方法。

png("C:/R/plot.png", width = 480, height = 480, pointsize = 12, bg = "white", res = NA, restoreConsole = TRUE)
plot(1)
dev.off()

dev.off()しないと出力が完了してくれない模様。

Rのスクリプトをコマンドプロンプトから実行して、plotの結果を画像として出力させたい場合に使ってる。とある統計を毎日実行でフォルダ指定して画像を出力⇒Webアプリ側から表示みたいな事に使用中。

Rのライブラリをインストールするあれこれ

最近、テキストマイニングを試してたり。

Rのライブラリのインストールで時間くったのでメモ。

Rでライブラリをインストールする場合、普通は↓。
install.packages("ggplot2")

自宅とかだとこれでいいんだけど、会社とか外部への接続が
わんさか切られてるとことかだとムリ。

プロキシの設定をちゃんと通せばいけるらしく、試してみたけどムリ。
ちなみにやってみたのは↓。

Rのコンソールを起動後に
Sys.setenv(http_proxy="http://プロキシサーバ:ポート")
認証がダメかと思い↓でやってみる
Sys.setenv(http_proxy="http://user:password@プロキシサーバ:ポート")

これも失敗。

なので、パッケージを直接手でダウンロードしてそれからインストールした。

欲しいパッケージの名前で「R CRAN パッケージ名」でググればCRANのページが出てくるので、
そこの「Windows binaries」のZipのどれかをダウンロード。たぶん「r-devel」か「r-release」あたり。
ぁ、OSはWindowsの話です。

Zipをダウンロードしたら”解凍しないで”適当なフォルダに置いて↓を実行

install.packages("[ダウンロードしたファイルのフルパス]", repos = NULL)

↓の感じ

install.packages("C:/R/ggplot2_1.0.0.zip", repos = NULL)

ただ、これだとライブラリの中でさらに使っているライブラリまではインストールできない。
なので、「library(ggplot)」みたいにすれば「このライブラリがねー」みたいなエラーが出るのでそれを頼りに
ダウンロード⇒インストール⇒エラー⇒ダウンロード⇒インストール・・・・をエラーで無くなるまで繰り返す。

めんどくさい。。。
まぁ、ネットワーク周りはハマると時間がかかるので、手っ取り早く使い始める方法。。。

あと、Windowsのアレなところで、ファイルを置いておくフォルダは下手に深い階層だったり、
日本語が含まれてると動かないまくりになるので、漢らしくCドラ直下くらいのフォルダに
置いておくのが吉みたいよ。。。

問合せ