Contenu connexe Similaire à dplyr と purrrを用いたデータハンドリング (20) dplyr と purrrを用いたデータハンドリング2. About Me
• 杣取 恵太(そまとり けいた)
• 専修⼤学⼤学院⽂学研究科⼼理学専攻 博⼠2年
• ⽇本学術振興会 特別研究員(DC1)
• 研究テーマ:
⎻ 恐怖条件づけの個⼈差
⎻ メタ認知の認知モデリング
• 趣味:
⎻ ⿇雀、ダーツ
21. ここまでの関数を使ってデータを整形してみる
outpatient_26 <- outpatient_26 %>%
fill(X1) %>% ## X1を前の値で埋める(男, 男, 男, ...となる) ---
slice(46:63) %>% ## 46-63⾏⽬を抜き出す ---
filter(X2 !="総数") %>% ## ”X2”列の値が”総数”以外の⾏を残す ---
filter(X2 !="(再掲)精神及び⾏動の障害") %>%
select(-3) %>% ## 3列⽬を削除 ---
select(-23:-26) %>%
## “X1”を”sex”に、”X2”を” disease_name”に ---
rename(sex=X1, disease_name=X2)
26. 最後に微調整する
## ”count”列の値が”-”になっていればNAに変換 ---
outpatient_26$count <- ifelse(outpatient_26$count=="-", NA,
outpatient_26$count)
## ”desease_name”列の各セルにあるスペースを削除 ---
outpatient_26$disease_name <- str_trim(outpatient_26$disease_name,
side="both")
## ”count”列の各セルを数値型にする ---
outpatient_26$count <- as.numeric(outpatient26_$count)
30. filter()でデータの抜き出し
## ” disease_name”列の値が統合失調症の⾏だけ取り出す ---
## ”count”列の値がNAの⾏は削除 ---
schizo <- outpatient_26 %>%
filter(disease_name == "統合失調症,
統合失調症型障害及び妄想性障害",
!is.na(count))
sex disease_name age count
… … … …
… 統合失調症 … NA
… 統合失調症 ... 1,5
… … … …
… 統合失調症 … 3.0
33. 年齢ごとに外来患者数をプロット
ggplot(data = schizo) +
geom_bar(aes(x=age,y=count),stat="identity") +
## Macの場合はフォント指定しないと⽂字化ける ---
theme_set(theme_gray(base_family="Hiragino Kaku Gothic Pro W3")) +
## グラフが浮くのを防ぐ ---
scale_y_continuous(expand = c(0,0))
38. 疾患ごとの平均外来患者数が知りたい
age count
気分障害 0歳 2.0
… 0歳 NA
気分障害 … NA
気分障害 90歳以上 0.5
気分障害 90歳以上 NA
統合失調症 0歳 0
統合失調症 0歳 0
… … NA
統合失調症 90歳以上 2.0
神経症性障害 0歳 1.4
神経腫性障害 0歳 …
mean
気分障害 2.0
統合失調症 1.2
神経症性障害 3
アルコール障害 0.5
その他 2
• 疾患ごとに平均外来患者数を算出して、
外来患者の多い疾患が知りたい
40. summarize()
## max_mean_minという変数にsummarize()の結果を保存 ---
temp <- outpatient_26 %>%
## ”count”列の値にmax()を適⽤した結果を”max”列に ---
summarize(max = max(count,na.rm=T),
## ”count”列の値にmean()を適⽤した結果を”mean”列に ---
mean = mean(count,na.rm=T),
## ”count”列の値にmin()を適⽤した結果を”min”列に ---
min = min(count,na.rm=T))
## na.rm=Tは「NAを無視して関数を適⽤してね」という意味 ---
43. group_by() & summarize()
temp <- outpatient_26 %>%
## “desease_name”列の値ごとにgroup化 ---
group_by(desease_name) %>%
## グループごとに、” count”列の値について平均&標準偏差を算出 ---
summarize(mean = mean(count, na.rm = T),
sd = sd(count, na.rm = T))
グループの情報は⽬に⾒えない形で存在し、
以降の関数適⽤では常に考慮される
→ ungroup()でグループ化解除
50. 標準化得点算出して結合する
## 全体の平均と標準偏差を出す ---
temp <- outpatient_26 %>%
summarize(mean = mean(count, na.rm = T),
sd = sd(count, na.rm = T))
## (“count”列の値ー平均)/標準偏差をすることで、標準化 ---
## 標準化得点を新しい列として結合 ---
temp <- outpatient_26 %>%
mutate(stan_score = (count - temp$mean)/temp$sd)
sex desease_name age count sex desease_name age count stan_score
51. 改めて平均・標準偏差とエラーバーの上限・下限を計算
temp <- temp %>%
## 疾患ごと、性別ごとにグループ化 ---
group_by(disease_name, sex) %>%
## グループごとに”stan_socre”列の平均と標準偏差を算出 ---
summarize(mean = mean(stan_score, na.rm = T),
sd = sd(stan_score, na.rm = T)) %>%
## 上限を平均+標準偏差、下限を平均-標準偏差として計算し、 ---
## 新しい列として結合 ---
mutate(upper = mean + sd,
lower = mean - sd)
56. 演算⼦のバリエーション
• A > B: AはBより⼤きい
• A >= B: AはBと等しいかそれより⼤きい
• A <= B: AはBと等しいかそれより⼩さい
• A != B: AはBと等しくない
• A == B: AとBは等しい
59. Data Transformation with dplyr.
• コア関数
⎻ slice(): ⾏抽出
⎻ filter(): (列の値で)⾏抽出
⎻ select(): 列抽出
⎻ arrange(): 並び替え
⎻ summarize(): 関数の⼀括適⽤
データの整形、加⼯を効率良くやる関数が豊富
他にも、distinct(), sample_flac(), count...etc
Rstudioチーとシート(https://www.rstudio.com/resources/cheatsheets/)
64. Left join
x
ID value
1 x1
2 x2
3 x3
y
ID value
1 y1
2 y2
4 y4
x_y
ID value_x value_y
1 x1 y1
2 x2 y2
3 x3 NA
ID3: データフレームxにはあるがyにはない ⇨ ⽋測
ID4: データフレームyにはあるがxにはない ⇨ 無視
左のデータセットにある値を紐付けKeyとして、右の
データセットをくっつける。
65. x
ID value
1 x1
2 x2
3 x3
y
ID value
1 y1
2 y2
4 y4
x_y
ID value_x value_y
1 x1 y1
2 x2 y2
4 NA y4
ID3: データフレームxにはあるがyにはない ⇨ 無視
ID4: データフレームyにはあるがxにはない ⇨ ⽋測
Right join
右のデータセットにある値を紐付けKeyとして、右の
データセットをくっつける。
66. Full join
x
ID value
1 x1
2 x2
3 x3
y
ID value
1 y1
2 y2
4 y4
x_y
ID value_x value_y
1 x1 y1
2 x2 y2
3 x3 NA
4 NA y4
対応しないデータは⽋測扱いで残す
結合するデータセットにあるすべての⾏を結合する
67. 平成20, 23, 26年度のデータを結合する
l これまで使ってきたデータ
平成26年度患者調査56: 精神科病院の推計患者数,年齢階級 × 性・疾病分類(精神及び⾏動の
障害) × ⼊院-外来別(https://www.e-
stat.go.jp/SG1/estat/GL08020103.do?_toGL08020103_&listID=000001141596&reques
tSender=dsearch)
l これから結合するデータ
⎻ 平成23年度患者調査56: 精神科病院の推計患者数,年齢階級 × 性・疾病分
類(精神及び⾏動の障害) × ⼊院-外来別(https://www.e-
stat.go.jp/SG1/estat/GL08020103.do?_toGL08020103_&listID=0000
01103073&requestSender=dsearch)
⎻ 平成20年度患者調査56: 精神科病院の推計患者数,年齢階級 × 性・疾病分
類(精神及び⾏動の障害) × ⼊院-外来別(https://www.e-
stat.go.jp/SG1/estat/GL08020103.do?_toGL08020103_&listID=0000
01060228&requestSender=dsearch)
68. ## by= が結合するためのkey ---
## disease_name, age, sexの値で結合する ---
join_data <- outpatient_26 %>%
inner_join(outpatient_23,
by = c(“disease_name” = "disease_name", "age” = "age", "sex” = "sex")) %>%
inner_join(outpatient_20,
by = c("disease_name” = "disease_name", "age” = "age", "sex” = "sex"))
Inner_join()
本来、紐付けKeyは1つで良いのに、なぜ複数設定するのか?
71. # outpatient20の⼀部の列を削除、countの列名を変更 ---
outpatient_20 <- outpatient_20 %>%
rename(year_20 = count)
# outpatient23の⼀部の列を削除、countの列名を変更 ---
outpatient_23 <- outpatient_23 %>%
rename(year_23 = count)
# outpatient26の⼀部の列を削除、countの列名を変更 ---
outpatient_26 <- outpatient_26 %>%
rename(year_26 = count)
各データセットの”count”列の名前を変更する
72. ## by= が結合するためのkey ---
## disease_name, age, sexの値で結合する ---
join_data <- outpatient_26 %>%
inner_join(outpatient_23,
by = c("disease_name" = "disease_name",
"age" = "age", "sex" = "sex")) %>%
inner_join(outpatient_20,by = c("disease_name" = "disease_name",
"age" = "age", "sex" = "sex")) %>%
gather(year_26:year_20, key = year, value = "count", na.rm=T)
改めてinner_join(): ついでにロングデータにしておく
77. コピペして書く
dep_20 <- join_data %>%
filter(disease_name == "気分[感情]障害(躁うつ病を含む)",
year == "year_20") %>%
group_by(age) %>%
summarize(mean = mean(count, na.rm = T))
dep_23 <- join_data %>%
filter(disease_name == "気分[感情]障害(躁うつ病を含む)",
year == "year_23") %>%
group_by(age) %>%
summarize(mean = mean(count, na.rm = T))
dep_26 <- join_data %>%
filter(disease_name == "気分[感情]障害(躁うつ病を含む)",
year == "year_26") %>%
group_by(age) %>%
summarize(mean = mean(count, na.rm = T))
79. temp <- join_data %>%
group_by(disease_name, age, year) %>%
summarize(mean = mean(count, na.rm=T))
コピペをせずに、dplyrを駆使して⼀気にやる
3年分をまとめたデータについて、
疾患ごと、年齢ごと、年度ごとに男⼥の平均を算出する
各疾患の年齢別外来患者数が、調査
年度でどう変わるかしりたいなぁ
84. purrr:: map()
temp <- join_data %>%
## “disease_name”列と”year”列の値ごとにリスト型化する ---
## %>%を使うと、「.」で変数名を省略できる ---
split(list(.$disease_name, .$year)) %>%
## map(): リストに関数をまとめて適⽤する ---
## リスト内の各データを”age”列の値でグループ化 ---
map(group_by, age) %>%
## リスト内の各データについて、 ---
## グループごとに”count”列の平均を算出 ---
map(summarize, mean = mean(count, na.rm = T))
これでコピペの必要なし!
85. 例によって複雑なのでイメージ図
sex desease_name age count
split group_by
sex age count
$ 統合失調症
$ 気分障害
sex age count
sex age count
$ 統合失調症
$ 気分障害
sex age count
age mean
$ 統合失調症
$ 気分障害
summarize
age mean
90. 可視化したグラフもリストにいれたい
## 可視化のための関数を⾃作する ---
## 先ほどまで使っていたggplot()の関数をデータだけ⼊れれば描けるように関数化 ---
geo_hist <- function(data){
ggplot(data) +
geom_bar(aes(x = age, y = mean), stat = "identity") +
theme_set(theme_gray(base_family = "Hiragino Kaku Gothic Pro W3")) +
scale_y_continuous(expand = c(0,0))
}
temp <- join_data %>%
split(list(.$disease_name, .$year)) %>%
map(group_by, age) %>%
map(summarize, mean = mean(count, na.rm = T)) %>%
map(geo_hist) ## リスト内の各データに⾃作した関数を適⽤ ---
96. 疾患ごとに回帰式を当てはめる
outpatient_26 %>%
## 疾患ごとにリスト化する ---
split(.$disease_name) %>%
## 26年度の外来患者数を20年度の気分障害の外来患者数で回帰 ---
## lm()は回帰分析を⾏う関数 lm(従属変数 ~ 独⽴変数) ---
map(~lm(count ~ dep, data = .)) %>%
## 解析結果をまとめる ---
## 分散説明率や係数などを素敵なリストにまとめてくれる ---
map(summary) %>%
## まとめの中から、係数に関するところを抽出 ---
map("coefficients")
98. map()の仲間たち
返り値を調整する系
• map_lg() : factor型
• map_chr() : character型
• map_int() : integer型
• map_dbl() : double型
複数リストに適⽤する系
• map2() : 引数に2つのリスト
• map3() : 引数に3つのリスト
• map_n() : 引数に3つ以上のリスト
どれだけ複雑なデータセット
にも対応可能!