Illustrative example
pydaria - The Data Variability Based Multi-Criteria Assessment Method based on TOPSIS.
Import necessary Python packages and functions and classes from files .py provided in the repository.
[1]:
import os
import copy
import numpy as np
import pandas as pd
from topsis import TOPSIS
from weighting_methods import critic_weighting
from normalizations import minmax_normalization
from additions import rank_preferences
from daria import DARIA
Evaluate each investigated period of a multi-criteria problem using the TOPSIS method.
[2]:
# Temporal alternatives assessment using the DARIA-TOPSIS method based on the Gini coefficient
# variability measure.
# Load the name of the folder with CSV files, including data.
path = 'data'
# Create the list with years to be analyzed that are elements of data files names.
str_years = [str(y) for y in range(2015, 2020)]
# Create a list with latex symbols of evaluated alternatives.
list_alt_names = [r'$A_{' + str(i) + '}$' for i in range(1, 26 + 1)]
# Create dataframes for TOPSIS preferences and rankings for each evaluated year.
preferences = pd.DataFrame(index = list_alt_names)
rankings = pd.DataFrame(index = list_alt_names)
# Evaluate alternatives with the TOPSIS method for each year.
for el, year in enumerate(str_years):
# Load data from a CSV file for a given year.
file = 'data_' + str(year) + '.csv'
pathfile = os.path.join(path, file)
data = pd.read_csv(pathfile, index_col = 'Country')
# Create a dataframe with a decision matrix.
df_data = data.iloc[:len(data) - 1, :]
df_data = df_data.dropna()
# Create a vector with criteria types.
types = data.iloc[len(data) - 1, :].to_numpy()
#list_of_cols = list(df_data.columns)
matrix = df_data.to_numpy()
# Calculate criteria weights using the CRITIC weighting method.
weights = critic_weighting(matrix)
# Initialize the TOPSIS method object.
topsis = TOPSIS(normalization_method=minmax_normalization)
# Calculate the TOPSIS preferences.
pref = topsis(matrix, weights, types)
# Generate the TOPSIS ranking based on calculated preferences.
rank = rank_preferences(pref, reverse = True)
# Save the results in dataframes.
preferences[year] = pref
rankings[year] = rank
preferences = preferences.rename_axis('Ai')
rankings = rankings.rename_axis('Ai')
[3]:
preferences
[3]:
| 2015 | 2016 | 2017 | 2018 | 2019 | |
|---|---|---|---|---|---|
| Ai | |||||
| $A_{1}$ | 0.536617 | 0.564310 | 0.564186 | 0.566951 | 0.556542 |
| $A_{2}$ | 0.336071 | 0.341904 | 0.344725 | 0.352701 | 0.360289 |
| $A_{3}$ | 0.513457 | 0.532405 | 0.553370 | 0.556225 | 0.572631 |
| $A_{4}$ | 0.641617 | 0.634091 | 0.633293 | 0.636302 | 0.606583 |
| $A_{5}$ | 0.560061 | 0.564331 | 0.553587 | 0.556579 | 0.548127 |
| $A_{6}$ | 0.655833 | 0.655372 | 0.676693 | 0.665219 | 0.680685 |
| $A_{7}$ | 0.618126 | 0.626109 | 0.631761 | 0.640734 | 0.633131 |
| $A_{8}$ | 0.428431 | 0.426274 | 0.431958 | 0.455727 | 0.419436 |
| $A_{9}$ | 0.565934 | 0.577866 | 0.581817 | 0.568268 | 0.560081 |
| $A_{10}$ | 0.562669 | 0.558237 | 0.573749 | 0.570323 | 0.564944 |
| $A_{11}$ | 0.374091 | 0.383914 | 0.401308 | 0.417238 | 0.434746 |
| $A_{12}$ | 0.367327 | 0.407637 | 0.443797 | 0.492639 | 0.475463 |
| $A_{13}$ | 0.420014 | 0.436216 | 0.452832 | 0.438847 | 0.491315 |
| $A_{14}$ | 0.465913 | 0.534756 | 0.524740 | 0.556866 | 0.524790 |
| $A_{15}$ | 0.547372 | 0.542932 | 0.543019 | 0.557809 | 0.570196 |
| $A_{16}$ | 0.429350 | 0.439897 | 0.446668 | 0.555374 | 0.546059 |
| $A_{17}$ | 0.552229 | 0.555966 | 0.552767 | 0.541881 | 0.526681 |
| $A_{18}$ | 0.586706 | 0.605333 | 0.595225 | 0.623013 | 0.606277 |
| $A_{19}$ | 0.412392 | 0.411369 | 0.422224 | 0.431644 | 0.439477 |
| $A_{20}$ | 0.461474 | 0.474797 | 0.458370 | 0.470094 | 0.461408 |
| $A_{21}$ | 0.264324 | 0.263751 | 0.287022 | 0.310190 | 0.328480 |
| $A_{22}$ | 0.454640 | 0.474449 | 0.501216 | 0.521071 | 0.507532 |
| $A_{23}$ | 0.444292 | 0.476562 | 0.485190 | 0.540184 | 0.542270 |
| $A_{24}$ | 0.731059 | 0.755261 | 0.752157 | 0.743942 | 0.755265 |
| $A_{25}$ | 0.757916 | 0.721979 | 0.722802 | 0.700069 | 0.708976 |
| $A_{26}$ | 0.584717 | 0.573694 | 0.559438 | 0.537077 | 0.512966 |
[4]:
rankings
[4]:
| 2015 | 2016 | 2017 | 2018 | 2019 | |
|---|---|---|---|---|---|
| Ai | |||||
| $A_{1}$ | 13 | 10 | 9 | 9 | 11 |
| $A_{2}$ | 25 | 25 | 25 | 25 | 25 |
| $A_{3}$ | 14 | 15 | 12 | 13 | 7 |
| $A_{4}$ | 4 | 4 | 4 | 5 | 5 |
| $A_{5}$ | 10 | 9 | 11 | 12 | 12 |
| $A_{6}$ | 3 | 3 | 3 | 3 | 3 |
| $A_{7}$ | 5 | 5 | 5 | 4 | 4 |
| $A_{8}$ | 20 | 21 | 22 | 21 | 24 |
| $A_{9}$ | 8 | 7 | 7 | 8 | 10 |
| $A_{10}$ | 9 | 11 | 8 | 7 | 9 |
| $A_{11}$ | 23 | 24 | 24 | 24 | 23 |
| $A_{12}$ | 24 | 23 | 21 | 19 | 20 |
| $A_{13}$ | 21 | 20 | 19 | 22 | 19 |
| $A_{14}$ | 15 | 14 | 15 | 11 | 16 |
| $A_{15}$ | 12 | 13 | 14 | 10 | 8 |
| $A_{16}$ | 19 | 19 | 20 | 14 | 13 |
| $A_{17}$ | 11 | 12 | 13 | 15 | 15 |
| $A_{18}$ | 6 | 6 | 6 | 6 | 6 |
| $A_{19}$ | 22 | 22 | 23 | 23 | 22 |
| $A_{20}$ | 16 | 17 | 18 | 20 | 21 |
| $A_{21}$ | 26 | 26 | 26 | 26 | 26 |
| $A_{22}$ | 17 | 18 | 16 | 18 | 18 |
| $A_{23}$ | 18 | 16 | 17 | 16 | 14 |
| $A_{24}$ | 2 | 1 | 1 | 1 | 1 |
| $A_{25}$ | 1 | 2 | 2 | 2 | 2 |
| $A_{26}$ | 7 | 8 | 10 | 17 | 17 |
Calculate variability of scores (efficiencies) obtained in particular periods.
[5]:
# applying the DARIA method
# dataframe `preferences` includes preferences of alternatives for evaluated years
df_varia_fin = pd.DataFrame(index = list_alt_names)
# Create a matrix with preference values for each year
# and transpose it to have years in rows and alternatives in columns
df = preferences.T
matrix = df.to_numpy()
# the TOPSIS method orders preferences in descending order
met = 'topsis'
# Calculate efficiencies variability using DARIA methodology
# Initialize the DARIA method object
daria = DARIA()
# Calculate the variability of TOPSIS preferences in all years using the Gini coefficient.
var = daria._gini(matrix)
[6]:
var
[6]:
array([0.00981627, 0.01365081, 0.02084493, 0.0092742 , 0.00558907,
0.00857705, 0.00663363, 0.01448177, 0.00776515, 0.00546707,
0.03075309, 0.0582477 , 0.02844171, 0.02944662, 0.01004122,
0.05927294, 0.01017834, 0.01109442, 0.01425877, 0.00714317,
0.04823991, 0.0269947 , 0.04172446, 0.00639214, 0.01434414,
0.02602968])
Calculate variability direction.
[7]:
# Calculate variability directions
dir_list, dir_class = daria._direction(matrix)
[8]:
dir_class
[8]:
array([ 1., 1., 1., -1., -1., 1., 1., -1., -1., 1., 1., 1., 1.,
1., 1., 1., -1., 1., 1., -1., 1., 1., 1., 1., -1., -1.])
[9]:
# variability of preference values
df_varia_fin[met.upper() + ' var'] = list(var)
# directions of preferences variability
df_varia_fin[met.upper() + ' dir'] = list(dir_class)
df_varia_fin = df_varia_fin.rename_axis('Ai')
[10]:
df_varia_fin
[10]:
| TOPSIS var | TOPSIS dir | |
|---|---|---|
| Ai | ||
| $A_{1}$ | 0.009816 | 1.0 |
| $A_{2}$ | 0.013651 | 1.0 |
| $A_{3}$ | 0.020845 | 1.0 |
| $A_{4}$ | 0.009274 | -1.0 |
| $A_{5}$ | 0.005589 | -1.0 |
| $A_{6}$ | 0.008577 | 1.0 |
| $A_{7}$ | 0.006634 | 1.0 |
| $A_{8}$ | 0.014482 | -1.0 |
| $A_{9}$ | 0.007765 | -1.0 |
| $A_{10}$ | 0.005467 | 1.0 |
| $A_{11}$ | 0.030753 | 1.0 |
| $A_{12}$ | 0.058248 | 1.0 |
| $A_{13}$ | 0.028442 | 1.0 |
| $A_{14}$ | 0.029447 | 1.0 |
| $A_{15}$ | 0.010041 | 1.0 |
| $A_{16}$ | 0.059273 | 1.0 |
| $A_{17}$ | 0.010178 | -1.0 |
| $A_{18}$ | 0.011094 | 1.0 |
| $A_{19}$ | 0.014259 | 1.0 |
| $A_{20}$ | 0.007143 | -1.0 |
| $A_{21}$ | 0.048240 | 1.0 |
| $A_{22}$ | 0.026995 | 1.0 |
| $A_{23}$ | 0.041724 | 1.0 |
| $A_{24}$ | 0.006392 | 1.0 |
| $A_{25}$ | 0.014344 | -1.0 |
| $A_{26}$ | 0.026030 | -1.0 |
Calculate final aggregated alternatives efficiencies considering variability var (G), performance values from the most recent period S and variability direction dir.
[11]:
df_final_results = pd.DataFrame(index = list_alt_names)
# S = preferences['2019'].to_numpy()
S = matrix[-1, :]
G = copy.deepcopy(var)
dir = copy.deepcopy(dir_class)
# Update efficiencies using DARIA methodology.
# final updated preferences
final_S = daria._update_efficiency(S, G, dir)
[12]:
final_S
[12]:
array([0.56635855, 0.37394021, 0.59347605, 0.59730846, 0.54253799,
0.68926166, 0.63976447, 0.40495374, 0.55231592, 0.57041145,
0.4654987 , 0.53371068, 0.51975682, 0.55423646, 0.58023707,
0.60533184, 0.51650296, 0.61737164, 0.45373564, 0.4542645 ,
0.37671978, 0.53452679, 0.5839945 , 0.76165676, 0.69463228,
0.48693636])
Rank the alternatives in descending order, like in TOPSIS (the best alternative has the highest value of efficiency).
[13]:
# The TOPSIS ranking is prepared in descending order according to prefs.
rank = rank_preferences(final_S, reverse = True)
[14]:
rank
[14]:
array([12, 26, 8, 7, 15, 3, 4, 24, 14, 11, 21, 17, 18, 13, 10, 6, 19,
5, 23, 22, 25, 16, 9, 1, 2, 20])
[15]:
# Save aggregated final preference values and rankings.
df_final_results[met.upper() + ' pref'] = final_S
df_final_results[met.upper() + ' rank'] = rank
df_final_results = df_final_results.rename_axis('Ai')
[16]:
df_final_results
[16]:
| TOPSIS pref | TOPSIS rank | |
|---|---|---|
| Ai | ||
| $A_{1}$ | 0.566359 | 12 |
| $A_{2}$ | 0.373940 | 26 |
| $A_{3}$ | 0.593476 | 8 |
| $A_{4}$ | 0.597308 | 7 |
| $A_{5}$ | 0.542538 | 15 |
| $A_{6}$ | 0.689262 | 3 |
| $A_{7}$ | 0.639764 | 4 |
| $A_{8}$ | 0.404954 | 24 |
| $A_{9}$ | 0.552316 | 14 |
| $A_{10}$ | 0.570411 | 11 |
| $A_{11}$ | 0.465499 | 21 |
| $A_{12}$ | 0.533711 | 17 |
| $A_{13}$ | 0.519757 | 18 |
| $A_{14}$ | 0.554236 | 13 |
| $A_{15}$ | 0.580237 | 10 |
| $A_{16}$ | 0.605332 | 6 |
| $A_{17}$ | 0.516503 | 19 |
| $A_{18}$ | 0.617372 | 5 |
| $A_{19}$ | 0.453736 | 23 |
| $A_{20}$ | 0.454264 | 22 |
| $A_{21}$ | 0.376720 | 25 |
| $A_{22}$ | 0.534527 | 16 |
| $A_{23}$ | 0.583994 | 9 |
| $A_{24}$ | 0.761657 | 1 |
| $A_{25}$ | 0.694632 | 2 |
| $A_{26}$ | 0.486936 | 20 |
[ ]: