Comment refaçonner les données du format long au format large?

j'ai de la difficulté à réorganiser la base de données suivante:

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 pour que chaque variable" name "unique soit un nom de ligne, avec les" valeurs "comme observations le long de cette ligne et les" nombres " comme colnames. 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 de quelques autres choses, mais aucune ne semble faire le travail.

187
demandé sur Taryn 2011-05-05 02:27:50

9 réponses

utilisant reshape fonction:

reshape(dat1, idvar = "name", timevar = "numbers", direction = "wide")
183
répondu Chase 2011-05-04 23:20:03

le nouveau paquet (en 2014) tidyr le fait aussi simplement, avec gather() / spread() étant les termes pour melt / cast .

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

à Partir de github ,

tidyr est un recadrage de reshape2 conçu pour accompagner le cadre de données tidy, et de travailler main dans la main avec magrittr et dplyr pour construire un pipeline solide pour l'analyse des données.

tout comme reshape2 fait moins que remodeler, tidyr fait moins que reshape2 . Il est conçu spécifiquement pour ranger les données, pas la refonte générale que reshape2 fait, ou l'agrégation générale que reshape fait. En particulier, les méthodes intégrées ne fonctionnent que pour les bases de données, et tidyr ne fournit aucune marge ou agrégation.

96
répondu Gregor 2015-07-29 16:39:29

vous pouvez le faire avec la fonction reshape() , ou avec les fonctions melt() / cast() dans le paquet reshape. Pour la deuxième option, exemple de code est

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

ou en utilisant reshape2

library(reshape2)
dcast(dat1, name ~ numbers)
62
répondu Ista 2015-05-26 14:52:24

une Autre option, si la performance est un sujet de préoccupation est d'utiliser des data.table l'extension de la reshape2 melt & dcast fonctions

( Référence: Efficace, remodeler à l'aide de données.tableaux )

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 des données.tableau v1.9.6 Nous pouvons mouler sur 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
26
répondu SymbolixAU 2016-03-27 22:51:39

en utilisant votre exemple dataframe, nous pourrions:

xtabs(value ~ name + numbers, data = dat1)
22
répondu Jim M. 2016-09-02 07:37:07

deux autres options:

paquet de Base:

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

sqldf colis:

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')
14
répondu mpalanco 2015-07-14 17:44:08

utilisant 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
7
répondu Ronak Shah 2017-12-25 04:05:05

il y a un nouveau paquet très puissant de genius data scientists chez Win-Vector (les gens qui ont fait vtreat , seplyr et replyr ) appelé cdata . Il met en œuvre des" données coordonnées "principes décrits dans ce document et aussi dans ce blog post . 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 en utilisant un système de "coordonnées de données". Voici un extrait extrait du récent billet de John Mount:

l'ensemble du système est basé sur deux primitives ou opérateurs cdata:: moveValuesToRowsD () et cdata::moveValuesToColumnsD (). Ils les opérateurs ont pivot, onu-pivot "one-hot" de coder, de transposer, le déplacement plusieurs lignes et colonnes, et beaucoup d'autres transformations comme simple spéciaux cas.

Il est facile d'écrire beaucoup d'opérations différentes en termes de primitives de cdata. Ces opérateurs peuvent travailler-en mémoire ou au big data scale (avec bases de données et Apache Spark; pour le big data utiliser le cdata:: moveValuesToRowsN () et cdata:: moveValuesToColumnsN() variantes.) Les transformations sont contrôlés par un tableau de contrôle qui elle - même est un diagramme (ou une image) de la transformation.

nous allons d'abord construire la table de contrôle (voir blog post pour plus de détails) et puis effectuer le déplacement des données des lignes aux 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
4
répondu dmi3kno 2017-12-23 23:01:37

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

si aucun idvar n'existe, 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

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

2
répondu Adam Erickson 2018-08-29 03:00:45