如何根据 R 中 tibble 中另一列指示的列的值添加列
How to add a column based on values of columns indicated by another column in a tibble in R
在下面的示例中,我想根据列 'variable' 的值(即 1 和 20)添加列 'value'。
toy_data <-
tibble::tribble(
~x, ~y, ~variable,
1, 2, "x",
10, 20, "y"
)
像这样:
x
y
variable
value
1
2
x
1
10
20
y
20
但是,以下 none 有效:
toy_data %>%
dplyr::mutate(
value = get(variable)
)
toy_data %>%
dplyr::mutate(
value = mget(variable)
)
toy_data %>%
dplyr::mutate(
value = mget(variable, inherits = TRUE)
)
toy_data %>%
dplyr::mutate(
value = !!variable
)
我该怎么做?
如果您事先知道数据框中有哪些变量:使用 ifelse()
或 dplyr::case_when()
等简单逻辑在它们之间进行选择。
如果不是:使用函数式编程。下面是一个例子:
library(dplyr)
f <- function(data, variable_col) {
data[[variable_col]] %>%
purrr::imap_dbl(~ data[[.y, .x]])
}
toy_data$value <- f(toy_data, "variable")
这里有一些应该可以很好扩展的选项。
First 是一个基本选项,适用于 variable
列及其索引。 (我复制了一份数据框,这样我就可以完整地保留原件以进行更多编程。)
library(dplyr)
toy2 <- toy_data
toy2$value <- mapply(function(v, i) toy_data[[v]][i], toy_data$variable, seq_along(toy_data$variable))
toy2
#> # A tibble: 2 × 4
#> x y variable value
#> <dbl> <dbl> <chr> <dbl>
#> 1 1 2 x 1
#> 2 10 20 y 20
第二个使用 purrr::imap_dbl
遍历变量及其索引,return 一个双精度值。
toy_data %>%
mutate(value = purrr::imap_dbl(variable, function(v, i) toy_data[[v]][i]))
#> # A tibble: 2 × 4
#> x y variable value
#> <dbl> <dbl> <chr> <dbl>
#> 1 1 2 x 1
#> 2 10 20 y 20
第三个最不直接,但我个人最有可能使用它,可能只是因为它适合我的许多工作流程。旋转生成数据的长版本,让您看到 variable
的值以及 x
和 y
的对应值,然后您可以过滤这两个列匹配的位置。然后自连接回数据框。
inner_join(
toy_data,
toy_data %>%
tidyr::pivot_longer(cols = -variable, values_to = "value") %>%
filter(variable == name),
by = "variable"
) %>%
select(-name)
#> # A tibble: 2 × 4
#> x y variable value
#> <dbl> <dbl> <chr> <dbl>
#> 1 1 2 x 1
#> 2 10 20 y 20
编辑: @jpiversen 正确地指出,如果 variable
有重复项,自连接将不起作用——在这种情况下,将行号添加到数据并将其用作附加连接列。这里我先补充一个观察来说明。
toy3 <- toy_data %>%
add_row(x = 5, y = 4, variable = "x") %>%
tibble::rowid_to_column()
inner_join(
toy3,
toy3 %>%
pivot_longer(cols = c(-rowid, -variable), values_to = "value") %>%
filter(variable == name),
by = c("rowid", "variable")
) %>%
select(-name, -rowid)
在下面的示例中,我想根据列 'variable' 的值(即 1 和 20)添加列 'value'。
toy_data <-
tibble::tribble(
~x, ~y, ~variable,
1, 2, "x",
10, 20, "y"
)
像这样:
x | y | variable | value |
---|---|---|---|
1 | 2 | x | 1 |
10 | 20 | y | 20 |
但是,以下 none 有效:
toy_data %>%
dplyr::mutate(
value = get(variable)
)
toy_data %>%
dplyr::mutate(
value = mget(variable)
)
toy_data %>%
dplyr::mutate(
value = mget(variable, inherits = TRUE)
)
toy_data %>%
dplyr::mutate(
value = !!variable
)
我该怎么做?
如果您事先知道数据框中有哪些变量:使用 ifelse()
或 dplyr::case_when()
等简单逻辑在它们之间进行选择。
如果不是:使用函数式编程。下面是一个例子:
library(dplyr)
f <- function(data, variable_col) {
data[[variable_col]] %>%
purrr::imap_dbl(~ data[[.y, .x]])
}
toy_data$value <- f(toy_data, "variable")
这里有一些应该可以很好扩展的选项。
First 是一个基本选项,适用于 variable
列及其索引。 (我复制了一份数据框,这样我就可以完整地保留原件以进行更多编程。)
library(dplyr)
toy2 <- toy_data
toy2$value <- mapply(function(v, i) toy_data[[v]][i], toy_data$variable, seq_along(toy_data$variable))
toy2
#> # A tibble: 2 × 4
#> x y variable value
#> <dbl> <dbl> <chr> <dbl>
#> 1 1 2 x 1
#> 2 10 20 y 20
第二个使用 purrr::imap_dbl
遍历变量及其索引,return 一个双精度值。
toy_data %>%
mutate(value = purrr::imap_dbl(variable, function(v, i) toy_data[[v]][i]))
#> # A tibble: 2 × 4
#> x y variable value
#> <dbl> <dbl> <chr> <dbl>
#> 1 1 2 x 1
#> 2 10 20 y 20
第三个最不直接,但我个人最有可能使用它,可能只是因为它适合我的许多工作流程。旋转生成数据的长版本,让您看到 variable
的值以及 x
和 y
的对应值,然后您可以过滤这两个列匹配的位置。然后自连接回数据框。
inner_join(
toy_data,
toy_data %>%
tidyr::pivot_longer(cols = -variable, values_to = "value") %>%
filter(variable == name),
by = "variable"
) %>%
select(-name)
#> # A tibble: 2 × 4
#> x y variable value
#> <dbl> <dbl> <chr> <dbl>
#> 1 1 2 x 1
#> 2 10 20 y 20
编辑: @jpiversen 正确地指出,如果 variable
有重复项,自连接将不起作用——在这种情况下,将行号添加到数据并将其用作附加连接列。这里我先补充一个观察来说明。
toy3 <- toy_data %>%
add_row(x = 5, y = 4, variable = "x") %>%
tibble::rowid_to_column()
inner_join(
toy3,
toy3 %>%
pivot_longer(cols = c(-rowid, -variable), values_to = "value") %>%
filter(variable == name),
by = c("rowid", "variable")
) %>%
select(-name, -rowid)