#r #dplyr
Вопрос:
Допустим, у меня есть проблема, подобная следующей:
tib <- tribble(~id, ~var1_countrya, ~var2_countrya, ~var1_countryb, ~var2_countryb,
1, 1, 2, 1, 2,
2, 5, 3, 1, 3,
3, 6, 3, 1, 3
)
Я хотел бы создать новые столбцы delta_countrya = var2_countrya - var1_countrya
и delta_countryb = var2_countryb - var2_countryb
, выбрав пары переменных, используя регулярное выражение и каналы dplyr. Финальная игра должна выглядеть так
id var1_countrya var2_countrya delta_countrya var1_countryb var2_countryb delta_countryb
1 1 2 1 1 2 1
2 5 3 -2 1 3 2
3 6 3 -3 1 3 2
Я изо всех сил пытался даже настроить предложение mutate таким образом, чтобы оно создавало несколько новых переменных, не говоря уже о том, чтобы найти пары переменных, которые я ищу, и учесть разницу.
Ответ №1:
В вашем примере вы можете преобразовать свои столбцы в переменные, разделить столбцы так, чтобы var и страна были разделены, затем повторно объединить, чтобы разные переменные находились в столбцах, и, наконец, вычислить дельту
library(dplyr)
tib <- tribble(~id, ~var1_countrya, ~var2_countrya, ~var1_countryb, ~var2_countryb,
1, 1, 2, 1, 2,
2, 5, 3, 1, 3,
3, 6, 3, 1, 3
) # your code had an error, need to replace ')' with comma
tib2 = tib %>%
pivot_longer(-id, names_to = "var") %>%
separate(var, c("Var", "Country")) %>%
pivot_wider(names_from = Var) %>%
mutate(Delta = var2-var1)
tib2
# # A tibble: 6 x 5
# id Country var1 var2 Delta
# <dbl> <chr> <dbl> <dbl> <dbl>
# 1 1 countrya 1 2 1
# 2 1 countryb 1 2 1
# 3 2 countrya 5 3 -2
# 4 2 countryb 1 3 2
# 5 3 countrya 6 3 -3
# 6 3 countryb 1 3 2
Комментарии:
1. Отлично, это сработало как заклинание. Очевидно, что затем нам понадобится pivot_wider, чтобы получить окончательный результат.
Ответ №2:
base
tib[paste0("delta_country", letters[1:2])] <- tib[paste0("var2_country", letters[1:2])] - tib[paste0("var1_country", letters[1:2])]
# id var1_countrya var2_countrya var1_countryb var2_countryb delta_countrya delta_countryb
# <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 1 1 2 1 2 1 1
# 2 2 5 3 1 3 -2 2
# 3 3 6 3 1 3 -3 2
tidyverse
library(tidyverse)
tib[paste0("delta_country", letters[1:2])] <- map2(tib %>% select(starts_with("var2_country")), tib %>% select(starts_with("var1_country")),
~.x - .y)
tib
# # id var1_countrya var2_countrya var1_countryb var2_countryb delta_countrya delta_countryb
# # <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# # 1 1 1 2 1 2 1 1
# # 2 2 5 3 1 3 -2 2
# # 3 3 6 3 1 3 -3 2
Ответ №3:
Мы также можем воспользоваться base::Reduce
здесь:
Reduce(function(x, y) {
cbind(x, x[, y] - x[, y - 1])
}, seq(1, ncol(tib), 2)[-1], init = tib) |>
setNames(c(names(tib), paste0("delta_country", unique(gsub(".*([[:alpha:]]$)", "\1", names(tib)[-1])))))
id var1_countrya var2_countrya var1_countryb var2_countryb delta_countrya delta_countryb
1 1 1 2 1 2 1 1
2 2 5 3 1 3 -2 2
3 3 6 3 1 3 -3 2