まだRロジックを取得しようとしています...複数の値を返す関数からの結果を(LHSで)アンパックする「最良の」方法は何ですか?
私は明らかにこれを行うことができません:
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
私は本当に次のことをしなければなりませんか?
R> r <- functionReturningTwoValues()
R> a <- r[1]; b <- r[2]
または、Rプログラマーは次のようなものを書くでしょうか。
R> functionReturningTwoValues <- function() {return(list(first=1, second=2))}
R> r <- functionReturningTwoValues()
R> r$first
[1] 1
R> r$second
[1] 2
---シェーンの質問に答えるように編集---
結果の値部分に名前を付ける必要はありません。 1つの集約関数を最初のコンポーネントに適用し、もう1つを2番目のコンポーネントに適用しています(min
およびmax
。両方のコンポーネントで同じ関数である場合、それらを分割する必要はありません)。
(1)list [...] <-10年以上前に r-help に投稿しました。それ以来、gsubfnパッケージに追加されました。特別な演算子は必要ありませんが、次のようにlist[...]
を使用して左側を記述する必要があります。
library(gsubfn) # need 0.7-0 or later
list[a, b] <- functionReturningTwoValues()
最初または2番目のコンポーネントのみが必要な場合、これらもすべて機能します。
list[a] <- functionReturningTwoValues()
list[a, ] <- functionReturningTwoValues()
list[, b] <- functionReturningTwoValues()
(もちろん、必要な値が1つだけの場合は、functionReturningTwoValues()[[1]]
またはfunctionReturningTwoValues()[[2]]
で十分です。)
その他の例については、引用されたr-helpスレッドを参照してください。
(2)with意図が単に複数の値を後で結合することであり、戻り値に名前が付けられる場合、単純な代替手段はwith
を使用することです:
myfun <- function() list(a = 1, b = 2)
list[a, b] <- myfun()
a + b
# same
with(myfun(), a + b)
(3)attach別の選択肢はattachです:
attach(myfun())
a + b
追加:with
およびattach
私はどういうわけかこのインターネットの巧妙なハックにつまずきました...それが厄介なのか美しいのかはわかりませんが、複数の戻り値を独自の変数にアンパックできる「魔法の」演算子を作成できます。 :=
関数 ここで定義されています 、そして後世のために以下に含まれます:
':=' <- 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))
}
それを手に入れると、あなたはあなたが望んでいることをすることができます:
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
私はそれについてどう思うかわかりません。おそらく、あなたはあなたのインタラクティブなワークスペースでそれが役立つと思うかもしれません。これを使用して(再)使用可能なライブラリ(大量消費)を構築するのは最善のアイデアではないかもしれませんが、それはあなた次第だと思います。
...あなたは彼らが責任と力について何を言っているか知っています...
通常、出力をリストにラップします。これは非常に柔軟です(数値、文字列、ベクトル、行列、配列、リスト、出力内のオブジェクトの任意の組み合わせを使用できます)
以下のようなので:
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
functionReturningTwoValues <- function() {
results <- list()
results$first <- 1
results$second <-2
return(results)
}
a <- functionReturningTwoValues()
これはうまくいくと思う。
この問題に取り組むために、Rパッケージ zeallot を作成しました。 zeallotには、複数の代入演算子またはアンパック代入演算子%<-%
が含まれています。演算子のLHSは、c()
の呼び出しを使用して構築される、割り当てる任意の数の変数です。演算子のRHSは、ベクトル、リスト、データフレーム、日付オブジェクト、またはdestructure
メソッドが実装されたカスタムオブジェクトです(?zeallot::destructure
を参照)。
以下は、元の投稿に基づいた少数の例です。
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, ..)
詳細と例については、パッケージ vignette をご覧ください。
この質問に対する正しい答えはありません。私はあなたがデータで何をしているのかに本当に依存しています。上記の簡単な例では、次のことを強くお勧めします。
上記の値1と2に名前があることは重要ですか?言い換えると、この例では、r [1]とr [2]だけでなく、1と2にaとbという名前を付けることが重要なのはなぜですか?このコンテキストで理解する1つの重要なことは、aとbがalso両方の長さ1のベクトルであるということです。したがって、2つの新しいベクトルを持つ以外は、その割り当てを行う過程で実際には何も変更しません添え字を参照する必要がない:
> 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
インデックスではなく文字を参照する場合は、元のベクターに名前を割り当てることもできます。
> names(r) <- c("a","b")
> names(r)
[1] "a" "b"
> r["a"]
a
1
[編集]各ベクトルに最小値と最大値を別々に適用する場合、マトリックス(aとbが同じ長さと同じデータ型の場合)またはデータフレームを使用することをお勧めします(aとbが同じ長さであるが、異なるデータ型にすることができる場合)または最後の例のようにリストを使用する(長さとデータ型が異なる場合).
> 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
リストはこの目的に最適のようです。たとえば、関数内では
x = desired_return_value_1 # (vector, matrix, etc)
y = desired_return_value_2 # (vector, matrix, etc)
returnlist = list(x,y...)
} # end of function
x = returnlist[[1]]
y = returnlist[[2]]
2番目と3番目の質問はい。割り当ての左側に複数の「左辺値」を持つことはできないため、これが必要です。
Assignを使用してはどうですか?
functionReturningTwoValues <- function(a, b) {
assign(a, 1, pos=1)
assign(b, 2, pos=1)
}
参照渡しする変数の名前を渡すことができます。
> functionReturningTwoValues('a', 'b')
> a
[1] 1
> b
[1] 2
既存の値にアクセスする必要がある場合、assign
の逆はget
です。
[A] fooとbarのそれぞれが単一の数値である場合、c(foo、bar)に問題はありません。また、コンポーネントに名前を付けることもできます:c(Foo = foo、Bar = bar)。したがって、res [1]、res [2]として結果 'res'のコンポーネントにアクセスできます。または、名前付きの場合、res ["Foo"]、res ["BAR"]のようになります。
[B] fooとbarが同じ型と長さのベクトルである場合、再びcbind(foo、bar)またはrbind(foo、bar)を返すことに問題はありません。同様に名前が付けられます。 'cbind'の場合、fooとbarにres [、1]、res [、2]として、またはres [、 "Foo"]、res [、 "Bar"]としてアクセスします。マトリックスではなくデータフレームを返すこともできます。
data.frame(Foo=foo,Bar=bar)
res $ Foo、res $ Barとしてアクセスします。これは、fooとbarが同じ長さで同じ型ではない場合にも機能します(たとえば、fooは数値のベクトル、barは文字列のベクトルです)。
[C] fooとbarが上記のように便利に結合できないほど十分に異なる場合、間違いなくリストを返します。
たとえば、関数が線形モデルに適合し、予測値も計算する場合、次のようになります。
LM<-lm(....) ; foo<-summary(LM); bar<-LM$fit
そして、return list(Foo=foo,Bar=bar)
して、res $ Fooとしてサマリーにアクセスし、res $ Barとして予測値にアクセスします。
ソース: http://r.789695.n4.nabble.com/How-to-return-multiple-values-in-a-function-td858528.html
関数の出力をグローバル環境に返したい場合は、この例のようにlist2env
を使用できます。
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)
この関数は、グローバル環境に3つのオブジェクトを作成します。
> my_obj1
[1] 1 2 3
> my_obj2
[1] 5 4 3
> myDF
a b
1 1 5
2 2 4
3 3 3
関数から複数の出力を取得し、目的の形式で保持するには、出力を関数内から(作業ディレクトリ内の)ハードディスクに保存し、関数の外部からロードします。
myfun <- function(x) {
df1 <- ...
df2 <- ...
save(df1, file = "myfile1")
save(df2, file = "myfile2")
}
load("myfile1")
load("myfile2")