【问题标题】:Vectorizing this function in R在 R 中向量化这个函数
【发布时间】:2018-05-15 02:30:38
【问题描述】:

嗨,我有以下功能:

kde.cv = function(X,s)    {
  l = length(X)

  log.fhat.vector = c()
  for (i in 1:l) {
    current.log.fhat = log ( kde(X[i],X[-i],s) )
    log.fhat.vector[i] = current.log.fhat
  }

  CV.score = sum(log.fhat.vector)

  return(CV.score)
}

我想在不使用任何 for 循环或 apply 语句的情况下对其进行矢量化,但似乎无法绕过这样做。帮助将不胜感激。谢谢。

编辑:鉴于回答,这是我对所提出问题的回答。

鉴于要求澄清,我将详细说明函数输入和给定函数内的用户定义函数。所以这里的 X 是一个向量形式的数据集,具体来说,是我用作该函数输入的数据集中长度为 7 的向量。我使用这个函数的 X 是 c(-1.1653, -0.7538, -1.3218, -2.3394, -1.9766, -1.8718, -1.5041)。 s 是设置为 0.2 的单个标量点,用于使用此函数。 kde 是我写的一个用户定义的函数。这是实现:

kde = function(x,X,s){
  l = length(x)   
  b = matrix(X,l,length(X),byrow = TRUE)
  c = x - b 
  phi.matrix = dnorm(c,0,s)
  d = rowMeans(phi.matrix)

  return(d)
}

在此函数中,X 与 kde.cv 中使用的数据点向量相同。 s 也是 kde.cv 中使用的相同标量值 0.2。 x 是函数的评估点向量,我使用了 seq(-2.5, -0.5, by = 0.1)。

【问题讨论】:

  • 请提供更完整的可重现示例。包括 X 和 s 的值,以便我们可以使用它来测试您的功能。此外,有关您尝试实现的目标的文档也将对社区有所帮助。
  • @Juan Zamora 我已经编辑了我的原始帖子以提供更多详细信息。就我对这段代码所做的事情而言:kde 是一个函数,通过使用评估点 x 和带宽 s 的向量在 X 给定的数据集上通过正常内核拟合非参数密度。 kde.cv 是一个进行交叉验证以选择最佳带宽 s 的函数。

标签: r


【解决方案1】:

这是一个使用sapply的选项

kde.cv = function(X,s) 
    sum(sapply(1:length(X), function(i) log(kde(X[i], X[-i], s))))

【讨论】:

  • OP 请求“我想在不使用任何 for 循环或应用语句的情况下对其进行矢量化”
  • @SymbolixAU 没有更多信息(特别是关于kde 的作用),很难优化代码。我的答案应该比在每个步骤中动态扩展log.fhat.vector 的原始代码尝试更快;另一个答案也使用了 apply 方法(mapplyVectorize)。
【解决方案2】:

为方便起见,请提供更完整的示例。例如,kde() 函数。那是自定义功能吗?

替代sapply,你可以试试Vectorize()。您可以找到一些有关堆栈溢出的示例。

Vectorize() vs apply()

这是一个例子

f1 <- function(x,y) return(x+y) 
f2 <- Vectorize(f1) 

f1(1:3, 2:4) 
[1] 3 5 7
f2(1:3, 2:4) 
[1] 3 5 7

第二个例子

f1 <- function(x) 
{
 new.vector<-c()  
 for (i in 1:length(x)) 
 {
  new.vector[i]<-sum(x[i] + x[-i])
 }
 return(sum(new.vector))
}

f2<-function(x)
{
 f3<-function(y, i)
 {
  u<-sum(y[i]+y[-i])
  return(u)
 }
 f3.v<-Vectorize(function(i) f3(y = x, i=i))
 new.value<-f3.v(1:length(x))
 return(sum(new.value))
}

f1(1:3) 
[1] 24

f2(1:3) 
[1] 24

注意:Vectorize 是 mapply 的包装器

编辑 1

根据回复,我编辑了你的kde.cv函数。

kde.cv = function(X,s)    {
 l = length(X)

 log.fhat.vector = c()
 for (i in 1:l) {
  current.log.fhat = log ( kde(X[i],X[-i],s) )
  log.fhat.vector[i] = current.log.fhat
 }

 CV.score = sum(log.fhat.vector)

 return(CV.score)
}

kde = function(x,X,s){
 l = length(x)   
 b = matrix(X,l,length(X),byrow = TRUE)
 c = x - b 
 phi.matrix = dnorm(c,0,s)
 d = rowMeans(phi.matrix)

 return(d)
}


##### Vectorize kde.cv ######

kde.cv.v = function(X,s)   
{
 log.fhat.vector = c()

 kde.v<-Vectorize(function(i) kde(X[i], X[-i], s))

 CV.score <- sum(log(kde.v(1:length(X))))

 return(CV.score)
}

X<-c(-1.1653, -0.7538, -1.3218, -2.3394, -1.9766, -1.8718, -1.5041)
s<-0.2
x<-seq(-2.5, -0.5, by = 0.1)

kde.cv(X, s)
[1] -10.18278

kde.cv.v(X, s)
[1] -10.18278

编辑 2

好吧,我认为以下功能可能符合您的要求。顺便说一句,由于您的kde.cv 中没有使用小x,我只是编辑了这两个函数

kde.cv.2 <- function(X,s)    
{
 log.fhat.vector<-log(kde.2(X, s))
 CV.score = sum(log.fhat.vector)
 return(CV.score)
}

kde.2<-function(X, s)
{
 l <- length(X)  
 b <- matrix(rep(X, l), l, l, byrow = T)
 c <- X - b
 diag(c) <- NA
 phi.matrix <- dnorm(c, 0, s)
 d <- rowMeans(phi.matrix, na.rm = T)
 return(d)
}

X<-c(-1.1653, -0.7538, -1.3218, -2.3394, -1.9766, -1.8718, -1.5041)
s<-0.2 

kde.cv(X,s)
[1] -10.18278

kde.cv.2(X, s)
[1] -10.18278

【讨论】:

  • 是的,Kde() 是我编写的用户定义函数。我已经编辑了我的原始帖子以提供更多详细信息。
  • @JaimeMelaraSosa 所以,在你的kde.cv函数中,你输入的kde的第一个参数是X[i],这是一个单一的值,而kde的第一个参数应该是一个向量。
  • @JaimeMelaraSosa 我认为kde.cv 可能符合您的要求。
  • 感谢您的回复。我意识到 X[i] 是单个值,但单个值不只是长度为 1 的向量吗?我不认为这太重要了,因为无论如何该功能都给了我正确的答案。就您使用 vectorize() 重写的 kde.cv 函数而言,我不确定这是否是我正在寻找的。当我说“向量化”函数时,我的意思是只使用向量/矩阵运算而不使用循环或应用语句来编写它。我对vectorize()不太熟悉,但它与apply()不相似,因为它也是使用循环预先编写的?
  • @JaimeMelaraSosa 在我看来只是有点奇怪的考虑。顺便说一句,小x 没有使用,kde 函数只能使用两个参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-19
  • 2018-06-24
相关资源
最近更新 更多