在 tibble 列表列中创建“NULL”变量
Create `NULL` variable in tibble list column
我想创建一个列表与 3 个命名元素的组合,即 B
、m
、replace
。例如 list(B = 50, m = 100, replace = FALSE)
就是一个这样的列表实例。我想将这些组合存储为 tibble
中的列表列,以及 B
、m
、replace
的网格值组合作为单独的列,用于构建个人 list
值。
目前为了构建此类列表,我为单个值 B
、m
、replace
创建了一个序列网格,然后只是交叉连接和变异。一个reprex如下所示:
library(tidyverse)
# Create individual sequences of grid values to cross join
B <- seq(from = 50, to = 250, by = 50)
m <- seq(from = 100, to = 300, by = 100)
# Uncommenting this line - causes issues
# m <- c(NA, m)
# Don't call it replace, so function replace function is not overidden
replc <- c(TRUE, FALSE)
# Inspect the individual grid values
B
#> [1] 50 100 150 200 250
m
#> [1] 100 200 300
replc
#> [1] TRUE FALSE
# TODO: Need to construct just NULL value
out_crossing <- tidyr::crossing(B, m, replc) %>%
dplyr::arrange(.data = ., B, m) %>%
dplyr::rename("replace" = replc) %>%
dplyr::rowwise(data = .) %>%
dplyr::mutate(boot_emp = list(tibble::lst("B" = B,
"m" = ifelse(!is.na(m), m, NULL),
"replace" = replace)))
# Seems to work, but would be nice to have
head(out_crossing, 3)
#> # A tibble: 3 x 4
#> # Rowwise:
#> B m replace boot_emp
#> <dbl> <dbl> <lgl> <list>
#> 1 50 100 FALSE <named list [3]>
#> 2 50 100 TRUE <named list [3]>
#> 3 50 200 FALSE <named list [3]>
# Check an individual element is a list with 3 elements
out_crossing[1, 4]$boot_emp
#> [[1]]
#> [[1]]$B
#> [1] 50
#>
#> [[1]]$m
#> [1] 100
#>
#> [[1]]$replace
#> [1] FALSE
由 reprex package (v2.0.0)
于 2021-04-07 创建
这行得通。虽然有一个小转折。对于 m
的值,我希望列表包含 NULL
值,即希望 list(B = 50, m = NULL, replace = FALSE)
作为输出之一。不幸的是,您不能将 NULL
值添加到向量中。所以作为黑客,我试图添加
NA
值,即通过取消注释上面 reprex 中的 # m <- c(NA, m)
行,然后在 mutate
行 [=33] 中将 NA
值调整为 NULL
=] 在最终列表中。这给出了 error
:
Error: Problem with `mutate()` input `boot_emp`.
x replacement has length zero
ℹ Input `boot_emp` is `list(tibble::lst(B = B, m = ifelse(!is.na(m), m, NULL), replace = replace))`.
ℹ The error occurred in row 7.
如果可能的话,谁能告诉我如何让它工作吗?
问题出在 ifelse
步骤中,每个参数应该具有相同的 length
,但是
length(NULL)
#[1] 0
因此,我们可能需要将条件更改为 NA
作为 'no' 值而不是 ifelse
中的 NULL
如果我们需要 NULL
个值,则在 vector
中是不可能的,但可以包含在 list
中,即
out_crossing <- tidyr::crossing(B, m, replc) %>%
dplyr::arrange(.data = ., B, m) %>%
dplyr::rename("replace" = replc) %>%
dplyr::rowwise(data = .) %>%
dplyr::mutate(boot_emp = list(tibble::lst("B" = B,
"m" = ifelse(!is.na(m), m, list(NULL)),
"replace" = replace)))
然后,我们移除 list
包装
out_crossing$boot_emp <- purrr::map(out_crossing$boot_emp,
~ purrr::map(.x, ~ if(is.list(.x) && is.null(.x[[1]])) NULL else .x ))
-输出
out_crossing$boot_emp[40]
#[[1]]
#[[1]]$B
#[1] 250
#[[1]]$m
#NULL
#[[1]]$replace
#[1] TRUE
或者如果只有一个元素,就做if/else
out_crossing <- tidyr::crossing(B, m, replc) %>%
dplyr::arrange(.data = ., B, m) %>%
dplyr::rename("replace" = replc) %>%
dplyr::rowwise(data = .) %>%
dplyr::mutate(boot_emp = list(tibble::lst("B" = B,
"m" = if(!is.na(m)) m else NULL,
"replace" = replace)))
out_crossing$boot_emp[40]
#[[1]]
#[[1]]$B
#[1] 250
#[[1]]$m
#NULL
#[[1]]$replace
#[1] TRUE
在试验和阅读 this helpful thread 之后,我意识到有一种方法可以做到这一点,但是使用 switch
语句而不是 ifelse
语句。完整的reprex
如下:
library(tidyverse)
# Create individual sequences of grid values to cross join
B <- seq(from = 50, to = 250, by = 50)
m <- seq(from = 100, to = 300, by = 100)
# Allow NULL values for m. However, vectors can't take NULL values so we
# set add NA values instead. We will coerce these to NULL values at the time
# the list is constructed
m <- c(NA, m)
# Don't call it replace, so function replace function is not overidden
replc <- c(TRUE, FALSE)
# Inspect the individual grid values
B
#> [1] 50 100 150 200 250
m
#> [1] NA 100 200 300
replc
#> [1] TRUE FALSE
# TODO: Need to construct just NULL value
out_crossing <- tidyr::crossing(B, m, replc) %>%
dplyr::arrange(.data = ., B, m) %>%
dplyr::rename("replace" = replc) %>%
dplyr::rowwise(data = .) %>%
dplyr::mutate(boot_emp = list(tibble::lst("B" = B,
"m" = switch(!is.na(m), m, NULL),
# "m" = ifelse(!is.na(m), m, NULL),
"replace" = replace)))
# Seems to work, but would be nice to have
head(out_crossing, 3)
#> # A tibble: 3 x 4
#> # Rowwise:
#> B m replace boot_emp
#> <dbl> <dbl> <lgl> <list>
#> 1 50 100 FALSE <named list [3]>
#> 2 50 100 TRUE <named list [3]>
#> 3 50 200 FALSE <named list [3]>
# out_crossing %>% dplyr::glimpse()
# out_crossing %>% View()
# Check an individual element is a list with 3 elements
out_crossing[8, 4]$boot_emp
#> [[1]]
#> [[1]]$B
#> [1] 50
#>
#> [[1]]$m
#> NULL
#>
#> [[1]]$replace
#> [1] TRUE
由 reprex package (v2.0.0)
于 2021-04-07 创建
希望这对其他人有帮助。我希望看到其他方法来解决这个问题,这些方法可能比这种方法更有优势。所以请继续添加到这个线程,以便我自己和其他人可以学习。
我想创建一个列表与 3 个命名元素的组合,即 B
、m
、replace
。例如 list(B = 50, m = 100, replace = FALSE)
就是一个这样的列表实例。我想将这些组合存储为 tibble
中的列表列,以及 B
、m
、replace
的网格值组合作为单独的列,用于构建个人 list
值。
目前为了构建此类列表,我为单个值 B
、m
、replace
创建了一个序列网格,然后只是交叉连接和变异。一个reprex如下所示:
library(tidyverse)
# Create individual sequences of grid values to cross join
B <- seq(from = 50, to = 250, by = 50)
m <- seq(from = 100, to = 300, by = 100)
# Uncommenting this line - causes issues
# m <- c(NA, m)
# Don't call it replace, so function replace function is not overidden
replc <- c(TRUE, FALSE)
# Inspect the individual grid values
B
#> [1] 50 100 150 200 250
m
#> [1] 100 200 300
replc
#> [1] TRUE FALSE
# TODO: Need to construct just NULL value
out_crossing <- tidyr::crossing(B, m, replc) %>%
dplyr::arrange(.data = ., B, m) %>%
dplyr::rename("replace" = replc) %>%
dplyr::rowwise(data = .) %>%
dplyr::mutate(boot_emp = list(tibble::lst("B" = B,
"m" = ifelse(!is.na(m), m, NULL),
"replace" = replace)))
# Seems to work, but would be nice to have
head(out_crossing, 3)
#> # A tibble: 3 x 4
#> # Rowwise:
#> B m replace boot_emp
#> <dbl> <dbl> <lgl> <list>
#> 1 50 100 FALSE <named list [3]>
#> 2 50 100 TRUE <named list [3]>
#> 3 50 200 FALSE <named list [3]>
# Check an individual element is a list with 3 elements
out_crossing[1, 4]$boot_emp
#> [[1]]
#> [[1]]$B
#> [1] 50
#>
#> [[1]]$m
#> [1] 100
#>
#> [[1]]$replace
#> [1] FALSE
由 reprex package (v2.0.0)
于 2021-04-07 创建这行得通。虽然有一个小转折。对于 m
的值,我希望列表包含 NULL
值,即希望 list(B = 50, m = NULL, replace = FALSE)
作为输出之一。不幸的是,您不能将 NULL
值添加到向量中。所以作为黑客,我试图添加
NA
值,即通过取消注释上面 reprex 中的 # m <- c(NA, m)
行,然后在 mutate
行 [=33] 中将 NA
值调整为 NULL
=] 在最终列表中。这给出了 error
:
Error: Problem with `mutate()` input `boot_emp`.
x replacement has length zero
ℹ Input `boot_emp` is `list(tibble::lst(B = B, m = ifelse(!is.na(m), m, NULL), replace = replace))`.
ℹ The error occurred in row 7.
如果可能的话,谁能告诉我如何让它工作吗?
问题出在 ifelse
步骤中,每个参数应该具有相同的 length
,但是
length(NULL)
#[1] 0
因此,我们可能需要将条件更改为 NA
作为 'no' 值而不是 ifelse
NULL
如果我们需要 NULL
个值,则在 vector
中是不可能的,但可以包含在 list
中,即
out_crossing <- tidyr::crossing(B, m, replc) %>%
dplyr::arrange(.data = ., B, m) %>%
dplyr::rename("replace" = replc) %>%
dplyr::rowwise(data = .) %>%
dplyr::mutate(boot_emp = list(tibble::lst("B" = B,
"m" = ifelse(!is.na(m), m, list(NULL)),
"replace" = replace)))
然后,我们移除 list
包装
out_crossing$boot_emp <- purrr::map(out_crossing$boot_emp,
~ purrr::map(.x, ~ if(is.list(.x) && is.null(.x[[1]])) NULL else .x ))
-输出
out_crossing$boot_emp[40]
#[[1]]
#[[1]]$B
#[1] 250
#[[1]]$m
#NULL
#[[1]]$replace
#[1] TRUE
或者如果只有一个元素,就做if/else
out_crossing <- tidyr::crossing(B, m, replc) %>%
dplyr::arrange(.data = ., B, m) %>%
dplyr::rename("replace" = replc) %>%
dplyr::rowwise(data = .) %>%
dplyr::mutate(boot_emp = list(tibble::lst("B" = B,
"m" = if(!is.na(m)) m else NULL,
"replace" = replace)))
out_crossing$boot_emp[40]
#[[1]]
#[[1]]$B
#[1] 250
#[[1]]$m
#NULL
#[[1]]$replace
#[1] TRUE
在试验和阅读 this helpful thread 之后,我意识到有一种方法可以做到这一点,但是使用 switch
语句而不是 ifelse
语句。完整的reprex
如下:
library(tidyverse)
# Create individual sequences of grid values to cross join
B <- seq(from = 50, to = 250, by = 50)
m <- seq(from = 100, to = 300, by = 100)
# Allow NULL values for m. However, vectors can't take NULL values so we
# set add NA values instead. We will coerce these to NULL values at the time
# the list is constructed
m <- c(NA, m)
# Don't call it replace, so function replace function is not overidden
replc <- c(TRUE, FALSE)
# Inspect the individual grid values
B
#> [1] 50 100 150 200 250
m
#> [1] NA 100 200 300
replc
#> [1] TRUE FALSE
# TODO: Need to construct just NULL value
out_crossing <- tidyr::crossing(B, m, replc) %>%
dplyr::arrange(.data = ., B, m) %>%
dplyr::rename("replace" = replc) %>%
dplyr::rowwise(data = .) %>%
dplyr::mutate(boot_emp = list(tibble::lst("B" = B,
"m" = switch(!is.na(m), m, NULL),
# "m" = ifelse(!is.na(m), m, NULL),
"replace" = replace)))
# Seems to work, but would be nice to have
head(out_crossing, 3)
#> # A tibble: 3 x 4
#> # Rowwise:
#> B m replace boot_emp
#> <dbl> <dbl> <lgl> <list>
#> 1 50 100 FALSE <named list [3]>
#> 2 50 100 TRUE <named list [3]>
#> 3 50 200 FALSE <named list [3]>
# out_crossing %>% dplyr::glimpse()
# out_crossing %>% View()
# Check an individual element is a list with 3 elements
out_crossing[8, 4]$boot_emp
#> [[1]]
#> [[1]]$B
#> [1] 50
#>
#> [[1]]$m
#> NULL
#>
#> [[1]]$replace
#> [1] TRUE
由 reprex package (v2.0.0)
于 2021-04-07 创建希望这对其他人有帮助。我希望看到其他方法来解决这个问题,这些方法可能比这种方法更有优势。所以请继续添加到这个线程,以便我自己和其他人可以学习。