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 vara mtcars[ , 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:

  1. Använd syntax som uppträder på samma sätt för båda klasserna.
  2. Använd en vanlig funktion som gör samma sak som den kortaste syntaxen.
  3. data.table att uppträda som data.frame (ex .: ring den specifika metoden print.data.frame ).
  4. Behandla dem som en list , som de i slutändan är.
  5. Konvertera tabellen till en data.frame innan du gör någonting (dålig idé om det är ett enormt bord).
  6. 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


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow