【问题标题】:How to use variables names as stored in a vector without the quotation marks?如何使用存储在不带引号的向量中的变量名称?
【发布时间】:2020-09-22 18:59:55
【问题描述】:

我想创建一个循环,将多个变量的 t 检验输出存储在数据框中。但是当我将不同的变量存储在带引号的向量中时,这些变量不能用于 t 检验,因为它们是用引号保存的。例如,R 将第一个变量作为循环中的“variable_1”,这会产生错误,因为对于 t 检验,我需要不带引号的变量,例如t.test(variable_1 ~ Gender)。有人知道如何去掉向量中变量名称的引号吗?

variable <- c("variable_1", "variable_2", "variable_3") 
df <- data.frame(t_value=as.numeric(), 
                 df=as.numeric(),
                 p_value= as.numeric(), 
                 mean_f= as.numeric(),
                 mean_m= as.numeric())
attach(data)
for(v in variable){
  output <- t.test(v ~ Gender)
  values <- output[c(1,2,3,5)]
  row <- round(unlist(values, use.names = FALSE),3)
  df <- rbind(df, row)
}

【问题讨论】:

  • 我知道有些课程和教程仍然建议使用attach,但我还没有找到增加安全性或结构的情况;几乎所有时间,它都会在用户的脑海中和语言本身中产生歧义。我强烈建议您学习如何在没有它的情况下进行操作。
  • MWE 中缺少性别。同上没有附加
  • 要“去掉引号”,你需要非标准的评估。 advanced R中给出了很好的介绍
  • 如果其中一个答案解决了您的问题,请accept it;这样做不仅为回答者提供了一些积分,而且还为有类似问题的读者提供了一些关闭。尽管您只能接受一个答案,但您可以选择对您认为有帮助的人进行投票。 (如果仍有问题,您可能需要编辑您的问题并提供更多详细信息。)
  • 感谢所有有用的 cmets!我不知道使用 attach 有缺点,但我肯定会停止使用它。

标签: r loops variable-names


【解决方案1】:

这是一种更现代的方法,采用非标准评估和purrr。我已将循环的逻辑放入一个函数中,该函数为variable 的每个条目调用。在函数内部,v 的值(一个字符串)被转换为一个符号。这是你的变量名。然后在为t.testdata 参数提供的data.frame 的上下文中评估此变量。

library(purrr)

variable <- c("variable_1", "variable_2", "variable_3") 

calc_fun <- function(v, input_data) {
  output <- t.test(eval(rlang::sym(v)) ~ Gender, data = input_data)
  values <- output[c(1,2,3,5)]
  values <- round(unlist(values, use.names = FALSE),3)
  data.frame(t_values = values[1],
             df = values[2],
             p_value = values[3],
             mean_f = values[4],
             mean_m = values[5])
}

df <- map_dfr(variable, ~calc_fun(v = .x, input_data = data))

使用@Chuck P 的示例,我的方法如下所示:

df <- map_dfr(variable, ~calc_fun(v = .x, input_data = data))

variable <- c("mpg", "hp")

calc_fun <- function(v, input_data) {
  output <- t.test(eval(rlang::sym(v)) ~ am, data = input_data)
  values <- output[c(1,2,3,5)]
  values <- round(unlist(values, use.names = FALSE),3)
  data.frame(t_values = values[1],
             df = values[2],
             p_value = values[3],
             mean_f = values[4],
             mean_m = values[5])
}

df <- map_dfr(variable, ~calc_fun(v = .x, input_data = mtcars))
df
  t_values     df p_value  mean_f  mean_m
1   -3.767 18.332   0.001  17.147  24.392
2    1.266 18.715   0.221 160.263 126.846

