Zwiększ swoje dane z R
Opublikowany: 2022-03-11Język R jest często postrzegany jako język dla statystyków i analityków danych. Dość dawno temu było to w większości prawdą. Jednak z biegiem lat elastyczność, jaką zapewnia R za pośrednictwem pakietów, sprawiła, że R stał się językiem bardziej ogólnego przeznaczenia. R był open source w 1995 roku i od tego czasu repozytoria pakietów R stale się powiększają. Mimo to, w porównaniu do języków takich jak Python, R jest silnie oparte na danych.
Mówiąc o danych, na szczególną uwagę zasługują dane tabelaryczne, ponieważ to jeden z najczęściej używanych typów danych. Jest to typ danych, który odpowiada strukturze tabeli znanej w bazach danych, gdzie każda kolumna może być innego typu, a wydajność przetwarzania tego konkretnego typu danych ma kluczowe znaczenie dla wielu aplikacji.
W tym artykule przedstawimy, jak w efektywny sposób przeprowadzić transformację danych tabelarycznych. Wiele osób, które już używają języka R do uczenia maszynowego, nie zdaje sobie sprawy, że mutowanie danych można wykonać szybciej w R i że nie muszą do tego celu używać innego narzędzia.
Wysokowydajne rozwiązanie w R
Base R wprowadził klasę data.frame
w 1997 roku, która była wcześniej oparta na S-PLUS. W przeciwieństwie do powszechnie używanych baz danych, które przechowują dane wiersz po wierszu, R data.frame
przechowuje dane w pamięci jako strukturę zorientowaną na kolumny, dzięki czemu jest bardziej wydajny w pamięci podręcznej dla operacji kolumnowych, które są powszechne w analityce. Dodatkowo, mimo że R jest funkcjonalnym językiem programowania, nie wymusza tego na deweloperze. Obie możliwości zostały dobrze zaadresowane przez pakiet data.table
R, który jest dostępny w repozytorium CRAN. Wykonuje się dość szybko podczas grupowania operacji i jest szczególnie wydajny pod względem pamięci, ponieważ należy uważać na materializację pośrednich podzbiorów danych, takich jak materializowanie tylko tych kolumn, które są niezbędne do określonego zadania. Pozwala również uniknąć niepotrzebnych kopii dzięki semantyce referencyjnej podczas dodawania lub aktualizowania kolumn. Pierwsza wersja pakietu została opublikowana w kwietniu 2006 roku, znacznie poprawiając w tym czasie wydajność data.frame
. Początkowy opis pakietu brzmiał:
Ten pakiet robi bardzo mało. Jedynym powodem jego istnienia jest to, że biała księga określa, że data.frame musi mieć nazwy wierszy. Ten pakiet definiuje nową klasę data.table, która działa jak data.frame, ale zużywa do 10 razy mniej pamięci i może być do 10 razy szybsza do tworzenia (i kopiowania). Wykorzystuje również możliwość zezwolenia na wyrażenia podobne do subset() i with() wewnątrz []. Większość kodu jest kopiowana z funkcji podstawowych z usuniętym kodem manipulującym row.names.
Od tego czasu implementacje data.frame
i data.table
zostały ulepszone, ale data.table
nadal jest niewiarygodnie szybsza niż base R. W rzeczywistości data.table
nie jest po prostu szybsza niż base R, ale wydaje się być jedną z nich. najszybszego dostępnego narzędzia open source do przetwarzania danych, które konkuruje z takimi narzędziami, jak Python Pandas i kolumnowymi bazami danych pamięci masowej lub aplikacjami Big Data, takimi jak Spark. Jego wydajność w rozproszonej infrastrukturze współużytkowanej nie została jeszcze przetestowana, ale możliwość posiadania do dwóch miliardów wierszy na jednej instancji daje obiecujące perspektywy. Znakomita wydajność idzie w parze z funkcjonalnościami. Dodatkowo, dzięki niedawnym wysiłkom zmierzającym do zrównoleglenia czasochłonnych części w celu zwiększenia wydajności, jeden kierunek w kierunku przesuwania limitu wydajności wydaje się całkiem jasny.
Przykłady transformacji danych
Nauka R staje się nieco łatwiejsza, ponieważ działa ono interaktywnie, dzięki czemu możemy krok po kroku śledzić przykłady i przyjrzeć się wynikom każdego kroku w dowolnym momencie. Zanim zaczniemy, zainstalujmy pakiet data.table
z repozytorium CRAN.
install.packages("data.table")
Przydatna wskazówka : Możemy otworzyć instrukcję dowolnej funkcji wpisując jej nazwę ze znakiem zapytania, np. ?install.packages
.
Ładowanie danych do R
Istnieje mnóstwo pakietów do wyodrębniania danych z szerokiej gamy formatów i baz danych, które często zawierają sterowniki natywne. Załadujemy dane z pliku CSV , najpopularniejszego formatu nieprzetworzonych danych tabelarycznych. Plik użyty w poniższych przykładach można znaleźć tutaj. Nie musimy przejmować się wydajnością odczytu plików CSV
, ponieważ funkcja fread
jest pod tym kątem wysoce zoptymalizowana.
Aby użyć dowolnej funkcji z pakietu, musimy załadować ją wywołaniem library
.
library(data.table) DT <- fread("flights14.csv") print(DT)
## year month day dep_delay arr_delay carrier origin dest air_time ## 1: 2014 1 1 14 13 AA JFK LAX 359 ## 2: 2014 1 1 -3 13 AA JFK LAX 363 ## 3: 2014 1 1 2 9 AA JFK LAX 351 ## 4: 2014 1 1 -8 -26 AA LGA PBI 157 ## 5: 2014 1 1 2 1 AA JFK LAX 350 ## --- ## 253312: 2014 10 31 1 -30 UA LGA IAH 201 ## 253313: 2014 10 31 -5 -14 UA EWR IAH 189 ## 253314: 2014 10 31 -8 16 MQ LGA RDU 83 ## 253315: 2014 10 31 -4 15 MQ LGA DTW 75 ## 253316: 2014 10 31 -5 1 MQ LGA SDF 110 ## distance hour ## 1: 2475 9 ## 2: 2475 11 ## 3: 2475 19 ## 4: 1035 7 ## 5: 2475 13 ## --- ## 253312: 1416 14 ## 253313: 1400 8 ## 253314: 431 11 ## 253315: 502 11 ## 253316: 659 8
Jeśli nasze dane nie są dobrze zamodelowane pod kątem dalszego przetwarzania, ponieważ muszą zostać przekształcone z formatu długiego na szeroki lub szeroki na długi (znany również jako pivot i unpivot ), możemy przyjrzeć się ?dcast
i ?melt
, znany z pakietu reshape2. Jednak data.table
implementuje szybsze i wydajniejsze pod względem pamięci metody dla klasy data.table/data.frame.
Zapytania za pomocą data.table
Składnia
Jeśli data.frame
Zapytanie data.table
jest bardzo podobne do zapytania data.frame
. Podczas filtrowania w argumencie i
możemy używać nazw kolumn bezpośrednio, bez konieczności dostępu do nich za pomocą znaku $
, np. df[df$col > 1, ]
. Podając kolejny argument j
, podajemy wyrażenie do oceny w zakresie naszego data.table
. Aby przekazać argument nie będący wyrażeniem j
, użyj with=FALSE
. Trzeci argument, nieobecny w metodzie data.frame
, definiuje grupy, co powoduje, że wyrażenie w j
jest oceniane przez grupy.
# data.frame DF[DF$col1 > 1L, c("col2", "col3")] # data.table DT[col1 > 1L, .(col2, col3), ...] # by group using: `by = col4`
Jeśli znasz bazy danych
Zapytanie data.table
w wielu aspektach odpowiada zapytaniom SQL, z którymi może być zaznajomiona większa liczba osób. DT
poniżej reprezentuje obiekt data.table
i odpowiada klauzuli SQLs FROM
.
DT[ i = where, j = select | update, by = group by] [ having, ... ] [ order by, ... ] [ ... ] ... [ ... ]
Sortowanie wierszy i zmiana kolejności kolumn
Sortowanie danych jest kluczową transformacją szeregów czasowych, a także importem do wyodrębniania i prezentacji danych. Sortowanie można uzyskać, podając wektor całkowity kolejności wierszy do argumentu i
, w taki sam sposób jak data.frame
. Pierwszy argument w order(carrier, -dep_delay)
wybierze dane w kolejności rosnącej na polu carrier
i malejącej na mierze dep_delay
. Drugi argument j
, jak opisano w poprzedniej sekcji, definiuje kolumny (lub wyrażenia), które mają zostać zwrócone, oraz ich kolejność.
ans <- DT[order(carrier, -dep_delay), .(carrier, origin, dest, dep_delay)] head(ans)
## carrier origin dest dep_delay ## 1: AA EWR DFW 1498 ## 2: AA JFK BOS 1241 ## 3: AA EWR DFW 1071 ## 4: AA EWR DFW 1056 ## 5: AA EWR DFW 1022 ## 6: AA EWR DFW 989
Aby zmienić kolejność danych według referencji, zamiast odpytywać dane w określonej kolejności, używamy funkcji set*
.
setorder(DT, carrier, -dep_delay) leading.cols <- c("carrier","dep_delay") setcolorder(DT, c(leading.cols, setdiff(names(DT), leading.cols))) print(DT)
## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1241 2014 4 15 1223 JFK BOS 39 ## 3: AA 1071 2014 6 13 1064 EWR DFW 175 ## 4: AA 1056 2014 9 12 1115 EWR DFW 198 ## 5: AA 1022 2014 6 16 1073 EWR DFW 178 ## --- ## 253312: WN -12 2014 3 9 -21 LGA BNA 115 ## 253313: WN -13 2014 3 10 -18 EWR MDW 112 ## 253314: WN -13 2014 5 17 -30 LGA HOU 202 ## 253315: WN -13 2014 6 15 10 LGA MKE 101 ## 253316: WN -13 2014 8 19 -30 LGA CAK 63 ## distance hour ## 1: 1372 7 ## 2: 187 13 ## 3: 1372 10 ## 4: 1372 6 ## 5: 1372 7 ## --- ## 253312: 764 16 ## 253313: 711 20 ## 253314: 1428 17 ## 253315: 738 20 ## 253316: 397 16
Najczęściej nie potrzebujemy zarówno oryginalnego zestawu danych, jak i uporządkowanego/posortowanego zestawu danych. Domyślnie język R, podobnie jak inne funkcjonalne języki programowania, zwróci posortowane dane jako nowy obiekt, a zatem będzie wymagał dwa razy więcej pamięci niż sortowanie przez odniesienie.
Podzbiór zapytań
Stwórzmy podzbiór danych dla początku lotu „JFK” i miesiąca od 6 do 9. W drugim argumencie podzbieramy wyniki do wymienionych kolumn, dodając jedną obliczoną zmienną sum_delay
.
ans <- DT[origin == "JFK" & month %in% 6:9, .(origin, month, arr_delay, dep_delay, sum_delay = arr_delay + dep_delay)] head(ans)
## origin month arr_delay dep_delay sum_delay ## 1: JFK 7 925 926 1851 ## 2: JFK 8 727 772 1499 ## 3: JFK 6 466 451 917 ## 4: JFK 7 414 450 864 ## 5: JFK 6 411 442 853 ## 6: JFK 6 333 343 676
Domyślnie, gdy zestaw danych podzbiór w pojedynczej kolumnie data.table
automatycznie utworzy indeks dla tej kolumny. Powoduje to odpowiedzi w czasie rzeczywistym na dalsze połączenia filtrujące w tej kolumnie.
Zaktualizuj zbiór danych
Dodanie nowej kolumny przez odwołanie odbywa się za pomocą operatora :=
, przypisuje on zmienną do zbioru danych w miejscu. Pozwala to uniknąć kopii zestawu danych w pamięci, więc nie musimy przypisywać wyników do każdej nowej zmiennej.
DT[, sum_delay := arr_delay + dep_delay] head(DT)
## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1241 2014 4 15 1223 JFK BOS 39 ## 3: AA 1071 2014 6 13 1064 EWR DFW 175 ## 4: AA 1056 2014 9 12 1115 EWR DFW 198 ## 5: AA 1022 2014 6 16 1073 EWR DFW 178 ## 6: AA 989 2014 6 11 991 EWR DFW 194 ## distance hour sum_delay ## 1: 1372 7 2992 ## 2: 187 13 2464 ## 3: 1372 10 2135 ## 4: 1372 6 2171 ## 5: 1372 7 2095 ## 6: 1372 11 1980
Aby dodać więcej zmiennych naraz, możemy użyć składni DT[,
:= (sum_delay = arr_delay + dep_delay)]
, podobnej do .(sum_delay = arr_delay + dep_delay)
podczas wykonywania zapytań z zestawu danych.
Możliwe jest przypisanie podrzędne przez odwołanie, aktualizując tylko określone wiersze w miejscu, po prostu łącząc z argumentem i
.
DT[origin=="JFK", distance := NA] head(DT)
## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1241 2014 4 15 1223 JFK BOS 39 ## 3: AA 1071 2014 6 13 1064 EWR DFW 175 ## 4: AA 1056 2014 9 12 1115 EWR DFW 198 ## 5: AA 1022 2014 6 16 1073 EWR DFW 178 ## 6: AA 989 2014 6 11 991 EWR DFW 194 ## distance hour sum_delay ## 1: 1372 7 2992 ## 2: NA 13 2464 ## 3: 1372 10 2135 ## 4: 1372 6 2171 ## 5: 1372 7 2095 ## 6: 1372 11 1980
Zagregowane dane
Aby zagregować dane, podajemy trzeci argument by
do nawiasu kwadratowego. Następnie w j
musimy podać wywołania funkcji agregujących, aby dane mogły być faktycznie zagregowane. Symbol .N
użyty w argumencie j
odpowiada liczbie wszystkich obserwacji w każdej grupie. Jak już wspomniano, agregaty można łączyć z podzbiorami w wierszach i wybieraniem kolumn.
ans <- DT[, .(m_arr_delay = mean(arr_delay), m_dep_delay = mean(dep_delay), count = .N), .(carrier, month)] head(ans)
## carrier month m_arr_delay m_dep_delay count ## 1: AA 10 5.541959 7.591497 2705 ## 2: AA 4 1.903324 3.987008 2617 ## 3: AA 6 8.690067 11.476475 2678 ## 4: AA 9 -1.235160 3.307078 2628 ## 5: AA 8 4.027474 8.914054 2839 ## 6: AA 7 9.159886 11.665953 2802
Często może być konieczne porównanie wartości wiersza z jego agregacją w grupie. W SQL stosujemy agregaty na partycji według : AVG(arr_delay) OVER (PARTITION BY carrier, month)
.

