用另一个列表元素的值替换一个列表元素的值

3

我希望用一个列表的第二个元素来替换另一个列表的某个元素,并且把替换后的值命名为“replaced”。具体来说,

  • 我有一个包含多个数据集的列表。
  • 每个数据集都有两个变量。
  • 这些变量都是因子。
  • 需要用每个数据集中第一个变量的第n个元素替换每个数据集中第二个变量的第n个元素。
  • dat1 <- data.frame(names1 =c("a", "b", "c", "f", "x"),values= c("val1_1", "val2_1", "val3_1", "val4_1", "val5_1"))
       dat1$values <- as.factor(dat1$values)
    dat2 <- data.frame(names1 =c("a", "b", "f2", "s5", "h"),values= c("val1_2", "val2_2", "val3_2", "val4_2", "val5_2"))
       dat2$values <- as.factor(dat2$values)
    list1 <- list(dat1, dat2)
    

    结果应该是相同的列表,只是第五个值被替换了。
    [[1]]
         names1  values
    1         a  val1_1
    2         b  val2_1
    3         c  val3_1
    4         f  val4_1
    5  replaced       x
    [[2]]
         names1  values
    1         a  val1_2
    2         b  val2_2
    3        f2  val3_2
    4        s5  val4_2
    5  replaced       h
    

    这只是一个简化的例子。我有超过4500个数据集。 - tobias sch
    2个回答

    3

    使用基础的 R 方法,通过 lapply 函数来实现。由于两列都是因子变量,所以我们需要先添加新的 levels,然后再用新值替换它们,否则这些值会变成 NA

    n <- 5
    
    lapply(list1, function(x) {
       levels(x$values) <- c(levels(x$values), as.character(x$names1[n]))
       x$values[n] <- x$names1[n]
       levels(x$names1) <- c(levels(x$names1), "replaced")
       x$names1[n] <- "replaced"
       x
    })
    
    #[[1]]
    #    names1 values
    #1        a val1_1
    #2        b val2_1
    #3        c val3_1
    #4        f val4_1
    #5 replaced      x
    
    #[[2]]
    #    names1 values
    #1        a val1_2
    #2        b val2_2
    #3       f2 val3_2
    #4       s5 val4_2
    #5 replaced      h
    

    还有另一种方法,我们可以将两个列都转换为字符,然后在所需位置替换值,再将它们转换回因子。但由于列表中的每个数据框可能非常庞大,我们不想将所有值都转换为字符,然后再将其转换回因子,仅更改一个值就会计算成本非常高。


    3

    使用 tidyverse,有一种选项。使用 map 循环遍历 listslice 感兴趣的行(在这种情况下,它是最后一行,因此可以使用 n()),使用 mutate 更改列值并将其与不包括最后一行的原始数据绑定。

    library(tidyverse)
    map(list1, ~ .x %>% 
                   slice(n()) %>%
                   mutate(values = names1, names1 = 'replaced') %>% 
                   bind_rows(.x %>% slice(-n()), .))
    #[[1]]
    #    names1 values
    #1        a val1_1
    #2        b val2_1
    #3        c val3_1
    #4        f val4_1
    #5 replaced      x
    
    #[[2]]
    #    names1 values
    #1        a val1_2
    #2        b val2_2
    #3       f2 val3_2
    #4       s5 val4_2
    #5 replaced      h
    

    或者可以使用forcats中的fct_c来使其更加紧凑。不同的factor级别可以通过fct_c组合在一起,用于“values”和“names1”列。

    library(forcats)
    map(list1, ~ .x %>% 
            mutate(values = fct_c(values[-n()], names1[n()]), 
                   names1 = fct_c(names1[-n()], factor('replaced'))))
    

    或者使用类似于 base R 的方法,我们可以通过使用 lapply 循环遍历 list,然后将 data.frame 转换为 matrix,用感兴趣的值删除最后一行的子集并使用 rbind 连接,最后将其转换为 data.frame(默认情况下,stringsAsFactors = TRUE,因此它会被转换为 factor)。

    lapply(list1,  function(x)  as.data.frame(rbind(as.matrix(x)[-5, ], 
                  c('replaced',  as.character(x$names1[5])))))
    

    Akrun,你怎么到行号的?n <- 5 是从上面的答案中使用的吗? - tobias sch
    @tobiassch 不,这里你只有5行,而n()是最后一行。如果你有自定义的n,那么在slice(n)中使用它。 - akrun
    1
    是的!我明白了,会尝试的! - tobias sch

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接