Jak przypisać z funkcji, która zwraca więcej niż jedną wartość?
Wciąż próbuję wejść w logikę R... jaki jest "najlepszy" sposób rozpakowania (na LHS) wyników funkcji zwracającej wiele wartości?
Nie mogę tego zrobić najwyraźniej:
R> functionReturningTwoValues <- function() { return(c(1, 2)) }
R> functionReturningTwoValues()
[1] 1 2
R> a, b <- functionReturningTwoValues()
Error: unexpected ',' in "a,"
R> c(a, b) <- functionReturningTwoValues()
Error in c(a, b) <- functionReturningTwoValues() : object 'a' not found
Czy naprawdę muszę wykonać następujące czynności?
R> r <- functionReturningTwoValues()
R> a <- r[1]; b <- r[2]
A może programista R napisze coś bardziej takiego:
R> functionReturningTwoValues <- function() {return(list(first=1, second=2))}
R> r <- functionReturningTwoValues()
R> r$first
[1] 1
R> r$second
[1] 2
- - - edytowane w odpowiedzi na pytania Shane ' a- - -
Naprawdę nie trzeba nadawać nazw części wartości wyniku. Stosuję jedną funkcję zbiorczą do pierwszej składnik i drugi do drugiego składnika (min
i max
. gdyby to była ta sama funkcja dla obu komponentów Nie potrzebowałbym ich dzielenia).
12 answers
(1) Lista [...] zamieściłem to ponad dekadę temu na r-help. Od tego czasu został dodany do pakietu gsubfn. Nie wymaga specjalnego operatora, ale wymaga, aby lewa strona była zapisywana za pomocą list[...]
w następujący sposób:
library(gsubfn) # need 0.7-0 or later
list[a, b] <- functionReturningTwoValues()
Jeśli potrzebujesz tylko pierwszego lub drugiego komponentu, wszystkie one również działają:
list[a] <- functionReturningTwoValues()
list[a, ] <- functionReturningTwoValues()
list[, b] <- functionReturningTwoValues()
(oczywiście, jeśli potrzebujesz tylko jednej wartości, to functionReturningTwoValues()[[1]]
lub functionReturningTwoValues()[[2]]
byłyby wystarczające.)
Zobacz cytowany wątek r-help dla więcej przykładów.
(2) z jeśli intencją jest jedynie późniejsze połączenie wielu wartości, a wartości zwracane są nazwane, to prostą alternatywą jest użycie with
:
myfun <- function() list(a = 1, b = 2)
list[a, b] <- myfun()
a + b
# same
with(myfun(), a + b)
(3) załącz inną alternatywą jest załącz:
attach(myfun())
a + b
Dodano: with
i attach
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
2018-05-10 03:04:35
W jakiś sposób natknąłem się na tego sprytnego hakera w Internecie ... Nie jestem pewien, czy jest paskudny czy piękny, ale pozwala stworzyć" magiczny " operator, który pozwala rozpakować wiele wartości zwrotnych do ich własnej zmiennej. Funkcja :=
jest zdefiniowana tutaj i dołączona poniżej dla potomności:
':=' <- function(lhs, rhs) {
frame <- parent.frame()
lhs <- as.list(substitute(lhs))
if (length(lhs) > 1)
lhs <- lhs[-1]
if (length(lhs) == 1) {
do.call(`=`, list(lhs[[1]], rhs), envir=frame)
return(invisible(NULL))
}
if (is.function(rhs) || is(rhs, 'formula'))
rhs <- list(rhs)
if (length(lhs) > length(rhs))
rhs <- c(rhs, rep(list(NULL), length(lhs) - length(rhs)))
for (i in 1:length(lhs))
do.call(`=`, list(lhs[[i]], rhs[[i]]), envir=frame)
return(invisible(NULL))
}
Mając to w ręku, możesz zrobić to, czego szukasz:
functionReturningTwoValues <- function() {
return(list(1, matrix(0, 2, 2)))
}
c(a, b) := functionReturningTwoValues()
a
#[1] 1
b
# [,1] [,2]
# [1,] 0 0
# [2,] 0 0
Nie wiem, co o tym myślę. Być może okaże się to pomocne w Twojej interaktywnej przestrzeni roboczej. Za pomocą budowanie (ponowne)użytecznych bibliotek (do masowej konsumpcji) może nie być najlepszym pomysłem, ale myślę, że to zależy od Ciebie.
... wiesz, co mówią o odpowiedzialności i władzy ...
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-03-16 21:05:35
Zwykle zawijam wyjście w listę, która jest bardzo elastyczna (możesz mieć dowolną kombinację liczb, łańcuchów, wektorów, macierzy, tablic, list, obiektów int he output)
Tak jak:
func2<-function(input) {
a<-input+1
b<-input+2
output<-list(a,b)
return(output)
}
output<-func2(5)
for (i in output) {
print(i)
}
[1] 6
[1] 7
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
2009-12-01 15:01:58
functionReturningTwoValues <- function() {
results <- list()
results$first <- 1
results$second <-2
return(results)
}
a <- functionReturningTwoValues()
Myślę, że to działa.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-03-23 14:46:36
Nie ma prawidłowej odpowiedzi na to pytanie. Zależy mi na tym, co robisz z danymi. W prostym przykładzie powyżej zdecydowanie sugerowałbym:
- trzymaj rzeczy tak proste, jak to tylko możliwe.
- tam, gdzie to możliwe, to najlepsza praktyka, aby utrzymać swoje funkcje wektoryzowane. Zapewnia to największą elastyczność i szybkość w dłuższej perspektywie.
Czy ważne jest, aby wartości 1 i 2 powyżej miały nazwy? Innymi słowy, dlaczego jest to ważne w tym przykład, że 1 i 2 mają nazwy a i b, a nie tylko r[1] i r[2]? Ważną rzeczą do zrozumienia w tym kontekście jest to, że a i b są również oba wektory o długości 1. Więc tak naprawdę nie zmieniasz niczego w procesie tworzenia tego przypisania, poza tym, że masz 2 nowe wektory, które nie wymagają referencji indeksów dolnych: {]}
> r <- c(1,2)
> a <- r[1]
> b <- r[2]
> class(r)
[1] "numeric"
> class(a)
[1] "numeric"
> a
[1] 1
> a[1]
[1] 1
Możesz również przypisać nazwy do oryginalnego wektora, jeśli wolisz odwoływać się do litery niż do indeks:
> names(r) <- c("a","b")
> names(r)
[1] "a" "b"
> r["a"]
a
1
[Edit] biorąc pod uwagę, że będziesz stosować min i max do każdego wektora osobno, sugerowałbym albo użycie macierzy (Jeśli a i b będą tej samej długości i tego samego typu danych) lub ramki danych (Jeśli a i b będą tej samej długości, ale mogą być różnymi typami danych) albo użycie listy, jak w poprzednim przykładzie (jeśli mogą być różnej długości i typów danych).
> r <- data.frame(a=1:4, b=5:8)
> r
a b
1 1 5
2 2 6
3 3 7
4 4 8
> min(r$a)
[1] 1
> max(r$b)
[1] 8
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
2009-12-01 15:03:46
Przygotowałem Pakiet R zeallot , aby rozwiązać ten problem. zeallot zawiera operator przypisania wielokrotnego lub rozpakowującego, %<-%
. LHS operatora to dowolna liczba zmiennych do przypisania, zbudowana za pomocą wywołań do c()
. RHS operatora to wektor, lista, ramka danych, obiekt daty lub dowolny obiekt niestandardowy z zaimplementowaną metodą destructure
(Zobacz ?zeallot::destructure
).
Oto garść przykładów opartych na oryginalnym poście,
library(zeallot)
functionReturningTwoValues <- function() {
return(c(1, 2))
}
c(a, b) %<-% functionReturningTwoValues()
a # 1
b # 2
functionReturningListOfValues <- function() {
return(list(1, 2, 3))
}
c(d, e, f) %<-% functionReturningListOfValues()
d # 1
e # 2
f # 3
functionReturningNestedList <- function() {
return(list(1, list(2, 3)))
}
c(f, c(g, h)) %<-% functionReturningNestedList()
f # 1
g # 2
h # 3
functionReturningTooManyValues <- function() {
return(as.list(1:20))
}
c(i, j, ...rest) %<-% functionReturningTooManyValues()
i # 1
j # 2
rest # list(3, 4, 5, ..)
Zobacz pakiet winieta aby uzyskać więcej informacji i przykładów.
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
2017-08-29 16:06:26
Listy wydają się idealne do tego celu. Na przykład w ramach funkcji masz
x = desired_return_value_1 # (vector, matrix, etc)
y = desired_return_value_2 # (vector, matrix, etc)
returnlist = list(x,y...)
} # end of function
Program główny
x = returnlist[[1]]
y = returnlist[[2]]
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
2013-02-28 16:05:44
Tak dla drugiego i trzeciego pytania-to jest to, co musisz zrobić, ponieważ nie możesz mieć wielu "lvalues" po lewej stronie zadania.
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
2009-12-01 14:41:39
Jak o użyciu przypisać?
functionReturningTwoValues <- function(a, b) {
assign(a, 1, pos=1)
assign(b, 2, pos=1)
}
Możesz przekazać nazwy zmiennej, którą chcesz przekazać przez odniesienie.
> functionReturningTwoValues('a', 'b')
> a
[1] 1
> b
[1] 2
Jeśli chcesz uzyskać dostęp do istniejących wartości, konwersją assign
jest get
.
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
2014-07-04 18:17:19
[A] Jeśli każdy z foo i bar jest pojedynczą liczbą, to nie ma nic złego w c (foo,bar); i możesz również nazwać komponenty: c (Foo=foo,Bar=bar). Można więc uzyskać dostęp do składników wyniku ' res ' jako res[1], res[2]; lub, w nazwanym przypadku, jako res ["Foo"], RES ["BAR"].
[B] Jeśli foo i bar są wektorami tego samego typu i długości, to nie ma nic złego w zwracaniu cbind (foo,bar) lub rbind (foo,bar); podobnie nameable. W przypadku "cbind" można uzyskać dostęp do foo i bar jako res[,1], res[,2] lub jako res[,"Foo"], res [, "Bar"]. Możesz również preferować zwracanie ramki danych zamiast matrycy:
data.frame(Foo=foo,Bar=bar)
I dostęp do nich jako res $ Foo, Res$Bar. Byłoby to również dobre, gdyby foo i bar były tej samej długości, ale nie tego samego typu (np. foo jest wektorem liczb, bar wektorem ciągów znaków).
[C] Jeśli foo i bar są wystarczająco różne, aby nie łączyć się wygodnie jak wyżej, to na pewno zwrócisz listę.
Dla przykład, twoja funkcja może pasować do modelu liniowego i również obliczyć przewidywane wartości, więc można mieć
LM<-lm(....) ; foo<-summary(LM); bar<-LM$fit
I wtedy będziesz return list(Foo=foo,Bar=bar)
i uzyskasz dostęp do podsumowania jako res$Foo, przewidywane wartości jako Res$Bar
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-14 17:49:35
Jeśli chcesz zwrócić wyjście swojej funkcji do środowiska globalnego, możesz użyć list2env
, jak w tym przykładzie:
myfun <- function(x) { a <- 1:x
b <- 5:x
df <- data.frame(a=a, b=b)
newList <- list("my_obj1" = a, "my_obj2" = b, "myDF"=df)
list2env(newList ,.GlobalEnv)
}
myfun(3)
Ta funkcja utworzy trzy obiekty w Twoim globalnym środowisku:
> my_obj1
[1] 1 2 3
> my_obj2
[1] 5 4 3
> myDF
a b
1 1 5
2 2 4
3 3 3
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
2017-04-30 17:18:01
Aby uzyskać wiele wyjść z funkcji i zachować je w pożądanym formacie, można zapisać wyjścia na dysku twardym (w katalogu roboczym) z poziomu funkcji, a następnie załadować je spoza funkcji:
myfun <- function(x) {
df1 <- ...
df2 <- ...
save(df1, file = "myfile1")
save(df2, file = "myfile2")
}
load("myfile1")
load("myfile2")
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
2017-05-17 09:32:41