Module fcmpy.intervention.intervention
Expand source code
import pandas as pd
import numpy as np
from typing import Union
from abc import ABC, abstractmethod
from fcmpy.store.methodsStore import InterventionStore
from fcmpy.expert_fcm.input_validator import type_check
class Intervention(ABC):
"""
Test intervention scenarios.
"""
@abstractmethod
def add_intervention():
raise NotImplementedError('add_intervention method is not defined!')
@abstractmethod
def remove_intervention():
raise NotImplementedError('remove_intervention method is not defined!')
@abstractmethod
def test_intervention():
raise NotImplementedError('test_intervention method is not defined!')
class FcmIntervention(Intervention):
"""
The class includes methods for testing interventions (what-if scenarios) on top of a defined FCM structure.
Methods:
__init__(self, simulator)
initialize(self, initial_state: dict, weight_matrix: Union[pd.DataFrame, np.ndarray],
transfer: str, inference: str, thresh: float, iterations: int, l=1,
output_concepts = None, convergence = 'absDiff', **params)
add_intervention(self, name, weights, effectiveness)
remove_intervention(self, name)
test_intervention(self, name, iterations = None)
"""
def __init__(self, simulator):
"""
Parameters
----------
simulator: Simulator
"""
self.__simulator = simulator()
self.__interventions = {}
self.__test_results = {}
self.__equilibriums = {}
self.__comparison_table = None
@property
def test_results(self):
return self.__test_results
@property
def interventions(self):
return self.__interventions
@property
def equilibriums(self):
return pd.DataFrame(self.__equilibriums)
@property
def comparison_table(self):
diff = {}
df = pd.DataFrame(self.__equilibriums)
for i in df.columns:
diff[i] = ((df[i] - df.iloc[:, 0])/df.iloc[:, 0])*100
self.__comparison_table = pd.DataFrame(diff)
return self.__comparison_table
@type_check
def initialize(self, initial_state: dict, weight_matrix: Union[pd.DataFrame, np.ndarray],
transfer: str, inference: str, thresh: float, iterations: int, l=1,
output_concepts = None, convergence = 'absDiff', **params):
"""
Parameters
----------
initial_state: dict
keys ---> concepts, values ---> initial states of the associated concepts
weight_matrix: panda.DataFrame
causal weights between concepts
transfer: str
transfer function --> "sigmoid", "bivalent", "trivalent", "tanh"
inference: str
inference method --> "kosko", "mKosko", "rescaled"
thresh: float
threshold for the error
iterations: int
number of iterations
l: 1
A parameter that determines the steepness of the sigmoid function at values around 0.
output_concepts: bool, list
the output concepts for the convergence check
default --> None
convergence: str,
convergence method
default --> 'absDiff': absolute difference between the simulation steps
**params: additional parameters
"""
self.__weight_matrix = weight_matrix
self.__initial_state=initial_state
self.__transfer = transfer
self.__inference = inference
self.__thresh = thresh
self.__iterations = iterations
self.__l = l
self.__output_concepts = output_concepts
self.__convergence = convergence
self.__test_results['baseline'] = self.__simulator.simulate(initial_state = self.__initial_state, weight_matrix = self.__weight_matrix,
transfer = self.__transfer, inference = self.__inference, thresh = self.__thresh,
iterations = self.__iterations, l=self.__l, output_concepts = self.__output_concepts, convergence = self.__convergence, params = params)
self.__equilibriums['baseline'] = self.test_results['baseline'].iloc[-1]
@type_check
def add_intervention(self, name, type='continuous', **kwargs):
"""
Add an intervention node with the associated causal weights to the FCM.
Parameters
----------
name: str
name of the intervention
type: str
type of intervention
default --> continuous
impact: dict
keys --> concepts the intervention impacts, value: the associated causal weight
effectiveness: float
the degree to which the intervention was delivered (should be between [-1, 1])
default --> 1
"""
if type != 'continuous':
s = self.__initial_state.copy()
s.update(kwargs['initial_state'])
initial_state = s.copy()
else:
initial_state = self.__initial_state
constructor = InterventionStore.get(type)()
self.__interventions[name] = constructor.build(weight_matrix=self.__weight_matrix, initial_state=initial_state,
equilibriums = self.__equilibriums, params=kwargs)
@type_check
def remove_intervention(self, name: str):
"""
Remove intervention.
Parameters
----------
name: str
name of the intervention
"""
del self.interventions[name]
@type_check
def test_intervention(self, name: str, iterations: int = None):
"""
Test an intervention case.
Parameters
----------
name: str
name of the intervention
iterations: number of iterations for the FCM simulation
default ---> the iterations specified in the init.
"""
if iterations:
iterations = iterations
else:
iterations = self.__iterations
weight_matrix = self.__interventions[name]['weight_matrix']
state_vector = self.__interventions[name]['state_vector']
self.__test_results[name] = self.__simulator.simulate(initial_state=state_vector, weight_matrix=weight_matrix,
transfer=self.__transfer, inference=self.__inference,
thresh=self.__thresh, iterations=iterations,
l = self.__l, output_concepts=self.__output_concepts,
convergence=self.__convergence)
self.__equilibriums[name] = self.__test_results[name].iloc[-1][:len(self.__initial_state)]
Classes
class FcmIntervention (simulator)
-
The class includes methods for testing interventions (what-if scenarios) on top of a defined FCM structure.
Methods
init(self, simulator)
initialize(self, initial_state: dict, weight_matrix: Union[pd.DataFrame, np.ndarray], transfer: str, inference: str, thresh: float, iterations: int, l=1, output_concepts = None, convergence = 'absDiff', **params)
add_intervention(self, name, weights, effectiveness)
remove_intervention(self, name)
test_intervention(self, name, iterations = None)
Parameters
simulator
:Simulator
Expand source code
class FcmIntervention(Intervention): """ The class includes methods for testing interventions (what-if scenarios) on top of a defined FCM structure. Methods: __init__(self, simulator) initialize(self, initial_state: dict, weight_matrix: Union[pd.DataFrame, np.ndarray], transfer: str, inference: str, thresh: float, iterations: int, l=1, output_concepts = None, convergence = 'absDiff', **params) add_intervention(self, name, weights, effectiveness) remove_intervention(self, name) test_intervention(self, name, iterations = None) """ def __init__(self, simulator): """ Parameters ---------- simulator: Simulator """ self.__simulator = simulator() self.__interventions = {} self.__test_results = {} self.__equilibriums = {} self.__comparison_table = None @property def test_results(self): return self.__test_results @property def interventions(self): return self.__interventions @property def equilibriums(self): return pd.DataFrame(self.__equilibriums) @property def comparison_table(self): diff = {} df = pd.DataFrame(self.__equilibriums) for i in df.columns: diff[i] = ((df[i] - df.iloc[:, 0])/df.iloc[:, 0])*100 self.__comparison_table = pd.DataFrame(diff) return self.__comparison_table @type_check def initialize(self, initial_state: dict, weight_matrix: Union[pd.DataFrame, np.ndarray], transfer: str, inference: str, thresh: float, iterations: int, l=1, output_concepts = None, convergence = 'absDiff', **params): """ Parameters ---------- initial_state: dict keys ---> concepts, values ---> initial states of the associated concepts weight_matrix: panda.DataFrame causal weights between concepts transfer: str transfer function --> "sigmoid", "bivalent", "trivalent", "tanh" inference: str inference method --> "kosko", "mKosko", "rescaled" thresh: float threshold for the error iterations: int number of iterations l: 1 A parameter that determines the steepness of the sigmoid function at values around 0. output_concepts: bool, list the output concepts for the convergence check default --> None convergence: str, convergence method default --> 'absDiff': absolute difference between the simulation steps **params: additional parameters """ self.__weight_matrix = weight_matrix self.__initial_state=initial_state self.__transfer = transfer self.__inference = inference self.__thresh = thresh self.__iterations = iterations self.__l = l self.__output_concepts = output_concepts self.__convergence = convergence self.__test_results['baseline'] = self.__simulator.simulate(initial_state = self.__initial_state, weight_matrix = self.__weight_matrix, transfer = self.__transfer, inference = self.__inference, thresh = self.__thresh, iterations = self.__iterations, l=self.__l, output_concepts = self.__output_concepts, convergence = self.__convergence, params = params) self.__equilibriums['baseline'] = self.test_results['baseline'].iloc[-1] @type_check def add_intervention(self, name, type='continuous', **kwargs): """ Add an intervention node with the associated causal weights to the FCM. Parameters ---------- name: str name of the intervention type: str type of intervention default --> continuous impact: dict keys --> concepts the intervention impacts, value: the associated causal weight effectiveness: float the degree to which the intervention was delivered (should be between [-1, 1]) default --> 1 """ if type != 'continuous': s = self.__initial_state.copy() s.update(kwargs['initial_state']) initial_state = s.copy() else: initial_state = self.__initial_state constructor = InterventionStore.get(type)() self.__interventions[name] = constructor.build(weight_matrix=self.__weight_matrix, initial_state=initial_state, equilibriums = self.__equilibriums, params=kwargs) @type_check def remove_intervention(self, name: str): """ Remove intervention. Parameters ---------- name: str name of the intervention """ del self.interventions[name] @type_check def test_intervention(self, name: str, iterations: int = None): """ Test an intervention case. Parameters ---------- name: str name of the intervention iterations: number of iterations for the FCM simulation default ---> the iterations specified in the init. """ if iterations: iterations = iterations else: iterations = self.__iterations weight_matrix = self.__interventions[name]['weight_matrix'] state_vector = self.__interventions[name]['state_vector'] self.__test_results[name] = self.__simulator.simulate(initial_state=state_vector, weight_matrix=weight_matrix, transfer=self.__transfer, inference=self.__inference, thresh=self.__thresh, iterations=iterations, l = self.__l, output_concepts=self.__output_concepts, convergence=self.__convergence) self.__equilibriums[name] = self.__test_results[name].iloc[-1][:len(self.__initial_state)]
Ancestors
- Intervention
- abc.ABC
Instance variables
var comparison_table
-
Expand source code
@property def comparison_table(self): diff = {} df = pd.DataFrame(self.__equilibriums) for i in df.columns: diff[i] = ((df[i] - df.iloc[:, 0])/df.iloc[:, 0])*100 self.__comparison_table = pd.DataFrame(diff) return self.__comparison_table
var equilibriums
-
Expand source code
@property def equilibriums(self): return pd.DataFrame(self.__equilibriums)
var interventions
-
Expand source code
@property def interventions(self): return self.__interventions
var test_results
-
Expand source code
@property def test_results(self): return self.__test_results
Methods
def add_intervention(self, name, type='continuous', **kwargs)
-
Add an intervention node with the associated causal weights to the FCM.
Parameters
name
:str
- name of the intervention
type
:str
- type of intervention default –> continuous
impact
:dict
- keys –> concepts the intervention impacts, value: the associated causal weight
effectiveness
:float
- the degree to which the intervention was delivered (should be between [-1, 1]) default –> 1
Expand source code
@type_check def add_intervention(self, name, type='continuous', **kwargs): """ Add an intervention node with the associated causal weights to the FCM. Parameters ---------- name: str name of the intervention type: str type of intervention default --> continuous impact: dict keys --> concepts the intervention impacts, value: the associated causal weight effectiveness: float the degree to which the intervention was delivered (should be between [-1, 1]) default --> 1 """ if type != 'continuous': s = self.__initial_state.copy() s.update(kwargs['initial_state']) initial_state = s.copy() else: initial_state = self.__initial_state constructor = InterventionStore.get(type)() self.__interventions[name] = constructor.build(weight_matrix=self.__weight_matrix, initial_state=initial_state, equilibriums = self.__equilibriums, params=kwargs)
def initialize(self, initial_state: dict, weight_matrix: Union[pandas.core.frame.DataFrame, numpy.ndarray], transfer: str, inference: str, thresh: float, iterations: int, l=1, output_concepts=None, convergence='absDiff', **params)
-
Parameters
initial_state
:dict
- keys —> concepts, values —> initial states of the associated concepts
weight_matrix
:panda.DataFrame
- causal weights between concepts
transfer
:str
- transfer function –> "sigmoid", "bivalent", "trivalent", "tanh"
inference
:str
- inference method –> "kosko", "mKosko", "rescaled"
thresh
:float
- threshold for the error
iterations
:int
- number of iterations
l
:1
- A parameter that determines the steepness of the sigmoid function at values around 0.
output_concepts
:bool, list
- the output concepts for the convergence check default –> None
convergence
:str,
- convergence method default –> 'absDiff': absolute difference between the simulation steps
**params
:additional parameters
Expand source code
@type_check def initialize(self, initial_state: dict, weight_matrix: Union[pd.DataFrame, np.ndarray], transfer: str, inference: str, thresh: float, iterations: int, l=1, output_concepts = None, convergence = 'absDiff', **params): """ Parameters ---------- initial_state: dict keys ---> concepts, values ---> initial states of the associated concepts weight_matrix: panda.DataFrame causal weights between concepts transfer: str transfer function --> "sigmoid", "bivalent", "trivalent", "tanh" inference: str inference method --> "kosko", "mKosko", "rescaled" thresh: float threshold for the error iterations: int number of iterations l: 1 A parameter that determines the steepness of the sigmoid function at values around 0. output_concepts: bool, list the output concepts for the convergence check default --> None convergence: str, convergence method default --> 'absDiff': absolute difference between the simulation steps **params: additional parameters """ self.__weight_matrix = weight_matrix self.__initial_state=initial_state self.__transfer = transfer self.__inference = inference self.__thresh = thresh self.__iterations = iterations self.__l = l self.__output_concepts = output_concepts self.__convergence = convergence self.__test_results['baseline'] = self.__simulator.simulate(initial_state = self.__initial_state, weight_matrix = self.__weight_matrix, transfer = self.__transfer, inference = self.__inference, thresh = self.__thresh, iterations = self.__iterations, l=self.__l, output_concepts = self.__output_concepts, convergence = self.__convergence, params = params) self.__equilibriums['baseline'] = self.test_results['baseline'].iloc[-1]
def remove_intervention(self, name: str)
-
Remove intervention.
Parameters
name
:str
- name of the intervention
Expand source code
@type_check def remove_intervention(self, name: str): """ Remove intervention. Parameters ---------- name: str name of the intervention """ del self.interventions[name]
def test_intervention(self, name: str, iterations: int = None)
-
Test an intervention case.
Parameters
name
:str
- name of the intervention
iterations
:number
ofiterations for the FCM simulation
- default —> the iterations specified in the init.
Expand source code
@type_check def test_intervention(self, name: str, iterations: int = None): """ Test an intervention case. Parameters ---------- name: str name of the intervention iterations: number of iterations for the FCM simulation default ---> the iterations specified in the init. """ if iterations: iterations = iterations else: iterations = self.__iterations weight_matrix = self.__interventions[name]['weight_matrix'] state_vector = self.__interventions[name]['state_vector'] self.__test_results[name] = self.__simulator.simulate(initial_state=state_vector, weight_matrix=weight_matrix, transfer=self.__transfer, inference=self.__inference, thresh=self.__thresh, iterations=iterations, l = self.__l, output_concepts=self.__output_concepts, convergence=self.__convergence) self.__equilibriums[name] = self.__test_results[name].iloc[-1][:len(self.__initial_state)]
class Intervention
-
Test intervention scenarios.
Expand source code
class Intervention(ABC): """ Test intervention scenarios. """ @abstractmethod def add_intervention(): raise NotImplementedError('add_intervention method is not defined!') @abstractmethod def remove_intervention(): raise NotImplementedError('remove_intervention method is not defined!') @abstractmethod def test_intervention(): raise NotImplementedError('test_intervention method is not defined!')
Ancestors
- abc.ABC
Subclasses
Methods
def add_intervention()
-
Expand source code
@abstractmethod def add_intervention(): raise NotImplementedError('add_intervention method is not defined!')
def remove_intervention()
-
Expand source code
@abstractmethod def remove_intervention(): raise NotImplementedError('remove_intervention method is not defined!')
def test_intervention()
-
Expand source code
@abstractmethod def test_intervention(): raise NotImplementedError('test_intervention method is not defined!')