Tidyverse/Dplyr 解决方案,用于为从嵌套列表中提取的列名称分配值

问题描述 投票:0回答:1

我有一个 tibble,其中有一列包含嵌套列表(具体来说,>> 数据类型)。

它看起来像下面这样(但是采用R/Arrow格式):

身份证 嵌套值
001
[[1]] (1,0.1) [[2]] (2,0.2) [[3]] (3,0.3) [[4]] (4,0.4) [[5]] (5,0.5)
002
[[1]] (1,0.1) [[2]] (2,0.2) [[3]] (3,0.3) [[4]] (4,0.4)
003
[[1]] (1,0.1) [[2]] (2,0.2) [[3]] (3,0.3)
004
[[1]] (1,0.1) [[2]] (2,0.2)
005
[[1]] (1,0.1)

如果我调用 nestedvals 的第 1 行,我会得到:

tibble$nestedvals[1]
<list<list<double>>[1]>
[[1]]
<list<double>[5]>
[[1]]
[1] 1   0.1

[[2]]
[1] 2   0.2

[[3]]
[1] 3   0.3

[[4]]
[1] 4   0.4

[[5]]
[1] 5   0.5

基本上,对于 nestedvals 列,有一个包含双精度对列表的列表,第一个表示特定索引(例如 5)和特定值(例如 0.5)。

我想做的是根据每个嵌套列表的唯一索引的范围生成一组零填充列。例如。: 列_1、列_2、列_3、列_4、列_5

然后根据索引(每个嵌套列表中的第一个数字),将 tibble 的每一行的每个 0 替换为值(嵌套列表中的第二个数字)。

我相信最好的方法是取消列出变量并使用索引列表和感兴趣的值列表创建单独的列,这样我就可以找到前者的名称生成最大值以及两个之间的分配。

为了实现这一点,我编写了一个函数来分割每个嵌套列表:

  nestsplit <- function(x, y) {
    unlist(lapply(x, `[[`, y))
  }

然后生成具有列名称(按索引)和感兴趣的值的唯一列以附加到 tibble:

  tibble <-
    tibble |> rowwise() |> mutate(index_names = list(paste0(
      "col_", as.character(nestsplit(nestedvals, 1))
    )),
    index_values = list(nestsplit(nestedvals, 2)))

但是我想看看是否有一个高效的、row-wise、基于tidyverse/dplyr的解决方案,可以使用index_names变量中的信息将index_values中的值分配给基于索引的列名称,而不是编写一个循环来按行分配它们。

这样的输出是这样的:

身份证 嵌套值 col_1 col_2 col_3 col_4 col_5
001
<Nested list of 5 pairs of values>
0 0 0 0 0
002
<Nested list of 4 pairs of values>
0 0 0 0 0
003
<Nested list of 3 pairs of values>
0 0 0 0 0
004
<Nested list of 2 pairs of values>
0 0 0 0 0
005
<Nested list of 1 pair of values>
0 0 0 0 0

看起来像下面这样:

身份证 嵌套值 col_1 col_2 col_3 col_4 col_5
001
<Nested list of 5 pairs of values>
0.1 0.2 0.3 0.4 0.5
002
<Nested list of 4 pairs of values>
0.1 0.2 0.3 0.4 0
003
<Nested list of 3 pairs of values>
0.1 0.2 0.3 0 0
004
<Nested list of 2 pairs of values>
0.1 0.2 0 0 0
005
<Nested list of 1 pair of values>
0.1 0 0 0 0

生成上面的一些示例数据,请使用:

tibble <-
  structure(
    list(
      ID = c(001, 002, 003, 004, 005),
      nestedvals = structure(
        list(
          structure(
            list(c(1, 0.1), c(2, 0.2), c(3, 0.3), c(4, 0.4), c(5, 0.5)),
            class = c("arrow_list", "vctrs_list_of", "vctrs_vctr", "list"),
            ptype = numeric(0)
          ),
          structure(
            list(c(1, 0.1), c(2, 0.2), c(3, 0.3), c(4, 0.4)),
            class = c("arrow_list", "vctrs_list_of", "vctrs_vctr", "list"),
            ptype = numeric(0)
          ),
          structure(
            list(c(1, 0.1), c(2, 0.2), c(3, 0.3)),
            class = c("arrow_list", "vctrs_list_of", "vctrs_vctr", "list"),
            ptype = numeric(0)
          ),
          structure(
            list(c(1, 0.1), c(2, 0.2)),
            class = c("arrow_list", "vctrs_list_of", "vctrs_vctr", "list"),
            ptype = numeric(0)
          ),
          structure(
            list(c(1, 0.1)),
            class = c("arrow_list", "vctrs_list_of", "vctrs_vctr", "list"),
            ptype = numeric(0)
          )
        ),
        ptype = structure(
          list(),
          class = c("arrow_list", "vctrs_list_of", "vctrs_vctr", "list"),
          ptype = numeric(0)
        ),
        class = c("arrow_list", "vctrs_list_of", "vctrs_vctr", "list")
      )
    ),
    row.names = c(NA, -5L),
    class = c("tbl_df", "tbl", "data.frame")
  )
r dplyr tidyr nested-lists
1个回答
0
投票

您可以将嵌套值绑定到数据框中,取消嵌套,然后进行透视:

library(dplyr)
library(tidyr)
library(purrr)

dat |>
  mutate(cols =  map(nestedvals, ~ setNames(do.call(rbind.data.frame, .x), c("col", "val")))) |>
  unnest(cols) |>
  pivot_wider(names_from = col, values_from = val, values_fill = 0, names_prefix = "col_")

# A tibble: 5 × 7
     ID nestedvals col_1 col_2 col_3 col_4 col_5
  <dbl> <arrw_lst> <dbl> <dbl> <dbl> <dbl> <dbl>
1     1        [5]   0.1   0.2   0.3   0.4   0.5
2     2        [4]   0.1   0.2   0.3   0.4   0  
3     3        [3]   0.1   0.2   0.3   0     0  
4     4        [2]   0.1   0.2   0     0     0  
5     5        [1]   0.1   0     0     0     0  
© www.soinside.com 2019 - 2024. All rights reserved.