Rのデータ型、データ構造


データ型とデータ構造

データ型の種類

Rの扱うデータには、数、文字列、論理定数、などがあり、それらは別々の型(type)を持つ。 代表的な型には numeric, complex, character, logical などがある。
numeric 型はコンピュータの内部表現の違いで、integer, double 型と呼ばれることもある。
計算では、それぞれの場合に適切なデータの型を選ばないと、不適切な結果となるか、あるいは場合によってはエラーになるので注意が必要である。

データの型 説明 定数の例
integer(numeric)  整数型  1, -1, 20300, ...
double(numeric)  実数型(整数も含む)  3.1415, -0.001, 125.00012, 1, 1e-10, ...
 complex  複素数型  1i, 1 - 4.5i, 3+0i, complex(re=a,im=b), ...
 character  文字型  "A", "2014/10/14", "", ...
 logical  論理型  TRUE, FALSE, T, F, NA, ...

numeric 型は、整数と小数点付き数(実数)を表現するデータ型である。いずれの場合も、有効桁は16桁程度である。これらの数は、コンピュータ内部では0以上1未満の数に2のべき乗を掛けた指数形式で記憶され、表示されるとき見やすい10進数に変換される。表示の桁数は options(digits=..) によって指定する。デフォルトは7、最大 22 である。有効桁は16桁程度なので、桁数がそれ以上に表示されても、たいていは意味がない(2進数から10進数へ変換する時、形式的に指定桁数を計算したにすぎない)。普通の表示で表示桁数に収まらない場合は、1以上10未満の数に10のべき乗を掛けた指数形式で表現される。10 のべき乗は数の次に「e」を書き、そのあとにべき指数を続けることで表現する(6.022e23 のように) 。演算結果が表現しきれない大きな数(21024以上、10進数で307桁程度)になった場合は Inf という記号が返される。

> 10^15+1
[1] 1e+15
> options(digits=22)
> 10^15+1 # 計算は正しく行われている
[1] 1000000000000001 > 10^16+1 # 10^16 に比べると 1 はゼロと同じ(切り捨てられる) [1] 1e+16
> 123456789.0123456789 # 2進数を10進数に変換して、末尾は意味のない数値を表示している [1] 123456789.0123456716537 > 0.0000000000000000001 # 16桁で四捨五入すれば正しい [1] 9.999999999999999752459e-20

> 2^1023 # 最大桁数 [1] 8.9884656743115795386e+307 > 2^1024 # コンピュータの表現能力を超える(無限大) [1] Inf
> 2^(-1074) # 絶対値最小数 [1] 4.94065646e-324
> 2^(-1075) [1] 0

complex 型は複素数を表すデータ型である。complex型定数は numeric型定数のあとに「i」を付けたものと、別の numeric型定数を「+」で結んだものとして表現される。実数部虚数部のどちらを先に書いても構わない。虚数部が1であっても「1i」と書かなければいけない。虚数部の値(i を除いたもの)が変数に記憶されている場合は complex(re=a, im=b) のように、関数を使って定義する。a が実数部、b が虚数部の数である。

character 型は文字列をデータとして扱う場合に用いられるデータ型である。character 型定数は、"" で囲まれた任意の文字列である。

logical 型は論理値を扱う。TRUE, FALSE, NA などは logical 型定数で、TRUE, FALSE の省略形 T, F も(最初は)論理型定数として扱われる。TRUE, FALSE を別の目的に使うことはないだろうが、T, F は通常の変数として使われる可能性も大きい。その場合は論理型でない型の変数になるので注意が必要。次の例では、2行目で「replace=TRUE」とすべきところを省略形で書いてあるが、その前に T に別の値を代入したためエラーになった。

> T = 0
> sample(c(0,1), 10, replace=T)
 以下にエラー sample.int(length(x), size, replace, prob) : 
   'replace = FALSE' なので、母集団以上の大きさの標本は取ることができません 
> sample(c(0,1), 10, replace=TRUE) [1] 0 1 1 0 1 1 0 1 0 0

データの型は typeof() 関数(内部表現の場合)、mode() 関数(実際の計算の場合)で知ることが出来る。 あるいは、is.xxx() 関数で、xxx 型か否かを判定することができる。
データ型を変えるには as.xxx() 関数を使う。

> (a <- 1)
[1] 1
> typeof(a)
[1] "double"
> (aint <- as.integer(1))
[1] 1
> typeof(aint)
[1] "integer"
> mode(a)
[1] "numeric"
> mode(aint)
[1] "numeric"

データ構造

データの基本はベクトルである。スカラーも長さ1のベクトルとして扱われる。行列はそれらを2次元構造に見立てたもの。データフレームは列ごとにデータ型の違うデータを行列に仕立てたもの。添え字が3つ以上の場合は array として定義される。

vector ベクトル「c(1,2,3)」
matrix 行列「matrix(c(...),n)」、ベクトルをcbind, rbindで行列化できる
array 配列
list リスト
data.frama データフレーム型(いろいろなデータ型の混じった行列)
factor  因子型(順序なし)
orderd  因子型(順序あり)

もどる


ベクトル

ベクトル

Rの扱うデータの基本構造は、同じ型のデータをひとまとめにしたベクトルである。

