Szukaj…


Wprowadzenie

Data.table to pakiet, który rozszerza funkcjonalność ramek danych od podstawy R, szczególnie poprawiając ich wydajność i składnię. Aby uzyskać szczegółowe informacje, zobacz obszar Dokumenty pakietu w części Pierwsze kroki z data.table .

Składnia

  • DT[i, j, by]
    # DT [gdzie, wybierz | aktualizuj | zrobić, przez]
  • DT[...][...]
    # łańcuchy
  • ################# Shortcuts, special functions and special symbols inside DT[...]
  • . ()
    # w kilku argumentach, zastępuje list ()
  • JOT()
    # w i, zastępuje list ()
  • : =
    # w j, funkcja używana do dodawania lub modyfikowania kolumn
  • .N
    # w i, łączna liczba wierszy
    # w j liczba wierszy w grupie
  • .JA
    # w j, wektor liczb wierszy w tabeli (filtrowane przez i)
  • .SD
    # w j, bieżący podzbiór danych
    # wybrane przez argument .SDcols
  • .GRP
    # w j, bieżący indeks podzbioru danych
  • .PRZEZ
    # w j, lista według wartości dla bieżącego podzbioru danych
  • V1, V2, ...
    # domyślne nazwy dla nienazwanych kolumn utworzonych w j
  • ################# Joins inside DT[...]
  • DT1 [DT2, włączony, j]
    # połącz dwie tabele
  • ja.*
    # specjalny prefiks w kolumnach DT2 po złączeniu
  • przez = .EACHI
    # specjalna opcja dostępna tylko z łączeniem
  • DT1 [! DT2, włączony, j]
    # anti-join dwie tabele
  • DT1 [DT2, on, roll, j]
    # połącz dwie tabele, przesuwając się po ostatniej kolumnie w =
  • ################# Reshaping, stacking and splitting
  • stop (DT, id.vars, Measure.vars)
    # przekształcić na długi format
    # dla wielu kolumn, użyj pomiaru. var = wzory (...)
  • dcast (DT, formuła)
    # przekształcić do formatu szerokiego
  • rbind (DT1, DT2, ...)
    # stos wyliczonych data.tables
  • rbindlist (DT_list, idcol)
    # stos listę list data.tables
  • podział (ID, według)
    # podziel tabelę danych na listę
  • ################# Some other functions specialized for data.tables
  • foverlaps
    # nakładanie się łączy
  • łączyć
    # inny sposób łączenia dwóch tabel
  • zestaw
    # inny sposób dodawania lub modyfikowania kolumn
  • fintersect, fsetdiff, funion, fsetequal, unique, duplicated, anyDuplicated
    # operacje teorii zbiorów z wierszami jako elementami
  • UniqueN
    # liczba różnych wierszy
  • rowidv (DT, cols)
    # identyfikator wiersza (od 1 do .N) w każdej grupie określony kols
  • rleidv (DT, cols)
    # ID grupy (od 1 do .GRP) w obrębie każdej grupy określone przez przebiegi kolumn
  • shift (DT, n, type = c („lag”, „lead”))
    # zastosuj operator shift do każdej kolumny
  • setorder, setcolorder, setnames, setkey, setindex, setattr
    # modyfikuj atrybuty i porządek przez odniesienie

Uwagi

Instalacja i wsparcie

Aby zainstalować pakiet 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")

Oficjalna strona pakietu zawiera strony wiki zapewniające pomoc w rozpoczęciu oraz listy prezentacji i artykułów z całej sieci. Przed zadaniem pytania - tutaj na StackOverflow lub gdziekolwiek indziej - przeczytaj stronę pomocy technicznej .

Ładowanie paczki

Wiele funkcji z powyższych przykładów istnieje w przestrzeni nazw data.table. Aby ich użyć, musisz najpierw dodać wiersz taki jak library(data.table) lub użyć ich pełnej ścieżki, jak data.table::fread zamiast po prostu fread . Aby uzyskać pomoc dotyczącą poszczególnych funkcji, składnia to help("fread") lub ?fread . Ponownie, jeśli pakiet nie jest załadowany, użyj pełnej nazwy jak ?data.table::fread .

Tworzenie tabeli danych

Data.table to ulepszona wersja klasy data.frame z bazy R. W związku z tym jej atrybutem class() jest wektor "data.table" "data.frame" a funkcje działające na data.frame również praca z tabelą danych. Istnieje wiele sposobów tworzenia, ładowania lub wymuszania tabeli danych.

