使用带有 NULL 值的 tidyr unnest
using tidyr unnest with NULL values
我将 JSON 文件转换为具有嵌套列表结构的 data.frame,我想将其取消嵌套并展平。列表中的某些值是 NULL,unnest 不接受。如果我用只有 NA 值的 data.frame 结构替换 NULL 值,我会得到想要的结果。
下面是我的问题的一个简化示例。我试图用 NA data.frame 替换 NULL 值,但由于嵌套结构而没有成功。我怎样才能达到预期的结果?
例子
library(tidyr)
input1 <- data.frame(id = c("c", "d", "e"), value = c(7, 8, 9))
input2 <- NULL
input3 <- data.frame(id = c(NA), value = c(NA))
df <- dplyr::tibble(
a = c(1, 2),
b = list(a = input1, c = input2))
unnest(df)
给出错误"Error: Each column must either be a list of vectors or a list of data frames [b]"
df2 <- dplyr::tibble(
a = c(1, 2),
b = list(a = input1, c = input3))
unnest(df2)
给出了想要的输出。
我们可以在这里使用 purrr
中的 map_lgl
。如果您不关心带有 NULL
的那些行,您可以简单地使用 filter
和 unnest
:
删除它们
library(tidyverse)
df %>%
filter(!map_lgl(b, is.null)) %>%
unnest()
#> # A tibble: 3 x 3
#> a id value
#> <dbl> <fctr> <dbl>
#> 1 1 c 7
#> 2 1 d 8
#> 3 1 e 9
如果你想保留这些行,你可以在取消嵌套后用 right_join
把它们带回来:
df %>%
filter(!map_lgl(b, is.null)) %>%
unnest() %>%
right_join(select(df, a))
#> Joining, by = "a"
#> # A tibble: 4 x 3
#> a id value
#> <dbl> <fctr> <dbl>
#> 1 1 c 7
#> 2 1 d 8
#> 3 1 e 9
#> 4 2 <NA> NA
数据
input1 <- data.frame(id = c("c", "d", "e"), value = c(7, 8, 9))
input2 <- NULL
input3 <- data.frame(id = c(NA), value = c(NA))
df <- dplyr::tibble(
a = c(1, 2),
b = list(a = input1, c = input2)
)
正如上面@Frank 所指出的,从 tidyr
1.0.0 开始,这可以使用 keep_empty
参数
来实现
library(tidyr)
input1 <- data.frame(id = c("c", "d", "e"), value = c(7, 8, 9))
input2 <- NULL
df <- tibble::tibble(
a = c(1, 2),
b = list(a = input1, c = input2)
)
unnest(df, cols = b, keep_empty = TRUE)
#> # A tibble: 4 x 3
#> a id value
#> <dbl> <chr> <dbl>
#> 1 1 c 7
#> 2 1 d 8
#> 3 1 e 9
#> 4 2 NA NA
由 reprex package (v2.0.1)
于 2021-09-24 创建
我将 JSON 文件转换为具有嵌套列表结构的 data.frame,我想将其取消嵌套并展平。列表中的某些值是 NULL,unnest 不接受。如果我用只有 NA 值的 data.frame 结构替换 NULL 值,我会得到想要的结果。
下面是我的问题的一个简化示例。我试图用 NA data.frame 替换 NULL 值,但由于嵌套结构而没有成功。我怎样才能达到预期的结果?
例子
library(tidyr)
input1 <- data.frame(id = c("c", "d", "e"), value = c(7, 8, 9))
input2 <- NULL
input3 <- data.frame(id = c(NA), value = c(NA))
df <- dplyr::tibble(
a = c(1, 2),
b = list(a = input1, c = input2))
unnest(df)
给出错误"Error: Each column must either be a list of vectors or a list of data frames [b]"
df2 <- dplyr::tibble(
a = c(1, 2),
b = list(a = input1, c = input3))
unnest(df2)
给出了想要的输出。
我们可以在这里使用 purrr
中的 map_lgl
。如果您不关心带有 NULL
的那些行,您可以简单地使用 filter
和 unnest
:
library(tidyverse)
df %>%
filter(!map_lgl(b, is.null)) %>%
unnest()
#> # A tibble: 3 x 3
#> a id value
#> <dbl> <fctr> <dbl>
#> 1 1 c 7
#> 2 1 d 8
#> 3 1 e 9
如果你想保留这些行,你可以在取消嵌套后用 right_join
把它们带回来:
df %>%
filter(!map_lgl(b, is.null)) %>%
unnest() %>%
right_join(select(df, a))
#> Joining, by = "a"
#> # A tibble: 4 x 3
#> a id value
#> <dbl> <fctr> <dbl>
#> 1 1 c 7
#> 2 1 d 8
#> 3 1 e 9
#> 4 2 <NA> NA
数据
input1 <- data.frame(id = c("c", "d", "e"), value = c(7, 8, 9))
input2 <- NULL
input3 <- data.frame(id = c(NA), value = c(NA))
df <- dplyr::tibble(
a = c(1, 2),
b = list(a = input1, c = input2)
)
正如上面@Frank 所指出的,从 tidyr
1.0.0 开始,这可以使用 keep_empty
参数
library(tidyr)
input1 <- data.frame(id = c("c", "d", "e"), value = c(7, 8, 9))
input2 <- NULL
df <- tibble::tibble(
a = c(1, 2),
b = list(a = input1, c = input2)
)
unnest(df, cols = b, keep_empty = TRUE)
#> # A tibble: 4 x 3
#> a id value
#> <dbl> <chr> <dbl>
#> 1 1 c 7
#> 2 1 d 8
#> 3 1 e 9
#> 4 2 NA NA
由 reprex package (v2.0.1)
于 2021-09-24 创建