Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add missing docstrings #40

Merged
merged 5 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 28 additions & 19 deletions mcda/configuration/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,34 @@


# noinspection PyMethodMayBeStatic
class Config():
class Config:
"""
Class Configuration

keys expected in the input dictionary are
input_matrix_path: path to the input matrix
marginal_distribution_for_each indicator: list of marginal distributions, one for each indicator
polarity_for_each_indicator: list of polarities, one for each indicator
monte_carlo_runs: number of MC runs
num_cores: number of cores used in the parallelization
monte_carlo_runs: list of weights, one for each indicator
output_path: path to the output file

Class representing configuration settings.

This class encapsulates the configuration settings.
It expects the following keys in the input dictionary:
- input_matrix_path: path to the input matrix file.
- polarity_for_each_indicator: list of polarities, one for each indicator.
- sensitivity: sensitivity configuration.
- robustness: robustness configuration.
- monte_carlo_sampling: Monte Carlo sampling configuration.
- output_path: path to the output file.

Attributes:
_valid_keys (List[str]): list of valid keys expected in the input dictionary.
_list_values (List[str]): list of keys corresponding to list values.
_str_values (List[str]): list of keys corresponding to string values.
_int_values (List[str]): list of keys corresponding to integer values.
_dict_values (List[str]): list of keys corresponding to dictionary values.
_keys_of_dict_values (Dict[str, List[str]]): dictionary containing keys and their corresponding sub-keys.

Methods:
__init__(input_config: dict): instantiate a configuration object.
_validate(input_config, valid_keys, str_values, int_values, list_values, dict_values): validate the input
configuration.
get_property(property_name: str): retrieve a property from the configuration.
check_dict_keys(dic: Dict[str, Any], keys: List[str]): check if a specific key is in a dictionary.
check_key(dic: dict, key: str): check if a key is in a dictionary.
"""

_valid_keys: List[str] = ['input_matrix_path',
Expand All @@ -34,7 +49,7 @@ class Config():
'marginal_distribution_for_each_indicator', 'polarity_for_each_indicator']

_str_values: List[str] = ['input_matrix_path', 'output_path', 'sensitivity_on', 'normalization', 'aggregation',
'robustness_on', 'on_single_weights', 'on_all_weights', 'given_weights', 'on_indicators']
'robustness_on', 'on_single_weights', 'on_all_weights', 'given_weights', 'on_indicators']
kapil-agnihotri marked this conversation as resolved.
Show resolved Hide resolved

_int_values: List[str] = ['monte_carlo_runs', 'num_cores']

Expand All @@ -47,10 +62,6 @@ class Config():
'marginal_distribution_for_each_indicator']}

def __init__(self, input_config: dict):
"""
Instantiate a configuration object
:param input_config: dictionary
"""

valid_keys = self._valid_keys
str_values = self._str_values
Expand Down Expand Up @@ -122,13 +133,11 @@ def output_file_path(self):

@staticmethod
def check_dict_keys(dic: Dict[str, Any], keys: List[str]):
"""Check if a specific key is in a dictionary"""
for key in keys:
Config.check_key(dic, key)

@staticmethod
def check_key(dic: dict, key: str):
"""Check if a key is in a dictionary"""
if key not in dic.keys():
raise KeyError(
"The key = {} is not present in dictionary: {}".format(key, dic))
76 changes: 35 additions & 41 deletions mcda/mcda_functions/aggregation.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,13 @@

class Aggregation(object):
"""
Class Aggregation

This class aggregates the normalized values of each indicator
by mean of different aggregation functions. The input_matrix contains
normalized values of the indicators
This class aggregates the normalized values of each indicator by mean of different aggregation functions.
The input_matrix contains normalized values of the indicators.

Type of aggregation functions
Compensatory: weighted-sum (i.e. additive)
Partially compensatory: geometric; harmonic
Non-compensatory: minimum

Compensatory: weighted-sum (i.e. additive).
Partially compensatory: geometric; harmonic.
Non-compensatory: minimum.
"""

def __init__(self, weights: list):
Expand All @@ -30,32 +26,31 @@ def __init__(self, weights: list):
if sum(self.weights) != 1:
self.weights = [val / sum(self.weights) for val in self.weights]