Budować

Nie zapomnij zainstalować i aktywować pakietu data.table

library(data.table)

Istnieje konstruktor o tej samej nazwie:

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

W przeciwieństwie do data.frame , data.table nie będzie wymuszać ciągów czynników:

sapply(DT, class)
#               x           y           z 
#     "character"   "integer"   "logical" 

Czytaj w

Możemy odczytać z pliku tekstowego:

dt <- fread("my_file.csv")

W przeciwieństwie do read.csv , fread będzie czytał ciągi jako ciągi, a nie jako czynniki.

Zmodyfikuj ramkę danych

Aby zwiększyć wydajność, data.table oferuje sposób zmiany ramki data.frame lub listy w celu utworzenia tabeli data.table w miejscu (bez wykonywania kopii lub zmiany lokalizacji pamięci):

# example data.frame
DF <- data.frame(x = letters[1:5], y = 1:5, z = (1:5) > 3)
# modification
setDT(DF)

Zauważ, że nie <- przypisujemy wyniku, ponieważ obiekt DF został zmodyfikowany w miejscu. Atrybuty klasy data.frame zostaną zachowane:

sapply(DF, class)
#         x         y         z 
#  "factor" "integer" "logical" 

Wymuś obiekt na data.table

Jeśli masz list , data.frame lub data.table , powinieneś użyć funkcji setDT do konwersji na data.table ponieważ wykonuje konwersję przez odniesienie zamiast tworzyć kopię (co robi as.data.table ). Jest to ważne, jeśli pracujesz z dużymi zestawami danych.

Jeśli masz inny obiekt R (na przykład macierz), musisz użyć as.data.table aby as.data.table go do data.table .

mat <- matrix(0, ncol = 10, nrow = 10)

DT <- as.data.table(mat)
# or
DT <- data.table(mat)

Dodawanie i modyfikowanie kolumn

Składnia DT[where, select|update|do, by] jest używana do pracy z kolumnami tabeli danych.

  • Część „gdzie” to argument i
  • Część „select | update | do” jest argumentem j

Te dwa argumenty są zwykle przekazywane według pozycji zamiast nazwy.

Nasze przykładowe dane poniżej to

mtcars = data.table(mtcars, keep.rownames = TRUE)

Edycja całych kolumn

Użyj operatora := wewnątrz j aby przypisać nowe kolumny:

mtcars[, mpg_sq := mpg^2]

Usuń kolumny, ustawiając NULL :

mtcars[, mpg_sq := NULL]

Dodaj wiele kolumn, używając formatu wielowymiarowego operatora := :

mtcars[, `:=`(mpg_sq = mpg^2, wt_sqrt = sqrt(wt))]
# or 
mtcars[, c("mpg_sq", "wt_sqrt") := .(mpg^2, sqrt(wt))]

Jeśli kolumny są zależne i muszą być zdefiniowane po kolei, jednym ze sposobów jest:

mtcars[, c("mpg_sq", "mpg2_hp") := .(temp1 <- mpg^2, temp1/hp)]

Składnia .() Jest używana, gdy prawa strona LHS := RHS jest listą kolumn.

W przypadku dynamicznie określanych nazw kolumn użyj nawiasów:

vn = "mpg_sq"
mtcars[, (vn) := mpg^2]

Kolumny można również modyfikować za pomocą set , choć rzadko jest to konieczne:

set(mtcars, j = "hp_over_wt", v = mtcars$hp/mtcars$wt)

Edycja podzbiorów kolumn

Użyj argumentu i aby podgrupować wiersze „tam, gdzie” należy wprowadzić zmiany:

mtcars[1:3, newvar := "Hello"]
# or
set(mtcars, j = "newvar", i = 1:3, v = "Hello")  

Podobnie jak w ramce data.frame, możemy dokonać podzbioru za pomocą numerów wierszy lub testów logicznych. Możliwe jest również użycie „złączenia” w i , ale to bardziej skomplikowane zadanie zostało omówione w innym przykładzie.

Edycja atrybutów kolumny

Funkcje edytujące atrybuty, takie jak levels<- lub names<- , faktycznie zastępują obiekt zmodyfikowaną kopią. Nawet jeśli zostanie użyty tylko w jednej kolumnie w pliku data.table, cały obiekt zostanie skopiowany i zastąpiony.

