今までRでデータの変数名を変更したり条件でグループ化したりしました。







そして前回の記事では集計して平均や標準偏差などの要約を出したり、グラフを作るためにgather関数を使ってlongデータを作りました。

【2-5】Rでデータを集計するのに便利なtidyデータとgather関数



今回は棒グラフや折れ線グラフ作成に必要な平均や標準偏差などの統計量を求めます。



データは前回と同じデータを使います。

FIM.xlsx

スクリーンショット 2019-02-19 22.25.41


ダウンロードした後、プロジェクトの指定フォルダにファイルを移動させておけば、以下のコマンドで前回最後の場面まで進みます。

library(tidyverse)
library(readxl)
fim <- read_excel("FIM.xlsx", sheet = "入院時")
fim_long <- fim %>% 
  gather(食事:FIM合計, key = 項目, value = 点数, factor_key = TRUE) 
head(fim_long)


1,groop_by関数でグループ化したい項目を指定する

ますグループ化するためにはgroop_by関数を使います。

group_by(データ,列名)

%>%を使うとデータの部分は省略できます。

fim_long %>% 
  group_by(項目) 

スクリーンショット 2019-02-21 21.42.39



何も変わってないように見えますが、薄い文字のところに# Groups:項目 [21]とあります。


ちなみにグループの種類が複数でも可能です。

fim_long %>% 
  group_by(項目,性別) 

スクリーンショット 2019-02-21 21.45.43



2.列名の順番について

下の2つのコードはどういった違いがあるのでしょうか?

スクリーンショット 2019-02-22 0.15.27

表の並び順が違うだけでその後グラフを作るときには影響はないのですがイメージとしては上記のようになります。





3.統計量を出すsummarize関数


平均などの統計量などを出すにはsummarize関数を使います。

summarize(名前1 = 関数1, 名前2 = 関数2)

summarize関数の前にgroup_by関数を使っていると、グループごとの集計が出てきます。

fim_summarize <-  fim_long %>% 
  group_by(項目,性別) %>% 
  summarize(平均 = mean(点数), 
            標準偏差 = sd(点数), 
            最小値 = min(点数), 
            最大値 = max(点数))
fim_summarize

スクリーンショット 2019-02-22 0.49.09




もし保存したい場合はwrite.csv関数を使います。

wite.csv(保存する変数名, "ファイル名.csv")
ファイル名には" "と.csvを入れます

write.csv(fim_summarize,"FIM集計")
スクリーンショット 2019-02-22 0.57.54
右のfilesビューにFIM集計.csvができました。

csvファイルをExcelで読み込む時は【1-11】Rで医療統計で必要なtable1を作るtableoneパッケージについて紹介しますをご参照ください。

ポイントとしてはファイルの出力先を$A$1ではなく$B$1にしてください。
$A$1だとなぜかエラーが出ます。
スクリーンショット 2019-02-22 1.04.57

スクリーンショット 2019-02-22 1.07.22

Excelにするとわかるのですが、小数点10桁まで表示されます。
もし小数点第一位までの表示にしたい時はround関数を使います。

round(数値, x)
たとえばxが1だと小数点第二位を四捨五入して小数点第一位まで表示します。

fim_summarize <- fim_long %>%
group_by(項目,性別) %>%
summarize(平均 = round(mean(点数), 1),
   標準偏差 = round(sd(点数), 1),
   最小値 = min(点数),
   最大値 = max(点数))
fim_summarize
スクリーンショット 2019-02-22 1.18.28



4.summarize関数を使うときの注意点。

group_by関数の順番に影響する

2でも紹介しましたが、groop_by関数で指定したグループが複数の場合、summarize関数で表示される順番はgroop_by関数の影響を受けます。

スクリーンショット 2019-02-22 0.15.27

あとでExcelで並べ替えるのはただ面倒です。もしcsvで保存をする時は何を示したいかをあらかじめイメージしておくことが重要になります。



2.欠損地があるとNAとなる

平均を求めるmean関数などはどこか1つでも欠損値(空欄)があると結果はNAとなります。