【讨论】:

    【解决方案2】:

    这里有一些更改可以使它通过get 工作。正如其他人指出的那样,attach 在这种情况下是一个糟糕的主意。所以我以mtcars 为例,省略了。

    其他几项更改以使事情尽可能好。在对多个变量运行 t 检验或仅使用 @starja 或 @r2evans 答案时,您最好在堆栈中搜索大量答案。

    variable <- c("mpg", "hp") 
    df <- data.frame(t_value=as.numeric(), 
                     df=as.numeric(),
                     p_value= as.numeric(), 
                     mean_f= as.numeric(),
                     mean_m= as.numeric())
    
    for(v in variable){
       output <- t.test(get(v) ~ am, data = mtcars)
       values <- output[c(1,2,3,5)]
       row <- round(unlist(values, use.names = FALSE), 3)
       df_row <- data.frame(t_value=row[[1]],
                            df=row[[2]],
                            p_value= row[[3]],
                            mean_f= row[[4]],
                            mean_m= row[[5]])
    
       df <- rbind(df, df_row)
    }
    df
    #>   t_value     df p_value  mean_f  mean_m
    #> 1  -3.767 18.332   0.001  17.147  24.392
    #> 2   1.266 18.715   0.221 160.263 126.846
    

    【讨论】:

      【解决方案3】:

      如果您需要将一个变量与一帧中的所有(或某些)其他变量进行比较,那么可以这样:

      vars <- c("cyl", "disp", "hp", "gear")
      do.call(
        rbind.data.frame,
        lapply(setNames(nm = vars), function(nm) {
          out <- t.test(mtcars[["mpg"]], mtcars[[nm]])
          c(out[c(1, 2, 3)], out[[5]])
        })
      )
      #      statistic parameter      p.value mean.of.x mean.of.y
      # cyl   12.51163  36.40239 9.507708e-15  20.09062    6.1875
      # disp  -9.60236  31.14661 7.978234e-11  20.09062  230.7219
      # hp   -10.40489  31.47905 1.030354e-11  20.09062  146.6875
      # gear  15.28179  31.92893 3.077106e-16  20.09062    3.6875
      

      如果您需要比较不同的配对(不仅仅是一对一),那么可能是这样的

      vars <- c("mpg", "cyl", "disp", "hp", "gear")
      eg <- expand.grid(vars, vars, stringsAsFactors = FALSE)
      eg <- eg[ eg[,1] != eg[,2], ]
      head(eg)
      #   Var1 Var2
      # 2  cyl  mpg
      # 3 disp  mpg
      # 4   hp  mpg
      # 5 gear  mpg
      # 6  mpg  cyl
      # 8 disp  cyl
      
      ret <- do.call(
        rbind.data.frame,
        Map(function(x, y) {
          out <- t.test(x, y)
          c(out[c(1, 2, 3)], out[[5]])
        }, mtcars[eg[,1]], mtcars[eg[,2]])
      )
      ret <- cbind(eg, ret)
      head(ret)
      #   Var1 Var2 statistic parameter      p.value mean.of.x mean.of.y
      # 2  cyl  mpg -12.51163  36.40239 9.507708e-15   6.18750  20.09062
      # 3 disp  mpg   9.60236  31.14661 7.978234e-11 230.72188  20.09062
      # 4   hp  mpg  10.40489  31.47905 1.030354e-11 146.68750  20.09062
      # 5 gear  mpg -15.28179  31.92893 3.077106e-16   3.68750  20.09062
      # 6  mpg  cyl  12.51163  36.40239 9.507708e-15  20.09062   6.18750
      # 8 disp  cyl  10.24721  31.01287 1.774454e-11 230.72188   6.18750
      
      
      ---
      
      Note:
      
      1. Iteratively build a frame row-by-row works fine logically and in small doses, but in the long run it performs very poorly: it makes a complete copy of the whole frame with each row, which is memory-inefficient (and slow).
      
      2. The use of `attach` is discouraged, as I said in my comment. Also, `get` should be avoided as well, though perhaps to a lesser degree than `attach`.
      

      【讨论】:

      • 感谢您的评论!不幸的是,当我尝试您的第一个示例时出现问题。我没有收到错误消息,但输出不正确(例如,所有变量的 y 均值相同,尽管我想计算男性的均值)。我已将您的建议应用于我的数据,如下所示:do.call(rbind.data.frame, lapply(setNames(nm = vars), function(nm) { out
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-20
      • 1970-01-01
      相关资源
      最近更新 更多