【问题标题】:Loops within function argument of sapplysapply 函数参数内的循环
【发布时间】:2016-02-17 07:29:32
【问题描述】:

我正在尝试使用 sapply 将从列表中传递的名称作为情节标题添加到一系列箱线图中,但遇到了麻烦。

首先生成玩具数据来说明问题。

set.seed(12345)

df <- data.frame(v = rep(letters[1:3], times = 4))

for (i in 1:21) { 
     x <- rnorm(12, 3, 1) 
     df <- cbind(df, x)
     }

colnames (df)<- c("group", paste(rep(letters[1:7], each = 3), rep(1:3,  times = 7), sep = ""))

这为我们提供了一个数据集,其中的列按列名的第一个字母聚类。这类似于我自己的数据集,其中有一份问卷,其中包含在多个时间点(很多时间点)测量的多个项目。该问卷产生了几个因素得分。因此,有几个列集群代表了多次测量的问卷的每个因素。在这个玩具数据集中,我们可以认为列名中的字母表示哪个因素,数字表示哪个时间点。

我希望能够通过 sapply 函数选择我制作箱线图的集群/因子。所以我需要制作一个列表,其组件是每个列名的集群。

colsList <-list (aCols <- c("a1", "a2", "a3"),
                 bCols <- c("b1", "b2", "b3"),
                 cCols <- c("c1", "c2", "c3"),
                 dCols <- paste("d", 1:3, sep = ""),
                 eCols <- paste("e", 1:3, sep = ""),
                 fCols <- paste("f", 1:3, sep = ""),
                 gCols <- paste("g", 1:3, sep = ""))

现在做一个箱线图函数。我想根据组为每个聚类因子绘制图。

boxplotFunct <- function (DV, IV, Title) {
                 boxplot(DV ~ IV, main = Title, horizontal = TRUE)
}

现在在 sapply 循环中调用函数。

par(mfrow = c(1,3))

sapply(df[,colsList[[1]]], function(x) boxplotFunct(x, df$group, colsList[[1]]))

箱线图有效,但每个箱线图的标题包含所有三个列名,而不是相应的列名。在仍然使用 sapply 的情况下,我将如何做到这一点?

我会欢迎有关如何更好地完成整个过程的建议,但我主要想要一些关于如何解决我的特定问题的建议:在 sapply 循环中包含另一个循环(即,这更适合我的一般学习 apply 系列,而不是如何绘制图表)。

【问题讨论】:

    标签: r sapply


    【解决方案1】:

    当迭代 colsList[[1]] 而不是 df[, colsList[[1]]] 时,您的 sapply 代码可以大大减少。

    sapply(colsList[[1]], function(x) {
      boxplotFunct(df[, x], df$group, x)
    })
    


    更新:

    作为对以下评论的回应,让我们假设您想用另一个列表中的字符串替换现有的图形标题。对于行为与sapply 非常相似的任务,我倾向于使用foreach,但允许您指定多个输入列表。如果您还不熟悉该软件包,请查看Using The foreach Pakage。这是一些示例代码。

    ## alternate column names
    colsList2 <- list(hCols <- paste("h", 1:3, sep = ""),
                      iCols <- paste("i", 1:3, sep = ""),
                      jCols <- paste("j", 1:3, sep = ""),
                      kCols <- paste("k", 1:3, sep = ""),
                      lCols <- paste("l", 1:3, sep = ""),
                      mCols <- paste("m", 1:3, sep = ""),
                      nCols <- paste("n", 1:3, sep = ""))
    
    ## create plots
    par(mfrow = c(1, 3))
    
    library(foreach)
    foreach(x = colsList[[1]], y = colsList2[[1]]) %do%
      boxplotFunct(df[, x], df$group, y)
    

    【讨论】:

    • 谢谢@fdetsch。十分优雅。这实际上是最有启发性的。
    • 如果我想用与列名不同的名称来标记图表,并且我想从第二个列表中调用这些列名怎么办?为了论证起见,说标签的模式与 colsList 相同,但从 h 到 n 运行。
    • @llewmills,我更新了上面的代码以响应您的最新评论。
    • 太棒了!非常感谢@fdetsch
    • @llewmills,那么您可能应该接受表明问题已结束的答案;-)
    【解决方案2】:

    你可以使用

    sapply(seq(lengths(colsList)[[1]]), function(x) 
      boxplotFunct(df[,colsList[[1]][x] ], df$group, colsList[[1]][x]))
    

    即使用索引。

    【讨论】:

    • 是的。完美的。谢谢@lukeA。
    • 我不认为你可以为我解构它?我得到了我认为的 x 索引,但我不明白你对第一个参数做了什么(即 'seq' 和 'lengths' 提供什么功能?)
    • 当然。 lengths(colsList) 为您提供一个向量,其中包含列表中每个向量的长度(它们的长度均为 3)。 lengths(colsList)[1]length(colsList[[1]]) 为您提供列表中第一个向量的长度。并且seq(3)seq_len(3) 生成一个从1 到3 的整数序列。您也可以使用seq_along(colsList[[1]]) 或只是1:3 --> 多种方法来实现您的目标。另请注意,?lengths 等会为您提供有关功能的帮助。
    • 谢谢。我不知道长度。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-19
    • 1970-01-01
    • 1970-01-01
    • 2021-01-02
    • 1970-01-01
    相关资源
    最近更新 更多