【问题标题】:How to use lapply to transform specific values in a list of dataframes如何使用 lapply 转换数据框列表中的特定值
【发布时间】:2019-03-22 18:16:05
【问题描述】:

我正在寻求将for 循环转换为lapply 或类似函数的帮助。

我有一个类似data.frames 的list,每个都包含

  • 一个指示列 ('a')
  • 值列 ('b')

我想为每个数据框反转 b 列中的值,但仅限于特定指标。例如,反转 'b' 中所有在 a 列中指示符为 2 的值。

以下是一些示例数据:

x = data.frame(a = c(1, 2, 3, 2),  b = (seq(from = .1, to = 1, by = .25)))
y = data.frame(a = c(1, 2, 3, 2),  b = (seq(from = 1, to = .1, by = -.25)))
my_list <- list(x = , y = y)

my_list
$x
  a    b
1 1 0.10
2 2 0.35
3 3 0.60
4 2 0.85

$y
  a    b
1 1 1.00
2 2 0.75
3 3 0.50
4 2 0.25

我想要的输出如下所示:

my_list
$x
  a    b
1 1 0.10
2 2 0.65
3 3 0.60
4 2 0.15

$y
  a    b
1 1 1.00
2 2 0.25
3 3 0.50
4 2 0.75

我可以通过以下 for 循环实现所需的输出。

for(i in 1:length(my_list)){
    my_list[[i]][my_list[[i]]['a'] == 2, 'b'] <-
        1 - my_list[[i]][my_list[[i]]['a'] == 2, 'b']
}

但是。当我尝试将它卷成这样的 lapply 形式时:

    invertfun <- function(inputDF){
    inputDF[inputDF['a'] == 2, 'b'] <- 1 - inputDF[inputDF['a'] == 2, 'b']
    }
resultList <- lapply(X = my_list, FUN = invertfun)

我得到一个只有反转值的列表:

resultList
$x
[1] 0.65 0.15

$y
[1] 0.25 0.75

我在这里缺少什么?我尝试应用(双关语)来自以下方面的见解:

how to use lapply instead of a for loop, to perform a calculation on a list of dataframes in R

如果有任何见解或替代解决方案,我将不胜感激。我正在尝试将我的 R 技能提升到一个新的水平,apply 和类似的功能似乎是关键。

【问题讨论】:

    标签: r lapply tidyverse


    【解决方案1】:

    我们可以使用lapply 循环遍历每个列表并根据a 列中的值更改b 列。

    my_list[] <- lapply(my_list, function(x) transform(x, b = ifelse(a==2, 1-b, b)))
    
    my_list
    #[[1]]
    #  a    b
    #1 1 0.10
    #2 2 0.65
    #3 3 0.60
    #4 2 0.15
    
    #[[2]]
    #  a    b
    #1 1 1.00
    #2 2 0.25
    #3 3 0.50
    #4 2 0.75
    

    同样可以使用来自purrrmap来完成

    library(purrr)
    map(my_list, function(x) transform(x, b = ifelse(a==2, 1-b, b)))
    

    【讨论】:

    • 谢谢罗纳克!我还了解了为什么我的原始方法不起作用,我将在另一个答案中分享。
    【解决方案2】:

    请参阅上面 Ronak 的回答,了解使用 transform()map() 的相当优雅的解决方案,但对于那些追随我脚步的人,如果我在自定义函数中添加一行以返回完整数据,我的原始解决方案将起作用像这样的框架:

    invertfun <- function(inputDF){
        inputDF[inputDF['a'] == 2, 'b'] <- 1 - inputDF[inputDF['a'] == 2, 'b']
    return(inputDF)    
    }
    
    resultList <- lapply(X = my_list, FUN = invertfun)
    

    更新 - 在进一步测试中,当所需的 'a' 值不存在于其中一个数据帧中时,此解决方案会引发 Error in x[[jj]][iseq] &lt;- vjj : replacement has length zero。所以最好不要走这条路并使用上面接受的答案。

    【讨论】:

      【解决方案3】:

      lapply 通常不是迭代修改list 的最佳方式。 lapply 无论如何都会在内部生成一个循环,所以如果你做一些更明确的事情通常更容易阅读:

      for (i in seq_along(my_list)) {
          my_list[[i]] <- within(my_list[[i]], {
              b[a==2] <- 1 - b[a==2]
          })}
      

      如果我们在上面的示例中将within 替换为with,我们会从您的初始解决方案中获得输出,即lapply(X = my_list, FUN = invertfun)

      也就是说,不是修改list 就地,后者的解决方案替换 list 元素与新的vectors。

      【讨论】:

        猜你喜欢
        • 2019-12-24
        • 2022-10-26
        • 2018-07-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-01
        • 1970-01-01
        • 2019-02-26
        相关资源
        最近更新 更多