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.
9 réponses
utilisant reshape
fonction:
reshape(dat1, idvar = "name", timevar = "numbers", direction = "wide")
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 dereshape2
conçu pour accompagner le cadre de données tidy, et de travailler main dans la main avecmagrittr
etdplyr
pour construire un pipeline solide pour l'analyse des données.tout comme
reshape2
fait moins que remodeler,tidyr
fait moins quereshape2
. Il est conçu spécifiquement pour ranger les données, pas la refonte générale quereshape2
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, ettidyr
ne fournit aucune marge ou agrégation.
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)
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
en utilisant votre exemple dataframe, nous pourrions:
xtabs(value ~ name + numbers, data = dat1)
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')
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
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
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
où
-
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é entretimevar
noms de classe etv.names
dans la sortiedata.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.