各個体ごとに測定データの出現回数をカウントしたい
データフレームの行ごとに(apply(..., 1, ...)
)測定データ(seq(1, 5)
)の出現回数を集計します(sapply(seq(1, 5), ...)
)。
r
1df <- data.frame(
2 No = 1:10,
3 `1回目` = c(1, 1, 3, 1, 4, 1, 4, NA, 4, 3),
4 `2回目` = c(NA, 2, NA, 3, 3, 1, 1, NA, 4, 3),
5 `3回目` = c(NA, NA, NA, NA, 4, 1, 3, NA, 1, NA),
6 `4回目` = c(NA, NA, NA, NA, 3, NA, NA, NA, NA, NA),
7 `5回目` = c(NA, NA, NA, NA, 1, NA, NA, NA, NA, NA),
8 check.names = FALSE
9)
10
11#
12df <- cbind(df, t(apply(df[,2:6], 1, \(x) sapply(1:5, \(a, b) sum(a==b, na.rm=T), x))))
13df
14
15# No 1回目 2回目 3回目 4回目 5回目 1 2 3 4 5
16# 1 1 1 NA NA NA NA 1 0 0 0 0
17# 2 2 1 2 NA NA NA 1 1 0 0 0
18# 3 3 3 NA NA NA NA 0 0 1 0 0
19# 4 4 1 3 NA NA NA 1 0 1 0 0
20# 5 5 4 3 4 3 1 1 0 2 2 0
21# 6 6 1 1 1 NA NA 3 0 0 0 0
22# 7 7 4 1 3 NA NA 1 0 1 1 0
23# 8 8 NA NA NA NA NA 0 0 0 0 0
24# 9 9 4 4 1 NA NA 1 0 0 2 0
25# 10 10 3 3 NA NA NA 0 0 2 0 0
追記
①cbindの第二引数、apply前の「t」です。
tは各1〜5の作成された列が入る変数を表している?
t は transpose(転置)関数です。例えば以下では 2x3 行列を 3x2 行列に変換しています。
> a <- matrix(1:6, 2, 3)
> a
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
> t(a)
[,1] [,2]
[1,] 1 2
[2,] 3 4
[3,] 5 6
なぜこの様なことをしているかと言うと、apply(..., 1, ...)
で返るデータフレームが5行10列になっているので、転置して10行5列のデータフレームにしないと元のデータフレーム(df
: 10行6列)と結合できないからです。
②「t(apply(df[,2:6],~」」の「df[,2~」でなぜ「,」が必要か?
すでにdfでデータフレームを指定しているので、何の引数を省略しているのでしょうか。
df[,2:6]
という表記は「df
の(全ての行の)2列目から6列目」を指しています。df[行範囲, 列範囲]
という表記で取り出す部分を指定することができますが、範囲を省略すると全ての行、もしくは全ての列として処理されます。例えば df[1:5,]
は「df
の1行目から5行目(までの全ての列)」を指します。また、行や列の指定にはラベルを指定することもできます。例えば df[,c("2回目", "3回目", "4回目")]
は「df
の"2回目"列, "3回目"列, "4回目"列」を取り出します。
③バックスラッシュで整数を文字列下していることは分かりました。
「~ (x) sapply(1:5, \~」のsapplyの前にある「(x)」ですが、
変数列名をつくるための変数?これにより各行の変数を示している?
バックスラッシュですが、これは R 4.1.0 から追加された表記方法で、無名関数(anonymous function)を表しています。なので、(x)
や (a, b)
は関数パラメータになります。
# R 4.1.0 以降(function(...) ~ 表記でも可)
df <- cbind(df, t(apply(df[,2:6], 1, \(x) sapply(1:5, \(a, b) sum(a==b, na.rm=T), x))))
# R 4.1.0 よりも前のバージョン
df <- cbind(df, t(apply(df[,2:6], 1, function(x) sapply(1:5, function(a, b) sum(a==b, na.rm=T), x))))
④「~(a, b) sum(a==b,~」でなぜ、1~5がにaとbに代入されていくのか?
このように前に変数を置く構文がはじめてです。もう少し探してみます。
⑤「~sum(a==b, na.rm=T), x)~」のxは何をしているのか?
この構文のxに意味することがわかりません。
具体的に、5行目のデータでの処理を見てみます。
# 5行目(No == 5)の1回目から5回目の測定データ
c(4, 3, 4, 3, 1)
# \(x) の x に c(4, 3, 4, 3, 1) が渡されます
apply(..., 1, \(c(4, 3, 4, 3, 1)) sapply(1:5, \(a, b) sum(a==b, na.rm=T), x)
# 次に sapply の引数である x が c(4, 3, 4, 3, 1) になります
sapply(1:5, \(a, b) sum(a==b, na.rm=T), c(4, 3, 4, 3, 1))
# 無名関数のパラメータとして 1:5 と c(4, 3, 4, 3, 1) が渡されることになりますが、
# パラメータ a にはそれぞれ 1 から 5 まで渡されて、パラメータ b は全て c(4, 3, 4, 3, 1)
# になります
\(1, c(4, 3, 4, 3, 1)) sum(a==b, na.rm=T)
\(2, c(4, 3, 4, 3, 1)) sum(a==b, na.rm=T)
\(3, c(4, 3, 4, 3, 1)) sum(a==b, na.rm=T)
\(4, c(4, 3, 4, 3, 1)) sum(a==b, na.rm=T)
\(5, c(4, 3, 4, 3, 1)) sum(a==b, na.rm=T)
# 最終的に以下が実行されることになります
sum(1==c(4, 3, 4, 3, 1), na.rm=T) => 1
sum(2==c(4, 3, 4, 3, 1), na.rm=T) => 0
sum(3==c(4, 3, 4, 3, 1), na.rm=T) => 2
sum(4==c(4, 3, 4, 3, 1), na.rm=T) => 2
sum(5==c(4, 3, 4, 3, 1), na.rm=T) => 0
# ここで、数値とベクタを比較すると logical型のベクタが返ります
> 1==c(4, 3, 4, 3, 1)
[1] FALSE FALSE FALSE FALSE TRUE
> 3==c(4, 3, 4, 3, 1)
[1] FALSE TRUE FALSE TRUE FALSE
# そして sum() 関数では TRUE は整数の 1, FALSE は 0 として集計されます。
> sum(1==c(4, 3, 4, 3, 1))
[1] 1
> sum(3==c(4, 3, 4, 3, 1))
[1] 2
以上の処理が1行目から10行目までのそれぞれの行で実行されます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2024/07/14 02:31 編集
2024/07/14 18:39
2024/07/15 05:52