カテゴリ:統計 > R

データを扱う中で「外れ値を外す方法」に関して検討してみます。

apply関数の記事で以下のコメントがありました。




大変勉強になりました。
列ごとに、ファイルの値(NAがある)が2SDより高い値をNAにしたいです。
Data01 <-read_excel("raw.xlsx",1)
Data02 <-apply(Data01, 2, sd, na.rm = TRUE)
Data01[Data01 > 2*Data02]<- NA
以上のコードをして最後は列ごとにうまく出来なかったです。
ご提言があれば大変嬉しいです。

自分もそうですが、実際にやってみるとうまくいかないことってたくさんあります。
今回は質問を一緒に考えながらどう考えるか?どんな解決方法があるかを考えて、今までの理解を深めるきっかけになればと思います。

1.データの作成

コードを確認してみます。
Data01 <-read_excel("raw.xlsx",1)
これはraw.xlsxの1シート目を読み込むという意味なので、今回は仮のデータを作ります。

set.seed(2020)
a <- c(rnorm(998,10,1),NA,30)
b <- c(rnorm(998,20,1),NA,40)
c <- c(rnorm(998,30,1),NA,50)
Data01 <- data.frame(a,b,c)
head(Data01)
簡単に言うと以下のとおりです。
a : 平均10, 標準偏差1のデータ998個にNAと30を加えた1000個のデータ
b : 平均20, 標準偏差1のデータ998個にNAと40を加えた1000個のデータ
c : 平均30, 標準偏差1のデータ998個にNAと50を加えた1000個のデータ

スクリーンショット 2020-03-28 2.34.45
この赤色が2SDを超えたデータです。やりたいことはこの赤い点のデータを削除することです(これの是非については今回問いません)

2.apply関数のおさらい

次の行を確認します。
Data02 <-apply(Data01, 2, sd, na.rm = TRUE)
apply関数【2-1】Rのfor関数、apply関数を使ってまとめて標準偏差などの統計量を求める方法で紹介しました。下はイメージ図です。
スクリーンショット 2020-03-27 13.46.36
上図ではsd関数(標準偏差)を求めました。
また欠損値(NA)があるのでrm.na = TRUEをつけることでNAの値を外して計算してくれます。

スクリーンショット 2020-03-27 13.54.01
それぞれの列の標準偏差が表示されました。
ただ元データが2標準偏差を超えているかどうかを確認するにはこれだけでは足りません。


3.どう考えるか?
スクリーンショット 2020-03-28 4.00.30

それぞれのデータが2SDを超えているかどうかを判定する必要があります。
具体的には(平均-2SD) < それぞれの値 < (平均 + 2SD)の条件を満たしているかどうかとなります。

そのため以下の2つを行えばなんとかできそうです。
①a,b,cそれぞれの平均±2標準偏差の値を求める
②条件に合えばそのまま、条件にあわなければNAと変換する


 4.平均±2SDを求める

まずa,b,cの平均と標準偏差を求めます。
これには前述のapply関数かsummarize関数を使います。
まずはapply関数でやってみます。

Data01_mean <-apply(Data01, 2, mean, na.rm = TRUE)
Data01_sd <-apply(Data01, 2, sd, na.rm = TRUE)
Data01_mean
Data01_sd

low <- Data01_mean - 2*Data01_sd
high <- Data01_mean + 2*Data01_sd
low
high
スクリーンショット 2020-03-28 3.17.41

ここからlow[2]、もしくはlow["b"]とすればbの平均-2SDが取り出せます。
high[1]、もしくはhigh["a"]であればaの平均+2SDとなります。

5.条件に合わないものをNAにする

次に条件に合わないものを抽出しNAにします。
データを抽出するにはデータ[条件]を使います

(aのデータ < 平均-2sd) または (平均+2SD < aのデータ)だとこうなります
Data01$a[(Data01$a < low["a"]) | (high["a"] < Data01$a)]
スクリーンショット 2020-03-28 4.08.45

条件式の記号については以下をご参照ください。今回はまたはの意味の を使いました。
スクリーンショット 2019-02-11 2.04.40
抽出した条件に <- を使うことでデータを置き換えることができます。
Data02 <- Data01
Data02$a[(Data02$a < low["a"]) | (high["a"] < Data02$a)] <- NA
Data02$b[(Data02$b < low["b"]) | (high["b"] < Data02$b)] <- NA
Data02$c[(Data02$c < low["c"]) | (high["c"] < Data02$c)] <- NA
これで完成です!
ただ他にも方法があります。どれもよく使う方法なので、もし余力があればぜひ比べてみてください。


6.tidyverseパッケージを使う(dplyrパッケージでも同じ)

第2章で紹介しているtidyverseパッケージのsummarize関数とmutate関数を使うこともできます。
tidyverseパッケージを使うときには先にlibrary関数で呼び出します。なければ先にインストールします。
#もし初めての場合はインストール
install.packages("tidyverse")
#インストール済ならlibrary関数で呼び出す
library(tidyverse)
low_high <-
  summarize(Data01,
          a_low = mean(a, na.rm = TRUE)-2*sd(a, na.rm = TRUE),
          a_high = mean(a, na.rm = TRUE)+2*sd(a, na.rm = TRUE),
          b_low = mean(b, na.rm = TRUE)-2*sd(b, na.rm = TRUE),
          b_high = mean(b, na.rm = TRUE)+2*sd(b, na.rm = TRUE),
          c_low = mean(c, na.rm = TRUE)-2*sd(c, na.rm = TRUE),
          c_high = mean(c, na.rm = TRUE)+2*sd(c, na.rm = TRUE)) 
