[英]Mutate across multiple columns to create new variable sets
我有一個國家和年份級別的面板數據集,我想根據現有變量創建兩個新變量。
年 | 國家 | 變量1 | 變量2 | 變量3 | 變量 4 | mean_var1 | relmean_var1 |
---|---|---|---|---|---|---|---|
1910 | GER | 1 | 4 | 10 | 6 | 3 | 0.333 |
1911 | GER | 2 | 3 | 11 | 7 | 1.5 | 1.3333 |
1910 | 法蘭克福機場 | 5 | 6 | 8 | 9 | 3 | 1.66667 |
1911 | 法蘭克福機場 | 1 | 4 | 10 | 9 | 1.5 | .66667 |
我想做的是創建兩個新變量集:(1)每年(跨國家)平均值的變量集和(2)相對於年平均值的國家價值變量集。 例如,對於 var1(1) 將產生 mean_var1 和 (2) relmean_var1 並且我希望這些用於所有其他變量。 數據集中總共有 1000 多個變量,但我只會將此 function 應用於大約 6 個。
我有適用於第一部分的代碼,但我想盡可能有效地將它與第二部分結合起來。
library(dplyr)
library(purrr)
df<- df%>%
group_by(year) %>%
mutate_at(.funs = list(mean = ~mean(.)), .vars = c("var1", "var1", "var1", "var4"))
此代碼產生名為 var1_mean 的新變量(我更喜歡 mean_var1:如何更改此名稱?)
對於第二步,我嘗試過:
df <- df %>%
map2_dfr(.x = d.test %>%
select(var1, var2),
.y = d.test %>%
select(var1_mean, var2_mean),
~ .x / .y) %>%
setNames(c("relmean_var1", "relmean_var2"))
我得到錯誤
“”選擇錯誤(., var1, var2):未找到 object 'd.test'。”
. (我從這個問題中得到了這個設置)
我也試過:
map2(var1, var1_mean, ~ df[[.x]] / df[[.y]]) %>%
set_names(cols) %>%
bind_cols(df, .)
並得到
“map2 中的錯誤(var1,var1_mean,~df[[.x]]/df[[.y]]):未找到 object 'var1'
結合這兩個目標的最佳方式是什么? 理想情況下,命名方案 mean_var1 用於 (1),relmean_var1 用於 (2)
編輯:輸入 dataframe 應該如下所示:
data <- tibble::tribble(
~year, ~country, ~var1, ~var2, ~var3, ~var.4,
1910L, "GER", 1L, 4L, 10L, 6L,
1911L, "GER", 2L, 3L, 11L, 7L,
1910L, "FRA", 5L, 6L, 8L, 9L,
1911L, "FRA", 1L, 4L, 10L, 9L
)
output dataframe 應如下所示(對於所有變量,僅以 var1 為例,但 var2 到 var4 的格式應相同):
datanew <- tibble::tribble(
~year, ~country, ~var1, ~var2, ~var3, ~var.4, ~mean_var1 , ~relmean_var1
1910L, "GER", 1L, 4L, 10L, 6L, 3L, .3333L,
1911L, "GER", 2L, 3L, 11L, 7L, 1.5L, 1.3333L,
1910L, "FRA", 5L, 6L, 8L, 9L, 3L, 1.6667L,
1911L, "FRA", 1L, 4L, 10L, 9L 1.5L, .6667L,
)
這在長格式中可能更容易,但這是一個您可以追求寬數據的選項。
使用最新版本across
dplyr
,您可以.names
mutate
來定義您希望新列的外觀。
library(tidyverse)
my_col <- c("var1", "var2", "var3", "var4")
df %>%
group_by(year) %>%
mutate(across(my_col, mean, .names = "mean_{col}")) %>%
mutate(across(my_col, .names = "relmean_{col}") / across(paste0("mean_", my_col)))
Output
year country var1 var2 var3 var4 mean_var1 mean_var2 mean_var3 mean_var4 relmean_var1 relmean_var2 relmean_var3 relmean_var4
<int> <chr> <int> <int> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1910 GER 1 4 10 6 3 5 9 7.5 0.333 0.8 1.11 0.8
2 1911 GER 2 3 11 7 1.5 3.5 10.5 8 1.33 0.857 1.05 0.875
3 1910 FRA 5 6 8 9 3 5 9 7.5 1.67 1.2 0.889 1.2
4 1911 FRA 1 4 10 9 1.5 3.5 10.5 8 0.667 1.14 0.952 1.12
library(tidyverse)
data <- tibble::tribble(
~year, ~country, ~var1, ~var2, ~var3, ~var.4,
1910L, "GER", 1L, 2L, 10L, 6L,
1911L, "GER", 2L, 3L, 11L, 7L,
1910L, "FRA", 5L, 6L, 8L, 9L,
1911L, "FRA", 1L, 3L, 10L, 9L
)
data_long <-
data %>%
pivot_longer(-c(year, country))
data_long
#> # A tibble: 16 x 4
#> year country name value
#> <int> <chr> <chr> <int>
#> 1 1910 GER var1 1
#> 2 1910 GER var2 2
#> 3 1910 GER var3 10
#> 4 1910 GER var.4 6
#> 5 1911 GER var1 2
#> 6 1911 GER var2 3
#> 7 1911 GER var3 11
#> 8 1911 GER var.4 7
#> 9 1910 FRA var1 5
#> 10 1910 FRA var2 6
#> 11 1910 FRA var3 8
#> 12 1910 FRA var.4 9
#> 13 1911 FRA var1 1
#> 14 1911 FRA var2 3
#> 15 1911 FRA var3 10
#> 16 1911 FRA var.4 9
means_country <-
data_long %>%
group_by(country) %>%
summarise(mean_country_value = mean(value))
means_years <-
data_long %>%
group_by(year) %>%
summarise(mean_year_value = mean(value))
data %>%
left_join(means_country) %>%
left_join(means_years)
#> Joining, by = "country"
#> Joining, by = "year"
#> # A tibble: 4 x 8
#> year country var1 var2 var3 var.4 mean_country_value mean_year_value
#> <int> <chr> <int> <int> <int> <int> <dbl> <dbl>
#> 1 1910 GER 1 2 10 6 5.25 5.88
#> 2 1911 GER 2 3 11 7 5.25 5.75
#> 3 1910 FRA 5 6 8 9 6.38 5.88
#> 4 1911 FRA 1 3 10 9 6.38 5.75
由代表 package (v2.0.1) 於 2021 年 11 月 24 日創建
這是@danlooo 方法的擴展,因此國家級平均值和年份平均值位於同一數據集中(如果需要)。 顯着的區別是在 pipe 鏈中使用兩個mutate
s,而不是兩個summarize
s,然后加入。
考慮一下你是否真的想要它再次變寬。 通常保持較長時間更容易(例如,刪除對tidyr::pivot_wider()
的最終調用)。
ds <- tibble::tribble(
~year, ~country, ~var1, ~var2, ~var3, ~var4,
1910L, "GER", 1L, 4L, 10L, 6L,
1911L, "GER", 2L, 3L, 11L, 7L,
1910L, "FRA", 5L, 6L, 8L, 9L,
1911L, "FRA", 1L, 4L, 10L, 9L
)
ds |>
dplyr::mutate(
year = as.character(year) # To help the pivot below
) |>
tidyr::pivot_longer(
cols = -c(year, country),
names_to = "key",
names_prefix = "^var"
) |>
dplyr::group_by(country, key) |>
dplyr::mutate(
m_c = mean(value), # Mean for the Country (and variable)
r_c = value / m_c, # Relative mean for the Country (and variable)
) |>
dplyr::ungroup() |>
dplyr::group_by(year, key) |>
dplyr::mutate(
m_y = mean(value), # Mean for the Year (and variable)
r_y = value / m_y, # Relative mean for the Year (and variable)
) |>
dplyr::ungroup() |>
dplyr::mutate(
year = as.integer(year) # Return it to a number
) |>
tidyr::pivot_wider(
id_cols = c(year, country),
names_from = key,
names_glue = "{.value}_{key}",
values_from = c(value, m_c, r_c, m_y, r_y)
)
Output(寬)我更喜歡像@danlooo這樣更長的描述性變量名稱,但我希望一切都適合SO屏幕:
year country value_1 value_2 value_3 value_4 m_c_1 m_c_2 m_c_3 m_c_4 r_c_1 r_c_2 r_c_3 r_c_4 m_y_1 m_y_2 m_y_3 m_y_4 r_y_1 r_y_2 r_y_3 r_y_4
<int> <chr> <int> <int> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1910 GER 1 4 10 6 1.5 3.5 10.5 6.5 0.667 1.14 0.952 0.923 3 5 9 7.5 0.333 0.8 1.11 0.8
2 1911 GER 2 3 11 7 1.5 3.5 10.5 6.5 1.33 0.857 1.05 1.08 1.5 3.5 10.5 8 1.33 0.857 1.05 0.875
3 1910 FRA 5 6 8 9 3 5 9 9 1.67 1.2 0.889 1 3 5 9 7.5 1.67 1.2 0.889 1.2
4 1911 FRA 1 4 10 9 3 5 9 9 0.333 0.8 1.11 1 1.5 3.5 10.5 8 0.667 1.14 0.952 1.12
Output (長 -- 沒有最后的tidyr::pivot_wider()
)
# A tibble: 16 x 8
year country key value m_c r_c m_y r_y
<int> <chr> <chr> <int> <dbl> <dbl> <dbl> <dbl>
1 1910 GER 1 1 1.5 0.667 3 0.333
2 1910 GER 2 4 3.5 1.14 5 0.8
3 1910 GER 3 10 10.5 0.952 9 1.11
...
15 1911 FRA 3 10 9 1.11 10.5 0.952
16 1911 FRA 4 9 9 1 8 1.12
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.