我目前正在R Studio中使用R版本3.4.4(2018-03-15)。
我需要计算两个值的比率。而且我在某些情况下有问题:
计算比率时,我得到一个NaN(因为0/0)。
第一个解决方案:
我使用了 Brobdingnag 库,该库允许将数字保留为指数,并最终得出该比率实际上是:exp(-3.8987)= 0.02026725
但是,使用库 profvis 检查我的代码的性能时,我可以看到,尽管在我的案例中Brobdingnag库非常有用,但在花费方面性能。而且我不能保留这种解决方案,因为我必须对我的算法进行很多模拟。
其他解决方案的问题:
您是否听说过另一个可以处理很小(或很大)值的库?
在进行除法运算之前,我想将分子和分母保持在指数表达式中,但是我不知道该怎么做。当然,因为我的分子和分母是向量,一旦它们都被计算,就将它们除。 (没有分子向量我无法获得分母) 有没有办法“强制” R将值保留为exp而不是整数(和0 ...)?
在此先感谢您的帮助。
编辑:
这是我要计算的比率:
我不确定是否可以使用技巧:exp(x)/ exp(y)= exp(x-y),因为我有一个加到定理中的和。 这就是为什么我需要exp公式直到执行比率... exp内的值是一个非常大的负数,这些数字的exp都为0。此外,我尝试将分子转换为对数,因此我可以将过去的记录对数+第二部分(没有exp),但有时将分子的第一部分(1 / sqrt ...)太小,其记录返回Inf ..
我认为有办法,但是我找不到。
感谢所有答案!
编辑2:
####### Fonction that calculate the density (with brobdingnag package) :
density <- function(nc,yc,X,beta,sig,k){
# n_c is a vector of integer
# y_c is a vector of numeric
# X is a matrix
# beta is a vector of numeric
# sigma is a value
res<-as.brob((1/(2*pi*sig[k])))^(nc/2)*exp(as.brob(-(1/(2*sig[k]))*t(yc-(X %*% beta[,k])) %*% (yc-(X %*% beta[,k]))))
return(res)
}
####### Code for calculation of the ratio :
# n_c[c] : num [1] 340
# y_c[c] : num [1:340] 1.279 0.777 1.069 0.864 1.56 ...
# X[c] : num [1:340, 1:11] 1 1 1 1 1 1 1 1 1 1 ... (matrix of 0 and 1)
# beta : num [1:11, 1:2] 1.542 -0.226 -0.145 -0.438 -0.201 ...
# sigma : num [1:2] 21.694381 4.267277
# lambda : num [1] 0.5
# Numerator :
num_tau<-sapply(1:100,function(c){
sapply(1:4,function(k){
lambda[k]*density(n_c[c], y_c[c],X[c],beta,sigma,k)
})
})
# Denominator :
denom_tau<-list()
for (c in 1:100){
val<-0
for (k in 1:4){
val<-val+num_tau[k,c][[1]]
}
denom_tau[[c]]<-val
}
# Ratio :
for (l in 1:4){
for (c in 1:100){
tau[l,c]<-as.numeric(num_tau[l,c][[1]]/denom_tau[[c]])
}
}
答案 0 :(得分:0)
如果两个值都需要先进行指数运算,则可以使用公式:
e ^ x / e ^ y = e ^(x-y)
否则,您可以尝试使用Rmpfr
软件包。
示例:
require(Rmpfr)
p = 40
x <- mpfr(-2408.9, p)
y <- mpfr(-2405, p)
exp(x)/exp(y)
# 1 'mpfr' number of precision 40 bits
# [1] 0.02024191147598
答案 1 :(得分:0)
按照@minem的建议,您可以使用 Rmpfr 软件包。这是将其应用于您的案例的一种方法。
首先使用a * exp(b)= exp(b + log(a))的事实,将乘法器移动到分子的指数内。然后,重新编写您的density
函数以计算日志分子:
log_numerator <- function(nc, yc, X, beta, sig, k, lambda){
v <- yc - X %*% beta[,k]
res <- -sum(v*v)/(2*sig[k]) - (nc/2)*log(2*pi*sig[k]) + log(lambda[k])
drop(res)
}
请注意,lambda
现在已传递给此函数。还要注意,如图所示,我们可以更有效地计算向量Y-X * beta的点积。
现在我们可以生成一些数据。在这里,我修复了c,只是k = 1:2。
set.seed(1)
n_c <- 340
y_c <- rnorm(340)
dat <- data.frame(fac = sample(letters[1:11], 340, replace = TRUE)
X_c <- model.matrix(~ fac, data = dat)
beta <- matrix(runif(22, -10, 10), 11, 2)
sigma <- c(21.694381, 4.267277)
lambda <- c(0.5, 0.5)
使用您的密度函数
x1 <- lambda[1] *density(n_c, y_c,X_c,beta,sigma,1)
y1 <- lambda[2] *density(n_c, y_c,X_c,beta,sigma,2)
x1
# [1] +exp(-1738.4)
y1
# [1] +exp(-1838.7)
as.numeric(y1/sum(x1, y1))
# [1] 2.780805e-44
使用对数分子功能
p <- 40
x <- mpfr(log_numerator(n_c, y_c,X_c,beta,sigma,1, lambda), p)
y <- mpfr(log_numerator(n_c, y_c,X_c,beta,sigma,2, lambda), p)
x
# 1 'mpfr' number of precision 40 bits
# [1] -1738.379327798
y
# 1 'mpfr' number of precision 40 bits
# [1] -1838.67033143
exp(y)/sum(exp(x), exp(y))
# 1 'mpfr' number of precision 53 bits
# [1] 2.780805017186589e-44
因此可以肯定mpfr
可以用来产生等效的结果,但是如果没有更好的测试代码,很难检查时间。
您还可以通过使用更多的向量化来提高效率。例如。我们可以在k上向量化log_numerator
:
log_numerator2 <- function(nc, yc, X, beta, sig, lambda){
M <- yc - X %*% beta
res <- -colSums(M*M)/(2*sig) - (nc/2)*log(2*pi*sig) + log(lambda)
drop(res)
}
z <- log_numerator2(n_c, y_c, X_c, beta, sigma, lambda)
z
# [1] -1738.379 -1838.670
现在假设我们在c x k矩阵中有对数分子,为说明起见,假设所有c的值都与z
相同,
log_num <- mpfr(matrix(z, byrow = TRUE, 3, 2), p)
您可以按如下方式计算比率
num <- exp(log_num)
denom <- apply(num, 1, sum) # rowSums not implemented for mpfr
num/denom
# 'mpfrMatrix' of dim(.) = (3, 2) of precision 53 bits
# [,1] [,2]
# [1,] 1.000000000000000 2.780805017186589e-44
# [2,] 1.000000000000000 2.780805017186589e-44
# [3,] 1.000000000000000 2.780805017186589e-44