class(low_high) #型を確認するとdata.frameとなっている
low_high <- unlist(low_high)
class(low_high) #型を確認するとnumeric(数値型)となっている
low_high
スクリーンショット 2020-03-28 3.37.43
文字は多いですが、コピペを使えば作業自体は楽になります。
ただsummarize関数の結果は表形式(data.frame型)で、このままでは数値として計算できません。
そのためunlist関数を使って数値型に戻します。
low_high[5]、もしくはlow_high["c_low"]とすればcの平均-2SDとなります。


既に第2章を読まれた方は%>%を使う事もできます。
#%>%使う場合
low_high <- summarize(Data01, a_low = mean(a, na.rm = TRUE)-2*sd(a, na.rm = TRUE), a_high = mean(a, na.rm = TRUE)+2*sd(a, na.rm = TRUE), b_low = mean(b, na.rm = TRUE)-2*sd(b, na.rm = TRUE), b_high = mean(b, na.rm = TRUE)+2*sd(b, na.rm = TRUE), c_low = mean(c, na.rm = TRUE)-2*sd(c, na.rm = TRUE), c_high = mean(c, na.rm = TRUE)+2*sd(c, na.rm = TRUE)) %>%
unlist()
low_high
スクリーンショット 2020-03-28 3.32.12

次に条件に応じて分類するifelse関数を使うこともできます。

ifelse(条件TRUEの場合FALSEの場合)

列の追加や修正を行うmutate関数を使うことでこうなります。
Data02 <- 
  Data01 %>% 
  mutate(a = ifelse((low_high["a_low"] < a) & (a < low_high["a_high"]), a, NA),
         b = ifelse((low_high["b_low"] < b) & (b < low_high["b_high"]), b, NA),
         c = ifelse((low_high["c_low"] < c) & (c < low_high["c_high"]), c, NA))
スクリーンショット 2020-03-28 4.57.19

条件式を少し変えているので確認してみてください。今回は&を使っています。

tidyverseパッケージは現在のRを使う上でとても重要になります。
ifelse,mutate関数に関してはこちらで紹介していますので難しかったという方はご参照ください。




7.関数を自作しapply関数でまとめて処理する
他の方法としては関数を自作するという方法があります。

関数名 <- function(○) {中身のコード}

今回はdrop_2sdという名前の関数を作ります(名前は何でもいいけど文字の最初に数字を使うのは×)。


a = ifelse((aの平均-2SD < a) & (a < aの平均+2SD), a, NA),
b = ifelse((bの平均-2SD < b) & (b < bの平均+2SD), b, NA),
c = ifelse((cの平均-2SD < c) & (c < cの平均+2SD), c, NA)
 ↓
function(x){
 ifelse((xの平均-2SD < x) & (x < xの平均+2SD), x, NA)
}
と共通部分をxにします。ちなみにxでなくてもcolとか別の名前をつけても大丈夫です。

drop_2sd <- function(x){
  ifelse((mean(x, na.rm = TRUE) - 2 * sd(x, na.rm = TRUE) < x) & (x < mean(x, na.rm = TRUE) + 2 * sd(x, na.rm = TRUE)), x, NA)
}
そしてapply関数で各列にdrop_2sd関数を使います。
Data02 <- apply(Data01, 2, drop_2sd)
スクリーンショット 2020-03-28 4.50.32
2行のコードで終わりました。
関数を作るのは最初は慣れないですが、使えるようになると強力です。


8.まとめ

今回は標準偏差±2SDの除去を3つの方法で紹介しました。

本やサイトで独学すると1つの方法でしか紹介してないことが多いです。

本当は自分の知っている知識でもできるはずなのに、知らない方法を偶然読んでしまいドツボにはまることもあります。そういった紆余曲折は勉強する上で必要な苦労でもありますが、いくつかの方法を見比べることでショートカットできることもあるのではと思っています。

また自分が躓いたところや他の記事でもコメントがあれば検討していきますので、ブログのコメントやtwitterで連絡いただければ幸いです。

第4章は統計を扱います。


今回も「シロート統計学」のハルさんとコラボレーションすることとなりました。


シロート統計学はEZRを使った統計分析をわかりやすく解説されています。


 


第4章はシロート統計学で使われていたEZRをRで行うとどうなるのか?といった視点で進めていきます。


今回使うデータもハルさんのサイトと同じものを使わせでいただく事になりました。それぞれ見比べることで参考にしてみてください!


今回はFriedman(フリードマン)検定を紹介します



まずFriedman(フリードマン)検定についてはハルさんのサイトをご参照ください。



また1.準備〜4.データの読み込みまでは【4-1】Rでt検定を行う方法と全く同じ流れになります。
もし1〜4まででわからない部分があれば確認してみてください。

 

1.準備

第4章は毎回ExcelデータをダウンロードしてRを使うのでプロジェクトで管理して行うことを勧めています。

 

ここではR練習というプロジェクトを作り、Excelファイルを入れるためのdataフォルダを作っています。
これを前提に次から進めていきます。
スクリーンショット 2019-10-20 7.54.14


2.スクリプトファイルの作成

次にRのコードを書くためのスクリプトファイルを作ります。

スクリーンショット 2019-12-08 20.26.22

3.データのダウンロード


今回もハルさんのサイトのデータを使わせていただきます。

デモデータ(Friedman検定)

この章ではRを使ってダウンロードしています。


download.file(url = “ファイルのURL”,
        destfile = “保存したい場所/ファイル名”)
urlはデモデータで右クリック → リンクのアドレスをコピー
destfileは保存場所と保存のファイル名を指定します。


