Deep dive into Analytical Hierarchy Process using Python | by Anirudh Chandra | Towards Data Science

Through the course of a lifetime, a human makes a number of decisions, ranging from the most trivial ones that have almost no impact, to those that have life changing consequences. And almost always, these situations involve X number of options and Y number of criteria that they are judged on.
Imagine you are out at the supermarket and you want to buy breakfast cereals. You are standing in front of rows and rows of cereals and not sure which one to buy. So what are you looking for?
Price: The cereal must not be too priceyFlavor: Maybe something with chocolate in it?Nutrition: Something with mixed fruits or oats.
Price: The cereal must not be too pricey
Flavor: Maybe something with chocolate in it?
Nutrition: Something with mixed fruits or oats.
These are some of the criteria you think of when you browse through the products. Let’s say you pick up Fruit Loops, Frosted Flakes and Lucky Charm. You mentally run each of them through the criteria and compare them against each other. Then you make a decision and put Frosted Flakes in your cart.
You are running a meeting at a town hall in a little village in Ghana. As the head of The Water Project delegation, you have been tasked to install a series of water pumps in the village. In front of you are the various stakeholders — village elders, geologists and engineers.
In this meeting you would like to select spots for setting up the water pumps and you list out a set of criteria —
Groundwater level: The spot must have a groundwater level that is reasonably high;Population: There must be a minimum number of people living nearby to make the installation useful;Cost: The cost of running materials and supplies must be within the project funds.
Groundwater level: The spot must have a groundwater level that is reasonably high;
Population: There must be a minimum number of people living nearby to make the installation useful;
Cost: The cost of running materials and supplies must be within the project funds.
You talk to the village elders, geologists and engineers and draw up a set of 15 possible locations to build the water pumps. After much discussion and weighing of opinions, you narrow it down to 5 spots that rank high in the list of selection criteria.
Although these two examples were vastly different in their scale of impact and domain of application, the problem was pretty much the same — Making a decision in the face of multiple, often conflicting, criteria.
In this post, I will provide a high level explanation of Analytical Hierarchy Process — one possible technique of solving such multi-criteria decision making problems. And in the process, I will also show you how to implement this technique, from scratch, in Python.
Analytical Hierarchy Process is a multi-criteria decision making method introduced by Prof. Thomas Saaty in the 1970s.
It is a way to help decision makers make informed decisions by quantifying subjective beliefs within a mathematical framework.
AHP is all about relative measurements of different quantities and is at the intersection of the field of decision analysis and operational research.
AHP is popular in a number of fields, ranging from supply chain, to sustainable systems, environmental management, portfolio selection etc. Its popularity stems from the fact that it is highly intuitive and allows the decision maker(s) to codify their subjective beliefs in a transparent manner.
AHP, essentially, is the process of assigning different weights to different options and summing them up. However, the beauty is in the way these weights are arrived at and therein lies the quantification of subjective beliefs.
Let me briefly present to you the highly intuitive process of AHP —
Step 1: Define the ultimate goal of the process. In the examples shared above, the goals were buying a breakfast cereal and selecting suitable installation spots respectively;
Step 2: List the various options you have in hand to fulfill the goal. These options are called ‘alternatives’.
Step 3: List out the different criteria by which you assess the above alternatives. These can involve sub-levels of criteria and is totally dependent on the amount of scrutiny you want, especially when the options are very similar to each other.
Step 4: Build the Hierarchy from Steps 1 to 3. If you are familiar with graph theory, then you can imagine this to be a directed acyclic graph. The connections between each node implies their consideration in the assessment.
Step 5: Pair-wise comparison of each criteria and sub-criteria to establish their weights.
Step 6: Pair-wise comparison of each alternatives against each sub-criteria to establish their weights.
Step 7: Global summation of all these weights (weighted arithmetic sum) for each alternative and ordering them on the basis of this weighted sum.
Step 8: Calculate the consistency ratio. This is a measure of how consistent the subjective assessment is, when compared to a table of critical values. If found inconsistent, go back to Step 5.
So from these steps, you can see how the process got its name and why it is so popular in terms of its application. Now, let’s have a look at the heart of this process — the quantification of subjective beliefs.
The key-word of AHP is pair-wise comparison. We all know how difficult it is to compare more than three options at a time. To eliminate this difficulty, Prof. Saaty suggested a pair-wise comparison of alternatives/criteria. And this comparison/evaluation is done by assigning intensities that represent various degree of importance, which he defined linguistically [3].
The evaluated/assessed alternatives are compiled into a n x n pair-wise comparison matrix A,for each criteria/sub-criteria/goal [1].
Here, the wi and wj are the weights or intensities of importance from the previous table. You can immediately see that the assessment matrix is symmetric, making computation easier.
Once you create the assessment matrix, the next step is to convert it into vector. This vector encodes the information present in the matrix and is called the priority vector.
There are a few ways in which you can calculate this priority vector. One way is to obtain the Perron-Frobenius eigenvector [4], or simply the normalized eigenvector of the matrix. The other way is to calculate the geometric mean of the elements on the respective row divided by a normalization term so that the components of the priority vector eventually add up to 1 [1]. This method is an approximation of the normalized eigenvector method.
The final step of the assessment is the weighted arithmetic sum of the priority vectors generated for each sub-criterion and ordering them to rank the alternatives.
The underlying assumption in AHP is that the decision makers are rational. This basically means that the decision maker is assumed to apply the same subjective beliefs every time for the same problem. However, in reality, this may not be the case. Prof. Saaty took care of this uncertainty by proposing a consistency index, CI
Where lambda_max is the maximum eigen value of the pair-wise comparison matrix and n is the number of alternatives.
To scale for different size matrices, the Consistency Ratio was developed, CR
Where, RI_n is an average estimate of the CI obtained from a large enough set of randomly generated matrices of size n. The look-up table for RI_n are given by Prof. Saaty as,
How to use the CR? — According to Prof. Saaty, in practice, one should accept matrices with CR ≤ 0.1 and reject values greater than 0.1. A value of CR = 0.1 basically means that the judgments are 10% as inconsistent as if they had been given randomly. By choosing a lower CR, one could try to reduce this inconsistency, and the only way to do that is to go back and re-evaluate the subjective weights.
Phew, that was a lot of theory, so let’s get on with its implementation in Python for a simple use-case
As far as I know there is only one well developed python library out there for AHP — pyAHP, but let’s write the code from scratch using the process described before. Here, I will use a typical use-case from [1] to illustrate the process. (Truth be told, it is pretty easy to implement in Excel!)
Code can be found on my GitHub repository
Let’s imagine you want to travel to Europe on a holiday and you plan on visiting a few interesting cities. You have a few cities in mind — Madrid, Hamburg and Paris, but your budget only allows you to visit one of those. To help you get maximum bang for your buck, you decide to use AHP to help you narrow down on a suitable city.
The overall goal is obviously your personal satisfaction. The alternatives are {Rome, Madrid, Paris} and let us imagine you select the following criteria to assess each city — {Climate, Sightseeing, Environment}. Let us build the Hierarchy -
Alright, so let's begin the assessment process by importing just two libraries
import numpy as npimport pandas as pd
We exploit the symmetric nature of the comparison matrix and take input only for the upper triangular matrix.
# Number of optionsn = 3# Creating default matrix of onesA = np.ones([n,n])# Running a for loop to take input from user and populate the upper triangular elementsfor i in range(0,n):    for j in range(0,n):         if i<j:             aij = input('How important is option{} over option{} ?: '.format(i,j))             A[i,j] = float(aij) #Upper triangular elements             A[j,i] = 1/float(aij) #Lower triangular elements
Remember, our criteria set was {Climate, Sightseeing, Environment}, so option 0 is Climate, option 1 is Sightseeing and option 2 is Environment. We run this piece of code to generate pair-wise comparison matrix for the criteria weights.
How important is option0 over option1 ?: 0.5How important is option0 over option2 ?: 0.25How important is option1 over option2 ?: 0.5
This can be interpreted as —
‘Climate is twice as less important than Sightseeing opportunities and four times less important than the Environment in the city. Sightseeing opportunities are twice as less important than the Environment in the city’
Once the matrix is generated, we compute the priority vector by normalizing the eigen vector of the largest eigen value. The elements in this eigen vector are the weights of the criteria.
e = np.linalg.eig(A)[1][:,0]p = e/e.sum()>>> array([0.14285714, 0.28571429, 0.57142857])
The two pieces of code are combined into a function
def pairwise_matrix(n):A = np.ones([n,n])    for i in range(0,n):        for j in range(0,n):            if i<j:                aij = input('How important is option{} over option{} ?: '.format(i,j))                A[i,j] = float(aij)                A[j,i] = 1/float(aij)#Computing the priority vector     eig_val = np.linalg.eig(A)[0].max()    eig_vec = np.linalg.eig(A)[1][:,0]    p = eig_vec/eig_vec.sum()    return p, eig_val
We call this function for generating pair-wise comparison matrices and priority vectors for assessing each of the alternative against each criterion. Remember our alternatives set was — {Rome, Madrid, Paris}.
The priority vectors for each of the matrix are —
pr_c = pairwise_matrix(3)[0]  #All Criteriapr_c0 = pairwise_matrix(3)[0] #Criteria 0: Climatepr_c1 = pairwise_matrix(3)[0] #Criteria 1: Sightseeingpr_c2 = pairwise_matrix(3)[0] #Criteria 2: Environment#Priority Vector for Criteria 0 pr_c0>>> array([0.44444444, 0.44444444, 0.11111111])#Priority Vector for Criteria 1 pr_c1>>> array([0.6, 0.3, 0.1])#Priority Vector for Criteria 2pr_c2>>> array([0.09090909, 0.18181818, 0.72727273])
We also calculate the Consistency Ratio for each of these comparison matrices. For n= 3, the RI_n would be 0.5247. The maximum eigen value across all the matrices was 3. Therefore, by the earlier formula, the CR would be 0 for each of the matrix, which is < 0.1 and hence acceptable.
The final step is to get their weighted arithmetic sum to yield the rank vector
r = pr_c0*pr_c[0] + pr_c1*pr_c[1] + pr_c2*pr_c[2]print(r)>>> [0.28686869 0.25310245 0.46002886]
The weighted arithmetic sum for Paris is much higher than Rome or Madrid, so it is assigned rank1, followed by Rome and Madrid.
There you go! With the help of AHP, you successfully managed to quantify your subjective analysis and decided to fly to Paris!
The major flaw with AHP is the rank reversals of alternatives when evaluated by a different group of people. The other issue is with the philosophical basis of including it in operational research.
Having said that, AHP is still a popular MCDM method and relatively easy to implement and interpret. Apart from python, there are a few commercial softwares such as SuperDecisions that help you create the hierarchy and perform pairwise evaluations.
There are many more MCDM methods to cater to the shortcomings of AHP and are more advanced in terms of their mathematical foundations. Some that come to mind are PROMETHEE, TOPSIS, etc.
[1] Brunelli, Matteo. 2015. Introduction to the Analytic Hierarchy Process. SpringerBriefs in Operations Research. P. 83. 978–3–319–12502–2 (electronic).10.1007/978–3–319–12502–2.
[2] https://en.wikipedia.org/wiki/Analytic_hierarchy_process_%E2%80%93_car_example
[3] T.L. Saaty, Decision making with the analytic hierarchy process. Int. J. Services Sciences, Vol. 1, No1, 2008
[4]https://en.wikipedia.org/wiki/Perron%E2%80%93Frobenius_theorem
I hope you found this post helpful and feedback is always appreciated!