Я генерирую несколько столбцов в вызове mutate(), используя функцию 1) уже существующего столбца и 2) некоторого значения, которое отличается для каждого выходного столбца. Следующий код производит то, что я хочу, но он пахнет:
df <- tibble(base_string = c("a", "b", "c"))
df_desired_result <- df |>
mutate(
one = str_c(base_string, "1"),
two = str_c(base_string, "2"),
three = str_c(base_string, "3")
)
df_desired_result
# A tibble: 3 × 4
base_string one two three
<chr> <chr> <chr> <chr>
1 a a1 a2 a3
2 b b1 b2 b3
3 c c1 c2 c3
Если бы было много других столбцов, это было бы плохим решением.
Лучшее улучшение, которое я придумал, это:
df_also_desired_result <- df |>
expand_grid(
tibble(
number_name = c("one", "two", "three"),
number_string = c("1", "2", "3")
)
) |>
mutate(final_string = str_c(base_string, number_string)) |>
pivot_wider(
id_cols = base_string,
names_from = number_name,
values_from = final_string
)
df_also_desired_result
# A tibble: 3 × 4
base_string one two three
<chr> <chr> <chr> <chr>
1 a a1 a2 a3
2 b b1 b2 b3
3 c c1 c2 c3
Но это кажется слишком многословным. Буду рад любым предложениям о том, как лучше это сделать.





Не уверен насчет «идиоматической» части, но немного более короткий подход с вложенными тибблами, управляемыми именованным вектором, который используется с purrr::map(), имена становятся именами столбцов, а аргументы функции выбираются из элементов.
library(dplyr)
library(tidyr)
library(purrr)
library(stringr)
df <- tibble(base_string = c("a", "b", "c"))
# named vector, column_name = "argument"
col_args <- c(one = "1", two = "2", three = "3")
# add a tibble column with new columns, controlled by col_args; unnest
df |>
mutate(cols = map(col_args, \(x) str_c(base_string, x)) |> bind_cols()) |>
unnest(cols)
#> # A tibble: 3 × 4
#> base_string one two three
#> <chr> <chr> <chr> <chr>
#> 1 a a1 a2 a3
#> 2 b b1 b2 b3
#> 3 c c1 c2 c3
Created on 2024-07-27 with reprex v2.1.0
Базовое решение R:
vars <- c("one"=1, "two"=2, "three"=3)
df <- data.frame(base_string = c("a", "b", "c"))
df[names(vars)] <- sapply(vars, \(x) paste0(df$base_string, x))
df
base_string one two three
1 a a1 a2 a3
2 b b1 b2 b3
3 c c1 c2 c3
Если ваши переменные и значения находятся в разных векторах, как в вашей попытке решения, используйте этот вариант:
vars = c("one", "two", "three")
vals = c("1", "2", "3")
df <- data.frame(base_string = c("a", "b", "c"))
df[vars] <- sapply(vals, \(x) paste0(df$base_string, x))
в базе R вы можете попробовать outer + paste0, как показано ниже.
> cbind(df, outer(df$base_string, vars, paste0))
base_string one two three
1 a a1 a2 a3
2 b b1 b2 b3
3 c c1 c2 c3
заимствовано из решения Эдварда
vars <- c("one" = 1, "two" = 2, "three" = 3)
df <- data.frame(base_string = c("a", "b", "c"))
Спасибо всем за ответы. Эдварда настолько хорош, что я раньше его принял, но передумал, так как мне очень хотелось чего-то с помощью Tidyverse. Сегодня я получил то, что изначально искал, создав постоянные столбцы для чисел, а затем используя across():
df <- tibble(base_string = c("a", "b", "c"))
df |>
mutate(
one = "1", two = "2", three = "3",
across(one:three, \(x) str_c(base_string, x))
)
А если определения столбцов находятся в именованном векторе, вы можете использовать !!! для объединения аргументов.
column_definitions <- c(one = "1", two = "2", three = "3")
df |>
mutate(
!!!column_definitions,
across(names(column_definitions), \(x) str_c(base_string, x))
)
Если вы предпочитаете способ tidyverse, вы можете попробовать
df %>%
cross_join(enframe(vars)) %>%
mutate(value = str_c(base_string, value)) %>%
pivot_wider(
names_from = name,
values_from = value
)
который дает
# A tibble: 3 × 4
base_string one two three
<chr> <chr> <chr> <chr>
1 a a1 a2 a3
2 b b1 b2 b3
3 c c1 c2 c3