5  複数の要素を含むオブジェクト・クラス

ここまでは、オブジェクトが一つだけの場合のデータ型や、変数について見てきました。しかし、統計で取り扱うのは、複数の数値や記録です。数値や記録がたくさんある場合には、数値や記録を一つづつ別々に取り扱うのは非効率です。多くのプログラミング言語では、このような複数の数値や記録を取り扱う専用のクラスを備えています。Rでは、複数の記録を取り扱うクラスとして、ベクター(vector)リスト(list)データフレーム(data.frame)行列(matrix)の4つが用いられます。以下にこの4つについて簡単に説明します。それぞれのクラスについてはさらに別章で詳しく説明します。

5.1 ベクター(vector)

Rで最も基本的なオブジェクトは、ベクター(vector)です。ベクターは同じ型を持つオブジェクトの集まりで、1次元の、つまり縦横の構造がないデータとして取り扱われます。ベクターはc関数(cはcombine、「結合する」の意味)で作成することができます。

ベクターは同じ型を持つデータの集まりです。ですので、ベクターの要素に文字列が交じると、自動的にすべての要素が文字列になる、という特徴があります。

ベクターの作成
vec_n <- c(1, 2, 3, 4) # 数値のベクター
vec_c <- c("dog", "cat", "pig", "horse") # 文字列のベクター
vec_temp <- c(1, 2, 3, "dog") # 文字列が交じると文字列のベクターになる

vec_n
## [1] 1 2 3 4

vec_c
## [1] "dog"   "cat"   "pig"   "horse"

vec_temp
## [1] "1"   "2"   "3"   "dog"

Rでは数値1つや文字列1つの要素も、ベクターとして取り扱われます。ですので、Rのオブジェクトの最小単位はベクターとなります。要素が1つであれば、c関数でつなぎ合わせる必要はありません。

1 # 数字1つでもベクター
## [1] 1

"Hello world" # 文字列1つでもベクター
## [1] "Hello world"

vectorはベクトルと表記されることもあります。この文書では、Rのオブジェクトをベクター、方向と大きさを持つ量のことをベクトルと表記することとします。

5.1.1 ベクターに要素を追加する

ベクターに要素を追加するために、append関数というものが用意されています。しかし、上記のc関数でもベクターに要素を追加することができます。

append関数では位置を特定して要素を追加することもできます。

ベクターに要素を追加する
append(vec_n, 5) # 上の数値ベクターに5を追加
## [1] 1 2 3 4 5

c(vec_n, 5) # 上と同じ
## [1] 1 2 3 4 5

append(vec_n, 5, after = 3) # 3つ目の要素の後に5を追加
## [1] 1 2 3 5 4

5.1.2 ベクターの要素を取り出す

ベクターの要素を取り出すときには、インデックスというものを用います。インデックスとは、ベクターなどの複数の値を取り扱うオブジェクトにおいて、値のある位置を示す数値のことです。インデックスはベクターの変数の後に、四角カッコ([ ])に数値を入れることで指定することができます。Rではインデックスは1から始まります。

図3:ベクターとインデックス

図3:ベクターとインデックス
ベクターの要素をインデックスで取り出す
vec <- c(4, 3, 2, 1) # 数値のベクターを作成する
vec[1] # インデックス1には4が入っている
## [1] 4

vec[3] # インデックス3には2が入っている
## [1] 2

多くのプログラミング言語では、インデックスは0から始まります。インデックスが1から始まるプログラミング言語はまれです。

5.1.3 ベクターの要素の置き換え

ベクターの要素を置き換えるときには、置き換えたいベクターのインデックスを指定し、数値などを代入します。この時、数値のベクターの要素を文字列に置き換えると、ベクター全体が文字列に置き換わるので注意して下さい。

ベクターの要素を置き換える
vec # 数値のベクター
## [1] 4 3 2 1

vec[3] <- 5 # インデックス3の数値を5に置き換える
vec # 3番めが2から5に置き換わる
## [1] 4 3 5 1

vec[4] <- "dog" # インデックス4の数値を"dog"(文字列)に置き換える
vec # ベクターはすべて文字列になる
## [1] "4"   "3"   "5"   "dog"

5.1.4 ベクターの要素を取り除く

ベクターの要素を取り除くときには、ベクターのインデックスをマイナスで指定します。マイナスのインデックスで指定した要素は取り除かれ、ベクターの長さが短くなります。

ベクターの要素を取り除く
vec
## [1] "4"   "3"   "5"   "dog"
vec[-3] # インデックス3の要素(5)を取り除く
## [1] "4"   "3"   "dog"

5.1.5 ベクターの演算

ベクターは、そのまま演算に用いることができます。数値のベクターに数値を足せば、ベクターのすべての要素に数値が足されます。文字列のベクターにpaste関数で文字を継ぎ足せば、すべての要素に文字が継ぎ足されます。

ベクターを演算に用いる
vec_n # 数値のベクター
## [1] 1 2 3 4
vec_n + 5 # 数値のベクターに5を足すと、すべての要素に5が足される
## [1] 6 7 8 9

vec_c # 文字のベクター
## [1] "dog"   "cat"   "pig"   "horse"
paste(vec_c, "is an animal.") # 文字のベクターにpaste関数で文字をつなぎ合わせる
## [1] "dog is an animal."   "cat is an animal."   "pig is an animal."  
## [4] "horse is an animal."

ベクターについては15章でさらに詳しく説明します。

5.2 因子(factor)

因子(factor)はR以外のプログラミング言語にはないクラスの一つです。因子とは、カテゴリを表すときに用いるクラスです。カテゴリとは、例えば男性/女性や、成人/未成年、喫煙者/非喫煙者などの、そのデータの性質を表す要素のことを指します。統計では、例えば男性と女性で分けて数値を集計する、といったシチュエーションがたくさんあります。このように、カテゴリごとの集計や統計を行いやすくするために準備されているクラスが因子です。因子はfactor関数を用いて作成します。

因子型(factor)
factor("male") # 男性を示す因子
## [1] male
## Levels: male

class(factor("male")) # 因子のクラスはfactor
## [1] "factor"

5.2.0.1 因子のレベル(levels)

因子には、レベル(levels)というアトリビュートが付いています。因子はカテゴリを示すものですので、通常1つだけで用いることはありません(カテゴリが1つだけであれば、カテゴリ分けする必要がありません)。つまり、因子は複数の要素を持つベクターとして作成することになります。このときのベクター内の各カテゴリ(男性・女性など)のことをレベルと呼びます。因子については14章で詳しく説明します。

5.3 リスト(list)

統計の計算をしていると、複数の計算結果をまとめて取り扱いたい、という場合があります。ベクターは1次元のオブジェクトで、かつすべての要素のデータ型が同じですので、ベクターでは型や長さの違う、様々な結果を一度に取り扱うことはできません。このような、型の違うデータを一度に取り扱うときに用いられるのが、リスト(list)と呼ばれるオブジェクトです。リストは、様々なオブジェクトをまとめて一つにしたようなデータ構造を持ちます。リストを作成するときには、list関数を用います。

リスト(list)の作成
vec1 <- c(1, 2, 3, 4) # 数値のベクター
vec2 <- c("dog", "cat", "pig", "horse") # 文字列のベクター
num <- 10 # 数値
char_temp <- "Hello world" # 文字列

list_temp <- list(vec1, vec2, num, char_temp) # 色々な要素をリストにまとめる
list_temp # まとめたリストを表示
## [[1]]
## [1] 1 2 3 4
## 
## [[2]]
## [1] "dog"   "cat"   "pig"   "horse"
## 
## [[3]]
## [1] 10
## 
## [[4]]
## [1] "Hello world"

5.3.1 リストの要素を取り出す

リストの要素を取り出す場合には、ベクターと同様にインデックスを用います。ただし、リストのインデックスは多層化、ネストされているため、呼び出しはやや複雑です。リストの要素を取り出すときには、四角カッコを2重にして用います([[ ]])。[[1]]で呼び出すと、リストの1番目の要素を呼び出すことになります。ベクターと同様に[1]で呼び出すと、リストの1番目の要素を、リストとして呼び出すことになり、要素までたどり着けません。

リストの要素を取り出す
list_temp[[1]] # リストの1番目の要素を取り出す
## [1] 1 2 3 4

list_temp[[2]] # 2番目の要素を取り出す
## [1] "dog"   "cat"   "pig"   "horse"

list_temp[1] # リストの1番目の要素を、リストとして取り出す
## [[1]]
## [1] 1 2 3 4

list_temp[[1]][1] # リストの1番目の要素(ベクター)の、1番目の要素を取り出す
## [1] 1

リストについては、16章で詳しく説明します。

5.4 データフレーム(data.frame)

データフレーム(data.frame)はExcelの表のように、行と列を持ち、長方形の形に整形された表形式のオブジェクトです。データフレームはExcelの表のように取り扱うことができます。

データフレームは縦方向(列)に同じデータ型を持つ、ベクターの集合になっています。データフレームは横方向(行)には異なる型を持つことができますが、縦方向(列)には必ず同じ型を持つ必要があります。列はベクターですので、ベクターと同じように数値の列の1つのデータを文字列に置き換えると、その列のデータが全て文字列に変換されるという特徴があります。

データフレームはdata.frame関数を用いて作ることができます。データフレームを作成するときには、「列名」=「列の要素」という形でカッコの中に入力します。

