Skip to content

Example 20: Ranking methods compared

All ten crisp ranking methods run on one decision matrix with the same weights, and the rank table shows where they agree.

Source

examples/20_ranking_methods_compared.py
"""All ten crisp ranking methods on one decision matrix, printed as a rank table.

Five suppliers are judged on price (cost), quality, delivery and service (benefits).
TOPSIS, VIKOR, WASPAS, EDAS, CODAS, COPRAS, MARCOS, CoCoSo, WISP and ELECTRE use the
same weights, so the table shows where the methods agree and where they do not.
"""

from bulanik.mcdm import cocoso, codas, copras, edas, electre, marcos, topsis, vikor, waspas, wisp

alternatives = ["S1", "S2", "S3", "S4", "S5"]
criteria = ["price", "quality", "delivery", "service"]
types = ["cost", "benefit", "benefit", "benefit"]
weights = [0.35, 0.30, 0.20, 0.15]
matrix = [
    [120, 8, 7, 6],
    [100, 6, 8, 7],
    [140, 9, 6, 8],
    [90, 5, 9, 5],
    [110, 7, 7, 9],
]

methods = {
    "topsis": topsis,
    "vikor": vikor,
    "waspas": waspas,
    "edas": edas,
    "codas": codas,
    "copras": copras,
    "marcos": marcos,
    "cocoso": cocoso,
    "wisp": wisp,
    "electre": electre,
}
results = {
    name: fn(matrix, weights, types, alternatives=alternatives, criteria=criteria)
    for name, fn in methods.items()
}

print("rank table (1 = best)")
print(f"{'method':<8}" + "".join(f"{a:>5}" for a in alternatives) + "   best first")
for name, result in results.items():
    position = {a: i + 1 for i, a in enumerate(result.ranking)}
    print(f"{name:<8}" + "".join(f"{position[a]:>5}" for a in alternatives) + "   " + " > ".join(result.ranking))

winners = {name: r.ranking[0] for name, r in results.items()}
print("winners:", winners)

assert len(results) == 10 and all(len(r.ranking) == 5 for r in results.values())
assert all(sorted(r.ranking) == alternatives for r in results.values())
# nine of ten methods put S5 first; CODAS, which is driven by distance from the
# negative-ideal solution, prefers S4 (cheapest, weakest quality)
assert [n for n, w in winners.items() if w == "S5"] == [n for n in methods if n != "codas"]
assert winners["codas"] == "S4"
assert results["topsis"].ranking == ("S5", "S1", "S2", "S3", "S4")
assert results["copras"].ranking == ("S5", "S2", "S3", "S4", "S1")
assert results["electre"].ranking == ("S5", "S2", "S1", "S4", "S3")

Output

Run when this page is built:

rank table (1 = best)
method     S1   S2   S3   S4   S5   best first
topsis      2    3    4    5    1   S5 > S1 > S2 > S3 > S4
vikor       4    2    5    3    1   S5 > S2 > S4 > S1 > S3
waspas      5    2    3    4    1   S5 > S2 > S3 > S4 > S1
edas        5    2    4    3    1   S5 > S2 > S4 > S3 > S1
codas       5    4    2    1    3   S4 > S3 > S5 > S2 > S1
copras      5    2    3    4    1   S5 > S2 > S3 > S4 > S1
marcos      5    2    4    3    1   S5 > S2 > S4 > S3 > S1
cocoso      3    2    5    4    1   S5 > S2 > S1 > S4 > S3
wisp        4    2    5    3    1   S5 > S2 > S4 > S1 > S3
electre     3    2    5    4    1   S5 > S2 > S1 > S4 > S3
winners: {'topsis': 'S5', 'vikor': 'S5', 'waspas': 'S5', 'edas': 'S5', 'codas': 'S4', 'copras': 'S5', 'marcos': 'S5', 'cocoso': 'S5', 'wisp': 'S5', 'electre': 'S5'}

What to notice

  • Nine methods put S5 first; CODAS prefers S4 because it ranks by distance from the negative-ideal solution.
  • VIKOR ranks by ascending Q, but its ranking still lists the best alternative first, like every other method.
  • The methods share one call shape, so swapping one for another is a one-word change.

Go further

Run it yourself: python examples/20_ranking_methods_compared.py.