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関数を紹介しました。

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

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




前回はmutate関数を使って列の追加や修正を行いました。
そして最後に以下のコメントで終了しました。
mutate関数を使うと「FIMの合計点」とかだけでなく、年齢を「年代ごとに分類する」だったり、ある評価の「カットオフ値以上とそれ以下」に分けた列をExcelを使わずに作成することができます。
【2-2】Rのmutate関数を使って列の追加や修正を行うより)

今回は連続変数を条件に応じて複数のカテゴリーに変換していきます。

Rではいくつか方法があるのですが、今回はifelse関数、case_when関数、cut関数を紹介します。


今回使う架空のデータは年齢、性別、病名が入っています。
下のコードをまとめてスクリプトにコピペして実行してください。
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



今回は%>%やmutate関数を使って作業します。
これらの使い方に不安がある場合は前回の記事をご参照ください



1.ifelse関数をつかって分類する

条件から2つに分類する場合

ifelse関数は条件からTRUEとFALSEの2つに分けることができます。

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



まず例としてdata_20という変数名に以下のように分類していきます。
・20歳未満を「未成年」、20歳以上を「成人」
・性別の男性を「male」、女性を「female」

data_20 <- data %>% 
  mutate(成人 = ifelse(.$年齢 < 20 , "未成年", "成人")) %>% 
  mutate(性別 = ifelse(.$性別 == "男性", "male", "female"))
head(data_成人)

スクリーンショット 2019-02-11 0.44.03

スクリーンショット 2019-02-11 0.46.48



条件から3つ以上分類する場合

3つ以上分類するはifelse関数のFALSEにifelseを入れ込みます。

ifelse(条件, TRUE, ifelse(条件2, TRUE, ifelse(条件3, TRUE, FALSE)))

このような形を「入れ子」と呼ぶそうです。繰り返せばいくらでも条件を増やすことができます。


今度は「年代」という変数名で20歳ごとに区切ってみます。
20歳未満なら「0〜」、
そうでなければ40歳未満なら「20〜」
そうでなければ60歳未満なら「40〜」・・・

上のイメージをコードにするとこうなります。

data_age <- data %>% 
  mutate(年代 = ifelse(.$年齢 < 20,"0〜", 
                      		ifelse(.$年齢 <40 ,"20〜", 
                        		ifelse(.$年齢 < 60,"40〜",
                        			ifelse(.$年齢 < 80, "60〜",
                        				ifelse(.$年齢 < 100, "80〜", "100〜")))))) %>% 
  mutate(年代 = factor(.$年代, levels = c("0〜", "20〜", "40〜", "60〜", "80〜", "100〜"), ordered = TRUE))
head(data_age)
スクリーンショット 2019-02-12 21.22.24

 mutate(年代 = factor(.$年代, levels = c("0〜", "20〜", "40〜", "60〜", "80〜", "100〜"), ordered = TRUE)の部分はfactorの順番を並べ替えています。

factorは50音順に並ぶので、もしこれをしなかったらグラフなど作る時に「0〜, 100〜, 20〜・・・」と100歳以上の場所がずれてしまいます。それを修正するためにlevels = でfactorの並べ替えをしています。
参照:【1-10】Rでよく使われる型について説明します。


個人的に感じる「ifelse関数+入れ子」のメリットは「他の関数を覚えなくていい」で、デメリットは終わりの))))))))の数が多すぎて間違えやすく、エラーに悩まされることです(笑)



2.case_when関数を使って分類する

3つ以上の分類で入れ子構造対策で慣れるとわかりやすいのがcase_when関数かもしれません。

case_when(条件A ~ 結果A, 条件B ~ 結果B, 条件C ~ 結果C)

今回は0歳以上 かつ 20歳未満といったように「かつ」が入る時は & を使います

年齢が0歳以上   かつ 年齢が20歳未満 を「0〜」
年齢が20歳以上 かつ 年齢が40歳未満 を「20〜」
年齢が40歳以上 かつ 年齢が60歳未満 を「60〜」・・・

上のイメージをコードにするとこうなります。

data_age <- data %>% 
  mutate(年代 = case_when(
    .$年齢 >= 0  & .$年齢 <20 ~ "0〜",
    .$年齢 >= 20 & .$年齢 <40 ~ "20〜",
    .$年齢 >= 40 & .$年齢 <60 ~ "40〜",
    .$年齢 >= 60 & .$年齢 <80 ~ "60〜",
    .$年齢 >= 80 & .$年齢 <100 ~ "80〜",
    .$年齢 >= 100 ~ "100〜")) %>% 
  mutate(年代 = factor(.$年代, levels = c("0〜", "20〜", "40〜", "60〜", "80〜", "100〜"), ordered = TRUE))

