313 votes

Comment remodeler les données du format long au format large

J'ai des difficultés à réorganiser le cadre de données suivant :

set.seed(45)
dat1 <- data.frame(
    name = rep(c("firstName", "secondName"), each=4),
    numbers = rep(1:4, 2),
    value = rnorm(8)
    )

dat1
       name  numbers      value
1  firstName       1  0.3407997
2  firstName       2 -0.7033403
3  firstName       3 -0.3795377
4  firstName       4 -0.7460474
5 secondName       1 -0.8981073
6 secondName       2 -0.3347941
7 secondName       3 -0.5013782
8 secondName       4 -0.1745357

Je veux le remodeler de façon à ce que chaque variable unique "nom" soit un rowname, avec les "valeurs" comme observations sur cette ligne et les "nombres" comme colnames. Un peu comme ceci :

     name          1          2          3         4
1  firstName  0.3407997 -0.7033403 -0.3795377 -0.7460474
5 secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357

J'ai regardé melt et cast et quelques autres choses, mais rien ne semble faire l'affaire.

3 votes

6 votes

@Frank : c'est un bien meilleur titre. formulaire long et grand format sont les termes standards utilisés. L'autre réponse ne peut être trouvée en effectuant une recherche sur ces termes.

27voto

akrun Points 148302

Avec la version devel de tidyr ‘0.8.3.9000’ il y a pivot_wider et pivot_longer qui est généralisé pour effectuer le remodelage (long -> large, large -> long, respectivement) de 1 à plusieurs colonnes. En utilisant les données de l'OP

-une seule colonne longue -> large

library(dplyr)
library(tidyr)
dat1 %>% 
    pivot_wider(names_from = numbers, values_from = value)
# A tibble: 2 x 5
#  name          `1`    `2`    `3`    `4`
#  <fct>       <dbl>  <dbl>  <dbl>  <dbl>
#1 firstName   0.341 -0.703 -0.380 -0.746
#2 secondName -0.898 -0.335 -0.501 -0.175

-> a créé une autre colonne pour montrer la fonctionnalité

dat1 %>% 
    mutate(value2 = value * 2) %>% 
    pivot_wider(names_from = numbers, values_from = c("value", "value2"))
# A tibble: 2 x 9
#  name       value_1 value_2 value_3 value_4 value2_1 value2_2 value2_3 value2_4
#  <fct>        <dbl>   <dbl>   <dbl>   <dbl>    <dbl>    <dbl>    <dbl>    <dbl>
#1 firstName    0.341  -0.703  -0.380  -0.746    0.682   -1.41    -0.759   -1.49 
#2 secondName  -0.898  -0.335  -0.501  -0.175   -1.80    -0.670   -1.00    -0.349

21voto

mpalanco Points 6903

Deux autres options :

Paquet de base :

df <- unstack(dat1, form = value ~ numbers)
rownames(df) <- unique(dat1$name)
df

sqldf paquet :

library(sqldf)
sqldf('SELECT name,
      MAX(CASE WHEN numbers = 1 THEN value ELSE NULL END) x1, 
      MAX(CASE WHEN numbers = 2 THEN value ELSE NULL END) x2,
      MAX(CASE WHEN numbers = 3 THEN value ELSE NULL END) x3,
      MAX(CASE WHEN numbers = 4 THEN value ELSE NULL END) x4
      FROM dat1
      GROUP BY name')

1 votes

Au lieu de coder les chiffres en dur, la requête peut être configurée comme suit : ValCol <- unique(dat1$numbers);s <- sprintf("MAX(CASE WHEN numbers = %s THEN value ELSE NULL END) `%s`,", ValCol, ValCol);mquerym <- gsub('.{1}$','',paste(s, collapse = "\n"));mquery <- paste("SELECT name,", mquerym, "FROM dat1", "GROUP BY name", sep = "\n");sqldf(mquery)

16voto

Ronak Shah Points 24715

En utilisant la base R aggregate fonction :

aggregate(value ~ name, dat1, I)

# name           value.1  value.2  value.3  value.4
#1 firstName      0.4145  -0.4747   0.0659   -0.5024
#2 secondName    -0.8259   0.1669  -0.8962    0.1681

13voto

Adam Erickson Points 44

La base reshape fonctionne parfaitement bien :

df <- data.frame(
  year   = c(rep(2000, 12), rep(2001, 12)),
  month  = rep(1:12, 2),
  values = rnorm(24)
)
df_wide <- reshape(df, idvar="year", timevar="month", v.names="values", direction="wide", sep="_")
df_wide

  • idvar est la colonne de classes qui sépare les rangées
  • timevar est la colonne des classes à lancer en grand
  • v.names est la colonne contenant les valeurs numériques
  • direction précise le format large ou long
  • l'option sep est le séparateur utilisé entre timevar les noms des classes et v.names dans la sortie data.frame .

Si non idvar existe, créez-en un avant d'utiliser l'option reshape() fonction :

df$id   <- c(rep("year1", 12), rep("year2", 12))
df_wide <- reshape(df, idvar="id", timevar="month", v.names="values", direction="wide", sep="_")
df_wide

N'oubliez pas que idvar est nécessaire ! Le site timevar et v.names est facile. La sortie de cette fonction est plus prévisible que certaines autres, car tout est explicitement défini.

10voto

dmi3kno Points 1711

Il y a un nouveau paquet très puissant des scientifiques de données géniaux de Win-Vector (les gens qui ont fait le vtreat , seplyr et replyr ) appelé cdata . Il met en œuvre les principes de " données coordonnées " décrits dans ce document et aussi dans ce article de blog . L'idée est que, quelle que soit la manière dont vous organisez vos données, il devrait être possible d'identifier les points de données individuels à l'aide d'un système de "coordonnées de données". Voici un extrait du récent billet de blog de John Mount :

L'ensemble du système est basé sur deux primitives ou opérateurs cdata::moveValuesToRowsD() et cdata::moveValuesToColumnsD(). Ces opérateurs permettent de pivoter, dé-pivoter, coder à un coup, transposer, déplacer plusieurs plusieurs lignes et colonnes, et de nombreuses autres transformations comme simples cas spéciaux simples.

Il est facile d'écrire de nombreuses opérations différentes en termes de primitives cdata. Ces opérateurs peuvent fonctionner en mémoire ou à l'échelle du big data (avec des bases de données et Apache Spark). (avec des bases de données et Apache Spark ; pour le big data, utilisez les fonctions cdata::moveValuesToRowsN() et cdata::moveValuesToColumnsN() ). Les transformations sont contrôlées par une table de contrôle qui est elle-même un diagramme (ou une image) d'un ensemble de données. qui est elle-même un diagramme (ou une image) de la transformation.

Nous allons d'abord construire la table de contrôle (voir article de blog pour plus de détails) et ensuite effectuer le déplacement des données des lignes vers les colonnes.

library(cdata)
# first build the control table
pivotControlTable <- buildPivotControlTableD(table = dat1, # reference to dataset
                        columnToTakeKeysFrom = 'numbers', # this will become column headers
                        columnToTakeValuesFrom = 'value', # this contains data
                        sep="_")                          # optional for making column names

# perform the move of data to columns
dat_wide <- moveValuesToColumnsD(tallTable =  dat1, # reference to dataset
                    keyColumns = c('name'),         # this(these) column(s) should stay untouched 
                    controlTable = pivotControlTable# control table above
                    ) 
dat_wide

#>         name  numbers_1  numbers_2  numbers_3  numbers_4
#> 1  firstName  0.3407997 -0.7033403 -0.3795377 -0.7460474
#> 2 secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X