3 Rのデータ構造
3.2 変数の型
変数には数値だけではなく、文字など様々なタイプの変数が存在します。
R には以下のような変数の型(タイプ)があります。
- numeric (数値型)
- character (文字列型)
- factor (因子型)
- logical (論理値型)
変数の中身を確認(表示)させるには、Console に変数名を入力してエンターを押します。
このページの例ではそのようにして変数の中身を表示させています。
Console ではなくスクリプトファイルにプログラムを書いて実行させた場合には、ただ変数名を書くだけではその変数の内容が Console に表示されることはありません。
スクリプトファイルを使う場合には print() 関数を使うと良いでしょう。例えば x という変数の内容をスクリプト実行時にコンソールに出力(表示)したい場合には、print(x) とスクリプトファイルに書いておきます。
あるいは Environment タブに使用中の変数の一覧があるのでそこを見ても良いでしょう。
3.2.1 数値型
数値型 (numeric) は実数値のデータのことです。
R では、複数の数値が並んだデータ(ベクトル、後述)を作るにはc()
を使います。
ベクトルに足し算引き算掛け算割り算をすればベクトル内の各要素に対して一度に計算を行えます。
3.2.2 文字列型
文字列型 (character) は文字データを表現するのに使います。
文字を引用符で囲うことで作成します。
引用符で囲えば数字でも文字列型になります。
文字列として日本語を使うこともできます。
3.2.3 因子型
因子型 (factor) はカテゴリカルなデータを扱うときなどに使われます。
例えば男性を1, 女性を2として入力されたデータがあったとします。
この時点ではxは数値型のベクトルですが、as.factor 関数を使うことでこれを因子型の配列に変換できます。
因子型のデータは順序情報を持つことができます。
各水準に順序関係がある場合はordered = T
を追加することでそれを明示できます。
また、その順序はデフォルトではアルファベット順になりますが、levels
を使って任意の順序を指定することができます。
x = c("Bad", "Good", "Excellent")
x = factor(x, ordered = T)
x
## [1] Bad Good Excellent
## Levels: Bad < Excellent < Good
# 因子の順序はABC順になる
x = c("Bad", "Good", "Excellent")
x = factor(x, ordered = T, levels = c("Bad", "Good", "Excellent"))
x
## [1] Bad Good Excellent
## Levels: Bad < Good < Excellent
# 順序を指定したい時は levels 引数を使う
x = c("Bad", "Good", "Excellent")
x = factor(x, levels = c("Bad", "Good", "Excellent"))
x
## [1] Bad Good Excellent
## Levels: Bad Good Excellent
# 順序づけはしないが、グラフなどで表示する際の順番は指定したい時は levels 引数を使う
上記の3つ目の例ではordered
は使わずにlevels
だけを指定しています。グラフでどの因子から順に表示するかを指定したい場合などにこのようなことを行います。
3.2.4 論理値型
論理値型 (logical) は真(TRUE)か偽(FALSE)のどちらかの値のみをとるデータです。
TRUEとFALSEの代わりにTとFと書くこともできます。
以下の x と y は全く同じデータを意味します。
TRUE
と FALSE
はすべて大文字で書く必要があります。また、"
で囲ってはいけません。
True と書くと変数名として扱われるし、“TRUE” と書くと文字列として扱われます。
論理値型は比較演算子を用いた際の結果の値にも使われる。
上記の例の>
や==
などは比較演算子と呼ばれる。
Rで用いられる比較演算子には以下のようなものがある。
演算子 | 構文 | 意味 |
---|---|---|
> | x > y | xはyより大きいか |
>= | x >= y | xはy以上か |
< | x < y | xはyより小さいか |
<= | x >= y | xはy以下か |
== | x == y | xとyは等しいか |
!= | x != y | xとyは等しくないか |
%in% | x %in% y | xはyに含まれるか |
以下は具体例。
x = 3
y = 5
y >= x
## [1] TRUE
x <= 1
## [1] FALSE
x == 3
## [1] TRUE
x == 3.0
## [1] TRUE
3 == 6/2
## [1] TRUE
"AAA" == "X"
## [1] FALSE
"AAA" != "X"
## [1] TRUE
a = 5
b = c(3, 4, 5, 6, 7)
a %in% b
## [1] TRUE
x = c("Bad", "Good", "Excellent")
x = factor(x, ordered = T, levels = c("Bad", "Good", "Excellent"))
x[1] < x[2]
## [1] TRUE
3.2.5 その他のデータ型
ここでは省略しますが、他にも以下のようなデータ型があります。
- Complex型(複素数を表現するのに使われる)
- Date型(日付や時刻を表現するのに使われる)
また、Numeric型にはさらにdouble型とinteger型に分けられます。
詳しくは以下のページを参照してください。
https://www.jaysong.net/RBook/datatype.html
3.2.6 データ型の判定
ある変数や配列がどのデータ型であるかは class 関数で調べることができます。
x = 1.0
class(x)
## [1] "numeric"
## 数値型です
x = c("a", "b", "c")
class( x )
## [1] "character"
## 文字列型です
x = as.factor(x)
class(x)
## [1] "factor"
## 因子型です
x = TRUE
class(x)
## [1] "logical"
## 論理値型です
ある変数や配列が特定のデータ型であるかを判定する関数もあります。
たとえば、is.numeric()
という関数は、数値型であるかどうかを判定します。
他のデータ型についてもisで始まる名前の関数が用意されています。
3.2.7 特殊な値について
NA
NA
は欠損値を表現するために使われます。
たとえば以下の例では、ベクトル内の5つの値のうち、4番目の値が欠損値になっています。
このようなデータの具体的な状況としては、はいかいいえで回答する質問を5人に実施した際に、4番目の人の回答が収集できなかった、といったものが考えられます。
NA
を含んでいても、変数のクラスはベクトル内の他の値のクラスのままです。
また、is.na()
関数で値がNAであるかを調べることができます。
NA
を含んだ変数において問題になりやすいのが、平均や総和などの計算です。
以下の例では、数値ベクトルの平均値や総和の計算結果がNA
になってしまっています。
na.rm = TRUE
を関数に追加することで、NAを除去して数値部分だけを使って計算できます。
3.3 データ構造
Rには以下のようなデータ構造があります。
- vector (ベクトル)
- matrix (行列)
- array (配列)
- data frame (データフレーム)
- list (リスト)
- table (テーブル)
それぞれの性質は後ほど Table 3.2 に要約されます。
たくさん種類があって最初は複雑に思えるかもしれません。
この中でも最も重要なのがベクトルとデータフレームなので、まずはこの2つをよく理解しましょう。
3.3.1 Vector (ベクトル)
ベクトルの作成
ベクトルは1次元の配列で、数値や文字や論理値を要素として持つことができます。
c() という関数を使って作成できます。
a = c(-1, 0, 1, 2)
a
## [1] -1 0 1 2
b = c("Alice", "Bob", "Chen")
b
## [1] "Alice" "Bob" "Chen"
c = c(TRUE, TRUE, FALSE)
c
## [1] TRUE TRUE FALSE
ベクトル内の各要素は、全て同じ型の値になります。
上の例だと a は数値型の配列、b は文字型の配列、c は論理値型の配列です。
ベクトルに含まれる要素は、全て同じ型でなければなりません。
では、もし c() の中に違う型の値を混ぜるとどうなるでしょうか?
その場合、全ての要素が同じ型になるように、要素の値が勝手に変換されます。
a = c(0, TRUE, FALSE)
a
## [1] 0 1 0
## 全ての要素が数値型になっています
b = c(1, "A")
b
## [1] "1" "A"
## 全ての要素が文字列型になっています
c = c(2, TRUE, "A")
c
## [1] "2" "TRUE" "A"
## 全ての要素が文字列型になっています
a の場合、TRUE は 1 に、FALSE は 0 に置き換わっています。
数値と論理値を混ぜると、論理値は数値に置き換えられます。
b の場合、1 が “1” に置き換わっています。
置き換わった後の 1 は数値ではなく文字です。
ベクトルの要素の中に文字型の値がある場合、文字型以外の要素は全て文字型に変換されます。
c では3つ目の要素が文字型であるため、他の二つの要素は文字型に変換されます。
この場合は、TRUEは “1” ではなく “TRUE” という文字型の値になります。
なお、要素が1つだけのベクトルは Scalar (スカラー) とも呼ばれます。
(R ではスカラーは独立したデータ型ではなく、要素数が1つであるベクトルです)
以下の a と b は同じものになります。
コロン(:)を使うと値が連続する数値型ベクトルが作れます。
この場合、コロンの前後に最初の数値と終わりの数値を指定します。
ちなみに、以下の3つはどれも同じことです。
c() の中にベクトルを入れて、ベクトルを作ることもできます。
ベクトルの要素の操作
ベクトルが持つ要素を取り出すには角カッコ[]を使って以下のようにします。
a = c("a", "b", "c", "d", "e", "f")
# 1番目の要素を取り出す
a[1]
## [1] "a"
# 3番目の要素を取り出す
a[3]
## [1] "c"
# 1, 3, 5番目の要素を取り出す
a[c(1, 3, 5)]
## [1] "a" "c" "e"
# 2番目から4番目までの要素を取り出す
a[2:4]
## [1] "b" "c" "d"
角カッコの中に1つの整数値を入れると、その番号番目の要素が取り出されます。
角カッコの中に書かれる数字のことをベクトルのインデックスと呼びます。
角カッコの中に整数値のベクトルを入れると、その番号に該当する全ての要素が取り出されます。
また、コロンを使うと連続する値を取り出す際に便利です。
また、以下のような方法でベクトル内の要素を書き換えることができます。
a = c("a", "b", "c", "d", "e", "f")
a
## [1] "a" "b" "c" "d" "e" "f"
a[1] = "1"
a
## [1] "1" "b" "c" "d" "e" "f"
a[c(2, 3)] = c("N2", "N3")
a
## [1] "1" "N2" "N3" "d" "e" "f"
a[4:6] = "X"
a
## [1] "1" "N2" "N3" "X" "X" "X"
もし、存在しない位置の要素に値を代入するとどうなるでしょうか。
以下の例では、3つしか要素がないベクトル x に対して、7番目の要素に10という値を代入しています。
この場合、7番目の要素には10が正しく代入され、4〜6番目は NA
という値で埋められます。
NA
というのは欠損値を表現する際に使われる記号です。Not Available の頭文字に由来。
ベクトルに関する他の話題
ベクトルに関していくつかの補足説明をします。
まず、ベクトルの長さ(大きさ)を知る方法について。
ベクトルは一つ以上の要素を含むデータ構造です。あるベクトルにいくつの要素が含まれているのか知りたい場合には、length()
関数が利用できます。
次に、ベクトルを使った計算について。
ベクトルに数を足したり掛けたりした場合、ベクトルの全ての要素にその計算が行われます。
x = 1:5
x
## [1] 1 2 3 4 5
# x の全ての要素に2が足される
x + 2
## [1] 3 4 5 6 7
# x の全ての要素が3倍される
x * 3
## [1] 3 6 9 12 15
これはたくさんの計算を同時に行うのに便利な性質です。
次の例では price
という変数に様々な商品の値段を入れておき、消費税を掛けることで全ての商品の税込価格を計算しています。
price = c(300, 720, 450, 1200, 1500)
tax = 0.08
price * (1 + tax)
## [1] 324.0 777.6 486.0 1296.0 1620.0
price
の各要素が 1.08 倍されています。
次に、ベクトル同士での加減乗除について。
同じ長さのベクトル同士で計算をすると以下のような結果になります。
つまり、a
と b
の1番目の要素同士の計算、2番目の要素同士の計算、…というやり方で計算が行われます。
ベクトルのリサイクル
長さの異なるベクトル同士で計算をした場合、短い方のベクトルの内容が繰り返し(リサイクル)されて計算が行われます。
以下の例の場合、xは長さ7でyは長さ2です。この場合、yの内容がリピート(リサイクル)されて長さ7に合わせられ(c(1, 8, 1, 8, 1, 8, 1)
になる)、そして計算が行われます。
ベクトルの要素名
使う機会はさほど多く無いかもしれませんが、ベクトルの各要素に名前を与えることが可能です。
# 4つの要素を持つデータ
x = c(10, 20, 5, 40)
# names() 関数を使って各要素に名前を与える
names(x) = c("north", "south", "east", "west")
# x には各要素に名前が付く
x
## north south east west
## 10 20 5 40
# 名前を使って要素にアクセスできる
x["east"]
## east
## 5
# 通常のようにインデックス番号を使うこともできる
x[3]
## east
## 5
# 名前を消したい場合は NULL を代入する
names(x) = NULL
x
## [1] 10 20 5 40
# 名前付きベクトルを作成する別の方法
y = c("Q1" = 4.5, "Q2" = 20.0, "Q3" = 50.1)
y
## Q1 Q2 Q3
## 4.5 20.0 50.1
インデックス番号よりも名前で要素にアクセスした方が便利な場合などに有効です。
3.3.2 Data frame (データフレーム)
データフレームは R においてよく使われる重要なデータ構造です。
縦と横に数字や文字が並んだ下記の表のようなデータを表現するのに使えます。
エクセルなどからデータを R に読み込むとデータフレームになります。
データフレームは2次元のデータ構造である点では行列と似ています。
しかし、データフレームは列ごとに別の型のデータを持たせることが可能です。
例えば、以下のようなデータを作りたいとします。
(エクセルなどの外部データを取り込むのではなく R の中で手作業でデータを作るとします)
1,3列目は数値型、2,4列目は文字列型、5列目は論理値型です。
id | name | age | sex | married |
---|---|---|---|---|
1 | Alice | 10 | Female | FALSE |
2 | Bob | 15 | Male | FALSE |
3 | Charlotte | 20 | Female | FALSE |
4 | Dick | 35 | Male | TRUE |
まず各列のデータのベクトルを作成し、それらを data.frame()
関数の引数に並べてデータフレームを作ります。
id = 1:4
name = c("Alice", "Bob", "Charlotte", "Dick")
age = c(10, 15, 20, 35)
sex = c("Female", "Male", "Female", "Male")
married = c(FALSE, FALSE, FALSE, TRUE)
data = data.frame(id, name, age, sex, married, stringsAsFactors = F)
data
## id name age sex married
## 1 1 Alice 10 Female FALSE
## 2 2 Bob 15 Male FALSE
## 3 3 Charlotte 20 Female FALSE
## 4 4 Dick 35 Male TRUE
stringsAsFactors
というのは、入力された文字列ベクトルを因子型に変換するかどうかの設定です。この例の場合はname列やsex列を文字列型のままにしておきたかったので FALSE にしています。
データフレームは同じ長さのベクトルを要素に持つリストです。各ベクトルは列とも呼ばれます。
上記の例のデータフレームは id, name, age, sex, married という5つの列を持っています。
データフレームの情報を調べるのに便利な関数を以下に示します。
# 列名
names(data)
## [1] "id" "name" "age" "sex" "married"
# 列数
ncol(data)
## [1] 5
# 行数
nrow(data)
## [1] 4
また、head()
関数を使うとデータフレームの冒頭数行が表示されます。
データフレームの中身を簡単に確認したい際に便利です。
# データフレームの冒頭の6行分が表示される
# (このデータフレームは4行分しかデータがないので全ての行が表示されます)
head(data)
## id name age sex married
## 1 1 Alice 10 Female FALSE
## 2 2 Bob 15 Male FALSE
## 3 3 Charlotte 20 Female FALSE
## 4 4 Dick 35 Male TRUE
# 第二引数に数値を入れると何行分を表示させるか指定できる
head(data, 2)
## id name age sex married
## 1 1 Alice 10 Female FALSE
## 2 2 Bob 15 Male FALSE
もうひとつ、str()
関数もデータフレームの概要を表示するのに便利です。
こちらの場合はベクトルの型も表示されます。
str(data)
## 'data.frame': 4 obs. of 5 variables:
## $ id : int 1 2 3 4
## $ name : chr "Alice" "Bob" "Charlotte" "Dick"
## $ age : num 10 15 20 35
## $ sex : chr "Female" "Male" "Female" "Male"
## $ married: logi FALSE FALSE FALSE TRUE
3.3.2.1 データフレームの値を取り出す
データフレームの値を取り出す方法はいくつかあります。
1つは配列の場合と同じように、数値を使って取り出したい列や行の位置を指定することです。
## 2列目を取り出す
data[2]
## name
## 1 Alice
## 2 Bob
## 3 Charlotte
## 4 Dick
# 2,4列目を取り出す
data[c(2, 4)]
## name sex
## 1 Alice Female
## 2 Bob Male
## 3 Charlotte Female
## 4 Dick Male
## 2列目の3行目を取り出す
data[2, 3]
## [1] 15
データフレームの各列には名前が付いているので、名前を使って列を指定することもできます。
## name列とage列を取り出す
data[c("name", "age")]
## name age
## 1 Alice 10
## 2 Bob 15
## 3 Charlotte 20
## 4 Dick 35
また、列名を使う場合には $ 記号を使った方法があります。
この $ 記号を使った方法はデータフレームを扱う際にはよく使われます。
次のような指定方法も可能です。
指定した要素を別の値で置き換えることができます。
data$name[4] = "Donald"
data
## id name age sex married
## 1 1 Alice 10 Female FALSE
## 2 2 Bob 15 Male FALSE
## 3 3 Charlotte 20 Female FALSE
## 4 4 Donald 35 Male TRUE
data$age = c(1, 2, 3, 4)
data
## id name age sex married
## 1 1 Alice 1 Female FALSE
## 2 2 Bob 2 Male FALSE
## 3 3 Charlotte 3 Female FALSE
## 4 4 Donald 4 Male TRUE
列に NULL を代入するとその列を削除できます。
3.3.3 Matrix (行列)
行列は2次元の配列です。
ベクトルと同様に、行列も全て同じ型の要素からなります。
行列は matrix() 関数を使って作成できます。
# 1から15までの数値ベクトルを、3行、5列の行列として作成
a = matrix(1:15, nrow = 3, ncol = 5)
a
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 4 7 10 13
## [2,] 2 5 8 11 14
## [3,] 3 6 9 12 15
matrix() 関数の最初の引数にベクトルを入れます。
nrow と ncol で行(row)と列(column)の数を指定します。
また、byrow という引数を使うと、数値が並ぶ方向を切り替えることができます。
a = matrix(1:15, nrow = 3, ncol = 5, byrow = T)
a
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 2 3 4 5
## [2,] 6 7 8 9 10
## [3,] 11 12 13 14 15
ベクトルではなくスカラーを指定した場合、全ての要素がその値である行列が作成されます。
dimnames という引数を使うと、行と列に名前を付けることができます。
v = 1:6
rnames = c("Cat1", "Cat2")
cnames = c("D1", "D2", "D3")
a = matrix(v, nrow = 2, ncol = 3, dimnames = list(rnames, cnames))
a
## D1 D2 D3
## Cat1 1 3 5
## Cat2 2 4 6
行列の要素の操作は以下のように行うことができます。
a = matrix(1:15, nrow = 3, ncol = 5, byrow = T)
a
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 2 3 4 5
## [2,] 6 7 8 9 10
## [3,] 11 12 13 14 15
# 1行目の全ての要素を取り出す
a[1,]
## [1] 1 2 3 4 5
# 3列目の全ての要素を取り出す
a[, 3]
## [1] 3 8 13
# 2行目の2列目にある値を取り出す
a[2, 2]
## [1] 7
# 1行目の2,3列目の要素を取り出す
a[1, 2:3]
## [1] 2 3
# 1,3行目の1,5列目の要素を取り出す
a[c(1, 3), c(1, 5)]
## [,1] [,2]
## [1,] 1 5
## [2,] 11 15
行や列に名前が付いている場合は名前を使って要素を取り出すこともできます。
v = 1:6
rnames = c("Cat1", "Cat2")
cnames = c("D1", "D2", "D3")
a = matrix(v, nrow = 2, ncol = 3, dimnames = list(rnames, cnames))
a
## D1 D2 D3
## Cat1 1 3 5
## Cat2 2 4 6
a["Cat1",]
## D1 D2 D3
## 1 3 5
a["Cat2", "D2"]
## [1] 4
行列の要素の書き換えは以下のようです。
a = matrix(1:15, nrow = 3, ncol = 5, byrow = T)
a
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 2 3 4 5
## [2,] 6 7 8 9 10
## [3,] 11 12 13 14 15
a[1,] = 21:25
a
## [,1] [,2] [,3] [,4] [,5]
## [1,] 21 22 23 24 25
## [2,] 6 7 8 9 10
## [3,] 11 12 13 14 15
a[3,] = 0
a
## [,1] [,2] [,3] [,4] [,5]
## [1,] 21 22 23 24 25
## [2,] 6 7 8 9 10
## [3,] 0 0 0 0 0
a[2, 3] = 999
a
## [,1] [,2] [,3] [,4] [,5]
## [1,] 21 22 23 24 25
## [2,] 6 7 999 9 10
## [3,] 0 0 0 0 0
a[1:3, 2:3] = matrix(1, nrow = 3, ncol = 2)
a
## [,1] [,2] [,3] [,4] [,5]
## [1,] 21 1 1 24 25
## [2,] 6 1 1 9 10
## [3,] 0 1 1 0 0
3.3.4 Array (配列)
配列は行列と似ていますが、3次元以上の次元を持つことができます。
array() 関数を使って作成します。
a = array(1:24, dim = c(2, 4, 3))
a
## , , 1
##
## [,1] [,2] [,3] [,4]
## [1,] 1 3 5 7
## [2,] 2 4 6 8
##
## , , 2
##
## [,1] [,2] [,3] [,4]
## [1,] 9 11 13 15
## [2,] 10 12 14 16
##
## , , 3
##
## [,1] [,2] [,3] [,4]
## [1,] 17 19 21 23
## [2,] 18 20 22 24
a[2, 1, 2]
## [1] 10
a[1, 1:3, 1:2] = 0
a
## , , 1
##
## [,1] [,2] [,3] [,4]
## [1,] 0 0 0 7
## [2,] 2 4 6 8
##
## , , 2
##
## [,1] [,2] [,3] [,4]
## [1,] 0 0 0 15
## [2,] 10 12 14 16
##
## , , 3
##
## [,1] [,2] [,3] [,4]
## [1,] 17 19 21 23
## [2,] 18 20 22 24
3.3.5 List (リスト)
リストは、様々な種類のデータ(オブジェクト)を持つことができます。
以下の例では数値、文字列、配列を要素に持つリストを作成しています。
x = list(1:4, c("A", "B", "C"), matrix(1:8, ncol = 2))
x
## [[1]]
## [1] 1 2 3 4
##
## [[2]]
## [1] "A" "B" "C"
##
## [[3]]
## [,1] [,2]
## [1,] 1 5
## [2,] 2 6
## [3,] 3 7
## [4,] 4 8
リストを作成する際に各要素に名前を付けることもできます。
x = list(num = 1:4, str = c("A", "B", "C"), arr = matrix(1:8, ncol = 2))
x
## $num
## [1] 1 2 3 4
##
## $str
## [1] "A" "B" "C"
##
## $arr
## [,1] [,2]
## [1,] 1 5
## [2,] 2 6
## [3,] 3 7
## [4,] 4 8
リストの要素を取り出すには2重の各括弧 [[ ]] や $ 記号を使います。