c 関数は、データの集合をベクトル化する関数である。「c」はConcatenation(連結)の頭文字。

ベクトルの各要素は、添字をカギ括弧「[]」でくくって変数名に添えた名前で参照することが出来る(a[1], a[2], ... のように)。添え字の数字は1から始まる。

ベクトルを表示させると、1行に複数のデータが固定長でスペース区切りの表形式で表示され、最左端に一番左のデータの添え字番号が表示される。

次の例は 501 から 550 までの 50 個の整数をベクトルとして w という名前に記憶させている。501:550 は 501,502,...,550 を意味する省略記号である。最左端に並ぶ [1], [24], [47] はそれぞれその行の先頭のデータ 501, 524, 547 の添え字がそれぞれ 1, 24, 47 であること、すなわち w[1] = 501, w[24] = 524, w[47] = 547 であることを示している。例えば添え字付き変数 w[30] と入力すると、w[30] が新たな(要素数が1の)ベクトルとして認識され、添え字番号([1])と共にそのデータ(530)が表示される。

> (w = 501:550)
 [1] 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
[24] 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
[47] 547 548 549 550
> w[30] [1] 530

データ型の自動変換

違う型が混在することは許されず、ベクトルとして違う型のデータが入力された場合は、より一般的な型のデータに揃えられる。一般性の度合いには次の順序関係が 適用される:

logical < integer < double < complex < charcter

logical 型定数の TRUE, FALSE はそれぞれ 1, 0 に変換されるが、NA は変わらない。

以下にいくつかの例を示す。小数点以下の桁数は揃えられる。

> (a = c(TRUE, FALSE, T, F, NA))
[1]  TRUE FALSE  TRUE FALSE    NA
> a[2] = -1; a						# TRUE は 1 に、FALSE は 0 に変換される
[1]  1 -1  1  0 NA
> a[3] = 1.234
> a[3] = 1.234; a					# integer は double に変換される
[1]  1.000 -1.000  1.234  0.000     NA
> a[4] = 3i; a						# 全て complex 型に変換される
[1]  1.000+0i -1.000+0i  1.234+0i  0.000+3i        NA
> a[1] = "char"; a					# 全て character 型に変換される、NA は不変
[1] "char"     "-1+0i"    "1.234+0i" "0+3i"     NA 

ベクトルの部分抽出

ベクトルの一部を取り出すには、[ ]の中に添字の集合を指定すれば良い。

添字にマイナスを付けると、その要素を除外するという意味である。「-(3:5)」のように、範囲にマイナスを付けると、連続した複数の要素を除外することも出来る。

ある条件を満たす要素だけを取り出す場合は、which() 関数を使う。which() 関数の引数は条件式で、条件を満たす添字の集合を生成する。

> (w = 101:110)
 [1] 101 102 103 104 105 106 107 108 109 110
> w[c(3,4,5,8,9)]			# 特定要素抽出
[1] 103 104 105 108 109
> w[-1]					# 特定要素除外
[1] 102 103 104 105 106 107 108 109 110
> w[which(w %% 3 == 0)]			# 条件抽出
[1] 102 105 108
> w[5:12]				# 添え字の範囲外は NA、エラーではない
[1] 105 106 107 108 109 110  NA  NA

ベクトルの要素追加

ベクトルの要素を増やすには、新たなベクトルを定義すれば良い。c 関数の引数はベクトルでも良いので、元のベクトルと、追加したい要素を並べたものを引数として c 関数を実行する。ベクトルの途中にデータを挿入したい場合は、部分抽出によって元のベクトルを部分列に2つに分割し、付け加えるデータとこれらの部分列を引数として c 関数を実行する。

その作業を専門に実行する append という関数もあるので、それを使っても良い。

> (w = 101:105)
[1] 101 102 103 104 105
> (w = c(w, 201, 202))					# 追加
[1] 101 102 103 104 105 201 202
> (w = c(w[1:3], 301, 302, 303, w[4:length(w)]))		# 挿入
 [1] 101 102 103 301 302 303 104 105 201 202
> append(w, 401:402, after=2)				# append で挿入
 [1] 101 102 401 402 103 301 302 303 104 105 201 202

ベクトルの要素を変更する

ベクトルの一部の要素を変更するには、添字付き変数に新しいデータを代入すれば良い。範囲外の添え字を指定してもよい。値が代入されない添え字要素には NA が入る。
> w = 101:108
> w[3] = 199
> w[10] = 999				# 追加もできる
> w [1] 101 102 199 104 105 106 107 108 NA 999

replace 関数は、同時に複数の要素を入れ替える。上の例で、「 replace(w, c(3,10), c(199,999))」としても同じ結果が得られる。2番目の引数が置き換えられるべき添え字の部分集合、3番目の引数が置き換えられる値のベクトルである。上の例との違いは、元のベクトルの内容が保存されていることである。

ベクトルの各要素のうち、ある条件を満たすものの添え字集合を返す関数 which を併用すれば、要素の内容をある条件によって一斉に変更することができる。ifelse 関数を使っても同じような変更が可能である。

また、sample 関数を併用すると、ランダムに選んだ要素の内容を変更することができる。

