对于 R 中的循环,完成时间太长
For Loops in R that are taking too long to finish
我正在尝试在 R 中重现此等式以进行内核 K-均值聚类:
但是我创建的循环完成时间太长,我不知道如何改进它,下面是出现问题的代码部分的示例:
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)
}
}
这可能是开始:
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)
但是没有数据集和核矩阵的定义就很难
您尝试过使用 Kernlab package 之类的东西吗?许多程序包作者会在 C++ 中实现此类功能,因此其性能将比手动方程式高得多,即使您已将此代码矢量化(如果您希望它合理执行,这是必不可少的步骤)。
R 解释器确实普遍较慢。使用 for 循环还是其他循环结构似乎无关紧要。因此,尽量减少实际 R 代码的数量,当性能出现问题时,考虑用 C 重写代码。仅将 R 用作 "driver".
在你的案例中,有几个明显的问题:
你的计算应该是对称的(如果你的核函数是对称的)。如果你利用这一点,你会快两倍。如果该点不在集群中,则内循环根本不需要 运行。你只是总结了零。
您选择了 k*k 次。如果循环将它们移出,只执行 k 次。然后向量化所有操作。
为了变得更快,请尝试用矩阵运算替换整个内部两个循环(这将 运行 在 C 中,而不是两个 R 解释器循环...)。天真地,一个乘法。但随后意识到您只是在进行选择。那么你要写的是sum(kernelmatrix[selection,selection]),对吧?
我正在尝试在 R 中重现此等式以进行内核 K-均值聚类:
但是我创建的循环完成时间太长,我不知道如何改进它,下面是出现问题的代码部分的示例:
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)
}
}
这可能是开始:
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)
但是没有数据集和核矩阵的定义就很难
您尝试过使用 Kernlab package 之类的东西吗?许多程序包作者会在 C++ 中实现此类功能,因此其性能将比手动方程式高得多,即使您已将此代码矢量化(如果您希望它合理执行,这是必不可少的步骤)。
R 解释器确实普遍较慢。使用 for 循环还是其他循环结构似乎无关紧要。因此,尽量减少实际 R 代码的数量,当性能出现问题时,考虑用 C 重写代码。仅将 R 用作 "driver".
在你的案例中,有几个明显的问题:
你的计算应该是对称的(如果你的核函数是对称的)。如果你利用这一点,你会快两倍。如果该点不在集群中,则内循环根本不需要 运行。你只是总结了零。
您选择了 k*k 次。如果循环将它们移出,只执行 k 次。然后向量化所有操作。
为了变得更快,请尝试用矩阵运算替换整个内部两个循环(这将 运行 在 C 中,而不是两个 R 解释器循环...)。天真地,一个乘法。但随后意识到您只是在进行选择。那么你要写的是sum(kernelmatrix[selection,selection]),对吧?