データフレームの作成
d <- data.frame( # データフレームを作成する(各列を同じ長さにする)
  number = c(1, 2, 3, 4), # 1列目は数値
  animal = c("dog", "cat", "pig", "horse"), # 2列目と3列目は動物と果物
  fruits = c("apple", "orange", "banana", "grape")
)

d # データフレームの表示
##   number animal fruits
## 1      1    dog  apple
## 2      2    cat orange
## 3      3    pig banana
## 4      4  horse  grape

データフレームは同じ長さのベクターをリストにしたものです。ですので、縦(列)はベクターとして同じ型を持ちます。データフレームはリストでもあるので、リストと同じように取り扱うこともできます。

5.4.1 データフレームの次元(dimension)と行数・列数

データフレームには、次元(dimension)という性質(アトリビュート、attribute)があります。この次元とは、行の数、列の数のことです。次元を取得する時には、dim関数を用います。また、行の数、列の数はそれぞれnrow関数、ncol関数で取得することができます。

データフレームの次元を取得する
dim(d) # 次元の取得(前が行の数、後ろが列の数)
## [1] 4 3
nrow(d) # 行の数
## [1] 4
ncol(d) # 列の数
## [1] 3

5.4.2 データフレームのインデックス

ベクターやリストと同じく、データフレームでもインデックスで要素を取り出すことができます。データフレームのインデックスは、[行, 列]という形で指定します。行も列も、1行目・1列目のインデックスが1となります。

データフレームでは、行だけ、列だけをインデックスとして指定することもできます。行だけをインデックスとして指定した時([行, ]の形で指定)には、その行がデータフレームとして取り出されます。一方、列だけを指定した時([, 列]の形で指定)には、その列がベクターとして取り出されます。データフレームを行と列で取り出した場合には異なるものが取り出されるので、特にデータフレームの行を取り出す際には注意が必要です。

データフレームの要素を取り出す
d
##   number animal fruits
## 1      1    dog  apple
## 2      2    cat orange
## 3      3    pig banana
## 4      4  horse  grape

d[2, 3] # 2行3列目のデータを取り出す
## [1] "orange"

d[2, ] # 2行目を取り出す(データフレーム)
##   number animal fruits
## 2      2    cat orange

d[, 3] # 3列目を取り出す(ベクター)
## [1] "apple"  "orange" "banana" "grape"

データフレームの列は、列の名前を用いても取り出すことができます。列を取り出すときには、$(ドルマーク)に列名を繋げて記述します。

列を列名で呼び出す
d$number # 1列目の列名はnumber
## [1] 1 2 3 4

d$animal # 2列目の列名はanimal
## [1] "dog"   "cat"   "pig"   "horse"

d$fruits # 3列目の列名はfruits
## [1] "apple"  "orange" "banana" "grape"

5.4.3 データフレームの要素の置き換え

データフレームの要素の置き換えは、ベクターと同じように、置き換えたい場所のインデックスを指定して、値を代入する形で行います。この時、その置き換える列の型と代入するデータの型が異なると、列の型がすべて置き換わることがあるので注意が必要です。

データフレームの要素を置き換える
d[2, 3] <- "peach" # 2行3列目の要素をpeachに置き換える
d # 2行3列目がpeachに置き換わる
##   number animal fruits
## 1      1    dog  apple
## 2      2    cat  peach
## 3      3    pig banana
## 4      4  horse  grape

d[2, 1] <- "tomato" # 2行1列目をtomato(文字列)に置き換える
d # 2行1列目がtomatoに置き換わる
##   number animal fruits
## 1      1    dog  apple
## 2 tomato    cat  peach
## 3      3    pig banana
## 4      4  horse  grape

mode(d[, 1]) # 1列目が文字列に置き換わる
## [1] "character"

5.4.4 データフレームの行・列の削除

データフレームの行や列を削除する場合には、ベクターと同じように、インデックスをマイナスで与えます。インデックスをマイナスで指定することで、そのインデックスの行・列を取り除くことができます。ただし、データフレームの1つの要素だけを削除することはできません(指定した行・列がまるごと削除されます)。1つの要素だけを取り除く場合には、その要素のインデックスに対してNAを代入するとよいでしょう。

データフレームの行・列を削除する
d # 元々のデータフレームは4行3列
##   number animal fruits
## 1      1    dog  apple
## 2 tomato    cat  peach
## 3      3    pig banana
## 4      4  horse  grape

d[-1, ] # 1行目を削除
##   number animal fruits
## 2 tomato    cat  peach
## 3      3    pig banana
## 4      4  horse  grape

d[, -1] # 1列目を削除
##   animal fruits
## 1    dog  apple
## 2    cat  peach
## 3    pig banana
## 4  horse  grape

d[-2, -3] # 2行目と3列目を削除
##   number animal
## 1      1    dog
## 3      3    pig
## 4      4  horse

