构建具有矢量化函数的新 Dataframe

bf1o4zei  于 2023-07-31  发布在  其他
关注(0)|答案(2)|浏览(106)

我试图通过跨几列执行重复计算,从现有的数据框架构建新的数据框架。目前我有一个解决方案,看起来像这样:

library(tidyverse)

iris_avg <- data.frame(SLength = colMeans(matrix(iris$Sepal.Length, nrow = 10)),
                       SWidth = colMeans(matrix(iris$Sepal.Width, nrow = 10)),
                       PLength = colMeans(matrix(iris$Petal.Length, nrow = 10)),
                       PWidth = colMeans(matrix(iris$Petal.Width, nrow = 10)))
> iris_avg
   SLength SWidth PLength PWidth
1     4.86   3.31    1.45   0.22
2     5.21   3.65    1.42   0.25
3     5.01   3.39    1.55   0.27
4     5.07   3.46    1.42   0.20
5     4.88   3.33    1.47   0.29
6     6.10   2.87    4.37   1.38
7     5.85   2.65    4.14   1.27
8     6.26   2.85    4.49   1.41
9     5.83   2.75    4.27   1.34
10    5.64   2.73    4.03   1.23
11    6.57   2.94    5.77   2.04
12    6.55   2.90    5.54   2.05
13    6.63   2.96    5.50   1.93
14    6.74   3.04    5.62   1.94
15    6.45   3.03    5.33   2.17

字符串
我觉得应该有一个简单的方法来使用lapply或map之类的东西,但我一直在努力让它工作,因为我是R的新手。任何建议将不胜感激!

44u64gxh

44u64gxh1#

你可以把它压缩到一行代码中,在基类R中:

as.data.frame(lapply(iris[1:4], \(x) sapply(split(x, 0:149 %/% 10), mean)))
#>    Sepal.Length Sepal.Width Petal.Length Petal.Width
#> 0          4.86        3.31         1.45        0.22
#> 1          5.21        3.65         1.42        0.25
#> 2          5.01        3.39         1.55        0.27
#> 3          5.07        3.46         1.42        0.20
#> 4          4.88        3.33         1.47        0.29
#> 5          6.10        2.87         4.37        1.38
#> 6          5.85        2.65         4.14        1.27
#> 7          6.26        2.85         4.49        1.41
#> 8          5.83        2.75         4.27        1.34
#> 9          5.64        2.73         4.03        1.23
#> 10         6.57        2.94         5.77        2.04
#> 11         6.55        2.90         5.54        2.05
#> 12         6.63        2.96         5.50        1.93
#> 13         6.74        3.04         5.62        1.94
#> 14         6.45        3.03         5.33        2.17

字符串
下面的解释会使这一点更加清楚。我们可以定义一个函数来代替匿名函数,它接受一个向量(或 Dataframe 列),将其分割成长度为10的块,并使用sapply来获得单个向量中每个块的平均值:

mean_of_every_10_items <- function(x) {
  
  groups_numbers <- (seq_along(x) - 1) %/% 10
  
  groups_of_10 <- split(x, group_numbers)
    
  return(sapply(groups_of_10, mean))
}


我们可以使用lapply将这个函数应用到iris的每个数值列上,以获得一个包含我们函数在每个列上的结果的列表。作为最后一步,我们将这个列表转换回数据框:

iris[1:4] |>
  lapply(mean_of_every_10_items) |>
  as.data.frame()
#>    Sepal.Length Sepal.Width Petal.Length Petal.Width
#> 0          4.86        3.31         1.45        0.22
#> 1          5.21        3.65         1.42        0.25
#> 2          5.01        3.39         1.55        0.27
#> 3          5.07        3.46         1.42        0.20
#> 4          4.88        3.33         1.47        0.29
#> 5          6.10        2.87         4.37        1.38
#> 6          5.85        2.65         4.14        1.27
#> 7          6.26        2.85         4.49        1.41
#> 8          5.83        2.75         4.27        1.34
#> 9          5.64        2.73         4.03        1.23
#> 10         6.57        2.94         5.77        2.04
#> 11         6.55        2.90         5.54        2.05
#> 12         6.63        2.96         5.50        1.93
#> 13         6.74        3.04         5.62        1.94
#> 14         6.45        3.03         5.33        2.17


“一行程序”版本也做了同样的事情,但要看清它在做什么就困难多了。
创建于2023-07-17带有reprex v2.0.2

iqih9akk

iqih9akk2#

在tidyverse中:

library(tidyverse)

 iris %>%
   reframe(across(-Species, ~colMeans(matrix(.x, 10))))
   Sepal.Length Sepal.Width Petal.Length Petal.Width
1          4.86        3.31         1.45        0.22
2          5.21        3.65         1.42        0.25
3          5.01        3.39         1.55        0.27
4          5.07        3.46         1.42        0.20
5          4.88        3.33         1.47        0.29
6          6.10        2.87         4.37        1.38
7          5.85        2.65         4.14        1.27
8          6.26        2.85         4.49        1.41
9          5.83        2.75         4.27        1.34
10         5.64        2.73         4.03        1.23
11         6.57        2.94         5.77        2.04
12         6.55        2.90         5.54        2.05
13         6.63        2.96         5.50        1.93
14         6.74        3.04         5.62        1.94
15         6.45        3.03         5.33        2.17

字符串
另一种基于R的方法是找到正确的分组并在tapply中使用:

x <- data.matrix(iris[-5])
tapply(x, list((row(x) -1 ) %/% 10, col(x)), mean)

      1    2    3    4
0  4.86 3.31 1.45 0.22
1  5.21 3.65 1.42 0.25
2  5.01 3.39 1.55 0.27
3  5.07 3.46 1.42 0.20
4  4.88 3.33 1.47 0.29
5  6.10 2.87 4.37 1.38
6  5.85 2.65 4.14 1.27
7  6.26 2.85 4.49 1.41
8  5.83 2.75 4.27 1.34
9  5.64 2.73 4.03 1.23
10 6.57 2.94 5.77 2.04
11 6.55 2.90 5.54 2.05
12 6.63 2.96 5.50 1.93
13 6.74 3.04 5.62 1.94
14 6.45 3.03 5.33 2.17


另一种使用sapply + split的方法

t(sapply(split(iris[-5], gl(nrow(iris)/10, 10)), colMeans))

   Sepal.Length Sepal.Width Petal.Length Petal.Width
1          4.86        3.31         1.45        0.22
2          5.21        3.65         1.42        0.25
3          5.01        3.39         1.55        0.27
4          5.07        3.46         1.42        0.20
5          4.88        3.33         1.47        0.29
6          6.10        2.87         4.37        1.38
7          5.85        2.65         4.14        1.27
8          6.26        2.85         4.49        1.41
9          5.83        2.75         4.27        1.34
10         5.64        2.73         4.03        1.23
11         6.57        2.94         5.77        2.04
12         6.55        2.90         5.54        2.05
13         6.63        2.96         5.50        1.93
14         6.74        3.04         5.62        1.94
15         6.45        3.03         5.33        2.17

相关问题