Aby zmodyfikować obiekt bez kopii, użyj setnames aby zmienić nazwy kolumn data.table lub data.frame i setattr aby zmienić atrybut dowolnego obiektu.

# 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")

Pamiętaj, że zmiany te są dokonywane przez odniesienie, więc są globalne . Zmiana ich w jednym środowisku wpływa na obiekt we wszystkich środowiskach.

# 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)

Symbole specjalne w tabeli danych

.SD

.SD odnosi się do podzestawu data.table dla każdej grupy, z wyłączeniem wszystkich kolumn używanych by .

.SD wraz z lapply można zastosować do zastosowania dowolnej funkcji do wielu kolumn według grup w data.table

Będziemy nadal używać tego samego wbudowanego zestawu danych, mtcars :

mtcars = data.table(mtcars) # Let's not include rownames to keep things simpler

Średnia wszystkich kolumn w zestawie danych według liczby cylindrów , 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

Oprócz cyl w zestawie danych znajdują się także inne kategorie, takie jak vs , am , gear i carb . To naprawdę nie ma sensu wziąć mean z tych kolumn. Wykluczmy więc te kolumny. To .SDcols pojawia się .SDcols .

.SDcols

.SDcols określa kolumny data.table które są zawarte w .SD .

Średnia wszystkich kolumn (kolumn ciągłych) w zbiorze danych według liczby kół gear i liczby cylindrów , cyl , ułożonych według gear i 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

Może nie chcemy obliczać mean według grup. Aby obliczyć średnią dla wszystkich samochodów w zbiorze danych, nie podajemy zmiennej by .

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

Uwaga:

  • Nie trzeba wcześniej definiować cols_chosen . .SDcols mogą bezpośrednio pobierać nazwy kolumn
  • .SDcols mogą również bezpośrednio pobierać wektor numerów kolumn. W powyższym przykładzie byłoby to mtcars[ , lapply(.SD, mean), .SDcols = c(1,3:7)]

.N

.N to skrót od liczby wierszy w grupie.

iris[, .(count=.N), by=Species]

#      Species count
#1:     setosa    50
#2: versicolor    50
#3:  virginica    50

Pisanie kodu kompatybilnego z data.frame i data.table

Różnice w składni podzbioru

data.table jest jedną z kilku dwuwymiarowych struktur danych dostępnych w R, oprócz data.frame , matrix i (2D) array . Wszystkie te klasy używają bardzo podobnej, ale nie identycznej składni do podzbioru, schematu A[rows, cols] .

Rozważ następujące dane przechowywane w matrix , data.frame i 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!

Jeśli chcesz mieć pewność, co zostanie zwrócone, lepiej być wyraźnym .

Aby uzyskać określone wiersze , po prostu dodaj przecinek za zakresem:

ma[2:3, ]  # \
df[2:3, ]  #  }---> returns the 2nd and 3rd rows
dt[2:3, ]  # /

Ale jeśli chcesz podzielić kolumny , niektóre przypadki są interpretowane inaczej. Wszystkie trzy mogą być podzielone w ten sam sposób z liczbami całkowitymi lub indeksami znaków nie przechowywanymi w zmiennej.

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")]  # /

Różnią się one jednak dla niecytowanych nazw zmiennych

mycols <- 2:3
ma[, mycols]                # \
df[, mycols]                #  }---> returns the 2nd and 3rd columns
dt[, mycols, with = FALSE]  # /

dt[, mycols]                # ---> Raises an error

W ostatnim przypadku mycols są oceniane jako nazwa kolumny. Ponieważ dt nie może znaleźć kolumny o nazwie mycols , mycols się błąd.

Uwaga: W przypadku wersji data.table pakietu priorto 1.9.8, to zachowanie było nieco inaczej. Wszystko w indeksie kolumny zostałoby ocenione przy użyciu dt jako środowiska. Zatem zarówno dt[, 2:3] i dt[, mycols] zwrócą wektor 2:3 . W drugim przypadku nie mycols żaden błąd, ponieważ zmienne mycols istnieją w środowisku nadrzędnym.

Strategie utrzymania zgodności z data.frame i data.table

