LoginSignup
1
1

More than 1 year has passed since last update.

R言語でデータフレームを1行ずつ計算【1】

Last updated at Posted at 2022-02-05

データフレームを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

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1