【问题标题】:How to use apply for functions that need "data$varname" vs functions that need just "varname"如何使用申请需要“data$varname”的函数与只需要“varname”的函数
【发布时间】:2020-12-10 14:54:54
【问题描述】:

这里相对较新的 R 用户一直在努力提高代码的未来使用效率,主要是尝试应用系列中的功能。

现在,我有一个脚本,通过(手动)创建变量名称列表并将其传递给 sapply,我从大量变量中提取方法。

所以这是我如何制作变量名列表以及如何将其传递给 sapply 的示例

vars <- c("data$age", "data$gender", "data$PCLR")
means <- sapply(vars, fmean, data$group, na.rm=TRUE)

但是,我现在想使用一个使用 function(varname, data) 的参数格式的函数,所以我实际上不能使用我创建的名称列表。我正在尝试做的事情:

krusk <- sapply(vars, function(x) kruskal.test(x ~ group, data))

我觉得有一种方法可以将我的变量名传递给我完全忽略的函数,而不是手动创建列表。有人有什么建议吗?

【问题讨论】:

  • 使用reformulate将字符串转换为公式:kruskal.test(reformulate('group', x), data)

标签: r apply sapply


【解决方案1】:

这可以使用 iris 数据集作为 data 工作,类似于 @deschen 的好建议:

#Vars
vars <- c("Sepal.Length", "Sepal.Width")
#Code
krusk <- sapply(vars, function(x) kruskal.test(iris[[x]] ~ iris[['Species']]))

输出:

krusk
          Sepal.Length                     Sepal.Width                     
statistic 96.93744                         63.57115                        
parameter 2                                2                               
p.value   8.918734e-22                     1.569282e-14                    
method    "Kruskal-Wallis rank sum test"   "Kruskal-Wallis rank sum test"  
data.name "iris[[x]] by iris[["Species"]]" "iris[[x]] by iris[["Species"]]"

【讨论】:

  • 我的实际上没有工作。我也可能弄错了,但我阅读 TOs 问题的方式是,vars 向量的要求仍然是它包含数据对象 + 名称,因此在您的示例中为 vars &lt;- c("iris$Sepal.Length", "iris$Sepal.Width")。
【解决方案2】:

你很亲密!您可以通过使用vars 向量将您输入的数据框子集到sapply 并更改kruskal.test 中的公式来实现:

vars <- c("Sepal.Length", "Sepal.Width")
sapply(iris[, vars], function(x) kruskal.test(x ~ iris$Species))

【讨论】:

    【解决方案3】:

    R 是一种非常多样化的编码语言,最终会有很多方法来做同样的事情。有些函数需要更标准的评估,而其他函数可能使用 NSE(非标准评估)。

    但是,您似乎在询问只期望单个向量作为估算的函数,而不是具有 data 参数的函数,其中您使用 variable 而不是 data$variable。

    在给出一些建议之前,我有几个侧边栏

    边栏 1 - S3 方法

    虽然这可能不是问题的重点,但函数kruskal.test 有两种方法。

    methods("kruskal.test")
    #[1] kruskal.test.default* kruskal.test.formula*
    #see '?methods' for accessing help and source code
    

    使用哪种方法取决于函数中第一个参数的类。在此示例中,您传递了一个公式表达式,其中 data 参数是必需的,而默认方法只需要 x 和 g 参数(您可能会使用原始管道)。

    因此,如果您习惯于以一种方式做某事,请务必检查函数的文档是否有适合您的不同调度方法。

    边栏 2 - 数据框

    数据框实际上只是向量的集合。 f(data$variable) 和 f(x = variable, data = data) 之间的区别在于,第一个用户明确告诉 R 在哪里找到向量,而在后者中,函数 f 在上下文中评估 x data。 我提出这个是因为我在开始时所说的——有很多方法可以做同样的事情。因此,通常取决于您希望自己的标准是什么。

    如果你更喜欢直白

    vars <- c("data$age", "data$gender", "data$PCLR")
    means <- sapply(vars, fmean, data$group, na.rm=TRUE)
    krusk <- sapply(vars, kruskal.test, g = data$group)
    

    或者你可以编写你的函数,期望它们在某个data.frame对象中被评估

    vars <- c("age", "gender", "PCLR")
    means <- sapply(vars, function(x, id, data) fmean(data[[x]], id = data[[id]], na.rm=T), id = "group", data = data)
    krusk <- sapply(vars, function(x, id, data) kruskal.test(data[[x]], data[[id]]), id = "group", data = data)
    

    我的建议

    我建议查看以下软件包 dplyr、tidyr、purrr。我敢肯定,这些软件包中的某些东西会让您的生活更轻松。

    例如,您曾表示必须在执行sapply 之前手动制作列表。在dplyr 包中,如果有过滤条件,您可以规避此问题。

    data %>%
        group_by(group) %>% #groups data
        summarise_if(is.numeric, mean, na.rm = TRUE) #applys mean to every column that is a numeric vector
    

    同样,如果我们稍微重塑数据,我们可以总结kurskal.test 函数的结果。

    data %>% 
         group_by(group) %>% #grouping to retain column in the next select statement
         select_if(is.numeric) %>% # selecting all numeric columns
         pivot_longer(cols = -group) %>% # all columns except "group" will be reshaped. Column names are stored in `name`, and values are stored in `values`
         group_by(name) %>% #regroup on name variable (old numeric columns)
         summarise(krusk = list(kruskal.test(value ~ as.factor(group)))) #perform test
    

    我只提到了purrr,因为您几乎可以将所有apply 样式函数替换为map 变体。 purrr 在其函数变体中非常一致,有很多选项来控制输出类型。

    我希望这对您有所帮助,并祝您在编码冒险中好运。

    【讨论】:

    • 嗨贾斯汀,谢谢你的回答!我还没有看到做 kruskal.test 的其他方式,所以这肯定会帮助我这次如何构建我的 vars 变量。实际上我已经经常使用 dplyr,但是我发现我需要更加熟悉如何使用相关的功能。我实际上有一些使用'summarise(across(starts_with(“Pect”)')的代码,因为我需要查看的所有变量都以这些单词开头(因此不一定只有数字变量)。但我会继续深入研究'select_if' 函数也是如此!
    • 成功了!我的代码的最终结果是: krusk % group_by(cutoff_26) %>% select(starts_with("Pect")) %>% pivot_longer(cols =-cutoff_26) %>% group_by(name) %>% summarise(krusk = list(kruskal.test(value ~ as.factor(cutoff_26)))) 非常感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2016-11-11
    • 2019-12-14
    • 1970-01-01
    • 1970-01-01
    • 2012-04-03
    • 2012-01-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多