【问题标题】:Using calls to update "calls" to functions in R使用调用来更新对 R 中函数的“调用”
【发布时间】:2016-12-13 20:46:16
【问题描述】:

我在理解如何在 R 中使用调用时遇到了一些麻烦。我想获取一个由函数创建的对象并将其用作另一个函数的参数,同时修改原始函数的一些参数方式。我看过Hadley Wickham's page on expressions,,但它似乎并没有告诉我如何做我想做的事。

这是我想做的事情的部分工作示例。一、假数据:

library(MASS)
N <- 1000
p <- 10
A <- matrix(rnorm(p^2), p)
X <- mvrnorm(N, rep(0, p), t(A) %*% A)
B <- rnorm(p)
y <- X %*% B + rnorm(N)

接下来,一个函数来做岭回归。它是Xy 和岭惩罚L 的函数。它返回系数和调用:

pols <- function(X, y, L){
  cl <- match.call()
  beta <- solve(t(X) %*% X + diag(rep(L, p))) %*% t(X) %*% y
  return(list(beta = beta, cl = cl))
}

1> pols(X, y, 1)
$beta
             [,1]
 [1,] -0.02622669
 [2,] -1.96523722
 [3,]  0.36375563
 [4,] -1.14192468
 [5,] -0.14436051
 [6,] -0.29700918
 [7,] -0.81543748
 [8,] -0.17699934
 [9,] -0.01342649
[10,]  0.58862577

$cl
pols(X = X, y = y, L = 1)

现在,如何使用调用来驱动以下函数?它接受一个pols 对象和一个L 不同值的向量,并使用它们重新调用pols

Lvec <- 1:10    
tryLs <- function(pols, Lvec){
      for (i in Lvec){
        1.  Extract the args from the call in pols
        2.  Modify the argument `L` based on Lvec
        3.  Run `pols` with old arguments, but `L` modified according to `i`
      }
    }

如何使最后一个功能起作用?

为了澄清,我设想的工作流程是这样的:

obj <- pols(X, y, 0)
Lvec <- 1:10
output <- tryLs(obj, Lvec)

【问题讨论】:

  • 所以,电话是pols(X = X, y = y, L = 1)。采用这些参数,以便可以在第二步中对其进行修改。所以就像 make L&lt;-2
  • 这只是 SO 的一个虚拟示例。我的真实代码要复杂得多。基本上我有一个很长的参数列表,我只想修改其中一个。我必须遍历pols(q,w,e,r,t,y,u,,o,p,a,s,d,f,g,i)

标签: r function arguments call


【解决方案1】:

我将在这里做一些猜测/假设。

(1) 当你说“一个 pols 对象”时,你的意思是一个由pols 函数返回的对象。我在下面修改了pols(),使它返回一个“pols”类型的对象。这完全没有必要,但如果您将来想做一些更有趣的事情(例如,为这些对象实现自定义打印或绘图方法),这可能会很有用。

设置:

library(MASS)
N <- 1000
p <- 10
A <- matrix(rnorm(p^2), p)
X <- mvrnorm(N, rep(0, p), t(A) %*% A)
B <- rnorm(p)
y <- X %*% B + rnorm(N)

我还修改了pols,以便将包含调用的元素称为call:这使得对象自动使用R 的默认update 方法。

pols <- function(X, y, L){
   cl <- match.call()
   beta <- solve(t(X) %*% X + diag(rep(L, p))) %*% t(X) %*% y
   r <- list(beta = beta, call = cl)
   class(r) <- "pols"
   return(r)
}

为了拥有pols 对象,我们必须运行一次pols() 并保存结果:

pols1 <- pols(X,y,0)

现在这是您的功能。我的第二个假设是您只希望返回 $beta 值...

tryLs <- function(pols,Lvec) {
    sapply(Lvec,
           function(L) update(pols,L=L)$beta)
}
Lvec <- 1:10
tryLs(pols1,Lvec)

如果您想在更具体的层面上执行此操作(而不是使用 update),您可以按照以下方式进行操作

pols$call$L <- new_L_value
new_result <- eval(pols$call,parent.frame())

如果您查看update.default(),您会或多或少地看到它的作用(它使用来自match.call() 的信息,隐含地......)

【讨论】:

  • 有趣。您没有使用match.call 中的信息。我想我以前是保存呼叫的全部目的是为了进行各种更新。
【解决方案2】:

如果我猜对了您需要什么,我会使用 pryr 包中的 partial。这允许您创建一个已设置多个参数的函数:

library(pryr)
preset_pols = partial(pols, X = preset_X, y = preset_y)
preset_pols(L = 1)

