第7回講義資料

データ型

スライド

新しいタブで開く

データ型とは

 ベクトル(vector)はデータ構造(data structure)であり、ベクトル内の一つ一つの要素は数値や、文字など様々なデータ型(data type)の値を取り得る。

obj1 <- c(1, 3, 5, 7, 9, 11)
obj2 <- c("Kansai", "Kwansei Gakuin", "Doshisha", "Ritsumeikan")
obj3 <- c(TRUE, FALSE, FALSE)
obj4 <- "R"
  • obj1: 長さ6の数値型ベクトル
  • obj2: 長さ4の文字型ベクトル
  • obj3: 長さ3の論理型ベクトル
  • obj4: 長さ1の文字型ベクトル
    • 長さ1のベクトルは原子ベクトル(atomic vector)とも呼ばれる
ベクトルの長さが知りたい

ベクトルの長さはlength(オブジェクト名)で計算できる。たとえば、Object2の長さは4である。

length(obj2)
[1] 4

 他にもRには様々なデータ型が使える。以下のリストはRが提供するデータ型の一部であり、太字は本講義で紹介するデータ型である。ここでは説明を割愛するが日付型(Date型)もよく使われるデータ型であり、それそれの詳細は教科書第8章を参照されたい。

  • Logical
  • Numeric
  • Complex
  • Character
  • Factor
  • Date
  • NA
  • NULL
  • NaN
  • Inf
  • その他

データ型の確認

 ベクトル内の要素は全て同じデータ型を取るが、そのデータ型を確認するためには、class(ベクトル・オブジェクト名)関数を使用する。先ほど作成した4つのベクトルのデータ型を確認してみよう。

class(obj1) # 数値型 (numeric)
[1] "numeric"
class(obj2) # 文字型 (character)
[1] "character"
class(obj3) # 論理型 (logical)
[1] "logical"
class(obj4) # 文字型 (character)
[1] "character"

Logical型

 論理型(logical型)とはTRUEFALSEのみで構成されるデータ型である。論理演算子の計算結果は必ず以下のように論理型の結果が返される。

(2 + 3) == (4 + 1)
[1] TRUE

 この結果を代入演算子(<-)を使って、オブジェクトに格納するとlogical型ベクトルが作業環境内に格納される。

logi_vec1 <- (2 + 3) == (2 * 3)
logi_vec1
[1] FALSE
class(logi_vec1)
[1] "logical"

あるオブジェクトがlogical型か否かを判定するにはis.logical()を使用する。

is.logical(FALSE)
[1] TRUE

作成

 Logical型ベクトルを作成するためには、通常のベクトルと同様、c()関数で作成する。

logi_vec2 <- c(TRUE, FALSE, TRUE, TRUE, FALSE)
logi_vec2
[1]  TRUE FALSE  TRUE  TRUE FALSE

 ここでのTRUETFALSEFと略すことが出来るが、推奨しない。必ずTRUEFALSEで表記すること。

logi_vec3 <- c(T, F, T, T, F)
logi_vec3
[1]  TRUE FALSE  TRUE  TRUE FALSE

注意点

 Logical型の値であるTRUEFALSE"で囲んではいけない。もし、一つでも"で囲んでしまうと、そのベクトルlogical型でなく、後ほど紹介するcharacter型へ変換される。

# 2つ目のFALSEを"で囲むと...
logi_vec4 <- c(TRUE, "FALSE", TRUE, TRUE, FALSE)
logi_vec4
[1] "TRUE"  "FALSE" "TRUE"  "TRUE"  "FALSE"
class(logi_vec4)
[1] "character"

使い方

 直接TRUEFALSEが格納されたベクトルを使う場面はほとんどない。つまり、ほとんどのlogical型ベクトルは何らかの論理演算子から返されたものである。以下の例は、my_vec1から奇数の要素のみを抽出するために、logi_vec5というベクトルを作成する例である。

