Ik heb problemen met het herschikken van het volgende gegevensframe:
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
Ik wil het zo hervormen dat elke unieke “naam”-variabele een rijnaam is, met de “waarden” als waarnemingen langs die rij en de “getallen” als colnamen. Zoiets als dit:
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
Ik heb gekeken naar melt
en cast
en een paar andere dingen, maar geen enkele lijkt het werk te doen.
Antwoord 1, autoriteit 100%
De functie reshape
gebruiken:
reshape(dat1, idvar = "name", timevar = "numbers", direction = "wide")
Antwoord 2, autoriteit 48%
Het nieuwe (in 2014) tidyr
-pakket doet dit ook eenvoudig, waarbij gather()
/spread()
de termen zijn voor melt
/cast
.
Bewerken:nu, in 2019, heeft netjesr v 1.0 spread
en gather
gelanceerd en ingesteld op een afschrijvingspad, in plaats daarvan liever pivot_wider
en pivot_longer
, die u in dit antwoordkunt vinden. Lees verder als je een korte blik wilt werpen op het korte leven van spread/gather
.
library(tidyr)
spread(dat1, key = numbers, value = value)
Van github,
tidyr
is een herformulering vanreshape2
die is ontworpen om het opgeruimde gegevensraamwerk te begeleiden, en om hand in hand te werken metmagrittr
endplyr
om een solide pijplijn voor gegevensanalyse te bouwen.Net zoals
reshape2
minder deed dan reshape, doettidyr
minder danreshape2
. Het is specifiek ontworpen voor het opschonen van gegevens, niet voor de algemene vormverandering diereshape2
doet, of de algemene aggregatie die de vorm heeft gegeven. In het bijzonder werken ingebouwde methoden alleen voor dataframes, entidyr
biedt geen marges of aggregatie.
Antwoord 3, autoriteit 26%
U kunt dit doen met de functie reshape()
, of met de functies melt()
/ cast()
in het reshape-pakket . Voor de tweede optie is de voorbeeldcode
library(reshape)
cast(dat1, name ~ numbers)
Of gebruik reshape2
library(reshape2)
dcast(dat1, name ~ numbers)
Antwoord 4, autoriteit 17%
Een andere optie als prestatie een probleem is, is het gebruik van de extensie data.table
van reshape2
‘s melt & dcast-functies
(Referentie: efficiënt vormgeven met behulp van gegevens. tabellen)
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
En vanaf data.table v1.9.6 kunnen we meerdere kolommen casten
## 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
Antwoord 5, autoriteit 9%
Met uw voorbeelddataframe kunnen we:
xtabs(value ~ name + numbers, data = dat1)
Antwoord 6, autoriteit 9%
Bij de ontwikkelversie van tidyr
‘0.8.3.9000’
is er pivot_wider
en pivot_longer
die gegeneraliseerd om de omvorming uit te voeren (respectievelijk lang -> breed, breed -> lang) van 1 naar meerdere kolommen. De gegevens van de OP gebruiken
-enkele kolom lang -> breed
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
-> een andere kolom gemaakt om de functionaliteit te tonen
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
Antwoord 7, autoriteit 7%
Andere twee opties:
Basispakket:
df <- unstack(dat1, form = value ~ numbers)
rownames(df) <- unique(dat1$name)
df
sqldf
pakket:
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')
Antwoord 8, autoriteit 5%
De functie basis R aggregate
gebruiken:
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
Antwoord 9, autoriteit 4%
De basis reshape
-functie werkt prima:
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
Waar
idvar
is de kolom met klassen die rijen scheidttimevar
is de kolom met klassen die breed moet worden gecastv.names
is de kolom met numerieke waardendirection
specificeert breed of lang formaat- het optionele argument
sep
is het scheidingsteken dat wordt gebruikt tussen klassenamentimevar
env.names
in de uitvoerdata.frame
.
Als er geen idvar
bestaat, maak er dan een aan voordat je de functie reshape()
gebruikt:
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
Onthoud dat idvar
vereist is! Het gedeelte timevar
en v.names
is eenvoudig. De uitvoer van deze functie is voorspelbaarder dan sommige van de andere, omdat alles expliciet is gedefinieerd.
Antwoord 10, autoriteit 3%
Er is een zeer krachtig nieuw pakket van geniale datawetenschappers bij Win-Vector (mensen die vtreat
, seplyr
en replyr
hebben gemaakt), genaamd cdata
. Het implementeert principes van “gecoördineerde gegevens” die worden beschreven in dit documenten ook in dit blogbericht. Het idee is dat, ongeacht hoe u uw gegevens organiseert, het mogelijk moet zijn om individuele gegevenspunten te identificeren met behulp van een systeem van “gegevenscoördinaten”. Hier is een fragment uit de recente blogpost van John Mount:
Het hele systeem is gebaseerd op twee primitieven of operators
cdata::moveValuesToRowsD() en cdata::moveValuesToColumnsD(). Deze
operators hebben pivot, un-pivot, one-hot encode, transpose, moving
meerdere rijen en kolommen, en vele andere transformaties als eenvoudig speciaal
gevallen.Het is gemakkelijk om veel verschillende bewerkingen te schrijven in termen van de
cdata-primitieven. Deze operators kunnen in het geheugen of bij big data werken
scale (met databases en Apache Spark; gebruik voor big data de
cdata::moveValuesToRowsN() en cdata::moveValuesToColumnsN()
varianten). De transformaties worden bestuurd door een controletabel die:
zelf is een diagram van (of afbeelding van) de transformatie.
We zullen eerst de controletabel bouwen (zie blogberichtvoor details) en voer vervolgens de verplaatsing van gegevens uit van rijen naar kolommen.
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
Antwoord 11
veel gemakkelijkere manier!
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
als je terug wilt gaan van breed naar lang, verander dan alleen Breed naar Lang en geen wijzigingen in objecten.
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