data.table
Hervormen, stapelen en splitsen
Zoeken…
Opmerkingen
Het officiële vignet, "Efficiënt hervormen met behulp van data.tables" , is de beste inleiding tot dit onderwerp.
Voor veel hervormtaken moet u schakelen tussen lange en brede formaten:
- Brede gegevens zijn gegevens waarbij elke kolom een afzonderlijke variabele vertegenwoordigt en rijen die afzonderlijke waarnemingen vertegenwoordigen
- Lange gegevens zijn gegevens met de formulier-ID | variabele | waarde, waarbij elke rij een observatie-variabel paar vertegenwoordigt
smelt en gegoten met data.table
data.table
biedt een breed scala aan mogelijkheden om uw gegevens zowel efficiënt als gemakkelijk te hervormen
Wanneer u bijvoorbeeld van lang naar breed verandert, kunt u beide verschillende variabelen tegelijkertijd doorgeven aan de parameters value.var
en fun.aggregate
library(data.table) #v>=1.9.6
DT <- data.table(mtcars)
Lang tot breed
dcast(DT, gear ~ cyl, value.var = c("disp", "hp"), fun = list(mean, sum))
gear disp_mean_4 disp_mean_6 disp_mean_8 hp_mean_4 hp_mean_6 hp_mean_8 disp_sum_4 disp_sum_6 disp_sum_8 hp_sum_4 hp_sum_6 hp_sum_8
1: 3 120.100 241.5 357.6167 97 107.5 194.1667 120.1 483.0 4291.4 97 215 2330
2: 4 102.625 163.8 NaN 76 116.5 NaN 821.0 655.2 0.0 608 466 0
3: 5 107.700 145.0 326.0000 102 175.0 299.5000 215.4 145.0 652.0 204 175 599
Hiermee wordt de gear
ingesteld als de indexkolom, terwijl het mean
en de sum
worden berekend voor disp
en hp
voor elke combinatie van gear
en cyl
. In het geval dat sommige combinaties bestaan niet kon je extra parameters zoals een specificatie van na.rm = TRUE
(die zal worden doorgegeven aan mean
en sum
functies) of geef de ingebouwde fill
argument. U kunt ook marges toevoegen, ontbrekende combinaties verwijderen en de gegevens subset. Zie meer in ?data.table::dcast
Breed tot lang
Tijdens het omvormen van breed naar lang, kunt u kolommen doorgeven aan de parameter measure.vars
met behulp van bijvoorbeeld reguliere expressies
print(melt(DT, c("cyl", "gear"), measure = patterns("^d", "e")), n = 10)
cyl gear variable value1 value2
1: 6 4 1 160.00 16.46
2: 6 4 1 160.00 17.02
3: 4 4 1 108.00 18.61
4: 6 3 1 258.00 19.44
5: 8 3 1 360.00 17.02
---
60: 4 5 2 3.77 5.00
61: 8 5 2 4.22 5.00
62: 6 5 2 3.62 5.00
63: 8 5 2 3.54 5.00
64: 4 4 2 4.11 4.00
Hierdoor worden de gegevens van cyl
en gear
melt
als de drat
, terwijl alle waarden voor de variabelen die beginnen met d
( disp
& drat
) aanwezig zijn in value1
en de waarden voor de variabelen die de letter e
erin bevatten ( qsec
en gear
) zullen aanwezig zijn in de value2
kolom.
U kunt ook de naam van alle kolomnamen de in het resultaat, terwijl het opgeven van variable.name
en value.name
argumenten of beslissen of u wilt dat het character
kolommen automatisch worden omgezet naar factor
is of niet, terwijl het opgeven van variable.factor
en value.factor
argumenten. Zie meer in ?data.table::melt
Wijzig de vorm met `data.table`
data.table
breidt reshape2
's melt
& dcast
functies
( Referentie: efficiënt hervormen met behulp van data.tables )
library(data.table)
## generate some data
dt <- data.table(
name = rep(c("firstName", "secondName"), each=4),
numbers = rep(1:4, 2),
value = rnorm(8)
)
dt
# name numbers value
# 1: firstName 1 -0.8551881
# 2: firstName 2 -1.0561946
# 3: firstName 3 0.2671833
# 4: firstName 4 1.0662379
# 5: secondName 1 -0.4771341
# 6: secondName 2 1.2830651
# 7: secondName 3 -0.6989682
# 8: secondName 4 -0.6592184
Lang tot breed
dcast(data = dt,
formula = 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
Op meerdere kolommen (vanaf data.table
1.9.6)
## add an extra column
dt[, value2 := value * 2]
## cast multiple value columns
dcast(data = dt,
formula = 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
Breed tot lang
## use a wide data.table
dt <- fread("name 1 2 3 4
firstName 0.1836433 -0.8356286 1.5952808 0.3295078
secondName -0.8204684 0.4874291 0.7383247 0.5757814", header = T)
dt
# 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
## melt to long, specifying the id column, and the name of the columns
## in the resulting long data.table
melt(dt,
id.vars = "name",
variable.name = "numbers",
value.name = "myValue")
# name numbers myValue
# 1: firstName 1 0.1836433
# 2: secondName 1 -0.8204684
# 3: firstName 2 -0.8356286
# 4: secondName 2 0.4874291
# 5: firstName 3 1.5952808
# 6: secondName 3 0.7383247
# 7: firstName 4 0.3295078
# 8: secondName 4 0.5757814
Gaan van breed naar lang formaat met behulp van smelt
Smelten: de basis
Smelten wordt gebruikt om gegevens te transformeren van breed naar lang formaat.
Beginnend met een brede dataset:
DT = data.table(ID = letters[1:3], Age = 20:22, OB_A = 1:3, OB_B = 4:6, OB_C = 7:9)
We kunnen onze data smelten met behulp van de melt
functie in data.table. Dit retourneert een andere datatabel in lang formaat:
melt(DT, id.vars = c("ID","Age"))
1: a 20 OB_A 1
2: b 21 OB_A 2
3: c 22 OB_A 3
4: a 20 OB_B 4
5: b 21 OB_B 5
6: c 22 OB_B 6
7: a 20 OB_C 7
8: b 21 OB_C 8
9: c 22 OB_C 9
class(melt(DT, id.vars = c("ID","Age")))
# "data.table" "data.frame"
Alle kolommen die niet zijn ingesteld in de parameter id.vars
worden verondersteld variabelen te zijn. Als alternatief kunnen we deze expliciet instellen met het argument measure.vars
:
melt(DT, measure.vars = c("OB_A","OB_B","OB_C"))
ID Age variable value
1: a 20 OB_A 1
2: b 21 OB_A 2
3: c 22 OB_A 3
4: a 20 OB_B 4
5: b 21 OB_B 5
6: c 22 OB_B 6
7: a 20 OB_C 7
8: b 21 OB_C 8
9: c 22 OB_C 9
In dit geval worden kolommen die niet zijn ingesteld in measure.vars
verondersteld ID's te zijn.
Als we beide expliciet instellen, worden alleen de geselecteerde kolommen geretourneerd:
melt(DT, id.vars = "ID", measure.vars = c("OB_C"))
ID variable value
1: a OB_C 7
2: b OB_C 8
3: c OB_C 9
Naamgeving variabelen en waarden in het resultaat
We kunnen de kolomnamen van de geretourneerde tabel manipuleren met behulp van variable.name
en value.name
melt(DT,
id.vars = c("ID"),
measure.vars = c("OB_C"),
variable.name = "Test",
value.name = "Result"
)
ID Test Result
1: a OB_C 7
2: b OB_C 8
3: c OB_C 9
Typen instellen voor meetvariabelen in het resultaat
Standaard wordt het smelten van een data.table converteert alle measure.vars
factoren:
M_DT <- melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"))
class(M_DT[, variable])
# "factor"
Gebruik in plaats daarvan het argument variable.factor
om als teken in te stellen:
M_DT <- melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"), variable.factor = FALSE)
class(M_DT[, variable])
# "character"
Waarden nemen over het algemeen van het gegevenstype van de oorspronkelijke kolom over:
class(DT[, value])
# "integer"
class(M_DT[, value])
# "integer"
Als er een conflict is, worden gegevenstypen gedwongen. Bijvoorbeeld:
M_DT <- melt(DT,id.vars = c("Age"), measure.vars = c("ID","OB_C"))
class(M_DT[, value])
# "character"
Tijdens het smelten worden alle factorvariabelen tot het karaktertype gedwongen:
DT[, OB_C := factor(OB_C)]
M_DT <- melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"))
class(M_DT)
# "character"
Om dit te voorkomen en het oorspronkelijke typen te behouden, gebruikt u het argument value.factor
:
M_DT <- melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"), value.factor = TRUE)
class(M_DT)
# "factor"
Omgaan met ontbrekende waarden
Standaard worden NA
waarden behouden in de gesmolten gegevens
DT = data.table(ID = letters[1:3], Age = 20:22, OB_A = 1:3, OB_B = 4:6, OB_C = c(7:8,NA))
melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"))
ID variable value
1: a OB_C 7
2: b OB_C 8
3: c OB_C NA
Als deze uit uw gegevens moeten worden verwijderd, stelt u na.rm = TRUE
melt(DT,id.vars = c("ID"), measure.vars = c("OB_C"), na.rm = TRUE)
ID variable value
1: a OB_C 7
2: b OB_C 8
Met dcast van lang naar breed formaat gaan
Casting: The Basics
Casting wordt gebruikt om gegevens te transformeren van lang naar breed formaat.
Beginnend met een lange gegevensset:
DT = data.table(ID = rep(letters[1:3],3), Age = rep(20:22,3), Test = rep(c("OB_A","OB_B","OB_C"), each = 3), Result = 1:9)
We kunnen onze gegevens casten met behulp van de dcast
functie in data.table. Dit retourneert een andere datatabel in groot formaat:
dcast(DT, formula = ID ~ Test, value.var = "Result")
ID OB_A OB_B OB_C
1: a 1 4 7
2: b 2 5 8
3: c 3 6 9
class(dcast(DT, formula = ID ~ Test, value.var = "Result"))
[1] "data.table" "data.frame"
Een waarde uitbrengen
Een argument value.var
is nodig voor een juiste cast - indien niet opgegeven, maakt dcast een veronderstelling op basis van uw gegevens.
dcast(DT, formula = ID ~ Test, value.var = "Result")
ID OB_A OB_B OB_C
1: a 1 4 7
2: b 2 5 8
3: c 3 6 9
ID OB_A OB_B OB_C
1: a 20 20 20
2: b 21 21 21
3: c 22 22 22
Er kunnen meerdere value.var
worden opgegeven in een lijst
dcast(DT, formula = ID ~ Test, value.var = list("Result","Age"))
ID Result_OB_A Result_OB_B Result_OB_C Age_OB_A Age_OB_B Age_OB_C
1: a 1 4 7 20 20 20
2: b 2 5 8 21 21 21
3: c 3 6 9 22 22 22
Formule
Casten wordt bestuurd met behulp van het formule-argument in dcast
. Dit is in de vorm ROWS ~ COLUMNS
dcast(DT, formula = ID ~ Test, value.var = "Result")
ID OB_A OB_B OB_C
1: a 1 4 7
2: b 2 5 8
3: c 3 6 9
dcast(DT, formula = Test ~ ID, value.var = "Result")
Test a b c
1: OB_A 1 2 3
2: OB_B 4 5 6
3: OB_C 7 8 9
Zowel rijen als kolommen kunnen worden uitgebreid met verdere variabelen met +
dcast(DT, formula = ID + Age ~ Test, value.var = "Result")
ID Age OB_A OB_B OB_C
1: a 20 1 4 7
2: b 21 2 5 8
3: c 22 3 6 9
dcast(DT, formula = ID ~ Age + Test, value.var = "Result")
ID 20_OB_A 20_OB_B 20_OB_C 21_OB_A 21_OB_B 21_OB_C 22_OB_A 22_OB_B 22_OB_C
1: a 1 4 7 NA NA NA NA NA NA
2: b NA NA NA 2 5 8 NA NA NA
3: c NA NA NA NA NA NA 3 6 9
#order is important
dcast(DT, formula = ID ~ Test + Age, value.var = "Result")
ID OB_A_20 OB_A_21 OB_A_22 OB_B_20 OB_B_21 OB_B_22 OB_C_20 OB_C_21 OB_C_22
1: a 1 NA NA 4 NA NA 7 NA NA
2: b NA 2 NA NA 5 NA NA 8 NA
3: c NA NA 3 NA NA 6 NA NA 9
Casten kan vaak cellen maken waar geen observatie in de gegevens bestaat. Standaard wordt dit aangegeven door NA
, zoals hierboven. We kunnen dit overschrijven met het fill=
argument.
dcast(DT, formula = ID ~ Test + Age, value.var = "Result", fill = 0)
ID OB_A_20 OB_A_21 OB_A_22 OB_B_20 OB_B_21 OB_B_22 OB_C_20 OB_C_21 OB_C_22
1: a 1 0 0 4 0 0 7 0 0
2: b 0 2 0 0 5 0 0 8 0
3: c 0 0 3 0 0 6 0 0 9
U kunt ook twee speciale variabelen gebruiken in het formuleobject
-
.
vertegenwoordigt geen andere variabelen -
...
vertegenwoordigt alle andere variabelen
dcast(DT, formula = Age ~ ., value.var = "Result")
Age .
1: 20 3
2: 21 3
3: 22 3
dcast(DT, formula = ID + Age ~ ..., value.var = "Result")
ID Age OB_A OB_B OB_C
1: a 20 1 4 7
2: b 21 2 5 8
3: c 22 3 6 9
Onze waarde samenvoegen. Var
We kunnen ook waarden in één stap casten en aggregeren. In dit geval hebben we drie observaties op elk van de kruispunten van Leeftijd en ID. Om in te stellen welke aggregatie we willen gebruiken we het argument fun.aggregate
:
#length
dcast(DT, formula = ID ~ Age, value.var = "Result", fun.aggregate = length)
ID 20 21 22
1: a 3 0 0
2: b 0 3 0
3: c 0 0 3
#sum
dcast(DT, formula = ID ~ Age, value.var = "Result", fun.aggregate = sum)
ID 20 21 22
1: a 12 0 0
2: b 0 15 0
3: c 0 0 18
#concatenate
dcast(DT, formula = ID ~ Age, value.var = "Result", fun.aggregate = function(x){paste(x,collapse = "_")})
ID 20 21 22
1: a 1_4_7
2: b 2_5_8
3: c 3_6_9
We kunnen ook een lijst doorgeven aan fun.aggregate
om meerdere functies te gebruiken
dcast(DT, formula = ID ~ Age, value.var = "Result", fun.aggregate = list(sum,length))
ID Result_sum_20 Result_sum_21 Result_sum_22 Result_length_20 Result_length_21 Result_length_22
1: a 12 0 0 3 0 0
2: b 0 15 0 0 3 0
3: c 0 0 18 0 0 3
Als we meer dan één functie en meer dan één waarde doorgeven, kunnen we alle combinaties berekenen door een vector van waarde.vars door te geven
dcast(DT, formula = ID ~ Age, value.var = c("Result","Test"), fun.aggregate = list(function(x){paste0(x,collapse = "_")},length))
ID Result_function_20 Result_function_21 Result_function_22 Test_function_20 Test_function_21 Test_function_22 Result_length_20 Result_length_21
1: a 1_4_7 OB_A_OB_B_OB_C 3 0
2: b 2_5_8 OB_A_OB_B_OB_C 0 3
3: c 3_6_9 OB_A_OB_B_OB_C 0 0
Result_length_22 Test_length_20 Test_length_21 Test_length_22
1: 0 3 0 0
2: 0 0 3 0
3: 3 0 0 3
waarbij elk paar wordt berekend in de volgorde value1_formula1, value1_formula2, ... , valueN_formula(N-1), valueN_formulaN
.
Als alternatief kunnen we onze waarden en functies één op één evalueren door 'value.var' als lijst door te geven:
dcast(DT, formula = ID ~ Age, value.var = list("Result","Test"), fun.aggregate = list(function(x){paste0(x,collapse = "_")},length))
ID Result_function_20 Result_function_21 Result_function_22 Test_length_20 Test_length_21 Test_length_22
1: a 1_4_7 3 0 0
2: b 2_5_8 0 3 0
3: c 3_6_9 0 0 3
Kolommen een naam geven in het resultaat
Standaard worden kolomnaamonderdelen gescheiden door een onderstrepingsteken _
. Dit kan handmatig worden opgeheven met het argument sep=
:
dcast(DT, formula = Test ~ ID + Age, value.var = "Result")
Test a_20 b_21 c_22
1: OB_A 1 2 3
2: OB_B 4 5 6
3: OB_C 7 8 9
dcast(DT, formula = Test ~ ID + Age, value.var = "Result", sep = ",")
Test a,20 b,21 c,22
1: OB_A 1 2 3
2: OB_B 4 5 6
3: OB_C 7 8 9
Dit fun.aggregate
elke fun.aggregate
of value.var
we gebruiken:
dcast(DT, formula = Test ~ ID + Age, value.var = "Result", fun.aggregate = c(sum,length), sep = ",")
Test Result,sum,a,20 Result,sum,b,21 Result,sum,c,22 Result,length,a,20 Result,length,b,21 Result,length,c,22
1: OB_A 1 2 3 1 1 1
2: OB_B 4 5 6 1 1 1
3: OB_C 7 8 9 1 1 1
Meerdere tabellen stapelen met behulp van rbindlist
Een gemeenschappelijk refrein in R gaat als volgt:
Je moet geen stel gerelateerde tabellen hebben met namen als
DT1
,DT2
, ...,DT11
. Iteratief lezen en toewijzen aan objecten op naam is rommelig. De oplossing is een lijst met gegevenstabellen!
Zo'n lijst ziet eruit
set.seed(1)
DT_list = lapply(setNames(1:3, paste0("D", 1:3)), function(i)
data.table(id = 1:2, v = sample(letters, 2)))
$D1
id v
1: 1 g
2: 2 j
$D2
id v
1: 1 o
2: 2 w
$D3
id v
1: 1 f
2: 2 w
Een ander perspectief is dat u deze tabellen als één tabel moet opslaan door ze te stapelen. Dit is eenvoudig te doen met behulp van rbindlist
:
DT = rbindlist(DT_list, id="src")
src id v
1: D1 1 g
2: D1 2 j
3: D2 1 o
4: D2 2 w
5: D3 1 f
6: D3 2 w
Dit formaat is veel logischer met de syntaxis van data.table, waar "per groep" -bewerkingen gebruikelijk en eenvoudig zijn.
Voor een diepere blik is het antwoord van Gregor misschien een goede plek om te beginnen. Kijk natuurlijk ook op ?rbindlist
. Er is een apart voorbeeld voor lezen in een aantal tabellen van CSV en deze vervolgens stapelen .