Wiem, że jest tu kilka podobnych pytań, ale wydaje się, że żadne z nich nie odnosi się do konkretnego problemu, który mam.
set.seed(4)
df = data.frame(
Key = c("A", "B", "A", "D", "A"),
Val1 = rnorm(5),
Val2 = runif(5),
Val3 = 1:5
)
Chcę zerować wartości kolumn wartości dla wierszy, w których Key == "A" Do nazw kolumn odwołuje się grep
:
cols = grep("Val", names(df), value = TRUE)
Zwykle, aby osiągnąć to, co chcę w tym przypadku, użyłbym data.table
tak:
library(data.table)
df = as.data.table(df)
df[Key == "A", (cols) := 0]
A pożądany wynik jest następujący:
Key Val1 Val2 Val3
1 A 0.000000 0.00000000 0
2 B -1.383814 0.55925762 2
3 A 0.000000 0.00000000 0
4 D 1.437151 0.05632773 4
5 A 0.000000 0.00000000 0
Jednak tym razem muszę go wykorzystać dplyr
, pracując nad projektem zespołowym, w którym wszyscy go używają. Przedstawione przeze mnie dane mają charakter poglądowy, a moje rzeczywiste dane to> 5 m wierszy z 16 kolumnami wartości do aktualizacji. Jedyne rozwiązanie, jakie mogłem wymyślić, to mutate_at
takie:
df %>% mutate_at(.vars = vars(cols), .funs = function(x) ifelse(df$Key == "A", 0, x))
Wydaje się jednak, że tak bardzo powolne w przypadku moich prawdziwych danych. Miałem nadzieję znaleźć rozwiązanie, które byłoby bardziej eleganckie i, co ważniejsze, szybsze.
Próbowałem wielu kombinacji przy użyciu map
, bez cytowania przy użyciu !!
, przy użyciu get
i :=
(które irytujące mogą zostać zamaskowane :=
w tabeli data.tab) itp., Ale myślę, że moje rozumienie tego, jak te prace nie są po prostu wystarczająco głębokie, aby stworzyć prawidłowe rozwiązanie.
źródło
Odpowiedzi:
Za pomocą tego polecenia dplyr
Rzeczywiście oceniasz wyrażenie df $ Key == "A", n razy, gdzie n = liczba kolumn, które masz.
Jednym z obejść jest wstępne zdefiniowanie wierszy, które chcesz zmienić:
Czystszym i lepszym sposobem, poprawnie wskazanym przez @IceCreamToucan (patrz komentarze poniżej), jest użycie funkcji replace, z jednoczesnym przekazaniem jej dodatkowych parametrów:
Możemy przetestować wszystkie te podejścia i uważam, że dplyr i data.table są porównywalne.
źródło
df %>% mutate_at(vars(contains('Val')), replace, df$Key == 'A', 0)
replace
metoda jest nieco wolniejsza niż oryginalnaidx
.dplyr::if_else()
jest szybszy niż bazaifelse()
.