実際のコードは以下になります。
前回のコードのURL(" "の中)とdestfileのdata/以降を変更するだけでOKです。
#データのダウンロード
url <- "https://haru-reha.com/wp-content/uploads/2018/05/demo-friedman-rank-sum-test.xlsx"
destfile = "data/demo-friedman-rank-sum-test.xlsx"
download.file(url, destfile)
スクリーンショット 2019-11-23 22.14.17


dataフォルダにダウンロードできたことを確認します。


4.データの読み込み

データを読み込みます。
今回は【4-0】第4章を進めていく上での準備で行った方法で進めます。

View Fileでデータを確認します。

スクリーンショット 2019-12-08 20.31.39


データが入っているセルを確認します。
B2からC22までデータが入っています(B2:D32と表記)
スクリーンショット 2019-12-08 20.31.58



次にImport Datasetでデータを取り込みます。
スクリーンショット 2019-12-08 20.31.39



Import画面ではName, Sheet,Rangeを指定します。

Name:ハルさんのサイトではgripでしたがgrip_friedmanとします(大文字・小文字は別物とされます)
Sheet:このExcelは1つしかデータがないのでDefaultのままでOK
Range:先ほど確認したB2:D32(実は今回のように表以外に余計なものがなければ空欄でもOK)

スクリーンショット 2019-12-08 20.35.24


Importボタンを押す前に右にあるコードをコピーしスクリプトファイルに貼り付けることも忘れずに行います。
library(readxl)
grip_friedman <- read_excel("data/demo-friedman-rank-sum-test.xlsx")
View(grip_friedman)

データが正しく入っていることを確認します。
スクリーンショット 2019-12-08 20.36.11


これでデータの取り込みは完成です。
Friedman検定は繰り返しのデータ(被験者内要因)なのでデータを横につなげています。


5.Friedman検定を行う(wideデータの場合)

ハルさんのサイトでは早速Friedman検定を行っていますのでこちらも早速行います。
今回はwideデータなのでまずwideデータの場合を紹介します。

Friedman検定はfriedman.test関数を使います。

friedman.test(cbind(繰り返しデータのある列))
スクリーンショット 2019-12-09 0.52.59

friedman.test(cbind(grip_friedman$W0,grip_friedman$W1,grip_friedman$W2))
スクリーンショット 2019-12-09 0.54.04

EZRと同じ結果が出ました。

6.Friedman検定を行う(longデータの場合)
次にlongデータでFriedman検定を行う方法も紹介します。

friedman.test(データ ~ グループ | 個人を識別するid, data = ○○)

スクリーンショット 2019-12-09 0.58.27

Friedman検定は対応のあるデータになります。

今回は30人がW0,W1,W2の3回データを取っているので3*30=90データあります。
そのため作るlongデータは上記のイメージになります。

今回はid, time, gripとしてますが自分がわかれば好きな名前を付けてOKです。
id:30人の内誰のデータかわかるためのid(氏名でも可)
time:W0, W1, W2の3つ
grip:今回測定した握力のデータ
wideデータをlongデータに変えるにはgather関数、もしくはpivot_longer関数を使います。
gather関数に関しては【2-5】Rでデータを集計するのに便利なlongデータとgather関数で紹介しています。



データの扱いはtidyverseパッケージに含まれていますので。まずlibrary関数でtidyverseパッケージを読み込みます。今回はgrip_friedman_longという名前にします。

library(tidyverse)

#gather関数の場合 grip_friedman_long <- grip_friedman %>% rowid_to_column("id") %>% gather(key = time, value = grip, W0:W2, factor_key = TRUE)

#pivot_longer関数の場合 grip_friedman_long <- grip_friedman %>% rowid_to_column("id") %>% pivot_longer(cols = c(W0,W1,W2), names_to = "time", values_to = "grip", names_ptypes = list(time = factor()))

ポイントはもともとのExcelデータにidにあたる列がないことです。
そこでrowid_to_column関数を使います。""の中身が列名になります。
スクリーンショット 2019-12-09 1.14.03

これで準備が整いました。

longデータでFriedan検定を行う場合は改めてこうなります。

friedman.test(データ ~ グループ | 個人を識別するid, data = ○○)
friedman.test(grip ~ time | id, data = grip_friedman_long)
スクリーンショット 2019-12-09 0.54.04
もちろん結果は同じです。

7.多重比較を行う
Friedman検定で多重比較を行いたいのですがwideデータだとEZR専用のパッケージでしかできません。
そのためRで行うにはlongデータで行う必要があります。

longデータで多重比較を行うにはpairwise.wilcox.test関数を使います。簡単に言うと全ての組み合わせでMann-Whitney U検定を行いその結果を元にp値の調整を行います
どの方法を使うかはp.adjust.method = で指定します。
またタイのエラーを回避するためにexact = FALSEを入れています。
data = 

pairwise.wilcox.test(目的変数factor(グループ),  p.adjust.method = "◯◯", paired = TRUE, exact = FALSE)

#Bonferroniの方法
pairwise.wilcox.test(grip_friedman_long$grip, grip_friedman_long$time, p.adjust.method = "bonferroni", paired = TRUE, exact = FALSE)
#Holmの方法
pairwise.wilcox.test(grip_friedman_long$grip, grip_friedman_long$time, p.adjust.method = "holm", paired = TRUE, exact = FALSE)
スクリーンショット 2019-12-09 1.39.44
EZRとほぼ同じ結果になりました。

8.どうしてもwideデータのままなら手計算が必要

wideデータのまま多重比較を行う方法がEZRのパッケージしかありません。

