複数シート、データのマージ、欠損値
理解を深めるために、データ数20レコードにおいて欠損値(Non Avairable value)を含む例を取り上げて解説する。 その都度、データセットの内容を確認して作業することを強く勧める。
複数のシートデータを扱う
Excel等の表計算ソフトウエアで作成したデータでは、複数のシートに記載されたデータが1つのファイルとなっていることがある(たしかに関連データの散逸を防ぐなど便利なことがある)。
パッケージ gregmisc の関数 read.xls( )
を使うとExcelのシートを指定して直接データを読み込むことができる。
しかし、日本語データの読取に問題が発生することがある。
確実なのは、各シートごとにCSV形式でシートデータを保存してRに読み込むことである。
basic.csv
、歴史(Hist)、物理(Phys)、生物(Bio)の選択科目データを selective.csv
として保存せよ。
basic.csv
を Basic として、選択科目データ selective.csv
をSelect としてRに読み込め。
[ヒント]: それぞれのシートデータを観察して、列ラベル名からの行データをデータフレームとして読み込む。
> Basic <- read.csv(file = "basic.csv", header = TRUE, skip = 5) > Select <- read.csv(file = "selective.csv", header = TRUE, skip = 3)
データセットの結合
Rでは、入力されていないフィールドを示すために欠損値(Non Avairable)として NA と記載される。 読み込んだデータセット Basic と Select の内容を観察してみよう。
基本科目データ Basic では20人分全員の「完全な」レコードがあるが、選択科目データ Select では学生番号 a129 のレコードは記載されていないことに注意。 実際、次のようにBasic は20行、Select は19行のデータであることが確かめられる。
> Basic Stnum Sex Eng Lang Math 1 a111 M 68 76 71 2 a112 F 38 62 33 3 a113 M NA 62 88 4 a114 F 62 77 52 5 a115 F 82 69 93 6 a116 F 44 72 57 7 a117 F 48 72 66 8 a118 M 47 64 NA 9 a119 M 77 77 55 10 a120 M 89 NA 75 11 a121 M 51 76 57 12 a122 F 61 65 45 13 a123 M 73 81 58 14 a124 F 48 84 56 15 a125 F NA 70 67 16 a126 M 74 76 51 17 a127 M 57 53 25 18 a128 M 47 74 81 19 a129 F 84 78 85 20 a130 M 68 82 74 > Select Stnum Hist Phys Bio 1 a111 90 NA 85 2 a112 NA 78 94 3 a113 78 80 NA 4 a114 85 NA 75 5 a115 NA 85 80 6 a116 68 84 85 7 a117 74 NA 75 8 a118 82 84 NA 9 a119 NA 95 85 10 a120 58 NA 60 11 a121 NA 68 95 12 a122 70 84 90 13 a123 75 NA 80 14 a124 NA 60 75 15 a125 59 92 NA 16 a126 85 80 NA 17 a127 NA 76 95 18 a128 90 NA 75 19 a130 94 NA NA
データフレーム Basic と Select は共通の識別ラベルである Stnum(学生番号)をキーとしてを使い、次のようにして合併することができる。
合併データ Exam0 を表示してわかるように、どちらかのデータフレームで欠けているレコードがあれば、合併後のデータフレームでも存在しないことに注意。 つまり、学生番号 a129 の行データ(レコード)は Exam0 には存在しない。
> Exam0 <- merge(Basic, Select, by = "Stnum") > Exam0 Stnum Sex Eng Lang Math Hist Phys Bio 1 a111 M 68 76 71 90 NA 85 2 a112 F 38 62 33 NA 78 94 3 a113 M NA 62 88 78 80 NA 4 a114 F 62 77 52 85 NA 75 5 a115 F 82 69 93 NA 85 80 6 a116 F 44 72 57 68 84 85 7 a117 F 48 72 66 74 NA 75 8 a118 M 47 64 NA 82 84 NA 9 a119 M 77 77 55 NA 95 85 10 a120 M 89 NA 75 58 NA 60 11 a121 M 51 76 57 NA 68 95 12 a122 F 61 65 45 70 84 90 13 a123 M 73 81 58 75 NA 80 14 a124 F 48 84 56 NA 60 75 15 a125 F NA 70 67 59 92 NA 16 a126 M 74 76 51 85 80 NA 17 a127 M 57 53 25 NA 76 95 18 a128 M 47 74 81 90 NA 75 19 a130 M 68 82 74 94 NA NA
合併時における欠損レコードの扱い
上の例のように、マージされる前のいずれかのデータセットで欠けているレコードが、マージされたときも存在しないのは、
関数 marge( )
のオプションがデフォルトで all が FALSE がセットされているためである。
オプション all = TRUE
を指定して次のようにすれば、いずれかのデータセットでレコードが存在していれば、マージ後の欠損箇所が NA で埋められて結合される。
> Exam <- merge(Basic, Select, by = "Stnum", all = TRUE) > Exam Stnum Sex Eng Lang Math Hist Phys Bio 1 a111 M 68 76 71 90 NA 85 2 a112 F 38 62 33 NA 78 94 3 a113 M NA 62 88 78 80 NA 4 a114 F 62 77 52 85 NA 75 5 a115 F 82 69 93 NA 85 80 6 a116 F 44 72 57 68 84 85 7 a117 F 48 72 66 74 NA 75 8 a118 M 47 64 NA 82 84 NA 9 a119 M 77 77 55 NA 95 85 10 a120 M 89 NA 75 58 NA 60 11 a121 M 51 76 57 NA 68 95 12 a122 F 61 65 45 70 84 90 13 a123 M 73 81 58 75 NA 80 14 a124 F 48 84 56 NA 60 75 15 a125 F NA 70 67 59 92 NA 16 a126 M 74 76 51 85 80 NA 17 a127 M 57 53 25 NA 76 95 18 a128 M 47 74 81 90 NA 75 19 a129 F 84 78 85 NA NA NA <-- 欠損行があっても、NAで埋められて結合される 20 a130 M 68 82 74 94 NA NA
欠損値のある平均
列データの取得で紹介したように、
結合データフレーム Exam の英語列データは、記号 $ を使って、Exam$Eng
で取り出すことができる。
今の例の場合、そこに欠損値 NA を2個含んでいる。
> Exam$Eng [1] 68 38 NA 62 82 44 48 47 77 89 51 61 73 48 NA 74 57 47 84 68
欠損値を含んでいるデータ並び(ベクトル)の平均値を関数 mean( ) で次のように単純に求めようとすると、うまくいかない(NAが返る)。
> mean(Exam$Eng) [1] NA
ただし、欠損値 NA がなかったことにして平均値や合計を求めることはできる。 次のような簡単な例を試してみよう。
ベクトル(データの並び)として、2つの欠損値 NA を含む6つのデータ(値があるのは1,2,3,5の4つのデータ)を x とする。
この x の平均を mean( ) で平均値 mean(x)
を求めようとすると NA が返って失敗する。
しかし、次のようにオプション na.rm=TRUE
を付けて関数 mean( ) を使うと、平均値(1+2+3+5)/4=2.75 を計算できることがわかる。
na.rm は Non Avairable値を除外する(reMove)の意である。
> x <- c(1, 2, 3, NA, 5, NA) > x [1] 1 2 3 NA 5 NA > mean(x) [1] NA > mean(x, na.rm = TRUE) [1] 2.75
na.rm = TRUE
を使って、
英語(Eng)、国語(Lang)、数学(Math)、歴史(Hist)、物理(Phys)、生物(Bio)のクラス平均値を求めよ。
[ヒント]:
> mean(Exam$Eng, na.rm = TRUE) [1] 62.11111
colMeans( )
でもオプション na.rm=TRUE
が使える。
関数 colMeans( )
を使って、
英語(Eng)、国語(Lang)、数学(Math)、歴史(Hist)、物理(Phys)、生物(Bio)のクラス平均値を求めよ。
[ヒント]:
> colMeans(Exam[,3:8], na.rm = TRUE)
欠損値の判定 is.na( )
Rでは、欠損値があっても、それをを除外して平均や合計などを計算することができるので便利である。 しかし、計算結果が得られたとしても、除外した欠損値の個数がどの程度あるのかについては常に注意をはらう必要がある。 ほとんどのデータがNSの場合に、平均値を求めても意味があるのかどうかは一考に値するからだ。
データが欠損値(NA)であるかどうかを判定する関数が is.na
( ) だ。
NA のとき TRUE、NA でないとき FALSE を返す。
否定演算子 !を付けると、結果は反転する。
> is.na(Exam$Eng)
[1] FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[13] FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
> !is.na(Exam$Eng)
[1] TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[13] TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE
関数 table
( ) は値に応じた分布表を返す。
次にようにすれば、クラスの英語データ Exam$Eng のNAの数は2個あることが分かる。
> table(!is.na(Exam$Eng)) FALSE TRUE 2 18
colMeans( )と rowMeans( )
2次元データセットに対して、関数 colMeans
( ) は各列の平均値を、関数 rowMeans
( ) は各行の平均値を計算する。
データフレーム Exam の3列から8列までの連続する列からなる2次元データの各列の NA値を除いた平均値は次で求めることができる。
> colMeans(Exam[ ,3:8], na.rm = TRUE) Eng Lang Math Hist Phys Bio 62.11111 72.10526 62.57895 77.53846 80.50000 82.07143
データフレーム Exam の3列から8列までの連続する列からなる2次元データの各行の NA値を除いた平均値は次のように求めることができる。
Exam$Ave <- ...
において、個人の科目平均値をデータフレーム Exam に新しくラベル Ave を定義し、Ave列に個人平均をセットしていることに注意する。
> rowMeans(Exam[ ,3:8], na.rm = TRUE) [1] 78.00000 61.00000 77.00000 70.20000 81.80000 68.33333 67.00000 69.25000 [9] 77.80000 70.50000 69.40000 69.16667 73.40000 64.60000 72.00000 73.20000 [17] 61.20000 73.40000 82.33333 79.50000 > Exam$Ave <- rowMeans(Exam[ ,3:8], na.rm = TRUE) > Exam Stnum Sex Eng Lang Math Hist Phys Bio Ave 1 a111 M 68 76 71 90 NA 85 78.00000 2 a112 F 38 62 33 NA 78 94 61.00000 3 a113 M NA 62 88 78 80 NA 77.00000 4 a114 F 62 77 52 85 NA 75 70.20000 5 a115 F 82 69 93 NA 85 80 81.80000 6 a116 F 44 72 57 68 84 85 68.33333 7 a117 F 48 72 66 74 NA 75 67.00000 8 a118 M 47 64 NA 82 84 NA 69.25000 9 a119 M 77 77 55 NA 95 85 77.80000 10 a120 M 89 NA 75 58 NA 60 70.50000 11 a121 M 51 76 57 NA 68 95 69.40000 12 a122 F 61 65 45 70 84 90 69.16667 13 a123 M 73 81 58 75 NA 80 73.40000 14 a124 F 48 84 56 NA 60 75 64.60000 15 a125 F NA 70 67 59 92 NA 72.00000 16 a126 M 74 76 51 85 80 NA 73.20000 17 a127 M 57 53 25 NA 76 95 61.20000 18 a128 M 47 74 81 90 NA 75 73.40000 19 a129 F 84 78 85 NA NA NA 82.33333 20 a130 M 68 82 74 94 NA NA 79.50000
データのソート
関数 sort
( ) はセットしたデータ並び(ベクトル)を並べ替えた結果を返す。
デフォルトは昇順で並べ替えた結果を返すが、オプション decreasing = TRUE
とすると降順に並べ替えた結果を返す。
> x <- c(6, 3, 4, 1, 5, 2) > sort(x) [1] 1 2 3 4 5 6 > sort(x, decreasing = TRUE) [1] 6 5 4 3 2 1
一方、関数 order
( ) は、セットしたデータ並び(ベクトル)を並べ替え(ソート)したとき、元のベクトルにおけるデータ位置を返す関数である。
デフォルトは昇順ソートでの元データの位置を返すが、オプション decreasing = TRUE
とすると降順ソートにおける元データの位置を返す。
次の例で、order(x) が返すデータ並び「4 6 2 3 5 1」の最初の値 4 の意味は、(昇順で x を並べ替えたときの)元データの場所が 4 であることを示す。 したがって、並べ替えたときの最初の値は x[4] つまり 1 である。
> x <- c(6, 3, 4, 1, 5, 2) > order(x) [1] 4 6 2 3 5 1 > order(x, decreasing = TRUE) [1] 1 5 3 2 6 4
次の例は、データフレームの Ave 列のデータ並び(ベクトル)を Exam$Ave で取り出したとき、降順で並べ替えたときの Ave 値の元位置は order(Exam$Ave, decreasing = TRUE) であることを示している。 Exam[AveOrder, ] の出力結果に現れる行番号の並びに注意する。 その並びは、まさに order(Exam$Ave, decreasing = TRUE) に一致している。
> AveOrder <- order(Exam$Ave, decreasing = TRUE) > AveOrder [1] 19 5 20 1 9 3 13 18 16 15 10 4 11 8 12 6 7 14 17 2 > Exam[AveOrder, ] Stnum Sex Eng Lang Math Hist Phys Bio Ave 19 a129 F 84 78 85 NA NA NA 82.33333 5 a115 F 82 69 93 NA 85 80 81.80000 20 a130 M 68 82 74 94 NA NA 79.50000 1 a111 M 68 76 71 90 NA 85 78.00000 9 a119 M 77 77 55 NA 95 85 77.80000 3 a113 M NA 62 88 78 80 NA 77.00000 13 a123 M 73 81 58 75 NA 80 73.40000 18 a128 M 47 74 81 90 NA 75 73.40000 16 a126 M 74 76 51 85 80 NA 73.20000 15 a125 F NA 70 67 59 92 NA 72.00000 10 a120 M 89 NA 75 58 NA 60 70.50000 4 a114 F 62 77 52 85 NA 75 70.20000 11 a121 M 51 76 57 NA 68 95 69.40000 8 a118 M 47 64 NA 82 84 NA 69.25000 12 a122 F 61 65 45 70 84 90 69.16667 6 a116 F 44 72 57 68 84 85 68.33333 7 a117 F 48 72 66 74 NA 75 67.00000 14 a124 F 48 84 56 NA 60 75 64.60000 17 a127 M 57 53 25 NA 76 95 61.20000 2 a112 F 38 62 33 NA 78 94 61.00000
男女別平均
データフレーム Exam から性別 Exam$Sex を取り出して、男性または女性であるときに TRUE であるデータ並び(ベクトル)をそれぞれ Men および Women とする。
> Men <- Exam$Sex == "M" > Men [1] TRUE FALSE TRUE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE FALSE [13] TRUE FALSE FALSE TRUE TRUE TRUE FALSE TRUE > Women <- Exam$Sex == "F" > Women [1] FALSE TRUE FALSE TRUE TRUE TRUE TRUE FALSE FALSE FALSE FALSE TRUE [13] FALSE TRUE TRUE FALSE FALSE FALSE TRUE FALSE
データフレーム Exam から Sex が男性または女性である行はそれぞれ Exam[Men, ] または Exam[Women, ] である。
> Exam[Men, ] Stnum Sex Eng Lang Math Hist Phys Bio Ave 1 a111 M 68 76 71 90 NA 85 78.00 3 a113 M NA 62 88 78 80 NA 77.00 8 a118 M 47 64 NA 82 84 NA 69.25 9 a119 M 77 77 55 NA 95 85 77.80 10 a120 M 89 NA 75 58 NA 60 70.50 11 a121 M 51 76 57 NA 68 95 69.40 13 a123 M 73 81 58 75 NA 80 73.40 16 a126 M 74 76 51 85 80 NA 73.20 17 a127 M 57 53 25 NA 76 95 61.20 18 a128 M 47 74 81 90 NA 75 73.40 20 a130 M 68 82 74 94 NA NA 79.50 > Exam[Women, ] Stnum Sex Eng Lang Math Hist Phys Bio Ave 2 a112 F 38 62 33 NA 78 94 61.00000 4 a114 F 62 77 52 85 NA 75 70.20000 5 a115 F 82 69 93 NA 85 80 81.80000 6 a116 F 44 72 57 68 84 85 68.33333 7 a117 F 48 72 66 74 NA 75 67.00000 12 a122 F 61 65 45 70 84 90 69.16667 14 a124 F 48 84 56 NA 60 75 64.60000 15 a125 F NA 70 67 59 92 NA 72.00000 19 a129 F 84 78 85 NA NA NA 82.33333
上のcolMeans( )と rowMeans( )の方法を使って、欠損値 NA を除外して、3列から8列までのクラスの男女別科目平均が求められる。
sapply( ) と tapply( )
sapply( )
を使って、クラスの男女別科目平均が求められることを説明せよ。
> sapply(Exam[Men,3:8], FUN = mean, na.rm = TRUE) Eng Lang Math Hist Phys Bio 65.10000 72.10000 63.50000 81.50000 80.50000 82.14286 > sapply(Exam[Women,3:8], FUN = mean, na.rm = TRUE) Eng Lang Math Hist Phys Bio 58.37500 72.11111 61.55556 71.20000 80.50000 82.00000
tapply( )
を使った計算できることを説明せよ。
> tapply(Exam$Eng, Basic$Sex, mean, na.rm = TRUE) F M 58.375 65.100