data.table
Använd listkolumner för att lagra data
Sök…
Introduktion
list
.
Anmärkningar
Om det ser konstigt ut att vi pratar om listor utan att använda det ordet i koden, observera att .()
Är ett alias för list()
när det används i ett DT[...]
-samtal.
Läser i många relaterade filer
Anta att vi vill läsa och stapla ett gäng liknande formaterade filer. Den snabba lösningen är:
rbindlist(lapply(list.files(patt="csv$"), fread), id=TRUE)
Vi kanske inte är nöjda med detta av några skäl:
- Det kan
fread
fel när du läser medfread
eller när du staplar medrbindlist
grund av inkonsekvent eller buggy dataformatering. - Vi kanske vill hålla reda på metadata för varje fil, tagna från filnamnet eller kanske från några rubrikrader i filerna (inte riktigt tabellformat).
Ett sätt att hantera detta är att skapa en "filtabell" och lagra innehållet i varje fil som en listkolumnpost på raden som är associerad med den.
Exempel data
Innan du gör exempeldata nedan, se till att du är i en tom mapp du kan skriva till. Kör getwd()
och läs ?setwd
om du behöver byta mappar.
# example data
set.seed(1)
for (i in 1:3)
fwrite(data.table(id = 1:2, v = sample(letters, 2)), file = sprintf("file201%s.csv", i))
Identifiera filer och filmetadata
Den här delen är ganska enkel:
# First, identify the files you want:
fileDT = data.table(fn = list.files(pattern="csv$"))
# Next, optionally parse the names for metadata using regex:
fileDT[, year := type.convert(sub(".*([0-9]{4}).*", "\\1", fn))]
# Finally construct a string file-ID column:
fileDT[, id := as.character(.I)]
# fn year id
# 1: file2011.csv 2011 1
# 2: file2012.csv 2012 2
# 3: file2013.csv 2013 3
Läs i filer
Läs filerna som en listkolumn:
fileDT[, contents := .(lapply(fn, fread))]
# fn year id contents
# 1: file2011.csv 2011 1 <data.table>
# 2: file2012.csv 2012 2 <data.table>
# 3: file2013.csv 2013 3 <data.table>
Om det finns en häng vid läsning av en av filerna eller om du behöver ändra argumenten för att fread
beroende på filens attribut, kan detta steg enkelt utökas, så att det ser ut som:
fileDT[, contents := {
cat(fn, "\n")
dat = if (year %in% 2011:2012){
fread(fn, some_args)
} else {
fread(fn)
}
.(.(dat))
}, by=fn]
För detaljer om läsning i CSV-filer och liknande filer, se ?fread
.
Stapla data
Härifrån vill vi stapla uppgifterna:
fileDT[, rbindlist(setNames(contents, id), idcol="file_id")]
# file_id id v
# 1: 1 1 g
# 2: 1 2 j
# 3: 2 1 o
# 4: 2 2 w
# 5: 3 1 f
# 6: 3 2 w
Om något problem uppstår vid stapling (som kolumnnamn eller klasser som inte matchar) kan vi gå tillbaka till de enskilda tabellerna i fileDT
att fileDT
var problemet har sitt ursprung. Till exempel,
fileDT[id == "2", contents[[1]]]
# id v
# 1: 1 o
# 2: 2 w
Extensions
Om filerna inte finns i ditt nuvarande arbetsdir, använd
my_dir = "whatever"
fileDT = data.table(fn = list.files(my_dir, pattern="*.csv"))
# and when reading
fileDT[, contents := .(lapply(fn, function(n) fread(file.path(my_dir, n))))]