こんにちは、エンジニアのnishimuです。
最近Rの勉強を始めました。Rが使えるようになると色々なデータが統計的に分析できるようになるので、そろそろ社内でも出番があるかなと思っています。
Rの資料については既に詳しいものがWebや書籍上に数多く存在しています。今回の記事は、Rの詳しい解説というよりは、Rでどんなことができるのかちょっと体験してみたい、という人向けをコンセプトにした記事です。細かい説明、厳密な説明を入れだすと内容が膨れて重たくなる一方なので、かなりざっくり目に書いてあります。(それでも結構な分量になってしまった気がします)
細かい所までしっかりと勉強がしたいということであればRjpWikiR-Tipsが充実していますのでそちらをご参照ください。

それでは早速いきましょう。

インストール

基本的にはここのページの「Download R for Windows」とか「Download R for (Mac)OS X」等のリンクを辿ってパッケージを落としてきてインストールするだけでOKです。
X11がデフォルトで入っていない最近のMacをお使いの人はXQuartzもインストールしておきましょう。
Linuxについてはディストリビューションによって異なります。redhat系ならばepelリポジトリを追加して

でインストールできました(CentOS6.5で確認)。
うまくいかない方はRjpWikiのこちらのページも参考にしてみてください。

実行方法

Rには何種類か実行方法があります。

1. RのGUIアプリケーションの利用

GUIのRを立ち上げるとコンソールのウィンドウが開いた状態になっているかと思います。コンソールに実行したいコマンドを入力していきましょう。

2. CUIから対話モードのRを立ち上げて使う方法

Rにパスを通した状態で(インストール時に自動で設定されていると思います)ターミナル上で”R”コマンドを実行すると対話モードでRが立ち上がるので、実行したいコマンドを入力していきましょう。終了したい際は”q()”を入力しましょう。

3. 予め作成したRスクリプトをバッチモードで実行する方法

例えばhoge.Rというスクリプトに実行したい処理をまとめてある場合はCUI上で

などとして実行します。
“–vanilla”オプションはRがこれまでに保存していたセッションを読み込まない状態で起動します。”–slave”を指定するとRの出力が標準出力に表示されないようになります。(※厳密には–vanillaも–slaveも複数のオプションの組み合わせから構成されており、他の効果もあります。)
スクリプトのデバッグ時などは”–vanilla”オプションだけでよいでしょう。

CSVを読み込んでグループ集計をしよう

サンプルのCSVを用意しました。こちらをダウンロードしておいてください。
これは、とある学校の生徒の学籍番号(student_id)、名前(name)、クラス(class)、学習時間(stydytime_h)のリスト、という想定のCSVです。
また、グループ集計に使うパッケージを以下のコマンドを使ってインストールしておきましょう。

どのミラーからインストールするのか尋ねられますが、一番近いところを選んでおけば大丈夫です。

それではサンプルのCSVを読み込んで、クラス毎に学習時間の平均値、最大値、最小値を求めてみましょう。

L.12の”result”を実行したところで結果が以下のように表示されたかと思います。

これがクラス毎の学習時間の平均値、最大値、最小値になります。

それではサンプルコードを解説していきます。

read.csv関数によってcsvからデータを読み込んで変数csvdataに格納しています。header=Tはcsvの1行目がヘッダ行であることをRに教えてあげています。stringsAsFactors=Fは、CSVの文字列カラムがFactor型として読み込まれないようにするために設定しています。

headはデータの最初の数行を取り出す関数です。nに表示したい行数を指定します。
これを実行すると以下のように出力されたかと思います。

csvdataの3行目までが表示されています。

この部分がグループ集計処理をしている部分です。
L.3で集計に使用するdplyrパッケージを読み込んでいます。
L.4〜L.11でグループ集計をした結果を変数resultに格納しています。
csvdataのデータの”class”カラムについてのグルーピングを行い(group_by(class))、studytime_hカラムの平均(mean)をstudytime_h_meanカラムに、最大値(max)をstudytime_h_maxカラムに、最小値(min)をstudytime_h_minカラムに格納する集約処理を行います(summarise)。L.11のas.data.frameはデータフレーム形式に変換するというものです。

変数resultの中身を表示する処理です。

グループ集計を使ってアクセスログの時間帯別集計をしてみよう

上の例は読み込んだCSVが既に整形されており、そのまま集計にかけることができました。 しかし、現実のデータは前処理が必要なことがほとんどです。 例えば以下のようなデータが手元にあるとします。

access_id access_time
2969 2013-06-01 01:20:36
3526 2013-06-01 15:18:29

これはWebサイトのアクセスログを想定したものです。(ダウンロード) このアクセスログから、どの時間帯(1時間単位で0〜23時という区分)にどれだけのアクセスがあるかを集計したいとします。 アクセスログは時刻が秒単位で刻まれており、このカラムでそのままグルーピングすることはできません。 今回はアクセスログの生データに対して前処理を行ってからグループ集計を行います。

それでは解説します。
上記のコードで一番のポイントとなるのはL.2です。

