R

プログラマーのためのR言語入門

なにやらR言語界隈が盛り上がってるそうで。
こちらのIEEE SPECTRUMが発表している2015年の人気言語ランキングではついに6位にまで登ってきています。
この流れにのってR言語を始める人も多いと思いますので、ポイントをまとめておくメモです。

統計とか機械学習とかの内容ではなくプログラム言語としての部分ですのでご注意を。また、1からしっかりではなく、他の言語と違っているところ中心です。

追記:
やっと続編も書けました。
プログラマーのためのR言語入門 その2 ~分析・表示編~

ざっくりとどんな言語?

統計の機能が盛りだくさんのスクリプト言語です。
似ている言語は?と聞かれるとPythonと答えています。

環境

以下をインストールします。

RStudioはR用のIDEです。R言語単体のインストールでも簡易なエディタはついてきますが、何かと便利なRStudioがおすすめ。

変数・演算子・コメントアウト

まずは基本から。

  • 代入は"<-"を使います。
    • 変数定義は初期化や型宣言は意識せずそのまま 変数 <- xxx とします。
    • 実は逆 "->" でも大丈夫です。
      • 何か計算式を試行錯誤したあと、最後に …->hogeとしても良いのでさり気なく便利。
  • 四則演算は " + - * / " を使うのは一般的なところです。 剰余も用意されていて " %% " を使います。
  • コメントアウトは " # " です。

この辺は何らかのプログラム言語触っていれば問題ないかと。

演算子
> a <- 123 #代入
> a
[1] 123
> 
> a <- a + 1
> a
[1] 124
> 
> a %% 5 #余りの演算
[1] 4

変数命名("."の扱い)

Rでの変数命名は少し変わっています。
"."(ピリオド)がプログラム的な意味を持っておらず、普通の文字列として扱われます。
そして変数命名の際の区切り文字としてよく使われます。

変数名
data.train <- xxx
data.test <- xxxxx

のように使われます。
"data"のメソッドというわけでも"data"という構造体なわけでもなく、単なる区切り文字です。

型確認・変換

変数の型を確認する場合はtypeof()やmode()やclass()を使います。
確認方法が沢山あるのは単にRの変数といっても数値型や論理型のような基本型もdata.frameのようなオブジェクトも混ざっているため、データの構造を見るのかデータの型を見るのか等の違いが出てくるからです。
(でも大体はほとんど意識することなくmodeやclassを使うとうまくいきます。)

変換はas.xxx()とします
as.numeric()
as.character()
as.data.frame()
など。

参考:
- データ型とデータ構造

制御構文

ここもさらっと。

  • if文はカッコ内に条件、中カッコ内に処理です。whileも同様。 if(条件){処理} else if(){} else {}
  • switch文は swhich(対象,"ケース"=処理,"ケース"=処理,その他の処理);
switch
a<-"犬"
switch(a,
       "犬"=print("わん"),
       "猫"=print("にゃん"),
       "鳥"=print("ぴよ"),
       print("ぎゃふん")
)
  • for文は for-in の形式 for(i in 1:100){処理} 例は1~100までの数値を1個ずつ"i"にセットしながらループしています。 foreach文(PHPなど)や拡張for文(Javaなど)と似た形式です。

関数定義

関数定義は
f <- function(引数){return(戻り値)}
引数部分はデフォルト値を設定することもできます。
また、呼び出し時は仮引数名を指定も可能です。

関数定義
f<-function(a,b=2){
  return(a * b)
  # a*b #←return省略も可能
}

> f(2)
[1] 4
> f(b=3,a=2)
[1] 6

ベクトル操作

このあたりからR言語っぽくなってきます。
R言語はデータの統計処理用言語なので連続したデータを扱うことが多いです。
基本的にベクトル単位で扱います。
データをc()で囲うことでベクトルになります。

ベクトル
> vec <- c(1,2,1,2,3,4,1,2,3)
> vec
[1] 1 2 1 2 3 4 1 2 3
> vec[3]
[1] 1

各要素へのアクセスは大かっこ"[]"で指定します。

他の言語の配列と一緒と思いがちですが、配列ではなく"ベクトル"です。数学的な意味で。
なので、以下のような演算ができます。

ベクトル演算
> vec1 <- c(4,5,2,3)
> vec2 <- c(1,2,1,2)
> 
> vec1 / 2
[1] 2.0 2.5 1.0 1.5
> vec1 - vec2
[1] 3 3 1 1
> vec1 * vec2
[1]  4 10  2  6

生成

数列などのベクトルを生成したい場合がよくあります。
そんな場合はrepやseqを使います。

  • コロン 1:10 とすると1~10までのベクトルができる。数列を作る場合以外にも範囲指定などで多用する。
  • seq(開始,終了,length = 要素数) / seq(開始,終了,by=増加) 開始と終了を指定し、間の補完方法を指定する形
  • rep(ベクトル,times=長さ) 第一引数のベクトルを長さtimesになるよう繰り返す
seq/rep
> seq(1,10,length=5)  #1~10を5分割で
[1]  1.00  3.25  5.50  7.75 10.00
> seq(1,10,by=2) #1から2ずつやして10まで
[1] 1 3 5 7 9

> rep(1:3,times=2) #(1,2,3)を2回
[1] 1 2 3 1 2 3
> rep(1:3,length=5) #(1,2,3)を5個になるまで繰り返す
[1] 1 2 3 1 2

これもまた高機能で、日付の生成なんかもできます。

日付生成
> seq(as.Date("2016-01-01"),as.Date("2016-01-05"),by="day")
[1] "2016-01-01" "2016-01-02" "2016-01-03" "2016-01-04"
[5] "2016-01-05"

