R 如何从返回多个值的函数赋值?
仍然试图进入R逻辑。。。从返回多个值的函数中解包(在LHS上)结果的“最佳”方法是什么 我显然不能这么做:R 如何从返回多个值的函数赋值?,r,return-value,variable-assignment,assign,multiple-results,R,Return Value,Variable Assignment,Assign,Multiple Results,仍然试图进入R逻辑。。。从返回多个值的函数中解包(在LHS上)结果的“最佳”方法是什么 我显然不能这么做: R> functionReturningTwoValues <- function() { return(c(1, 2)) } R> functionReturningTwoValues() [1] 1 2 R> a, b <- functionReturningTwoValues() Error: unexpected ',' in "a," R> c
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>functionReturningWoValues functionReturningWoValues()
[1] 1 2
R> a,b c(a,b)对你的第二和第三个问题回答是的——这是你需要做的,因为你不能在作业的左边有多个“左值”。这个问题没有正确答案。我真的取决于你对数据做了什么。在上面的简单示例中,我强烈建议:
让事情尽可能简单
只要可能,保持函数矢量化是最佳实践。从长远来看,这提供了最大的灵活性和速度
上面的值1和2有名称是否重要?换句话说,在本例中,为什么将1和2命名为a和b而不仅仅是r[1]和r[2]很重要?在此上下文中需要理解的一件重要事情是,a和b也是长度为1的向量。因此,在赋值过程中,除了有两个不需要引用下标的新向量外,您并没有真正改变任何东西:
> 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
>r a b类(r)
[1] “数字”
>(甲)级
[1] “数字”
>a
[1] 1
>a[1]
[1] 1
如果您希望引用字母而不是索引,也可以将名称指定给原始向量:
> names(r) <- c("a","b")
> names(r)
[1] "a" "b"
> r["a"]
a
1
>名称(r)名称(r)
[1] “a”“b”
>r[“a”]
A.
1.
[编辑]鉴于您将分别对每个向量应用最小值和最大值,我建议使用矩阵(如果a和b的长度和数据类型相同)或数据帧(如果a和b的长度相同,但数据类型可能不同),或者使用上一个示例中的列表(如果它们可以具有不同的长度和数据类型)
>r
a b
1 1 5
2 2 6
3 3 7
4 4 8
>最低(r$a)
[1] 1
>最高(南非兰特$b)
[1] 8
通常我会将输出包装到一个列表中,这非常灵活(输出中可以有数字、字符串、向量、矩阵、数组、列表和对象的任意组合)
就像:
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
func2我不知何故在互联网上偶然发现了这个聪明的黑客……我不确定它是肮脏的还是美丽的,但它让你创建了一个“神奇”的操作符,允许你将多个返回值解包到它们自己的变量中。:=
函数,包括以下供后代使用:
':=' <- 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))
}
“:=”列表似乎非常适合此用途。例如,在函数中
x = desired_return_value_1 # (vector, matrix, etc)
y = desired_return_value_2 # (vector, matrix, etc)
returnlist = list(x,y...)
} # end of function
主程序
(1)列出[…]使用assign怎么样
functionReturningTwoValues <- function(a, b) {
assign(a, 1, pos=1)
assign(b, 2, pos=1)
}
如果需要访问现有值,则assign
的相反方式是get
函数returningwovalues[A]
functionReturningTwoValues <- function() {
results <- list()
results$first <- 1
results$second <-2
return(results)
}
a <- functionReturningTwoValues()
如果foo和bar中的每一个都是一个数字,那么c(foo,bar)就没有问题;您还可以将这些组件命名为:c(foo=foo,bar=bar)。因此,您可以将结果“res”的组件命名为res[1]、res[2];或者在命名的情况下,命名为res[“foo”]、res[“bar”]
[乙]
如果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是字符串的向量),这也会很好地工作
[丙]
如果foo和bar差异很大,不能像上面那样方便地组合,那么您肯定应该返回一个列表
例如,您的函数可能适合线性模型,并且
还要计算预测值,以便
LM<-lm(....) ; foo<-summary(LM); bar<-LM$fit
LM如果要将函数的输出返回到全局环境,可以使用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)
要从函数中获取多个输出并将其保持在所需格式,您可以从函数内部将输出保存到硬盘(在工作目录中),然后从函数外部加载它们:
myfun <- function(x) {
df1 <- ...
df2 <- ...
save(df1, file = "myfile1")
save(df2, file = "myfile2")
}
load("myfile1")
load("myfile2")
myfun我用一个R包来解决这个问题。Zeellot包含一个多重赋值或解包赋值操作符,%在R3.6.1中,我可以做以下操作
fr2v <- function() { c(5,3) }
a_b <- fr2v()
(a_b[[1]]) # prints "5"
(a_b[[2]]) # prints "3"
fr2v编辑了这个问题,以便包含您的评论。谢谢。给r[1]
这样的名字可以帮助您把事情弄清楚(好吧,如果像a
这样的名字取而代之,就不需要了).FYI,返回多个值的另一种方法是在返回值上设置一个attr
。这相当于Python的元组解包。此外,我现在更不鼓励使用它,因为该包使用了:=
操作符mucho,更方便:-)我接受了你的答案,因为“with”,但我无法重现您对“list”左侧用法的描述,我得到的只是“object'a'notfound”,它对我有效。您尝试了什么?您阅读了链接帖子并遵循了它吗?您定义了list
和[@G.Grothendieck,你介意我把你链接的内容放在你的答案中吗?我想这会让人们更容易使用它。我同意@merlin2011;正如我所写的那样,这种语法似乎嵌入到了R base中。@G.Grothendieck我同意merlin2011和knowah-最好是使用这里重要的实际代码(链接中引用的代码)答案中有。提到结果对象不需要命名列表可能不是一个坏主意。在阅读实际代码之前,这让我困惑了一段时间。正如前面提到的,答案说您需要在链接中运行代码,但大多数人不会立即阅读该代码,除非它直接出现在答案中-这
myfun <- function() list(a = 1, b = 2)
list[a, b] <- myfun()
a + b
# same
with(myfun(), a + b)
attach(myfun())
a + b
functionReturningTwoValues <- function(a, b) {
assign(a, 1, pos=1)
assign(b, 2, pos=1)
}
> functionReturningTwoValues('a', 'b')
> a
[1] 1
> b
[1] 2
functionReturningTwoValues <- function() {
results <- list()
results$first <- 1
results$second <-2
return(results)
}
a <- functionReturningTwoValues()
data.frame(Foo=foo,Bar=bar)
LM<-lm(....) ; foo<-summary(LM); bar<-LM$fit
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)
> 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")
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, ..)
fr2v <- function() { c(5,3) }
a_b <- fr2v()
(a_b[[1]]) # prints "5"
(a_b[[2]]) # prints "3"