Istnieje wiele powodów, aby napisać kod, który gwarantuje pracę z data.frame i data.table . Być może jesteś zmuszony użyć data.frame lub być może będziesz musiał udostępnić trochę kodu, którego nie wiesz, jak będzie używany. Istnieją więc pewne główne strategie osiągnięcia tego celu, według wygody:

  1. Użyj składni, która zachowuje się tak samo dla obu klas.
  2. Użyj wspólnej funkcji, która robi to samo, co najkrótsza składnia.
  3. Wymuś, aby data.table zachowywał się jak data.frame (np .: wywołaj określoną metodę print.data.frame ).
  4. Traktuj je jak list , którą ostatecznie są.
  5. Przed zrobieniem czegokolwiek data.frame tabelę w data.frame (zły pomysł, jeśli jest to ogromny stół).
  6. Konwertuj tabelę na tabelę data.table , jeśli zależności nie stanowią problemu.

Podzbiór wierszy. To proste, wystarczy użyć selektora [, ] z przecinkiem:

A[1:10, ]
A[A$var > 17, ]  # A[var > 17, ] just works for data.table

Podzbiór kolumn. Jeśli chcesz mieć jedną kolumnę, użyj selektora $ lub [[ ]] :

A$var
colname <- 'var'
A[[colname]]
A[[1]]

Jeśli chcesz uzyskać jednolity sposób na zdobycie więcej niż jednej kolumny, musisz nieco odwołać się do:

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'))

Podzbiór „indeksowanych” wierszy. Podczas gdy data.frame ma row.names , data.table ma swoją unikalną key funkcję. Najlepiej jest całkowicie unikać row.names i w data.table możliwości korzystać z istniejących optymalizacji w przypadku data.table .

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, ]

Uzyskaj tabelę 1-kolumnową, uzyskaj wiersz jako wektor. Są to łatwe dzięki temu, co widzieliśmy do tej pory:

B <- select(A, 2)    #---> a table with just the second column
C <- unlist(A[1, ])  #---> the first row as a vector (coerced if necessary)

Ustawianie kluczy w tabeli danych

Tak, musisz SETKEY wcześniej niż 1.9.6

W przeszłości (wcześniejsza niż 1.9.6) twoja data.table była przyspieszana przez ustawienie kolumn jako kluczy do tabeli, szczególnie dla dużych tabel. [Zobacz winietę wprowadzającą na stronie 5 wersji z września 2015 r., Gdzie szybkość wyszukiwania była 544 razy lepsza.] Możesz znaleźć starszy kod korzystający z tych klawiszy ustawień za pomocą „setkey” lub ustawiający kolumnę „key =” podczas konfigurowania tabeli.

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

Ustaw swój klucz za pomocą polecenia setkey . Możesz mieć klucz z wieloma kolumnami.

setkey(DT, y)

Sprawdź klucz swojej tabeli w tabelach ()

tables()

> tables()
     NAME NROW NCOL MB COLS  KEY
[1,] DT      5    3  1 x,y,z y  
Total: 1MB

Uwaga: spowoduje to ponowne sortowanie danych.

#> DT
#   x y     z
#1: e 1  TRUE
#2: d 2  TRUE
#3: c 3 FALSE
#4: b 4 FALSE
#5: a 5 FALSE

Teraz jest to niepotrzebne

Przed wersją 1.9.6 trzeba było ustawić klucz dla niektórych operacji, zwłaszcza łączenia tabel. Twórcy data.table przyspieszyli i wprowadzili funkcję "on=" która może zastąpić zależność od kluczy. Zobacz SO odpowiedź tutaj, aby uzyskać szczegółową dyskusję.

W styczniu 2017 r. Programiści napisali winietę wokół indeksów wtórnych, która wyjaśnia składnię „on” i pozwala na identyfikację innych kolumn w celu szybkiego indeksowania.

Tworzysz indeksy wtórne?

W podobny sposób jak klucz, możesz setindex(DT, key.col) lub setindexv(DT, "key.col.string") , gdzie DT jest twoją tabelą danych. Usuń wszystkie indeksy za pomocą setindex(DT, NULL) .

Zobacz swoje indeksy wtórne z indices(DT) .

Dlaczego indeksy wtórne?

Nie sortuje tabeli (w przeciwieństwie do klucza), ale pozwala na szybkie indeksowanie przy użyciu składni „on”. Uwaga: może istnieć tylko jeden klucz, ale możesz użyć wielu drugorzędnych indeksów, co oszczędza konieczności ponownego generowania tabeli i odwoływania się do tabeli. Przyspieszy to podzbiór przy zmianie kolumn, na których chcesz podzbiór.

Przypomnijmy, w powyższym przykładzie y był kluczem do tabeli 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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow