日々のつれづれ

不惑をむかえ戸惑いを隠せない男性の独り言

data.frameとmatrixの違い

Rの行列表示には、data.frameというものがある。
matrixとの違っていろいろな型を放り込めるところがすごく便利。

> (x <- matrix(1:12,3)) # 全部が数値のmatrix
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
> y <- LETTERS[1:3]
> cbind(x,y) # 強制的に文字になる
y
[1,] "1" "4" "7" "10" "A"
[2,] "2" "5" "8" "11" "B"
[3,] "3" "6" "9" "12" "C"

これが、さっき書いた型の優先順位ってやつ。

でも、同じ型しか扱えないのは統計解析上、面倒だ。
例えば、2症例の多重比較を考えただけでも、パラメータは前治療の有無(TRUE/FALSEの論理値)、性別(男/女の2因子)、生存日数(10日、20日などの整数)、体重(数値)、問診結果(解析自体が難しいけど、文字)と、いろいろ混じってくる。

で、data.frameはこれを回避できるオブジェクトを提供する便利関数。

#さっきのmatrixをdata.frameで準備する
> x <- data.frame(matrix(1:12,3))
> y <- LETTERS[1:3]
> (x <- cbind(x,y)) # 上との違いに注目、数字と文字が共存できる
  X1 X2 X3 X4 y
1  1  4  7 10 A
2  2  5  8 11 B
3  3  6  9 12 C
> str(x)
'data.frame':	3 obs. of  5 variables:
 $ X1: int  1 2 3
 $ X2: int  4 5 6
 $ X3: int  7 8 9
 $ X4: int  10 11 12
 $ y : Factor w/ 3 levels "A","B","C": 1 2 3

matrixでは、文字ベクトル(y)を数値マトリクス(x)に列方向に結合(cbind)すると、全てが文字になりましたが、data.frameは1~3列目までは数値(integer)のままです。
つまり、数値の型を残したまま、他の型を繋いだ行列が準備できる。

でも、ここで注意。
文字ベクトル(y)がcbindすると因子ベクトルになっている。
これは、data.frame関数の副作用で、文字ベクトルはデフォルトで因子ベクトルに変換される。
統計上、文字はカテゴリ変数を意味することが多く、自動的に因子にしてしまった方が楽だからじゃないか、と思っている。

もし、文字の型で残したいなら、こうする。

> x <- data.frame(matrix(1:12,3))
> y <- LETTERS[1:3]
#ここまでは同じで、data.frame関数の使い方を少し変える

#I(文字ベクトル)で文字ベクトルのまま、引き渡せる
> (x1 <- data.frame(x,I(y)))
  X1 X2 X3 X4 y
1  1  4  7 10 A
2  2  5  8 11 B
3  3  6  9 12 C
> str(x1)
'data.frame':	3 obs. of  5 variables:
 $ X1: int  1 2 3
 $ X2: int  4 5 6
 $ X3: int  7 8 9
 $ X4: int  10 11 12
 $ y :Class 'AsIs'  chr [1:3] "A" "B" "C"

#引数stringsAsFactors=FALSEで因子ベクトルへの変換をキャンセルする
> (x2 <- data.frame(x,y,stringsAsFactors=FALSE))
  X1 X2 X3 X4 y
1  1  4  7 10 A
2  2  5  8 11 B
3  3  6  9 12 C
> str(x2)
'data.frame':	3 obs. of  5 variables:
 $ X1: int  1 2 3
 $ X2: int  4 5 6
 $ X3: int  7 8 9
 $ X4: int  10 11 12
 $ y : chr  "A" "B" "C"

複数の文字ベクトルがあるときは、I(文字ベクトル)を個別に指定するのが面倒。
だから、僕は打ち込む文字は多くなるけど、stringsAsFactors=FALSEが一括だから好き。

で、data.frame関数はいろんな型を気にせず放り込めるところが、エクセルっぽくて、まわりのウケがいい。