web-dev-qa-db-fra.com

Comment diffuser des colonnes avec des identifiants en double?

A ont le tibble suivant:

structure(list(age = c("21", "17", "32", "29", "15"), 
               gender = structure(c(2L, 1L, 1L, 2L, 2L), .Label = c("Female", "Male"), class = "factor")), 
          row.names = c(NA, -5L), class = c("tbl_df", "tbl", "data.frame"), .Names = c("age", "gender"))

    age gender
  <chr> <fctr>
1    21   Male
2    17 Female
3    32 Female
4    29   Male
5    15   Male

Et j'essaie d'utiliser tidyr::spread Pour y parvenir:

  Female Male
1    NA     21
2    17     NA
3    32     NA
4    NA     29
5    NA     15

Je pensais que spread(gender, age) fonctionnerait, mais je reçois un message d'erreur disant:

Error: Duplicate identifiers for rows (2, 3), (1, 4, 5)
15
Dambo

À l'heure actuelle, vous disposez de deux valeurs age pour Female et trois pour Male, et aucune autre variable ne les empêche d'être réduites en une seule ligne, comme spread essaie de faire avec des valeurs avec des valeurs d'index similaires/sans:

library(tidyverse)

df <- data_frame(x = c('a', 'b'), y = 1:2)

df    # 2 rows...
#> # A tibble: 2 x 2
#>       x     y
#>   <chr> <int>
#> 1     a     1
#> 2     b     2

df %>% spread(x, y)    # ...become one if there's only one value for each.
#> # A tibble: 1 x 2
#>       a     b
#> * <int> <int>
#> 1     1     2

spread n'applique pas de fonction pour combiner plusieurs valeurs (à la dcast), donc les lignes doivent être indexées pour qu'il y ait une ou zéro valeur pour un emplacement, par ex.

df <- data_frame(i = c(1, 1, 2, 2, 3, 3), 
                 x = c('a', 'b', 'a', 'b', 'a', 'b'), 
                 y = 1:6)

df    # the two rows with each `i` value here...
#> # A tibble: 6 x 3
#>       i     x     y
#>   <dbl> <chr> <int>
#> 1     1     a     1
#> 2     1     b     2
#> 3     2     a     3
#> 4     2     b     4
#> 5     3     a     5
#> 6     3     b     6

df %>% spread(x, y)    # ...become one row here.
#> # A tibble: 3 x 3
#>       i     a     b
#> * <dbl> <int> <int>
#> 1     1     1     2
#> 2     2     3     4
#> 3     3     5     6

Si vos valeurs ne sont pas indexées naturellement par les autres colonnes, vous pouvez ajouter une colonne d'index unique (par exemple en ajoutant les numéros de ligne en tant que colonne) qui empêchera spread d'essayer de réduire les lignes:

df <- structure(list(age = c("21", "17", "32", "29", "15"), 
                     gender = structure(c(2L, 1L, 1L, 2L, 2L), 
                                        .Label = c("Female", "Male"), class = "factor")), 
                row.names = c(NA, -5L), 
                class = c("tbl_df", "tbl", "data.frame"), 
                .Names = c("age", "gender"))

df %>% mutate(i = row_number()) %>% spread(gender, age)
#> # A tibble: 5 x 3
#>       i Female  Male
#> * <int>  <chr> <chr>
#> 1     1   <NA>    21
#> 2     2     17  <NA>
#> 3     3     32  <NA>
#> 4     4   <NA>    29
#> 5     5   <NA>    15

Si vous souhaitez le supprimer par la suite, ajoutez select(-i). Cela ne produit pas un data.frame terriblement utile dans ce cas, mais peut être très utile au milieu d'un remodelage plus compliqué.

21
alistaire