Jaki jest cel ustawienia klucza w danych.stolik?

Używam danych.table i jest wiele funkcji, które wymagają od mnie ustawienia klucza (np. X[Y]). W związku z tym chciałbym zrozumieć, co robi klucz, aby prawidłowo ustawić klucze w moich tabelach danych.


Przeczytałem Jedno źródło ?setkey.

setkey() sortuje data.table i zaznacza jako posortowane. Kluczem są posortowane kolumny. Kluczem mogą być dowolne kolumny w dowolnej kolejności. Kolumny są zawsze sortowane w porządku rosnącym. Tabela jest zmieniana przez odniesienie. W ogóle nie wykonuje się kopii, inne niż tymczasowa pamięć robocza o wielkości jednej kolumny.

Moim zdaniem klucz "sortuje" dane.tabela, co daje bardzo podobny efekt do order(). Nie wyjaśnia to jednak celu posiadania klucza.


Dane.tabela FAQ 3.2 i 3.3 wyjaśnia:

3.2 nie mam klucza na dużym stole, ale grupowanie jest nadal bardzo szybkie. Dlaczego?

Data.tabela wykorzystuje sortowanie radix. Jest to znacznie szybsze niż inne Sortuj algorytmy. Radix jest tylko dla liczb całkowitych, zobacz ?base::sort.list(x,method="radix"). Jest to również jeden z powodów, dla których Jest szybki. Gdy nie ma ustawionego klucza lub grupujemy w innej kolejności od klucza nazywamy go ad hoc by.

3.3 dlaczego Grupowanie według kolumn w kluczu jest szybsze niż ad hoc przez?

Ponieważ każda grupa jest sąsiadująca w pamięci RAM, co minimalizuje stronę pobiera, a pamięć może być kopiowana luzem (memcpy W C), a nie zapętlenie w C.

Stąd chyba to ustawienie klucza w jakiś sposób pozwala R używać "sortowania radix" nad innymi algorytmami i dlatego jest szybsze.


The 10 minute quick start guide ma również przewodnik po klawiszach.

  1. Klucze

Zacznijmy od rozważenia danych.ramki, konkretnie rownolegle (lub w Angielski, nazwy rzędów). Czyli wielokrotne nazwy należące do jednego wiosłować. Wielokrotne nazwiska należące do jednego rzędu? To nie jest to, co jesteśmy przyzwyczajeni do danych.rama. Wiemy, że każdy rząd ma co najwyżej jeden nazwisko. Osoba ma co najmniej dwa nazwiska, pierwsze imię i drugie imię. Przydatne jest np. zorganizowanie książki telefonicznej, która jest posortowane według nazwiska, a następnie pierwszego imienia. Jednak każdy wiersz w data.ramka może mieć tylko jedną nazwę.

Klucz składa się z jednego lub więcej kolumny nazw wierszy, które mogą być integer, factor, character lub niektóre inna klasa, nie zwykły charakter. Ponadto wiersze są sortowane według klucz. Dlatego dane.puszka stołowa mieć co najwyżej jeden klucz, bo to nie można sortować w więcej niż jeden sposób.

Wyjątkowość nie jest egzekwowana, np. dozwolone są zduplikowane wartości klucza. Ponieważ wiersze są sortowane według klucz, wszelkie duplikaty w kluczu pojawią się kolejno

Książka telefoniczna była pomocna w zrozumieniu, czym jest klucz, ale wydaje się, że klucz nie różni się od Kolumny czynnika. Co więcej, nie wyjaśnia, dlaczego potrzebny jest klucz (zwłaszcza do użycia pewnych funkcje) i jak wybrać kolumnę do Ustawienia jako klucz. Ponadto, wydaje się, że w danych.tabela z czasem jako kolumną, ustawienie dowolnej innej kolumny jako klucza prawdopodobnie spowoduje również bałagan w kolumnie czasu, co sprawia, że jest jeszcze bardziej mylące, ponieważ Nie wiem, czy mogę ustawić dowolną inną kolumnę jako klucz. Czy ktoś może mnie oświecić?

Author: Arun, 2013-11-18

2 answers

mała aktualizacja: prosimy o zapoznanie się również z nowymi winietami HTML . ten numer podkreśla inne winiety, które planujemy.


Ponownie zaktualizowałem tę odpowiedź (Luty 2016) w świetle nowej funkcji on=, która pozwala ad-hoc dołączać również. Zobacz historię wcześniejszych (nieaktualnych) odpowiedzi.

