複数の値を返す関数から割り当てる方法は?
-
22-07-2019 - |
質問
Rロジックを取得しようとしていますが、<!> quot; best <!> quot;とは何ですか?複数の値を返す関数の結果を(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 [...] <!> lt;- 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(myfun())
a + b
追加:attach
および<=>
他のヒント
インターネット上のこの巧妙なハックに何らかの理由でつまずきました...それが不快なのか美しいのかはわかりませんが、<!> quot; magical <!> quot;複数の戻り値を独自の変数にアンパックできる演算子。 :=
関数ここで定義され、含まれています後世のために:
':=' <- 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
私はそれについてどう思うかわかりません。おそらく、あなたはあなたのインタラクティブなワークスペースでそれが役立つと思うかもしれません。それを使用して(再)使用可能なライブラリ(大量消費用)を構築することは最善のアイデアではないかもしれませんが、それはあなた次第だと思います。
...責任と権力について彼らが言うことを知っています...
通常、出力をリストにラップします。これは非常に柔軟です(数値、文字列、ベクトル、行列、配列、リスト、出力内のオブジェクトの任意の組み合わせを使用できます)
so like:
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, ..)
ビネットのパッケージをご覧ください詳細と例。
この質問に対する正しい答えはありません。私はあなたがデータで何をしているのかに本当に依存しています。上記の簡単な例では、次のことを強くお勧めします。
- できるだけシンプルにしてください。
- 可能な限り、関数をベクトル化しておくことをお勧めします。これにより、長期的には最大限の柔軟性と速度が提供されます。
上記の値1と2に名前を付けることは重要ですか?言い換えると、この例では、r [1]とr [2]だけでなく、1と2にaとbという名前を付けることが重要なのはなぜですか?このコンテキストで理解する1つの重要なことは、aとbが両方とも長さ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 [<!> quot; Foo <!> quot;]、res [<!> quot; BAR <!> quot;]のようになります。
[B] fooとbarが同じタイプと長さのベクトルである場合、再びcbind(foo、bar)またはrbind(foo、bar)を返すことに問題はありません。同様に名前が付けられます。 'cbind'の場合、res [、1]、res [、2]またはres [、<!> quot; Foo <!> quot;]、res [、<!> quotとしてfooとbarにアクセスします。 ; Bar <!> quot;]。また、マトリックスではなくデータフレームを返すこともできます。
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")