【问题标题】:Vary Arguments Passed to Function in lapply call在 lapply 调用中改变传递给函数的参数
【发布时间】:2018-09-24 21:50:52
【问题描述】:

一般问题

我想改变在 lapply/sapply(或者可能是 mapply?)调用中传递给函数的附加参数。很高兴知道如何做到这一点。但是,如果这很重要,出于我的特定目的,我会尝试将其合并到自定义函数中。 (所以希望它可以扩展)。

问题的具体示例

假设我有以下数据框:

df <- data.frame(column1 = letters[1:4], 
             column2 = LETTERS[1:4], 
             column3 = 1:4, 
             stringsAsFactors = FALSE)

例如,我想将 column1 和 column2 转换为因子,每个因子都有不同的级别。我可能会这样记下列和级别:

# Columns in df I want to apply the factor() function to.

     cols <- c("column1", "column2")

# Desired levels for column1

     column1_lvl <- c(letters[1:5])

# Desired levels for column2

     column2_lvl <- c(LETTERS[1:6])

请注意,我为列指定了两个单独的级别,每个级别都比df 中存在的级别多。这是改变论点的动机。现在我测试了一个lapply 调用而不将levels 参数更改为factor:

     df[cols] <- lapply(df[,cols], factor)

这有效并成功地将这些列转换为因子。我将df 重新定义为下一步的原始结构。现在我想为每一列指定级别。在?lapply 中,它说您可以将其他参数传递给FUN,但它没有指定如何在X 中的每个向量上改变这些参数。尝试使用 one 实例,我可以这样写:

     df["column1"]<- factor(df[,"column1"], levels = column1_lvl)

这行得通。但现在我想抽象出levels 参数。不幸的是,这不起作用,因为无论您为levels 分配什么,R 都会尝试将该参数用于X 中的每个向量。

理想情况下,类似以下的内容会起作用。 以下是我希望按照我想要的方式工作的假代码,但不是

     df[cols] <- lapply(df[,cols], factor, level = list(column1_lvl, column2_lvl))

我的尝试

我无法找到很多资源来解释我如何能够做到这一点。或者,我看不出需要做什么。 This post 帮助了我一点,但我想知道是否有办法创建我自己的 factor 函数,例如。

此外,this person's answer 对他们自己的问题鼓励我查看mapply。虽然我已经阅读了?mapply 的文档,并遵循了一些教程,但我还是无法弄清楚。在这方面,我尝试了以下代码,但它不起作用(出于我的目的):

     col_levels <- list(column1_lvl, column2_lvl)
     df[cols] <- mapply(factor, df[,cols], MoreArgs = col_levels)

会话信息

> sessionInfo()
R version 3.5.1 (2018-07-02)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows >= 8 x64 (build 9200)

Matrix products: default

locale:
[1] LC_COLLATE=English_United States.1252  LC_CTYPE=English_United States.1252    LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C                           LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
[1] compiler_3.5.1 tools_3.5.1    yaml_2.1.19  

最后的想法

我可能只是很难知道要搜索什么。如果你能指出我正确的方向,我总是愿意自己解决问题。任何其他资源都非常受欢迎。

谢谢,提前!

【问题讨论】:

    标签: r


    【解决方案1】:

    我们可以使用Maplevels 列更改为list 中对应的'lvl' 对象

    df[cols] <- Map(function(x, y) factor(x, levels = y),
                 df[cols], list(column1_lvl, column2_lvl))
    

    并检查列的levels

    lapply(df[cols], levels)
    #$column1
    #[1] "a" "b" "c" "d" "e"
    
    #$column2
    #[1] "A" "B" "C" "D" "E" "F"
    

    正如 OP 提到的一种使用 lapply 解决此问题的方法,lapply 的一个选项是循环遍历序列,然后对数据和相应的“lvls”list 进行子集化

    lvls_lst <- list(column1_lvl, column2_lvl)
    df[cols] <- lapply(seq_along(lvls_lst), function(i) 
             factor(df[cols][[i]], levels = lvls_lst[[i]]))
    

    注意:在这两种情况下,我们都需要明确指定levels

    【讨论】:

    • 您能否详细解释一下Map 解决方案的工作原理?我正在阅读文档,但很难直观地掌握。它将匿名函数(在您的示例中)“映射”到该函数的第一个参数,然后将任何剩余参数用于匿名函数的附加参数?我喜欢您的 lapply 解决方案如何不强迫您使用现有函数的所有参数创建一个函数(以防万一您想从现有函数中更改更多参数),但 Map 似乎“更干净” .
    • @MillionC - 您甚至可以进一步折叠它并将输入命名为 factorMap - df[cols] &lt;- Map(factor, x=df[cols], levels=list(column1_lvl, column2_lvl)) 。您不必创建匿名函数。
    • 谢谢,@thelatemail。我只需要花一些时间来加深对泛函的理解。代码有效,我的问题也解决了,但我还是不明白Map 是如何工作的。有趣的是,您映射函数的向量也是函数参数。对我来说,这是一种新的思考方式。无论如何,感谢您的帮助!
    • @MillionC - 所有这些函数实际上只是循环。它是说运行factor() 与提供的x= 参数的第一部分+ 提供的levels= 参数的第一部分。然后重复每个参数的第 2、第 3、第 n 部分。一个可能有助于理解的简单示例是Map(paste, 1:3, c("a","b","c")) - 其中pastes 一起1/a,然后是2/b,然后是3/c。祝你好运!
    • @MillionC 我使用匿名函数使其更明显。您可以指定levels,如最新邮件所示。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-17
    • 1970-01-01
    • 2014-06-26
    • 1970-01-01
    相关资源
    最近更新 更多