集計関数

今の例では数値を数個書いているだけで面白くないですが、実際にR言語を使う際は何らかのデータ数万件などをベクトルで扱うことになります。
そこでデータの性質を知るために集計するわけですが、集計関数は非常に充実しています。よく使うものを列挙。

  • max / min / which.max / which.min 最大値/ 最小値/ 最大値のある場所 / 最小値のある場所
  • unique 重複除去
  • sum / mean / median / var 合計 / 平均値 / 中央値 / 不偏分散
  • log / sqrt / sin / cos / exp ・・・ 対数 / 平方根 / サイン・・・

…大体なんでもある。Excelの計算式名を参考にすると何かしらある。
さらにこんな便利な関数も。

  • summary ベクトルに限らず要約を表示。ベクトルなら最大最小や四分位が見れる。
集計
> v <- c(4,5,2,3)
> max(v)
[1] 5
> which.min(v)
[1] 3
> mean(v)
[1] 3.5
> summary(v)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   2.00    2.75    3.50    3.50    4.25    5.00 

データフレーム

Rでデータ分析をする際にはこのdata.frameと言われる形式で保持することが多いです。分析用関数も引数にこの形式のデータを受け取る場合が多いです。
data.frameは2次元配列のような表形式のデータ型です(列ベクトルのベクトル)。また単に2次元なだけでなく列名行名などの付加情報を持っています。

作成と参照

data.frame(列名=ベクトル[,…])の形で定義します。

作成
data <- data.frame(
  "商品" = c("りんご","たまご","キャベツ"),
  "値段" = c(100,20,120)
)

> data
      商品 値段
1   りんご  100
2   たまご   20
3 キャベツ  120
> head(data)
      商品 値段
1   りんご  100
2   たまご   20
3 キャベツ  120
> 

データ量が多くなった場合はhead()を利用すると先頭数行だけ表示できます。

次に特定の行や列の参照です。基本的に行や列の参照は
data[行指定,列指定]
の形式で書きます。省略した場合は"すべて"の扱いになります。
また、列名での指定もできます。
data$列名
サンプルを見てみましょう。

data.frame参照
> data[1,2]  #りんごの値段
[1] 100

> data[,1] #一列目(商品列)
[1] りんご   たまご   キャベツ
Levels: キャベツ たまご りんご

> data$値段 #"値段"列
[1] 100  20 120

> data[2,] #2行目
    商品 値段
2 たまご   20

> data[c(1,3),] #ベクトル指定
      商品 値段
1   りんご  100
3 キャベツ  120

> data[-1,] #1行目以外
      商品 値段
2   たまご   20
3 キャベツ  120

#応用編)値段が50以上の行を指定
> data[50<data$値段,]
      商品 値段
1   りんご  100
3 キャベツ  120

apply関数群

data.frameにデータを保持するわけですが、そうすると、各列ごとに合計値を出すだとか、行ごとの最大値を見つけるといったように行ごと列ごとに処理を行う機会が多々あります。
そういった「行や列ごとに同様の処理を行う」動作を効率よく行う手段としてapply関数というものが用意されています。
この機能があるため、Rでは行ごと列ごとにループさせるというような冗長なfor文は嫌われる傾向にあります。

使い方は
apply(データ,方向指定,処理関数)
データは処理対象のデータフレーム、方向指定は"1"なら行ごと"2"なら列ごと"c(1,2)"なら要素1つずつに対して処理をします。

例えば列ごとに合計値を出す場合は

apply
> data
  A B C
1  80 100  90
2  80  20  90
3 110 120  90
> apply(data,2,sum)
A B C 
270 240 270 

処理関数は自分で記述することもできます。
行ごとに最低値の1.08倍を計算するようにしてみます。

apply自作関数
> apply(data,1,function(v){return(min(v)*1.08)})
[1] 86.4 21.6 97.2

注意点は関数に渡している引数です。行ごと(もしくは列ごと)に処理しているのでこの引数は1行(もしくは1列)の"ベクトル"が入ってきます。
そのベクトルを一つの値に集計してreturn()で返す、という処理になります。

また、自作関数に複数の値を渡したい場合は第4引数以降に書けます。

apply自作関数2
> f<-function(v,add){
+   return(min(v)*1.08+add)
+ }
> apply(data,1,f,3)
[1]  89.4  24.6 100.2

applyは単に行と列の処理だけでなく、よく使う処理を実現できるようにapplyの亜種が幾つかあります。

  • tapply
  • mapply
  • lapply
  • sapply

などなど。詳しい使い方は今回は省略しますが、こんなことができますという例だけでも載せておきます。

テストの点と血液型のデータがあったとして、、、
血液型ごとの平均値を科目ごとに求めます。

applyとtapply
> data
  国語 算数 血液型
1   80   60      A
2   80   90      B
3   70  100      O
4   55   40      B
5   80   90      A

> apply(data[,-3],2,function(v){
+   tapply(v,data[,3],mean)
+ })
  国語 算数
A 80.0   75
B 67.5   65
O 70.0  100

参考:

その他Tips

  • "?"+関数名 でヘルプが見れます。
    例:?which.max

  • Excelからクリップボード経由でデータが読み込めます。
    エクセルで該当範囲をコピーし
    xxx <- read.table("clipboard")
    とすることでdata.frame型で読み込めます。

  • すべてのオブジェクトをクリア
    rm(list=ls())

参考

おわりに

まとめていけばいくほど、まだまだあれもこれもまとめなきゃいけないことが出てきます。行列計算や作図関連やパッケージ導入など…。
それが終わって○○分析とか○○モデルとかに入ってくるとやっとR言語本領発揮という流れです。
まだまだ先は長い。