R Language
datatabell
Sök…
Introduktion
Data.table är ett paket som utvidgar funktionaliteten för dataramar från bas R, särskilt förbättrar deras prestanda och syntax. Se paketets Dokument-område på Komma igång med data.table för mer information.
Syntax
-
DT[i, j, by]
# DT [där, välj | uppdatera | göra, av] -
DT[...][...]
# kedja -
################# Shortcuts, special functions and special symbols inside DT[...]
- . ()
# i flera argument ersätter listan () - J ()
# i i, ersätter lista () - : =
# i j, en funktion som används för att lägga till eller ändra kolumner - .N
# i i, det totala antalet rader
# i j, antalet rader i en grupp - .I
# i j, vektorn med radnumren i tabellen (filtrerad av i) - .SD
# i j, den aktuella delmängden av data
# valt av argumentet .SDcols - .GRP
# i j, det aktuella indexet för delmängden av data - .FÖRBI
# i j, listan med efter värden för den aktuella datamängden - V1, V2, ...
# standardnamn för namngivna kolumner skapade i j -
################# Joins inside DT[...]
- DT1 [DT2, på, j]
# gå med i två bord - i. *
# speciellt prefix på DT2s kolumner efter anslutningen - med = .EACHI
# specialalternativ endast tillgängligt med en anslutning - DT1 [! DT2, på, j]
# anti-gå med två bord - DT1 [DT2, på, rulla, j]
# gå med i två tabeller och rulla på den sista kolumnen i på = -
################# Reshaping, stacking and splitting
- smälta (DT, id.vars, measure.vars)
# omvandla till långt format
# för flera kolumner, använd mått.vars = mönster (...) - dcast (DT, formel)
# omvandla till brett format - rbind (DT1, DT2, ...)
# stack uppräknade data.tabeller - rbindlist (DT_list, idcol)
# stapla en lista med data.tabeller - split (DT, av)
# dela upp en data.table i en lista -
################# Some other functions specialized for data.tables
- foverlaps
# överlappning går med - sammanfoga
# ett annat sätt att gå med i två bord - uppsättning
# ett annat sätt att lägga till eller ändra kolumner - fintersect, fsetdiff, funion, fsetequal, unik, duplicerad, anyDuplicated
# set-teoretiska operationer med rader som element - uniqueN
# antalet olika rader - rowidv (DT, cols)
# rad-ID (1 till .N) inom varje grupp bestämd av kollegor - rleidv (DT, cols)
# grupp-ID (1 till .GRP) inom varje grupp bestämd med körningar av koljor - skift (DT, n, typ = c ("lag", "bly"))
# applicera en skiftoperatör på varje kolumn - setorder, setcolorder, setnamn, setkey, setindex, setattr
# ändra attribut och ordning efter referens
Anmärkningar
Installation och support
Så här installerar du paketet data.table:
# install from CRAN
install.packages("data.table")
# or install development version
install.packages("data.table", type = "source", repos = "http://Rdatatable.github.io/data.table")
# and to revert from devel to CRAN, the current version must first be removed
remove.packages("data.table")
install.packages("data.table")
Paketets officiella webbplats har wikisidor som ger hjälp att komma igång, och listor över presentationer och artiklar från hela webben. Innan du ställer en fråga - här på StackOverflow eller någon annanstans - läs supportsidan .
Laddar paketet
Många av funktionerna i exemplen ovan finns i namnsområdet data.table. För att använda dem måste du först lägga till en rad som library(data.table)
eller använda deras fulla sökväg, som data.table::fread
istället för helt enkelt fread
. För hjälp med enskilda funktioner är syntaxen help("fread")
eller ?fread
. Återigen, om paketet inte laddas, använd det fulla namnet som ?data.table::fread
.
Skapa en data.table
En data.table är en förbättrad version av klassen data.frame från bas R. Som sådan är attributet class()
vektorn "data.table" "data.frame"
och funktioner som fungerar på en data.frame kommer också arbeta med en data.table. Det finns många sätt att skapa, ladda eller tvinga till en data.table.
Bygga
Glöm inte att installera och aktivera paketet data.table
library(data.table)
Det finns en konstruktör med samma namn:
DT <- data.table(
x = letters[1:5],
y = 1:5,
z = (1:5) > 3
)
# x y z
# 1: a 1 FALSE
# 2: b 2 FALSE
# 3: c 3 FALSE
# 4: d 4 TRUE
# 5: e 5 TRUE
Till skillnad data.frame
data.table
kommer data.table
inte att tvinga strängar till faktorer:
sapply(DT, class)
# x y z
# "character" "integer" "logical"
Läs in
Vi kan läsa från en textfil:
dt <- fread("my_file.csv")
Till skillnad read.csv
fread
kommer fread
att läsa strängar som strängar, inte som faktorer.
Ändra ett data.frame
För effektivitet erbjuder data.table ett sätt att ändra en data.frame eller en lista för att göra en data.table på plats (utan att göra en kopia eller ändra dess minnesplats):
# example data.frame
DF <- data.frame(x = letters[1:5], y = 1:5, z = (1:5) > 3)
# modification
setDT(DF)
Observera att vi inte <-
tilldelar resultatet, eftersom objektet DF
har modifierats på plats. Klassattributen för data.frame behålls:
sapply(DF, class)
# x y z
# "factor" "integer" "logical"
Tvinga objekt till data.table
Om du har en list
, data.frame
eller data.table
bör du använda setDT
funktionen för att konvertera till en data.table
eftersom den gör konverteringen genom referens istället för att göra en kopia (vilket as.data.table
gör). Detta är viktigt om du arbetar med stora datasätt.
Om du har ett annat R-objekt (t.ex. en matris) måste du använda as.data.table
att tvinga det till ett data.table
.
mat <- matrix(0, ncol = 10, nrow = 10)
DT <- as.data.table(mat)
# or
DT <- data.table(mat)
Lägga till och ändra kolumner
DT[where, select|update|do, by]
syntax används för att arbeta med kolumner i en data.table.
- "Var" -delen är
i
argumentet - Delen "select | update | do" är
j
argumentet
Dessa två argument skickas vanligtvis efter position istället för med namn.
Våra exempeldata nedan är
mtcars = data.table(mtcars, keep.rownames = TRUE)
Redigering av hela kolumner
Använd :=
operatören inuti j
att tilldela nya kolumner:
mtcars[, mpg_sq := mpg^2]
Ta bort kolumner genom att ställa in på NULL
:
mtcars[, mpg_sq := NULL]
Lägg till flera kolumner med hjälp av :=
operatörens multivariatformat:
mtcars[, `:=`(mpg_sq = mpg^2, wt_sqrt = sqrt(wt))]
# or
mtcars[, c("mpg_sq", "wt_sqrt") := .(mpg^2, sqrt(wt))]
Om kolumnerna är beroende och måste definieras i sekvens är ett sätt:
mtcars[, c("mpg_sq", "mpg2_hp") := .(temp1 <- mpg^2, temp1/hp)]
Syntaxen .()
Används när höger sida av LHS := RHS
är en kolumnlista.
För dynamiskt bestämda kolumnnamn, använd parenteser:
vn = "mpg_sq"
mtcars[, (vn) := mpg^2]
Kolumner kan också ändras med set
, men detta är sällan nödvändigt:
set(mtcars, j = "hp_over_wt", v = mtcars$hp/mtcars$wt)
Redigera delmängder av kolumner
Använd i
argumentet för att delmängda till rader "där" redigeringar ska göras:
mtcars[1:3, newvar := "Hello"]
# or
set(mtcars, j = "newvar", i = 1:3, v = "Hello")
Som i en data.frame kan vi deluppsätta med radnummer eller logiska test. Det är också möjligt att använda en "join" i i
, men den mer komplicerade uppgiften behandlas i ett annat exempel.
Redigera kolumnattribut
Funktioner som redigerar attribut, till exempel levels<-
eller names<-
, ersätter faktiskt ett objekt med en modifierad kopia. Även om det bara används på en kolumn i en data.table kopieras och ersätts hela objektet.
För att ändra ett objekt utan kopior, använd setnames
att ändra kolumnnamnen på en data.table eller data.frame och setattr
att ändra ett attribut för alla objekt.
# Print a message to the console whenever the data.table is copied
tracemem(mtcars)
mtcars[, cyl2 := factor(cyl)]
# Neither of these statements copy the data.table
setnames(mtcars, old = "cyl2", new = "cyl_fac")
setattr(mtcars$cyl_fac, "levels", c("four", "six", "eight"))
# Each of these statements copies the data.table
names(mtcars)[names(mtcars) == "cyl_fac"] <- "cf"
levels(mtcars$cf) <- c("IV", "VI", "VIII")
Var medveten om att dessa förändringar görs genom referens, så att de är globala . Att ändra dem inom en miljö påverkar objektet i alla miljöer.
# This function also changes the levels in the global environment
edit_levels <- function(x) setattr(x, "levels", c("low", "med", "high"))
edit_levels(mtcars$cyl_factor)
Speciella symboler i data.table
.SD
.SD
hänvisar till delmängden av data.table
för varje grupp, exklusive alla kolumner som används by
.
.SD
tillsammans med lapply
kan användas för att tillämpa valfri funktion på flera kolumner per grupp i en data.table
Vi kommer att fortsätta använda samma inbyggda dataset, mtcars
:
mtcars = data.table(mtcars) # Let's not include rownames to keep things simpler
Medel av alla kolumner i datasatsen efter antal cylindrar , cyl
:
mtcars[ , lapply(.SD, mean), by = cyl]
# cyl mpg disp hp drat wt qsec vs am gear carb
#1: 6 19.74286 183.3143 122.28571 3.585714 3.117143 17.97714 0.5714286 0.4285714 3.857143 3.428571
#2: 4 26.66364 105.1364 82.63636 4.070909 2.285727 19.13727 0.9090909 0.7272727 4.090909 1.545455
#3: 8 15.10000 353.1000 209.21429 3.229286 3.999214 16.77214 0.0000000 0.1428571 3.285714 3.500000
Förutom cyl
finns det andra kategoriska kolumner i datasättet som vs
, am
, gear
och carb
. Det är inte vettigt att ta med sig mean
från dessa kolumner. Så låt oss utesluta dessa kolumner. Det är här .SDcols
kommer in i bilden.
.SDcols
.SDcols
anger kolumnerna i data.table
som ingår i .SD
.
Medelvärde för alla kolumner (kontinuerliga kolumner) i datauppsättningen genom antalet växlar gear
, och antalet cylindrar, cyl
, arrangerad av gear
och cyl
:
# All the continuous variables in the dataset
cols_chosen <- c("mpg", "disp", "hp", "drat", "wt", "qsec")
mtcars[order(gear, cyl), lapply(.SD, mean), by = .(gear, cyl), .SDcols = cols_chosen]
# gear cyl mpg disp hp drat wt qsec
#1: 3 4 21.500 120.1000 97.0000 3.700000 2.465000 20.0100
#2: 3 6 19.750 241.5000 107.5000 2.920000 3.337500 19.8300
#3: 3 8 15.050 357.6167 194.1667 3.120833 4.104083 17.1425
#4: 4 4 26.925 102.6250 76.0000 4.110000 2.378125 19.6125
#5: 4 6 19.750 163.8000 116.5000 3.910000 3.093750 17.6700
#6: 5 4 28.200 107.7000 102.0000 4.100000 1.826500 16.8000
#7: 5 6 19.700 145.0000 175.0000 3.620000 2.770000 15.5000
#8: 5 8 15.400 326.0000 299.5000 3.880000 3.370000 14.5500
Vi kanske inte vill beräkna mean
med grupper. För att beräkna medelvärdet för alla bilar i dataset vi inte anger by
variabel.
mtcars[ , lapply(.SD, mean), .SDcols = cols_chosen]
# mpg disp hp drat wt qsec
#1: 20.09062 230.7219 146.6875 3.596563 3.21725 17.84875
Notera:
- Det är inte nödvändigt att definiera
cols_chosen
förväg..SDcols
kan direkt ta kolumnnamn -
.SDcols
kan också direkt ta en vektor med kolumnnummer. I exemplet ovan skulle detta varamtcars[ , lapply(.SD, mean), .SDcols = c(1,3:7)]
.N
.N
är kortfattat för antalet rader i en grupp.
iris[, .(count=.N), by=Species]
# Species count
#1: setosa 50
#2: versicolor 50
#3: virginica 50
Skrivkod kompatibel med både data.frame och data.table
Skillnader i syntax för underinställningar
En data.table
är en av flera tvådimensionella datastrukturer som finns tillgängliga i R, förutom data.frame
, matrix
och (2D) array
. Alla dessa klasser använder en mycket likadan men inte identisk syntax för underinställning, schemat A[rows, cols]
.
Tänk på följande data lagrade i en matrix
, en data.frame
och en data.table
:
ma <- matrix(rnorm(12), nrow=4, dimnames=list(letters[1:4], c('X', 'Y', 'Z')))
df <- as.data.frame(ma)
dt <- as.data.table(ma)
ma[2:3] #---> returns the 2nd and 3rd items, as if 'ma' were a vector (because it is!)
df[2:3] #---> returns the 2nd and 3rd columns
dt[2:3] #---> returns the 2nd and 3rd rows!
Om du vill vara säker på vad som kommer att returneras är det bättre att vara uttrycklig .
För att få specifika rader , lägg bara till ett komma efter intervallet:
ma[2:3, ] # \
df[2:3, ] # }---> returns the 2nd and 3rd rows
dt[2:3, ] # /
Men om du vill dela upp kolumner tolkas vissa fall annorlunda. Alla tre kan delas på samma sätt med heltal eller teckenindex som inte lagras i en variabel.
ma[, 2:3] # \
df[, 2:3] # \
dt[, 2:3] # }---> returns the 2nd and 3rd columns
ma[, c("Y", "Z")] # /
df[, c("Y", "Z")] # /
dt[, c("Y", "Z")] # /
De skiljer sig emellertid för ociterade variabla namn
mycols <- 2:3
ma[, mycols] # \
df[, mycols] # }---> returns the 2nd and 3rd columns
dt[, mycols, with = FALSE] # /
dt[, mycols] # ---> Raises an error
I det sista fallet utvärderas mycols
som namnet på en kolumn. Eftersom dt
inte kan hitta en kolumn med namnet mycols
, mycols
ett fel upp.
Obs: För versioner av data.table
paketet före 1.9.8 var detta beteende något annorlunda. Allt i kolumnindexet skulle ha utvärderats med hjälp av dt
som en miljö. Så både dt[, 2:3]
och dt[, mycols]
skulle returnera vektorn 2:3
. Inget fel skulle tas upp för det andra fallet, eftersom variabla mycols
finns i modermiljön.
Strategier för att upprätthålla kompatibilitet med data.frame och data.table
Det finns många skäl att skriva kod som garanteras fungerar med data.frame
och data.table
. Du kanske tvingas använda data.frame
, eller kanske du behöver dela någon kod som du inte vet hur kommer att användas. Så det finns några huvudstrategier för att uppnå detta, i bekvämlighetsordning:
- Använd syntax som uppträder på samma sätt för båda klasserna.
- Använd en vanlig funktion som gör samma sak som den kortaste syntaxen.
-
data.table
att uppträda somdata.frame
(ex .: ring den specifika metodenprint.data.frame
). - Behandla dem som en
list
, som de i slutändan är. - Konvertera tabellen till en
data.frame
innan du gör någonting (dålig idé om det är ett enormt bord). - Konvertera tabellen till
data.table
, om beroenden inte är ett problem.
Undergruppsrader. Det är enkelt, använd bara [, ]
-väljaren med komma:
A[1:10, ]
A[A$var > 17, ] # A[var > 17, ] just works for data.table
Underuppsättning kolumner. Om du vill ha en enda kolumn använder du $
eller [[ ]]
-väljaren:
A$var
colname <- 'var'
A[[colname]]
A[[1]]
Om du vill ha ett enhetligt sätt att ta mer än en kolumn är det nödvändigt att överklaga lite:
B <- `[.data.frame`(A, 2:4)
# We can give it a better name
select <- `[.data.frame`
B <- select(A, 2:4)
C <- select(A, c('foo', 'bar'))
Delmängden 'indexerade' rader. Medan data.frame
har row.names
, har data.table
sin unika key
. Det bästa är att undvika row.names
helt och dra nytta av de befintliga optimeringarna för data.table
när det är möjligt.
B <- A[A$var != 0, ]
# or...
B <- with(A, A[var != 0, ]) # data.table will silently index A by var before subsetting
stuff <- c('a', 'c', 'f')
C <- A[match(stuff, A$name), ] # really worse than: setkey(A); A[stuff, ]
Skaffa en tabell med 1 kolumn, få en rad som en vektor. Dessa är enkla med vad vi har sett hittills:
B <- select(A, 2) #---> a table with just the second column
C <- unlist(A[1, ]) #---> the first row as a vector (coerced if necessary)
Ställa in nycklar i data.table
Ja, du måste SETKEY pre 1.9.6
Tidigare (före 1.9.6) rusades din data.table
upp genom att ställa in kolumner som nycklar till tabellen, särskilt för stora tabeller. [Se introvignett sidan 5 i september 2015-versionen, där sökhastigheten var 544 gånger bättre.] Du kan hitta äldre kod som använder dessa inställningsknappar med 'setkey' eller ställer in en 'key =' kolumn när du ställer in tabellen.
library(data.table)
DT <- data.table(
x = letters[1:5],
y = 5:1,
z = (1:5) > 3
)
#> DT
# x y z
#1: a 5 FALSE
#2: b 4 FALSE
#3: c 3 FALSE
#4: d 2 TRUE
#5: e 1 TRUE
Ställ in din nyckel med kommandot setkey
. Du kan ha en nyckel med flera kolumner.
setkey(DT, y)
Kontrollera tabellens nyckel i tabeller ()
tables()
> tables()
NAME NROW NCOL MB COLS KEY
[1,] DT 5 3 1 x,y,z y
Total: 1MB
Observera att det kommer att sortera dina data igen.
#> DT
# x y z
#1: e 1 TRUE
#2: d 2 TRUE
#3: c 3 FALSE
#4: b 4 FALSE
#5: a 5 FALSE
Nu är det onödigt
Innan v1.9.6 var du tvungen att ställa in en nyckel för vissa operationer, särskilt att gå med i tabeller. Utvecklarna av data.table har påskyndat och introducerat en "on="
-funktion som kan ersätta beroendet av nycklar. Se SO svar här för en detaljerad diskussion.
I januari 2017 har utvecklarna skrivit en vinjett runt sekundära index som förklarar syntaxen "on" och gör det möjligt att identifiera andra kolumner för snabb indexering.
Skapa sekundära index?
På ett sätt som liknar nyckel kan du setindex(DT, key.col)
eller setindexv(DT, "key.col.string")
, där DT är din datatabell. Ta bort alla index med setindex(DT, NULL)
.
Se dina sekundära index med indices(DT)
.
Varför sekundära index?
Detta sorterar inte tabellen (till skillnad från nyckel), men möjliggör snabb indexering med "on" -syntaxen. Observera att det bara kan finnas en nyckel, men du kan använda flera sekundära index, vilket sparar att behöva rekey och ta bort tabellen. Detta påskyndar din underinställning när du ändrar kolumnerna som du vill underuppsätta på.
Kom ihåg, i exemplet ovan var y nyckeln för tabell DT:
DT
# x y z
# 1: e 1 TRUE
# 2: d 2 TRUE
# 3: c 3 FALSE
# 4: b 4 FALSE
# 5: a 5 FALSE
# Let us set x as index
setindex(DT, x)
# Use indices to see what has been set
indices(DT)
# [1] "x"
# fast subset using index and not keyed column
DT["c", on ="x"]
#x y z
#1: c 3 FALSE
# old way would have been rekeying DT from y to x, doing subset and
# perhaps keying back to y (now we save two sorts)
# This is a toy example above but would have been more valuable with big data sets