下の例で、which(z<0) はベクトル z の要素が負になる添え字集合を返す。「z[which(z<0)] = 0」としても同じ結果が得られるが、この場合、配列の中身が変わってしまう。replace 関数を使った場合は、オリジナルデータは保存されている。
sample(1:10, 4) は1から10までの数を重複なしにランダムに4つ選んで返す関数である。rnorm(10) は標準正規乱数を 10個生成して返す関数である。

# 別の例:負の数をゼロにする
> (z = rnorm(10)) [1] 0.73260679 1.20164193 0.98607082 -0.08200957 -0.81407622 0.02463435 1.39606875 [8] 0.97554153 0.54799434 -0.23892839 > replace(z, which(z<0), 0) [1] 0.73260679 1.20164193 0.98607082 0.00000000 0.00000000 0.02463435 1.39606875 [8] 0.97554153 0.54799434 0.00000000
> ifelse(z < 0, 0, z) # としても同じ

# ランダムに符号を入れ替える
> w = 1:10 > (m = sample(1:10, 4)) [1] 10 7 4 9 > replace(w, m, -w[m]) [1] 1 2 3 -4 5 6 -7 8 -9 -10

特別なベクトルの生成

a:b は a < b の時、初項 a 公差1の等差数列で b 以下のものを集めたベクトルである。
a > b の場合、a:b は初項 a 公差 -1 の等差数列で b 以上のものを集めたベクトルである。a,b は整数でなくても構わない。

> 1.5:6
[1] 1.5 2.5 3.5 4.5 5.5
> 9:1
[1] 9 8 7 6 5 4 3 2 1

seq(a, b, by=c) は初項 a 公差 c の等差数列を返す。c > 0 ならば b 以下、c < 0 ならば b 以上の範囲である(by= は書かなくても良い)。
seq(a, b, length=n) は初項 a 公差 (b-a) / (n-1) の等差数列を返す(区間 [a,b] を n-1 等分した場合の分点の集合)。公差がプラスならば b 以下、公差がマイナスならば b 以上の範囲である。

> seq(0, 1, length=9)
[1] 0.000 0.125 0.250 0.375 0.500 0.625 0.750 0.875 1.000
> (0:8) / 8
[1] 0.000 0.125 0.250 0.375 0.500 0.625 0.750 0.875 1.000
> seq(pi, 2*pi, pi/4)
[1] 3.141593 3.926991 4.712389 5.497787 6.283185
> pi + (0:4)*pi/4
[1] 3.141593 3.926991 4.712389 5.497787 6.283185

numeric(n) はn次元のゼロベクトルを返す。
logical(n) は全ての要素が FALSE のn次元論理ベクトルを返す。

rep(a, n) は、a がスカラーの場合、要素が全て a のn次元ベクトルを返す(したがって rep(0,n)numeric(n) は同じ結果を返す)。
a がベクトルの場合は、そのベクトルを n 個並べたベクトルを返す。
a, n が同じ長さのベクトルの場合は、a の各要素を n の各要素「回」繰り返したベクトルを返す。

> rep(0,4)			# numeric(4) と同じ
[1] 0 0 0 0
> rep(1:2,3)			# 1,2を3回繰り返す
[1] 1 2 1 2 1 2
> rep(c("A", "B"), c(3,2))	# "A" を3回、"B" を2回繰り返す
[1] "A" "A" "A" "B" "B"

さいころを振ったときに得られるようなでたらめに並んだ数列(乱数列)は sample() 関数を使って生成できる。詳しくはここを参照のこと。

> sample(c("表", "裏"), 5, replace=TRUE)
[1] "表" "表" "裏" "表" "表"
> sample(1:6, 20, replace=TRUE)
 [1] 4 2 6 1 6 1 5 5 4 5 1 2 2 2 4 5 3 6 4 1

並べ替え

ベクトルのデータを昇順に並べ替えるには sort 関数を使う。decreasing=TRUE オプションを使うと、降順にソートする。
order 関数は、データを並び替えることなく、昇順に並べた時の添え字ベクトルを返す。

rev 関数は、ベクトルを逆順に並べ替える。

sample(1:n) をn次元ベクトルの添え字にするとランダムな順番に並べ替える。

次のプログラム例で length(w) はベクトル w の要素数を返す関数である。

> w = c(3,4,7,1,3,9,6,8,2,5,3)
> sort(w)				# 昇順
 [1] 1 2 3 3 3 4 5 6 7 8 9
> sort(w, decreasing=TRUE)		# 降順
 [1] 9 8 7 6 5 4 3 3 3 2 1
> order(w)				# w[4] = min(w), w[6] = max(w)
 [1]  4  9  1  5 11  2 10  7  3  8  6
> w[order(w, decreasing = TRUE)]		# 降順の場合
 [1] 9 8 7 6 5 4 3 3 3 2 1

> w[sample(1:length(w))] # ランダムな並べ替え [1] 3 4 3 7 5 9 2 1 8 3 6 > w[sample(1:length(w))] # 実行のたびに結果が異なる [1] 7 6 9 5 2 3 3 3 4 8 1

ベクトルの演算