my_vec1  <- c(89, 28, 93, 64, 6)
logi_vec5 <- my_vec1 %% 2 == 1 # my_vec1を2で割ったら余りが1か
logi_vec5
[1]  TRUE FALSE  TRUE FALSE FALSE
class(logi_vec5)
[1] "logical"
my_vec1[logi_vec5] # my_vec1から奇数のみ抽出
[1] 89 93
my_vec1[my_vec1 %% 2 == 0] # 直接式を入れてもOK
[1] 28 64  6

Numeric型

num_vec1 <- c(2, 0, 0, 1, 3)
num_vec1
[1] 2 0 0 1 3
# num_vec1のデータ型
class(num_vec1)
[1] "numeric"
# num_vec1がnumeric型か否かを判定
is.numeric(num_vec1)
[1] TRUE

Numeric型の演算

 以下ではnumeric型ベクトル同士の演算について解説する。Numeric型ベクトル同士は常に可能であるが、ベクトルの長さによって動きがやや異なる(ベクトル・リサイクル)。ベクトル・リサイクルは第3回にて解説したが、ここで改めて解説する。

ケース1: 同じ長さのベクトル同士の演算

 2つのベクトルの長さが同じ場合、同じ位置の要素同士の演算となる。したがって、返ってくる結果(ベクトル)の長さは元のベクトルの長さと同じとなる。たとえば、長さ5の2つのベクトル同士の演算を考えてみよう。

num_vec2 <- c(1, 2, 3, 4, 5)  # 長さ5のnumeric型ベクトル
num_vec3 <- c(11, 7, 5, 3, 2) # 長さ5のnumeric型ベクトル

num_vec2 + num_vec3 # c(1+11, 2+7, 3+5, 4+3, 5+2)
[1] 12  9  8  7  7

 この場合、num_vec2の1番目の要素(1)とnum_vec3の1番目の要素(11)の足し算、num_vec2の2番目の要素(2)とnum_vec3の2番目の要素(7)の足し算、…が行われる。

ケース2: 長さ2以上 (A)長さ1 (B)同士の演算

 この場合、(A)のそれぞれ要素と(B)の要素同士で演算を行う。長さ5のベクトルに対し、たとえば長さ1のベクトルがc(10)であれば、自動的にc(10, 10, 10, 10, 10)へ変換されたと考えても良いだろう。

num_vec4 <- 10 # 長さ1の場合、c()はなくてもOK

num_vec3 / num_vec4 # c(11/10, 7/10, 5/10, 3/10, 2/10)
[1] 1.1 0.7 0.5 0.3 0.2

ケース3: 長さ2以上長さ2以上で長さが異なる場合

 この場合、より短いの要素がリサイクルされる。長さ5のベクトルに対し、たとえば長さ3のベクトルがc(1, 2, 3)であれば、自動的にc(1, 2, 3, 1, 2)へ変換されたと考えても良いだろう。これをRでは「ベクトル・リサイクル」(vector recycle)と呼ぶ。ちなみに、この場合、警告が表示される場合もある。これは長い方のベクトルの長さが短い方の長さの倍数になっていない場合に出力される。しかし、計算そのものには問題がない。

num_vec5 <- c(1, 2, 3)

num_vec3 * num_vec5 # c(11*1, 7*2, 5*3, 3*1, 2*2)
Warning in num_vec3 * num_vec5: longer object length is not a multiple of
shorter object length
[1] 11 14 15  3  4

注意点

 Logical型と同じ理由でnumeric型の値を"で囲んではいけない。一つでも"で囲むとNumeric型でなく、Character型へ変換されてしまう。

# 4つ目のFALSEを"で囲むと...
num_vec6 <- c(38, 29, 10, "94", 51)
num_vec6
[1] "38" "29" "10" "94" "51"
class(num_vec6)
[1] "character"

Character型

 Character型(文字型)は要素が"で囲まれたデータ型である。