ans <- DT[, .(arr_delay, carrierm_mean_arr = mean(arr_delay), dep_delay, carrierm_mean_dep = mean(dep_delay)), .(carrier, month)] head(ans)
## carrier month arr_delay carrierm_mean_arr dep_delay carrierm_mean_dep ## 1: AA 10 1494 5.541959 1498 7.591497 ## 2: AA 10 840 5.541959 848 7.591497 ## 3: AA 10 317 5.541959 338 7.591497 ## 4: AA 10 292 5.541959 331 7.591497 ## 5: AA 10 322 5.541959 304 7.591497 ## 6: AA 10 306 5.541959 299 7.591497
Jeśli nie chcemy wykonywać zapytań o dane za pomocą tych agregatów, a zamiast tego umieszczamy je w rzeczywistej aktualizacji tabeli przez odniesienie, możemy to osiągnąć za pomocą operatora :=
. Pozwala to uniknąć kopii zestawu danych w pamięci, więc nie musimy przypisywać wyników do nowej zmiennej.
DT[, `:=`(carrierm_mean_arr = mean(arr_delay), carrierm_mean_dep = mean(dep_delay)), .(carrier, month)] head(DT)
## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1241 2014 4 15 1223 JFK BOS 39 ## 3: AA 1071 2014 6 13 1064 EWR DFW 175 ## 4: AA 1056 2014 9 12 1115 EWR DFW 198 ## 5: AA 1022 2014 6 16 1073 EWR DFW 178 ## 6: AA 989 2014 6 11 991 EWR DFW 194 ## distance hour sum_delay carrierm_mean_arr carrierm_mean_dep ## 1: 1372 7 2992 5.541959 7.591497 ## 2: NA 13 2464 1.903324 3.987008 ## 3: 1372 10 2135 8.690067 11.476475 ## 4: 1372 6 2171 -1.235160 3.307078 ## 5: 1372 7 2095 8.690067 11.476475 ## 6: 1372 11 1980 8.690067 11.476475
Dołącz do zbiorów danych
Łączenie i scalanie zestawów danych Base R jest uważane za specjalny typ operacji na podzbiorach . Dostarczamy zbiór danych, do którego chcemy dołączyć w pierwszym argumencie nawiasu kwadratowego i
. Dla każdego wiersza w zestawie danych dostarczonym do i
, dopasowujemy wiersze z zestawu danych, w którym używamy [
. Jeśli chcemy zachować tylko pasujące wiersze ( złącze wewnętrzne ), przekazujemy dodatkowy argument nomatch = 0L
. Używamy on
argument, aby określić kolumny, na których chcemy połączyć oba zbiory danych.
# create reference subset carrierdest <- DT[, .(count=.N), .(carrier, dest) # count by carrier and dest ][1:10 # just 10 first groups ] # chaining `[...][...]` as subqueries print(carrierdest)
## carrier dest count ## 1: AA DFW 5877 ## 2: AA BOS 1173 ## 3: AA ORD 4798 ## 4: AA SEA 298 ## 5: AA EGE 85 ## 6: AA LAX 3449 ## 7: AA MIA 6058 ## 8: AA SFO 1312 ## 9: AA AUS 297 ## 10: AA DCA 172
# outer join ans <- carrierdest[DT, on = c("carrier","dest")] print(ans)
## carrier dest count dep_delay year month day arr_delay origin ## 1: AA DFW 5877 1498 2014 10 4 1494 EWR ## 2: AA BOS 1173 1241 2014 4 15 1223 JFK ## 3: AA DFW 5877 1071 2014 6 13 1064 EWR ## 4: AA DFW 5877 1056 2014 9 12 1115 EWR ## 5: AA DFW 5877 1022 2014 6 16 1073 EWR ## --- ## 253312: WN BNA NA -12 2014 3 9 -21 LGA ## 253313: WN MDW NA -13 2014 3 10 -18 EWR ## 253314: WN HOU NA -13 2014 5 17 -30 LGA ## 253315: WN MKE NA -13 2014 6 15 10 LGA ## 253316: WN CAK NA -13 2014 8 19 -30 LGA ## air_time distance hour sum_delay carrierm_mean_arr ## 1: 200 1372 7 2992 5.541959 ## 2: 39 NA 13 2464 1.903324 ## 3: 175 1372 10 2135 8.690067 ## 4: 198 1372 6 2171 -1.235160 ## 5: 178 1372 7 2095 8.690067 ## --- ## 253312: 115 764 16 -33 6.921642 ## 253313: 112 711 20 -31 6.921642 ## 253314: 202 1428 17 -43 22.875845 ## 253315: 101 738 20 -3 14.888889 ## 253316: 63 397 16 -43 7.219670 ## carrierm_mean_dep ## 1: 7.591497 ## 2: 3.987008 ## 3: 11.476475 ## 4: 3.307078 ## 5: 11.476475 ## --- ## 253312: 11.295709 ## 253313: 11.295709 ## 253314: 30.546453 ## 253315: 24.217560 ## 253316: 17.038047
# inner join ans <- DT[carrierdest, # for each row in carrierdest nomatch = 0L, # return only matching rows from both tables on = c("carrier","dest")] # joining on columns carrier and dest print(ans)
## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1071 2014 6 13 1064 EWR DFW 175 ## 3: AA 1056 2014 9 12 1115 EWR DFW 198 ## 4: AA 1022 2014 6 16 1073 EWR DFW 178 ## 5: AA 989 2014 6 11 991 EWR DFW 194 ## --- ## 23515: AA -8 2014 10 11 -13 JFK DCA 53 ## 23516: AA -9 2014 5 21 -12 JFK DCA 52 ## 23517: AA -9 2014 6 5 -6 JFK DCA 53 ## 23518: AA -9 2014 10 2 -21 JFK DCA 51 ## 23519: AA -11 2014 5 27 10 JFK DCA 55 ## distance hour sum_delay carrierm_mean_arr carrierm_mean_dep count ## 1: 1372 7 2992 5.541959 7.591497 5877 ## 2: 1372 10 2135 8.690067 11.476475 5877 ## 3: 1372 6 2171 -1.235160 3.307078 5877 ## 4: 1372 7 2095 8.690067 11.476475 5877 ## 5: 1372 11 1980 8.690067 11.476475 5877 ## --- ## 23515: NA 15 -21 5.541959 7.591497 172 ## 23516: NA 15 -21 4.150172 8.733665 172 ## 23517: NA 15 -15 8.690067 11.476475 172 ## 23518: NA 15 -30 5.541959 7.591497 172 ## 23519: NA 15 -1 4.150172 8.733665 172
Należy pamiętać, że ze względu na spójność z podstawowym podzbiorem R, sprzężenie zewnętrzne jest domyślnie RIGHT OUTER
. Jeśli szukamy LEFT OUTER
, musimy zamienić tabele, jak w powyższym przykładzie. Dokładne zachowanie można również łatwo kontrolować w metodzie merge
data.table
, używając tego samego interfejsu API, co base R merge
data.frame
.
Jeśli chcemy po prostu wyszukać kolumny w naszym zbiorze danych, możemy to zrobić wydajnie za pomocą operatora :=
w argumencie j
podczas łączenia. W ten sam sposób, w jaki przypisujemy przez odwołanie, jak opisano w sekcji Aktualizacja zestawu danych , właśnie teraz dodajemy kolumnę przez odwołanie z zestawu danych, do którego dołączamy. Pozwala to uniknąć kopii danych w pamięci, więc nie musimy przypisywać wyników do nowych zmiennych.
DT[carrierdest, # data.table to join with lkp.count := count, # lookup `count` column from `carrierdest` on = c("carrier","dest")] # join by columns head(DT)
## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1241 2014 4 15 1223 JFK BOS 39 ## 3: AA 1071 2014 6 13 1064 EWR DFW 175 ## 4: AA 1056 2014 9 12 1115 EWR DFW 198 ## 5: AA 1022 2014 6 16 1073 EWR DFW 178 ## 6: AA 989 2014 6 11 991 EWR DFW 194 ## distance hour sum_delay carrierm_mean_arr carrierm_mean_dep lkp.count ## 1: 1372 7 2992 5.541959 7.591497 5877 ## 2: NA 13 2464 1.903324 3.987008 1173 ## 3: 1372 10 2135 8.690067 11.476475 5877 ## 4: 1372 6 2171 -1.235160 3.307078 5877 ## 5: 1372 7 2095 8.690067 11.476475 5877 ## 6: 1372 11 1980 8.690067 11.476475 5877
Dla agregacji podczas łączenia użyj by = .EACHI
. Wykonuje sprzężenie, które nie zmaterializuje pośrednich wyników sprzężenia i zastosuje agregacje w locie, dzięki czemu jest wydajne w pamięci.
Rolling join to rzadko spotykana funkcja, przeznaczona do obsługi uporządkowanych danych. Idealnie nadaje się do przetwarzania danych czasowych i ogólnie szeregów czasowych. Zasadniczo przerzuca dopasowania w warunku dołączenia do następnej pasującej wartości. Użyj go, podając argument roll
podczas dołączania.
Szybkie łączenie nakładające się łączy zestawy danych na podstawie okresów i ich nakładania się obsługi przy użyciu różnych nakładających się operatorów: any
, within
, start
, end
.
Obecnie opracowywana jest funkcja łączenia nierównego do łączenia zbiorów danych przy użyciu warunku nierównego.
Profilowanie danych
Podczas eksploracji naszego zbioru danych czasami możemy chcieć zebrać informacje techniczne na ten temat, aby lepiej zrozumieć jakość danych.
Opisowe statystyki
summary(DT)
## carrier dep_delay year month ## Length:253316 Min. :-112.00 Min. :2014 Min. : 1.000 ## Class :character 1st Qu.: -5.00 1st Qu.:2014 1st Qu.: 3.000 ## Mode :character Median : -1.00 Median :2014 Median : 6.000 ## Mean : 12.47 Mean :2014 Mean : 5.639 ## 3rd Qu.: 11.00 3rd Qu.:2014 3rd Qu.: 8.000 ## Max. :1498.00 Max. :2014 Max. :10.000 ## ## day arr_delay origin dest ## Min. : 1.00 Min. :-112.000 Length:253316 Length:253316 ## 1st Qu.: 8.00 1st Qu.: -15.000 Class :character Class :character ## Median :16.00 Median : -4.000 Mode :character Mode :character ## Mean :15.89 Mean : 8.147 ## 3rd Qu.:23.00 3rd Qu.: 15.000 ## Max. :31.00 Max. :1494.000 ## ## air_time distance hour sum_delay ## Min. : 20.0 Min. : 80.0 Min. : 0.00 Min. :-224.00 ## 1st Qu.: 86.0 1st Qu.: 529.0 1st Qu.: 9.00 1st Qu.: -19.00 ## Median :134.0 Median : 762.0 Median :13.00 Median : -5.00 ## Mean :156.7 Mean : 950.4 Mean :13.06 Mean : 20.61 ## 3rd Qu.:199.0 3rd Qu.:1096.0 3rd Qu.:17.00 3rd Qu.: 23.00 ## Max. :706.0 Max. :4963.0 Max. :24.00 Max. :2992.00 ## NA's :81483 ## carrierm_mean_arr carrierm_mean_dep lkp.count ## Min. :-22.403 Min. :-4.500 Min. : 85 ## 1st Qu.: 2.676 1st Qu.: 7.815 1st Qu.:3449 ## Median : 6.404 Median :11.354 Median :5877 ## Mean : 8.147 Mean :12.465 Mean :4654 ## 3rd Qu.: 11.554 3rd Qu.:17.564 3rd Qu.:6058 ## Max. : 86.182 Max. :52.864 Max. :6058 ## NA's :229797
Kardynalność
Możemy sprawdzić unikalność danych za pomocą funkcji uniqueN
i zastosować ją na każdej kolumnie. Obiekt .SD
w poniższym zapytaniu odpowiada podzbiorowi tabeli danych:
DT[, lapply(.SD, uniqueN)]
## carrier dep_delay year month day arr_delay origin dest air_time ## 1: 14 570 1 10 31 616 3 109 509 ## distance hour sum_delay carrierm_mean_arr carrierm_mean_dep lkp.count ## 1: 152 25 1021 134 134 11
Stosunek NA
Aby obliczyć stosunek nieznanych wartości ( NA
w R i NULL
w SQL) dla każdej kolumny, podajemy żądaną funkcję do zastosowania w każdej kolumnie.
DT[, lapply(.SD, function(x) sum(is.na(x))/.N)]
## carrier dep_delay year month day arr_delay origin dest air_time ## 1: 0 0 0 0 0 0 0 0 0 ## distance hour sum_delay carrierm_mean_arr carrierm_mean_dep lkp.count ## 1: 0.3216654 0 0 0 0 0.9071555
Eksportowanie danych
Szybki eksport danych tabelarycznych do formatu CSV
zapewnia również pakiet data.table
.
tmp.csv <- tempfile(fileext=".csv") fwrite(DT, tmp.csv) # preview exported data cat(system(paste("head -3",tmp.csv), intern=TRUE), sep="\n")
## carrier,dep_delay,year,month,day,arr_delay,origin,dest,air_time,distance,hour,sum_delay,carrierm_mean_arr,carrierm_mean_dep,lkp.count ## AA,1498,2014,10,4,1494,EWR,DFW,200,1372,7,2992,5.54195933456561,7.59149722735674,5877 ## AA,1241,2014,4,15,1223,JFK,BOS,39,,13,2464,1.90332441727168,3.98700802445548,1173
W chwili pisania tego tekstu funkcja fwrite
nie została jeszcze opublikowana w repozytorium CRAN. Aby z niego skorzystać, musimy zainstalować wersję rozwojową data.table
, w przeciwnym razie możemy użyć podstawowej funkcji R write.csv
, ale nie oczekuj, że będzie szybka.
Zasoby
Dostępnych jest wiele zasobów. Oprócz podręczników dostępnych dla każdej funkcji, dostępne są również winiety pakietów, które są samouczkami skupionymi wokół konkretnego tematu. Można je znaleźć na stronie Pierwsze kroki. Dodatkowo strona Prezentacje zawiera ponad 30 materiałów (slajdy, wideo itp.) z prezentacji data.table
na całym świecie. Ponadto wsparcie społeczności rosło z biegiem lat, osiągając ostatnio 4000-te pytanie w tagu data.table
Stack Overflow, nadal mając wysoki wskaźnik (91,9%) odpowiedzi na pytania. Poniższy wykres przedstawia liczbę otagowanych pytań data.table
w Stack Overflow w czasie.
Streszczenie
Ten artykuł zawiera wybrane przykłady efektywnej transformacji danych tabelarycznych w języku R przy użyciu pakietu data.table
. Rzeczywiste dane dotyczące wydajności można sprawdzić, szukając powtarzalnych wzorców. Opublikowałem podsumowany wpis na blogu o rozwiązaniach data.table
dla 50 najczęściej ocenianych pytań StackOverflow dla języka R, zatytułowany Wydajne rozwiązywanie typowych problemów R za pomocą data.table, gdzie można znaleźć wiele liczb i powtarzalny kod. Pakiet data.table
wykorzystuje natywną implementację szybkiego porządkowania podstaw do operacji grupowania i binarnego wyszukiwania szybkich podzbiorów/połączeń. Ta kolejność podstaw została włączona do bazy R od wersji 3.3.0. Ponadto algorytm został niedawno zaimplementowany w platformie uczenia maszynowego H2O i zrównoleglony przez klaster H2O, umożliwiając wydajne, duże łączenia w wierszach 10B x 10B.