Moje pytanie dotyczy przydzielania zadań przez referencje a kopiowania data.table
. Chcę wiedzieć, czy można usuwać wiersze przez odniesienie, podobnie do
DT[ , someCol := NULL]
Chcę wiedzieć
DT[someRow := NULL, ]
Wydaje mi się, że istnieje dobry powód, dla którego ta funkcja nie istnieje, więc może po prostu możesz wskazać dobrą alternatywę dla zwykłego podejścia do kopiowania, jak poniżej. W szczególności idąc z moim ulubionym z przykładu (data.table),
DT = data.table(x = rep(c("a", "b", "c"), each = 3), y = c(1, 3, 6), v = 1:9)
# x y v
# [1,] a 1 1
# [2,] a 3 2
# [3,] a 6 3
# [4,] b 1 4
# [5,] b 3 5
# [6,] b 6 6
# [7,] c 1 7
# [8,] c 3 8
# [9,] c 6 9
Powiedzmy, że chcę usunąć pierwszy wiersz z tej tabeli data.table. Wiem, że potrafię to zrobić:
DT <- DT[-1, ]
ale często możemy chcieć tego uniknąć, ponieważ kopiujemy obiekt (a to wymaga około 3 * N pamięci, jeśli N object.size(DT)
, jak wskazano tutaj . Teraz znalazłem set(DT, i, j, value)
. Wiem, jak ustawić określone wartości (jak tutaj: ustaw wszystko wartości w wierszach 1 i 2 oraz kolumnach 2 i 3 do zera)
set(DT, 1:2, 2:3, 0)
DT
# x y v
# [1,] a 0 0
# [2,] a 0 0
# [3,] a 6 3
# [4,] b 1 4
# [5,] b 3 5
# [6,] b 6 6
# [7,] c 1 7
# [8,] c 3 8
# [9,] c 6 9
Ale jak mam usunąć, powiedzmy, pierwsze dwa wiersze? Robić
set(DT, 1:2, 1:3, NULL)
ustawia cały ID na NULL.
Moja znajomość SQL jest bardzo ograniczona, więc mówicie mi: podane dane. Tabela używa technologii SQL, czy istnieje odpowiednik polecenia SQL
DELETE FROM table_name
WHERE some_column=some_value
w data.table?
źródło
data.table()
wykorzystuje technologię SQL tak bardzo, jak można narysować paralelę między różnymi operacjami w SQL i różnymi argumentami w plikudata.table
. Dla mnie odniesienie do „technologii” w pewnym stopniu sugeruje, żedata.table
siedzi gdzieś na szczycie bazy danych SQL, czego AFAIK nie ma.DT[ , keep := .I > 1]
podzbioru dla późniejszych operacji:DT[(keep), ...]
być może nawetsetindex(DT, keep)
szybkości tego podzbioru. Nie jest to panaceum, ale warto rozważyć wybór projektu w swoim przepływie pracy - czy naprawdę chcesz usunąć wszystkie te wiersze z pamięci , czy wolisz je wykluczyć? Odpowiedź różni się w zależności od przypadku użycia.Odpowiedzi:
Dobre pytanie.
data.table
nie można jeszcze usunąć wierszy za pomocą odwołania.data.table
może dodawać i usuwać kolumny przez odniesienie, ponieważ jak wiesz, nadmiernie przydziela wektor wskaźników kolumn. Plan jest taki, aby zrobić coś podobnego dla rzędów i pozwolić na szybkieinsert
idelete
. Usunięcie wiersza spowoduje użyciememmove
w C do przesunięcia elementów (w każdej kolumnie) po usuniętych wierszach. Usunięcie wiersza w środku tabeli byłoby nadal dość nieefektywne w porównaniu z bazą danych magazynu wierszy, taką jak SQL, która jest bardziej odpowiednia do szybkiego wstawiania i usuwania wierszy, gdziekolwiek te wiersze znajdują się w tabeli. Mimo wszystko byłoby to dużo szybsze niż kopiowanie nowego dużego obiektu bez usuniętych wierszy.Z drugiej strony, ponieważ wektory kolumn byłyby nadmiernie alokowane, wiersze mogłyby być wstawiane (i usuwane) na końcu , natychmiast; np. rosnący szereg czasowy.
Został zgłoszony jako problem: Usuń wiersze przez odniesienie .
źródło
fread
pierwszy. Potem jest już dość wysoko.DT[b<8 & a>3]
zwraca nowy data.table. Chcielibyśmy dodaćdelete(DT, b>=8 | a<=3)
iDT[b>=8 | a<=8, .ROW:=NULL]
. Zaletą tego ostatniego byłoby połączenie z innymi cechami,[]
takimi jak numery wierszyi
, dołączaniei
iroll
czerpanie korzyści z[i,j,by]
optymalizacji.podejście, które obrałem, aby wykorzystanie pamięci było podobne do usuwania na miejscu, polega na podziale kolumny na raz i usuwaniu. nie tak szybko, jak właściwe rozwiązanie memmove w C, ale zależy mi tylko na wykorzystaniu pamięci. coś takiego:
źródło
memmove
zająć kilka sekund, aby usunąć luki, ale to jest w porządku.DT[, col:= NULL, with = F]
wset(DT, NULL, col, NULL)
Oto działająca funkcja oparta na odpowiedzi @ vc273 i opinii @ Franka.
I przykład jego zastosowania:
Gdzie „dat” to data.table. Usunięcie 14 tys. Wierszy z 1,4 mln wierszy zajmuje na moim laptopie 0,25 sekundy.
PS. Ponieważ jestem nowy w SO, nie mogłem dodać komentarza do wątku @ vc273 :-(
źródło
Zamiast tego lub próbując ustawić na NULL, spróbuj ustawić NA (pasujące do typu NA dla pierwszej kolumny)
źródło
Temat jest nadal interesujący dla wielu osób (w tym mnie).
Co z tym? Kiedyś
assign
zastępowałemglovalenv
i kod opisany wcześniej. Byłoby lepiej uchwycić oryginalne środowisko, ale przynajmniej wglobalenv
nim jest wydajne pamięć i działa jak zmiana przez odniesienie.źródło
address(DT); delete(DT, 3); address(DT)
), chociaż może być w pewnym sensie skuteczne.Oto kilka strategii, których użyłem. Myślę, że funkcja .ROW może się pojawić. Żadne z poniższych podejść nie jest szybkie. Oto kilka strategii wykraczających nieco poza podzbiory lub filtrowanie. Próbowałem myśleć jak dba, po prostu próbując wyczyścić dane. Jak wspomniano powyżej, możesz wybrać lub usunąć wiersze w data.table:
Uwaga: .SD tworzy podzbiór oryginalnych danych i pozwala na wykonanie dużej ilości pracy w j lub kolejnych data.table. Zobacz https://stackoverflow.com/a/47406952/305675 . Tutaj zamówiłem moje tęczówki według długości działki, weź określoną długość działki jako minimum, wybierz trzy pierwsze (według długości działki) wszystkich gatunków i zwróć wszystkie towarzyszące dane:
Podejścia przede wszystkim do zmiany kolejności data.table sekwencyjnie podczas usuwania wierszy. Możesz transponować dane.table i usunąć lub zastąpić stare wiersze, które są teraz transponowane jako kolumny. Gdy używasz „: = NULL” do usunięcia transponowanego wiersza, następna nazwa kolumny również jest usuwana:
Podczas transpozycji data.frame z powrotem do data.table, możesz chcieć zmienić nazwę z oryginalnego data.table i przywrócić atrybuty klasy w przypadku usunięcia. Zastosowanie „: = NULL” do transponowanego pliku data.table tworzy wszystkie klasy znaków.
Możesz po prostu usunąć zduplikowane wiersze, które możesz zrobić z kluczem lub bez:
Możliwe jest również dodanie licznika przyrostowego z „.I”. Następnie możesz wyszukać zduplikowane klucze lub pola i usunąć je, usuwając rekord z licznikiem. Jest to kosztowne obliczeniowo, ale ma pewne zalety, ponieważ można wydrukować linie do usunięcia.
Możesz również po prostu wypełnić wiersz 0 lub NA, a następnie użyć zapytania i, aby je usunąć:
źródło
t
na data.frame zwykle nie jest dobrym pomysłem; sprawdź,str(m_iris)
czy wszystkie dane stały się ciągiem / znakiem. Przy okazji, możesz również uzyskać numery wierszy, używającd_iris[duplicated(Key), which = TRUE]
bez tworzenia kolumny licznika.