d[2, 3] <- NA # 1要素だけを取り除くときは、NAを代入する

5.5 行列(matrix)

行列(matrix)は、線形代数(高校数学での行列計算)に用いるものです。行列は基本的には一つの型の要素からなる、行と列のあるオブジェクトです。行列はデータフレームとよく似ていますが、データフレームが列方向のベクターのリストであるのに対し、行列は次元(dimension)を持つベクターに近いものとなります。

Rで行列を作成するときには、matrix関数を用います。matrix関数では、カッコの中に、ベクター、行数、列数を指定する数値を与えます。

行列を作成する
# 2行3列の行列
mat <- matrix(c(1,2,3,4,5,6), nrow = 2, ncol = 3) # nrowは行数、ncolは列数
mat
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6

5.5.1 行列の次元とインデックス

行列の次元とインデックスは、データフレームとほぼ同じように取り扱うことができます。行列の行・列に名前をつけることもできます。従って、列を取り出すときに列名を利用することもできます。取り出したものはいずれもベクターになります。要素・行・列の削除もデータフレームと同じ方法で行います。

行列の要素の取り出し
mat[1, 1] # 1行1列目の要素
## [1] 1

mat[1, ] # 1行目の要素(ベクター)
## [1] 1 3 5

mat[, 1] # 1列目の要素(ベクター)
## [1] 1 2

dim(mat) # matのdimensionを表示
## [1] 2 3

nrow(mat) # matの行数を表示
## [1] 2

ncol(mat) # matの列数を表示
## [1] 3

5.5.2 行列の演算

データフレームとは異なり、数値の行列は演算に用いることができます。行列(線形代数)の計算のために、Rには行列積、外積、クロネッカー積に対応する演算子が準備されています。

表4:Rで使える行列の演算子
行列の演算子 演算子の意味
%*% 行列の積
%o% 外積
%x% クロネッカー積
行列の演算
mat2 <- matrix(c(1, 2, 3, 4, 5, 6), nrow=3, ncol=2)

mat %*% mat2 # 行列の積
##      [,1] [,2]
## [1,]   22   49
## [2,]   28   64

mat %o% mat2 # 外積
## , , 1, 1
## 
##      [,1] [,2] [,3]
## [1,]    1    3    5
## [2,]    2    4    6
## 
## , , 2, 1
## 
##      [,1] [,2] [,3]
## [1,]    2    6   10
## [2,]    4    8   12
## 
## , , 3, 1
## 
##      [,1] [,2] [,3]
## [1,]    3    9   15
## [2,]    6   12   18
## 
## , , 1, 2
## 
##      [,1] [,2] [,3]
## [1,]    4   12   20
## [2,]    8   16   24
## 
## , , 2, 2
## 
##      [,1] [,2] [,3]
## [1,]    5   15   25
## [2,]   10   20   30
## 
## , , 3, 2
## 
##      [,1] [,2] [,3]
## [1,]    6   18   30
## [2,]   12   24   36

mat %x% mat2 # クロネッカー積
##      [,1] [,2] [,3] [,4] [,5] [,6]
## [1,]    1    4    3   12    5   20
## [2,]    2    5    6   15   10   25
## [3,]    3    6    9   18   15   30
## [4,]    2    8    4   16    6   24
## [5,]    4   10    8   20   12   30
## [6,]    6   12   12   24   18   36

5.5.3 3次元以上のオブジェクト:array

行列はベクターに次元を2つ(行と列)与えたものですが、3次元以上の次元を与えることもできます。このような3次元以上のデータを取り扱う場合には、arrayというオブジェクトを使用します。arrayはarray関数で作成することができ、各次元の数(行数、列数に当たるもの)をベクターで与えます。統計やデータ解析で3次元以上のデータを取り扱うことは比較的まれです。

arrayを作成する
array(c(1, 2, 3, 4, 5, 6, 7, 8), dim = c(2, 2, 2)) # 2行2列2シートの行列
## , , 1
## 
##      [,1] [,2]
## [1,]    1    3
## [2,]    2    4
## 
## , , 2
## 
##      [,1] [,2]
## [1,]    5    7
## [2,]    6    8

5.6 その他のオブジェクト

Rに基本的に備わっているオブジェクトとして、ベクター、リスト、データフレーム、行列の他に、時系列(time series、ts)というオブジェクトがあります。時系列とは、例えば株価や為替相場の時間変化のような、時間とともに定期的に記録されたデータのことを指します。時系列はクラスとして設定されており、中身はベクターです。

時系列データ(ts)
co2[1:10] # 1959年からのCO2濃度の推移
##  [1] 315.42 316.31 316.50 317.56 318.13 318.00 316.39 314.65 313.68 313.18

class(co2) # クラスはts
## [1] "ts"

typeof(co2) # 型はdouble
## [1] "double"