以下では具体的な例を示すためにRに最初から入っているデモ用データのiris
を用いる.
irisデータはアイリス(菖蒲)のがく(Sepal)と花びら(Petal)の長さ(length)と幅(width)の実測データが3つのアイリスの種類(Setosa
,
vergicolor
,
virginica
)ごとに50点ずつ格納されている.
内容を確認するために,summary()
関数とhead()
関数(データフレームの冒頭データを出力させる関数)を実行してみた.
data_iris <- iris #irisデータを呼び出してdというオブジェクトに格納
summary(data_iris)
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100
## 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300
## Median :5.800 Median :3.000 Median :4.350 Median :1.300
## Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199
## 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800
## Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500
## Species
## setosa :50
## versicolor:50
## virginica :50
##
##
##
head(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
## 5 5.0 3.6 1.4 0.2 setosa
## 6 5.4 3.9 1.7 0.4 setosa
列名が英語のままだと分かりにくいので,日本語に翻訳した名前に置き換える(->参考).以下はそのためのコード.
colnames(data_iris) <- c("がく長","がく幅","花びら長","花びら幅","種類")
head(data_iris)
## がく長 がく幅 花びら長 花びら幅 種類
## 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
## 5 5.0 3.6 1.4 0.2 setosa
## 6 5.4 3.9 1.7 0.4 setosa
グループ分け変数を持ったデータを処理するときに,ある特定のグループのデータだけを抜き出したいということはよくある.
そうした「データの抽出」を行うための関数としてtidyverse
パッケージにfilter()
関数が設けられている.利用するためにはTools->install.packagesでtidyverse
パッケージをインストールしたうえで,スクリプト上でlibrary(tidyverse)
と入力してパッケージを読み込む必要がある.
filter()
関数の利用法は,第1引数に元のデータを与え,第2引数に検索条件を与える.検索条件の書式のパターンは以下の通り.
書式 | 動作 |
---|---|
元データ$列名==Key | 列名で指定した列の値がKeyと一致しているものを抽出.「=」を重ねる点がポイント. |
元データ$列名>Key | 列名で指定した列の値がKeyよりも大きいものを抽出 |
元データ$列名>=Key | 列名で指定した列の値がKeyと等しいかKeyよりも大きいものを抽出 |
元データ$列名<Key | 列名で指定した列の値がKeyよりも小さいものを抽出 |
元データ$列名<=Key | 列名で指定した列の値がKeyと等しいかKeyよりも小さいものを抽出 |
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.1 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.1
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
summary(data_iris)
## がく長 がく幅 花びら長 花びら幅
## Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100
## 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300
## Median :5.800 Median :3.000 Median :4.350 Median :1.300
## Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199
## 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800
## Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500
## 種類
## setosa :50
## versicolor:50
## virginica :50
##
##
##
res<- filter(data_iris, 種類=="virginica")
summary(res)
## がく長 がく幅 花びら長 花びら幅
## Min. :4.900 Min. :2.200 Min. :4.500 Min. :1.400
## 1st Qu.:6.225 1st Qu.:2.800 1st Qu.:5.100 1st Qu.:1.800
## Median :6.500 Median :3.000 Median :5.550 Median :2.000
## Mean :6.588 Mean :2.974 Mean :5.552 Mean :2.026
## 3rd Qu.:6.900 3rd Qu.:3.175 3rd Qu.:5.875 3rd Qu.:2.300
## Max. :7.900 Max. :3.800 Max. :6.900 Max. :2.500
## 種類
## setosa : 0
## versicolor: 0
## virginica :50
##
##
##
res <- filter(data_iris, がく長<=5)
summary(res)
## がく長 がく幅 花びら長 花びら幅
## Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.1000
## 1st Qu.:4.600 1st Qu.:3.000 1st Qu.:1.375 1st Qu.:0.2000
## Median :4.850 Median :3.150 Median :1.400 Median :0.2000
## Mean :4.787 Mean :3.091 Mean :1.703 Mean :0.3406
## 3rd Qu.:5.000 3rd Qu.:3.400 3rd Qu.:1.600 3rd Qu.:0.3000
## Max. :5.000 Max. :3.600 Max. :4.500 Max. :1.7000
## 種類
## setosa :28
## versicolor: 3
## virginica : 1
##
##
##
res <- filter(data_iris, がく長>=6)
summary(res)
## がく長 がく幅 花びら長 花びら幅 種類
## Min. :6.00 Min. :2.200 Min. :4.000 Min. :1.000 setosa : 0
## 1st Qu.:6.30 1st Qu.:2.800 1st Qu.:4.700 1st Qu.:1.500 versicolor:24
## Median :6.50 Median :3.000 Median :5.200 Median :1.800 virginica :43
## Mean :6.61 Mean :2.966 Mean :5.263 Mean :1.816
## 3rd Qu.:6.85 3rd Qu.:3.150 3rd Qu.:5.700 3rd Qu.:2.100
## Max. :7.90 Max. :3.800 Max. :6.900 Max. :2.500
条件は複数並べることもできる.|
は複数の条件のいずれかにマッチすれば抽出される.&
は複数条件の全てにマッチするものが抽出される.
それぞれ以下に示す.
res <- filter(data_iris, がく長>=6 | 花びら長>1.5) # がく長が6以上「または」花びら長が1.5より大きいもの
summary(res)
## がく長 がく幅 花びら長 花びら幅 種類
## Min. :4.700 Min. :2.00 Min. :1.600 Min. :0.200 setosa :13
## 1st Qu.:5.600 1st Qu.:2.70 1st Qu.:4.000 1st Qu.:1.300 versicolor:50
## Median :6.100 Median :3.00 Median :4.700 Median :1.500 virginica :50
## Mean :6.125 Mean :2.94 Mean :4.535 Mean :1.519
## 3rd Qu.:6.600 3rd Qu.:3.20 3rd Qu.:5.400 3rd Qu.:2.000
## Max. :7.900 Max. :3.90 Max. :6.900 Max. :2.500
res <- filter(data_iris, がく長>=6 & 花びら長>1.5) # がく長が6以上「かつ」花びら長が1.5より大きいもの
summary(res)
## がく長 がく幅 花びら長 花びら幅 種類
## Min. :6.00 Min. :2.200 Min. :4.000 Min. :1.000 setosa : 0
## 1st Qu.:6.30 1st Qu.:2.800 1st Qu.:4.700 1st Qu.:1.500 versicolor:24
## Median :6.50 Median :3.000 Median :5.200 Median :1.800 virginica :43
## Mean :6.61 Mean :2.966 Mean :5.263 Mean :1.816
## 3rd Qu.:6.85 3rd Qu.:3.150 3rd Qu.:5.700 3rd Qu.:2.100
## Max. :7.90 Max. :3.800 Max. :6.900 Max. :2.500
res <- filter(data_iris, がく長>=5 & がく長<6.5) # 5<=がく長<6.5
summary(res)
## がく長 がく幅 花びら長 花びら幅
## Min. :5.000 Min. :2.000 Min. :1.200 Min. :0.100
## 1st Qu.:5.300 1st Qu.:2.700 1st Qu.:1.600 1st Qu.:0.400
## Median :5.700 Median :3.000 Median :4.100 Median :1.300
## Mean :5.691 Mean :3.047 Mean :3.577 Mean :1.133
## 3rd Qu.:6.100 3rd Qu.:3.400 3rd Qu.:4.800 3rd Qu.:1.600
## Max. :6.400 Max. :4.400 Max. :6.000 Max. :2.500
## 種類
## setosa :30
## versicolor:40
## virginica :23
##
##
##
res <- filter(data_iris, がく長<5 | がく長>=6.5) # がく長<5, 6.5<=学長
summary(res)
## がく長 がく幅 花びら長 花びら幅
## Min. :4.300 Min. :2.300 Min. :1.000 Min. :0.100
## 1st Qu.:4.800 1st Qu.:3.000 1st Qu.:1.500 1st Qu.:0.200
## Median :6.600 Median :3.100 Median :4.800 Median :1.500
## Mean :6.091 Mean :3.074 Mean :4.053 Mean :1.307
## 3rd Qu.:6.900 3rd Qu.:3.200 3rd Qu.:5.800 3rd Qu.:2.100
## Max. :7.900 Max. :3.800 Max. :6.900 Max. :2.500
## 種類
## setosa :20
## versicolor:10
## virginica :27
##
##
##
抽出したデータのある列だけが必要だという場合には,抽出したデータを収めたオブジェクトにに$
や[]
をつけて指定すればよい.以下では内容を確認するため,head()
関数を使って最初の数行だけを表示させている.
res <- filter(data_iris, がく長>=6 | 花びら長>1.5)
res<- res$花びら長
head(res)
## [1] 1.7 1.6 1.7 1.7 1.7 1.9
res <- filter(data_iris, がく長>=6 | 花びら長>1.5)
res<- res["花びら長"]
head(res)
## 花びら長
## 1 1.7
## 2 1.6
## 3 1.7
## 4 1.7
## 5 1.7
## 6 1.9
#次のように関数に対して直接[]や$を書くこともできる
res2 <- filter(data_iris, がく長>=6 | 花びら長>1.5)$花びら長
head(res2)
## [1] 1.7 1.6 1.7 1.7 1.7 1.9
res2 <- filter(data_iris, がく長>=6 | 花びら長>1.5)["花びら長"]
head(res2)
## 花びら長
## 1 1.7
## 2 1.6
## 3 1.7
## 4 1.7
## 5 1.7
## 6 1.9
#複数の列を取り出す場合には[c()]を使う
res3 <- filter(data_iris, がく長>=6 | 花びら長>1.5)[c("花びら長","花びら幅")]
head(res3)
## 花びら長 花びら幅
## 1 1.7 0.4
## 2 1.6 0.2
## 3 1.7 0.3
## 4 1.7 0.2
## 5 1.7 0.5
## 6 1.9 0.2
$
と[]
とで出力が違うのはこちらで説明したように,$
は指定した列をベクトルとして取り出すのに対して,[]
は指定した列だけで構成されるデータフレームとして取り出されるためである.
数値の置換にはifelse()
関数を応用する.ifelse()
関数は,第1引数に条件を記述し(条件の記述方法は検索と同じ),第2引数には条件にマッチした場合に置き換える値,第3引数にはマッチしなかった場合に置き換える値を記載する(Excelのif()
関数と同じ引数構造である).ifelse()
関数の実行結果として最終的に返ってくるのは,そうした置き換えが行われたベクトルとなる.あくまでベクトルが返ってくるだけなので,実際に置き換えをデータに反映させるためには,元のデータの元の列に返ってきたベクトルを代入するなり,元のデータに新しい列を作ってベクトルを代入するなりする必要がある.
「値」と記載しているが,コンピュータの用語として「値」という場合には,数値だけでなく文字列も含められていることは覚えておこう.数値だけをいう場合には「数値」,文字列だけを言う場合には「文字列」とはっきりと言わなければならない.
以下の例ではがく長が平均以上なら1,未満なら0を割り当てた新しい変数bがく長
を作成している.
data_iris2 <- data_iris
data_iris2$bがく長 <- ifelse(data_iris2$がく長 >= mean(data_iris2$がく長), 1, 0)
print(data_iris2$bがく長)
## [1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
## [38] 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 0 1 0 1 0 0 1 1 1 0 1 0 0 1 0 1 1 1 1
## [75] 1 1 1 1 1 0 0 0 0 1 0 1 1 1 0 0 0 1 0 0 0 0 0 1 0 0 1 0 1 1 1 1 0 1 1 1 1
## [112] 1 1 0 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1
## [149] 1 1
ついでにas.factor()
を用いて要因型に変換をしてみた.
data_iris2$bがく長 <- as.factor(data_iris2$bがく長)
summary(data_iris2)
## がく長 がく幅 花びら長 花びら幅
## Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100
## 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300
## Median :5.800 Median :3.000 Median :4.350 Median :1.300
## Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199
## 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800
## Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500
## 種類 bがく長
## setosa :50 0:80
## versicolor:50 1:70
## virginica :50
##
##
##
ifelse()
関数は入れ子にすることもできる.すなわち,
ifelse(<<条件>>, <<条件が真の場合の処理>>,
ifelse(<<条件2>>, <<条件2が真の場合の処理>>, <<条件2が偽の場合の処理)
)
という書き方ができる.
以下の例では,入れ子を用いてがく長を以下の4段階に分けてたものをbがく長
に格納している.
data_iris2 <- data_iris
M <- mean(data_iris2$がく長)
SD <-sd(data_iris2$がく長)
data_iris2$bがく長 <- ifelse(data_iris2$がく長 < M-SD,0,
ifelse(data_iris2$花びら長 <M,1,
ifelse(data_iris2$花びら長 < M+SD,2,3)
)
)
print(data_iris2$bがく長)
## [1] 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 0 1 0 0 0 1 1 0 0 1 1 1 0 0 1
## [38] 0 0 1 0 0 0 0 1 0 1 0 1 0 1 1 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
## [75] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 2 1 2 1 1 2 0 2 1 2 1
## [112] 1 1 1 1 1 1 3 3 1 1 1 3 1 1 2 1 1 1 1 2 2 1 1 1 2 1 1 1 1 1 1 1 2 1 1 1 1
## [149] 1 1
data_iris2$bがく長 <- as.factor(data_iris2$bがく長)
summary(data_iris2)
## がく長 がく幅 花びら長 花びら幅
## Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100
## 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300
## Median :5.800 Median :3.000 Median :4.350 Median :1.300
## Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199
## 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800
## Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500
## 種類 bがく長
## setosa :50 0: 32
## versicolor:50 1:105
## virginica :50 2: 10
## 3: 3
##
##
なお,上記では分かりやすさのため,入れ子となっている箇所で改行をしているが,別に改行しなくてもよい.以下は改行せずに書いた例.上記と同じ結果を返す.
data_iris2$bがく長 <- ifelse(data_iris2$がく長<M-SD, 0, ifelse(data_iris2$花びら長<M, 1, ifelse(data_iris2$花びら長<M+SD, 2, 3)))
print(data_iris2$bがく長)
## [1] 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 0 1 0 0 0 1 1 0 0 1 1 1 0 0 1
## [38] 0 0 1 0 0 0 0 1 0 1 0 1 0 1 1 1 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1
## [75] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 2 1 2 1 1 2 0 2 1 2 1
## [112] 1 1 1 1 1 1 3 3 1 1 1 3 1 1 2 1 1 1 1 2 2 1 1 1 2 1 1 1 1 1 1 1 2 1 1 1 1
## [149] 1 1
data_iris2$bがく長 <- as.factor(data_iris2$bがく長)
summary(data_iris2)
## がく長 がく幅 花びら長 花びら幅
## Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100
## 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300
## Median :5.800 Median :3.000 Median :4.350 Median :1.300
## Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199
## 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800
## Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500
## 種類 bがく長
## setosa :50 0: 32
## versicolor:50 1:105
## virginica :50 2: 10
## 3: 3
##
##
ifelse()関数は第2,第3引数はそれぞれ第1引数で指定した条件が真であった場合に返す値,偽であった場合に返す値を設定しているが,この部分に式や関数を指定しても良い.先のifelse()の入れ子はまさに関数の1つとしてのifelse()を実行している例だが,例えば,以下のようにすることもできる.
M<-mean(data_iris2$がく長)
SD<-sd(data_iris2$がく長)
data_iris2$がく長r <- ifelse(data_iris2$がく長<M-SD, M-SD, ifelse(data_iris2$花びら長>=M+SD, M+SD, M))
print(data_iris2$がく長r)
## [1] 5.843333 5.015267 5.015267 5.015267 5.015267 5.843333 5.015267 5.015267
## [9] 5.015267 5.015267 5.843333 5.015267 5.015267 5.015267 5.843333 5.843333
## [17] 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333 5.015267 5.843333
## [25] 5.015267 5.015267 5.015267 5.843333 5.843333 5.015267 5.015267 5.843333
## [33] 5.843333 5.843333 5.015267 5.015267 5.843333 5.015267 5.015267 5.843333
## [41] 5.015267 5.015267 5.015267 5.015267 5.843333 5.015267 5.843333 5.015267
## [49] 5.843333 5.015267 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333
## [57] 5.843333 5.015267 5.843333 5.843333 5.015267 5.843333 5.843333 5.843333
## [65] 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333
## [73] 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333
## [81] 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333
## [89] 5.843333 5.843333 5.843333 5.843333 5.843333 5.015267 5.843333 5.843333
## [97] 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333
## [105] 5.843333 5.843333 5.015267 5.843333 5.843333 5.843333 5.843333 5.843333
## [113] 5.843333 5.843333 5.843333 5.843333 5.843333 6.671399 6.671399 5.843333
## [121] 5.843333 5.843333 6.671399 5.843333 5.843333 5.843333 5.843333 5.843333
## [129] 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333
## [137] 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333
## [145] 5.843333 5.843333 5.843333 5.843333 5.843333 5.843333
この例では,がく長が平均-標準偏差未満のものは,すべて平均-標準偏差=5.0152672に,平均+標準偏差以上のものは,すべて平均+標準偏差=6.6713995に,平均-標準偏差から平均+標準偏差の間にあるものは全て平均=5.8433333に置き換えられる
文字列型の列や要因型の列を置換したい場合にはifelse()
関数を使うよりも,recode()
関数を使うほうが簡単である.
第1引数には,変換したいベクトル,第2引数以降には,置換内容を記述していく.置換内容が指定されていないものは元の値が維持される.以下の例では,setosa
をセトサ
に,versicolor
をバーシカラー
に置換している.
data_iris2 <- data_iris
data_iris2$種類 <- recode(data_iris2$種類, "setosa"="セトサ", "versicolor"="バーシカラー")
print(data_iris2$種類)
## [1] セトサ セトサ セトサ セトサ セトサ
## [6] セトサ セトサ セトサ セトサ セトサ
## [11] セトサ セトサ セトサ セトサ セトサ
## [16] セトサ セトサ セトサ セトサ セトサ
## [21] セトサ セトサ セトサ セトサ セトサ
## [26] セトサ セトサ セトサ セトサ セトサ
## [31] セトサ セトサ セトサ セトサ セトサ
## [36] セトサ セトサ セトサ セトサ セトサ
## [41] セトサ セトサ セトサ セトサ セトサ
## [46] セトサ セトサ セトサ セトサ セトサ
## [51] バーシカラー バーシカラー バーシカラー バーシカラー バーシカラー
## [56] バーシカラー バーシカラー バーシカラー バーシカラー バーシカラー
## [61] バーシカラー バーシカラー バーシカラー バーシカラー バーシカラー
## [66] バーシカラー バーシカラー バーシカラー バーシカラー バーシカラー
## [71] バーシカラー バーシカラー バーシカラー バーシカラー バーシカラー
## [76] バーシカラー バーシカラー バーシカラー バーシカラー バーシカラー
## [81] バーシカラー バーシカラー バーシカラー バーシカラー バーシカラー
## [86] バーシカラー バーシカラー バーシカラー バーシカラー バーシカラー
## [91] バーシカラー バーシカラー バーシカラー バーシカラー バーシカラー
## [96] バーシカラー バーシカラー バーシカラー バーシカラー バーシカラー
## [101] virginica virginica virginica virginica virginica
## [106] virginica virginica virginica virginica virginica
## [111] virginica virginica virginica virginica virginica
## [116] virginica virginica virginica virginica virginica
## [121] virginica virginica virginica virginica virginica
## [126] virginica virginica virginica virginica virginica
## [131] virginica virginica virginica virginica virginica
## [136] virginica virginica virginica virginica virginica
## [141] virginica virginica virginica virginica virginica
## [146] virginica virginica virginica virginica virginica
## Levels: セトサ バーシカラー virginica
上記の例では文字列を文字列で置換しているので,=
の前後はすべて""
で括っているが,数値に置換する場合には当然ながら""
は不要である.ただし,この場合,置換内容が指定されていなかったものはNA
として処理されるので注意が必要である.
data_iris2 <- data_iris
data_iris2$種類 <- recode(data_iris2$種類, "setosa"=1, "versicolor"=2) # virginicaは置換されないのでNAになる
print(data_iris2$種類)
## [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [26] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [51] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
## [76] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
## [101] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
## [126] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
ifelse()
を使った文字列置換
文字列の変換にifelse()
関数を使うこともできるが,列が要因型の場合には,一旦文字列型に変換してからでないと,思ったような結果とならない場合がある.例えば,以下の例ではsetosa
だけをセトサ
に置き換えたいと思って実行したのにもかかわらず,列が要因型ではなく勝手に文字列型にされ,さらに,他のもの種類名も勝手に2
や3
に設定されてしまっているのがわかる.
data_iris2 <- data_iris
data_iris2$種類 <- ifelse(data_iris2$種類=="setosa", "セトサ", data_iris2$種類 )
summary(data_iris2$種類) #サマリー表示 classがCharacter(文字列型)となっている
data_iris2$種類 #中身を確認してみる
## Length Class Mode
## 150 character character
## [1] "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ"
## [9] "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ"
## [17] "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ"
## [25] "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ"
## [33] "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ"
## [41] "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ" "セトサ"
## [49] "セトサ" "セトサ" "2" "2" "2" "2" "2" "2"
## [57] "2" "2" "2" "2" "2" "2" "2" "2"
## [65] "2" "2" "2" "2" "2" "2" "2" "2"
## [73] "2" "2" "2" "2" "2" "2" "2" "2"
## [81] "2" "2" "2" "2" "2" "2" "2" "2"
## [89] "2" "2" "2" "2" "2" "2" "2" "2"
## [97] "2" "2" "2" "2" "3" "3" "3" "3"
## [105] "3" "3" "3" "3" "3" "3" "3" "3"
## [113] "3" "3" "3" "3" "3" "3" "3" "3"
## [121] "3" "3" "3" "3" "3" "3" "3" "3"
## [129] "3" "3" "3" "3" "3" "3" "3" "3"
## [137] "3" "3" "3" "3" "3" "3" "3" "3"
## [145] "3" "3" "3" "3" "3" "3"
意図した通りのことをしたいならば,以下のようになる.つまり,一旦,文字列型に戻した後に,ifelse()
で置換を行ない,再度要因型に変換している.
data_iris2 <- data_iris
data_iris2$種類 <- as.character(data_iris2$種類) #要因型から文字列型に変換
data_iris2$種類 <- ifelse(data_iris2$種類=="setosa", "セトサ", data_iris2$種類 )
data_iris2$種類 #中身を確認してみる
summary(data_iris2$種類) #サマリー表示
data_iris2$種類 <- as.factor(data_iris2$種類) #文字列型から要因型に変換
summary(data_iris2$種類) #サマリー表示 要因型に変換したので表示が変わる
## [1] "セトサ" "セトサ" "セトサ" "セトサ" "セトサ"
## [6] "セトサ" "セトサ" "セトサ" "セトサ" "セトサ"
## [11] "セトサ" "セトサ" "セトサ" "セトサ" "セトサ"
## [16] "セトサ" "セトサ" "セトサ" "セトサ" "セトサ"
## [21] "セトサ" "セトサ" "セトサ" "セトサ" "セトサ"
## [26] "セトサ" "セトサ" "セトサ" "セトサ" "セトサ"
## [31] "セトサ" "セトサ" "セトサ" "セトサ" "セトサ"
## [36] "セトサ" "セトサ" "セトサ" "セトサ" "セトサ"
## [41] "セトサ" "セトサ" "セトサ" "セトサ" "セトサ"
## [46] "セトサ" "セトサ" "セトサ" "セトサ" "セトサ"
## [51] "versicolor" "versicolor" "versicolor" "versicolor" "versicolor"
## [56] "versicolor" "versicolor" "versicolor" "versicolor" "versicolor"
## [61] "versicolor" "versicolor" "versicolor" "versicolor" "versicolor"
## [66] "versicolor" "versicolor" "versicolor" "versicolor" "versicolor"
## [71] "versicolor" "versicolor" "versicolor" "versicolor" "versicolor"
## [76] "versicolor" "versicolor" "versicolor" "versicolor" "versicolor"
## [81] "versicolor" "versicolor" "versicolor" "versicolor" "versicolor"
## [86] "versicolor" "versicolor" "versicolor" "versicolor" "versicolor"
## [91] "versicolor" "versicolor" "versicolor" "versicolor" "versicolor"
## [96] "versicolor" "versicolor" "versicolor" "versicolor" "versicolor"
## [101] "virginica" "virginica" "virginica" "virginica" "virginica"
## [106] "virginica" "virginica" "virginica" "virginica" "virginica"
## [111] "virginica" "virginica" "virginica" "virginica" "virginica"
## [116] "virginica" "virginica" "virginica" "virginica" "virginica"
## [121] "virginica" "virginica" "virginica" "virginica" "virginica"
## [126] "virginica" "virginica" "virginica" "virginica" "virginica"
## [131] "virginica" "virginica" "virginica" "virginica" "virginica"
## [136] "virginica" "virginica" "virginica" "virginica" "virginica"
## [141] "virginica" "virginica" "virginica" "virginica" "virginica"
## [146] "virginica" "virginica" "virginica" "virginica" "virginica"
## Length Class Mode
## 150 character character
## versicolor virginica セトサ
## 50 50 50
実験や調査を行った際にデータの一部が欠損しているケースは多々ある.Rでは欠損データはデータフレーム上でNA
(Not
Available:利用不可能の意味)と表記されている.
関数によっては欠損データを含んでいるデータを受け付けないケースがある.例えばすでに平均値で紹介したようにmean()
関数は,そのままでは欠損値を含んだデータは受け付けない.
mean()
関数では,関数の引数でna.rm = T
を設定しておくと関数処理の中でNA
を除いて処理してくれるが,そもそも与えるデータそのものでNA
を除いておくほうが望ましい.
例えば,次のようなデータを処理するケースを考えよう.これはAからFまでの6人に対して10問セットの2種類のクイズを解いてもらった時のスコアである.ただ,1つめのデータセットではDさんのデータが,2つめのデータではEさんのデータが欠損してしまっている.このスコアをもとに,どちらのデータセットが難しいデータだったのかを比べたい.そこで,それぞれの平均や標準偏差を求めてみた.欠損データを含んでいるのでna.rm=T
を設定した.さて,このやり方は正しいだろうか.
data_iris3 <- data.frame(
name = c("A", "B", "C", "D", "E", "F"),
score1 = c(9,8,9,NA,6,7),
score2 = c(8,7,8,10,NA,7)
)
mean(data_iris3$score1, na.rm=T)
## [1] 7.8
sd(data_iris3$score1, na.rm=T)
## [1] 1.30384
mean(data_iris3$score2, na.rm=T)
## [1] 8
sd(data_iris3$score2, na.rm=T)
## [1] 1.224745
このデータの場合,平均や標準偏差を単純比較してはまずい.理由としてscore1
ではD以外のデータが使われているのに対して,score2
ではE以外のデータが使われているからである.すなわち,それぞれを計算するときに使われたデータが異なっているからである.もしDさんがクイズがすごく得意な人であったならば,Dさんのデータが入っていないscore1
の方は,不当に低くくなってしまっているであろうし,逆にEさんがクイズが苦手な人であったならば,Eさんのデータが入っていないscore2
の方は不当に高くなっている可能性がある.
データを比較するときには,比較しようとしている項目以外で結果に影響を与えると考えられる項目(条件)は同一条件となっている,ということが大前提である.したがって,上記のようなデータを比較するときには,2種類のクイズのデータが両方ともそろっているA,B,C,Fの4人のデータだけで比較するべきである.
このように,データの一部に欠損値を含んでいるよな観測をすべて除外して,すべての変数でデータがそろっているものだけを残すには,na.omit()
関数を用いる.
data_iris3.naomit <- na.omit(data_iris3)
data_iris3.naomit
## name score1 score2
## 1 A 9 8
## 2 B 8 7
## 3 C 9 8
## 6 F 7 7
mean(data_iris3.naomit$score1)
## [1] 8.25
sd(data_iris3.naomit$score1)
## [1] 0.9574271
mean(data_iris3.naomit$score2)
## [1] 7.5
sd(data_iris3.naomit$score2)
## [1] 0.5773503
こうした欠損値は特に任意回答の項目を入れているアンケート調査では間違いなく含まれてくるし,紙でとったアンケート調査においては無回答であったり,択一回答の質問なのに勝手に2つ以上の選ぶなど不正回答をしてくるケースも多々ある.そういう場合にはデータ上はNA
として処理すべきデータとなる.そのような形でNA
を含んだデータではデータを読み込んだ時点で上記の通りにna.omit()
を実施しておくとよい.
例えば,ある中学校のあるクラス(25人)での1年間の定期テストでの数学の得点をデータとして扱う事例を考えてみよう.
人がそのようなデータを扱うときには以下のような表を作るだろう.
学生番号 | 前期中間 | 前期期末 | 後期中間 | 後期期末 |
---|---|---|---|---|
1 | 75 | 94 | 89 | 65 |
2 | 60 | 81 | 70 | 95 |
3 | 68 | 84 | 65 | 70 |
4 | 99 | 78 | 80 | 88 |
5 | 73 | 59 | 85 | 64 |
・・・ | ・・・ | ・・・ | ・・・ | ・・・ |
24 | 85 | 62 | 75 | 88 |
25 | 72 | 77 | 87 | 92 |
このようなデータの並べ方を「ワイド形式」と呼ぶ.ワイド形式は一般に人がみてわかりやすい表形式となる. それに対して,Rで扱う表は以下のような並べ方のデータを並べている方が扱いやすい.このような並べ方を「ロング形式」と呼ぶ.
データNo. | 生徒番号 | 時期 | 得点 |
---|---|---|---|
1 | 1 | 前期中間 | 75 |
2 | 1 | 前期期末 | 94 |
3 | 1 | 後期中間 | 89 |
4 | 1 | 後期期末 | 65 |
5 | 2 | 前期中間 | 60 |
6 | 2 | 前期期末 | 81 |
7 | 2 | 後期中間 | 70 |
8 | 2 | 後期期末 | 95 |
9 | 3 | 前期中間 | 68 |
10 | 3 | 前期期末 | 84 |
11 | 3 | 後期中間 | 65 |
12 | 3 | 後期期末 | 70 |
13 | 4 | 前期中間 | 99 |
・・・ | ・・・ | ・・・ | ・・・ |
92 | 23 | 後期期末 | 94 |
93 | 24 | 前期中間 | 85 |
94 | 24 | 前期期末 | 62 |
95 | 24 | 後期中間 | 75 |
96 | 24 | 後期期末 | 88 |
97 | 25 | 前期中間 | 72 |
98 | 25 | 前期期末 | 77 |
99 | 25 | 後期中間 | 87 |
100 | 25 | 後期期末 | 92 |
ワイド形式では列は測定された属性変数を属性値ごとに横に並べるのに対して,ロング形式では属性変数はあくまで一つの変数として1つの列にまとめられ縦方向に各属性値が記述されていくが異なる.
また,ワイド形式の場合,例えば,数学の得点を並べた表とは国語の得点を並べた表ば別個に作成する必要がある. 一方で,ロング形式の場合,数学の得点の列,国語の得点の列,というように並べて行けばよい.
データ処理という点では,人の目からはわかりづらいがロング形式のデータの方が,何が変数なのかが明確に分かるため,ロング形式のデータを作る習慣を持っておこう.
tidyverse
パッケージ(正確にはtidyr
パッケージ)ではワイド形式のデータをロング形式のデータに変換するpivot_longer()
関数が存在している.もし提供されたデータがワイド形式であった場合には,pivot_longer()
関数を用いればよい(もちろん,Excelで手作業で並べ変えを行っても構わない).
pivot_longer()関数の引数は以下のとおりである.
cols=
の形でワイド形式で列名になっている属性名を与える.names_to=
で第2引数で指定した属性名を収めた列に与える属性変数の名を与える.values_to=
でワイド形式での各値そのものの変数名を与える.以下に例を示す.
# ワイド形式のデータフレームを作成
wide_data <- data.frame(
id = 1:4,
性別=c("男性","女性","男性","女性"),
time1 = c(10, 20, 30, 40),
time2 = c(50, 60, 70, 80),
time3 = c(90, 100, 110,120)
)
# ワイド形式のデータを表示
print(wide_data)
## id 性別 time1 time2 time3
## 1 1 男性 10 50 90
## 2 2 女性 20 60 100
## 3 3 男性 30 70 110
## 4 4 女性 40 80 120
# ロング形式に変換
long_data <- pivot_longer(
wide_data,
cols=c("time1","time2","time3"),# cols=colnames(wide_data)[c(3:5)]でも可
names_to = "時期", #属性変数に与える列名(変数名)
values_to= "得点" #測定変数に与える列名
)
#ロング形式のデータを表示
print(long_data)
## # A tibble: 12 × 4
## id 性別 時期 得点
## <int> <chr> <chr> <dbl>
## 1 1 男性 time1 10
## 2 1 男性 time2 50
## 3 1 男性 time3 90
## 4 2 女性 time1 20
## 5 2 女性 time2 60
## 6 2 女性 time3 100
## 7 3 男性 time1 30
## 8 3 男性 time2 70
## 9 3 男性 time3 110
## 10 4 女性 time1 40
## 11 4 女性 time2 80
## 12 4 女性 time3 120
この例の「性別」列のように,pivot_longer()
関数実行時に特に何の指定もしなかった変数については,属性変数として,その列名がそのまま使われるとともに,各列に対して自動で適切な値が付与される.
pivot_longer()
の出力結果はdata.frame
型ではなくtibble
型となっている.tibble
はdata.frame
の上位互換のデータ型である.いくつかの違いがあるが,わかりやすい点としてはprint()
させたときに,列名に各列の型が表示される点が異なっている.基本的な使い方はdata.frame
と変わらないが,もしdata.frame
にしたければ,as.data.frmae()
関数を利用すればよい.
class(long_data)
## [1] "tbl_df" "tbl" "data.frame"
long_data <- as.data.frame(long_data)
class(long_data)
## [1] "data.frame"
次のデータを読み込み,以下の処理を行え.
M
を「男性」,F
を「女性」に置換し,再度sumary()関数を実施し,先の結果との違いを確認せよ.身長
の平均値と標準偏差,ならびに平均の95%信頼区間を求めよ.身長
が170㎝以上の人の数が何人か求めよ.次のデータは,調査協力者40名(男性19名,女性21名)に対して,食パンA, B, Cを試食し,風味の良さを10段階で回答してもらったデータである.以下の課題を行え.
今回用いた関数は以下の通りである.
colnames()
:データフレームの列名を取得する関数.これを左辺に<-
で新しい列名を収めたベクトルを与えることによって列名(変数名)を置換できる.
head()
:データフレームの先頭から指定した行数だけを表示する関数
filter()
:デーソースの行を抽出する関数
ifelse()
:条件分岐を行う関数 - 第1引数:条件式
TRUE
の場合の値もしくは式FALSE
の場合の値もしくは式recode()
:文字列や要因型の列を置換する関数
"置換前"="置換後"
)を,
で区切りながら順に記述する.na.omit()
:欠損データを除外する関数
pivot_longer()
:ワイド形式のデータをロング形式に変換する関数
cols=
でワイド形式で列名になっている属性値を与える.names_to=
で第2引数で指定した属性値を収めた列に与える属性変数の名を与える.values_to=
でワイド形式での各値そのものの変数名を与える.