データフレームを1行ずつ処理をするときに役立つTipsメモです。
自習用に調べたことなので、入門者レベルかもしれません。ご了承ください。
for文を使い行ごとの処理をできますが、もう少しシンプルに(かつ自分にとってわかりやすい方法で)やりたいと考えました。
別の方法を見つけた場合は追加していきたいと思います。
rowwise
まず、tidyverseに含まれているdplyrパッケージで使えるrowwise。
データに、Rのサンプルとして付いている**「iris」**を使います。
iris
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
7 4.6 3.4 1.4 0.3 setosa
8 5.0 3.4 1.5 0.2 setosa
9 4.4 2.9 1.4 0.2 setosa
10 4.9 3.1 1.5 0.1 setosa
Sepal(がく片)、Petal(花弁)それぞれの平均を行ごとに計算し、mean_Sepal、mean_Pepa列を作成し配置しています。
iris %>%
as_tibble() %>% #tibble型のデータフレームに変換(なくても集計可)
rowwise() %>%
mutate(
mean_Sepal = mean(c(Sepal.Length, Sepal.Width)),
mean_Pepal = mean(c(Petal.Length, Petal.Width))
)
# A tibble: 150 x 7
# Rowwise:
Sepal.Length Sepal.Width Petal.Length Petal.Width Species mean_Sepal mean_Pepal
<dbl> <dbl> <dbl> <dbl> <fct> <dbl> <dbl>
1 5.1 3.5 1.4 0.2 setosa 4.3 0.8
2 4.9 3 1.4 0.2 setosa 3.95 0.8
3 4.7 3.2 1.3 0.2 setosa 3.95 0.75
4 4.6 3.1 1.5 0.2 setosa 3.85 0.85
5 5 3.6 1.4 0.2 setosa 4.3 0.8
6 5.4 3.9 1.7 0.4 setosa 4.65 1.05
7 4.6 3.4 1.4 0.3 setosa 4 0.85
8 5 3.4 1.5 0.2 setosa 4.2 0.85
9 4.4 2.9 1.4 0.2 setosa 3.65 0.8
10 4.9 3.1 1.5 0.1 setosa 4 0.8
# ... with 140 more rows
rowwiseコメントアウト
rowwiseがないとどうなるか?、確かめてみます。
rowwiseをコメントアウトすると、
iris %>%
as_tibble() %>% #tibble型のデータフレームに変換(なくても集計可)
#rowwise() %>%
mutate(
mean_Sepal = mean(c(Sepal.Length, Sepal.Width)),
mean_Pepal = mean(c(Petal.Length, Petal.Width))
)
# A tibble: 150 x 7
Sepal.Length Sepal.Width Petal.Length Petal.Width Species mean_Sepal mean_Pepal
<dbl> <dbl> <dbl> <dbl> <fct> <dbl> <dbl>
1 5.1 3.5 1.4 0.2 setosa 4.45 2.48
2 4.9 3 1.4 0.2 setosa 4.45 2.48
3 4.7 3.2 1.3 0.2 setosa 4.45 2.48
4 4.6 3.1 1.5 0.2 setosa 4.45 2.48
5 5 3.6 1.4 0.2 setosa 4.45 2.48
6 5.4 3.9 1.7 0.4 setosa 4.45 2.48
7 4.6 3.4 1.4 0.3 setosa 4.45 2.48
8 5 3.4 1.5 0.2 setosa 4.45 2.48
9 4.4 2.9 1.4 0.2 setosa 4.45 2.48
10 4.9 3.1 1.5 0.1 setosa 4.45 2.48
# ... with 140 more rows
となります。
行ごとの集計が行われず、mean_Sepal列にはSepal.Length列とSepal.Width列全体の平均値が並びます。
以下の集計と同じ値です。
mean(c(iris$Sepal.Length,iris$Sepal.Width))
[1] 4.450333
rowMeans
上記のように平均を求める場合は、rowMeansも使えます。
Rの基本パッケージ(標準R)に含まれる関数です。
iris %>%
as_tibble() %>% #tibble型のデータフレームに変換(なくても集計可)
mutate(
mean_Sepal = rowMeans(iris[,c(1,2)]), #1列目と2列目を指定
mean_Pepal = rowMeans(iris[,c(3,4)]) #3列目と4列目を指定
)
# A tibble: 150 x 7
Sepal.Length Sepal.Width Petal.Length Petal.Width Species mean_Sepal mean_Pepal
<dbl> <dbl> <dbl> <dbl> <fct> <dbl> <dbl>
1 5.1 3.5 1.4 0.2 setosa 4.3 0.8
2 4.9 3 1.4 0.2 setosa 3.95 0.8
3 4.7 3.2 1.3 0.2 setosa 3.95 0.75
4 4.6 3.1 1.5 0.2 setosa 3.85 0.85
5 5 3.6 1.4 0.2 setosa 4.3 0.8
6 5.4 3.9 1.7 0.4 setosa 4.65 1.05
7 4.6 3.4 1.4 0.3 setosa 4 0.85
8 5 3.4 1.5 0.2 setosa 4.2 0.85
9 4.4 2.9 1.4 0.2 setosa 3.65 0.8
10 4.9 3.1 1.5 0.1 setosa 4 0.8
# ... with 140 more rows
行の和を計算する場合はrowSumsを使います。
apply
よく使われる関数applyでもできます。
こちらも標準Rに含まれています。
iris %>%
as_tibble() %>% #tibble型のデータフレームに変換(なくても集計可)
mutate(
mean_Sepal = apply(iris[, c("Sepal.Length", "Sepal.Width")], 1, mean),
mean_Pepal = apply(iris[, c("Petal.Length", "Petal.Width")], 1, mean)
) #applyの中の2番目の引数は、1は各行を毎意味する(2は各列を意味する)
# A tibble: 150 x 7
Sepal.Length Sepal.Width Petal.Length Petal.Width Species mean_Sepal mean_Pepal
<dbl> <dbl> <dbl> <dbl> <fct> <dbl> <dbl>
1 5.1 3.5 1.4 0.2 setosa 4.3 0.8
2 4.9 3 1.4 0.2 setosa 3.95 0.8
3 4.7 3.2 1.3 0.2 setosa 3.95 0.75
4 4.6 3.1 1.5 0.2 setosa 3.85 0.85
5 5 3.6 1.4 0.2 setosa 4.3 0.8
6 5.4 3.9 1.7 0.4 setosa 4.65 1.05
7 4.6 3.4 1.4 0.3 setosa 4 0.85
8 5 3.4 1.5 0.2 setosa 4.2 0.85
9 4.4 2.9 1.4 0.2 setosa 3.65 0.8
10 4.9 3.1 1.5 0.1 setosa 4 0.8
# ... with 140 more rows
rowMeansで使ったように列番号指定でもできます。
iris %>%
as_tibble() %>% #tibble型のデータフレームに変換(なくても集計可)
mutate(
mean_Sepal = apply(iris[, c(1,2)], 1, mean),
mean_Pepal = apply(iris[, c(3,4)], 1, mean)
)
# A tibble: 150 x 7
Sepal.Length Sepal.Width Petal.Length Petal.Width Species mean_Sepal mean_Pepal
<dbl> <dbl> <dbl> <dbl> <fct> <dbl> <dbl>
1 5.1 3.5 1.4 0.2 setosa 4.3 0.8
2 4.9 3 1.4 0.2 setosa 3.95 0.8
3 4.7 3.2 1.3 0.2 setosa 3.95 0.75
4 4.6 3.1 1.5 0.2 setosa 3.85 0.85
5 5 3.6 1.4 0.2 setosa 4.3 0.8
6 5.4 3.9 1.7 0.4 setosa 4.65 1.05
7 4.6 3.4 1.4 0.3 setosa 4 0.85
8 5 3.4 1.5 0.2 setosa 4.2 0.85
9 4.4 2.9 1.4 0.2 setosa 3.65 0.8
10 4.9 3.1 1.5 0.1 setosa 4 0.8
# ... with 140 more rows
map
mapは、purrrパッケージを利用すると使えます。
purrrも、先述のdplyr同様、tidyverseに含まれています。
まだ調べ中なので、Sepal(がく片)、Petal(花弁)それぞれ個別に集計しています。
もっと効率よくできそうでです。
手順としては、集計対処の列を**ネスト(nest)**して、リスト型のデータとして格納します。
計算後、ネストを解除(unnnest)してリストを展開することで、列に切り替えています。
map関数を使うことで、行単位で指定した計算をしてくれます。
ただし、計算対象はリスト型で、リスト全体をまとめて集計するようなので、「Sepal(がく片)の列だけ取り出してmapで処理」「、Petal(花弁)列だけ取り出してmapで処理」と、今の時点では分けています。
# Sepal(がく片)
iris %>%
as_tibble() %>%
select(1, 2) %>%
rowid_to_column("id") %>% #nest(畳み込み)しやすいように行番号を振る
group_nest(id) %>% #行番号でnest
mutate(mean = map(data, ~ mean(unlist(.x)))) %>% #「~」&「.x」が直前に指定した列を指定する
unnest(cols = c(data, mean)) #nestを解除
# A tibble: 150 x 4
id Sepal.Length Sepal.Width mean
<int> <dbl> <dbl> <dbl>
1 1 5.1 3.5 4.3
2 2 4.9 3 3.95
3 3 4.7 3.2 3.95
4 4 4.6 3.1 3.85
5 5 5 3.6 4.3
6 6 5.4 3.9 4.65
7 7 4.6 3.4 4
8 8 5 3.4 4.2
9 9 4.4 2.9 3.65
10 10 4.9 3.1 4
# ... with 140 more rows
iris2 <-
iris %>%
as_tibble() %>%
select(3, 4) %>%
rowid_to_column("id") %>% #nest(畳み込み)しやすいように行番号を振る
group_nest(id) %>% #行番号でnest
mutate(mean = map(data, ~ mean(unlist(.x)))) %>%
unnest(cols = c(data, mean)) #nestを解除
# A tibble: 150 x 4
id Petal.Length Petal.Width mean
<int> <dbl> <dbl> <dbl>
1 1 1.4 0.2 0.8
2 2 1.4 0.2 0.8
3 3 1.3 0.2 0.75
4 4 1.5 0.2 0.85
5 5 1.4 0.2 0.8
6 6 1.7 0.4 1.05
7 7 1.4 0.3 0.85
8 8 1.5 0.2 0.85
9 9 1.4 0.2 0.8
10 10 1.5 0.1 0.8
# ... with 140 more rows
了