Master Multi‑Criteria Decisions with VIKOR: Steps, Code, and TOPSIS Comparison
This article introduces the VIKOR multi‑criteria decision‑making method, explains its core concepts, outlines each computational step, compares it with TOPSIS, presents a real‑world energy‑saving case study, and provides a complete Python implementation.
Introduction to VIKOR
Opricovic introduced the VIKOR decision‑making method in 1998 as a compromise ranking technique that maximizes group utility while minimizing individual regret, suitable when decision makers cannot precisely express preferences, criteria are conflicting or incommensurable, and a compromise solution is acceptable.
Basic Concept
The method identifies a positive ideal solution (PIS) and a negative ideal solution (NIS) and evaluates each alternative by its distance to these ideals; the PIS contains the best values of each criterion, the NIS the worst.
Basic Steps
Define the set of criteria and their weights.
Standardize the decision matrix to remove dimensional effects, distinguishing benefit (higher is better) and cost (lower is better) criteria.
Compute group utility (S) and individual regret (R) for each alternative.
Calculate the compromise index Q using a coefficient v that balances S and R.
Rank alternatives by ascending Q; the smaller the value, the better.
Step 1: Standardization
Benefit criteria are normalized by dividing each value by the maximum, while cost criteria are normalized by dividing the minimum by each value.
Step 2: Determine group utility and individual regret
For each criterion column, the maximum and minimum of the standardized matrix are used to compute S and R.
Step 3: Compute the compromise decision index
The index Q combines S and R with a coefficient v (0 ≤ v ≤ 1) that reflects the decision maker’s emphasis on group utility versus individual regret.
Step 4: Rank alternatives and identify compromise solutions
Alternatives are ordered by increasing Q; the top alternatives form the compromise set.
Comparison with TOPSIS
Aggregation function: TOPSIS uses simple distance sums, while VIKOR adds a weighting factor v to balance proximity to PIS and distance from NIS.
Subjectivity: VIKOR incorporates a decision‑making coefficient, allowing more aggressive or conservative choices, whereas TOPSIS is purely objective.
Solution set: VIKOR can produce a set of compromise alternatives with priority levels, while TOPSIS yields a single optimal solution.
Case Study: Energy‑saving Renovation of Existing Buildings
An evaluation index system is applied to assess retrofit options.
Python Implementation
<code>from numpy import *
import matplotlib.pyplot as plt
# Step 1: determine the best and worst values for all
# criteria functions
def best_worst_fij(a, b):
"""
a is the array with the performances and b is
the criteria min/max array
"""
f = zeros((b.shape[0], 2))
for i in range(b.shape[0]):
if b[i] == 'max':
f[i, 0] = a.max(0)[i]
f[i, 1] = a.min(0)[i]
elif b[i] == 'min':
f[i, 0] = a.min(0)[i]
f[i, 1] = a.max(0)[i]
return f
# Step 2: compute the values S_i and R_i
def SR(a, b, c):
"""
a is the array with the performances, b is the
array with the best and worst performances, and
c is the criteria min/max array
"""
s = zeros(a.shape[0])
r = zeros(a.shape[0])
for i in range(a.shape[0]):
k = 0
o = 0
for j in range(a.shape[1]):
k = k + c[j] * (b[j, 0] - a[i, j]) / (b[j, 0] - b[j, 1])
u = c[j] * (b[j, 0] - a[i, j]) / (b[j, 0] - b[j, 1])
if u > o:
o = u
r[i] = round(o, 3)
else:
r[i] = round(o, 3)
s[i] = round(k, 3)
return s, r
# Step 3: compute the values Q_i
def Q(s, r, n):
"""
s is the vector with the S_i values, r is
the vector with the R_i values, and n is the
number of criteria
"""
q = zeros(s.shape[0])
for i in range(s.shape[0]):
q[i] = round((((n + 1) / (2 * n)) * (s[i] - min(s)) / (max(s) - min(s)) +
(1 - (n + 1) / (2 * n)) * (r[i] - min(r)) / (max(r) - min(r))), 3)
return q
# VIKOR method: it calls the other functions
def vikor(a, b, c, pl):
""" a is the decision matrix, b is the criteria
min/max array, c is the weights matrix, and
pl is 'y' for plotting the results or any other
string for not
"""
s, r = SR(a, best_worst_fij(a, b), c)
q = Q(s, r, len(c))
if pl == 'y':
e = [i + 1 for i in range(a.shape[0])]
plt.plot(e, s, 'p--', color='red', markeredgewidth=2, markersize=8)
plt.text(0.02, 0.5, '123', fontsize=14)
plt.plot(e, r, '*--', color='blue', markeredgewidth=2, markersize=8)
plt.plot(e, q, 'o--', color='green', markeredgewidth=2, markersize=8)
plt.xticks(range(a.shape[0] + 2))
plt.axis([0, a.shape[0] + 1, 0, max(maximum(maximum(s, r), q)) + 0.3])
plt.title("VIKOR results")
text = "Alternatives \n s:{} \n r:{}\n q:{}".format(s, r, q)
plt.xlabel("Alternatives")
plt.legend(['S', 'R', 'Q'])
plt.grid(True)
plt.show()
plt.savefig('test.png')
return s, r, q
# performances of the alternatives
x = array([[8, 7, 2, 1], [5, 3, 7, 5], [7, 5, 6, 4],
[9, 9, 7, 3], [11, 10, 3, 7], [6, 9, 5, 4], [6, 9, 5, 4]])
# weights of the criteria
w = array([0.4, 0.3, 0.1, 0.2])
# criteria max/min
crit_max_min = array(['max', 'max', 'max', 'max'])
# final results
vikor(x, crit_max_min, w, 'n')
s, r, q = vikor(x, crit_max_min, w, 'y')
print("S = ", s)
print("R = ", r)
print("Q = ", q)
</code>Model Perspective
Insights, knowledge, and enjoyment from a mathematical modeling researcher and educator. Hosted by Haihua Wang, a modeling instructor and author of "Clever Use of Chat for Mathematical Modeling", "Modeling: The Mathematics of Thinking", "Mathematical Modeling Practice: A Hands‑On Guide to Competitions", and co‑author of "Mathematical Modeling: Teaching Design and Cases".
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.