现在调用preset_pols 将始终使用preset_Xpreset_y 中指定的数据。

在我看来,for 循环不需要,lapply 在这里就可以了:

list_of_results = lapply(Lvec, preset_pols)

【讨论】:

  • 效果很好,谢谢。但令我惊讶的是,在基本 R 中没有解决方案。如果不保存参数以供以后重新评估,match.call() 的意义何在?
  • 您可以使用do.call 来运行带有list 参数的函数。只需使用带有预设参数的列表并附加L = 1
【解决方案3】:
Lvec <- 1:10    
tryLs <- function(pols, Lvec){
  for (i in Lvec){
    print(paste("Result for ",i))
    print(pols(X,y,i))$beta
    print(pols(X,y,i))$cl

  }
}

tryLs(pols,Lvec)
[1] "Result for  1"
$beta
             [,1]
 [1,]  0.03317113
 [2,] -0.37399461
 [3,] -1.35395755
 [4,]  0.09850883
 [5,] -0.14503628
 [6,] -1.97204600
 [7,] -0.56459244
 [8,] -1.10422047
 [9,] -0.92047748
[10,]  1.76236287

$cl
pols(X = X, y = y, L = i)

$beta
             [,1]
 [1,]  0.03317113
 [2,] -0.37399461
 [3,] -1.35395755
 [4,]  0.09850883
 [5,] -0.14503628
 [6,] -1.97204600
 [7,] -0.56459244
 [8,] -1.10422047
 [9,] -0.92047748
[10,]  1.76236287

$cl
pols(X = X, y = y, L = i)

[1] "Result for  2"
$beta
             [,1]
 [1,] -0.01014376
 [2,] -0.32064189
 [3,] -1.29381243
 [4,]  0.10695047
 [5,] -0.24791384
 [6,] -1.83662948
 [7,] -0.55615073
 [8,] -1.12204424
 [9,] -0.96717380
[10,]  1.79084625

$cl
pols(X = X, y = y, L = i)

$beta
             [,1]
 [1,] -0.01014376
 [2,] -0.32064189
 [3,] -1.29381243
 [4,]  0.10695047
 [5,] -0.24791384
 [6,] -1.83662948
 [7,] -0.55615073
 [8,] -1.12204424
 [9,] -0.96717380
[10,]  1.79084625

$cl
pols(X = X, y = y, L = i)

[1] "Result for  3"
$beta
             [,1]
 [1,] -0.04097765
 [2,] -0.28237279
 [3,] -1.25064282
 [4,]  0.11286963
 [5,] -0.32135783
 [6,] -1.74000917
 [7,] -0.55025764
 [8,] -1.13481390
 [9,] -1.00038377
[10,]  1.81099139

$cl
pols(X = X, y = y, L = i)

$beta
             [,1]
 [1,] -0.04097765
 [2,] -0.28237279
 [3,] -1.25064282
 [4,]  0.11286963
 [5,] -0.32135783
 [6,] -1.74000917
 [7,] -0.55025764
 [8,] -1.13481390
 [9,] -1.00038377
[10,]  1.81099139

$cl
pols(X = X, y = y, L = i)

[1] "Result for  4"
$beta
             [,1]
 [1,] -0.06401718
 [2,] -0.25352501
 [3,] -1.21807596
 [4,]  0.11721395
 [5,] -0.37641945
 [6,] -1.66761823
 [7,] -0.54595545
 [8,] -1.14442668
 [9,] -1.02517135
[10,]  1.82592968

$cl
pols(X = X, y = y, L = i)

$beta
             [,1]
 [1,] -0.06401718
 [2,] -0.25352501
 [3,] -1.21807596
 [4,]  0.11721395
 [5,] -0.37641945
 [6,] -1.66761823
 [7,] -0.54595545
 [8,] -1.14442668
 [9,] -1.02517135
[10,]  1.82592968

$cl
pols(X = X, y = y, L = i)

[1] "Result for  5"
$beta
             [,1]
 [1,] -0.08186374
 [2,] -0.23095555
 [3,] -1.19257456
 [4,]  0.12050945
 [5,] -0.41923287
 [6,] -1.61137106
 [7,] -0.54271257
 [8,] -1.15193566
 [9,] -1.04434740
[10,]  1.83739926

$cl
pols(X = X, y = y, L = i)

$beta
             [,1]
 [1,] -0.08186374
 [2,] -0.23095555
 [3,] -1.19257456
 [4,]  0.12050945
 [5,] -0.41923287
 [6,] -1.61137106
 [7,] -0.54271257
 [8,] -1.15193566
 [9,] -1.04434740
