web-dev-qa-db-fra.com

Mutager sur plusieurs colonnes pour créer de nouveaux ensembles de variables

J'ai un jeu de données en panneau au niveau du pays et de l'année, et j'aimerais créer deux nouvelles variables basées sur des personnes existantes.

anpaysvar1var2var3var 4signifie_var1relMean_var1
1910Ger14dix630,333
1911Ger2311sept1.51.3333
1910Fra568931.66667
1911Fra14dix91.5.66667

Ce que j'aimerais faire, c'est créer deux nouvelles variables définies: (1) un ensemble de variables de la moyenne pour chaque année (dans les pays) et (2) un ensemble variable de la valeur du pays relatif à la moyenne de l'année. Par exemple, pour Var1 (1) donnerait des moyens_var1 et (2) RelMean_var1 et je les souhaiterais pour toutes les autres variables. Au total, il y a plus de 1000 variables dans l'ensemble de données, mais je n'appliquerais que cette fonction à environ 6.

J'ai du code qui fonctionne pour la première partie, mais je voudrais le combiner aussi efficacement que possible avec la seconde.

library(dplyr)
library(purrr)
df<- df%>% 
            group_by(year) %>%
            mutate_at(.funs = list(mean = ~mean(.)), .vars = c("var1", "var1", "var1", "var4"))

Ce code donne de nouvelles variables appelées Var1_Mean (je préférerais méchant_var1: Comment changer ce nom?)

Pour la deuxième étape, j'ai essayé:

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"))

et je reçois des erreurs

"" Erreur dans SELECT (., VAR1, VAR2): Objet 'D.Test' introuvable. "

. (J'ai eu cette configuration de cette question )

J'ai aussi essayé:

 map2(var1, var1_mean, ~ df[[.x]] / df[[.y]]) %>% 
   set_names(cols) %>% 
   bind_cols(df, .)

Et a eu

"Erreur dans map2 (var1, var1_mean, ~ df [[[x]]/df [[[y]]]): objet 'var1' non trouvé non trouvé

Quelle est la meilleure façon de combiner ces deux objectifs? Idéalement avec le schéma de dénominage signifie_var1 pour (1) et relMean_var1 pour (2)

EDIT: L'entrée Dataframe devrait ressembler à ceci:

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
)

sortie Dataframe doit ressembler à ceci (pour toutes les variables, il suffit de montrer Var1 à titre d'exemple, mais doit être le même format pour 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,
)
5
PierreRoubaix

Voici une extension de l'approche de @ Danlooo afin que la moyenne de moyenne et une moyenne de niveau de campagne se situe dans le même jeu de données (si cela est souhaité). La différence notable utilise deux mutates dans la chaîne de tuyaux, au lieu de deux summarizes, puis joignant.

Considérez si vous le voulez vraiment grand. Habituellement, il est plus facile de le garder longtemps (par exemple, supprimez l'appel final à 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)
  )

Sortie (large) Je préfère les noms variables descriptifs plus longs tels que @ Danlooo's, mais je voulais que tout s'adapte à SO écran:

   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 

Sortie (long - sans la finale 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 
0
wibeasley