まず、データを取り込みましょう
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.2 ✔ readr 2.1.4
✔ forcats 1.0.0 ✔ stringr 1.5.0
✔ ggplot2 3.4.2 ✔ tibble 3.2.1
✔ lubridate 1.9.2 ✔ tidyr 1.3.0
✔ purrr 1.0.1
── 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
library(readxl)
dat <- read_excel("data/ifelse_casewhen.xlsx")
dat
# A tibble: 19 × 5
height weight bp alcohol smoking
<dbl> <chr> <chr> <dbl> <dbl>
1 176. 73.099999999999994 125/78 0 0
2 180 78 107/54 0 0
3 150. S6.7 126/81 0 1
4 156. 66.2 110/68 0 1
5 180. 61.6 110/66 0 0
6 174. 64.7 107/83 1 0
7 169. 64.400000000000006 113/71 1 0
8 172. 86.l 126/72 0 0
9 165. 69.7 137/85 1 0
10 168. 66.900000000000006 110/71 1 0
11 180. 88.8 109/65 0 0
12 184 61.6 153/87 1 1
13 179. 51.4 112/77 0 1
14 173. 69.2 119/81 0 0
15 154. 64.5 113/82 1 1
16 165. 87.1 125/76 1 1
17 159. 86.3 131/80 1 0
18 169. 61.1 121/75 0 0
19 164. 63.O 132/81 0 0
課題1:
身長と体重を利用して、BMIを計算してその結果をbmiという名前の列に保存してください。
まず、datのweight列が文字列型になっているので数字に変換してみましょう。
dat_weight <- dat %>%
select(weight) %>%
mutate(num_weight = as.numeric(weight))
Warning: There was 1 warning in `mutate()`.
ℹ In argument: `num_weight = as.numeric(weight)`.
Caused by warning:
! NAs introduced by coercion
ところどころ、欠損しています。
とりあえず、欠損している列のみを抜き出して眺めてみましょう。
欠損の有無は、is.na()関数というものを用います。
dat_weight %>%
filter(is.na(num_weight))
# A tibble: 3 × 2
weight num_weight
<chr> <dbl>
1 S6.7 NA
2 86.l NA
3 63.O NA
はい。ここは、意図的に入力ミスをいれています。
5でなくてS 1でなくてl 0でなくてOが使われています。
他のデータはすべて数字にNAになることなく変換できているので、とりあえず、上の3つを置き換えてから数値に変換しましょう。
dat1 <- dat %>%
mutate(
replace_weight = str_replace_all(weight,
c("S"="5",
"l"="1",
"O"="0"))
) %>%
mutate(num_weight = as.numeric(replace_weight))
View(dat1)
これで、無事、weight列が数字に変換されました。BMIを計算しましょう。
dat1 <- dat1 %>%
mutate(bmi = num_weight/(height/100)^2)
dat1$bmi
[1] 23.49201 24.07407 25.09950 27.06353 18.97017 21.29656 22.46839 29.06976
[9] 25.57047 23.59076 27.28600 18.19471 15.98831 23.09468 27.09118 32.07035
[17] 34.09341 21.36751 23.39502
Min. 1st Qu. Median Mean 3rd Qu. Max.
15.99 21.92 23.59 24.38 27.08 34.09
課題2:
bmi列の値を利用して、if_else関数を使って、BMIが25以上であれば1、25未満であれば0となる列、obese、を作成してください。
ここでif_else関数の動作を確認しておきます。
dat2 <- dat1 %>%
mutate(obese = if_else(bmi >= 25, 1, 0))
ここで作成した変数の分布を確認するためにはsummaryでもよいのですが、
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.0000 0.0000 0.0000 0.4211 1.0000 1.0000
数値型の場合は平均値等がでてきてしまい、個数がわかりません。個数を確認したい場合は、dplyr::count関数という便利な関数があります。
# A tibble: 2 × 2
obese n
<dbl> <int>
1 0 11
2 1 8
あるいは、base::tableも使いやすいです。
countは、パイプの中で変数名だけ書くような使い方ができますが、tableはベクトルを与えないといけないので注意が必要です
課題3:
血圧の表示が”120/80”のように入力されています。これを、sbpとdbpの二つの変数に分割してください。
[1] "125/78" "107/54" "126/81" "110/68" "110/66" "107/83" "113/71" "126/72"
[9] "137/85" "110/71"
このデータを分割するために、正規表現を利用してsbpとdbpを抜き出してみましょう。
dat3 <- dat2 %>%
mutate(
sbp = str_extract(bp,"^\\d+(?=/)"),
dbp = str_extract(bp,"(?<=/)\\d+$")
)
dat3 %>% select(ends_with("bp"))
# A tibble: 19 × 3
bp sbp dbp
<chr> <chr> <chr>
1 125/78 125 78
2 107/54 107 54
3 126/81 126 81
4 110/68 110 68
5 110/66 110 66
6 107/83 107 83
7 113/71 113 71
8 126/72 126 72
9 137/85 137 85
10 110/71 110 71
11 109/65 109 65
12 153/87 153 87
13 112/77 112 77
14 119/81 119 81
15 113/82 113 82
16 125/76 125 76
17 131/80 131 80
18 121/75 121 75
19 132/81 132 81
抜き出せましたね。文字列型になっているので数値型に戻しておきましょう
dat3 <- dat3 %>%
mutate(
sbp = as.numeric(sbp),
dbp = as.numeric(dbp)
)
課題4:
課題3で作成した変数、sbp、dbpを利用して、
sbpが120未満かつdbpが80未満であれば「至適血圧」 sbpが130未満かつ/あるいはdbp85未満であれば「正常血圧」 sbpが140未満かつ/あるいはdbp90未満であれば「正常高値血圧」 sbpが160未満かつ/あるいはdbp100未満であれば「1度高血圧」 sbpが180未満かつ/あるいはdbp110未満であれば「2度高血圧」 sbpが180以上かつ/あるいはdbp110以上であれば「3度高血圧」
とした因子型の列を作成してください。
ここではcase_whenを利用しましょう。だいぶ複雑です。かつ/あるいはを条件設定するのがややこしいので、収縮期、拡張期それぞれで判定してより重い方を採用する形にしました。
dat4 <- dat3 %>%
mutate(sbp_kubun = case_when(
sbp < 120 ~ 1,
sbp < 130 ~ 2,
sbp < 140 ~ 3,
sbp < 160 ~ 4,
sbp < 180 ~ 5,
sbp >= 180 ~ 6
)) %>%
mutate(dbp_kubun = case_when(
dbp < 80 ~ 1,
dbp < 85 ~ 2,
dbp < 90 ~ 3,
dbp < 100 ~ 4,
dbp < 110 ~ 5,
dbp >=110 ~ 6
))
count関数は2変数でも使えます。
dat4 %>%
count(sbp_kubun, dbp_kubun)
# A tibble: 7 × 3
sbp_kubun dbp_kubun n
<dbl> <dbl> <int>
1 1 1 7
2 1 2 3
3 2 1 4
4 2 2 1
5 3 2 2
6 3 3 1
7 4 3 1
このsbp_kubunとdbp_kubunの値で大きいほうを採用すれば良いので、if_elseを利用しましょう。
dat4 <- dat4 %>%
mutate(bp_kubun = if_else(
sbp_kubun >= dbp_kubun, sbp_kubun, dbp_kubun
))
dat4 %>%
count(bp_kubun, sbp_kubun, dbp_kubun)
# A tibble: 7 × 4
bp_kubun sbp_kubun dbp_kubun n
<dbl> <dbl> <dbl> <int>
1 1 1 1 7
2 2 1 2 3
3 2 2 1 4
4 2 2 2 1
5 3 3 2 2
6 3 3 3 1
7 4 4 3 1
きちんと狙った通りに分けられていますね?あとは、数値を因子型のラベルをあててあげれば完成です。
bplabel <- c("至適","正常","正常高値","1度","2度","3度")
dat4 <- dat4 %>%
mutate(bp_kubun = factor(bp_kubun, levels = 1:6, labels=bplabel))
dat4 %>% count(bp_kubun)
# A tibble: 4 × 2
bp_kubun n
<fct> <int>
1 至適 7
2 正常 8
3 正常高値 3
4 1度 1
できあがりです。
課題5:
課題1から課題4までで作成した変数を利用して、高血圧、肥満、飲酒、喫煙のリスクの個数を計算したriskという名前の列を作成してください。
(尚、ここでは、高血圧を1度から3度高血圧、肥満はBMI25以上とします)
血圧のカテゴリーが、0か1になっていないためこれを変換しておきましょう。
# A tibble: 4 × 2
bp_kubun n
<fct> <int>
1 至適 7
2 正常 8
3 正常高値 3
4 1度 1
dat5 <- dat4 %>%
mutate(risk_bp = if_else(as.numeric(bp_kubun) >= 4, 1, 0))
dat5 %>% count(risk_bp, bp_kubun)
# A tibble: 4 × 3
risk_bp bp_kubun n
<dbl> <fct> <int>
1 0 至適 7
2 0 正常 8
3 0 正常高値 3
4 1 1度 1
ちゃんと0と1で分けられていますね?後は、リスクの個数を足し合わせるだけです。一応、データを確認しておくと、
dat5 %>%
count(obese, risk_bp, alcohol, smoking)
# A tibble: 8 × 5
obese risk_bp alcohol smoking n
<dbl> <dbl> <dbl> <dbl> <int>
1 0 0 0 0 6
2 0 0 0 1 1
3 0 0 1 0 3
4 0 1 1 1 1
5 1 0 0 0 2
6 1 0 0 1 2
7 1 0 1 0 2
8 1 0 1 1 2
です。
risk列の作成は簡単ですね?
dat5 <- dat5 %>%
mutate(risk = obese + risk_bp + alcohol + smoking)
dat5 %>% count(risk)
# A tibble: 4 × 2
risk n
<dbl> <int>
1 0 6
2 1 6
3 2 4
4 3 3
以上です!
どうでしょうか? 相当ややこしく感じられたかもしれませんが、ここまで学んでいただいた関数のみで、ここまでデータの加工ができます。
次以降はこれらのデータの加工をより便利にしてくれる関数群を解説していきます。