char_vec1 <- c("Kansai", "Kwansei-gakuin", "Doshisha", "Ritsmeikan")
char_vec1
[1] "Kansai"         "Kwansei-gakuin" "Doshisha"       "Ritsmeikan"    
class(char_vec1)
[1] "character"
is.character(char_vec1) # char_vec1がcharacter型であればTRUE
[1] TRUE

文字列の長さ

 文字列ベクトルの長さを求める場合はlength()関数を使用する。

length(char_vec1)
[1] 4

 ただし、length()関数はベクトルの長さを求める関数であって、各要素の文字数を求める関数ではない。各要素の文字数を求める場合はnchar()関数を使用する。

nchar(char_vec1)
[1]  6 14  8 10

文字の結合

 本講義では使うことはほとんどないものの、頻繁に使う関数としてpaste()関数(またはpaste0()関数)がある。これは2つの文字列を結合する関数であり、使い方はpaste(Character型ベクトル, Character型ベクトル)である。

ケース1: char_vec1の全要素の後に"University"を付ける。

char_vec2 <- paste(char_vec1, "University")
char_vec2 # "University"の前に自動的にスペースが入る
[1] "Kansai University"         "Kwansei-gakuin University"
[3] "Doshisha University"       "Ritsmeikan University"    

 この場合、大学名(たとえば、"Kansai")と"University"の間には自動的にスペースが入る。スペースを無くしたい場合は、paste()内にsep = ""を追加するか、paste0()関数を使用する。このsep引数は結合される2つの文字列の間に入る文字を意味し、デフォルトはスペース(" ")である。

paste(char_vec1, "University", sep = "")
[1] "KansaiUniversity"         "Kwansei-gakuinUniversity"
[3] "DoshishaUniversity"       "RitsmeikanUniversity"    
paste0(char_vec1, "University")
[1] "KansaiUniversity"         "Kwansei-gakuinUniversity"
[3] "DoshishaUniversity"       "RitsmeikanUniversity"    
paste(char_vec1, "University", sep = "-")
[1] "Kansai-University"         "Kwansei-gakuin-University"
[3] "Doshisha-University"       "Ritsmeikan-University"    

ケース2: char_vec2の全要素の前に12、…を付け、数字と大学名は"."で結合

 結合する2つのベクトルの長さがいずれも2以上の場合、同じ位置の要素同士の結合となる。

char_vec3 <- paste(1:4, char_vec2, sep = ".")
char_vec3
[1] "1.Kansai University"         "2.Kwansei-gakuin University"
[3] "3.Doshisha University"       "4.Ritsmeikan University"    

Factor型

 Factor型は見た目上はcharacter型と同じであるが要素に順番(順位)が付いている点で異なる。つまり、factor型は順序付きcharacter型とも言えよう。

 以下の2つの表形式データの内容は全く同じものである。しかし、左の表の場合大学名列のデータ型はcharacter型(列名の下に<chr>と表示される)、右の表の場合はfactor型(列名の下に<fct>と表示される)である。Factor型変数は要素の順番(順位)が決まっていて、ここでは"Kansai" > "Kwansei-gakuin" > "Doshisha" > "Ritsumeikan"の順番で設定してある。

大学名がcharacter型の場合

# A tibble: 4 × 2
  大学名         学生数
  <chr>           <dbl>
1 Kansai          27736
2 Kwansei-gakuin  23671
3 Doshisha        25974
4 Ritsumeikan     32467

大学名がfactor型の場合

# A tibble: 4 × 2
  大学名         学生数
  <fct>           <dbl>
1 Kansai          27736
2 Kwansei-gakuin  23671
3 Doshisha        25974
4 Ritsumeikan     32467

 この見た目上は全く同じの2つのデータを使って、大学別学生数の棒グラフを作成した例が以下の図である。

 このようにcharacter型だと、作図の際、大学がアルファベット順で並ぶものの、factor型であれば、予め決めておいた順番で並ぶ。Factor型は図表を作成する際に重宝されるデータ型である。

