2016-02-12 11 views
8

Nie wiesz, jak sformułować pytanie w słowach, ale jak utworzyć kolumnę indeksową dla tabeli data.table, która dla każdej grupy rośnie, gdy pojawia się inna wartość?Indeksuj unikatowe wartości w data.table

Oto MWE

library(data.table) 
in.data <- data.table(fruits=c(rep("banana", 4), rep("pear", 5)),vendor=c("a", "b", "b", "c", "d", "d", "e", "f", "f")) 

Oto wynik R-kod powinien generować

in.data[, wanted.column:=c(1,2,2,3,1,1,2,3,3)] 

# fruits vendor wanted.column 
# 1: banana  a    1 
# 2: banana  b    2 
# 3: banana  b    2 
# 4: banana  c    3 
# 5: pear  d    1 
# 6: pear  d    1 
# 7: pear  e    2 
# 8: pear  f    3 
# 9: pear  f    3 

więc etykiety każdy sprzedawca 1, 2, 3, ... w ramach każdego owocu. Prawdopodobnie istnieje bardzo proste rozwiązanie, ale utknąłem.

+1

Zadziałało! Dodałem go w ten sposób: in.data [, wanted.2: = in.data [, rleid (vendor), by = fruits] [, V1]]. Może możesz napisać odpowiedź, abym mógł ją zaakceptować? – Chris

Odpowiedz

9

Mam kilka pomysłów. Można użyć zagnieżdżonego licznika Grupa:

in.data[, w := setDT(list(v = vendor))[, g := .GRP, by=v]$g, by=fruits] 

Alternatywnie, zrób Bieg ID, która zależy od danych segregowanych (dzięki @eddi) i wydaje się marnotrawstwem:

in.data[, w := rleid(vendor), by=fruits] 

Podejście base-R prawdopodobnie być:

in.data[, w := match(vendor, unique(vendor)), by=fruits] 

# or in base R ... 

in.data$w = with(in.data, ave(vendor, fruits, FUN = function(x) match(x, unique(x)))) 
+1

Dzięki! Nigdy nie byłbym w stanie rozwiązać tego samodzielnie. – Chris

+1

Warto zauważyć, że pierwsza i druga opcja dają różne wyniki, np. 'in.data [6, sprzedawca: = 'f']'. Nie jestem pewien, który z nich jest pożądany. – eddi

+0

Dobra uwaga; dzięki @eddi – Frank

8

Innym rozwiązaniem mogłoby być dwa kroki:

DT = data.table(fruits=c(rep("banana", 4), rep("pear", 5)),vendor=c("a", "b", "b", "c", "d", "d", "e", "f", "f")) 
DT 
    fruits vendor 
1: banana  a 
2: banana  b 
3: banana  b 
4: banana  c 
5: pear  d 
6: pear  d 
7: pear  e 
8: pear  f 
9: pear  f 
DT[, wanted:=.GRP, by="fruits,vendor"] # step 1 
DT 
    fruits vendor wanted 
1: banana  a  1 
2: banana  b  2 
3: banana  b  2 
4: banana  c  3 
5: pear  d  4 
6: pear  d  4 
7: pear  e  5 
8: pear  f  6 
9: pear  f  6 
DT[, wanted:=wanted-wanted[1]+1L, by="fruits"] # step 2 (adjust) 
DT 
    fruits vendor wanted 
1: banana  a  1 
2: banana  b  2 
3: banana  b  2 
4: banana  c  3 
5: pear  d  1 
6: pear  d  1 
7: pear  e  2 
8: pear  f  3 
9: pear  f  3 
> 

Sposób Chciałbym skomentować to w kodzie produkcyjnym może być:

DT[, wanted:=.GRP, by="fruits,vendor"]   # .GRP is simple group counter 
DT[, wanted:=wanted-wanted[1]+1L, by="fruits"] # reset vendor counter per fruit 
+0

Dzięki. Używam R w produkcji, więc dziękuję za przykład. data.table nadal jest dla mnie magią, ale mam nadzieję, że w końcu ją zrozumiem. – Chris

+1

@Chris Cieszę się, że słyszę. Wygląda na to, że się tam dostałeś. Miło widzieć dobre MRE. –

+2

@Chris Chociaż twój MRE pozostawił pewne aspekty niejednoznaczne, co spowodowało zamieszanie. MRE mogłoby być lepsze, włączając grupy, które nie sąsiadują ze sobą i stwierdzając, jaki jest pożądany rezultat. –

4

Jeśli indeks ma być samo dla wszystkich sprzedawców w ramach danego owocu, to jest inna opcja:

in.data[, wanted := as.integer(factor(vendor, levels = unique(vendor))), by = fruits] 

W przeciwnym razie, jeśli chcesz, aby odznaczał się za każdym razem, gdy zmienia się sprzedawca, to z dotychczasowych odpowiedzi tylko rleid działa.