如何使用lapply转换数据帧列表中的特定值

时间:2018-10-18 01:02:14

标签: r lapply tidyverse

我正在寻找将for循环转换为lapply或类似功能的帮助。

我有一个list个相似的data.frame,每个都包含

  • 指标列('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和类似的功能似乎是关键。

3 个答案:

答案 0 :(得分:0)

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

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

使用map中的purrr可以完成同样的操作

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

答案 1 :(得分:0)

有关使用transform()map()的相当优雅的解决方案,请参见上面的Ronak答案,但是对于那些追随我的脚步的人,如果我在自定义函数中添加一行到返回完整的数据帧,如下所示:

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] <- vjj : replacement has length zero。因此最好不要走这条路,并使用上面接受的答案。

答案 2 :(得分:0)

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元素,而是代替了vector