Factor型の作成

 ここでは、既存のcharacter型ベクトルをfactor型に変換する方法について紹介する。以下のchar_vec4は関関同立の名前をアルファベット順で格納した長さ4のcharacter型ベクトルである。

char_vec4 <- c("Doshisha", "Kansai", "Kwansei-gakuin", "Ritsumeikan")
class(char_vec4)
[1] "character"
char_vec4
[1] "Doshisha"       "Kansai"         "Kwansei-gakuin" "Ritsumeikan"   

 Factor型ベクトルはfactor()関数で作成する。第一引数は元となるcharacter型ベクトルであり、levels引数に要素の順位を付ける。

fct_vec1 <- factor(char_vec4,
                   levels = c("Kansai", "Kwansei-gakuin", "Doshisha", "Ritsumeikan"))
class(fct_vec1)
[1] "factor"
fct_vec1
[1] Doshisha       Kansai         Kwansei-gakuin Ritsumeikan   
Levels: Kansai Kwansei-gakuin Doshisha Ritsumeikan

 このようにfactor型ベクトルを出力した場合、ベクトルの中身に加え、下段に要素の順位が表示され、図表を作成する際はこの順番で自動的にソートされる。

Factor型の詳細

 このfactor型は非常に重要なデータ型であり、図表を作成する際には必ず考えなくてはならないものである。先ほどの例のように、文字列をfactor化しないと要素はアルファベット順になる。図表において順番が思い通りにならない原因は、factor化していない、またはfactor化が間違っているのがほとんどである。factor型については今後データハンドリング、可視化の講義で改めて解説する。


欠損値

 データ分析において頻繁に遭遇するのはNAであるが、これは欠損値(missing value)を意味する。欠損値は何らかの値があるはずであるものの、観察されていない値である。例えば、国連開発機構が毎年発表している「人間開発指数(Human Development Index; HDI)」では世界各国のデータが含まれている。しかし、世界における全ての国のデータが入っているわけではなく、たとえば台湾や北朝鮮のデータは含まれていない。これらの国/地域に人間開発という概念がないわけではなく、なんらかの理由(今回は政治的な理由)で値が欠損しているだけである。

 自分でデータセットを構築しようとする時に、特定のケースに欠損が生じるケースは多々あり、世論調査でも例外ではない。たとえば答えづらい質問に対して「わからない」や「答えたくない」を選んだ場合、その回答者における当該質問は欠損となる。このように多くのデータには欠損値が含まれているため、欠損値処理は非常に重要である。欠損値の処理には様々な方法があるが、本講義では欠損値が含まれたケースを除外した分析を行う予定である。

 他にも計算上、何らかの問題を生じさせうるものはあるが、以下では簡単にその例を紹介する。ただし、NaNInfのベクトルを作ることは可能であるが、使う機会はほとんどなく、何かの計算の結果によって返ってくるケースが多いので、その意味さえ把握しておけば良い。

  • NA: 何らかの値があるはずだが、欠損している状態
  • NULL: そもそも存在しない
  • NaN: 計算不可(例: 0 \(\div\) 0)
  • Inf: 無限大(例: 10 \(\div\) 0)

NANULLの違い

 値がないという点でNANULLは似ているように見えるが、実は全く異なる概念である。NAは要素としてカウントされるが、NULLはカウントされない。以下の例を見てみよう。

NA_vec   <- c(1, 2, 3, NA, 5, NA, 7)
NULL_vec <- c(1, 2, 3, NULL, 5, NULL, 7)
length(NA_vec)
[1] 7
length(NULL_vec)
[1] 5
NA_vec
[1]  1  2  3 NA  5 NA  7
NULL_vec
[1] 1 2 3 5 7

 このようにNULLはそもそも存在しないことを意味する。NAが入居者がいない空き部屋であれば、NULLはそもそも部屋が存在しないことを意味する。ここまでの話だとNULLの存在意義が疑われるだろうが、中級者以上になるといずれ使う機会があろう。

