【问题标题】:For Loops in R that are taking too long to finish对于 R 中需要很长时间才能完成的循环
【发布时间】:2018-11-07 10:47:47
【问题描述】:

我试图在 R 中重现这个方程来进行内核 K-Means 聚类:

但是我创建的循环需要很长时间才能完成,我不知道如何改进它,这是给出问题的代码部分的示例:

c=3
for (g in 1:c) { 
  ans = 0
  for (k in 1:nrow(iris)) {
    for (l in 1:nrow(iris)) {
      ans = ans + (iris[k,'cluster']==g) *(iris[l,'cluster']==g)*kernelmatrix[k,l]
      }
    }
  third[g] = ans
  }   

这是一个伪代码,因为它只是完整函数的一部分,表达式(iris[l,'cluster']==g)是为了验证元素iris[l,'cluster']是否属于集群g,而kernelmatrix[k,l]是来自nxn 内核操作矩阵。

我知道R 不太适合循环,所以我不知道如何改进循环。

编辑:这是带有 kernelmatrix 部分的代码,但我认为这对代码并不重要(你们都读取数据的地方,可以认为这是任何数据集,例如 iris:

## Euclidian Distance  
        # Remember: 
        #1.|| a || = sqrt(aDOTa), 
        #2. d(x,y) = || x - y || = sqrt((x-y)DOT(x-y))
        #3. aDOTb = sum(a*b)


        d<-function(x,y){
                aux=x-y
                dis=sqrt(sum(aux*aux))
                return(dis)
        }

        ##Radial Basis Function Kernel
        # Remember :
        # 1.K(x,x')=exp(-q||x-x'||^2) where ||x-x'|| is could be defined as the
        # euclidian distance and 'q' it's the gamma parameter
        rbf<-function(x,y,q=0.2){
                aux<-d(x,y)
                rbfd<-exp(-q*(aux)^2)
                return(rbfd)
        }
        #
        #calculating the kernel matrix
        kernelmatrix=matrix(0,nrow(data),nrow(data))
        for(i in 1:nrow(data)){
                for(j in 1:nrow(data)){
                        kernelmatrix[i,j]=rbf(data[i,1:(ncol(data)-1)],data[j,1:(ncol(data)-1)],q)
                }
        }

【问题讨论】:

  • 正如你所说,R 不适合 for 循环。您的代码似乎“可矢量化”,因此 apply() 家族应该可以解决问题。另一种解决方案是使用Rcpp
  • 实际上 R 在循环方面很出色,尤其是最近的更新 - 请参阅 post。我在代码中看到的问题是它有 3 个 for 循环。可以dput(kernelmatrix)吗?
  • iris 没有cluster 列?
  • 没有,但这相当于每个物种对应一个数字
  • 你有没有尝试找到已经有计算kk mreas功能的包?例如rdocumentation.org/packages/kernlab/versions/0.9-26/topics/…

标签: r for-loop time cluster-analysis nested-loops


【解决方案1】:

R 解释器确实通常很慢。使用 for 循环还是其他循环结构似乎并不重要。所以尽量减少实际 R 代码的数量,当性能出现问题时,考虑用 C 重写代码。仅将 R 用作“驱动程序”。

在你的情况下,有几个明显的问题:

您的计算应该是对称的(如果您的核函数是对称的)。如果你利用这一点,你会快两倍。如果该点不在集群中,则内部循环根本不需要运行。你总结的只是零。

你做了 k*k 次选择。如果循环将它们移出,只做 k 次。然后向量化所有操作。

为了变得更快,尝试用矩阵运算替换整个内部两个循环(它将在 C 中运行,而不是两个 R 解释器循环......)。天真地,乘法。但随后意识到你只是在做一个选择。那你要写的是sum(kernelmatrix[selection,selection]),对吧?

【讨论】:

  • 正是我想在我的数据集中观察属于一个集群的观察结果,并使用该信息来计算内核矩阵中的元素。谢谢你,我会尝试做你建议的修改
【解决方案2】:

您是否尝试过使用Kernlab package 之类的东西?许多包作者会在 C++ 中实现这样的东西,因此即使你已经对这段代码进行了矢量化(如果你希望它合理地执行,这是必不可少的步骤),它的性能也会比手动计算的方程高得多。

【讨论】:

  • 我尝试使用 Kernlab 包,但无法返回集群的值...
【解决方案3】:

这可能是一个开始:

data("iris")
iris <- as.data.frame(iris, stringsAsFactors = FALSE)
ans <- 1:nrow(iris)
third <- ans + as.numeric(iris[,'Sepal.Length']==5)*as.numeric(iris[,'Sepal.Length']==4)

但是没有数据集和核矩阵的定义很难

【讨论】:

    猜你喜欢
    • 2018-02-07
    • 2016-07-30
    • 2013-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多