def weighted_sum(self, norm_indicators: pd.DataFrame()) -> pd.Series(dtype='object'):
def weighted_sum(self, norm_indicators: pd.DataFrame) -> pd.Series(dtype='object'):
"""
Weighted-sum or additive aggregation function
gets as input the normalized values of the indicators in a matrix
and estimates the scores over the indicators, per alternative.
Weighted-sum or additive aggregation function gets as input the normalized values of the indicators in a matrix
and estimates the scores over the indicators, per alternative. The norm_indicators has
shape = (num. alternatives x num. indicators) and the returned scores has length = num. of alternatives.

:gets: pd.DataFrame() of shape (no.alternatives x num. indicators)
:returns: pd.Series of length = num. of alternatives
:param norm_indicators: pd.DataFrame
:returns scores: pd.Series
"""

scores = (norm_indicators * self.weights).sum(axis=1)

return scores

def geometric(self, norm_indicators: pd.DataFrame()) -> np.ndarray:
def geometric(self, norm_indicators: pd.DataFrame) -> np.ndarray:
"""
The weighted geometric mean works only with strictly positive
normalized indicator values (i.e. not with minmax and target with feature range (0,1);
not with standardized with feature range ('-inf','+inf')).
Gets as input the normalized values of the indicators in a matrix
and estimates the scores over the indicators, per alternative.

:gets: pd.DataFrame() of shape (no.alternatives x num. indicators)
:returns: pd.Series of length = num. of alternatives
The weighted geometric mean works only with strictly positive normalized indicator values
(i.e. not with minmax and target with feature range (0,1); and not with standardized with feature range
('-inf','+inf')). It gets as input positive normalized values of the indicators in a matrix and estimates the
scores over the indicators, per alternative. The norm_indicators has shape = (no.alternatives x num. indicators)
kapil-agnihotri marked this conversation as resolved.
Show resolved Hide resolved
and the returned scores has length = num. of alternatives.

:param norm_indicators: pd.DataFrame
:returns scores: pd.Series
"""

if (norm_indicators <= 0).any().any():
logger.error('Error Message', stack_info=True)
raise ValueError(
Expand All @@ -66,16 +61,16 @@ def geometric(self, norm_indicators: pd.DataFrame()) -> np.ndarray:

return scores

def harmonic(self, norm_indicators: pd.DataFrame()) -> np.ndarray:
def harmonic(self, norm_indicators: pd.DataFrame) -> np.ndarray:
"""
The weighted harmonic mean works only with strictly positive
normalized indicator values (i.e. not with minmax, and target with feature range (0,1);
not with standardized with feature range ('-inf','+inf')).
Gets as input the normalized values of the indicators in a matrix
and estimates the scores over the indicators, per alternative.

:gets: pd.DataFrame() of shape (no.alternatives x num. indicators)
:returns: pd.Series of length = num. of alternatives
The weighted harmonic mean works only with strictly positive normalized indicator values
(i.e. not with minmax, and target with feature range (0,1); and not with standardized with feature range
('-inf','+inf')). It gets as input positive normalized values of the indicators in a matrix and estimates the
scores over the indicators, per alternative. The norm_indicators has shape = (no.alternatives x num. indicators)
and the returned scores has length = num. of alternatives.

:param norm_indicators: pd.DataFrame
kapil-agnihotri marked this conversation as resolved.
Show resolved Hide resolved
:returns scores: pd.Series
"""

if (norm_indicators == 0).any().any():
Expand All @@ -87,17 +82,16 @@ def harmonic(self, norm_indicators: pd.DataFrame()) -> np.ndarray:

return scores

# noinspection PyMethodMayBeStatic
def minimum(self, norm_indicators: pd.DataFrame()) -> pd.Series(dtype='object'):
def minimum(self, norm_indicators: pd.DataFrame) -> pd.Series(dtype='object'):
"""
Minimum aggregation function. It does not consider the weights.
Gets as input the normalized values of the indicators
in a matrix and estimates the scores over the indicators, per alternative.
It gets as input the normalized values of the indicators in a matrix and estimates the scores over the
indicators, per alternative. The norm_indicators has shape = (no.alternatives x num. indicators) and the
returned scores has length = num. of alternatives.

:gets: pd.DataFrame() of shape (no.alternatives x num. indicators)
:returns: pd.Series of length = num. of alternatives
:param norm_indicators: pd.DataFrame
kapil-agnihotri marked this conversation as resolved.
Show resolved Hide resolved
:returns scores: pd.Series
"""

scores = norm_indicators.min(axis=1)

return scores
Loading
Loading