英文:
VIKOR function from MCDM R package is returning error
问题
我正在尝试使用以下代码从MCDM
R包中运行VIKOR
:
library(MCDM)
d <- matrix(c(1,2,5,3000,3750,4500), nrow = 3, ncol = 2)
w <- c(0.5, 0.5)
cb <- c('min', 'max')
v <- 0.5
VIKOR(d, w, cb, v)
但它返回以下错误:
> Error in (Q == "NaN") || (Q == "Inf") :
'length = 3' in coercion to 'logical(1)'
我该如何解决这个错误?
英文:
I am trying to run VIKOR
from MCDM
R package using the following code
library(MCDM)
d <- matrix(c(1,2,5,3000,3750,4500),nrow = 3,ncol = 2)
w <- c(0.5,0.5)
cb <- c('min','max')
v <- 0.5
VIKOR(d,w,cb,v)
But it returns me following error
>Error in (Q == "NaN") || (Q == "Inf") :
'length = 3' in coercion to 'logical(1)'
How can I solve this error?
The source code for VIKOR is available here.
答案1
得分: 2
这个错误是从哪里来的?
这个错误出现在 R 4.3.0 中(自 4.2.0 起是一个警告)。从NEWS中得知:
> 使用左操作数(LHS)或(如果被计算)右操作数(RHS)的长度大于一时,现在总是会报错,报错信息如下:
> 'length = 4' in coercion to 'logical(1)'
在你提供的源代码中,问题出现在 VIKOR()
函数的最后一行:
if( (Q == "NaN") || (Q == "Inf")){
问题在于,在你的情况下,Q
返回一个向量:
1 0 1
因此,这两个语句中的每一个都返回长度为 3 的向量:
> print((Q == "NaN"))
[1] FALSE FALSE FALSE
> print((Q == "Inf"))
[1] FALSE FALSE FALSE
对这两个长度大于 1 的向量使用 ||
会引发错误。
你有哪些选项?
-
检查你的输入是否正确。
-
联系包的作者。显然,该包已经不再在 CRAN 上了(在 2022 年 4 月被移除),但你仍然可以从DESCRIPTION文件中获取作者的电子邮件地址。
-
这个函数本身并不难从包中提取出来。它不使用任何内部函数或其他包。如果你对代码和背后的方法足够熟悉,你可以尝试自己修复它。
英文:
Where does this error come from?
This error appeared in R 4.3.0 (it was a warning since 4.2.0). From the NEWS:
> Calling && or || with LHS or (if evaluated) RHS of length greater than one is now always an error, with a report of the form
>
> 'length = 4' in coercion to 'logical(1)'
In the source code you link to, the problem is this line at the end of VIKOR()
:
if( (Q == "NaN") || (Q == "Inf")){
The problem is that, in your case, Q
returns a vector:
1 0 1
so each of the two statements returns a length-3 vector:
> print((Q == "NaN"))
[1] FALSE FALSE FALSE
> print((Q == "Inf"))
[1] FALSE FALSE FALSE
Using ||
with these two vectors whose length is larger than 1 throws an error.
What are your options?
-
Check that your input is correct.
-
Contact the package author. Apparently the package isn't on CRAN anymore (removed in April 2022) but you can still get the email address from the DESCRIPTION file.
-
The function in itself is not hard to extract from the package. It doesn't use any internal function or another package. If you're comfortable enough with the code and the method behind, you could try to fix it yourself.
答案2
得分: 0
我已经通过修改源代码来解决这个问题,如下所示:
VIKOR <- function(decision,
weights,
cb,
v
)
{
# 检查参数
if(! is.matrix(decision))
stop('decision必须是一个包含替代方案值的矩阵')
if(missing(weights))
stop('应提供一个包含n个权重值(总和为1)的向量')
if(sum(weights) != 1)
stop('权重的总和不等于1')
if(! is.character(cb))
stop('cb必须是一个包含标准类型的字符向量(benefit = "max",cost = "min")')
if(! all(cb == "max" | cb == "min"))
stop('cb应该只包含"max"或"min"')
if(length(weights) != ncol(decision))
stop('weights的长度与标准的数量不匹配')
if(length(cb) != ncol(decision))
stop('cb的长度与标准的数量不匹配')
if(missing(v))
stop('应提供v的值,范围在[0,1]之间')
# 1. 理想解决方案
posI <- as.integer(cb == "max") * apply(decision, 2, max) +
as.integer(cb == "min") * apply(decision, 2, min)
negI <- as.integer(cb == "min") * apply(decision, 2, max) +
as.integer(cb == "max") * apply(decision, 2, min)
# 2. S和R指数
norm = function(x, w, p, n) {
w * ((p - x) / (p - n))
}
SAux <- apply(decision, 1, norm, weights, posI, negI)
S <- apply(SAux, 2, sum)
R <- apply(SAux, 2, max)
# 3. Q指数
if (v == 0)
Q <- (R - min(R)) / (max(R) - min(R))
else if (v == 1)
Q <- (S - min(S)) / (max(S) - min(S))
else
Q <- v * (S - min(S)) / (max(S) - min(S)) + (1 - v) * (R - min(R)) / (max(R) - min(R))
# 4. 检查Q是否有效
RankingQ = ifelse(is.infinite(Q) | is.na(Q), NA,
rank(Q, ties.method = "first"))
# 5. 对替代方案进行排名
return(data.frame(Alternatives = 1:nrow(decision), S = S, R = R, Q = Q,
Ranking = RankingQ))
}
现在它的工作正常,如下所示:
d <- matrix(c(1,2,5,3000,3750,4500),nrow = 3,ncol = 2)
w <- c(0.5,0.5)
cb <- c('min','max')
v <- 0.5
VIKOR(d,w,cb,v)
#> Alternatives S R Q Ranking
#> 1 1 0.500 0.50 1.00 2
#> 2 2 0.375 0.25 0.00 1
#> 3 3 0.500 0.50 1.00 3
英文:
I have solved this problem by modifying the source code like
VIKOR <- function(decision, #matrix with all the alternatives
weights, #vector with the numeric values of the weights
cb, #vector with the "type" of the criteria (benefit = "max", cost = "min")
v #value with the real number of the 'v' parameter to calculate Q
)
{
#Checking parameters
if(! is.matrix(decision))
stop("'decision' must be a matrix with the values of the alternatives")
if(missing(weights))
stop("a vector containing n weigths, adding up to 1, should be provided")
if(sum(weights) != 1)
stop("The sum of 'weights' is not equal to 1")
if(! is.character(cb))
stop("'cb' must be a character vector with the type of the criteria")
if(! all(cb == "max" | cb == "min"))
stop("'cb' should contain only 'max' or 'min'")
if(length(weights) != ncol(decision))
stop("length of 'weights' does not match the number of the criteria")
if(length(cb) != ncol(decision))
stop("length of 'cb' does not match the number of the criteria")
if(missing(v))
stop("a value for 'v' in [0,1] should be provided")
#1. Ideal solutions
posI <- as.integer(cb == "max") * apply(decision, 2, max) +
as.integer(cb == "min") * apply(decision, 2, min)
negI <- as.integer(cb == "min") * apply(decision, 2, max) +
as.integer(cb == "max") * apply(decision, 2, min)
#2. S and R index
norm =function(x,w,p,n){
w*((p-x)/(p-n))
}
SAux <- apply(decision, 1, norm, weights, posI, negI)
S <- apply(SAux, 2, sum)
R <- apply(SAux, 2, max)
#3. Q index
#If v=0
if (v==0)
Q <- (R-min(R))/(max(R)-min(R))
#If v=1
else if (v==1)
Q <- (S-min(S))/(max(S)-min(S))
#Another case
else
Q <- v*(S-min(S))/(max(S)-min(S))+(1-v)*(R-min(R))/(max(R)-min(R))
#4. Checking if Q is valid
#Here is the change by taking help from https://stackoverflow.com/questions/76667355/how-to-ignore-ranking-if-the-data-conatins-nan-or-inf-in-r
RankingQ = ifelse(is.infinite(Q) | is.na(Q), NA,
rank(Q, ties.method = "first"))
#5. Ranking the alternatives
return(data.frame(Alternatives = 1:nrow(decision), S = S, R = R, Q = Q,
Ranking = RankingQ))
}
Now it is working fine like
d <- matrix(c(1,2,5,3000,3750,4500),nrow = 3,ncol = 2)
w <- c(0.5,0.5)
cb <- c('min','max')
v <- 0.5
VIKOR(d,w,cb,v)
#> Alternatives S R Q Ranking
#> 1 1 0.500 0.50 1 2
#> 2 2 0.375 0.25 0 1
#> 3 3 0.500 0.50 1 3
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论