for循环在R中运行

for loop to function in R

我正在尝试将 for 循环转换为函数。预期的结果是 Summ.Stats。任何帮助将不胜感激,以便以 b.

的函数格式获得预期结果 (Summ.Stats)
CN = colnames(mtcars);CN
var <- c("vs", "am")

Summ.Stats <- NULL
library(psych)

for (i in 1:(length(var))) {
  
  temp <- which(CN == var[i])
  
  aux.0 <- mtcars  %>% filter(mtcars[,temp]==0)
  aux.1 <- mtcars %>% filter(mtcars[,temp]==1)
  fname.0 <- paste0(paste(var[i], "0", sep = "_"))
  fname.1 <- paste0(paste(var[i], "1", sep = "_"))
  Summ.0 <- describe(aux.0)
  Summ.1 <- describe(aux.1)
  tab <- round(cbind(Summ.0$mean, Summ.1$mean), 4)
  rownames(tab) <- colnames(aux.0)
  colnames(tab) <- c(fname.0, fname.1)
  Summ.Stats [[i]] <- tab
}
Summ.Stats #EXPECTED OUTCOME

我试过的是以下;

Summ.Stats <- NULL
my.function <- function(var, df){
  
  df <- df[, !sapply(df, is.character)]#REMOVE THE CHARACTER COLUMNS
  CN = colnames(df)  
  
  for (i in 1:length(var)) {
    temp <- which(CN == var[i])
    #
    res <- split(df, df[,temp])
    names(res) <- paste(var[i], names(res), sep = ".") 
    return(res) }
    
    for (j in 1:length(res)){
      tab <- describe(res[[j]]) #here the mean of res[[1]] and res[[2]] should be saved
      Summ.Stats [[j]] <- tab
      return(Summ.Stats)
    }
  }

b <- my.function(var, mtcars);b #only shows vs.0 and vs.1

我在这里很懒,但乍一看可能是因为你写的地方 return,试试:

my.function <- function(var, df){
  
  df <- df[, !sapply(df, is.character)]#REMOVE THE CHARACTER COLUMNS
  CN = colnames(df)  
  
  for (i in 1:length(var)) {
    temp <- which(CN == var[i])
    #
    res <- split(df, df[,temp])
    names(res) <- paste(var[i], names(res), sep = ".") 
    }
    
    for (j in 1:length(res)){
      tab <- describe(res[[j]]) #here I need to save mean res[[1]] and res[[2]]
      Summ.Stats [[j]] <- tab
    } 
   return(Summ.Stats)
  }

一些建议:

  • 注意 return 在正确的地方,return 在每个 for 循环的末尾都是不对的
  • 尝试了解您正在增长的对象,res 在您的循环中每次都被新值擦除,在测试前一个之前不要编写下一步
  • 不要在不需要时相互转换数字、字符、逻辑索引
  • 可以在名称上循环时不要在数字索引上循环,如果可以直接在项目上循环就不要在名称上循环。
  • 尽可能学习使用 lapply 而不是 for 循环
  • 在你的函数中使用 browser() 来了解你在做什么。
  • 如果可能,将数据参数放在首位(我不会在下面这样做来重现您请求的输出)
  • 玩得开心:)

我想你想要以下内容

my.function <- function(var, df){
  df <- Filter(is.numeric, df) 
  lapply(var, function(nm) {
    # browser() # uncomment, run and print objects to understand what these steps do
    split_data <- split(df, df[[nm]])
    cols <- lapply(split_data, function(x) psych::describe(x)["mean"])
    df <- do.call(cbind, cols)
    names(df) <- paste(nm, names(split_data), sep = ".")
    df
  })
}
my.function(c("vs", "am"), mtcars)
#> [[1]]
#>             vs.0       vs.1
#> mpg   16.6166667  24.557143
#> cyl    7.4444444   4.571429
#> disp 307.1500000 132.457143
#> hp   189.7222222  91.357143
#> drat   3.3922222   3.859286
#> wt     3.6885556   2.611286
#> qsec  16.6938889  19.333571
#> vs     0.0000000   1.000000
#> am     0.3333333   0.500000
#> gear   3.5555556   3.857143
#> carb   3.6111111   1.785714
#> 
#> [[2]]
#>             am.0        am.1
#> mpg   17.1473684  24.3923077
#> cyl    6.9473684   5.0769231
#> disp 290.3789474 143.5307692
#> hp   160.2631579 126.8461538
#> drat   3.2863158   4.0500000
#> wt     3.7688947   2.4110000
#> qsec  18.1831579  17.3600000
#> vs     0.3684211   0.5384615
#> am     0.0000000   1.0000000
#> gear   3.2105263   4.3846154
#> carb   2.7368421   2.9230769

reprex package (v2.0.1)

于 2021-11-22 创建

另一种方法 - 使用一些点并完全避免 psych 包。

data <- mtcars

b <- function(df, ...){
  m <- function(y, z) df[df[[y]] == z,] |> colMeans()
  args <- as.list(match.call()[-c(1L, 2L)])
  lapply(args, \(.){
    cbind(m(., 0), m(., 1)) |>  # if you want a data.frame use cbind.data.frame instead
      (\(x) {colnames(x) <- paste0(c(., .), c("_1", "_2")) ; x})()
  }) |>
    lapply(round, 4)
}
b(data, vs, am)

#> [[1]]
#>          vs_1     vs_2
#> mpg   16.6167  24.5571
#> cyl    7.4444   4.5714
#> disp 307.1500 132.4571
#> hp   189.7222  91.3571
#> drat   3.3922   3.8593
#> wt     3.6886   2.6113
#> qsec  16.6939  19.3336
#> vs     0.0000   1.0000
#> am     0.3333   0.5000
#> gear   3.5556   3.8571
#> carb   3.6111   1.7857
#> 
#> [[2]]
#>          am_1     am_2
#> mpg   17.1474  24.3923
#> cyl    6.9474   5.0769
#> disp 290.3789 143.5308
#> hp   160.2632 126.8462
#> drat   3.2863   4.0500
#> wt     3.7689   2.4110
#> qsec  18.1832  17.3600
#> vs     0.3684   0.5385
#> am     0.0000   1.0000
#> gear   3.2105   4.3846
#> carb   2.7368   2.9231

说明 - 在检查 psych::describe() 时,它运行了一堆我们在输出中不需要的函数。相反,我们可以做的是创建一个辅助函数 m 对数据进行子集化并直接计算列均值,保留名称。要处理任意数量的变量,使用列表通常是个好主意,即使用 lapplypurrr::map 风格的方法,这有利于简洁的语法。