欠損値を含むベクトルの計算

 ベクトルに欠損値が含まれている場合、平均値(mean())、標準偏差(sd())などの計算ができず、以下のように結果としてNAが返ってくる。

mean(NA_vec)
[1] NA

 ここで欠損値を以外の要素のみを使って計算する方法としては以下の2つの方法がある1

方法1: データから欠損値を除外する。

  • !演算子は否定を意味する(第3回参照)
  • ちなみに、NA_vec == NANA_vec != NAは使用不可
is.na(NA_vec) # 各要素がNAか否かを判定
[1] FALSE FALSE FALSE  TRUE FALSE  TRUE FALSE
!is.na(NA_vec) # 各要素がNAか否かの判定を反転
[1]  TRUE  TRUE  TRUE FALSE  TRUE FALSE  TRUE
NA_vec[!is.na(NA_vec)] # 欠損値でない要素のみ抽出
[1] 1 2 3 5 7
mean(NA_vec[!is.na(NA_vec)])
[1] 3.6

方法2: 関数内にna.rm = TRUEを追加する。

 mean()関数の場合、na.rmという引数が用意されており、これをTRUEにすると、欠損値を除外した平均値が求められる(既定値はFALSE)。通常、関数には様々な引数が用意されている。Rコンソール上で?関数名を入力するとヘルプが読める(mean()関数のヘルプは?meanで読める)。

mean(NA_vec, na.rm = TRUE)
[1] 3.6

ベクトル操作(続)

 今回はデータ型が主な内容であったが、ベクトル操作はこれからも必要となるため、以下では第3回に続き、ベクトルの操作方法について解説する。練習用のベクトルとしてmy_vec2を用意する。

my_vec2 <- c(4, 3, 2, 1)
my_vec2
[1] 4 3 2 1

要素の追加

 ベクトルに新しい要素を追加するためにはベクトル名[追加したい位置] <- 追加する値と入力する。たとえば、my_vec2の5番目の要素として0を追加する場合は以下のように入力する。

my_vec2[5] <- 0
my_vec2
[1] 4 3 2 1 0

 複数の要素を入れることができる。my_vec2の6、7、8番目の要素として、-1、-2、-3を追加する場合、以下のように入力する。

# 6:8の代わりにc(6, 7, 8)もOK
my_vec2[6:8] <- c(-1, -2, -3)
my_vec2
[1]  4  3  2  1  0 -1 -2 -3

 今、my_vec2の長さは8である。もし、このmy_vec2の11番目の要素としてに10を入れたらどうなるだろうか。

my_vec2[11] <- 10
my_vec2
 [1]  4  3  2  1  0 -1 -2 -3 NA NA 10

 このように11番目に10が追加され、9、10番目の要素は欠損値(NA)になる。

要素の置換

 要素の置換は要素の追加と同じである。つまり、ベクトル名[置換したい位置] <- 置換する値と入力する。my_vec2の11番目の要素は10であったが、これを-6に置換する。

my_vec2[11] <- -6
my_vec2
 [1]  4  3  2  1  0 -1 -2 -3 NA NA -6

 要素の追加と同様、複数の要素を置換することもできる。ここではmy_vec2の9、10番目の要素(NANA)を-4、-5に置換してみよう。

my_vec2[9:10] <- c(-4, -5)
my_vec2
 [1]  4  3  2  1  0 -1 -2 -3 -4 -5 -6

 置換する位置を指定する[]内に論理演算子を使えば、条件に合致する要素のみ置換することができる。たとえば、my_vec2の要素の中で、0より小さい要素に-1を掛けて置換する場合、以下のように入力する。

my_vec2[my_vec2 < 0] <- my_vec2[my_vec2 < 0] * -1
my_vec2
 [1] 4 3 2 1 0 1 2 3 4 5 6

教科書

  1. 欠損値を統計的処理を用いて補完することもでき、これを「多重代入法(multiple imputation)」と呼ぶ。↩︎