【问题标题】:Assigning values within lapply在 lapply 内赋值
【发布时间】:2012-12-25 12:21:28
【问题描述】:

这是一个玩具示例,我总是为此编写一个循环。我很难找出一个班轮。我确定我见过它,但它没有坚持。

smallFrame <- data.frame(colA = c('A', 'B', 'C' ,'D'), colB = c(1,1,1,1))
someList <- list(A=20, B=30, C=40, D=50)
for(letter in names(someList)){
  smallFrame[smallFrame$colA==letter, 'newColumn'] <- someList[[letter]]
}

如何在一行中执行循环?这样做不行。

lapply(names(someList), function(x) {smallFrame[smallFrame$colA==x, 'newColumn'] <- someList[[x]]})

【问题讨论】:

    标签: r merge lapply


    【解决方案1】:

    丑陋,但有效:

    lapply(names(someList), function(x) {smallFrame[smallFrame$colA==x, 'newColumn'] <<- someList[[x]]})
    

    注意&lt;&lt;-。它不能与&lt;- 一起工作的原因是在函数中修改了 someList 的副本。

    这里的“丑陋”意味着你永远不应该使用这种语法,原因有两个。首先,有副作用的函数容易出错。其次,lapply 的返回值被忽略。这些都表明显式循环是最好的。

    不那么难看,几乎是从@thelatemail 偷来的:

    smallFrame$newColumn <- unlist(someList[match(smallFrame$colA, names(someList))])
    

    例子:

    smallFrame <- data.frame(colA = c('A', 'B', 'C' ,'D', 'A'), colB = c(1,1,1,1,1))
    > smallFrame
    
    > smallFrame
      colA colB
    1    A    1
    2    B    1
    3    C    1
    4    D    1
    5    A    1
    
    smallFrame$newColumn <- unlist(someList[match(smallFrame$colA, names(someList))])
    
    > smallFrame
      colA colB newColumn
    1    A    1        20
    2    B    1        30
    3    C    1        40
    4    D    1        50
    5    A    1        20
    

    【讨论】:

    • lapply + &lt;&lt;- 通常意味着您应该使用 for 循环。
    • @hadley 确实如此。这个例子是为了说明为什么他的代码不起作用。
    【解决方案2】:

    这是一个简单的合并,如果你适当地重塑你的smallList

    # reshape2 for melt.
    library(reshape2)
    # slightly expanded version with duplicate colA == A
    smallFrame <- data.frame(colA = c('A', 'A', 'B', 'C' ,'D'), colB = c(1,2,1,1,1))
    someList <- list(A=20, B=30, C=40, D=50)
    merge(smallFrame, melt(someList), by.x = 'colA', by.y = 'L1')
    
      colA colB value
    1    A    1    20
    2    A    2    20
    3    B    1    30
    4    C    1    40
    5    D    1    50
    

    或者,如果您真的热衷于在 smallFrame 中高效地分配,请使用 data.table

    library(data.table)
    smallDT <- data.table(smallFrame, key = 'colA')
    someDT <- data.table(melt(someList), key = 'L1')
    
    # left join smallDT and someDT, assigning the `value` column by reference
    # within smallDT as the column `newColumn`
    smallDT[someDT, newColumn := value]
    
    
    
    
    smallDT
       colA colB newColumn
    1:    A    1        20
    2:    A    2        20
    3:    B    1        30
    4:    C    1        40
    5:    D    1        50
    

    【讨论】:

    • 这很棒。我必须克服使用数据框并专门转向 data.table 。我现在已经重新学习了 2 到 3 次。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-04
    • 1970-01-01
    • 2016-11-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多