氏名 <- c("A", "B", "C", "D")
年齢 <- c(55, 63, 67, 71)
test_1回目 <- c(1,2,3,NA)
test_2回目 <- c(5:8) test_3回目 <- c(9:12)
data <- data_frame(氏名, 年齢, test_1回目, test_2回目, test_3回目)
data data %>%
gather(3:5, key = 回数, value = 点数) %>%
group_by(回数) %>%
summarize(平均 = mean(点数))
スクリーンショット 2019-02-22 1.53.38


もし結果にNAが出た時はまずはそもそものデータの入れ損ねがないか確認をし対応します。

それでも欠損値がある時はNAを省いて計算する欠損値を統計の技術を使って代入するといった方法があります。

もし欠損値を省いて平均を出す場合はna.rm = TRUEを付け加えます。

data %>%
gather(3:5, key = 回数, value = 点数) %>%
group_by(回数) %>%
summarize(平均 = mean(点数, na.rm = TRUE))
スクリーンショット 2019-02-22 2.06.51


ただ実は欠損値を省いた方がいいのかどうかという問題があります。ただ業務で傾向を確認したいなどであれば欠損値を省いてもいいと思いますが、きちんと出さないと行けない場面ではこれはこれできちんと勉強する必要があります。欠測データに関しては医療統計の本では紹介されていない事が多く専門書が必要かもしれません。


欠測データ処理: Rによる単一代入法と多重代入法 (統計学One Point)



summarize関数に入れられる関数は単一の値が出るものに限る。

summarize関数で使える統計量はmean関数,sd関数,median関数など単一の値になります。

ただ、関数の中には最小値と最大値を一度に出してくれるrange関数など複数の値を出すものがあります。

test_2回目 <- c(5:8)
range(test_2回目)
スクリーンショット 2019-02-22 2.27.00


range関数をsummarize関数に入れようとするとエラーが出ます。

data %>% gather(3:5, key = 回数, value = 点数) %>% group_by(回数) %>% summarize(平均 = mean(点数, na.rm = TRUE), 範囲 = range(点数))

スクリーンショット 2019-02-22 2.36.38

「1つの値しか入れられないのに2つ入ってるよ!」と怒られています。

スクリーンショット 2019-02-22 2.41.49

特にあるのが四分位範囲です。
四分位範囲はquantile関数を使って以下のように一度に値を出すことができます。
quantile(fim$年齢, c(0.1, 0.25, 0.5, 0.75, 0.9))
スクリーンショット 2019-02-22 2.45.59


しかしsummarize関数ではまとめて入れられないので1つずつ入れる必要があります。
fim_summarize <- fim_long %>% group_by(項目,性別) %>% summarize(平均 = mean(点数), 標準偏差 = sd(点数), 最小値 = min(点数), percent_25 = quantile(点数, 0.25), 中央値 = median(点数), percent_75 = quantile(点数, 0.75), 最大値 = max(点数)) fim_summarize
スクリーンショット 2019-02-22 3.01.32



そもそもの列のfactorの順番があってるのか?

gather関数のkey列に関してはfactor_key=TRUEで五十音順ではなく、元の順番に戻すことができます。

しかし他の列でfactorの順番が合っていない可能性もあります。

もしほかの列でfactorの順番を合わせるにはmutate関数とfactor関数を組み合わせて使うことができます。

今回は女性と男性を入れ替えてみます。
fim_summarize <- fim_long %>%
mutate(性別 = factor(性別, levels = c("男性","女性"))) %>%
group_by(項目,性別) %>%
summarize(平均 = mean(点数),
     標準偏差 = sd(点数),
      最小値 = min(点数),
   percent_25 = quantile(点数, 0.25),
   中央値 = median(点数),
   percent_75 = quantile(点数, 0.75),
      最大値 = max(点数))
fim_summarize
スクリーンショット 2019-02-22 3.01.32


factor関数の使い方は【1-10】Rでよく使われる型について説明しますをご参照ください


まとめ

今回はgroup_by関数とsummarize関数と、実際に集計を出し保存するところまで紹介しました。