ベクトルとスカラーの計算(+, -, * , /, %/% %%, ^, >, <, ==, ...は、ベクトルの要素ごとにスカラーとして計算した結果をベクトルにまとめる。例えば、次のように。

> 1:30 %% 5
 [1] 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0
> (1:10 %% 5) == 0 [1] FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE TRUE
> 2^(10:20) [1] 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576

ベクトル同士の演算は、対応する要素ごとにスカラーとして計算した結果をベクトルにまとめる。長さの違うベクトル同士の演算も、短いベクトルの要素を「リサイクル」して実行され、警告メッセージが表示される。リサイクルとは、最後の要素の次に先頭の要素が並んでいると考えて同じデータを繰り返し使用することである。

積記号 * の代わりに、行列としての積記号「%*%」を使うとベクトルの内積が計算できる。

> z = c(1,0,4)
> w = c(-1,1,2)
> z %*% w
     [,1]
[1,]    7
> sum(z * w)			 # こうやっても同じ
[1] 7> ifelse(w > z, w, z)
[1] 1 1 4

論理値ベクトル同士の複合論理演算(または、かつ)には注意が必要である。論理型変数 a, b に対して a&&b は「a かつ b」、a||b は「a または b」を意味するが、a,b が論理値ベクトルの場合は、

    a&&b は「a[1] かつ b[1]」、a||b は「a[1] または b[1]

を意味する(警告なしに実行)。
要素ごとに適用して結果を論理値ベクトルで受け取りたい場合は、それぞれ a&b, a|b としなければいけない。

> x = c(1,0,5)
> y = c(2,1,0)
> x > y
[1] FALSE FALSE  TRUE
> (x > 0) && (y > 0)
[1] TRUE
> (x > 0) & (y > 0)
[1]  TRUE FALSE FALSE

ベクトルとして x, y が等しい時何かをしたい、というように論理値ベクトルが全て TRUE か、一つでも TRUE があるか知りたい場合に、all 関数、any 関数を使う。論理値ベクトル a に対して
all(a) は a の要素全てが TRUE である場合のみ TRUE を返す。
any(a)
は a の中に一つでも TRUE がある場合のみ TRUE を返す。

2つのベクトルの要素ごとに比べて大きい方をとって並べたベクトルは ifelse 関数で計算できる。A, x, y を長さの等しいベクトルとし、A を論理値を集めたベクトルとしたとき、
ifelse(A, x, y)
A[i]=TRUE ならば x[i]、さもなければ y[i] (i=1,2,...) とするベクトルを生成する。
max(x,y) とすると、対応する要素ごとに max 関数は適用されず、x,y の要素の中の最大値が計算される。

> z = c(1,0,4)
> w = c(-1,1,2)
> max(z, w) [1] 4
> ifelse(w > z, w, z) [1] 1 1 4


もどる


行列

行列

ベクトルを適当な個数ごとに区切って2次元の表のように扱うことができるようにしたものを行列という。横に並んだデータの集まりを行、縦に並んだデータの集まりを列という。別の言い方をすれば、先頭から何番目のデータ、という指定の仕方だけでなく、何行目何列目のデータという指定の仕方もできるようにしたベクトルを行列という、と言っても良い。行列はベクトルなので、すべての要素は同じ型でなければならない。numeric型と character型 のように、異なる型のデータを含む行列を使いたい場合は、データフレームを利用する。

matrix() はベクトルに行列の構造を追加する関数である。ベクトル a と正整数 n,m に対して matrix(a, n, m) と書くと、n 行 m 列の行列を生成する。
a の最初の n 個を1列目、次の n 個を2列目、というように、列優先で行列を作る。要素を行優先で並べたい場合は byrow=TRUE オプションを使う。
ベクトル a の長さは n x m あることが望ましいが、そうでない場合は警告メッセージが出されるものの、多すぎる場合は最初の n x m 個が使われ、足りない場合は a が繰り返し使われる。

> (A = matrix(1:6, 2, 3)) 			# matrix(1:6,2) と書いてもよい
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
> (A = matrix(c(1,2,3,4), 2, 3, byrow=TRUE))	# c(1,2,3,4,1,2) と書いたのと同じ
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    1    2
 警告メッセージ: 
In matrix(c(1, 2, 3, 4), ncol = 3, byrow = TRUE) :
   データ長 [4] が列数 [3] を整数で割った、もしくは掛けた値ではありません 

行列の要素は、二つの添字をカンマで区切り、[ ] で囲んだものを行列名に添えることでアクセスすることが出来る。
行の添字を省略すると列ベクトルを、列の添字を省略すると行ベクトルを取り出すことが出来る(上の出力例で、左端に [1,],[2,] とあるのは、その行全体に付けられた添字、という意味である)。行列はベクトルなので、行列名をベクトル名と考えて添え字一つの変数名も許される。

> A[1,1] + A[2,3]
[1] 3
> A[2,]			# 行ベクトル
[1] 4 1 2
> A[3:5]			# 列優先でベクトルと考えた時の3番目から5番目の要素
[1] 2 1 3		

length() は、ベクトル(行列)の要素数を返す関数である。
dim() は、行列の行と列を2つの要素とする2次元ベクトルを返す関数である。
nrow() は、行列の行数を、ncol() は、行列の列数を返す関数である。

ベクトルから行列の生成:cbind(), rbind()

列ベクトル、あるいは行ベクトルを先に定義し、それらをまとめて行列を生成することも出来る。
cbind 関数は、要素数の等しい複数のベクトルを列ベクトルの集合とみなして、それを行列にまとめたものを返す。要素数 n の列ベクトルを n行1列の行列と考えると、cbind 関数は、行数が同じ複数の行列を横に並べて作った新たな行列を返す、と言っても良い。

同じように、rbind 関数は、要素数の等しい複数のベクトルを行ベクトルの集合とみなして、それを行列にまとめたものを返す。あるいは、列数の同じ複数の行列を縦に並べて作った新たな行列を返す、と言っても良い。

名前の付いたベクトルを行列にした場合は、行列の行ベクトル、あるいは列ベクトルにその名前が付けられ、その名前で特定の列を参照することが出来る。

colnames() 関数を使うと、定義されている行列の各列に名前を後から付ける(変更する)ことが出来る。rownames() 関数も同様である。

> (data <- cbind(ID=1:5, math=c(10,8,4,6,9), prog=c(4,6,7,6,8)))
     ID math prog
[1,]  1   10    4
[2,]  2    8    6
[3,]  3    4    7
[4,]  4    6    6
[5,]  5    9    8
> data[,"math"]
[1] 10  8  4  6  9
> (datab <- rbind(kei=c(1,10,4), mie=c(3,4,7), jun=c(5,9,8)))
    [,1] [,2] [,3]
kei    1   10    4
mie    3    4    7
jun    5    9    8
> colnames(datab) <- c("ID", "math", "prog")
> datab
      ID math prog
kei    1   10    4
mie    3    4    7
jun    5    9    8
> (datc <- cbind(datab, eng=c(6,5,7,10)))
    ID math prog eng
kei  1   10    4   6
mie  3    4    7   5
jun  5    9    8   7
> (datad <- rbind(datab, aki=c(6,10,10)))
    ID math prog
kei  1   10    4
mie  3    4    7
jun  5    9    8
aki  6   10   10
> datab[, c("ID", "prog")]
    ID prog
kei  1    4
mie  3    7
jun  5    8

特別な行列の生成

diag(n) (n は正整数)は n 次単位行列を生成する。diag(n)[,k] は k 番目の単位ベクトルになる。

daig(a) (a は要素数が n のベクトル)は n 次元正方行列で、対角要素が a 、それ以外は0の行列を生成する。

多次元配列

3次元以上の配列を定義する場合はarray+dim関数を使う

> (z = array(1:24, dim=c(4,3,2)))
, , 1

     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12

, , 2

     [,1] [,2] [,3]
[1,]   13   17   21
[2,]   14   18   22
[3,]   15   19   23
[4,]   16   20   24
> z[1,,]
     [,1] [,2]
[1,]    1   13
[2,]    5   17
[3,]    9   21
> z[,1,]
     [,1] [,2]
[1,]    1   13
[2,]    2   14
[3,]    3   15
[4,]    4   16

行列の部分抽出、行・列の追加、要素の変更

ベクトルの場合と同じように、添え字として集合を指定すると、それらの行、あるいは列だけを取り出した部分行列が生成される。添え字(集合)にマイナスをつければ、特定の行、あるいは列を取り除いた部分行列が生成される。添え字集合の指定は、その集合が確定するならばどのような方法でも構わない。

新たな行、あるいは列を追加するには rbind 関数、cbind 関数を使う。複数行、複数列、あるいは別の行列の場合も同じ。

行列の要素を変更するには、添え字付きの変数にあらなたデータを代入すれば良い。ベクトルの場合と違い、範囲外の添え字を指定するとエラーになる。

 diag(A) とすると、行列 A の対角要素だけを取り出したベクトルが得られる。A は正方行列である必要はない。

> (A = matrix(1:6, 2))
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
> diag(A)
[1] 1 4

upper.tri(A) は、A と同じ大きさの行列で、上三角行列が TRUE、それ以外が FALSE の値を持つ論理値行列である。diag=TRUE オプションを指定すると、対角要素を含めることができる。lower.tri(A) は下三角行列だけ TRUE となる論理値行列を生成する。

> upper.tri(B)			# 結果は行列
      [,1]  [,2] [,3]
[1,] FALSE  TRUE TRUE
[2,] FALSE FALSE TRUE
> B[upper.tri(B)]		# 行列構造はなくなり、TRUE の要素だけを並べたベクトルになる
[1] 3 5 6
> B[upper.tri(B)] = 0		# 下三角行列化、diag=TRUE を指定すると、対角要素もゼロになる
> B
     [,1] [,2] [,3]
[1,]    1    0    0
[2,]    2    4    0

並べ替え

ある列が大きさの順になるように行列を行単位で並べ替えるには order 関数を使う。行列 z の k 列目を昇順に並べた時の添え字ベクトルは order(z[,k]) なので、それを行番号とする行列 z[order(z[,k]),] は目的の行列となる。

> (z = matrix(sample(1:9),3))
     [,1] [,2] [,3]
[1,]    1    9    8
[2,]    4    3    5
[3,]    6    7    2
> z[order(z[,k]),]
     [,1] [,2] [,3]
[1,]    4    3    5
[2,]    6    7    2
[3,]    1    9    8

行列の計算

行列はベクトルを2次元構造化しただけなので、計算の仕方はベクトルの場合と基本的には同じ。+, -, * , /, %/% %%, ^, >, == のような演算子を行列同士の計算に使用すると、各要素ごとに通常の計算を実行して行列として返す。片方だけが行列の場合は、もう一方も同じサイズの行列になるように整形して行列同士の演算として実行する。

行列独特の演算として、%*%, %o%, %x% がある。A = (aij) は m x n 行列、B = (bij) は p x q 行列とする。

%*% は行列同士の掛け算で、A %*% B とする場合は、n = p が必要。結果は m x q 行列、その i,j 要素は Σkaik bkj である。片方がベクトルの場合、左から掛ける場合は行ベクトル、右から掛ける場合は列ベクトルとみなされる。

%x% はクロネッカー積を計算する。2つの行列 A=(aij), B のクロネッカー積とは (aijB) として定義される。すなわち、mp x nq 行列で、B の行数列数単位をブロックとして i 行 j 列ブロックの要素が aijB で与えられる行列である。

%o% は外積を計算する。A %o% B は、その i,j,k,l 要素が aijbkl であるような m x n x p x q 行列である。特に、A, B がベクトル(n = p = 1)ならば外積はクロネッカー積と同じで ABt と表される m x q 行列になる。

# クロネッカー積
> A = cbind(c(1,-1), c(-2,3)) > (B = matrix(1:6, 2, 3)) [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6 > A %x% B [,1] [,2] [,3] [,4] [,5] [,6] [1,] 1 3 5 -2 -6 -10 [2,] 2 4 6 -4 -8 -12 [3,] -1 -3 -5 3 9 15 [4,] -2 -4 -6 6 12 18
# 外積の例:掛け算の九々の表
> 1:9 %o% 1:9 [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [1,] 1 2 3 4 5 6 7 8 9 [2,] 2 4 6 8 10 12 14 16 18 [3,] 3 6 9 12 15 18 21 24 27 [4,] 4 8 12 16 20 24 28 32 36 [5,] 5 10 15 20 25 30 35 40 45 [6,] 6 12 18 24 30 36 42 48 54 [7,] 7 14 21 28 35 42 49 56 63 [8,] 8 16 24 32 40 48 56 64 72 [9,] 9 18 27 36 45 54 63 72 81

行列式や逆行列、固有値などは関数を使う。

行列関数

行列を操作する関数の例を挙げる。

関数 機能
t 転置行列 t(A)
solve 逆行列、連立方程式の解を求める solve(A)、Solve(A,b)
det 行列式 det(A)
eigen 固有値、固有ベクトル eigen(A)$value、eigen(A)$vectors
outer
外積(ベクトル積とは違う) %o% と書いても良い

行列式、逆行列

行列 A の転置行列は t(A) によって生成できる。

正方行列の行列式は det(A) で計算できる。

正方行列 A の逆行列は solve(A) によって生成される。

> (A = cbind(1:2,1:0))
     [,1] [,2]
[1,]    1    1
[2,]    2    0
> solve(A)			# 逆行列
     [,1] [,2]
[1,]    0  0.5
[2,]    1 -0.5
> solve(A) %*% A			# 検算
     [,1] [,2]
[1,]    1    0
[2,]    0    1

固有値、固有ベクトル

eigen() は固有値と固有ベクトルを計算する関数である。固有値は $values、 固有ベクトル(列ベクトル)は $vectors で取り出すことが出来る。

> (a = matrix(c(1,2,1,0),2,2))
     [,1] [,2]
[1,]    1    1
[2,]    2    0
> (ai = eigen(a))					# 固有値と固有ベクトルの計算
$values
[1]  2 -1

$vectors
          [,1]       [,2]
[1,] 0.7071068 -0.4472136
[2,] 0.7071068  0.8944272

> a %*% ai$vectors[,1] - ai$values[1] * ai$vectors[,1]	# 固有ベクトルと固有値の関係
     [,1]
[1,]    0
[2,]    0
> solve(ai$vectors) %*% a %*% ai$vectors			# あるいは、別の表現
     [,1]          [,2]
[1,]    2  1.110223e-16
[2,]    0 -1.000000e+00

外積

outer 関数は、2つのベクトルと一つの2変数関数を引数として2つのベクトルの外積の各要素に関数を適用した行列を返す。引数として2変数関数を指定しない場合は「*」がデフォルトとして使われ、通常の外積が返される。すなわち、outer(u,v) u %o% v と書いても同じ。

2変数関数のグラフを描くための persp, contour 関数は定義域の長方形を格子点で覆い、各点での関数値を引数として要求するが、その場合の計算として outer 関数が使える。


# 2変数関数の値表
> outer(seq(0,3,0.1), seq(0,3,0.1), function(x,y) exp(-x^2-y^2+x*y)) [,1] [,2] [,3] [,4] [1,] 1.0000000000 0.9900498337 0.9607894392 0.9139311853 [2,] 0.9900498337 0.9900498337 0.9704455335 0.9323938199 [3,] 0.9607894392 0.9704455335 0.9607894392 0.9323938199 [4,] 0.9139311853 0.9323938199 0.9323938199 0.9139311853 以下略

特別な行列の生成

対称行列を作る(upper.tri, lower.tri, t)

上三角部分の要素をその対角成分に代入して対象行列にするためには、上三角行列だけを取り出して転置したものを下三角行列に代入すれば良い。そのために、三角行列要素を取り出す upper.tri, lower.tri 関数、行列を転置する t関数を使って次のようにすれば良い。

> (A <- matrix(sample(9),3,3))
     [,1] [,2] [,3]
[1,]    2    3    1
[2,]    7    9    4
[3,]    8    6    5
> A[lower.tri(A)] = t(A[upper.tri(A)]); A
     [,1] [,2] [,3]
[1,]    2    3    1
[2,]    3    9    4
[3,]    1    4    5

列を定数倍する(対角行列を掛ける)

> (w = matrix(1:6,2,3))	# 行列の定義
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
> d = diag(1:3)		# 対角行列を定義して
> w %*% d		# 右から掛ける(列の定数倍)
     [,1] [,2] [,3]
[1,]    1    6   15
[2,]    2    8   18
> dd = diag(1:2)	# 対角行列を定義して
> dd %*% w		# 左から掛ける(行の定数倍)
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    4    8   12

もどる


データフレーム

データフレーム

身長と血液型のように、numeric型と character型を混在させた行列をデータフ レーム という。
data.frame()cbind() 関数と同じように、列ベクトルを束ねる関数である。

numeric型と character型の混在する列を cbind() で束ねると、すべて character型になる。

class() はデータ構造を返す関数である。data.frame() で作成した場合は "dataframe"型、cbind() で作成した場合は "matrix"型 になる(数と文字は共存できない)。

> (data <- data.frame(氏名=c("kei", "mie", "tom"), 身長=c(178.9, 183.1, 172.3), 血液型=c("A","AB","O")))
  氏名  身長 血液型
1  kei 178.9      A
2  mie 183.1     AB
3  jun 172.3      O
> class(data)
[1] "data.frame"
 
> (datam <- cbind(氏名=c("kei", "mie", "jun"), 身長=c(178.9, 183.1, 172.3), 血液型=c("A","AB","O"))) 氏名 身長 血液型 [1,] "kei" "178.9" "A" [2,] "mie" "183.1" "AB" [3,] "jun" "172.3" "O" > class(datam) [1] "matrix"

データの入力

ベクトル変数に値を定義する場合、データの個数が少なければ c 関数を使って直接入力しても良いが、ちょっと多めのデータを入力したい場合、scan 関数を使ってスペース区切りのデータを入力し、R にベクトル化の作業をさせることもできる。この場合、キーボードから入力しても良いが、コピーペーストが使えるので、Excel などで作成したデータを一気に取り込むことができる。

統計データのような2次元の表にデータ入力する場合も、read.table 関数を使えば、Excelで作業した2次元の表形式のデータをRのデータフ レームに取り込むことができる。header= オプションは項目見出し行の有無を指定する。

# Excelのデータ範囲をコピーしてから、次の命令を入力する
> zza = scan()
1: 1	2
3: 3	4
5: 
Read 4 items
> zza
[1] 1 2 3 4

# Excelのデータ範囲(項目名も含む)をコピーしてから、次の命令を入力する > (df <- read.table("clipboard", header=TRUE)) 氏名 身長 体重 血液型 1 kei 178.9 72.1 A 2 mie 183.1 84.9 AB 3 jun 172.3 65.2 O

csvファイルからの入力

データをカンマ区切りの csv ファイルで存在しておけば、read.csv() 関数を使い、ファイル名を指定して読み込むことが出来る。ファイルは「ワーキングディレクトリ」になければいけない。

Windows の場合は、マイドキュメントの中にワーキングディレクトリとして新しいフォルダ(例えば「R」という名前を付ける)を作っておくと良い。
ワーキングディレクトリは、「R console」画面の「ファイル」メニュー」から「ディレクトリの変更」サブメニューを選び、「フォルダの参照」ウィンドウで、ファイルの保存されているファイルを選択 することによって指定する。
あるいは、setwd() 関数を使って、ファイルの保存されているフォルダ名を文字列として入力する。

フォルダ名の書き方は、getwd() 関数を使って現在のワーキングディレクトリを表示させれば想像が付く。

> getwd()
[1] "C:/Users/user/Documents"
> setwd(paste(getwd(),"/R",sep=""))		# setwd("C:/Users/user/Documents/R") と同じ
> (dfc <- read.csv("dataa.csv", header=TRUE))
  氏名  身長 体重 血液型
1  kei 178.9 72.1      A
2  mie 183.1 84.9     AB
3  jun 172.3 65.2      O
> class(dfc)
[1] "data.frame"

テキストファイルからの入力

データファイルがタブ区切りのテキストファイルで存在する場合は、read.table() 関数を使い、ファイル名を指定して読み込むことが出来る。

sep="\t" はデータがタブ区切りになっていることを知らせるオプションである。sep="," とすればカンマ区切りのデータファイルに対応する。
skip=2 は最初の2行には表のタイトルなど、データ表とは無関係な情報が入力されている(ので読み込まない)ことを知らせるオプションである。

> (dft <- read.table("datat.txt", sep="\t", header=TRUE, skip=2))
  氏名  身長 体重 血液型
1  kei 178.9 72.1      A
2  mie 183.1 84.9     AB
3  jun 172.3 65.2      O

データフレームの内容を変えたい場合は、データフレームを行列のように考えて、行と列を指定した添字付き変数にデータを代入すれば良い。

> dft[1,"身長"] <- 176.5; dft
  氏名  身長 体重 血液型
1  kei 176.5 72.1      A
2  mie 183.1 84.9     AB
3  jun 172.3 65.2      O

修正箇所がたくさんある場合は、fix() 関数を使う。
例えば次のように入力すると、Excelのスプレッドシートのようなウィンドウが表示されて、中身が編集可能になる。
しかし、このウィンドウの操作はあまりスムーズではなく、例えば、数値のある桁だけ修正できないなど、使い勝手が悪いので、元のファイルを修正して再読込した 方が効率的。

fix(dft)

Excelファイルからの入力

エクセルファイル(.xls)を読むためには、ライブラリが必要

library(gdata)

最初は「そんなライブラリは無い」と断られるので、インストールが必要

「パッケージ/パッケージのインストール」メニューから、ミラーサイトとgdataライブラリを指定すれば、自動的にインストールされる。Excelファ イルを取り込む場合は

read.xls("dataFile.xls")

とすればよい(はず)

列、あるいは行の追加

新たに列を追加したい場合は cbind() 関数を使う。 あるいは一つの列を共通にした別のデータフレームを作り、merge() 関数を利用する。

> (data <- cbind(data, 体重=c(72.1, 84.9, 65.2)))
  氏名  身長 血液型 体重
1  kei 178.9      A 72.1
2  mie 183.1     AB 84.9
3  tom 172.3      O 65.2
> (dataa <- data.frame(氏名=c("kei", "mie", "tom"), 最高血圧=c(110, 145, 123)))
  氏名 最高血圧
1  kei      110
2  mie      145
3  tom      123
> merge(data, dataa)
  氏名  身長 血液型 体重 最高血圧
1  kei 178.9      A 72.1      110
2  mie 183.1     AB 84.9      145
3  tom 172.3      O 65.2      123

データフレームのデータを加工して新たな列を追加することが出来る。そのために、transform() 関数を使う。

> transform(dft, BMI=体重/身長/身長*10000)
  氏名  身長 体重 血液型      BMI
1  kei 176.5 72.1      A 23.14440
2  mie 183.1 84.9     AB 25.32392
3  jun 172.3 65.2      O 21.96226

cbind() 関数を使っても同じ結果が得られる:

> (dftt <- cbind(dft, BMI=dft$体重/dft$身長/dft$身長*10000))
  氏名  身長 体重 血液型      BMI
1  kei 176.5 72.1      A 23.14440
2  mie 183.1 84.9     AB 25.32392
3  jun 172.3 65.2      O 21.96226

データフレームのいくつかの列だけを取り出すには、列番号、あるいは列名を指定すれば良い。

> dft[c("氏名", "身長", "体重")]
  氏名  身長 体重
1  kei 176.5 72.1
2  mie 183.1 84.9
3  jun 172.3 65.2

データフレームの統合、抜粋、並べ替え

同じ行数を持つ複数のデータフレームを結合する

dfs <- merge(df1, df2, ...)

1列目と2列目だけからなるデータフレームを新たに作る場合

dfp <- df[c(1,2)]

あるキーでソートしたデータフレームを新規作成する場合

dfsort <- df[order(df$x),]

データフレームの保存

データフレームを保存する場合は、white.table() 関数を使う。

write.table(dftt, "savedatacheck.txt")

同じものを読み込むと、確かに復元されている。エディタを使っても確かめることが出来る。

read.table("savedatacheck.txt", header=TRUE)

csv ファイルとして保存することもできる。

write.csv(df, "testdata.csv", row.names=F)

テスト用のデータセット

Rには多数のテスト用データセットが用意されている。data() 関数でその内容を知ることが出来る。
データセットの名前がそのままデータフレームの名前になっているので、名前を入力すると、中身が表示される。

> data()
> iris
    Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
1            5.1         3.5          1.4         0.2     setosa
2            4.9         3.0          1.4         0.2     setosa
3            4.7         3.2          1.3         0.2     setosa
4            4.6         3.1          1.5         0.2     setosa
(以下省略)

リスト

リスト

データ型も大きさも違うデータをひとまとめにして、一つの名前で参照することが出来るようなデータ構造を「リスト」という。 list() 関数を使ってリストを作ることが出来る。関数定義の中で、データ型の違う複数の計算結果を返す場合、list 構造が用いられる。

リスト構造のデータをベクトルとして扱うために unlist 関数が必要になる。

次のプログラム例で stats はテストの点数を入力して、その平均と標準偏差、各個人の偏差値を計算して返す関数である。スカラー量とベクトルを同時に関数値として返したいので、list 構造を使っている。

> stats = function(x) {
+   y = round((x - mean(x)) / sd(x) * 10 + 50, 0)
+   return(list(mean=mean(x), sigma=sd(x), hensati=y))
+ }
> x = c(85,83,87,75,95,78,70,100,79,92)
> stats(x)
$mean
[1] 84.4

$sigma
[1] 9.359487

$hensati
 [1] 51 49 53 40 61 43 35 67 44 58

もどる