csvに含まれるaccess_timeはそのままではグルーピングに使用できないので、このカラムから何時台であるかという情報を抽出したカラムaccess_hourを追加作成します。このときに文字列抽出関数substrを使います。第一引数に抽出元のデータ、第二引数に何文字目から抽出開始するか、第三引数に何文字目まで抽出するかを記述します。
この時点でheadを使ってlogdataの中身を見てみると以下が確認できます。

あとは前セクションと同様に、dplyrパッケージを使って集計を行います。

access_hour毎のログレコードの数をカウントしたかったのでsummarise(cnt=n())でcntカラムにカウント結果値を格納しています。
また、arrange(desc(cnt))でcntの降順ソートを取っています。
結果は以下のようになります。

午前9〜10時、午後18〜23時がアクセスの多い時間帯のようですね。

複数のCSVから読み込んだデータの結合

これまでに紹介した例では読み込んだCSVは一つでした。しかし実際には複数のCSVを読み込んで結合するという作業が必要になることがあります。SQLでいうところのjoinの操作です。
サンプルとして用意したのは、とある学校の定期試験の科目毎の成績データを想定したものです。(ダウンロード)

この科目毎に分かれているデータを一つに結合してみましょう。これは、次のセクションで扱うクラスタリングに必要な前処理でもあります。

前半はひたすらCSVの読み込みなので特に問題ないと思います。
後半も同じことを繰り返しているだけですので、次の行さえチェックしておけば大丈夫です。

ポイントは2つあります。merge関数の使い方と、そのmerge関数の引数になっている’kokugo[,c(“student_id”, “KOKUGO”)]’です。

merge(input1,input2,by=”column1″)は”by”に指定したカラムでinput1とinput2を内部結合するという関数です。また、all.x=Tを指定することで左結合になります。
kokugo[,c(“student_id”,”KOKUGO”)]は、データフレームkokugoからstudent_idカラムとKOKUGOカラムのみを抽出したものになります。kokugoには余分なカラムであるnameが存在しており、それを除外したものをmergeに渡しています。

結果のheadを取ると以下のようになります。

全科目分のデータが乗ったstudents_scoresを作成することができました。

k-means法を使ったクラスタリング

いよいよこの記事のタイトルにもなっているクラスタリングに挑戦します。
前セクションで作成した試験成績の結合データを使って、生徒を試験成績の傾向でクラスタリングします。クラスタリング手法にも種々ありますが、一番手軽なk-means法によるクラスタリングを紹介します。k-means法は以下の手順を用いるクラスタリング手法です。

1. 初期値として各レコードをランダムにk個のクラスタに割り当てる
2. 各クラスタに属するレコードの中心値を計算する
3. レコードそれぞれを一番中心が近いクラスタに再割り当てする
4. 2番と3番の処理を収束するまで繰り返して最終的な各レコードの所属クラスタを得る

Rでは組み込みの”kmeans”関数により簡単にk-meansクラスタリングの処理を行うことができます。

inputdataには数値ベクトルからなるデータフレームもしくは数値の行列が指定できます。
今回は試験成績でクラスタリングを行います。inputdataとして、生徒の名前や学籍番号、クラスといった試験成績以外の情報を省いてkmeans関数に渡します。

kには何個のクラスタに分割するかという数を指定します。
クラスタ数kをどのように決定するかについてですが、色々調べてみたのですが今のところよく分かっていません(すみません)。様々な範囲のkで試行錯誤しながら探っていってます。

以下がクラスタリングを行い、そのクラスタ番号を付与した生徒リストを作るまでのサンプルコードです。students_scoresは前セクションで作成したものをそのまま使用します。

解説します。kmeans関数に渡しているstudents_scores[,5:13]は生徒リストから試験成績の部分のみを抽出したものです。kmeans_resultにkmeans関数の結果が格納されているのですが、それぞれの生徒がどのクラスタに属しているかについてはkmeans_result$clusterを参照します。
試しにkmeans_result$clusterを表示してみましょう。

2,5,1,…と数字が並んでいますが、これが元データの1行目のクラスタ番号、2行目のクラスタ番号,…という風に対応づいています。これをそのまま元データに結合すればよいです。
これで、クラスタ番号が付与されたデータclustered_studentsが作成されました。
あとはこれを使って集計をしていきましょう。

※k-meansクラスタリングは計算の最初に与えられる初期値で結果が変動します。上記の結果の通りになるとは限りません。

クラスタリング結果の集計

クラスタ毎の各科目の平均点、最大値を求めてみましょう。
既に紹介したグループ集計を使えば可能です。

こんな結果になりました。

どうやら主要5科目が得意なクラスタ(クラスタ2)、理系科目が得意なクラスタ(クラスタ1)、文系科目が得意なクラスタ(クラスタ3)、実技科目が得意なクラスタ(クラスタ5)、得意不得意が特にないクラスタ(クラスタ4)が存在しているようだということが読み取れます。

まとめ

いかがでしたか?この記事ではRの体験をしてみようということでグループ集計やクラスタリングの例を紹介しました。
簡単なデータ分析ならばエクセルなどでも可能ですが、Rを活用すればより高度な処理ができたりするので、気になった方は使ってみてはいかがでしょうか。