web-dev-qa-db-fra.com

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

Je ne parviens pas à réorganiser le bloc 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 souhaite le remodeler afin que chaque variable "name" unique soit un nom de fichier, avec les "valeurs" comme observations le long de cette ligne et les "nombres" comme noms. Un peu comme ça:

     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 aucune ne semble faire l'affaire.

231
Steve

Utilisation de la fonction reshape:

reshape(dat1, idvar = "name", timevar = "numbers", direction = "wide")
228
Chase

Le nouveau package tidyr (en 2014) le fait également de manière simple, avec gather()/spread() étant les termes utilisés pour melt/cast.

library(tidyr)
spread(dat1, key = numbers, value = value)

De github ,

tidyr est un recadrage de reshape2 conçu pour accompagner le cadre de données ordonné et pour travailler main dans la main avec magrittr et dplyr afin de créer un solide pipeline d'analyse de données. .

Tout comme reshape2 n'a pas remodelé, tidyr en fait moins que reshape2. Il est conçu spécifiquement pour ranger les données, pas pour le remodelage général que reshape2 fait, ni pour l'agrégation générale que remodèle a fait. En particulier, les méthodes intégrées ne fonctionnent que pour les trames de données et tidyr ne fournit aucune marge ou agrégation.

124
Gregor

Vous pouvez le faire avec la fonction reshape() ou avec les fonctions melt()/cast() du package de remodelage. Pour la deuxième option, l'exemple de code est

library(reshape)
cast(dat1, name ~ numbers)

Ou en utilisant reshape2

library(reshape2)
dcast(dat1, name ~ numbers)
69
Ista

Une autre option si la performance est une préoccupation est d'utiliser l'extension de data.table des fonctions de fusion et de diffusion de reshape2

( Référence: Remodelage efficace en utilisant data.tables )

library(data.table)

setDT(dat1)
dcast(dat1, name ~ numbers, value.var = "value")

#          name          1          2         3         4
# 1:  firstName  0.1836433 -0.8356286 1.5952808 0.3295078
# 2: secondName -0.8204684  0.4874291 0.7383247 0.5757814

Et, à partir de Data.table v1.9.6, nous pouvons lancer plusieurs colonnes

## add an extra column
dat1[, value2 := value * 2]

## cast multiple value columns
dcast(dat1, name ~ numbers, value.var = c("value", "value2"))

#          name    value_1    value_2   value_3   value_4   value2_1   value2_2 value2_3  value2_4
# 1:  firstName  0.1836433 -0.8356286 1.5952808 0.3295078  0.3672866 -1.6712572 3.190562 0.6590155
# 2: secondName -0.8204684  0.4874291 0.7383247 0.5757814 -1.6409368  0.9748581 1.476649 1.1515627
38
SymbolixAU

En utilisant votre exemple de cadre de données, nous pourrions:

xtabs(value ~ name + numbers, data = dat1)
25
Jim M.

Deux autres options:

Paquet de base:

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

sqldf package:

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')
18
mpalanco

Utilisation de la fonction de base R aggregate:

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
11
Ronak Shah

Win-Vector (les personnes qui fabriquaient vtreat, seplyr et replyr) appelé cdata est très puissant. Il met en œuvre les principes de "données coordonnées" décrits dans ce document et également 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 des points de données individuels à l'aide d'un système de "coordonnées de données". Voici un extrait du récent post 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 ont pivot, déverrouillage, encodage à chaud, transposition, déplacement de plusieurs lignes et colonnes et de nombreuses autres transformations en tant que cas particuliers simples.

Il est facile d'écrire de nombreuses opérations différentes en termes de primitives cdata. Ces opérateurs peuvent travailler en mémoire ou à grande échelle (avec les bases de données et Apache Spark; pour les grandes données, utilisez les variantes 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) de la transformation.

Nous allons d’abord construire la table de contrôle (voir article de blog pour plus de détails), puis effectuer le déplacement des données de rangées en 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
6
dmi3kno

La fonction de base reshape fonctionne parfaitement:

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 lignes
  • timevar est la colonne de classes à élargir
  • v.names est la colonne contenant des valeurs numériques
  • direction spécifie un format large ou long
  • l'argument facultatif sep est le séparateur utilisé entre timevar noms de classe et v.names dans la sortie data.frame.

S'il n'y a pas idvar, créez-en un avant d'utiliser la fonction reshape():

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

Rappelez-vous que idvar est requis! La partie timevar et v.names est simple. Le résultat de cette fonction est plus prévisible que certains autres, car tout est explicitement défini.

5
Adam Erickson

Avec la version de développement 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) à partir de 1 à plusieurs colonnes. Utilisation des données du PO

-solonne 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

-> créé une autre colonne pour afficher 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
1
akrun

manière beaucoup plus facile!

devtools::install_github("yikeshu0611/onetree") #install onetree package

library(onetree)
widedata=reshape_toWide(data = dat1,id = "name",j = "numbers",value.var.prefix = "value")
widedata

        name     value1     value2     value3     value4
   firstName  0.3407997 -0.7033403 -0.3795377 -0.7460474
  secondName -0.8981073 -0.3347941 -0.5013782 -0.1745357

si vous voulez revenir de large à long, ne changez que Wide à Long et aucun changement d’objets.

reshape_toLong(data = widedata,id = "name",j = "numbers",value.var.prefix = "value")

        name numbers      value
   firstName       1  0.3407997
  secondName       1 -0.8981073
   firstName       2 -0.7033403
  secondName       2 -0.3347941
   firstName       3 -0.3795377
  secondName       3 -0.5013782
   firstName       4 -0.7460474
  secondName       4 -0.1745357
1
zhang jing