これでひとまず第2章で行う予定だった「データを集計しやすいように形を整え集計する」が終わりです。

スクリーンショット 2019-02-08 10.33.40


ただ今回は「できるだけExcelの時点でデータは編集しやすい形式で保存している」ことを前提に話を進めています。

もっと形が整っていないデータの扱いやここでは説明できなかった項目も多くあります。

もし「もっと知りたい」「ここの情報では足りない!」ということであれば下記のサイトなどもご参照ください。


データハンドリング入門
https://kazutan.github.io/kazutanR/hands_on_170730/index.html




今までRでデータの変数名を変更したり条件でグループ化したりしました。






ここからは集計して平均や標準偏差などの要約を出したり、グラフを作るための準備に進みます。


こういったグラフを作るにはもう1つ工夫が必要です。

それはwideデータをlongデータに変更することです。

今回はlongデータとwideデータの違いを知り、longデータに変換するgather関数を紹介します。




1.wideデータとlongデータ

wideデータというのは1つのid(たとえば患者氏名)に対してデータが横に並びます。

スクリーンショット 2019-02-20 0.03.06
これはまた別の架空のデータです。4人にあるテストを3回ずつ行った設定です。

データを入力したり人の目で見る時はwideデータがわかりやすいです。

ただ今後出てくるのですが、Rではグラフを作るときに「『回数』で色分けして!」とか「『回数』で別々のグラフを作って」みたいな指定ができます。そのためにはlongデータが便利になります。


2.gather関数とspread関数

スクリーンショット 2019-02-20 0.53.33

wideをlongに変えるのがgather関数で、longをwideに戻すのがspread関数です。

ここで大切になるのがkey = と value=です。

key = も valueもlongデータの変数名に当たる部分です。wideデータにはそれに当てはまる名前を入れる欄がなく、列を分けることで表示しています。



3.gather関数の使い方

gather(使うデータ名, くっつける列, key = 要素の変数名,value = テストの値)



スクリーンショット 2019-02-20 1.12.43


まずくっつける列を指定します。
くっつける列は列名でも列番号でもどちらでも構いません。

key = は「1回目、2回目、3回目」に当たる部分の列の名前です。
ここでは回数としました。

value = は実際のデータに当たるところの列の名前です。
ここでは点数としました。


library(tidyverse)
氏名 <- c("A", "B", "C", "D")
年齢 <- c(55, 63, 67, 71)
test_1回目 <- c(1:4)
test_2回目 <- c(5:8)
test_3回目 <- c(9:12)

data <- data_frame(氏名, 年齢, test_1回目, test_2回目, test_3回目)

data %>% 
  gather(3:5, key = 回数, value = 点数) 

スクリーンショット 2019-02-20 1.29.48

変数名の頭を数字にするとRに怒られますので、1回目とせずtest_1回目としています。

それと今回data.frame関数ではなくdata_frame関数を使っています。
どちらも基本的には変わりませんが、data_frame関数はtidyverseパッケージに含まれている関数で、プログラミング初心者であれば少し機能が高いものといった程度で構わないと思います。data.frameとしても大丈夫です。



4.spread関数の使い方

スクリーンショット 2019-02-20 1.26.47

spread関数はlongデータから戻します。

data %>%
gather(3:5, key = 回数, value = 点数) %>% 
  spread(key = 回数, value = 点数)
  スクリーンショット 2019-02-20 1.40.16


gather関数でlongデータにしたものをそのままspread関数でwideデータに戻しました。

そのためもとのdataに戻っています。


5.実際にやってみる

今回はExcelで架空のデータを作りました。

FIM.xlsx

スクリーンショット 2019-02-19 22.25.41


データには氏名・年齢・性別・時期とFIM(18項目の評価と運動項目合計、認知項目合計、全体の合計)が入っています。運動合計は1~13項目目の合計、認知は14~18項目目の合計、FIM合計は18項目の合計です。
そしてタブには「入院時・1ヶ月・退院時」というタブがあります。


ダウンロードした後、プロジェクトの指定フォルダにファイルを移動させておけば、以下のコマンドで上記の画面まで進みます。今回は入院時のデータのみ使います。

liburary(tidyverse)
library(readxl)
fim <- read_excel("FIM.xlsx", sheet = "入院時")
view(fim)


まずどんなデータか確認してみます。

head(fim)
str(fim)
スクリーンショット 2019-02-20 1.54.48

スクリーンショット 2019-02-20 1.55.46

100 obs. of  25 variablesと書いてあるので100人のデータで25列あるということです。

列が多いので、列番号も取得します。
列番号を取得する時はt関数とnames関数の組み合わせが便利です。
またはdata.frame関数とnames関数の組み合わせでもできます。

t(names(fim))
data.frame(names(fim))

スクリーンショット 2019-02-20 2.01.28


この中で5列目の「食事」から25列目の「FIM合計」まではいってしまえば全部FIMというテストの点数です。

なので、これを全部gather関数でまとめてlongデータに変えます。

ここではkeyを回数、valueを点数という列名にしました。好きな名前で構いません。
下の結果を見て、keyとvalueの関係を確認してみてください。

fim_long <- fim %>% 
  gather(食事:FIM合計, key = 項目, value = 点数) 

スクリーンショット 2019-02-20 23.00.29


氏名〜時期までは変わっていませんが、5列目〜25列目がなくなり、代わりに「項目」と「点数」という列ができています。

またA tibble: 2,100 x 6となっており、2100行×6列の表に変わりました。
だいぶ縦長に変わりました。


まとめ

今回はlongデータ、wideデータの説明とgather関数(spread関数も)を紹介しました。

まだこれだけではメリットがわからないと思います。

しかし次に行うgroup_by関数とsummarize関数を行う時やグラフを作る時にこの作業が大きな意味を持つことになります。

次回はこのデータを使って要約(グループごとの平均や標準偏差など)をしていきます。


追記

gather関数のkey = でつなげた要素は五十音順になっている


gather関数でlongデータにした場合、key =に当たる部分の要素はどうなっているのでしょうか?

class(fim_long$項目)
スクリーンショット 2019-02-20 23.30.38


項目は"character"(文字列)となっています。

そしてこのままグラフを作ると下の左の図のように並びが五十音順となります。
これでは困ります。できれば右図のようにもとの順で並べたいところです。

スクリーンショット 2019-02-20 22.22.01



gather関数にfactor_key = TRUEをつける


gather関数内でfactor_key = TRUEを加えるとkeyの列をfactor型にし、順番も元の順番になります。
https://tidyr.tidyverse.org/reference/gather.html より

fim_long <- fim %>% 
  gather(食事:FIM合計, key = 項目, value = 点数, factor_key = TRUE) 
fim_long

class(fim_long$項目)
スクリーンショット 2019-02-21 1.27.33


こうすると集計やグラフ作成で順番が崩れずに表示することができます。

Rで集計やグラフ作成を行う場面は多くあります。

その際、元の表から分析に使いたい列や行だけを抽出したり、「男性だけを取り出す」みたいに様々な条件にあった行だけを抽出することが必要になります

今回はRで指定した列や行だけを取り出すselect関数、slice関数、filter関数を紹介します。
これらはtidyverseパッケージ内にあるdplyrパッケージの機能です。



今回使う架空のデータは前回と同じものを使用します。

年齢、性別、病名が入っています。
下のコードをまとめてスクリプトにコピペして実行してください。
library(tidyverse)
set.seed(1) 年齢 <- floor(rnorm(100,60,20)) 性別 <- sample(c("男性","女性"),100,replace = TRUE) 病名 <- sample(c("脳梗塞", "脳出血", "骨折", "靭帯損傷","心筋梗塞"), 100, replace = TRUE) data <- data.frame(年齢,性別,病名) head(data)

スクリーンショット 2019-02-10 22.48.49



1.指定した列を抽出するselect関数

select(データの変数名, 選択する列)

スクリーンショット 2019-02-13 20.15.20


select関数では縦の列を抽出します。

列名または列番号で選択します(" "をつけなくてOK)。

もしくは使わない列を選ぶこともできます。

そのため以下の3つのコードは全て同じ結果になります。
data_A <- data %>% 
  select(1,2)
head(data_A)

data_A <- data %>% 
  select(年齢,性別)
head(data_A)

data_A <- data %>% 
  select(1,性別)
head(data_A)

data_A <- data %>% select(-3) head(data_A)

列名で指定する場合は""で囲む必要はないですが、大文字や小文字など間違えないことが大切です。

また列番号の場合「何列目かなんてわからない…」ということもよくあります。

列名と列番号の一覧を知りたい時はt関数とnames関数を使うと便利です
t(names(data))
スクリーンショット 2019-02-13 20.28.22



応用編

応用①
もし列名が連番ならを使います。1番目〜5番目なら1:5と書きます。
select(1:5)

応用②
もっと選びたい列があって1番目と5番目〜10番目と13番目を使いたい場合は以下になります。
select(1, 5:10, 13)

応用③

インデックスという考え方で、選ぶ列番号を入れた変数を予め作成する方法があります。

data %>%
index <- c(1, 5:10, 13)
select(index)
スクリーンショット 2019-02-13 23.31.02


先にindexという変数名を作り、そこに指定する列を選びます。

Rを紹介する本やサイトではindexindという変数名で見かけることがありますが、もちろん好きな変数名で構いません。

indexの便利なところはindexを変えるだけで、本体のコードは1つも変わらないところにあります。

スクリーンショット 2019-02-13 21.08.16

このような考え方は色々な場面で使われます。

特に繰り返しの作業で効果を発揮します。



2.指定した行を抽出するslice関数

slice(データの変数名選択する列)

slice関数はselect関数の行バージョンです。

ただ条件で絞るのはslice関数でなく次に紹介するfilter関数になります。

silce関数は10万桁あって処理に時間かかるから、いきなり全部使わず1000行だけ切り取って、プログラムが動くかどうかテストしてみようみたいな場合に使えます。

他にも下のようなExcelをファイルを読み込むことになってしまい、1行目いらない!下の平均の行いらない!など切り取る列が決まってるときに使います。

スクリーンショット 2019-02-13 21.47.00

slice(2:7)はslice(-1,-8)でもOKです。



3.指定した条件を抽出するfilter関数

filter(データの変数名条件1,条件2)

filter関数は条件にあった行を抽出します。

data_B <- data %>% 
  filter(病名 %in% c("骨折", "靭帯損傷"))
head(data_B)
スクリーンショット 2019-02-13 21.45.33


前回の記事でも出ましたが、条件を付ける場合は演算子を使います。

スクリーンショット 2019-02-11 2.04.40
使い方に自身がない場合はRで数値を複数のカテゴリーに分類するifelse関数、case_when関数、cut関数を紹介しますをご参照ください。


複数の条件で絞る場合

filter関数で複数条件の場合は3つ方法があります。

, でつなぐ

filter関数はfilter(データの変数名条件1,条件2)という形式なので、カンマを使ってつなげることができます。

data_B <- data %>% 
  filter(病名 %in% c("骨折", "靭帯損傷") ,
         性別 == "女性" ,
         年齢 < 60)

%>%でつなぎ、filter関数を重ねる

filter関数は複数あって悪いことはないので、素直に%>%でつなげる方法ことも可能です。
メリットとしてはとりあえずわかりやすいのと、考えた順にコードを追加できるところでしょうか。

下のコードで①と同じ結果になります。
スクリーンショット 2019-02-13 21.56.55


&| で条件を付け加える

& や | でつなぐこともできます。演算子の前後に , は入れません。
今までの方法は全て「かつ」という意味でつないでいたので、「または」の意味でつなぎたい時は | でつなぎましょう。

これも①②と同じ結果になります。
スクリーンショット 2019-02-13 23.10.11



まとめ

今回はselect関数、slice関数、filter関数を紹介しました。

これらの関数は集計やグラフを作成するときによく使います。

今後も出てくる予定なのでわからなくなったら復習に使ってください。




↑このページのトップヘ