2016-08-30 42 views
5

Jestem samoukiem w R i to jest moje pierwsze pytanie StackOverflow. Przepraszam, jeśli to jest oczywisty problem; Proszę bądź uprzejmy.Powtórzyć mutację zmiennej przy użyciu dplyr i purrr

wersja skrócona moje pytanie
napisałem funkcję niestandardową obliczyć procentową zmianę w zmiennej roku na rok. Chciałbym użyć funkcji purrr 'map_at, aby zastosować moją funkcję niestandardową do wektora nazw zmiennych. Mój zwyczaj funkcja działa po nałożeniu jednej zmiennej, ale nie powiedzie się, gdy łańcuch jest używany map_a

mój zwyczaj funkcja

calculate_delta <- function(df, col) { 

    #generate variable name 
    newcolname = paste("d", col, sep="") 

    #get formula for first difference. 
    calculate_diff <- lazyeval::interp(~(a + lag(a))/a, a = as.name(col)) 

    #pass formula to mutate, name new variable the columname generated above 
    df %>% 
     mutate_(.dots = setNames(list(calculate_diff), newcolname)) } 

Kiedy zastosować tę funkcję do pojedynczej zmiennej w zbiorze mtcars The wyjście jest zgodne z oczekiwaniami (chociaż oczywiście znaczenie wyniku nie ma sensu).

calculate_delta(mtcars, "wt") 

Próbowano zastosować funkcję do postaci wektorowej Korzystanie Purrr

myślę, że mam problemy konceptualizacji jak map_at przechodzi argumentów do funkcji. Wszystkie przykładowe fragmenty, które mogę znaleźć w Internecie, używają map_at z funkcjami takimi jak is.character, które nie wymagają dodatkowych argumentów. Oto moje próby zastosowania funkcji przy użyciu purrr.

vars <- c("wt", "mpg") 
mtcars %>% map_at(vars, calculate_delta) 

To daje mi ten komunikat o błędzie

Error in paste("d", col, sep = "") : argument "col" is missing, with no default

zakładam to dlatego map_at przechodzi vars jako df, a nie przekazując argument dla col. Aby obejść ten problem, próbowałem następujące:

vars <- c("wt", "mpg") 
mtcars %>% map_at(vars, calculate_delta, df = .) 

To rzuca mi ten błąd:

Error: unrecognised index type 

Mam monkeyed dokoła z gronem różnych wersjach, w tym usunięcie df argumentu z calculate_delta Funkcja, ale nie miałem szczęścia.

innych możliwych rozwiązań

1) Wersja z użyciem sapply, zamiast purrr. Próbowałem rozwiązać problem w ten sposób i miałem podobne problemy. Moim celem jest znalezienie sposobu na zrobienie tego za pomocą purrr, jeśli to możliwe. W oparciu o moje zrozumienie purrr wydaje się, że jest to typowy przypadek użycia.

2) Mogę oczywiście wymyślić, jak zaimplementowałem to za pomocą pętli for, ale staram się tego uniknąć, jeśli to możliwe z podobnych powodów.

Najwyraźniej myślę o tym źle. Proszę pomóż!

EDIT 1

Aby wyjaśnić, jestem ciekaw, czy istnieje metoda wielokrotnie transformacji zmiennych, które realizuje dwie rzeczy.

1) Generuje nowe zmienne w oryginalnym numerze tbl_df bez zastępowania kolumn zamienianych (tak jak w przypadku korzystania z dplyr z mutate_at).

2) Automatycznie generuje nowe etykiety zmiennych.

3) Jeśli to możliwe, wykonaj to, co opisałem, stosując jedną funkcję, używając map_at.

Możliwe, że nie jest to możliwe, ale wydaje mi się, że powinien istnieć elegancki sposób na osiągnięcie tego, co opisuję.

+2

Twoja funkcja nie jest gotowa do umieszczenia w strukturze "mutate" lub podobnej. Spróbuj 'mtcars%>% mutate (calcul_delta (wt))', aby zobaczyć, że nawet bez 'purrr' lub' map' nie działa. Jeśli nie działa z normalnym wywołaniem 'dplyr', to nie zadziała w tej strukturze. Powinien zostać ponownie napisany. Możesz zacząć od usunięcia konieczności specyfikacji ramki danych. Pomyśl o tym, jak "suma" lub "średnia" nie wymagają ramek danych w ramach połączenia, są zbudowane dla wektorów. –

+0

Dziękujemy, jest to pomocny sposób na przemyślenie tego problemu. Ta funkcja, z @PierreLafortune poniżej, działa jako część wywołania mutacji dplyr: 'delta <- funkcja (x) (x + dplyr :: lag (x))/x' i działa również z' purrr'. Jak już wspomniałem, część, która mnie wyzwala, dynamicznie zmienia nazwę zmiennych. –

Odpowiedz

9

Spróbuj uproszczenie procesu:

delta <- function(x) (x + dplyr::lag(x)) /x 
cols <- c("wt", "mpg") 

#This 
library(dplyr) 
mtcars %>% mutate_at(cols, delta) 
#Or 
library(purrr) 
mtcars %>% map_at(cols, delta) 

#If necessary, in a function 
f <- function(df, cols) { 
    df %>% mutate_at(cols, delta) 
} 

f(iris, c("Sepal.Width", "Petal.Length")) 
f(mtcars, c("wt", "mpg")) 

Edycja

Jeśli chcesz po osadzić nowe nazwy, możemy napisać niestandardowy rur gotowy funkcję:

Rename <- function(object, old, new) { 
    names(object)[names(object) %in% old] <- new 
    object 
} 

mtcars %>% 
    mutate_at(cols, delta) %>% 
    Rename(cols, paste0("lagged",cols)) 

Jeśli chcesz zmienić nazwę wynikowych zmiennych opóźnionych:

mtcars %>% mutate_at(cols, funs(lagged = delta)) 
+0

Dziękuję za odpowiedź. Rozwiązania te w większości dają wynik, którego szukam, ale robią to, zastępując oryginalne zmienne zmienną opóźnioną. [Ten post] (http://stackoverflow.com/questions/38340180/automatically-generate-new-variable-names-using-dplyr-mutate) pokazuje jeden sposób dynamicznej zmiany nazwy zmiennej w 'mutate_each', ale mogę ' t przekazać wektor znaków jako argument do 'vars'. –

+0

Nie trzeba dynamicznie zmieniać nazwy. Po prostu zmień nazwę po. Lub jeśli potrzebujesz go w rurze, napisz niestandardową funkcję. –

+0

Jeszcze raz dziękuję, Pierre. Opisana metoda ma tę wadę, że zastępuje zmienne zmutowane zmiennymi opóźnionymi. Jak opisuję w "Edit 1" mojego oryginalnego posta, moim celem jest zastosowanie tej funkcji bez zastępowania oryginalnych zmiennych i dynamiczne generowanie nazw w jednym kroku. –