R Language
Tabela danych
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 tomtcars[ , 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:
- Użyj składni, która zachowuje się tak samo dla obu klas.
- Użyj wspólnej funkcji, która robi to samo, co najkrótsza składnia.
- Wymuś, aby
data.table
zachowywał się jakdata.frame
(np .: wywołaj określoną metodęprint.data.frame
). - Traktuj je jak
list
, którą ostatecznie są. - Przed zrobieniem czegokolwiek
data.frame
tabelę wdata.frame
(zły pomysł, jeśli jest to ogromny stół). - 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