そのためどうしてもwideデータのまま行うにはwilcox.test関数、もしくはcoinパッケージwilcox_test関数を使い、1つずつ組み合わせを行い、BonferroniHolmHochbergそれぞれの方法で自分でp値を直接計算することになります。

この方法は統計ERさんの記事に詳しく紹介されています。
更にBonferroniHolmHochbergって何をしてるの?という疑問も解決するかもしれません。
仕組みがわかればp値に2とか3とかかけるだけなので意外と単純です。
 


8.まとめ

今回はFriedman検定を紹介しました。

もしRで行う場合はwideデータで分析するかlongで分析するかをあらかじめイメージしていた方がその後の解析もスムーズかもしれません。

次は相関係数について紹介します!

9.今回使ったコード
#データのダウンロード
url <- "https://haru-reha.com/wp-content/uploads/2018/05/demo-friedman-rank-sum-test.xlsx"
destfile = "data/demo-friedman-rank-sum-test.xlsx"

download.file(url, destfile)

library(readxl)
grip_friedman <- read_excel("data/demo-friedman-rank-sum-test.xlsx")
View(grip_friedman)

friedman.test(cbind(grip_friedman$W0,grip_friedman$W1,grip_friedman$W2))

#pivot_longer関数の場合
grip_friedman_long <-
  grip_friedman %>% 
  rowid_to_column("id") %>% 
  pivot_longer(cols = c(W0,W1,W2), names_to = "time", values_to = "grip", names_ptypes = list(time = factor())) 

#gather関数の場合
grip_friedman_long <-
  grip_friedman %>% 
  rowid_to_column("id") %>% 
  gather(key = time, value = grip, W0:W2, factor_key = TRUE)

friedman.test(grip ~ time | id, data = grip_friedman_long)

pairwise.wilcox.test(grip_friedman_long$grip, grip_friedman_long$time, p.adjust.method = "bonferroni", paired = TRUE, exact = FALSE)
pairwise.wilcox.test(grip_friedman_long$grip, grip_friedman_long$time, p.adjust.method = "holm", paired = TRUE, exact = FALSE)
 

記事一覧はこちらになります。


第4章は統計を扱います。


今回も「シロート統計学」のハルさんとコラボレーションすることとなりました。


シロート統計学はEZRを使った統計分析をわかりやすく解説されています。


 


第4章はシロート統計学で使われていたEZRをRで行うとどうなるのか?といった視点で進めていきます。


今回使うデータもハルさんのサイトと同じものを使わせでいただく事になりました。それぞれ見比べることで参考にしてみてください!


まずはハルさんのサイトをご覧ください。
ここで行っている解析をRで実施する方法を紹介します。


1.データの準備

今回は前回のデータを使います。記事の1~4までをご準備ください。


もし前回の記事を見るなんて面倒くさい!という方は以下のコードを実行してください。
(このコードはデータの保存場所が今までのの記事と違います)

#データのダウンロード
url <- "https://haru-reha.com/wp-content/uploads/2018/05/demo-repeated-measures-anova.xlsx"
destfile <- "demo-repeated-measures-anova.xlsx" #今まで第4章の記事を読まれて実践されてる方は destfile <- "data/demo-repeated-measures-anova.xlsx"
download.file(url, destfile) #データの読み込み library(readxl) grip_rep_anova <- read_excel("data/demo-repeated-measures-anova.xlsx", range = "B2:E32") View(grip_rep_anova)

スクリーンショット 2019-11-25 22.48.23
前回は
ある運動プログラムを行い、0週目・1週目・2週目で握力を測定した、ということを想定した仮想データとなっています。今回は握力の経時的検討に加えて男女の群分けも行います。

2.被験者間要因と被験者内要因と分散分析のデザインについて
分散分析を行う上で大切なのがvについてです。
スクリーンショット 2019-11-24 6.33.40
被験者間要因はいわゆる対応のないデータのことで被験者全体をA法、B法の2つに割り振るといった方法です。なので同じ人がA法とB法を行うことはありません。
被験者内要因はいわゆる対応のあるデータのことで同じ人が繰り返し測定します

そして被験者間要因は列の左側に、被験者内要因は列の右側に並べると後々分析しやすくなります。
また被験者間要因は縦に、被験者内要因は横につなげるとEZRで分析を行うには都合がいいです。

仮に下のデータがあったとします。
スクリーンショット 2019-11-24 6.35.12
この並びが分散分析を行う上での基本的な形になります。

要因が3つ(sex, treatment, 繰り返し)あるのでABC
被験者間要因と被験者内要因の間にsを付ける

上記の場合はABsCデザインと言います。
また被験者間要因と被験者内要因が両方あるデザインを混合計画とも呼んだりします。


今回は以下のようになります。