[10,]  1.83739926

$cl
pols(X = X, y = y, L = i)

[1] "Result for  6"
$beta
             [,1]
 [1,] -0.09607715
 [2,] -0.21277987
 [3,] -1.17201761
 [4,]  0.12307151
 [5,] -0.45347618
 [6,] -1.56641949
 [7,] -0.54021027
 [8,] -1.15797228
 [9,] -1.05959733
[10,]  1.84644233

$cl
pols(X = X, y = y, L = i)

$beta
             [,1]
 [1,] -0.09607715
 [2,] -0.21277987
 [3,] -1.17201761
 [4,]  0.12307151
 [5,] -0.45347618
 [6,] -1.56641949
 [7,] -0.54021027
 [8,] -1.15797228
 [9,] -1.05959733
[10,]  1.84644233

$cl
pols(X = X, y = y, L = i)

[1] "Result for  7"
$beta
            [,1]
 [1,] -0.1076495
 [2,] -0.1977993
 [3,] -1.1550561
 [4,]  0.1251007
 [5,] -0.4814888
 [6,] -1.5296799
 [7,] -0.5382458
 [8,] -1.1629381
 [9,] -1.0719931
[10,]  1.8537217

$cl
pols(X = X, y = y, L = i)

$beta
            [,1]
 [1,] -0.1076495
 [2,] -0.1977993
 [3,] -1.1550561
 [4,]  0.1251007
 [5,] -0.4814888
 [6,] -1.5296799
 [7,] -0.5382458
 [8,] -1.1629381
 [9,] -1.0719931
[10,]  1.8537217

$cl
pols(X = X, y = y, L = i)

[1] "Result for  8"
$beta
            [,1]
 [1,] -0.1172419
 [2,] -0.1852151
 [3,] -1.1407910
 [4,]  0.1267308
 [5,] -0.5048296
 [6,] -1.4990974
 [7,] -0.5366841
 [8,] -1.1671009
 [9,] -1.0822491
[10,]  1.8596792

$cl
pols(X = X, y = y, L = i)

$beta
            [,1]
 [1,] -0.1172419
 [2,] -0.1852151
 [3,] -1.1407910
 [4,]  0.1267308
 [5,] -0.5048296
 [6,] -1.4990974
 [7,] -0.5366841
 [8,] -1.1671009
 [9,] -1.0822491
[10,]  1.8596792

$cl
pols(X = X, y = y, L = i)

[1] "Result for  9"
$beta
            [,1]
 [1,] -0.1253119
 [2,] -0.1744744
 [3,] -1.1286001
 [4,]  0.1280542
 [5,] -0.5245776
 [6,] -1.4732498
 [7,] -0.5354316
 [8,] -1.1706458
 [9,] -1.0908596
[10,]  1.8646205

$cl
pols(X = X, y = y, L = i)

$beta
            [,1]
 [1,] -0.1253119
 [2,] -0.1744744
 [3,] -1.1286001
 [4,]  0.1280542
 [5,] -0.5245776
 [6,] -1.4732498
 [7,] -0.5354316
 [8,] -1.1706458
 [9,] -1.0908596
[10,]  1.8646205

$cl
pols(X = X, y = y, L = i)

[1] "Result for  10"
$beta
            [,1]
 [1,] -0.1321862
 [2,] -0.1651825
 [3,] -1.1180392
 [4,]  0.1291370
 [5,] -0.5415033
 [6,] -1.4511217
 [7,] -0.5344217
 [8,] -1.1737051
 [9,] -1.0981778
[10,]  1.8687639

$cl
pols(X = X, y = y, L = i)

$beta
            [,1]
 [1,] -0.1321862
 [2,] -0.1651825
 [3,] -1.1180392
 [4,]  0.1291370
 [5,] -0.5415033
 [6,] -1.4511217
 [7,] -0.5344217
 [8,] -1.1737051
 [9,] -1.0981778
[10,]  1.8687639

$cl
pols(X = X, y = y, L = i)

【讨论】:

  • Xy 不一定会在全球环境中。
  • @generic_user 在这种情况下,您可以设置或预先设置环境。这里有一个例子:adv-r.had.co.nz/Environments.html
  • 我真正想做的是找到避免重新指定大量参数的方法。
  • @generic_user 我对你的意思感到困惑。添加另一个更能反映您正在处理的内容的示例可能会提供信息。
  • 嗯,我想要的第一件事是从我通过match.call() 保存的调用中提取参数。然后我想修改该信息并使用它来驱动功能。该函数将通过调用来驱动。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-23
  • 1970-01-01
  • 2015-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-01
相关资源
最近更新 更多