使用 purrr::map 简化 xml。添加简化列表的索引号
Using purrr::map to simplify xml. Add index number of the simplified list
坚持了几个小时。
我正在简化一个超过 15000 行的 xml 文件,其中包含有关肺功能测试的数据。每个 xml 文件包含多个测试。使用 xml2 和 map 我可以将数据放入长度为 n-of-tests.
的列表中
这是文件中两个测试列表的摘录:
[[1]]
[[1]][[1]]
Name UM Value
"MEF75%" "L/s" "6.82"
[[1]][[2]]
Name UM Value Predicted PercPred ZScore LLN ULN
"FEV1" "L" "3.83" "4.16" "92" "-0.62" "3.27" "5.01"
...
[[2]]
[[2]][[1]]
Name UM Value
"MEF75%" "L/s" "6.65"
[[2]][[2]]
Name UM Value Predicted PercPred ZScore LLN ULN
"FEV1" "L" "3.79" "4.16" "91" "-0.69" "3.27" "5.01"
....
我可以使用 map_dfr 或 bind_rows 轻松地将其转换为 tibble 但是 我似乎无法弄清楚的是如何添加列表索引[[1]] 或 [[2]] 作为小标题中的一列。如果我使用 .id 参数,它只是按顺序对行进行编号,不引用列表:
map(trials, ~xml_find_all(., "AdditionalData/Parameters/Parameter")) %>%
map (., ~xml_attrs(.)) %>% bind_rows(. , .id = "test")
A tibble: 104 x 9
test Name UM Value Predicted PercPred ZScore LLN ULN
<chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 1 MEF75% L/s 6.82 NA NA NA NA NA
2 2 FEV1 L 3.83 4.16 92 -0.62 3.27 5.01
...
53 53 MEF75% L/s 6.65 NA NA NA NA NA
54 54 FEV1 L 3.79 4.16 91 -0.69 3.27 5.01
我想要得到的是(第一列中的差异 - “测试”):
map(trials, ~xml_find_all(., "AdditionalData/Parameters/Parameter")) %>%
map (., ~xml_attrs(.)) %>% bind_rows(. , .id = "test")
A tibble: 104 x 9
test Name UM Value Predicted PercPred ZScore LLN ULN
<chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 1 MEF75% L/s 6.82 NA NA NA NA NA
2 1 FEV1 L 3.83 4.16 92 -0.62 3.27 5.01
...
53 2 MEF75% L/s 6.65 NA NA NA NA NA
54 2 FEV1 L 3.79 4.16 91 -0.69 3.27 5.01
这是 do-able 和 tidyverse 吗?我应该尝试使用 base-R 循环来解决吗?
感谢任何帮助,谢谢。
-BF
要根据可变长度列表元素创建 ID 列,我们可以重复列表中元素的索引(参见 this),元素数量 次。
x <- list(
list(
c(Name = "a", UM = "L/s", Value = "1"),
c(Name = "a", UM = "L", Value = "3.1", Predicted = "1")
),
list(
c(Name = "b", UM = "L", Value = "2"),
c(Name = "b", UM = "L/s", Value = "4", Predicted = "1.1"),
c(Name = "b", UM = "L/s", Value = "4", Predicted = "1.1", ZScore = "-.50")
),
list(1)
)
y <- sapply(x, length)
unlist(Map(function(n, i) rep(i, n), y, seq_along(y)), use.names = F)
#> [1] 1 1 2 2 2 3
或使用tidyverse
函数
imap(map_int(x, length), ~rep(.y, .x)) %>% flatten_int()
#> [1] 1 1 2 2 2 3
并将其添加为 ID 列。
如果测试次数相等(原始 post 中为 2),只需 rep(1:length(x), each = 2)
其中 each
参数是测试次数。
我不太清楚你在 post 中显示的列表是命名向量还是 data.frames 有 1 行。在任何情况下 - 一个替代方案,使用 set_names
因为 bind_rows
可以采用命名列表:
list(
data.frame(x = 1, y = 2),
data.frame(x = 10, y = 15)
) %>%
set_names(1:2) %>%
bind_rows(.id = "test") # %>% a character column
# mutate(test = as.numeric(test))
#> test x y
#> 1 1 1 2
#> 2 2 10 15
坚持了几个小时。
我正在简化一个超过 15000 行的 xml 文件,其中包含有关肺功能测试的数据。每个 xml 文件包含多个测试。使用 xml2 和 map 我可以将数据放入长度为 n-of-tests.
的列表中这是文件中两个测试列表的摘录:
[[1]]
[[1]][[1]]
Name UM Value
"MEF75%" "L/s" "6.82"
[[1]][[2]]
Name UM Value Predicted PercPred ZScore LLN ULN
"FEV1" "L" "3.83" "4.16" "92" "-0.62" "3.27" "5.01"
...
[[2]]
[[2]][[1]]
Name UM Value
"MEF75%" "L/s" "6.65"
[[2]][[2]]
Name UM Value Predicted PercPred ZScore LLN ULN
"FEV1" "L" "3.79" "4.16" "91" "-0.69" "3.27" "5.01"
....
我可以使用 map_dfr 或 bind_rows 轻松地将其转换为 tibble 但是 我似乎无法弄清楚的是如何添加列表索引[[1]] 或 [[2]] 作为小标题中的一列。如果我使用 .id 参数,它只是按顺序对行进行编号,不引用列表:
map(trials, ~xml_find_all(., "AdditionalData/Parameters/Parameter")) %>%
map (., ~xml_attrs(.)) %>% bind_rows(. , .id = "test")
A tibble: 104 x 9
test Name UM Value Predicted PercPred ZScore LLN ULN
<chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 1 MEF75% L/s 6.82 NA NA NA NA NA
2 2 FEV1 L 3.83 4.16 92 -0.62 3.27 5.01
...
53 53 MEF75% L/s 6.65 NA NA NA NA NA
54 54 FEV1 L 3.79 4.16 91 -0.69 3.27 5.01
我想要得到的是(第一列中的差异 - “测试”):
map(trials, ~xml_find_all(., "AdditionalData/Parameters/Parameter")) %>%
map (., ~xml_attrs(.)) %>% bind_rows(. , .id = "test")
A tibble: 104 x 9
test Name UM Value Predicted PercPred ZScore LLN ULN
<chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 1 MEF75% L/s 6.82 NA NA NA NA NA
2 1 FEV1 L 3.83 4.16 92 -0.62 3.27 5.01
...
53 2 MEF75% L/s 6.65 NA NA NA NA NA
54 2 FEV1 L 3.79 4.16 91 -0.69 3.27 5.01
这是 do-able 和 tidyverse 吗?我应该尝试使用 base-R 循环来解决吗?
感谢任何帮助,谢谢。 -BF
要根据可变长度列表元素创建 ID 列,我们可以重复列表中元素的索引(参见 this),元素数量 次。
x <- list(
list(
c(Name = "a", UM = "L/s", Value = "1"),
c(Name = "a", UM = "L", Value = "3.1", Predicted = "1")
),
list(
c(Name = "b", UM = "L", Value = "2"),
c(Name = "b", UM = "L/s", Value = "4", Predicted = "1.1"),
c(Name = "b", UM = "L/s", Value = "4", Predicted = "1.1", ZScore = "-.50")
),
list(1)
)
y <- sapply(x, length)
unlist(Map(function(n, i) rep(i, n), y, seq_along(y)), use.names = F)
#> [1] 1 1 2 2 2 3
或使用tidyverse
函数
imap(map_int(x, length), ~rep(.y, .x)) %>% flatten_int()
#> [1] 1 1 2 2 2 3
并将其添加为 ID 列。
如果测试次数相等(原始 post 中为 2),只需 rep(1:length(x), each = 2)
其中 each
参数是测试次数。
我不太清楚你在 post 中显示的列表是命名向量还是 data.frames 有 1 行。在任何情况下 - 一个替代方案,使用 set_names
因为 bind_rows
可以采用命名列表:
list(
data.frame(x = 1, y = 2),
data.frame(x = 10, y = 15)
) %>%
set_names(1:2) %>%
bind_rows(.id = "test") # %>% a character column
# mutate(test = as.numeric(test))
#> test x y
#> 1 1 1 2
#> 2 2 10 15