head(data_age)
スクリーンショット 2019-02-12 23.58.42


入れ子よりも( )の数が少ないのがありがたいところです。


数値でなくカテゴリーを条件で更に分類する場合

上記の場合は数値でしたが次のような場合はどうでしょう?

最初に行ったdata_20という変数名に以下のように分類していきます。
・成人という変数名で20歳未満を「未成年」、20歳以上を「成人」とする
・性別の男性を「male」、女性を「female」に変更
・疾患分類という変数名で、骨折・靭帯損傷を「運動器疾患」、脳梗塞・脳出血を「脳血管疾患」、心筋梗塞を「心疾患」とする

data_age <- data %>% 
  mutate(年代 = case_when(
    .$年齢 < 20 ~ "未成年",
    .$年齢 <= 20 ~ "成人")) %>% 
  mutate(性別 = case_when(
    .$性別 == "男性" ~ "male",
    .$性別 == "女性" ~ "female")) %>%
  mutate(疾患分類 = case_when(
    .$病名 %in% c("骨折", "靭帯損傷") ~ "運動器疾患",
    .$病名 %in% c("脳梗塞", "脳出血") ~ "脳血管疾患",
    .$病名 %in% "心筋梗塞" ~ "心疾患"))
head(data_age)
スクリーンショット 2019-02-13 0.58.43


ここで新たな ==%in% が出てきました。

スクリーンショット 2019-02-11 2.04.40
A == Bと A %in% Bは似ていますが、Bにあたる部分で==であれば1つしか入りません。
%in%は1つでも複数でも大丈夫です。

上記のコードで言うと .$性別 == "男性" ~ "male" の==は %in%に変えても大丈夫ですし、.$病名 %in% "心筋梗塞" ~ "心疾患" の %in% は == に変えても大丈夫です。

しかし.$病名 %in% c("骨折", "靭帯損傷") ~ "運動器疾患" に関しては ==に変えるとエラーが出ます。

上記図は今回の記事だけでなく条件式を作る時に必要になる考え方です。


case_when関数のメリットは入れ子構造にならないことで、デメリットとしては2つに分類するならifelseの方がコードが短くなります。



3.cut関数を使って分類する


数値を分類するに限って言うとcut関数も使えます。
cut関数はコードはスッキリしますが、少しクセがあり、おまじないが必要です。

cut(目的の列,
      breaks = (下限, カットする数値, 上限),
      right = FALSE,
      include.lowest = TRUE,
      labels =c("カテゴリー毎の名前"))

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


「10代・20代」などでは0〜19のような分け方をするので、right = FALSEが必要になります。
加えてinclude.lowest = TRUEを加えないと端の値を読み込まず<NA>とデータなしとみなされてしまいます。


これらをふまえると以下のコードになります。

 data_age <- data %>% 
  mutate(年代 = cut(.$年齢, 
                  breaks = c(0, 20, 40, 60, 80, 100, 120),
                  right = FALSE, 
                  include.lowest = TRUE,
                  labels = c("0〜", "20〜", "40〜", "60〜", "80〜", "100〜")))
head(data_age)
スクリーンショット 2019-02-13 1.51.09


cut関数を使えば細かい条件が必要にならない分、right = や include.lowest = を忘れないように注意が必要です。


補足.mutate関数の組み合わせについて

mutate関数を複数回行うにはいくつかの方法があります。

スクリーンショット 2019-02-16 19.31.02
(追記)2019/02/16更新
すみません。mutate関数では②の方法は使えませんでした。
②の方法は次で紹介するfilter関数で使うことができます。


本来は,でつなぐと1つの行で済むのですが、初心者だと、()や,の数がうまくあわなかったりします。プログラミングの上級者からは意見があるかもしれませんが、プログラミング未経験・初心者はまず自分の覚えやすいものから始めていいと思っています。


まとめ

今回は条件によって分類する方法についてifelse関数、case_when関数、cut関数を紹介しました。

それぞれに特徴がありますので、必要に応じて使い分けてください。

また今回は演算子(<, ==, %in%など)の紹介も行いました。

演算子はデータを集計するときに必要になりますのでまた紹介していきたいと思います。

前回の記事から第2章が始まりました。

第1章:Rの基本的な使い方について知る
第2章:データの扱いに慣れる

【2-1】Rのfor関数、apply関数を使ってまとめて標準偏差などの統計量を求める方法


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

今回は「合計」など新たな列を追加したり、すでにある列を修正するmutate関数について紹介します。

mutate関数は前回の記事でも行ったパイプ演算子(%>%)と一緒に使うことが多いので、パイプ演算子の練習の意味も含めて紹介していきます。


今回は前回の記事のデータを使います。

data01.xlsx 

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