被験者間要因:sex(A
被験者内要因:W0,W1,W2の繰り返し(B


今回のExcelではsexの列が1番右にありますが被験者間要因を左、被験者内要因を右に書くのが習わしのようなのでAsBデザインということになります。

被験者内要因(改善の傾向)に性別が影響しているかどうかを見たいということになります。

3.反復測定分散分析(repeated measures ANOVA)を行う

前回の記事で正規分布の確認を行いましたので、早速反復測定分散分析を行います。

反復測定分散分析を行うには主に2つの方法があります。

1.carパッケージのAnova関数を使う(EZRもcarパッケージを使ってる)
2.ANOVA君を使う

ANOVA君は井関龍太さんが作成した分散分析に特化したスクリプトです。
使い方に特徴がありますが使えるようになると慣れると簡単でどの方法よりも詳細に分析できます。

ここではまず1の方法を紹介します。

反復測定分散分析を行うには次の方法になります。




①carパッケージを読み込む
ここは前回の記事と全く同じです。
まずはcarパッケージを読み込みます。
carパッケージはEZRをインストールする時に一緒にインストールされています。
もしインストールしていなければ先にインストールします。

install.packages("car")


その後library関数で呼び出します。

library(car)


②被験者要因を指定するdata.frameを準備する
ここは前回の内容と全く同じです。
今回のデータではsexの列は「MとFの2つのデータがある」とパソコンは読み取れますがW0,W1,W2はwideデータとなっているため「この3列が繰り返しのデータである」ことがパソコンは読み取れません。それがわかるためのものを2つ作ります。

まず繰り返しの順番がわかるtimeというベクトルを作ります。
このデータはfactor型である必要があるためfactor関数を使います。
そしてtimeのデータをdata.frame型に変更したidataを作ります。

 スクリーンショット 2019-11-24 10.11.33
そして大事なのがlevels = です。levels = を指定しないとfacorは五十音順になります。
今回は問題ないのですがもしpre,mid,postのように列名を付けるとlevels = を使わないとmid→post→preの順番になってしまいます。
factor関数に関しては【1-10】Rでよく使われる型について説明します。
 

③lm関数でモデルを作る
スクリーンショット 2019-11-25 23.38.40
次に分析するためのモデルを作ります。ここが前回の記事と唯一違うところです。

モデルはlm関数を使います。model(名前は何でもいい)という変数名に結果を入れます。

被験者内要因は3列になっているのでcbind関数でつなげます。
被験者間要因は~の右に入れます。もし被験者間要因が複数あれば * でつなぎます(交互作用を見たい場合)。もし交互作用を見ない場合は + でつなぎます。

そして必ず大切なのがcontrasts = の箇所です。
数学的には反復測定分散分析はタイプⅢ平方和というものを計算します。
詳しい話は井関龍太さんの記事にありますが、contrasts = を設定しないと正しいタイプⅢ平方和を計算してくれないため、この設定が必要となります。
使い方はcontrasts = list(〇 = contr.sum, △ = contr.sum, □ = contr.sum)のようにlist内で指定します。


④Anova関数で分散分析を実行する
スクリーンショット 2019-11-25 23.40.16
ここは前回の記事と全く同じです。
反復測定分散分析を行う時はcarパッケージのAnova関数を使います。Aは必ず大文字です。
res(resultの略、何でも良い)という変数名に結果を入れます。

Anova(lm関数で作ったモデル, idata = ◯◯, idesign = ~ ◯◯, type = "Ⅲ")

lm関数で作ったモデル:先程作ったmodel
idata:先程つくったidata
idesign:先程作ったtime(timeの前に を付けます)
type:"Ⅲ"または3とする(反復測定分散分析の場合は必ずⅢ)

スクリーンショット 2019-11-24 12.08.02

⑤summary関数で結果を表示する

summary(Anova関数の結果, multivariate = FALSE)

multivariate = FALSEと入れるとEZRと同じ結果が表示されます。

①〜⑤をまとめると以下になります

library(car)
time <- factor(c("W0", "W1", "W2"), levels = c("W0","W1", "W2"))
idata <- as.data.frame(time)
model <- lm(cbind(W0,W1,W2) ~ sex, 
            data = grip_rep_anova, 
            contrasts = list(sex = contr.sum))
res <- Anova(model, idata = idata, idesign = ~time, type = 3)
summary(res, multivariate = FALSE)


行が長くて大変ですが実は色の部分以外はコピペ可能です。
(被験者間要因があればまた変わります。次回記事で紹介します)
スクリーンショット 2019-11-25 23.51.29

結果はまずMauchlyの球面仮定を確認し、有意差がなければ上、あれば下をチェックします。

sex→握力は性別により変化する
time→握力は時間経過により変化する
sex:time→交互作用(時間経過に伴う握力の改善の程度は男女で異なるか)

スクリーンショット 2019-11-26 0.16.54
結果はEZRと同じになりました。

4.まとめ
今回は2要因以上ある反復測定分散分析を行いました。
前回の記事との違いは被験者間要因があるかどうかでした。
被験者間要因があるとcontrasts = 設定が必要になりますので注意が必要です。

そして前回・今回はEZRと同じ方法のcarパッケージのAnova関数を使いました。
ただどうしてもコードが長くなってしまいます。
ただRにはのANOVA君という分散分析に特化した非常に有名なスクリプトがあります。


次回はANOVA君を使った分散分析を紹介します。

5.今回使ったコード


#データのダウンロード
url <- "https://haru-reha.com/wp-content/uploads/2018/05/demo-repeated-measures-anova.xlsx"
destfile <- "demo-repeated-measures-anova.xlsx" #今まで第4章の記事を読まれて実践されてる方は destfile <- "data/demo-repeated-measures-anova.xlsx"
download.file(url, destfile) #データの読み込み library(readxl) grip_rep_anova <- read_excel("data/demo-repeated-measures-anova.xlsx", range = "B2:E32") View(grip_rep_anova)

#sexの列もいれた反復測定分散分析 library(car) time <- factor(c("W0", "W1", "W2"), levels = c("W0","W1", "W2")) idata <- as.data.frame(time) model <- lm(cbind(W0,W1,W2) ~ sex, data = grip_rep_anova, contrasts = list(sex = contr.sum)) res <- Anova(model, idata = idata, idesign = ~time, type = 3) summary(res, multivariate = FALSE)





(2019年11月24日修正:8の②のfactor関数を修正しています)

第4章は統計を扱います。


今回も「シロート統計学」のハルさんとコラボレーションすることとなりました。


シロート統計学はEZRを使った統計分析をわかりやすく解説されています。


 


第4章はシロート統計学で使われていたEZRをRで行うとどうなるのか?といった視点で進めていきます。


今回使うデータもハルさんのサイトと同じものを使わせでいただく事になりました。それぞれ見比べることで参考にしてみてください!


今回は繰り返しのある一元配置分散分析を紹介します



まず繰り返しのある一元配置分散分析(ANOVA)についてはハルさんのサイトをご参照ください。



また1.準備〜4.データの読み込みまでは【4-1】Rでt検定を行う方法と全く同じ流れになります。
もし1〜4まででわからない部分があれば確認してみてください。

 

1.準備

第4章は毎回ExcelデータをダウンロードしてRを使うのでプロジェクトで管理して行うことを勧めています。

 

ここではR練習というプロジェクトを作り、Excelファイルを入れるためのdataフォルダを作っています。
これを前提に次から進めていきます。
スクリーンショット 2019-10-20 7.54.14


2.スクリプトファイルの作成

次にRのコードを書くためのスクリプトファイルを作ります。

スクリーンショット 2019-11-23 22.05.34



3.データのダウンロード


【1-13】Rで読み込みやすいExcelファイルの作り方今回もハルさんのサイトのデータを使わせていただきます。
実は分散分析を行う上で覚えておくと便利なExcelデータの作り方(列の並べ方)があります。
詳細は【1-13】Rで読み込みやすいExcelファイルの作り方で紹介しています。

デモデータ(反復測定分散分析)

この章ではRを使ってダウンロードしています。


download.file(url = “ファイルのURL”,
        destfile = “保存したい場所/ファイル名”)
urlはデモデータで右クリック → リンクのアドレスをコピー
destfileは保存場所と保存のファイル名を指定します。


実際のコードは以下になります。
前回のコードのURL(" "の中)とdestfileのdata/以降を変更するだけでOKです。
#データのダウンロード
url <- "https://haru-reha.com/wp-content/uploads/2018/05/demo-repeated-measures-anova.xlsx"
destfile = "data/demo-repeated-measures-anova.xlsx"
download.file(url, destfile)
スクリーンショット 2019-11-23 22.14.17


dataフォルダにダウンロードできたことを確認します。


4.データの読み込み

データを読み込みます。
今回は【4-0】第4章を進めていく上での準備で行った方法で進めます。

View Fileでデータを確認します。

スクリーンショット 2019-11-23 22.15.57

データが入っているセルを確認します。
B2からC22までデータが入っています(B2:E32と表記)
スクリーンショット 2019-11-23 22.20.35


次にImport Datasetでデータを取り込みます。
スクリーンショット 2019-11-23 22.15.57


Import画面ではName, Sheet,Rangeを指定します。

Name:ハルさんのサイトではgripでしたがgrip_rep_anovaとします(大文字・小文字は別物とされます)
Sheet:このExcelは1つしかデータがないのでDefaultのままでOK
Range:先ほど確認したB2:E32(実は今回のように表以外に余計なものがなければ空欄でもOK)

スクリーンショット 2019-11-23 22.24.40

Importボタンを押す前に右にあるコードをコピーしスクリプトファイルに貼り付けることも忘れずに行います。
library(readxl)
grip_rep_anova <- read_excel("data/demo-repeated-measures-anova.xlsx", 
                             range = "B2:E32")
View(grip_rep_anova)

データが正しく入っていることを確認します。
スクリーンショット 2019-11-23 22.25.10


これでデータの取り込みは完成です。

5.被験者間要因と被験者内要因と分散分析のデザインについて
分散分析を行う上で大切なのが被験者間要因と被験者内要因についてです。
スクリーンショット 2019-11-24 6.33.40
被験者間要因はいわゆる対応のないデータのことで被験者全体をA法、B法の2つに割り振るといった方法です。なので同じ人がA法とB法を行うことはありません。
被験者内要因はいわゆる対応のあるデータのことで同じ人が繰り返し測定します

そして被験者間要因は列の左側に、被験者内要因は列の右側に並べると後々分析しやすくなります。
また被験者間要因は縦に、被験者内要因は横につなげるとEZRで分析を行うには都合がいいです。

仮に下のデータがあったとします。
スクリーンショット 2019-11-24 6.35.12
この並びが分散分析を行う上での基本的な形になります。
要因が3つ(sex, treatment, 繰り返し)あるのでABC
被験者間要因と被験者内要因の間にsを付ける
上記の場合はABsCデザインと言います。

今回はsexの列を使いませんので繰り返しの1要因のみで分散分析を実施します。
(sexの列を使った分析は次の記事で紹介します)

被験者間要因がありませんので、今回はsAデザインということになります。
繰り返しの群間に差があるかどうかを見たいということです。


6.正規分布かどうかを確認
分散分析を行うにはデータの分布が正規分布であることが必要です。
ハルさんのサイトに沿って正規分布の確認を行います。

正規分布の確認は【4-10】Rで分散分析(一元配置分散分析)を行う方法と基本的には同じですが、今回は繰り返しの部分がwideデータになっています。longデータであれば今までの記事で紹介した方法でまとめて出すことができますが、今回は1つずつ確認します。

今回ヒストグラムはgeom_histgram関数を使いますのでtidyverseパッケージを読み込みます。
EZRで正規性の確認をする時に併せて作成されるヒストグラムは棒が5本なのでbins = 5とすることにします。

library(tidyverse)
ggplot(data = grip_rep_anova) +
  geom_histogram(aes(x = W0), bins = 5) 

ggplot(data = grip_rep_anova) +
  geom_histogram(aes(x = W1), bins = 5) 

ggplot(data = grip_rep_anova) +
  geom_histogram(aes(x = W2), bins = 5) 
スクリーンショット 2019-11-23 22.42.57


7.シャピロ・ウィルク検定
次にハルさんのサイトでは正規性の検定を行っています。
正規性の検討はshapriro.test関数3つのカテゴリーそれぞれに行う必要があります。
ここでもwideデータなので1つずつ行います。

shapiro.test((grip_rep_anova$W0))
shapiro.test((grip_rep_anova$W1))
shapiro.test((grip_rep_anova$W2))
スクリーンショット 2019-11-23 22.44.56


すべて正規分布であることが棄却されませんでした。


8.反復測定分散分析(repeated measures ANOVA)を行う

そして反復測定分散分析を行います。

反復測定分散分析を行うには主に2つの方法があります。

1.carパッケージのAnova関数を使う(EZRもcarパッケージを使ってる)
2.ANOVA君を使う

ANOVA君は井関龍太さんが作成した分散分析に特化したスクリプトです。
使い方に特徴がありますが使えるようになると慣れると簡単でどの方法よりも詳細に分析できます。

ここではまず1の方法を紹介します。

反復測定分散分析を行うには次の方法になります。




①carパッケージを読み込む

まずはcarパッケージを読み込みます。
carパッケージはEZRをインストールする時に一緒にインストールされています。
もしインストールしていなければ先にインストールします。

install.packages("car")

その後library関数で呼び出します。
library(car)

②被験者要因を指定するdata.frameを準備する

今回のデータではsexの列は「MとFの2つのデータがある」とパソコンは読み取れますがW0,W1,W2はwideデータとなっているため「この3列が繰り返しのデータである」ことがパソコンは読み取れません。それがわかるためのものを2つ作ります。

まず繰り返しの順番がわかるtimeというベクトルを作ります。
このデータはfactor型である必要があるためfactor関数を使います。
そしてtimeのデータをdata.frame型に変更したidataを作ります。

 スクリーンショット 2019-11-24 10.11.33
そして大事なのがlevels = です。levels = を指定しないとfacorは五十音順になります。
今回は問題ないのですがもしpre,mid,postのように列名を付けるとlevels = を使わないとmid→post→preの順番になってしまいます。
factor関数に関しては【1-10】Rでよく使われる型について説明します。
 

③lm関数でモデルを作る

次に分析するためのモデルを作ります。
モデルはlm関数を使います。model(名前は何でもいい)という変数名に結果を入れます。
被験者内要因は3列になっているのでcbind関数でつなげます。
被験者間要因は今回無いので1とします。もしあると別の設定も必要ですが次の記事で紹介します。

スクリーンショット 2019-11-24 11.55.22
④Anova関数で分散分析を実行する



反復測定分散分析を行う時はcarパッケージのAnova関数を使います。Aは必ず大文字です。
res(resultの略、何でも良い)という変数名に結果を入れます。

Anova(lm関数で作ったモデル, idata = ◯◯, idesign = ~ ◯◯, type = "Ⅲ")

lm関数で作ったモデル:先程作ったmodel
idata:先程つくったidata
idesign:先程作ったtime(timeの前に を付けます)
type:"Ⅲ"または3とする(反復測定分散分析の場合は必ずⅢ)
スクリーンショット 2019-11-24 12.08.02

⑤summary関数で結果を表示する

summary(Anova関数の結果, multivariate = FALSE)

multivariate = FALSEと入れるとEZRと同じ結果が表示されます。

①〜⑤をまとめると以下になります
library(car)
time<- factor(c("W0", "W1", "W2"), levels = c("W0","W1", "W2")) idata <- as.data.frame(time) model <- lm(cbind(W0,W1,W2) ~ 1, data = grip_rep_anova) res <- Anova(model, idata = idata, idesign = ~time, type = 3 ) summary(res, multivariate = FALSE)
スクリーンショット 2019-11-24 21.02.57
行が長くて大変ですが実は色の部分以外はコピペ可能です。
(被験者間要因があればまた変わります。次回記事で紹介します)

スクリーンショット 2019-11-24 12.51.33
このあたりはハルさんのサイトと同じです。
EZRと同じ結果になります。

9.多重比較を行う

EZRの多重比較はEZR独自の関数を使っています。
そのため今回はpairwise.t.test関数を使います。
(被験者間要因があると使えないので注意!)
ただpairwise.t.test関数はlongデータで行う必要があります。

wideデータをlongデータに変えるにはgather関数、またはpivot_longer関数を使います。
wideデータとlongデータの切り替えは【2-5】Rでデータを集計するのに便利なlongデータとgather関数で紹介しています。

pairwise.t.test(数値, グループ, p.adjust.method = "◯◯")
〇〇はここでは3つの方法を紹介します。

bonferroni
holm
hochberg


grip_rep_anova_long <- 
  grip_rep_anova %>% 
  gather(key = "key", value = "value", W0:W2)

pairwise.t.test(grip_rep_anova_long$value, grip_rep_anova_long$key, paired = TRUE, p.adjust.method = "bonferroni")
pairwise.t.test(grip_rep_anova_long$value, grip_rep_anova_long$key, paired = TRUE, p.adjust.method = "holm")
pairwise.t.test(grip_rep_anova_long$value, grip_rep_anova_long$key, paired = TRUE, p.adjust.method = "hochberg")

スクリーンショット 2019-11-24 13.17.18


10.まとめ

今回は反復測定分散分析を紹介しました。
今までの手法に比べると手続きが必要ですが、慣れるとコピペでもできるようになります。
次回は被験者間要因も含めた混合計画反復測定分散分析を紹介します。


11.今回使ったコード

今回使ったコードは以下になります。
#データのダウンロード
url <- "https://haru-reha.com/wp-content/uploads/2018/05/demo-repeated-measures-anova.xlsx"
destfile <- "data/demo-repeated-measures-anova.xlsx"

download.file(url, destfile)

#データの読み込み
library(readxl)
grip_rep_anova <- read_excel("data/demo-repeated-measures-anova.xlsx", 
                             range = "B2:E32")
View(grip_rep_anova)

#正規分布の確認
library(tidyverse)
ggplot(data = grip_rep_anova) +
  geom_histogram(aes(x = W0), bins = 5) 

ggplot(data = grip_rep_anova) +
  geom_histogram(aes(x = W1), bins = 5) 

ggplot(data = grip_rep_anova) +
  geom_histogram(aes(x = W2), bins = 5) 

shapiro.test((grip_rep_anova$W0))
shapiro.test((grip_rep_anova$W1))
shapiro.test((grip_rep_anova$W2))


#carパッケージのインストールしたことなければインストール
install.packages("car")

#反復測定分散分析を行う
library(car)
time<- factor(c("W0", "W1", "W2"), levels = c("W0","W1", "W2"))
idata <- as.data.frame(time)
model <- lm(cbind(W0,W1,W2) ~ 1, data = grip_rep_anova)
res <- Anova(model, idata = idata, idesign = ~time, type = 3)
summary(res, multivariate = FALSE)

#多重比較
grip_rep_anova_long <- 
  grip_rep_anova %>% 
  gather(key = "key", value = "value", W0:W2)

pairwise.t.test(grip_rep_anova_long$value, grip_rep_anova_long$key, paired = TRUE, p.adjust.method = "bonferroni")
pairwise.t.test(grip_rep_anova_long$value, grip_rep_anova_long$key, paired = TRUE, p.adjust.method = "holm")
pairwise.t.test(grip_rep_anova_long$value, grip_rep_anova_long$key, paired = TRUE, p.adjust.method = "hochberg")



RStudioではまずExcelやcsvファイル等を読み込む必要がありますが、そもそもExcelではRに読み込みやすい形とそうでない形があります。Excelの見栄え的には良くても実際にRで読み込もうとすると大変な手間になることもあります。

今回はRで読み込みやすいExcelのポイントを紹介します。



1.上や左に空白はないか?

スクリーンショット 2019-10-20 20.07.06

RでなにもせずにExcelファイルを読み込むとA1を始めとしてデータを読み込みます。よくExcelでかけ線を設定している場合B2から表をつくることがありますが、Rで読み込むときには一手間必要です。



2.一番下に合計の行がないか?

加えてもし一番下に合計や平均の列があったらそれも1データとして読み込んでしまうので注意が必要です。
Excelは集計のために使い分析をRで行う場合はそもそも無いほうが安全です。
もしExcelでも集計を行いたい場合は集計を別のタブで行うかピボットテーブルを使う方法があります。



3.タイトル行が2行に渡っていないか?

タイトル行が2行に渡っているとRではうまく読み込んでくれません。
そしてそういう場合はセル結合されていることも多いです。
こういった場合も対処が必要です。

タイトルが2行に渡った時の対処法に関しては以下の記事で説明しています。




4.無駄な空間を作らない
スクリーンショット 2019-11-24 6.59.39
上記の図のように空欄だとパソコンは読み込んでくれません。
列名をちゃんと書き、データは空欄にせず入力しましょう。

5.桁数に使う , を入れていないか

10,000などカンマ含む場合、Rで読み込むと数字ではなく文字として認識されます。
「どうしても , はつけないとダメ」と上司に言われてもRで , を取る方法はあります(parse_number関数)


6.マイナスの値を▲にしていないか?

-100を▲100にしていたらマイナスに直す必要があります。
文字の置換(ここでは▲ → − )にするにはstr_replaceなどの関数がありますが、手間を考えると−の方が手間が省けます。


7.和暦か西暦か?

和暦だと古いExcelではいつまでたっても令和になりません。
計算や列の順番を考えると西暦のほうが後々対処しやすいです。
加えて2001年を01年としないよう注意しましょう。


8.tidyなデータか?

データ分析を行う上で必要な考え方にtidy(タイディー:整然データ)なデータかどうかという考え方があります。

tidyに関しては以下の記事が具体例も交えながらわかりやすく説明されています。




これからデータ収集を考えている方は参考になると思います。


9.被験者間要因は左側に、被験者内要因は右側に並べる
先程tidyなデータの話がありましたが、実際にデータを取りExcelに打ち込む時に覚えておくと後で便利になる考え方があります。それは被験者間要因被験者内要因です。
スクリーンショット 2019-11-24 6.33.40
被験者間要因はいわゆる対応のないデータのことで被験者全体をA法、B法の2つに割り振るといった方法です。なので同じ人がA法とB法を行うことはありません。

被験者内要因はいわゆる対応のあるデータのことで同じ人が繰り返し測定します

加えて被験者間要因は列の左側に、被験者内要因は列の右側に並べると後々分析しやすくなります。
また被験者間要因は縦に、被験者内要因は横につなげるとEZRで分析を行うには都合がいいです。
もし横に列が長くなりすぎて困る場合は全部縦にしても大丈夫です。あとで横に変換できます。
スクリーンショット 2019-11-24 6.35.12
この方法は特に分散分析を行う場合に便利になります。



10.まとめ

予めExcelのデータをRで読み込みやすい形にするとデータの前処理で心が折れにくくなりますので参考にしてみてください!


↑このページのトップヘ