R 将嵌套列表安全地转换为数据帧,其中有些值是单数,有些是向量
我有一个列表,其中每个元素本身都是一个命名的属性列表,这是一种典型的JSON输出:R 将嵌套列表安全地转换为数据帧,其中有些值是单数,有些是向量,r,purrr,R,Purrr,我有一个列表,其中每个元素本身都是一个命名的属性列表,这是一种典型的JSON输出: l <- list( list( "attr1" = 1, "attr2" = "x", "attr3" = 3:4 ), list( "attr1" = 5, "attr2" = "y", "attr3" = 7:9 ), list( "attr1" = 10, "attr2" = "z", "attr3" = 1
l <- list(
list(
"attr1" = 1,
"attr2" = "x",
"attr3" = 3:4
),
list(
"attr1" = 5,
"attr2" = "y",
"attr3" = 7:9
),
list(
"attr1" = 10,
"attr2" = "z",
"attr3" = 12
)
)
错误:参数3的长度必须为1,而不是2
这种方法是有效的,但我必须事先知道哪些属性应该是单数的,哪些列表是单数的。我使用的是一个命名的向量attrs_dict,有点像Python字典,Pulk_包装函数会引用它来返回一个单数值或一个列表:
attrs_dict <- c("attr1" = FALSE, "attr2" = FALSE, "attr3" = TRUE)
pluck_wrapper <- function(element, attr, attrs_dict) {
res <- pluck(element, attr)
if (attrs_dict[attr]) {
return(list(res))
}
return(res)
}
get_element_details <- function(element, attrs_dict) {
attrs <- names(attrs_dict)
element_list <- map(attrs, function(attr) pluck_wrapper(element, attr, attrs_dict))
names(element_list) <- attrs
element_list
}
df <- l %>% map_dfr(get_element_details, attrs_dict)
df
我不知道如何简单地简化,但这也是一个很好的方向。您可以检查列表中每个元素的长度,如果所有元素都是1,我们可以取消列出它们 如果您想拥有不需要的完整数据,您可以这样做
transpose(l) %>% map_dfc(list) %>% tidyr::unnest(cols = V1:V3)
# A tibble: 6 x 3
# V1 V2 V3
# <dbl> <chr> <dbl>
#1 1 x 3
#2 1 x 4
#3 5 y 7
#4 5 y 8
#5 5 y 9
#6 10 z 12
您可以检查列表中每个元素的长度,如果所有元素都是1,我们可以取消它们的列表 如果您想拥有不需要的完整数据,您可以这样做
transpose(l) %>% map_dfc(list) %>% tidyr::unnest(cols = V1:V3)
# A tibble: 6 x 3
# V1 V2 V3
# <dbl> <chr> <dbl>
#1 1 x 3
#2 1 x 4
#3 5 y 7
#4 5 y 8
#5 5 y 9
#6 10 z 12
在base R中,您可以使用cbind
在base R中,您可以使用cbind
如果将一个观察值设为1行,表示前两行分别为1 x 3和1 x 4,这不是很有帮助吗?或者您只希望它们作为列表?@RonakShah您的意思是生成的数据帧将不被列出?在这个例子中,总共2+3+1=6行是的,这就是我的意思。我看到的问题是,列表类型的许多属性,其长度远远超过1、2或3,可能对一些非常丑陋的东西毫无意义。。。但是你下面的答案太棒了,谢谢!如果将一个观察值设为1行,表示前两行分别为1 x 3和1 x 4,这不是很有帮助吗?或者您只希望它们作为列表?@RonakShah您的意思是生成的数据帧将不被列出?在这个例子中,总共2+3+1=6行是的,这就是我的意思。我看到的问题是,列表类型的许多属性,其长度远远超过1、2或3,可能对一些非常丑陋的东西毫无意义。。。但是你下面的答案太棒了,谢谢!这在最新的purrr中不再有效。但这是:transposel%>%map\u dfc~ifalllength.x==1 unlist.x else tibble.x,除了不保留列的名称,我不知道该怎么做。此外,它只适用于单个列表列。这在最新的purrr中不再适用。但这是:transposel%>%map\u dfc~ifalllength.x==1 unlist.x else tibble.x,除了不保留列的名称,我不知道该怎么做。而且,它只适用于单个列表列。
attrs_dict <- c("attr1" = FALSE, "attr2" = FALSE, "attr3" = TRUE)
pluck_wrapper <- function(element, attr, attrs_dict) {
res <- pluck(element, attr)
if (attrs_dict[attr]) {
return(list(res))
}
return(res)
}
get_element_details <- function(element, attrs_dict) {
attrs <- names(attrs_dict)
element_list <- map(attrs, function(attr) pluck_wrapper(element, attr, attrs_dict))
names(element_list) <- attrs
element_list
}
df <- l %>% map_dfr(get_element_details, attrs_dict)
df
# A tibble: 3 x 3
attr1 attr2 attr3
<dbl> <chr> <list>
1 1 x <int [2]>
2 5 y <int [3]>
3 10 z <dbl [1]>
get_element_details <- function(element, attrs) {
element_list <- map(attrs, function(attr) list(pluck(element, attr)))
names(element_list) <- attrs
element_list
}
df <- l %>% map_dfr(get_element_details, attrs)
df
# A tibble: 3 x 3
attr1 attr2 attr3
<list> <list> <list>
1 <dbl [1]> <chr [1]> <int [2]>
2 <dbl [1]> <chr [1]> <int [3]>
3 <dbl [1]> <chr [1]> <dbl [1]>
library(purrr)
transpose(l) %>% map_dfc(~if(all(lengths(.x) ==1)) unlist(.x) else .x)
# A tibble: 3 x 3
# attr1 attr2 attr3
# <dbl> <chr> <list>
#1 1 x <int [2]>
#2 5 y <int [3]>
#3 10 z <dbl [1]>
transpose(l) %>% map_dfc(list) %>% tidyr::unnest(cols = V1:V3)
# A tibble: 6 x 3
# V1 V2 V3
# <dbl> <chr> <dbl>
#1 1 x 3
#2 1 x 4
#3 5 y 7
#4 5 y 8
#5 5 y 9
#6 10 z 12
res <- do.call(rbind, lapply(l, function(x) data.frame(t(cbind(x)))))
res
# attr1 attr2 attr3
# x 1 x 3, 4
# x1 5 y 7, 8, 9
# x2 10 z 12
str(res)
'data.frame': 3 obs. of 3 variables:
$ attr1:List of 3
..$ : num 1
..$ : num 5
..$ : num 10
$ attr2:List of 3
..$ : chr "x"
..$ : chr "y"
..$ : chr "z"
$ attr3:List of 3
..$ : int 3 4
..$ : int 7 8 9
..$ : num 12