R语言 当列表元素的长度不同时,将列表合并到data.table中

xwmevbvl  于 2023-04-09  发布在  其他
关注(0)|答案(3)|浏览(161)

假设我有3个对象想要合并成一个data.table,一个长度为1的向量('id'),和两个列表:

id = "ID 1"
scores = list(c(1,2,3), c(2,3,2), c(0,0,3,2,1), c(2,2,2), c(2,2,2))
age = list(c(30,30,31), c(52,42,33), NA, c(54,62,11), c(65,66,12))

请注意,'scores'中的第三个元素有5个值,而'age'中的相应元素只包含一个NA
我想按行合并这三个对象

data.table(id = id, scores = unlist(scores), age = unlist(age))

显然,这是由于两个未列出的列表的长度不同而导致的错误:
在as.data.table.list(x,keep.rownames = keep.rownames,check.names = check.names,:项目3有13行,但最长的项目有17行;与剩余物一起回收。
我最终想要

id scores age
 1: ID 1      1  30
 2: ID 1      2  30
 3: ID 1      3  31
 4: ID 1      2  52
 5: ID 1      3  42
 6: ID 1      2  33
 7: ID 1      0  NA
 8: ID 1      0  NA
 9: ID 1      3  NA
10: ID 1      2  NA
11: ID 1      1  NA
12: ID 1      2  54
13: ID 1      2  62
14: ID 1      2  11
15: ID 1      2  65
16: ID 1      2  66
17: ID 1      2  12

也就是说,'age'的第三个元素中的单个NA重复5次,以获得与'scores'中对应的第三个元素相同的长度。我如何高效地做到这一点?

h79rfbju

h79rfbju1#

下面是一个使用mapply()的辅助函数,它将length-1 NA s扩展为另一个列表中相应元素的长度:

library(data.table)

expand_na <- function(x, y) {
  mapply(
    \(x, y) if (length(x) == 1 && is.na(x)) rep(x, length(y)) else x,
    x,
    y
  )
}

data.table(
  id = id,
  scores = unlist(scores),
  age = unlist(expand_na(age, scores))
)
id scores age
 1: ID 1      1  30
 2: ID 1      2  30
 3: ID 1      3  31
 4: ID 1      2  52
 5: ID 1      3  42
 6: ID 1      2  33
 7: ID 1      0  NA
 8: ID 1      0  NA
 9: ID 1      3  NA
10: ID 1      2  NA
11: ID 1      1  NA
12: ID 1      2  54
13: ID 1      2  62
14: ID 1      2  11
15: ID 1      2  65
16: ID 1      2  66
17: ID 1      2  12
8aqjt8rx

8aqjt8rx2#

我们可以使用unnest,如果有一个NA,它会自动执行复制

library(tibble)
library(dplyr)
library(tidyr)
tibble(id, scores, age) %>% 
  unnest(where(is.list))
  • 输出
# A tibble: 17 × 3
   id    scores   age
   <chr>  <dbl> <dbl>
 1 ID 1       1    30
 2 ID 1       2    30
 3 ID 1       3    31
 4 ID 1       2    52
 5 ID 1       3    42
 6 ID 1       2    33
 7 ID 1       0    NA
 8 ID 1       0    NA
 9 ID 1       3    NA
10 ID 1       2    NA
11 ID 1       1    NA
12 ID 1       2    54
13 ID 1       2    62
14 ID 1       2    11
15 ID 1       2    65
16 ID 1       2    66
17 ID 1       2    12
4xrmg8kj

4xrmg8kj3#

下面是一个带有Map的基本R选项

do.call(
  rbind,
  Map(cbind, list(data.frame(id)), scores = scores, age = age)
)

它给出了

id scores age
1  ID 1      1  30
2  ID 1      2  30
3  ID 1      3  31
4  ID 1      2  52
5  ID 1      3  42
6  ID 1      2  33
7  ID 1      0  NA
8  ID 1      0  NA
9  ID 1      3  NA
10 ID 1      2  NA
11 ID 1      1  NA
12 ID 1      2  54
13 ID 1      2  62
14 ID 1      2  11
15 ID 1      2  65
16 ID 1      2  66
17 ID 1      2  12

如果您想最终获得一个data.table对象,可以尝试

rbindlist(
  Map(
    cbind,
    list(data.table(id)),
    scores = scores,
    age = age
  )
)

它给出了

id scores age
 1: ID 1      1  30
 2: ID 1      2  30
 3: ID 1      3  31
 4: ID 1      2  52
 5: ID 1      3  42
 6: ID 1      2  33
 7: ID 1      0  NA
 8: ID 1      0  NA
 9: ID 1      3  NA
10: ID 1      2  NA
11: ID 1      1  NA
12: ID 1      2  54
13: ID 1      2  62
14: ID 1      2  11
15: ID 1      2  65
16: ID 1      2  66
17: ID 1      2  12

相关问题