lapply()在数据框的多个列上使用函数

时间:2018-12-29 00:02:26

标签: r lapply

我正在跟踪一段时间内个体的体重,下面的函数使我可以计算相对于初始值(基本上是将特定天的体重除以除以第1天观察到的体重。

variability <- function(df, column_number) {
  variable_name <- paste0("var_BW", column_number)

   df %>% 
  mutate(!!variable_name := round(100*(df[,column_number]/df[1,column_number]), 1))

}

如果我在一列上使用此函数,它将很好用,但是由于我有很多人,所以我想使用apply()系列在一个数据帧的多个列上使用该函数(例如,在第1列上) :以下数据框的8:)

 BW1  BW2  BW3  BW4  BW5  BW6  BW7  BW8
1 18.4 19.6 20.7 17.4 18.7 18.9 19.0 17.8
2 18.1 19.3 20.0 17.5 18.3 19.4 19.5 18.0
3 17.7 18.9 20.4 17.3 18.3 19.2 19.3 17.9

我最初的猜测是将列号存储在列表中,然后将该列表作为参数传递给lapply()函数,例如:

l <- list(1:8)
lapply(working_df, variability, l)

但是,当我这样做时,出现以下错误:

Error in UseMethod("mutate_") : 
  no applicable method for 'mutate_' applied to an object of class "c('double', 'numeric')" 

有什么想法吗?

3 个答案:

答案 0 :(得分:0)

这合适吗?
由于可以对相对百分比部分进行矢量化处理,因此可以大大简化事情。

bw <- read.table(text="
 BW1  BW2  BW3  BW4  BW5  BW6  BW7  BW8
1 18.4 19.6 20.7 17.4 18.7 18.9 19.0 17.8
2 18.1 19.3 20.0 17.5 18.3 19.4 19.5 18.0
3 17.7 18.9 20.4 17.3 18.3 19.2 19.3 17.9", header=TRUE)

apply(bw, 2, function(x) round(100*x/x[1], 1))
#     BW1   BW2   BW3   BW4   BW5   BW6   BW7   BW8
# 1 100.0 100.0 100.0 100.0 100.0 100.0 100.0 100.0
# 2  98.4  98.5  96.6 100.6  97.9 102.6 102.6 101.1
# 3  96.2  96.4  98.6  99.4  97.9 101.6 101.6 100.6

或使用sweep()

round(sweep(bw, 2, unlist(bw[1,]), "/")*100, 1)
#     BW1   BW2   BW3   BW4   BW5   BW6   BW7   BW8
# 1 100.0 100.0 100.0 100.0 100.0 100.0 100.0 100.0
# 2  98.4  98.5  96.6 100.6  97.9 102.6 102.6 101.1
# 3  96.2  96.4  98.6  99.4  97.9 101.6 101.6 100.6

或更简单

round(100 * t(t(bw) / as.matrix(bw)[1,]), 1)
#     BW1   BW2   BW3   BW4   BW5   BW6   BW7   BW8
# 1 100.0 100.0 100.0 100.0 100.0 100.0 100.0 100.0
# 2  98.4  98.5  96.6 100.6  97.9 102.6 102.6 101.1
# 3  96.2  96.4  98.6  99.4  97.9 101.6 101.6 100.6

答案 1 :(得分:0)

在这种情况下,您实际上并不需要apply

pctvals <- round(100.0 * bw[,1:ncol(bw)] / bw[,1], 2)

收益

  BW1    BW2    BW3   BW4    BW5    BW6    BW7    BW8
1 100 106.52 112.50 94.57 101.63 102.72 103.26  96.74
2 100 106.63 110.50 96.69 101.10 107.18 107.73  99.45
3 100 106.78 115.25 97.74 103.39 108.47 109.04 101.13

答案 2 :(得分:0)

使用mutate_at软件包中的dplyr有一个非常简单的选择:

library(dplyr)

working_df <-
  data.frame(BW1 = c(18.4, 18.1, 17.7),
             BW2 = c(19.6, 19.3, 18.9),
             BW3 = c(20.7, 20.0, 20.4))

variability_v2 <- function(df, column_numbers) {

  df %>% 
    mutate_at(vars(column_numbers), funs(var = round(100*(./first(.)), 1)))

}

variability_v2(working_df, 1:3)
#>    BW1  BW2  BW3 BW1_var BW2_var BW3_var
#> 1 18.4 19.6 20.7   100.0   100.0   100.0
#> 2 18.1 19.3 20.0    98.4    98.5    96.6
#> 3 17.7 18.9 20.4    96.2    96.4    98.6

使用此方法的仅有2个(在我看来是非常小的问题):

  • 如果仅将单个列号输入到函数中,则新列将简称为“ var”
  • “ var”附加在列名之后,而不是之前

前者可以通过函数中的简单“ if”语句处理,从而消除了仅指定一列的情况。希望您不关心后者!