Apply list of functions to list of values

W odniesieniu do to pytanie, próbowałem wymyślić najprostszy sposób, aby zastosować listę funkcji do listy wartości. Zasadniczo zagnieżdżone lapply. Na przykład stosujemy sd i mean do wbudowanego zbioru danych trees:

funs <- list(sd=sd, mean=mean)
sapply(funs, function(x) sapply(trees, x))

Aby uzyskać:

              sd     mean
Girth   3.138139 13.24839
Height  6.371813 76.00000
Volume 16.437846 30.17097

Ale miałem nadzieję uniknąć wewnętrznego function i mieć coś w stylu:

sapply(funs, sapply, X=trees)

Co nie działa, ponieważ X pasuje do pierwszego sapply zamiast drugiego. Możemy to zrobić z functional::Curry:

sapply(funs, Curry(sapply, X=trees))

Ale miałem nadzieję, że może jest sprytny sposób, aby to zrobić z pozycjonowaniem i dopasowaniem nazwy, którego mi brakuje.

 22
Author: Community, 2015-06-10

4 answers

Ponieważ mapply Użyj elipsy ..., aby przekazać wektory (atomiki lub listy), a nie nazwany argument (X) jak w sapply, lapply, etc ... nie musisz nazywać parametru X = trees Jeśli używasz mapply zamiast sapply:

funs <- list(sd = sd, mean = mean)

x <- sapply(funs, function(x) sapply(trees, x))

y <- sapply(funs, mapply, trees)

> y
              sd     mean
Girth   3.138139 13.24839
Height  6.371813 76.00000
Volume 16.437846 30.17097
> identical(x, y)
[1] TRUE
Byłeś o jedną literę blisko, żeby dostać to, czego szukasz ! :)

Zauważ, że użyłem listy dla funs ponieważ nie mogę utworzyć ramki danych funkcji, dostałem błąd.

> R.version.string
[1] "R version 3.1.3 (2015-03-09)"
 20
Author: Julien Navarre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-10 18:15:28

Będziesz potrzebował jakiejś anonimowej funkcji, ponieważ nie ma innego sposobu na rozróżnienie nazwanych parametrów od dwóch różnych wywołań sapply. Pokazałeś już jawną funkcję anonimową i metodę Curry. Możesz również użyć magrittr

 library(magrittr)
 sapply(funs, . %>%  sapply(trees, .))
 # or .. funs %>% sapply(. %>%  sapply(trees, .))

Ale chodzi o to, że potrzebujesz czegoś tam do podziału. "Problem" polega na tym, że sapply wysyła do lapply, która jest wewnętrzną funkcją , która wydaje się być zdeterminowana, aby umieścić zmiana wartości jako początek wywołania funkcji. Potrzebujesz czegoś do zmiany kolejności parametrów i ze względu na identyczne zestawy nazw parametrów nie jest możliwe, aby tease that apart bez funkcji helper dbać o disambiguation.

Funkcja mapply pozwala przekazać listę do "MoreArgs", co pozwala ominąć konflikt nazwanych parametrów. Jest to przeznaczone do podziału między elementy, które należy wektoryzować i te, które są stałe. W ten sposób można do

mapply(sapply, funs, MoreArgs=list(X=trees))
#               sd     mean
# Girth   3.138139 13.24839
# Height  6.371813 76.00000
# Volume 16.437846 30.17097
 13
Author: MrFlick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-10 15:36:42

Innym podejściem używającym purrr byłoby:

require(purrr)

funs <- list(sd=sd, mean=mean)
trees %>% map_df(~invoke_map(funs, ,.), .id="id")

Ważne : zwróć uwagę, że pusty drugi argument invoke_map pasuje do pozycji. Zobacz ?purrr::invoke_map przykłady.

Co daje:

Source: local data frame [3 x 3]

      id        sd     mean
   <chr>     <dbl>    <dbl>
1  Girth  3.138139 13.24839
2 Height  6.371813 76.00000
3 Volume 16.437846 30.17097

Zamiast nazw wierszy to podejście daje kolumnę id zawierającą oryginalne kolumny.

 5
Author: Rentrop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-22 16:06:19

Choć nie tak budujące ani tak eleganckie jak rozwiązanie przedstawione przez @ Floo0, oto jeszcze jedno ujęcie za pomocą tidyr i dplyr :

library(dplyr)
library(tidyr)

fns <- funs(sd = sd, mean = mean)
trees %>% 
    gather(property, value, everything()) %>% 
    group_by(property) %>% 
    summarise_all(fns)

#   A tibble: 3 x 3
#   property        sd     mean
#      <chr>     <dbl>    <dbl>
# 1    Girth  3.138139 13.24839
# 2   Height  6.371813 76.00000
# 3   Volume 16.437846 30.17097

Ta sekwencja operacji wykonuje przyzwoitą pracę sygnalizowania intencji, kosztem dodatkowej gadatliwości.

 0
Author: egnha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-28 06:43:11