library(readxl)
data01 <- read_excel("data01.xlsx", sheet = "日本語")
data01$性別 <- factor(data01$性別, levels = c("男性","女性"))
data01$歩行 <- as.factor(data01$歩行)
head(data01)

*注意
もしプロジェクトファイルを作成していない場合はgetwd()と打ち込むと作業フォルダが表示されます、作業フォルダにExcelデータを入れると後は同じです。

getwd()


1.mutate関数を使ってBMIの列を作る

library(tidyverse)  #既に実行していたらなくても可
data01_bmi <- mutate(data01, BMI = 体重 / (身長 / 100)^2)
data01_bmi

スクリーンショット 2019-02-08 13.51.51
つまり今回は以下の3つは同じ意味になります。
data01_bmi <- mutate(data01, data01$BMI = data01$体重 / (身長 / 100)^2)
data01_bmi <- mutate(data01, BMI = .$体重 / (.$身長 / 100)^2)
data01_bmi <- mutate(data01, BMI = 体重 / (身長 / 100)^2)


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

2乗は ^ を使います。
5の2乗は5^2となりますが、5 ^ 2のようにスペースは空けずにくっつけて使います
+ - * / は前後にスペースを入れて使います()
, は,の後にだけスペースを入れます。前に入れません
%>%はくっつけて使い、前後にスペースを入れます


data01 <- mutate(・・・)とdata01自体を修正すると、コードを振り返る時にどこからがBMIを追加する前のdata01で、どこからがBMIを追加した後のdata01かわからなくなるので、今回は新たにdata01_bmiという変数名を作りました。


1つ注意点なのですが、変数名や列の名前にカンマ( , )やドット( . )、ハイフン( - )をつけないようにしましょう。これらは計算式とご認識されて後でめんどくさいことになります。
対策としてはアンダーバー( _ )を使います。



1−2.パイプ演算子とmutate関数をで同じことをする

今度はパイプ演算子を使って同じことをします。

パイプ演算子(%>%)は解析の流れをスムーズにしてくれます。
データ① %>%
    プログラム② %>%
    プログラム③ %>%
    プログラム④
とすると先程のdata01_selectの用な変数を介することもなく、データ①をプログラム②に送り、その結果をプログラム③に送り、その結果をプログラム④に送るといったことが可能になります
【2-1】Rのfor関数、apply関数を使ってまとめて標準偏差などの統計量を求める方法より引用

library(tidyverse)  #既に実行していたらなくても可
data01_bmi <- data01 %>% mutate(BMI = 体重 / (身長 / 100)^2)
data01_bmi

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


同じ結果になります。

%>%なんでめんどくさいのでは・・・?と思うかもしれませんが、今回はmutate関数1行で終わる課題だからです。何行もかかるプログラムの時に効果を発揮します。

下の2つのケースではapply関数の後「あれ、小数点以下多すぎ!」となったので結果をそのまま%>%でつないでround関数を使おう!といった使い方ができます。

スクリーンショット 2019-02-05 0.57.27

スクリーンショット 2019-02-05 1.13.08

【2-1】Rのfor関数、apply関数を使ってまとめて標準偏差などの統計量を求める方法


2.既にある列を修正する

次は既にある列を修正します。

今回は以前も紹介した型の変更を行います。
このページの最初に使ったコードをパイプ演算子を使うと以下のようになります。

比較してみてください。
library(readxl)
data01 <- read_excel("data01.xlsx", sheet = "日本語")
data01$性別 <- factor(data01$性別, levels = c("男性","女性"))
data01$歩行 <- as.factor(data01$歩行)
head(data01)

library(tidyverse)
library(readxl)
data01 <- read_excel("data01.xlsx", sheet = "日本語")
data01 <- data01 %>% 
  mutate(性別 = factor(.$性別, levels = c("男性","女性"))) %>% 
  mutate(歩行 = as.factor(.$歩行))
head(data01)
スクリーンショット 2019-02-08 15.05.44

今回は型の修正だけなので、data01に上書きしました。

mutate関数の列の追加か修正は名前が既にあるものであれば「修正(上書き)」され、無いものであれば新しく列が追加されます。


まとめ

今回はmutate関数とパイプ演算子の使い方を練習しました。

修正はdata01$性別 <- 〇〇でもいいのですが、パイプ演算子でつなぎたい場合はmutate関数を使うと覚えておくとわかりやすいです。

mutate関数を使うと「FIMの合計点」とかだけでなく、年齢を「年代ごとに分類する」だったり、ある評価の「カットオフ値以上とそれ以下」に分けた列をExcelを使わずに作成することができます。

 次回もmutate関数を使ってそのような新しい列の作成を行っていきます。

↑このページのトップヘ