web-dev-qa-db-fra.com

Répandre avec data.frame/tibble avec des identificateurs en double

La documentation de tidyr suggère que la collecte et la propagation sont transitives, mais l'exemple suivant avec les données "iris" montre qu'elles ne le sont pas, mais on ne sait pas pourquoi. Toute clarification serait grandement appréciée

iris.df = as.data.frame(iris)
long.iris.df = iris.df %>% gather(key = feature.measure, value = size, -Species)
w.iris.df = long.iris.df %>% spread(key = feature.measure, value = size, -Species)

Je m'attendais à ce que la trame de données "w.iris.df" soit identique à "iris.df", mais j'ai reçu l'erreur suivante: 

"Erreur: identificateurs en double pour les lignes (1, 2, 3, 4, 5, 6, 7, 8, 9 ..."

Ma question générale est de savoir comment inverser une application de "rassembler" sur ce type de jeu de données.

35
John D Lee

L’intervention de Hadley était sans surprise parfaite ... mais j’ai fini par modifier la syntaxe un peu plus tard ... alors, pour ce que ça vaut, je publie le code entièrement opérationnel (désolée, ma syntaxe est un peu différente de celle ci-dessus):

library(tidyr)
library(dplyr)

wide <- 
  iris %>%
  mutate(row = row_number()) %>%
  gather(vars, val, -Species, -row) %>%
  spread(vars, val)

head(wide)
#   Species row Petal.Length Petal.Width Sepal.Length Sepal.Width
# 1  setosa   1          1.4         0.2          5.1         3.5
# 2  setosa   2          1.4         0.2          4.9         3.0
# 3  setosa   3          1.3         0.2          4.7         3.2
# 4  setosa   4          1.5         0.2          4.6         3.1
# 5  setosa   5          1.4         0.2          5.0         3.6
# 6  setosa   6          1.7         0.4          5.4         3.9

head(iris)
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1          5.1         3.5          1.4         0.2  setosa
# 2          4.9         3.0          1.4         0.2  setosa
# 3          4.7         3.2          1.3         0.2  setosa
# 4          4.6         3.1          1.5         0.2  setosa
# 5          5.0         3.6          1.4         0.2  setosa
# 6          5.4         3.9          1.7         0.4  setosa

Ils sont les mêmes .... il suffit de réorganiser si vous en avez envie ... 

wide <- wide[,c(3, 4, 5, 6, 1)]  ## Reorder and then remove "row" column

et fait.

26
Amit Kohli

Comme la réponse précédente n’était peut-être pas suffisamment claire, la façon dont vous exécutez gather pose un problème qui apparaît lorsque vous essayez de modifier spread

Le problème est qu’au cours du processus de collecte, vous perdez la trace de ce que feature.measure appartient à quelle ligne du cadre de données original, de sorte que spread n’a aucune idée de la manière de combiner à nouveau des valeurs individuelles dans la table "large".

iris.df = as.data.frame(iris)
long.iris.df = iris.df %>% 
  tibble::rowid_to_column() %>% 
  gather(key = feature.measure, value = size, -Species, -rowid)

#>   rowid Species feature.measure size
#> 1     1  setosa    Sepal.Length  5.1
#> 2     2  setosa    Sepal.Length  4.9
#> 3     3  setosa    Sepal.Length  4.7
#> 4     4  setosa    Sepal.Length  4.6
#> 5     5  setosa    Sepal.Length  5.0
#> 6     6  setosa    Sepal.Length  5.4

Désormais, chaque valeur de size conserve sa rowid afin que vous puissiez toujours la recombiner dans le jeu de données étendu (en supprimant rowid inutile):

w.iris.df = long.iris.df %>% 
  spread(key = feature.measure, value = size) %>% 
  select(-rowid)
head(w.iris.df)
#>   Species Petal.Length Petal.Width Sepal.Length Sepal.Width
#> 1  setosa          1.4         0.2          5.1         3.5
#> 2  setosa          1.4         0.2          4.9         3.0
#> 3  setosa          1.3         0.2          4.7         3.2
#> 4  setosa          1.5         0.2          4.6         3.1
#> 5  setosa          1.4         0.2          5.0         3.6
#> 6  setosa          1.7         0.4          5.4         3.9
0
dmi3kno