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.
Utilisation de la fonction reshape
:
reshape(dat1, idvar = "name", timevar = "numbers", direction = "wide")
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 dereshape2
conçu pour accompagner le cadre de données ordonné et pour travailler main dans la main avecmagrittr
etdplyr
afin de créer un solide pipeline d'analyse de données. .Tout comme
reshape2
n'a pas remodelé,tidyr
en fait moins quereshape2
. Il est conçu spécifiquement pour ranger les données, pas pour le remodelage général quereshape2
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 ettidyr
ne fournit aucune marge ou agrégation.
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)
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
En utilisant votre exemple de cadre de données, 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
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')
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
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
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
Où
idvar
est la colonne de classes qui sépare les lignestimevar
est la colonne de classes à élargirv.names
est la colonne contenant des valeurs numériquesdirection
spécifie un format large ou longsep
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.
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
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