Co dokładnie robi setkey(DT, a, b)?

Robi dwie rzeczy:

  1. zmienia kolejność wierszy danych .tabela DT przez podaną kolumnę (a, b) przez odniesienie , zawsze w rosnącym porządku.
  2. oznacza te kolumny jako klucz kolumny, ustawiając atrybut o nazwie sorted na DT.

Zmiana kolejności jest szybka (ze względu na Dane.table's internal radix sorting) oraz memory efficient (przydzielana jest tylko jedna dodatkowa kolumna typu double ).

Kiedy jest wymagane setkey()?

Do grupowania operacje, setkey() nigdy nie było absolutnym wymogiem. Oznacza to, że możemy wykonać cold-by lub adhoc-by.

## "cold" by
require(data.table)
DT <- data.table(x=rep(1:5, each=2), y=1:10)
DT[, mean(y), by=x] # no key is set, order of groups preserved in result

Jednak przed v1.9.6 dołączenie formularza x[i] wymagało key aby było ustawione na x. z nowym argumentem on= z v1.9.6+, nie jest to już prawdą, dlatego ustawienie klawiszy nie jest bezwzględnym wymogiem również tutaj.

## joins using < v1.9.6 
setkey(X, a) # absolutely required
setkey(Y, a) # not absolutely required as long as 'a' is the first column
X[Y]

## joins using v1.9.6+
X[Y, on="a"]
# or if the column names are x_a and y_a respectively
X[Y, on=c("x_a" = "y_a")]

Zauważ, że argument on= może być jawnie podany nawet dla keyed jako cóż.

Jedyną operacją wymagającą bezwzględnego ustawienia key jest funkcja foverlaps(). Ale pracujemy nad kilkoma dodatkowymi funkcjami, które po wykonaniu usuną ten wymóg.

  • Jaki jest powód implementacji argumentu on=?

    Jest kilka powodów.
    1. Pozwala to wyraźnie odróżnić operację jako operację obejmującą dwa Dane.tabele . Just Robienie X[Y] również tego nie rozróżnia, chociaż może to być jasne poprzez odpowiednie nazwanie zmiennych.

    2. Pozwala również zrozumieć kolumny, na których join/podzbiór jest wykonywany natychmiast, patrząc na tę linijkę kodu (i nie ma konieczności śledzenia odpowiedniej linii setkey()).

    3. W operacjach, w których kolumny są dodawane lub aktualizowane przez odniesienie, on= operacje są znacznie bardziej wydajne, ponieważ nie potrzebuję wszystkich danych.Zmiana kolejności tabeli tylko w celu dodania / aktualizacji kolumn. Na przykład,

      ## compare 
      setkey(X, a, b) # why physically reorder X to just add/update a column?
      X[Y, col := i.val]
      
      ## to
      X[Y, col := i.val, on=c("a", "b")]
      
      W drugim przypadku nie musieliśmy zmieniać kolejności. To nie jest obliczanie kolejności, która jest czasochłonna, ale fizycznie Zmiana kolejności danych.tabeli w pamięci RAM, a unikając jej, zachowujemy pierwotną kolejność, a także
    4. Nawet w przeciwnym razie, chyba że wykonujesz połączenia powtarzalnie, nie powinna być zauważalna różnica wydajności między keyed and ad-hoc joins.

To prowadzi do pytania, jaka przewaga ma keying a danych.table have anymore?
  • Czy jest zaleta keying danych.stolik?

    Keying a data.table fizycznie zmienia kolejność na podstawie tych kolumn w pamięci RAM. Obliczanie kolejności zwykle nie jest czasochłonną częścią, raczej Zmiana kolejności. Jednak gdy już mamy dane sortowane w pamięci RAM, wiersze należące do tej samej grupy są sąsiadujące ze sobą w pamięci RAM i dlatego są bardzo wydajne w pamięci podręcznej. To sortowanie przyspiesza operacje na danych z kluczem.stoły.

    Dlatego ważne jest, aby dowiedzieć się, czy czas spędzony na zmianę kolejności całych danych.tabela jest warta czasu, aby wykonać efektywne łączenie/agregację pamięci podręcznej. Zazwyczaj, o ile nie są wykonywane powtarzające się operacje grupowania / łączenia na tych samych danych Z kluczem.tabela, nie powinno być zauważalna różnica.

W większości przypadków nie powinno być już potrzeby ustawiania kluczy. Zalecamy używanie on= tam, gdzie jest to możliwe, chyba że ustawienie klawisza znacząco poprawi wydajność, którą chcesz wykorzystać.

Pytanie: jak myślisz, jak wyglądałaby wydajność w porównaniu do keyed join, jeśli użyjesz setorder()do zmiany kolejności danych .table and use on=? Jeśli do tej pory, powinieneś być w stanie to rozgryźć :-).

 102
Author: Arun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:30

Klucz jest w zasadzie indeksem do zbioru danych, który pozwala na bardzo szybkie i wydajne operacje sortowania, filtrowania i łączenia. Są to prawdopodobnie najlepsze powody, aby używać tabel danych zamiast ramek danych (składnia korzystania z tabel danych jest również znacznie bardziej przyjazna dla użytkownika, ale nie ma to nic wspólnego z kluczami).

Jeśli nie rozumiesz indeksów, rozważ to: książka telefoniczna jest "indeksowana" według nazwy. Więc jeśli chcę sprawdzić czyjś numer telefonu, to całkiem proste. Ale przypuśćmy, że chcesz wyszukać według numeru telefonu (np. sprawdzić, kto ma konkretny numer telefonu)? Jeśli nie mogę" ponownie indeksować " książki telefonicznej według numeru telefonu, zajmie to bardzo dużo czasu.

Rozważ następujący przykład: załóżmy, że mam tabelę, ZIP, wszystkich kodów pocztowych w USA (>33,000) wraz z powiązanymi informacjami (miasto, stan, ludność, mediana dochodów itp.). Jeśli chcę wyszukać informacje o konkretnym kodzie pocztowym, wyszukiwanie (filtr) jest około 1000 razy szybsze, jeśli setkey(ZIP,zipcode) najpierw.

Kolejna korzyść ma związek z połączeniami. Załóżmy, że A ma listę osób i ich kodów pocztowych w tabeli danych (nazwij to "PPL"), I chcę dołączyć informacje z tabeli ZIP (np. miasto, stan, i tak dalej). Zrobi to następujący kod:

setkey(ZIP,zipcode)
setkey(PPL,zipcode)
full.info <- PPL[ZIP, nomatch=F]

Jest to "join" w tym sensie, że dołączam informacje z tabel 2 opartych na wspólnym polu (Kod zipcode). Takie połączenia na bardzo dużych tabelach są niezwykle powolne w przypadku ramek danych i niezwykle szybkie w przypadku tabel danych. W prawdziwy przykład, że musiałem zrobić więcej niż 20,000 takich połączeń na pełnej tabeli kodów pocztowych. Z tabelami danych skrypt trwał około 20 min. biegać. Nawet nie próbowałem z ramkami danych, ponieważ zajęłoby to więcej niż 2 tygodnie.

IMHO nie powinieneś tylko czytać, ale przestudiować FAQ i wstęp. Jest to łatwiejsze do uchwycenia, jeśli masz rzeczywisty problem, Aby zastosować to.

[odpowiedź na komentarz Franka]

Re: sortowanie a indeksowanie - na podstawie odpowiedź na to pytanie, wygląda na to, że setkey(...) w rzeczywistości zmienia kolejność kolumn w tabeli (np. rodzaj fizyczny) i nie tworzy indeksu w sensie bazy danych. Ma to pewne praktyczne implikacje: po pierwsze, jeśli ustawisz klucz w tabeli za pomocą setkey(...), a następnie zmienisz dowolną wartość w kolumnie key, data.table po prostu deklaruje, że tabela nie będzie już sortowana( wyłączając atrybut sorted); robi , a nie dynamicznie ponownie indeksuje, aby utrzymać prawidłowa kolejność sortowania (tak jak w bazie danych). Ponadto "usunięcie klucza" za pomocą setky(DT,NULL) powoduje , a nie przywrócenie tabeli do pierwotnej, niesortowanej kolejności.

Re: filter vs. join - praktyczna różnica polega na tym, że filtrowanie wyodrębnia podzbiór z pojedynczego zbioru danych, podczas gdy join łączy dane z dwóch zbiorów danych opartych na wspólnym polu. Istnieje wiele różnych rodzajów łączenia (wewnętrzne, zewnętrzne, lewe). Powyższy przykład to połączenie wewnętrzne (tylko rekordy z kluczami wspólnymi dla obu zwracane są tabele), a to ma wiele podobieństw do filtrowania.

 17
Author: jlhoward,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:34