2017-01-21 12 views
5

Próbuję dokonać podzbioru zbioru danych, wybierając niektóre kolumny z tabeli data.table. Jednak mój kod nie działa z niektórymi odmianami.Podział kolumn z data.table w R

Oto próbka data.table

library(data.table) 
DT <- data.table(ID = 1:50, 
      Capacity = sample(100:1000, size = 50, replace = F), 
      Code = sample(LETTERS[1:4], 50, replace = T), 
      State = rep(c("Alabama","Indiana","Texas","Nevada"), 50)) 

Oto kod podgrupa robocza:

DT[,1:2] 

A oto kawałek kodu, który nie działa. Zauważ, że działa to z ramką danych, ale nie z tabelą data.table.

DT[,seq(1:2)] 

muszę coś na wzór drugiego formatu, bo jestem podzbiorów oparty na wyjściu (grep) i to daje taki sam efekt jak w drugim formacie. Co robię nieprawidłowo?

Dzięki!

+0

Używanie 'with = FALSE' powoduje, że drugi działa, ale nie wiem, dlaczego to nie działa. –

+2

@RichScriven dzięki za wskazówkę! Używając tego, wykopałem głębiej za pomocą? Data.table. Ta linia wydaje się wskazywać, dlaczego. "Gdy dla = FALSE, j może być tylko wektorem nazw kolumn lub pozycji do wyboru (jak w data.frame).". – Naumz

+0

@RichScriven patrz [odpowiedź poniżej] (http://stackoverflow.com/a/41781264/2761575) dlaczego ':' działa ale 'seq' nie – dww

Odpowiedz

3

W ostatnich wersjach data.table, numery mogą być wykorzystywane w celu j określ kolumny. To zachowanie obejmuje formaty takie jak DT[,1:2], aby określić zakres liczb kolumn. (Zauważ, że ta składnia nie działa w starszych wersjach data.table).

Dlaczego więc DT[,1:2] działa, ale DT[,seq(1:2)] nie?Odpowiedź jest pochowany w kodzie dla data.table:::[.data.table, który zawiera wiersze:

if (!missing(j)) { 
    jsub = replace_dot_alias(substitute(j)) 
    root = if (is.call(jsub)) 
     as.character(jsub[[1L]])[1L] 
    else "" 
    if (root == ":" || (root %chin% c("-", "!") && is.call(jsub[[2L]]) && 
     jsub[[2L]][[1L]] == "(" && is.call(jsub[[2L]][[2L]]) && 
     jsub[[2L]][[2L]][[1L]] == ":") || (!length(all.vars(jsub)) && 
      root %chin% c("", "c", "paste", "paste0", "-", "!") && 
      missing(by))) { 
     with = FALSE 
    } 

Widzimy tutaj, że data.table jest automatycznie ustawienie parametru with = FALSE dla Ciebie, gdy wykryje użycie funkcji : w j. Nie ma tej samej funkcjonalności wbudowanej dla seq, więc musimy sami określić za pomocą = FALSE, jeśli chcemy użyć składni seq.

DT[,seq(1:2), with=FALSE] 
+0

Myślę, że byłoby bardziej pomocne skierowanie OP i innych czytelników (takich jak ja) do odpowiedniego miejsca w dokumentach i/lub WIADOMOŚCIACH. – Frank

+0

@Frank Nie jestem pewien, czy jest to faktycznie udokumentowane w dowolnym miejscu. Musiałem zajrzeć do kodu źródłowego, aby znaleźć powód .... – dww

+1

Artykuł 3 w wydaniu 1.9.8 obejmuje go. Właśnie założyłem, że oni zaktualizowali dokumenty, aby odzwierciedlić zmianę: https://github.com/Rdatatable/data.table/blob/master/NEWS.md#changes-in-v198--on-cran-25-nov-2016 – Frank

3

Głównym problemem jest to, że kolumny w data.table są obiektami referencyjnymi, więc nie można używać tej samej składni co data.frame. tj. brak cytowanych nazw lub numerów

, więc DT[,c("ID", "Capacity")] nie będzie działać z tego samego powodu, dla którego DT[,seq(1:2)] nie będzie działać.

Jednak dodanie ,with=FALSE powoduje data.table pracować odwoływać jako data.frame byłoby

tak DT[,c("ID", "Capacity"), with=FALSE] I DT[,seq(1:2), with=FALSE] teraz dać ci to, co chcesz.

 ID Capacity 
    1: 1  913 
    2: 2  602 
    3: 3  861 
    4: 4  967 
    5: 5  374 
---    
196: 46  163 
197: 47  254 
198: 48  390 
199: 49  853 
200: 50  486 

EDIT: jak podkreślił @Rich Scriven

+0

Dziękujemy! Pytanie jednak. Czy seq (1: 2) nie jest taki sam jak 1: 2 dla podzbioru? Jestem ciekawy, bo jeden działa, a drugi nie. – Naumz

+0

szczerze nie do końca jestem pewien, na czym polega różnica. Nie wiem też, dlaczego 1: 2 zadziałało dla ciebie, ponieważ to nie działa dla mnie. Tak czy inaczej używanie za pomocą = FALSE razem z grep zgodnie z twoim zamierzeniem działa poprawnie. – JustGettinStarted

+1

'DT [, c (" ID "," Pojemność ")]' działa z najnowszą wersją data.table. Podobnie jak "DT [, 1: 2]", dlatego też byłem zaskoczony, że 'DT [, seq (1, 2)]' nie działa. –

5

Lekcja dowiedziałem jest użycie list zamiast c:

DT[ ,list(ID,Capacity)] 
#--------------------------- 
    ID Capacity 
    1: 1  483 
    2: 2  703 
    3: 3  924 
    4: 4  267 
    5: 5  588 
---    
196: 46  761 
197: 47  584 
198: 48  402 
199: 49  416 
200: 50  130 

Pozwala zignorować te brzydkie cytaty, a także przesuwa cię w kierunku wyświetlania argumentu j jako ewaluowanego wyrażenia ze środowiskiem samego elementu datatable.

Aby "uzyskać" nazwane kolumny według numerów, należy użyć funkcji mget i funkcji . R 'names' są elementami języka, tj. Obiektami danych w ścieżce wyszukiwania z bieżącego środowiska. Nazwy słupów ramek danych nie są w rzeczywistości R names. Potrzebujesz funkcji, która przyjmie wartość znakową i spowoduje, że tłumacz uzna ją za w pełni kwalifikowaną name. DataTable - [- Funkcja Składnia elementu j radzi sobie nazwy kolumn jako język obiektów zamiast wartości znakowych, jak miałby [.data.frame -function:

DT[ ,mget(names(DT)[c(1,2)])] 
    ID Capacity 
    1: 1  483 
    2: 2  703 
    3: 3  924 
    4: 4  267 
    5: 5  588 
---    
196: 46  761 
197: 47  584 
198: 48  402 
199: 49  416 
200: 50  130 
+0

Ja też lubię "listę", to tylko jeśli OP planuje wybór kolumn z grep, sugerowałem z = FALSE może być więcej zgodny z tym. Ale lista na pewno przechwytuje znaczenie data.table lepiej – JustGettinStarted

+0

@ 42-, dziękuję za odpowiedź! Korzystając z podejścia do listy, w jaki sposób uzyskać dostęp do kolumn według ich indeksów, w przeciwieństwie do nazw? DT [, list (c (1,2))] również nie działa. – Naumz

+1

c (1,2) nie ocenia niczego użytecznego. Potrafi również "odwzorować" wartość "języka" na "get" lub "mget". Patrz wyżej. –