【问题标题】:for loop to function in R [closed]for循环在R中起作用[关闭]
【发布时间】:2022-01-01 03:23:13
【问题描述】:

我正在尝试将 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 语句移出您的 for 循环。在 mkoment,您在第一个 for 循环的第一次迭代期间从 my.function 返回。

标签: r function for-loop data-manipulation


【解决方案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)
  }

【讨论】:

  • 这段代码恐怕还有很多问题
【解决方案2】:

一些建议:

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

我认为您想要以下内容

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 日创建

【讨论】:

    【解决方案3】:

    另一种方法 - 使用一些点并完全避免使用 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 风格的方法,这使得语法简洁。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-21
      • 2020-08-03
      • 1970-01-01
      • 2011-04-08
      • 2018-05-02
      • 1970-01-01
      • 1970-01-01
      • 2016-01-18
      相关资源
      最近更新 更多