Usage
Installation
To use crispyn package, first install it using pip:
pip install crispyn
Usage examples
The VIKOR method
The VIKOR method provided in this library can be used with single weight vector and with multiple weight vectors, like in the Stochastic Multicriteria Acceptability Analysis (SMAA) method.
Using the VIKOR method with single weight vector:
import numpy as np
from crispyn.mcda_methods import VIKOR
from crispyn.additions import rank_preferences
# Provide decision matrix in array numpy.darray.
matrix = np.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]])
# Provide criteria weights in array numpy.darray. All weights must sum to 1.
weights = np.array([0.4, 0.3, 0.1, 0.2])
# Provide criteria types in array numpy.darray. Profit criteria are represented by 1, and cost criteria by -1.
types = np.array([1, 1, 1, 1])
# Create the VIKOR method object providing `v` parameter. The default `v` parameter is set to 0.5, so if you do not provide it, `v` will be equal to 0.5.
vikor = VIKOR(v = 0.625)
# Calculate the VIKOR preference values of alternatives.
pref = vikor(matrix, weights, types)
# Generate ranking of alternatives by sorting alternatives ascendingly according to the VIKOR algorithm (reverse = False means sorting in ascending order) according to preference values.
rank = rank_preferences(pref, reverse = False)
print('Preference values: ', np.round(pref, 4))
print('Ranking: ', rank)
Output
Preference values: [[0.6399]
[1. ]
[0.6929]
[0.2714]
[0. ]
[0.6939]]
Ranking: [3 6 4 2 1 5]
The VIKOR method provided in the crispyn library can also be used with multiple weight vectors provided in the matrix. This matrix
includes weight vectors in rows. The number of rows is equal to the vectors number, and the number of columns is equal to the criteria number. In this case,
the VIKOR method returns a matrix with preference values. Vectors with preference values for each weight vector are contained in each column. The number
of rows of the matrix with preference values is equal to the number of alternatives, and the number of columns is equal to the number of weight vectors.
This functionality is useful for Stochastic Multicriteria Acceptability Analysis (SMAA) methods. Here is demonstrated how it works using the VIKOR method
with multiple weight vectors.
import numpy as np
from crispyn.additions import rank_preferences
from crispyn.mcda_methods import VIKOR, VIKOR_SMAA
matrix = np.array([[256, 8, 41, 1.6, 1.77, 7347.16],
[256, 8, 32, 1.0, 1.8, 6919.99],
[256, 8, 53, 1.6, 1.9, 8400],
[256, 8, 41, 1.0, 1.75, 6808.9],
[512, 8, 35, 1.6, 1.7, 8479.99],
[256, 4, 35, 1.6, 1.7, 7499.99]])
n = matrix.shape[1]
iterations = 10
types = np.array([1, 1, 1, 1, -1, -1])
vikor_smaa = VIKOR_SMAA()
weight_vectors = vikor_smaa._generate_weights(n, iterations)
vikor = VIKOR()
pref = vikor(matrix, weight_vectors, types)
print(pref)
Output
Preference values: [[0.09618783 0.27346371 0.09902209 0.16314653 0.58629107 0.01900846
0.85270574 0.28086327 0.24628691 0.05633723]
[1. 0.40327448 1. 1. 1. 1.
0.97327618 0.29458204 0.94333641 1. ]
[0.28701119 1. 0.55618621 0.231067 0.57237663 0.52735721
0.95398644 0.29797528 0. 0.41316479]
[0.85675331 0.21838546 0.8992903 0.89447867 0.95984659 0.89945467
0.8867631 0.27612402 0.32504461 0.89805712]
[0.03792154 0. 0. 0. 0. 0.22357098
0. 0. 0.50907579 0.01255136]
[0.42033457 0.34191157 0.30924524 0.30984365 0.64516556 0.02140185
1. 1. 0.86570054 0.05526169]]
Matrix with preference values includes subsequent vectors with preference values in columns. We can rank preferences in this matrix
using the rank_preferences method in following way:
rank = np.zeros((pref.shape))
for i in range(pref.shape[1]):
rank[:, i] = rank_preferences(pref[:, i], reverse = False)
print('Rankings: ', rank)
Output
Rankings: [[2. 3. 2. 4. 1. 2. 2. 1. 1. 4.]
[5. 5. 5. 3. 6. 5. 4. 5. 4. 5.]
[3. 6. 4. 6. 3. 4. 5. 3. 6. 6.]
[4. 4. 1. 2. 2. 3. 1. 2. 3. 2.]
[1. 1. 3. 1. 5. 1. 6. 4. 5. 1.]
[6. 2. 6. 5. 4. 6. 3. 6. 2. 3.]]
Now each column of the above matrix contains a ranking generated for each weight vector.
Correlation coefficents
Spearman correlation coefficient
import numpy as np
from crispyn import correlations as corrs
# Provide two vectors with rankings obtained with different MCDA methods.
R = np.array([1, 2, 3, 4, 5])
Q = np.array([1, 3, 2, 4, 5])
# Calculate the correlation using `spearman` coefficient.
coeff = corrs.spearman(R, Q)
print('Spearman coeff: ', np.round(coeff, 4))
Output
Spearman coeff: 0.9
Weighted Spearman correlation coefficient
import numpy as np
from crispyn import correlations as corrs
# Provide two vectors with rankings obtained with different MCDA methods.
R = np.array([1, 2, 3, 4, 5])
Q = np.array([1, 3, 2, 4, 5])
# Calculate the correlation using `weighted_spearman` coefficient.
coeff = corrs.weighted_spearman(R, Q)
print('Weighted Spearman coeff: ', np.round(coeff, 4))
Output
Weighted Spearman coeff: 0.8833
Pearson correlation coefficient
import numpy as np
from crispyn import correlations as corrs
# Provide two vectors with rankings obtained with different MCDA methods.
R = np.array([1, 2, 3, 4, 5])
Q = np.array([1, 3, 2, 4, 5])
# Calculate the correlation using `pearson_coeff` coefficient.
coeff = corrs.pearson_coeff(R, Q)
print('Pearson coeff: ', np.round(coeff, 4))
Output
Pearson coeff: 0.9
Objective methods for criteria weights determination
Entropy weighting method
import numpy as np
from crispyn import weighting_methods as mcda_weights
matrix = np.array([[30, 30, 38, 29],
[19, 54, 86, 29],
[19, 15, 85, 28.9],
[68, 70, 60, 29]])
weights = mcda_weights.entropy_weighting(matrix)
print('Entropy weights: ', np.round(weights, 4))
Output
Entropy weights: [0.463 0.3992 0.1378 0. ]
CRITIC weighting method
import numpy as np
from crispyn import weighting_methods as mcda_weights
matrix = np.array([[5000, 3, 3, 4, 3, 2],
[680, 5, 3, 2, 2, 1],
[2000, 3, 2, 3, 4, 3],
[600, 4, 3, 1, 2, 2],
[800, 2, 4, 3, 3, 4]])
weights = mcda_weights.critic_weighting(matrix)
print('CRITIC weights: ', np.round(weights, 4))
Output
CRITIC weights: [0.157 0.2495 0.1677 0.1211 0.1541 0.1506]
Standard deviation weighting method
import numpy as np
from crispyn import weighting_methods as mcda_weights
matrix = np.array([[0.619, 0.449, 0.447],
[0.862, 0.466, 0.006],
[0.458, 0.698, 0.771],
[0.777, 0.631, 0.491],
[0.567, 0.992, 0.968]])
weights = mcda_weights.std_weighting(matrix)
print('Standard deviation weights: ', np.round(weights, 4))
Output
Standard deviation weights: [0.2173 0.2945 0.4882]
Equal weighting method
import numpy as np
from crispyn import weighting_methods as mcda_weights
matrix = np.array([[0.619, 0.449, 0.447],
[0.862, 0.466, 0.006],
[0.458, 0.698, 0.771],
[0.777, 0.631, 0.491],
[0.567, 0.992, 0.968]])
weights = mcda_weights.equal_weighting(matrix)
print('Equal weights: ', np.round(weights, 3))
Output
Equal weights: [0.333 0.333 0.333]
Gini coefficient-based weighting method
import numpy as np
from crispyn import weighting_methods as mcda_weights
matrix = np.array([[29.4, 83, 47, 114, 12, 30, 120, 240, 170, 90, 1717.75],
[30, 38.1, 124.7, 117, 16, 60, 60, 60, 93, 70, 2389],
[29.28, 59.27, 41.13, 58, 16, 30, 60, 120, 170, 78, 239.99],
[33.6, 71, 55, 159, 23.6, 60, 240, 240, 132, 140, 2099],
[21, 59, 41, 66, 16, 24, 60, 120, 170, 70, 439],
[35, 65, 42, 134, 12, 60, 240, 240, 145, 60, 1087],
[47, 79, 54, 158, 19, 60, 120, 120, 360, 72, 2499],
[28.3, 62.3, 44.9, 116, 12, 30, 60, 60, 130, 90, 999.99],
[36.9, 28.6, 121.6, 130, 12, 60, 120, 120, 80, 80, 1099],
[32, 59, 41, 60, 16, 30, 120, 120, 170, 60, 302.96],
[28.4, 66.3, 48.6, 126, 12, 60, 240, 240, 132, 135, 1629],
[29.8, 46, 113, 47, 18, 50, 50, 50, 360, 72, 2099],
[20.2, 64, 80, 70, 8, 24, 60, 120, 166, 480, 699.99],
[33, 60, 44, 59, 12, 30, 60, 120, 170, 90, 388],
[29, 59, 41, 55, 16, 30, 60, 120, 170, 120, 299],
[29, 59, 41, 182, 12, 30, 30, 60, 94, 140, 249],
[29.8, 59.2, 41, 65, 16, 30, 60, 120, 160, 90, 219.99],
[28.8, 62.5, 41, 70, 12, 60, 120, 120, 170, 138, 1399.99],
[24, 40, 59, 60, 12, 10, 30, 30, 140, 78, 269.99],
[30, 60, 45, 201, 16, 30, 30, 30, 170, 90, 199.99]])
weights = mcda_weights.gini_weighting(matrix)
print('Gini coefficient-based weights: ', np.round(weights, 4))
Output
Gini coefficient-based weights: [0.0362 0.0437 0.0848 0.0984 0.048 0.0842 0.1379 0.1125 0.0745 0.1107 0.169 ]
MEREC weighting method
import numpy as np
from crispyn import weighting_methods as mcda_weights
matrix = np.array([[450, 8000, 54, 145],
[10, 9100, 2, 160],
[100, 8200, 31, 153],
[220, 9300, 1, 162],
[5, 8400, 23, 158]])
types = np.array([1, 1, -1, -1])
weights = mcda_weights.merec_weighting(matrix, types)
print('MEREC weights: ', np.round(weights, 4))
Output
MEREC weights: [0.5752 0.0141 0.4016 0.0091]
Statistical variance weighting method
import numpy as np
from crispyn import weighting_methods as mcda_weights
matrix = np.array([[0.619, 0.449, 0.447],
[0.862, 0.466, 0.006],
[0.458, 0.698, 0.771],
[0.777, 0.631, 0.491],
[0.567, 0.992, 0.968]])
weights = mcda_weights.stat_var_weighting(matrix)
print('Statistical variance weights: ', np.round(weights, 4))
Output
Statistical variance weights: [0.3441 0.3497 0.3062]
CILOS weighting method
import numpy as np
from crispyn import weighting_methods as mcda_weights
matrix = np.array([[3, 100, 10, 7],
[2.500, 80, 8, 5],
[1.800, 50, 20, 11],
[2.200, 70, 12, 9]])
types = np.array([-1, 1, -1, 1])
weights = mcda_weights.cilos_weighting(matrix, types)
print('CILOS weights: ', np.round(weights, 3))
Output
CILOS weights: [0.334 0.22 0.196 0.25 ]
IDOCRIW weighting method
import numpy as np
from crispyn import weighting_methods as mcda_weights
matrix = np.array([[3.0, 100, 10, 7],
[2.5, 80, 8, 5],
[1.8, 50, 20, 11],
[2.2, 70, 12, 9]])
types = np.array([-1, 1, -1, 1])
weights = mcda_weights.idocriw_weighting(matrix, types)
print('IDOCRIW weights: ', np.round(weights, 3))
Output
IDOCRIW weights: [0.166 0.189 0.355 0.291]
Angle weighting method
import numpy as np
from crispyn import weighting_methods as mcda_weights
matrix = np.array([[30, 30, 38, 29],
[19, 54, 86, 29],
[19, 15, 85, 28.9],
[68, 70, 60, 29]])
types = np.array([1, 1, 1, 1])
weights = mcda_weights.angle_weighting(matrix, types)
print('Angle weights: ', np.round(weights, 4))
Output
Angle weights: [0.415 0.3612 0.2227 0.0012]
Coefficient of variation weighting method
import numpy as np
from crispyn import weighting_methods as mcda_weights
matrix = np.array([[30, 30, 38, 29],
[19, 54, 86, 29],
[19, 15, 85, 28.9],
[68, 70, 60, 29]])
weights = mcda_weights.coeff_var_weighting(matrix)
print('Coefficient of variation weights: ', np.round(weights, 4))
Output
Coefficient of variation weights: [0.4258 0.361 0.2121 0.0011]
Subjective methods for criteria weights determination
AHP weighting method
import numpy as np
from crispyn import weighting_methods as mcda_weights
PCcriteria = np.array([[1, 1, 5, 3], [1, 1, 5, 3],
[1/5, 1/5, 1, 1/3], [1/3, 1/3, 3, 1]])
ahp_weighting = mcda_weights.AHP_WEIGHTING()
weights = ahp_weighting(X = PCcriteria, compute_priority_vector_method=ahp_weighting._eigenvector)
print('AHP weights: ', np.round(weights, 4))
Output
Inconsistency index: 0.01610868948440318
AHP weights: [0.3899 0.3899 0.0679 0.1524]
SWARA weighting method
import numpy as np
from crispyn import weighting_methods as mcda_weights
criteria_indexes = np.array([0, 1, 2, 3, 4, 5, 6])
s = np.array([0, 0.35, 0.2, 0.3, 0, 0.4])
weights = mcda_weights.swara_weighting(criteria_indexes, s)
print('SWARA weights: ', np.round(weights, 4))
Output
SWARA weights: [0.2152 0.2152 0.1594 0.1328 0.1022 0.1022 0.073 ]
LBWA weighting method
import numpy as np
from crispyn import weighting_methods as mcda_weights
criteria_indexes = [
[1, 4, 6, 5, 0, 2],
[7, 3]
]
criteria_values_I = [
[0, 2, 3, 4, 4, 5],
[1, 2]
]
weights = mcda_weights.lbwa_weighting(criteria_indexes, criteria_values_I)
print('LBWA weights: ', np.round(weights, 4))
Output
LBWA weights: [0.1215 0.1909 0.1114 0.0835 0.1485 0.1215 0.1336 0.0891]
SAPEVO weighting method
import numpy as np
from crispyn import weighting_methods as mcda_weights
criteria_matrix = np.array([
[0, 0, 3, 3, 1, 3, 2, 1, 2],
[0, 0, 3, 3, 1, 3, 2, 1, 2],
[-3, -3, 0, 0, -1, -2, -2, -1, -2],
[-3, -3, 0, 0, -2, 2, -2, -2, -2],
[-1, -1, 1, 2, 0, 2, 0, -1, 1],
[-3, -3, 2, -2, -2, 0, -2, -1, -2],
[-3, -2, 2, 2, 0, 2, 0, 3, 0],
[-1, -1, 1, 2, 1, 1, -3, 0, -1],
[-2, -2, 2, 2, -1, 2, 0, 1, 0],
])
weights = mcda_weights.sapevo_weighting(criteria_matrix)
print('SAPEVO weights: ', np.round(weights, 4))
Output
SAPEVO weights: [0.232 0.232 0. 0.016 0.136 0.008 0.144 0.104 0.128]
Stochastic Multicriteria Acceptability Analysis Method - SMAA (VIKOR_SMAA)
from crispyn.mcda_methods import VIKOR_SMAA
# Criteria number
n = matrix.shape[1]
# Number of weight vectors to generate for SMAA
iterations = 10000
# Create the object of the ``VIKOR_SMAA`` method
vikor_smaa = VIKOR_SMAA()
# Generate weight vectors for SMAA. Number of weight vectors is equal to ``iterations`` number. Vectors include ``n`` values.
weight_vectors = vikor_smaa._generate_weights(n, iterations)
# Calculate Rank acceptability index, Central weight vector and final ranking based on SMAA method combined with VIKOR
rank_acceptability_index, central_weight_vector, rank_scores = vikor_smaa(matrix, weight_vectors, types)
Normalization methods
Here is an example of vector_normalization usage. Other normalizations provided in module normalizations, namely minmax_normalization, max_normalization,
sum_normalization, linear_normalization are used in analogous way.
Vector normalization
import numpy as np
from crispyn import normalizations as norms
matrix = np.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]])
types = np.array([1, 1, 1, 1])
norm_matrix = norms.vector_normalization(matrix, types)
print('Normalized matrix: ', np.round(norm_matrix, 4))
Output
Normalized matrix: [[0.4126 0.3769 0.1525 0.0928]
[0.2579 0.1615 0.5337 0.4642]
[0.361 0.2692 0.4575 0.3714]
[0.4641 0.4845 0.5337 0.2785]
[0.5673 0.5384 0.2287 0.6499]
[0.3094 0.4845 0.3812 0.3714]]