Fundamentals 11 min read

Mastering ELECTRE: A Step-by-Step Guide to Multi-Criteria Decision Making with Python

This article introduces the ELECTRE multi-criteria decision analysis method, outlines its standard and improved procedures, and provides a complete Python implementation with sample data, demonstrating how to normalize criteria, compute concordance and discordance matrices, and derive preference rankings.

Model Perspective
Model Perspective
Model Perspective
Mastering ELECTRE: A Step-by-Step Guide to Multi-Criteria Decision Making with Python

ELECTRE Evaluation Method

ELECTRE (elimination et choice translating reality) is a multi-criteria decision analysis method that supports decision makers by comparing alternatives.

The basic idea is to compare alternatives against criteria to assess relative performance. The method uses elimination and choice steps: elimination filters out clearly unsuitable alternatives based on performance scores, and choice ranks the remaining alternatives.

ELECTRE consists of the following steps:

Define decision criteria and their weights.

Collect and preprocess data, normalizing performance values for comparison.

Construct the decision matrix (alternatives as rows, criteria as columns).

Build concordance and discordance matrices: the concordance matrix measures the degree to which one alternative is at least as good as another across criteria; the discordance matrix measures the degree of disagreement.

Determine priority indices and rank alternatives, selecting the highest‑ranked alternative as the final decision.

The method’s advantages include handling multiple criteria and interactions, while its drawbacks are computational intensity and subjectivity in weight and threshold selection.

Improved ELECTRE Method

An improved version of ELECTRE (see references) follows these steps:

Construct a decision matrix based on evaluation items.

Normalize the matrix to obtain a standardized matrix.

Apply criteria weights to produce a weighted decision matrix.

For each pair of alternatives, partition criteria into a concordance set (weights where the weighted score of the first alternative is not lower) and a discordance set (weights where it is lower).

From the concordance set, build a concordance matrix indicating the relative strength of criteria weights.

From the discordance set, build a discordance matrix reflecting relative weakness.

Combine concordance and discordance matrices into a comprehensive dominance matrix.

Compute a net dominance index for each alternative.

Rank alternatives by descending net dominance and select the best.

Python Implementation

We evaluate the following data (higher values are better) using range transformation for normalization:

<code>Alternative 1: [6, 8, 9]
Alternative 2: [7, 6, 8]
Alternative 3: [8, 7, 6]</code>

Code:

<code>import numpy as np

# Normalization function
def normalize(x):
    return (x - x.min(axis=0)) / (x.max() - x.min())

# Concordance matrix
def compute_H(x, w):
    """Calculate concordance values between each pair of alternatives."""
    n, m = x.shape
    v = np.zeros((n, n))
    for i in range(n):
        for j in range(n):
            if i == j:
                continue
            numerator = 0
            denominator = 0
            for k in range(m):
                numerator += w[k] * (x[i, k] >= x[j, k])
                denominator += w[k]
            v[i][j] = numerator / denominator
    return v

# Discordance matrix
def compute_B(x, w):
    """Calculate discordance values between each pair of alternatives."""
    n, m = x.shape
    v = np.zeros((n, n))
    for i in range(n):
        for j in range(n):
            if i == j:
                continue
            max_num = 0
            max_den = 0
            for k in range(m):
                numerator = np.abs((w[k] * x[i, k] - w[k] * x[j, k]) * (x[i, k] < x[j, k]))
                denominator = np.abs(w[k] * x[i, k] - w[k] * x[j, k])
                if numerator > max_num:
                    max_num = numerator
                if denominator > max_den:
                    max_den = denominator
            v[i][j] = max_num / max_den
    return v

def compute_E(H_matrix, B_matrix):
    return H_matrix - B_matrix

def determine_preference(E_matrix):
    n = E_matrix.shape[0]
    v = np.zeros(n)
    for k in range(n):
        for i in range(n):
            if k != i:
                v[k] += E_matrix[k, i] - E_matrix[i, k]
    return v

# Example
x = np.array([[6, 8, 9],
              [7, 6, 8],
              [8, 7, 6]])
w = np.array([0.4, 0.3, 0.3])

x_norm = normalize(x)
H_matrix = compute_H(x, w)
B_matrix = compute_B(x, w)
E_matrix = compute_E(H_matrix, B_matrix)
p = determine_preference(E_matrix)
</code>

The code first normalizes the data, then computes concordance (H) and discordance (B) matrices, derives the net preference matrix (E), and finally obtains a preference vector indicating the ranking of alternatives.

Resulting preference scores:

<code>array([ 0.84444444, -0.6       , -0.24444444])</code>

Reference:

Cheng Zhiyu, Zhu Xiaohu, Li Jianqing. “Improved ELECTRE method for multi-criteria fusion decision in power grid planning investment,” China Electric, 2022, 55(11):59-65.

optimizationpythondecision makingELECTREmulti-criteria decision analysis
Model Perspective
Written by

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".

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.