@@ -84,589 +84,621 @@
2 """
3 from __future__ import annotations
4
- 5 from typing import Optional , Tuple , Union
- 6
- 7 import numpy as np
- 8 import pandas as pd
- 9 from jpype import JClass
- 10 from pydantic import BaseModel # pylint: disable=no-name-in-module
- 11
- 12 from rulekit . _helpers import ExampleSetFactory , PredictionResultMapper
- 13 from rulekit . _operator import BaseOperator , Data , ExpertKnowledgeOperator
- 14 from rulekit . _problem_types import ProblemType
- 15 from rulekit . kaplan_meier import KaplanMeierEstimator
- 16 from rulekit . params import ( DEFAULT_PARAMS_VALUE , ContrastSetModelParams ,
- 17 ExpertModelParams )
- 18 from rulekit . rules import RuleSet , SurvivalRule
- 19
- 20 _DEFAULT_SURVIVAL_TIME_ATTR : str = 'survival_time'
- 21
- 22
- 23 class _SurvivalModelsParams ( BaseModel ) :
- 24 survival_time_attr : Optional [ str ]
- 25 minsupp_new : Optional [ float ] = DEFAULT_PARAMS_VALUE [ 'minsupp_new' ]
- 26 max_growing : Optional [ float ] = DEFAULT_PARAMS_VALUE [ 'max_growing' ]
- 27 enable_pruning : Optional [ bool ] = DEFAULT_PARAMS_VALUE [ 'enable_pruning' ]
- 28 ignore_missing : Optional [ bool ] = DEFAULT_PARAMS_VALUE [ 'ignore_missing' ]
- 29 max_uncovered_fraction : Optional [ float ] = DEFAULT_PARAMS_VALUE [ 'max_uncovered_fraction' ]
- 30 select_best_candidate : Optional [ bool ] = DEFAULT_PARAMS_VALUE [ 'select_best_candidate' ]
- 31 complementary_conditions : Optional [ bool ] = DEFAULT_PARAMS_VALUE [ 'complementary_conditions' ]
- 32
- 33
- 34 class _SurvivalExpertModelParams ( _SurvivalModelsParams , ExpertModelParams ) :
- 35 pass
- 36
- 37
- 38 class _BaseSurvivalRulesModel :
- 39
- 40 model : RuleSet [ SurvivalRule ]
- 41
- 42 def get_train_set_kaplan_meier ( self ) -> KaplanMeierEstimator :
- 43 """Returns train set KaplanMeier estimator
- 44
- 45 Returns:
- 46 KaplanMeierEstimator: estimator
- 47 """
- 48 return KaplanMeierEstimator (
- 49 self . model . _java_object . getTrainingEstimator ( ) # pylint: disable=protected-access
- 50 )
- 51
+ 5 from typing import Optional
+ 6 from typing import Tuple
+ 7 from typing import Union
+ 8
+ 9 import numpy as np
+ 10 import pandas as pd
+ 11 from jpype import JClass
+ 12 from pydantic import BaseModel # pylint: disable=no-name-in-module
+ 13
+ 14 from rulekit . _helpers import ExampleSetFactory
+ 15 from rulekit . _helpers import PredictionResultMapper
+ 16 from rulekit . _operator import BaseOperator
+ 17 from rulekit . _operator import Data
+ 18 from rulekit . _operator import ExpertKnowledgeOperator
+ 19 from rulekit . _problem_types import ProblemType
+ 20 from rulekit . kaplan_meier import KaplanMeierEstimator
+ 21 from rulekit . params import ContrastSetModelParams
+ 22 from rulekit . params import DEFAULT_PARAMS_VALUE
+ 23 from rulekit . params import ExpertModelParams
+ 24 from rulekit . rules import RuleSet
+ 25 from rulekit . rules import SurvivalRule
+ 26
+ 27 _DEFAULT_SURVIVAL_TIME_ATTR : str = "survival_time"
+ 28
+ 29
+ 30 class _SurvivalModelsParams ( BaseModel ) :
+ 31 survival_time_attr : Optional [ str ]
+ 32 minsupp_new : Optional [ float ] = DEFAULT_PARAMS_VALUE [ "minsupp_new" ]
+ 33 max_growing : Optional [ float ] = DEFAULT_PARAMS_VALUE [ "max_growing" ]
+ 34 enable_pruning : Optional [ bool ] = DEFAULT_PARAMS_VALUE [ "enable_pruning" ]
+ 35 ignore_missing : Optional [ bool ] = DEFAULT_PARAMS_VALUE [ "ignore_missing" ]
+ 36 max_uncovered_fraction : Optional [ float ] = DEFAULT_PARAMS_VALUE [
+ 37 "max_uncovered_fraction"
+ 38 ]
+ 39 select_best_candidate : Optional [ bool ] = DEFAULT_PARAMS_VALUE [
+ 40 "select_best_candidate"
+ 41 ]
+ 42 complementary_conditions : Optional [ bool ] = DEFAULT_PARAMS_VALUE [
+ 43 "complementary_conditions"
+ 44 ]
+ 45
+ 46
+ 47 class _SurvivalExpertModelParams ( _SurvivalModelsParams , ExpertModelParams ) :
+ 48 pass
+ 49
+ 50
+ 51 class _BaseSurvivalRulesModel :
52
- 53 class SurvivalRules ( BaseOperator , _BaseSurvivalRulesModel ) :
- 54 """Survival model."""
- 55
- 56 __params_class__ = _SurvivalModelsParams
+ 53 model : RuleSet [ SurvivalRule ]
+ 54
+ 55 def get_train_set_kaplan_meier ( self ) -> KaplanMeierEstimator :
+ 56 """Returns train set KaplanMeier estimator
57
- 58 def __init__ ( # pylint: disable=super-init-not-called,too-many-arguments
- 59 self ,
- 60 survival_time_attr : str = None ,
- 61 minsupp_new : int = DEFAULT_PARAMS_VALUE [ 'minsupp_new' ] ,
- 62 max_growing : int = DEFAULT_PARAMS_VALUE [ 'max_growing' ] ,
- 63 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ 'enable_pruning' ] ,
- 64 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ 'ignore_missing' ] ,
- 65 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ 'max_uncovered_fraction' ] ,
- 66 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ 'select_best_candidate' ] ,
- 67 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [ 'complementary_conditions' ] ,
- 68 max_rule_count : int = DEFAULT_PARAMS_VALUE [ 'max_rule_count' ] ,
- 69 ) :
- 70 """
- 71 Parameters
- 72 ----------
- 73 survival_time_attr : str
- 74 name of column containing survival time data (use when data passed to model is padnas
- 75 dataframe).
- 76 minsupp_new : float = 5.0
- 77 a minimum number (or fraction, if value < 1.0) of previously uncovered examples
- 78 to be covered by a new rule (positive examples for classification problems); default: 5,
- 79 max_growing : int = 0.0
- 80 non-negative integer representing maximum number of conditions which can be added to
- 81 the rule in the growing phase (use this parameter for large datasets if execution time
- 82 is prohibitive); 0 indicates no limit; default: 0,
- 83 enable_pruning : bool = True
- 84 enable or disable pruning, default is True.
- 85 ignore_missing : bool = False
- 86 boolean telling whether missing values should be ignored (by default, a missing value
- 87 of given attribute is always considered as not fulfilling the condition build upon that
- 88 attribute); default: False.
- 89 max_uncovered_fraction : float = 0.0
- 90 Floating-point number from [0,1] interval representing maximum fraction of examples
- 91 that may remain uncovered by the rule set, default: 0.0.
- 92 select_best_candidate : bool = False
- 93 Flag determining if best candidate should be selected from growing phase;
- 94 default: False.
- 95 complementary_conditions : bool = False
- 96 If enabled, complementary conditions in the form a = !{value} for nominal attributes
- 97 are supported.
- 98 max_rule_count : int = 0
- 99 Maximum number of rules to be generated (for classification data sets it applies
- 100 to a single class); 0 indicates no limit.
- 101 """
- 102 self . _params = None
- 103 self . _rule_generator = None
- 104 self . _configurator = None
- 105 self . _initialize_rulekit ( )
- 106 self . set_params (
- 107 survival_time_attr = survival_time_attr ,
- 108 minsupp_new = minsupp_new ,
- 109 max_growing = max_growing ,
- 110 enable_pruning = enable_pruning ,
- 111 ignore_missing = ignore_missing ,
- 112 max_uncovered_fraction = max_uncovered_fraction ,
- 113 select_best_candidate = select_best_candidate ,
- 114 complementary_conditions = complementary_conditions ,
- 115 max_rule_count = max_rule_count
- 116 )
- 117 self . model : RuleSet [ SurvivalRule ] = None
- 118
- 119 def set_params (
- 120 self ,
- 121 ** kwargs
- 122 ) -> object :
- 123 """Set models hyperparameters. Parameters are the same as in constructor."""
- 124 self . survival_time_attr = kwargs . get ( 'survival_time_attr' )
- 125 return BaseOperator . set_params ( self , ** kwargs )
- 126
- 127 @ staticmethod
- 128 def _append_survival_time_columns (
- 129 values ,
- 130 survival_time : Union [ pd . Series , np . ndarray , list ]
- 131 ) -> Optional [ str ] :
- 132 survival_time_attr : str = _DEFAULT_SURVIVAL_TIME_ATTR
- 133 if isinstance ( survival_time , pd . Series ) :
- 134 if survival_time . name is None :
- 135 survival_time . name = survival_time_attr
- 136 else :
- 137 survival_time_attr = survival_time . name
- 138 values [ survival_time . name ] = survival_time
- 139 elif isinstance ( survival_time , np . ndarray ) :
- 140 np . append ( values , survival_time , axis = 1 )
- 141 elif isinstance ( survival_time , list ) :
- 142 for index , row in enumerate ( values ) :
- 143 row . append ( survival_time [ index ] )
- 144 else :
- 145 raise ValueError (
- 146 'Data values must be instance of either pandas DataFrame, numpy array or list'
- 147 )
- 148 return survival_time_attr
- 149
- 150 def _prepare_survival_attribute ( self , survival_time : Optional [ Data ] , values : Data ) -> str :
- 151 if self . survival_time_attr is None and survival_time is None :
- 152 raise ValueError (
- 153 'No "survival_time" attribute name was specified. ' +
- 154 'Specify it using method set_params'
- 155 )
- 156 if survival_time is not None :
- 157 return SurvivalRules . _append_survival_time_columns (
- 158 values , survival_time )
- 159 return self . survival_time_attr
- 160
- 161 def fit ( self , values : Data , labels : Data , survival_time : Data = None ) -> SurvivalRules : # pylint: disable=arguments-differ
- 162 """Train model on given dataset.
- 163
- 164 Parameters
- 165 ----------
- 166 values : :class:`rulekit.operator.Data`
- 167 attributes
- 168 labels : :class:`rulekit.operator.Data`
- 169 survival status
- 170 survival_time: :class:`rulekit.operator.Data`
- 171 data about survival time. Could be omitted when *survival_time_attr* parameter
- 172 was specified.
- 173
- 174 Returns
- 175 -------
- 176 self : SurvivalRules
- 177 """
- 178 survival_time_attribute = self . _prepare_survival_attribute (
- 179 survival_time , values )
- 180 super ( ) . fit ( values , labels , survival_time_attribute )
- 181 return self
- 182
- 183 def predict ( self , values : Data ) -> np . ndarray :
- 184 """Perform prediction and return estimated survival function for each example.
- 185
- 186 Parameters
- 187 ----------
- 188 values : :class:`rulekit.operator.Data`
- 189 attributes
- 190
- 191 Returns
- 192 -------
- 193 result : np.ndarray
- 194 Each row represent single example from dataset and contains estimated survival function
- 195 for that example. Estimated survival function is returned as a dictionary containing
- 196 times and corresponding probabilities.
- 197 """
- 198 return PredictionResultMapper . map_survival ( super ( ) . predict ( values ) )
+ 58 Returns:
+ 59 KaplanMeierEstimator: estimator
+ 60 """
+ 61 return KaplanMeierEstimator (
+ 62 self . model . _java_object . getTrainingEstimator ( ) # pylint: disable=protected-access
+ 63 )
+ 64
+ 65
+ 66 class SurvivalRules ( BaseOperator , _BaseSurvivalRulesModel ) :
+ 67 """Survival model."""
+ 68
+ 69 __params_class__ = _SurvivalModelsParams
+ 70
+ 71 def __init__ ( # pylint: disable=super-init-not-called,too-many-arguments
+ 72 self ,
+ 73 survival_time_attr : str = None ,
+ 74 minsupp_new : int = DEFAULT_PARAMS_VALUE [ "minsupp_new" ] ,
+ 75 max_growing : int = DEFAULT_PARAMS_VALUE [ "max_growing" ] ,
+ 76 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ] ,
+ 77 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ] ,
+ 78 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ] ,
+ 79 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ] ,
+ 80 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
+ 81 "complementary_conditions"
+ 82 ] ,
+ 83 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ] ,
+ 84 ) :
+ 85 """
+ 86 Parameters
+ 87 ----------
+ 88 survival_time_attr : str
+ 89 name of column containing survival time data (use when data passed to model
+ 90 is padnas dataframe).
+ 91 minsupp_new : float = 5.0
+ 92 a minimum number (or fraction, if value < 1.0) of previously uncovered
+ 93 examples to be covered by a new rule (positive examples for classification
+ 94 problems); default: 5,
+ 95 max_growing : int = 0.0
+ 96 non-negative integer representing maximum number of conditions which can be
+ 97 added to the rule in the growing phase (use this parameter for large
+ 98 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
+ 99 enable_pruning : bool = True
+ 100 enable or disable pruning, default is True.
+ 101 ignore_missing : bool = False
+ 102 boolean telling whether missing values should be ignored (by default, a
+ 103 missing value of given attribute is always considered as not fulfilling the
+ 104 condition build upon that attribute); default: False.
+ 105 max_uncovered_fraction : float = 0.0
+ 106 Floating-point number from [0,1] interval representing maximum fraction of
+ 107 examples that may remain uncovered by the rule set, default: 0.0.
+ 108 select_best_candidate : bool = False
+ 109 Flag determining if best candidate should be selected from growing phase;
+ 110 default: False.
+ 111 complementary_conditions : bool = False
+ 112 If enabled, complementary conditions in the form a = !{value} for nominal
+ 113 attributes are supported.
+ 114 max_rule_count : int = 0
+ 115 Maximum number of rules to be generated (for classification data sets it
+ 116 applies to a single class); 0 indicates no limit.
+ 117 """
+ 118 self . _params = None
+ 119 self . _rule_generator = None
+ 120 self . _configurator = None
+ 121 self . _initialize_rulekit ( )
+ 122 self . set_params (
+ 123 survival_time_attr = survival_time_attr ,
+ 124 minsupp_new = minsupp_new ,
+ 125 max_growing = max_growing ,
+ 126 enable_pruning = enable_pruning ,
+ 127 ignore_missing = ignore_missing ,
+ 128 max_uncovered_fraction = max_uncovered_fraction ,
+ 129 select_best_candidate = select_best_candidate ,
+ 130 complementary_conditions = complementary_conditions ,
+ 131 max_rule_count = max_rule_count ,
+ 132 )
+ 133 self . model : RuleSet [ SurvivalRule ] = None
+ 134
+ 135 def set_params ( self , ** kwargs ) -> object :
+ 136 """Set models hyperparameters. Parameters are the same as in constructor."""
+ 137 self . survival_time_attr = kwargs . get ( "survival_time_attr" )
+ 138 return BaseOperator . set_params ( self , ** kwargs )
+ 139
+ 140 @ staticmethod
+ 141 def _append_survival_time_columns (
+ 142 values , survival_time : Union [ pd . Series , np . ndarray , list ]
+ 143 ) -> Optional [ str ] :
+ 144 survival_time_attr : str = _DEFAULT_SURVIVAL_TIME_ATTR
+ 145 if isinstance ( survival_time , pd . Series ) :
+ 146 if survival_time . name is None :
+ 147 survival_time . name = survival_time_attr
+ 148 else :
+ 149 survival_time_attr = survival_time . name
+ 150 values [ survival_time . name ] = survival_time
+ 151 elif isinstance ( survival_time , np . ndarray ) :
+ 152 np . append ( values , survival_time , axis = 1 )
+ 153 elif isinstance ( survival_time , list ) :
+ 154 for index , row in enumerate ( values ) :
+ 155 row . append ( survival_time [ index ] )
+ 156 else :
+ 157 raise ValueError (
+ 158 "Data values must be instance of either pandas DataFrame, numpy array"
+ 159 " or list"
+ 160 )
+ 161 return survival_time_attr
+ 162
+ 163 def _prepare_survival_attribute (
+ 164 self , survival_time : Optional [ Data ] , values : Data
+ 165 ) -> str :
+ 166 if self . survival_time_attr is None and survival_time is None :
+ 167 raise ValueError (
+ 168 'No "survival_time" attribute name was specified. '
+ 169 + "Specify it using method set_params"
+ 170 )
+ 171 if survival_time is not None :
+ 172 return SurvivalRules . _append_survival_time_columns ( values , survival_time )
+ 173 return self . survival_time_attr
+ 174
+ 175 def fit (
+ 176 self , values : Data , labels : Data , survival_time : Data = None
+ 177 ) -> SurvivalRules : # pylint: disable=arguments-differ
+ 178 """Train model on given dataset.
+ 179
+ 180 Parameters
+ 181 ----------
+ 182 values : :class:`rulekit.operator.Data`
+ 183 attributes
+ 184 labels : :class:`rulekit.operator.Data`
+ 185 survival status
+ 186 survival_time: :class:`rulekit.operator.Data`
+ 187 data about survival time. Could be omitted when *survival_time_attr*
+ 188 parameter was specified.
+ 189
+ 190 Returns
+ 191 -------
+ 192 self : SurvivalRules
+ 193 """
+ 194 survival_time_attribute = self . _prepare_survival_attribute (
+ 195 survival_time , values
+ 196 )
+ 197 super ( ) . fit ( values , labels , survival_time_attribute )
+ 198 return self
199
- 200 def score ( self , values : Data , labels : Data , survival_time : Data = None ) -> float :
- 201 """Return the Integrated Brier Score on the given dataset and labels
- 202 (event status indicator).
- 203
- 204 Integrated Brier Score (IBS) - the Brier score (BS) represents the squared difference
- 205 between true event status at time T and predicted event status at that time;
- 206 the Integrated Brier score summarizes the prediction error over all observations and over
- 207 all times in a test set.
- 208
- 209 Parameters
- 210 ----------
- 211 values : :class:`rulekit.operator.Data`
- 212 attributes
- 213 labels : :class:`rulekit.operator.Data`
- 214 survival status
- 215 survival_time: :class:`rulekit.operator.Data`
- 216 data about survival time. Could be omitted when *survival_time_attr* parameter was
- 217 specified
- 218
- 219 Returns
- 220 -------
- 221 score : float
- 222 Integrated Brier Score of self.predict(values) wrt. labels.
- 223 """
- 224
- 225 survival_time_attribute = self . _prepare_survival_attribute (
- 226 survival_time , values )
- 227 example_set = ExampleSetFactory ( self . _get_problem_type ( ) ) . make (
- 228 values , labels , survival_time_attribute = survival_time_attribute )
- 229
- 230 predicted_example_set = self . model . _java_object . apply ( # pylint: disable=protected-access
- 231 example_set
- 232 )
- 233
- 234 IntegratedBrierScore = JClass ( # pylint: disable=invalid-name
- 235 'adaa.analytics.rules.logic.performance.IntegratedBrierScore'
- 236 )
- 237 integrated_brier_score = IntegratedBrierScore ( )
- 238 ibs = integrated_brier_score . countExample (
- 239 predicted_example_set ) . getValue ( )
- 240 return float ( ibs )
+ 200 def predict ( self , values : Data ) -> np . ndarray :
+ 201 """Perform prediction and return estimated survival function for each example.
+ 202
+ 203 Parameters
+ 204 ----------
+ 205 values : :class:`rulekit.operator.Data`
+ 206 attributes
+ 207
+ 208 Returns
+ 209 -------
+ 210 result : np.ndarray
+ 211 Each row represent single example from dataset and contains estimated
+ 212 survival function for that example. Estimated survival function is returned
+ 213 as a dictionary containing times and corresponding probabilities.
+ 214 """
+ 215 return PredictionResultMapper . map_survival ( super ( ) . predict ( values ) )
+ 216
+ 217 def score ( self , values : Data , labels : Data , survival_time : Data = None ) -> float :
+ 218 """Return the Integrated Brier Score on the given dataset and labels
+ 219 (event status indicator).
+ 220
+ 221 Integrated Brier Score (IBS) - the Brier score (BS) represents the squared
+ 222 difference between true event status at time T and predicted event status at
+ 223 that time; the Integrated Brier score summarizes the prediction error over all
+ 224 observations and over all times in a test set.
+ 225
+ 226 Parameters
+ 227 ----------
+ 228 values : :class:`rulekit.operator.Data`
+ 229 attributes
+ 230 labels : :class:`rulekit.operator.Data`
+ 231 survival status
+ 232 survival_time: :class:`rulekit.operator.Data`
+ 233 data about survival time. Could be omitted when *survival_time_attr*
+ 234 parameter was specified
+ 235
+ 236 Returns
+ 237 -------
+ 238 score : float
+ 239 Integrated Brier Score of self.predict(values) wrt. labels.
+ 240 """
241
- 242 def _get_problem_type ( self ) -> ProblemType :
- 243 return ProblemType . SURVIVAL
- 244
- 245
- 246 class ExpertSurvivalRules ( ExpertKnowledgeOperator , SurvivalRules ) :
- 247 """Expert Survival model."""
+ 242 survival_time_attribute = self . _prepare_survival_attribute (
+ 243 survival_time , values
+ 244 )
+ 245 example_set = ExampleSetFactory ( self . _get_problem_type ( ) ) . make (
+ 246 values , labels , survival_time_attribute = survival_time_attribute
+ 247 )
248
- 249 __params_class__ = _SurvivalExpertModelParams
- 250
- 251 def __init__ ( # pylint: disable=super-init-not-called,too-many-arguments,too-many-locals
- 252 self ,
- 253 survival_time_attr : str = None ,
- 254 minsupp_new : float = DEFAULT_PARAMS_VALUE [ 'minsupp_new' ] ,
- 255 max_growing : int = DEFAULT_PARAMS_VALUE [ 'max_growing' ] ,
- 256 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ 'enable_pruning' ] ,
- 257 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ 'ignore_missing' ] ,
- 258 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ 'max_uncovered_fraction' ] ,
- 259 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ 'select_best_candidate' ] ,
- 260 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [ 'complementary_conditions' ] ,
+ 249 predicted_example_set = (
+ 250 self . model . _java_object . apply ( # pylint: disable=protected-access
+ 251 example_set
+ 252 )
+ 253 )
+ 254
+ 255 IntegratedBrierScore = JClass ( # pylint: disable=invalid-name
+ 256 "adaa.analytics.rules.logic.performance.IntegratedBrierScore"
+ 257 )
+ 258 integrated_brier_score = IntegratedBrierScore ( )
+ 259 ibs = integrated_brier_score . countExample ( predicted_example_set ) . getValue ( )
+ 260 return float ( ibs )
261
- 262 extend_using_preferred : bool = DEFAULT_PARAMS_VALUE [ 'extend_using_preferred' ] ,
- 263 extend_using_automatic : bool = DEFAULT_PARAMS_VALUE [ 'extend_using_automatic' ] ,
- 264 induce_using_preferred : bool = DEFAULT_PARAMS_VALUE [ 'induce_using_preferred' ] ,
- 265 induce_using_automatic : bool = DEFAULT_PARAMS_VALUE [ 'induce_using_automatic' ] ,
- 266 preferred_conditions_per_rule : int = DEFAULT_PARAMS_VALUE [
- 267 'preferred_conditions_per_rule' ] ,
- 268 preferred_attributes_per_rule : int = DEFAULT_PARAMS_VALUE [
- 269 'preferred_attributes_per_rule' ] ,
- 270 max_rule_count : int = DEFAULT_PARAMS_VALUE [ 'max_rule_count' ] ,
- 271 ) :
- 272 """
- 273 Parameters
- 274 ----------
- 275 minsupp_new : float = 5.0
- 276 a minimum number (or fraction, if value < 1.0) of previously uncovered examples
- 277 to be covered by a new rule (positive examples for classification problems); default: 5,
- 278 survival_time_attr : str
- 279 name of column containing survival time data (use when data passed to model is pandas
- 280 dataframe).
- 281 max_growing : int = 0.0
- 282 non-negative integer representing maximum number of conditions which can be added to
- 283 the rule in the growing phase (use this parameter for large datasets if execution time
- 284 is prohibitive); 0 indicates no limit; default: 0,
- 285 enable_pruning : bool = True
- 286 enable or disable pruning, default is True.
- 287 ignore_missing : bool = False
- 288 boolean telling whether missing values should be ignored (by default, a missing value
- 289 of given attribute is always considered as not fulfilling the condition build upon that
- 290 attribute); default: False.
- 291 max_uncovered_fraction : float = 0.0
- 292 Floating-point number from [0,1] interval representing maximum fraction of examples
- 293 that may remain uncovered by the rule set, default: 0.0.
- 294 select_best_candidate : bool = False
- 295 Flag determining if best candidate should be selected from growing phase;
- 296 default: False.
- 297 complementary_conditions : bool = False
- 298 If enabled, complementary conditions in the form a = !{value} for nominal attributes
- 299 are supported.
- 300 max_rule_count : int = 0
- 301 Maximum number of rules to be generated (for classification data sets it applies
- 302 to a single class); 0 indicates no limit.
- 303
- 304 extend_using_preferred : bool = False
- 305 boolean indicating whether initial rules should be extended with a use of preferred
- 306 conditions and attributes; default is False
- 307 extend_using_automatic : bool = False
- 308 boolean indicating whether initial rules should be extended with a use of automatic
- 309 conditions and attributes; default is False
- 310 induce_using_preferred : bool = False
- 311 boolean indicating whether new rules should be induced with a use of preferred
- 312 conditions and attributes; default is False
- 313 induce_using_automatic : bool = False
- 314 boolean indicating whether new rules should be induced with a use of automatic
- 315 conditions and attributes; default is False
- 316 preferred_conditions_per_rule : int = None
- 317 maximum number of preferred conditions per rule; default: unlimited,
- 318 preferred_attributes_per_rule : int = None
- 319 maximum number of preferred attributes per rule; default: unlimited.
- 320 """
- 321 self . _params = None
- 322 self . _rule_generator = None
- 323 self . _configurator = None
- 324 self . _initialize_rulekit ( )
- 325 self . set_params (
- 326 survival_time_attr = survival_time_attr ,
- 327 minsupp_new = minsupp_new ,
- 328 max_growing = max_growing ,
- 329 enable_pruning = enable_pruning ,
- 330 ignore_missing = ignore_missing ,
- 331 max_uncovered_fraction = max_uncovered_fraction ,
- 332 select_best_candidate = select_best_candidate ,
- 333 extend_using_preferred = extend_using_preferred ,
- 334 extend_using_automatic = extend_using_automatic ,
- 335 induce_using_preferred = induce_using_preferred ,
- 336 induce_using_automatic = induce_using_automatic ,
- 337 preferred_conditions_per_rule = preferred_conditions_per_rule ,
- 338 preferred_attributes_per_rule = preferred_attributes_per_rule ,
- 339 complementary_conditions = complementary_conditions ,
- 340 max_rule_count = max_rule_count
- 341 )
- 342 self . model : RuleSet [ SurvivalRule ] = None
- 343
- 344 def set_params ( # pylint: disable=arguments-differ
- 345 self ,
- 346 ** kwargs
- 347 ) -> object :
- 348 self . survival_time_attr = kwargs [ 'survival_time_attr' ]
- 349 return ExpertKnowledgeOperator . set_params ( self , ** kwargs )
- 350
- 351 def fit ( # pylint: disable=arguments-differ,too-many-arguments
- 352 self ,
- 353 values : Data ,
- 354 labels : Data ,
- 355 survival_time : Data = None ,
- 356
- 357 expert_rules : list [ Union [ str , tuple [ str , str ] ] ] = None ,
- 358 expert_preferred_conditions : list [ Union [ str , tuple [ str , str ] ] ] = None ,
- 359 expert_forbidden_conditions : list [ Union [ str , tuple [ str , str ] ] ] = None
- 360 ) -> ExpertSurvivalRules :
- 361 """Train model on given dataset.
- 362
- 363 Parameters
- 364 ----------
- 365 values : :class:`rulekit.operator.Data`
- 366 attributes
- 367 labels : Data
- 368 survival status
- 369 survival_time: :class:`rulekit.operator.Data`
- 370 data about survival time. Could be omitted when *survival_time_attr* parameter was
- 371 specified.
- 372
- 373 expert_rules : List[Union[str, Tuple[str, str]]]
- 374 set of initial rules, either passed as a list of strings representing rules or as list
- 375 of tuples where first
- 376 element is name of the rule and second one is rule string.
- 377 expert_preferred_conditions : List[Union[str, Tuple[str, str]]]
- 378 multiset of preferred conditions (used also for specifying preferred attributes by
- 379 using special value Any). Either passed as a list of strings representing rules or as
- 380 list of tuples where first element is name of the rule and second one is rule string.
- 381 expert_forbidden_conditions : List[Union[str, Tuple[str, str]]]
- 382 set of forbidden conditions (used also for specifying forbidden attributes by using
- 383 special valye Any). Either passed as a list of strings representing rules or as list
- 384 of tuples where first element is name of the rule and second one is rule string.
- 385
- 386 Returns
- 387 -------
- 388 self : ExpertSurvivalRules
- 389 """
- 390 survival_time_attribute = SurvivalRules . _prepare_survival_attribute (
- 391 self , survival_time , values )
- 392 return ExpertKnowledgeOperator . fit (
- 393 self ,
- 394 values = values ,
- 395 labels = labels ,
- 396 survival_time_attribute = survival_time_attribute ,
- 397 expert_rules = expert_rules ,
- 398 expert_preferred_conditions = expert_preferred_conditions ,
- 399 expert_forbidden_conditions = expert_forbidden_conditions
- 400 )
- 401
- 402 def predict ( self , values : Data ) -> np . ndarray :
- 403 return PredictionResultMapper . map_survival ( ExpertKnowledgeOperator . predict ( self , values ) )
- 404
- 405 def _get_problem_type ( self ) -> ProblemType :
- 406 return ProblemType . SURVIVAL
- 407
- 408
- 409 class _SurvivalContrastSetModelParams ( ContrastSetModelParams , _SurvivalModelsParams ) :
- 410 pass
- 411
- 412
- 413 class ContrastSetSurvivalRules ( BaseOperator , _BaseSurvivalRulesModel ) :
- 414 """Contrast set survival model."""
- 415
- 416 __params_class__ = _SurvivalContrastSetModelParams
- 417
- 418 def __init__ ( # pylint: disable=super-init-not-called,too-many-arguments
- 419 self ,
- 420 minsupp_all : Tuple [ float , float , float ,
- 421 float ] = DEFAULT_PARAMS_VALUE [ 'minsupp_all' ] ,
- 422 max_neg2pos : float = DEFAULT_PARAMS_VALUE [ 'max_neg2pos' ] ,
- 423 max_passes_count : int = DEFAULT_PARAMS_VALUE [ 'max_passes_count' ] ,
- 424 penalty_strength : float = DEFAULT_PARAMS_VALUE [ 'penalty_strength' ] ,
- 425 penalty_saturation : float = DEFAULT_PARAMS_VALUE [ 'penalty_saturation' ] ,
- 426
- 427 survival_time_attr : str = None ,
- 428 minsupp_new : float = DEFAULT_PARAMS_VALUE [ 'minsupp_new' ] ,
- 429 max_growing : int = DEFAULT_PARAMS_VALUE [ 'max_growing' ] ,
- 430 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ 'enable_pruning' ] ,
- 431 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ 'ignore_missing' ] ,
- 432 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ 'max_uncovered_fraction' ] ,
- 433 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ 'select_best_candidate' ] ,
- 434 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [ 'complementary_conditions' ] ,
- 435 max_rule_count : int = DEFAULT_PARAMS_VALUE [ 'max_rule_count' ] ,
- 436 ) :
- 437 """
- 438 Parameters
- 439 ----------
- 440 minsupp_all: Tuple[float, float, float, float]
- 441 a minimum positive support of a contrast set (p/P). When multiple values are specified,
- 442 a metainduction is performed; Default and recommended sequence is: 0.8, 0.5, 0.2, 0.1
- 443 max_neg2pos: float
- 444 a maximum ratio of negative to positive supports (nP/pN); Default is 0.5
- 445 max_passes_count: int
- 446 a maximum number of sequential covering passes for a single minsupp-all; Default is 5
- 447 penalty_strength: float
- 448 (s) - penalty strength; Default is 0.5
- 449 penalty_saturation: float
- 450 the value of p_new / P at which penalty reward saturates; Default is 0.2.
- 451 survival_time_attr : str
- 452 name of column containing survival time data (use when data passed to model is pandas
- 453 dataframe).
- 454 minsupp_new : float = 5.0
- 455 a minimum number (or fraction, if value < 1.0) of previously uncovered examples
- 456 to be covered by a new rule (positive examples for classification problems); default: 5,
- 457 max_growing : int = 0.0
- 458 non-negative integer representing maximum number of conditions which can be added to
- 459 the rule in the growing phase (use this parameter for large datasets if execution time
- 460 is prohibitive); 0 indicates no limit; default: 0,
- 461 enable_pruning : bool = True
- 462 enable or disable pruning, default is True.
- 463 ignore_missing : bool = False
- 464 boolean telling whether missing values should be ignored (by default, a missing value
- 465 of given attribute is always considered as not fulfilling the condition build upon that
- 466 attribute); default: False.
- 467 max_uncovered_fraction : float = 0.0
- 468 Floating-point number from [0,1] interval representing maximum fraction of examples
- 469 that may remain uncovered by the rule set, default: 0.0.
- 470 select_best_candidate : bool = False
- 471 Flag determining if best candidate should be selected from growing phase;
- 472 default: False.
- 473 complementary_conditions : bool = False
- 474 If enabled, complementary conditions in the form a = !{value} for nominal attributes
- 475 are supported.
- 476 max_rule_count : int = 0
- 477 Maximum number of rules to be generated (for classification data sets it applies
- 478 to a single class); 0 indicates no limit.
- 479 """
- 480 self . _params = None
- 481 self . _rule_generator = None
- 482 self . _configurator = None
- 483 self . contrast_attribute : str = None
- 484 self . _initialize_rulekit ( )
- 485 self . set_params (
- 486 minsupp_all = minsupp_all ,
- 487 max_neg2pos = max_neg2pos ,
- 488 max_passes_count = max_passes_count ,
- 489 penalty_strength = penalty_strength ,
- 490 penalty_saturation = penalty_saturation ,
- 491 survival_time_attr = survival_time_attr ,
- 492 minsupp_new = minsupp_new ,
- 493 max_growing = max_growing ,
- 494 enable_pruning = enable_pruning ,
- 495 ignore_missing = ignore_missing ,
- 496 max_uncovered_fraction = max_uncovered_fraction ,
- 497 select_best_candidate = select_best_candidate ,
- 498 complementary_conditions = complementary_conditions ,
- 499 max_rule_count = max_rule_count
- 500 )
- 501 self . model : RuleSet [ SurvivalRule ] = None
- 502
- 503 def set_params ( self , ** kwargs ) -> object :
- 504 """Set models hyperparameters. Parameters are the same as in constructor."""
- 505 # params validation
- 506 self . survival_time_attr = kwargs [ 'survival_time_attr' ]
- 507 return BaseOperator . set_params ( self , ** kwargs )
- 508
- 509 def fit ( # pylint: disable=arguments-renamed
- 510 self ,
- 511 values : Data ,
- 512 labels : Data ,
- 513 contrast_attribute : str ,
- 514 survival_time : Data = None
- 515 ) -> ContrastSetSurvivalRules :
- 516 """Train model on given dataset.
- 517
- 518 Parameters
- 519 ----------
- 520 values : :class:`rulekit.operator.Data`
- 521 attributes
- 522 labels : :class:`rulekit.operator.Data`
- 523 survival status
- 524 contrast_attribute: str
- 525 group attribute
- 526 survival_time: :class:`rulekit.operator.Data`
- 527 data about survival time. Could be omitted when *survival_time_attr* parameter
- 528 was specified.
- 529
- 530 Returns
- 531 -------
- 532 self : ContrastSetSurvivalRules
- 533 """
- 534 survival_time_attribute = SurvivalRules . _prepare_survival_attribute ( # pylint: disable=protected-access
- 535 self , survival_time , values )
- 536 super ( ) . fit (
- 537 values , labels ,
- 538 survival_time_attribute = survival_time_attribute ,
- 539 contrast_attribute = contrast_attribute )
- 540 self . contrast_attribute = contrast_attribute
- 541 return self
- 542
- 543 def predict ( self , values : Data ) -> np . ndarray :
- 544 """Perform prediction and return estimated survival function for each example.
- 545
- 546 Parameters
- 547 ----------
- 548 values : :class:`rulekit.operator.Data`
- 549 attributes
- 550
- 551 Returns
- 552 -------
- 553 result : np.ndarray
- 554 Each row represent single example from dataset and contains estimated survival function
- 555 for that example. Estimated survival function is returned as a dictionary containing
- 556 times and corresponding probabilities.
- 557 """
- 558 return PredictionResultMapper . map_survival ( super ( ) . predict ( values ) )
- 559
- 560 def score ( self , values : Data , labels : Data , survival_time : Data = None ) -> float :
- 561 """Return the Integrated Brier Score on the given dataset and
- 562 labels(event status indicator).
- 563
- 564 Integrated Brier Score (IBS) - the Brier score (BS) represents the squared difference
- 565 between true event status at time T and predicted event status at that time;
- 566 the Integrated Brier score summarizes the prediction error over all observations and
- 567 over all times in a test set.
- 568
- 569 Parameters
- 570 ----------
- 571 values : :class:`rulekit.operator.Data`
- 572 attributes
- 573 labels : :class:`rulekit.operator.Data`
- 574 survival status
- 575 survival_time: :class:`rulekit.operator.Data`
- 576 data about survival time. Could be omitted when *survival_time_attr* parameter was
- 577 specified
- 578
- 579 Returns
- 580 -------
- 581 score : float
- 582 Integrated Brier Score of self.predict(values) wrt. labels.
- 583 """
- 584 return SurvivalRules . score ( self , values , labels , survival_time = survival_time )
- 585
- 586 def _get_problem_type ( self ) -> ProblemType :
- 587 return ProblemType . CONTRAST_SURVIVAL
+ 262 def _get_problem_type ( self ) -> ProblemType :
+ 263 return ProblemType . SURVIVAL
+ 264
+ 265
+ 266 class ExpertSurvivalRules ( ExpertKnowledgeOperator , SurvivalRules ) :
+ 267 """Expert Survival model."""
+ 268
+ 269 __params_class__ = _SurvivalExpertModelParams
+ 270
+ 271 def __init__ ( # pylint: disable=super-init-not-called,too-many-arguments,too-many-locals
+ 272 self ,
+ 273 survival_time_attr : str = None ,
+ 274 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ] ,
+ 275 max_growing : int = DEFAULT_PARAMS_VALUE [ "max_growing" ] ,
+ 276 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ] ,
+ 277 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ] ,
+ 278 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ] ,
+ 279 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ] ,
+ 280 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
+ 281 "complementary_conditions"
+ 282 ] ,
+ 283 extend_using_preferred : bool = DEFAULT_PARAMS_VALUE [ "extend_using_preferred" ] ,
+ 284 extend_using_automatic : bool = DEFAULT_PARAMS_VALUE [ "extend_using_automatic" ] ,
+ 285 induce_using_preferred : bool = DEFAULT_PARAMS_VALUE [ "induce_using_preferred" ] ,
+ 286 induce_using_automatic : bool = DEFAULT_PARAMS_VALUE [ "induce_using_automatic" ] ,
+ 287 preferred_conditions_per_rule : int = DEFAULT_PARAMS_VALUE [
+ 288 "preferred_conditions_per_rule"
+ 289 ] ,
+ 290 preferred_attributes_per_rule : int = DEFAULT_PARAMS_VALUE [
+ 291 "preferred_attributes_per_rule"
+ 292 ] ,
+ 293 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ] ,
+ 294 ) :
+ 295 """
+ 296 Parameters
+ 297 ----------
+ 298 minsupp_new : float = 5.0
+ 299 a minimum number (or fraction, if value < 1.0) of previously uncovered
+ 300 examples to be covered by a new rule (positive examples for classification
+ 301 problems); default: 5,
+ 302 survival_time_attr : str
+ 303 name of column containing survival time data (use when data passed to model
+ 304 is pandas dataframe).
+ 305 max_growing : int = 0.0
+ 306 non-negative integer representing maximum number of conditions which can be
+ 307 added to the rule in the growing phase (use this parameter for large
+ 308 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
+ 309 enable_pruning : bool = True
+ 310 enable or disable pruning, default is True.
+ 311 ignore_missing : bool = False
+ 312 boolean telling whether missing values should be ignored (by default, a
+ 313 missing value of given attribute is always considered as not fulfilling the
+ 314 condition build upon that attribute); default: False.
+ 315 max_uncovered_fraction : float = 0.0
+ 316 Floating-point number from [0,1] interval representing maximum fraction of
+ 317 examples that may remain uncovered by the rule set, default: 0.0.
+ 318 select_best_candidate : bool = False
+ 319 Flag determining if best candidate should be selected from growing phase;
+ 320 default: False.
+ 321 complementary_conditions : bool = False
+ 322 If enabled, complementary conditions in the form a = !{value} for nominal
+ 323 attributes are supported.
+ 324 max_rule_count : int = 0
+ 325 Maximum number of rules to be generated (for classification data sets it
+ 326 applies to a single class); 0 indicates no limit.
+ 327
+ 328 extend_using_preferred : bool = False
+ 329 boolean indicating whether initial rules should be extended with a use of
+ 330 preferred conditions and attributes; default is False
+ 331 extend_using_automatic : bool = False
+ 332 boolean indicating whether initial rules should be extended with a use of
+ 333 automatic conditions and attributes; default is False
+ 334 induce_using_preferred : bool = False
+ 335 boolean indicating whether new rules should be induced with a use of
+ 336 preferred conditions and attributes; default is False
+ 337 induce_using_automatic : bool = False
+ 338 boolean indicating whether new rules should be induced with a use of
+ 339 automatic conditions and attributes; default is False
+ 340 preferred_conditions_per_rule : int = None
+ 341 maximum number of preferred conditions per rule; default: unlimited,
+ 342 preferred_attributes_per_rule : int = None
+ 343 maximum number of preferred attributes per rule; default: unlimited.
+ 344 """
+ 345 self . _params = None
+ 346 self . _rule_generator = None
+ 347 self . _configurator = None
+ 348 self . _initialize_rulekit ( )
+ 349 self . set_params (
+ 350 survival_time_attr = survival_time_attr ,
+ 351 minsupp_new = minsupp_new ,
+ 352 max_growing = max_growing ,
+ 353 enable_pruning = enable_pruning ,
+ 354 ignore_missing = ignore_missing ,
+ 355 max_uncovered_fraction = max_uncovered_fraction ,
+ 356 select_best_candidate = select_best_candidate ,
+ 357 extend_using_preferred = extend_using_preferred ,
+ 358 extend_using_automatic = extend_using_automatic ,
+ 359 induce_using_preferred = induce_using_preferred ,
+ 360 induce_using_automatic = induce_using_automatic ,
+ 361 preferred_conditions_per_rule = preferred_conditions_per_rule ,
+ 362 preferred_attributes_per_rule = preferred_attributes_per_rule ,
+ 363 complementary_conditions = complementary_conditions ,
+ 364 max_rule_count = max_rule_count ,
+ 365 )
+ 366 self . model : RuleSet [ SurvivalRule ] = None
+ 367
+ 368 def set_params ( self , ** kwargs ) -> object : # pylint: disable=arguments-differ
+ 369 self . survival_time_attr = kwargs [ "survival_time_attr" ]
+ 370 return ExpertKnowledgeOperator . set_params ( self , ** kwargs )
+ 371
+ 372 def fit ( # pylint: disable=arguments-differ,too-many-arguments
+ 373 self ,
+ 374 values : Data ,
+ 375 labels : Data ,
+ 376 survival_time : Data = None ,
+ 377 expert_rules : list [ Union [ str , tuple [ str , str ] ] ] = None ,
+ 378 expert_preferred_conditions : list [ Union [ str , tuple [ str , str ] ] ] = None ,
+ 379 expert_forbidden_conditions : list [ Union [ str , tuple [ str , str ] ] ] = None ,
+ 380 ) -> ExpertSurvivalRules :
+ 381 """Train model on given dataset.
+ 382
+ 383 Parameters
+ 384 ----------
+ 385 values : :class:`rulekit.operator.Data`
+ 386 attributes
+ 387 labels : Data
+ 388 survival status
+ 389 survival_time: :class:`rulekit.operator.Data`
+ 390 data about survival time. Could be omitted when *survival_time_attr*
+ 391 parameter was specified.
+ 392 expert_rules : List[Union[str, Tuple[str, str]]]
+ 393 set of initial rules, either passed as a list of strings representing rules
+ 394 or as list of tuples where first element is name of the rule and second one
+ 395 is rule string.
+ 396 expert_preferred_conditions : List[Union[str, Tuple[str, str]]]
+ 397 multiset of preferred conditions (used also for specifying preferred
+ 398 attributes by using special value Any). Either passed as a list of strings
+ 399 representing rules or as list of tuples where first element is name of the
+ 400 rule and second one is rule string.
+ 401 expert_forbidden_conditions : List[Union[str, Tuple[str, str]]]
+ 402 set of forbidden conditions (used also for specifying forbidden attributes
+ 403 by using special valye Any). Either passed as a list of strings representing
+ 404 rules or as list of tuples where first element is name of the rule and
+ 405 second one is rule string.
+ 406
+ 407 Returns
+ 408 -------
+ 409 self : ExpertSurvivalRules
+ 410 """
+ 411 survival_time_attribute = SurvivalRules . _prepare_survival_attribute (
+ 412 self , survival_time , values
+ 413 )
+ 414 return ExpertKnowledgeOperator . fit (
+ 415 self ,
+ 416 values = values ,
+ 417 labels = labels ,
+ 418 survival_time_attribute = survival_time_attribute ,
+ 419 expert_rules = expert_rules ,
+ 420 expert_preferred_conditions = expert_preferred_conditions ,
+ 421 expert_forbidden_conditions = expert_forbidden_conditions ,
+ 422 )
+ 423
+ 424 def predict ( self , values : Data ) -> np . ndarray :
+ 425 return PredictionResultMapper . map_survival (
+ 426 ExpertKnowledgeOperator . predict ( self , values )
+ 427 )
+ 428
+ 429 def _get_problem_type ( self ) -> ProblemType :
+ 430 return ProblemType . SURVIVAL
+ 431
+ 432
+ 433 class _SurvivalContrastSetModelParams ( ContrastSetModelParams , _SurvivalModelsParams ) :
+ 434 pass
+ 435
+ 436
+ 437 class ContrastSetSurvivalRules ( BaseOperator , _BaseSurvivalRulesModel ) :
+ 438 """Contrast set survival model."""
+ 439
+ 440 __params_class__ = _SurvivalContrastSetModelParams
+ 441
+ 442 def __init__ ( # pylint: disable=super-init-not-called,too-many-arguments
+ 443 self ,
+ 444 minsupp_all : Tuple [ float , float , float , float ] = DEFAULT_PARAMS_VALUE [
+ 445 "minsupp_all"
+ 446 ] ,
+ 447 max_neg2pos : float = DEFAULT_PARAMS_VALUE [ "max_neg2pos" ] ,
+ 448 max_passes_count : int = DEFAULT_PARAMS_VALUE [ "max_passes_count" ] ,
+ 449 penalty_strength : float = DEFAULT_PARAMS_VALUE [ "penalty_strength" ] ,
+ 450 penalty_saturation : float = DEFAULT_PARAMS_VALUE [ "penalty_saturation" ] ,
+ 451 survival_time_attr : str = None ,
+ 452 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ] ,
+ 453 max_growing : int = DEFAULT_PARAMS_VALUE [ "max_growing" ] ,
+ 454 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ] ,
+ 455 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ] ,
+ 456 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ] ,
+ 457 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ] ,
+ 458 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
+ 459 "complementary_conditions"
+ 460 ] ,
+ 461 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ] ,
+ 462 ) :
+ 463 """
+ 464 Parameters
+ 465 ----------
+ 466 minsupp_all: Tuple[float, float, float, float]
+ 467 a minimum positive support of a contrast set (p/P). When multiple values are
+ 468 specified, a metainduction is performed; Default and recommended sequence
+ 469 is: 0.8, 0.5, 0.2, 0.1
+ 470 max_neg2pos: float
+ 471 a maximum ratio of negative to positive supports (nP/pN); Default is 0.5
+ 472 max_passes_count: int
+ 473 a maximum number of sequential covering passes for a single minsupp-all;
+ 474 Default is 5
+ 475 penalty_strength: float
+ 476 (s) - penalty strength; Default is 0.5
+ 477 penalty_saturation: float
+ 478 the value of p_new / P at which penalty reward saturates; Default is 0.2.
+ 479 survival_time_attr : str
+ 480 name of column containing survival time data (use when data passed to model
+ 481 is pandas dataframe).
+ 482 minsupp_new : float = 5.0
+ 483 a minimum number (or fraction, if value < 1.0) of previously uncovered
+ 484 examples to be covered by a new rule (positive examples for classification
+ 485 problems); default: 5,
+ 486 max_growing : int = 0.0
+ 487 non-negative integer representing maximum number of conditions which can be
+ 488 added to the rule in the growing phase (use this parameter for large
+ 489 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
+ 490 enable_pruning : bool = True
+ 491 enable or disable pruning, default is True.
+ 492 ignore_missing : bool = False
+ 493 boolean telling whether missing values should be ignored (by default, a
+ 494 missing value of given attribute is always considered as not fulfilling the
+ 495 condition build upon that attribute); default: False.
+ 496 max_uncovered_fraction : float = 0.0
+ 497 Floating-point number from [0,1] interval representing maximum fraction of
+ 498 examples that may remain uncovered by the rule set, default: 0.0.
+ 499 select_best_candidate : bool = False
+ 500 Flag determining if best candidate should be selected from growing phase;
+ 501 default: False.
+ 502 complementary_conditions : bool = False
+ 503 If enabled, complementary conditions in the form a = !{value} for nominal
+ 504 attributes are supported.
+ 505 max_rule_count : int = 0
+ 506 Maximum number of rules to be generated (for classification data sets it
+ 507 applies to a single class); 0 indicates no limit.
+ 508 """
+ 509 self . _params = None
+ 510 self . _rule_generator = None
+ 511 self . _configurator = None
+ 512 self . contrast_attribute : str = None
+ 513 self . _initialize_rulekit ( )
+ 514 self . set_params (
+ 515 minsupp_all = minsupp_all ,
+ 516 max_neg2pos = max_neg2pos ,
+ 517 max_passes_count = max_passes_count ,
+ 518 penalty_strength = penalty_strength ,
+ 519 penalty_saturation = penalty_saturation ,
+ 520 survival_time_attr = survival_time_attr ,
+ 521 minsupp_new = minsupp_new ,
+ 522 max_growing = max_growing ,
+ 523 enable_pruning = enable_pruning ,
+ 524 ignore_missing = ignore_missing ,
+ 525 max_uncovered_fraction = max_uncovered_fraction ,
+ 526 select_best_candidate = select_best_candidate ,
+ 527 complementary_conditions = complementary_conditions ,
+ 528 max_rule_count = max_rule_count ,
+ 529 )
+ 530 self . model : RuleSet [ SurvivalRule ] = None
+ 531
+ 532 def set_params ( self , ** kwargs ) -> object :
+ 533 """Set models hyperparameters. Parameters are the same as in constructor."""
+ 534 # params validation
+ 535 self . survival_time_attr = kwargs [ "survival_time_attr" ]
+ 536 return BaseOperator . set_params ( self , ** kwargs )
+ 537
+ 538 def fit ( # pylint: disable=arguments-renamed
+ 539 self ,
+ 540 values : Data ,
+ 541 labels : Data ,
+ 542 contrast_attribute : str ,
+ 543 survival_time : Data = None ,
+ 544 ) -> ContrastSetSurvivalRules :
+ 545 """Train model on given dataset.
+ 546
+ 547 Parameters
+ 548 ----------
+ 549 values : :class:`rulekit.operator.Data`
+ 550 attributes
+ 551 labels : :class:`rulekit.operator.Data`
+ 552 survival status
+ 553 contrast_attribute: str
+ 554 group attribute
+ 555 survival_time: :class:`rulekit.operator.Data`
+ 556 data about survival time. Could be omitted when *survival_time_attr*
+ 557 parameter was specified.
+ 558
+ 559 Returns
+ 560 -------
+ 561 self : ContrastSetSurvivalRules
+ 562 """
+ 563 survival_time_attribute = SurvivalRules . _prepare_survival_attribute ( # pylint: disable=protected-access
+ 564 self , survival_time , values
+ 565 )
+ 566 super ( ) . fit (
+ 567 values ,
+ 568 labels ,
+ 569 survival_time_attribute = survival_time_attribute ,
+ 570 contrast_attribute = contrast_attribute ,
+ 571 )
+ 572 self . contrast_attribute = contrast_attribute
+ 573 return self
+ 574
+ 575 def predict ( self , values : Data ) -> np . ndarray :
+ 576 """Perform prediction and return estimated survival function for each example.
+ 577
+ 578 Parameters
+ 579 ----------
+ 580 values : :class:`rulekit.operator.Data`
+ 581 attributes
+ 582
+ 583 Returns
+ 584 -------
+ 585 result : np.ndarray
+ 586 Each row represent single example from dataset and contains estimated
+ 587 survival function for that example. Estimated survival function is returned
+ 588 as a dictionary containing times and corresponding probabilities.
+ 589 """
+ 590 return PredictionResultMapper . map_survival ( super ( ) . predict ( values ) )
+ 591
+ 592 def score ( self , values : Data , labels : Data , survival_time : Data = None ) -> float :
+ 593 """Return the Integrated Brier Score on the given dataset and
+ 594 labels(event status indicator).
+ 595
+ 596 Integrated Brier Score (IBS) - the Brier score (BS) represents the squared
+ 597 differencebetween true event status at time T and predicted event status at that
+ 598 time; the Integrated Brier score summarizes the prediction error over all
+ 599 observations and over all times in a test set.
+ 600
+ 601 Parameters
+ 602 ----------
+ 603 values : :class:`rulekit.operator.Data`
+ 604 attributes
+ 605 labels : :class:`rulekit.operator.Data`
+ 606 survival status
+ 607 survival_time: :class:`rulekit.operator.Data`
+ 608 data about survival time. Could be omitted when *survival_time_attr*
+ 609 parameter was specified
+ 610
+ 611 Returns
+ 612 -------
+ 613 score : float
+ 614 Integrated Brier Score of self.predict(values) wrt. labels.
+ 615 """
+ 616 return SurvivalRules . score ( self , values , labels , survival_time = survival_time )
+ 617
+ 618 def _get_problem_type ( self ) -> ProblemType :
+ 619 return ProblemType . CONTRAST_SURVIVAL
diff --git a/docs/reports/flake8/flake8stats.txt b/docs/reports/flake8/flake8stats.txt
index 366abe8..5003324 100644
--- a/docs/reports/flake8/flake8stats.txt
+++ b/docs/reports/flake8/flake8stats.txt
@@ -1,34 +1 @@
-21 E501 line too long (100 > 99 characters)
-250 E501 line too long (93 > 88 characters)
-1 E261 at least two spaces before inline comment
-244 E501 line too long (93 > 88 characters)
-1 W291 trailing whitespace
-244 E501 line too long (93 > 88 characters)
-239 E501 line too long (89 > 88 characters)
-3 W291 trailing whitespace
-238 E501 line too long (91 > 88 characters)
-4 W291 trailing whitespace
-238 E501 line too long (91 > 88 characters)
-231 E501 line too long (91 > 88 characters)
-3 W291 trailing whitespace
-231 E501 line too long (91 > 88 characters)
-222 E501 line too long (91 > 88 characters)
-4 W291 trailing whitespace
-222 E501 line too long (91 > 88 characters)
-211 E501 line too long (91 > 88 characters)
-130 E501 line too long (91 > 88 characters)
-80 E501 line too long (91 > 88 characters)
-36 W291 trailing whitespace
-80 E501 line too long (91 > 88 characters)
-36 W291 trailing whitespace
-80 E501 line too long (91 > 88 characters)
-79 E501 line too long (94 > 88 characters)
-78 E501 line too long (91 > 88 characters)
-2 W291 trailing whitespace
-75 E501 line too long (92 > 88 characters)
-5 W291 trailing whitespace
-75 E501 line too long (92 > 88 characters)
-9 E501 line too long (92 > 88 characters)
-2 W291 trailing whitespace
-9 E501 line too long (92 > 88 characters)
7 E501 line too long (92 > 88 characters)
diff --git a/docs/reports/flake8/index.html b/docs/reports/flake8/index.html
index 4220f0a..2b4f00d 100644
--- a/docs/reports/flake8/index.html
+++ b/docs/reports/flake8/index.html
@@ -9,7 +9,7 @@
flake8 violations
-
Generated on 2024-11-28 13:34
+
Generated on 2024-11-28 14:18
with Installed plugins: flake8-html: 0.4.3, mccabe: 0.7.0, pycodestyle: 2.12.1, pyflakes: 3.2.0
diff --git a/docs/reports/flake8/rulekit.classification.report.html b/docs/reports/flake8/rulekit.classification.report.html
index 1e43a1a..15258a4 100644
--- a/docs/reports/flake8/rulekit.classification.report.html
+++ b/docs/reports/flake8/rulekit.classification.report.html
@@ -60,8 +60,8 @@
3
+ class="code sev- ">3 from __future__ import annotations
4 from __future__ import annotations
+ class="code sev- ">4
5
+ class="code sev- ">5 from enum import Enum
6 from enum import Enum
+ class="code sev- ">6 from numbers import Number
7 from numbers import Number
+ class="code sev- ">7 from typing import Tuple
8 from typing import Tuple , TypedDict , Union
+ class="code sev- ">8 from typing import TypedDict
9
+ class="code sev- ">9 from typing import Union
10 import numpy as np
+ class="code sev- ">10
11 import pandas as pd
+ class="code sev- ">11 import numpy as np
12 from jpype import JClass , JObject
+ class="code sev- ">12 import pandas as pd
13 from sklearn import metrics
+ class="code sev- ">13 from jpype import JClass
14
+ class="code sev- ">14 from jpype import JObject
15 from rulekit._helpers import PredictionResultMapper
+ class="code sev- ">15 from sklearn import metrics
16 from rulekit._operator import BaseOperator , Data , ExpertKnowledgeOperator
+ class="code sev- ">16
17 from rulekit._problem_types import ProblemType
+ class="code sev- ">17 from rulekit._helpers import PredictionResultMapper
18 from rulekit.params import ( DEFAULT_PARAMS_VALUE , ContrastSetModelParams ,
+ class="code sev- ">18 from rulekit._operator import BaseOperator
19 ExpertModelParams , Measures , ModelsParams )
+ class="code sev- ">19 from rulekit._operator import Data
20 from rulekit.rules import ClassificationRule , RuleSet
+ class="code sev- ">20 from rulekit._operator import ExpertKnowledgeOperator
21
+ class="code sev- ">21 from rulekit._problem_types import ProblemType
22
+ class="code sev- ">22 from rulekit.params import ContrastSetModelParams
23 class ClassificationPredictionMetrics ( TypedDict ):
+ class="code sev- ">23 from rulekit.params import DEFAULT_PARAMS_VALUE
24 """Stores additional metrics for classification prediction.
+ class="code sev- ">24 from rulekit.params import ExpertModelParams
25
+ class="code sev- ">25 from rulekit.params import Measures
26 Fields:
+ class="code sev- ">26 from rulekit.params import ModelsParams
27 * rules_per_example (float): Average number of rules per example.
+ class="code sev- ">27 from rulekit.rules import ClassificationRule
28 * voting_conflicts (_type_): Number of voting conflicts.
+ class="code sev- ">28 from rulekit.rules import RuleSet
29 """
+ class="code sev- ">29
30
31 rules_per_example : float
+ class="code sev- ">31 class ClassificationPredictionMetrics ( TypedDict ):
32 voting_conflicts : float
+ class="code sev- ">32 """Stores additional metrics for classification prediction.
33
34
+ class="code sev- ">34 Fields:
35 class _ClassificationParams ( ModelsParams ):
+ class="code sev- ">35 * rules_per_example (float): Average number of rules per example.
36 control_apriori_precision : bool = DEFAULT_PARAMS_VALUE [ "control_apriori_precision" ]
+ class="code sev- ">36 * voting_conflicts (_type_): Number of voting conflicts.
37 approximate_induction : bool = DEFAULT_PARAMS_VALUE [ "approximate_induction" ]
+ class="code sev- ">37 """
38 approximate_bins_count : int = DEFAULT_PARAMS_VALUE [ "approximate_bins_count" ]
+ class="code sev- ">38
39
+ class="code sev- ">39 rules_per_example : float
40
+ class="code sev- ">40 voting_conflicts : float
41 class _ClassificationExpertParams ( _ClassificationParams , ExpertModelParams ):
+ class="code sev- ">41
42 pass
+ class="code sev- ">42
43
+ class="code sev- ">43 class _ClassificationParams ( ModelsParams ):
44
+ class="code sev- ">44 control_apriori_precision : bool = DEFAULT_PARAMS_VALUE [ "control_apriori_precision" ]
45 class BaseClassifier :
+ class="code sev- ">45 approximate_induction : bool = DEFAULT_PARAMS_VALUE [ "approximate_induction" ]
46 """:meta private:"""
+ class="code sev- ">46 approximate_bins_count : int = DEFAULT_PARAMS_VALUE [ "approximate_bins_count" ]
47
48 def __init__ ( self ):
+ class="code sev- ">48
49 self . _ClassificationRulesPerformance : JClass = (
+ class="code sev- ">49 class _ClassificationExpertParams ( _ClassificationParams , ExpertModelParams ):
50 None # pylint: disable=invalid-name
+ class="code sev- ">50 pass
51 )
+ class="code sev- ">51
52 self . _NegativeVotingConflictsPerformance : JClass = (
+ class="code sev- ">52
53 None # pylint: disable=invalid-name
+ class="code sev- ">53 class BaseClassifier :
54 )
+ class="code sev- ">54 """:meta private:"""
55 self . _init_classification_rule_performance_classes ()
+ class="code sev- ">55
56
+ class="code sev- ">56 def __init__ ( self ):
57 class MetricTypes ( Enum ):
+ class="code sev- ">57 self . _ClassificationRulesPerformance : JClass = (
58 """:meta private:"""
+ class="code sev- ">58 None # pylint: disable=invalid-name
59
+ class="code sev- ">59 )
60 RulesPerExample = 1 # pylint: disable=invalid-name
+ class="code sev- ">60 self . _NegativeVotingConflictsPerformance : JClass = (
61 VotingConflicts = 2 # pylint: disable=invalid-name
+ class="code sev- ">61 None # pylint: disable=invalid-name
62 NegativeVotingConflicts = 3 # pylint: disable=invalid-name
+ class="code sev- ">62 )
63
+ class="code sev- ">63 self . _init_classification_rule_performance_classes ()
64 def _init_classification_rule_performance_classes ( self ):
+ class="code sev- ">64
65 self . _ClassificationRulesPerformance = JClass ( # pylint: disable=invalid-name
+ class="code sev- ">65 class MetricTypes ( Enum ):
66 "adaa.analytics.rules.logic.performance.ClassificationRulesPerformance"
+ class="code sev- ">66 """:meta private:"""
67 )
+ class="code sev- ">67
68
+ class="code sev- ">68 RulesPerExample = 1 # pylint: disable=invalid-name
69 def _calculate_metric (
+ class="code sev- ">69 VotingConflicts = 2 # pylint: disable=invalid-name
70 self , example_set : JObject , metric_type : MetricTypes
+ class="code sev- ">70 NegativeVotingConflicts = 3 # pylint: disable=invalid-name
71 ) -> float :
+ class="code sev- ">71
72 metric : JObject = self . _ClassificationRulesPerformance ( metric_type . value )
+ class="code sev- ">72 def _init_classification_rule_performance_classes ( self ):
73 metric_value = float ( metric . countExample ( example_set ) . getValue ())
+ class="code sev- ">73 self . _ClassificationRulesPerformance = JClass ( # pylint: disable=invalid-name
74 return metric_value
+ class="code sev- ">74 "adaa.analytics.rules.logic.performance.ClassificationRulesPerformance"
75
+ class="code sev- ">75 )
76 def _calculate_prediction_metrics (
+ class="code sev- ">76
77 self , example_set
+ class="code sev- ">77 def _calculate_metric (
78 ) -> ClassificationPredictionMetrics :
+ class="code sev- ">78 self , example_set : JObject , metric_type : MetricTypes
79 return ClassificationPredictionMetrics (
+ class="code sev- ">79 ) -> float :
80 rules_per_example = self . _calculate_metric (
+ class="code sev- ">80 metric : JObject = self . _ClassificationRulesPerformance ( metric_type . value )
81 example_set , BaseClassifier . MetricTypes . RulesPerExample
+ class="code sev- ">81 metric_value = float ( metric . countExample ( example_set ) . getValue ())
82 ),
+ class="code sev- ">82 return metric_value
83 voting_conflicts = self . _calculate_metric (
+ class="code sev- ">83
84 example_set , BaseClassifier . MetricTypes . VotingConflicts
+ class="code sev- ">84 def _calculate_prediction_metrics (
85 ),
+ class="code sev- ">85 self , example_set
86 )
+ class="code sev- ">86 ) -> ClassificationPredictionMetrics :
87
+ class="code sev- ">87 return ClassificationPredictionMetrics (
88
+ class="code sev- ">88 rules_per_example = self . _calculate_metric (
89 class RuleClassifier ( BaseOperator , BaseClassifier ):
+ class="code sev- ">89 example_set , BaseClassifier . MetricTypes . RulesPerExample
90 """Classification model."""
+ class="code sev- ">90 ),
91
+ class="code sev- ">91 voting_conflicts = self . _calculate_metric (
92 __params_class__ = _ClassificationParams
+ class="code sev- ">92 example_set , BaseClassifier . MetricTypes . VotingConflicts
93
+ class="code sev- ">93 ),
94 def __init__ ( # pylint: disable=too-many-arguments,too-many-locals
+ class="code sev- ">94 )
95 self ,
+ class="code sev- ">95
96 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
+ class="code sev- ">96
97 induction_measure : Measures = DEFAULT_PARAMS_VALUE [ "induction_measure" ],
+ class="code sev- ">97 class RuleClassifier ( BaseOperator , BaseClassifier ):
98 pruning_measure : Union [ Measures , str ] = DEFAULT_PARAMS_VALUE [ "pruning_measure" ],
+ class="code sev- ">98 """Classification model."""
99 voting_measure : Measures = DEFAULT_PARAMS_VALUE [ "voting_measure" ],
+ class="code sev- ">99
100 max_growing : float = DEFAULT_PARAMS_VALUE [ "max_growing" ],
+ class="code sev- ">100 __params_class__ = _ClassificationParams
101 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
+ class="code sev- ">101
102 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
+ class="code sev- ">102 def __init__ ( # pylint: disable=too-many-arguments,too-many-locals
103 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
+ class="code sev- ">103 self ,
104 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
+ class="code sev- ">104 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
105 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">105 induction_measure : Measures = DEFAULT_PARAMS_VALUE [ "induction_measure" ],
106 "complementary_conditions"
+ class="code sev- ">106 pruning_measure : Union [ Measures , str ] = DEFAULT_PARAMS_VALUE [ "pruning_measure" ],
107 ],
+ class="code sev- ">107 voting_measure : Measures = DEFAULT_PARAMS_VALUE [ "voting_measure" ],
108 control_apriori_precision : bool = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">108 max_growing : float = DEFAULT_PARAMS_VALUE [ "max_growing" ],
109 "control_apriori_precision"
+ class="code sev- ">109 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
110 ],
+ class="code sev- ">110 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
111 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
+ class="code sev- ">111 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
112 approximate_induction : bool = DEFAULT_PARAMS_VALUE [ "approximate_induction" ],
+ class="code sev- ">112 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
113 approximate_bins_count : int = DEFAULT_PARAMS_VALUE [ "approximate_bins_count" ],
+ class="code sev- ">113 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
114 ):
+ class="code sev- ">114 "complementary_conditions"
115 """
+ class="code sev- ">115 ],
116 Parameters
+ class="code sev- ">116 control_apriori_precision : bool = DEFAULT_PARAMS_VALUE [
117 ----------
+ class="code sev- ">117 "control_apriori_precision"
118 minsupp_new : float = 5.0
+ class="code sev- ">118 ],
119 a minimum number (or fraction, if value < 1.0) of previously uncovered
+ class="code sev- ">119 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
120 examples to be covered by a new rule (positive examples for classification
+ class="code sev- ">120 approximate_induction : bool = DEFAULT_PARAMS_VALUE [ "approximate_induction" ],
121 problems); default: 5,
+ class="code sev- ">121 approximate_bins_count : int = DEFAULT_PARAMS_VALUE [ "approximate_bins_count" ],
122 induction_measure : :class:`rulekit.params.Measures` = :class:`rulekit.params.\
+ class="code sev- ">122 ):
123 Measures.Correlation`
+ class="code sev- ">123 """
124 measure used during induction; default measure is correlation
+ class="code sev- ">124 Parameters
125 pruning_measure : Union[:class:`rulekit.params.Measures`, str] = \
+ class="code sev- ">125 ----------
126 :class:`rulekit.params.Measures.Correlation`
+ class="code sev- ">126 minsupp_new : float = 5.0
127 measure used during pruning. Could be user defined (string), for example
+ class="code sev- ">127 a minimum number (or fraction, if value < 1.0) of previously uncovered
128 :code:`2 * p / n`; default measure is correlation
+ class="code sev- ">128 examples to be covered by a new rule (positive examples for classification
129 voting_measure : :class:`rulekit.params.Measures` = \
+ class="code sev- ">129 problems); default: 5,
130 :class:`rulekit.params.Measures.Correlation`
+ class="code sev- ">130 induction_measure : :class:`rulekit.params.Measures` = :class:`rulekit.params.\
131 measure used during voting; default measure is correlation
+ class="code sev- ">131 Measures.Correlation`
132 max_growing : int = 0.0
+ class="code sev- ">132 measure used during induction; default measure is correlation
133 non-negative integer representing maximum number of conditions which can be
+ class="code sev- ">133 pruning_measure : Union[:class:`rulekit.params.Measures`, str] = \
134 added to the rule in the growing phase (use this parameter for large
+ class="code sev- ">134 :class:`rulekit.params.Measures.Correlation`
135 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
+ class="code sev- ">135 measure used during pruning. Could be user defined (string), for example
136 enable_pruning : bool = True
+ class="code sev- ">136 :code:`2 * p / n`; default measure is correlation
137 enable or disable pruning, default is True.
+ class="code sev- ">137 voting_measure : :class:`rulekit.params.Measures` = \
138 ignore_missing : bool = False
+ class="code sev- ">138 :class:`rulekit.params.Measures.Correlation`
139 boolean telling whether missing values should be ignored (by default, a
+ class="code sev- ">139 measure used during voting; default measure is correlation
140 missing valueof given attribute is always cconsidered as not fulfilling the
+ class="code sev- ">140 max_growing : int = 0.0
141 condition build upon that attribute); default: False.
+ class="code sev- ">141 non-negative integer representing maximum number of conditions which can be
142 max_uncovered_fraction : float = 0.0
+ class="code sev- ">142 added to the rule in the growing phase (use this parameter for large
143 Floating-point number from [0,1] interval representing maximum fraction of
+ class="code sev- ">143 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
144 examples that may remain uncovered by the rule set, default: 0.0.
+ class="code sev- ">144 enable_pruning : bool = True
145 select_best_candidate : bool = False
+ class="code sev- ">145 enable or disable pruning, default is True.
146 Flag determining if best candidate should be selected from growing phase;
+ class="code sev- ">146 ignore_missing : bool = False
147 default: False.
+ class="code sev- ">147 boolean telling whether missing values should be ignored (by default, a
148 complementary_conditions : bool = False
+ class="code sev- ">148 missing valueof given attribute is always cconsidered as not fulfilling the
149 If enabled, complementary conditions in the form a = !{value} for nominal
+ class="code sev- ">149 condition build upon that attribute); default: False.
150 attributes are supported.
+ class="code sev- ">150 max_uncovered_fraction : float = 0.0
151 control_apriori_precision : bool = True
+ class="code sev- ">151 Floating-point number from [0,1] interval representing maximum fraction of
152 When inducing classification rules, verify if candidate precision is higher
+ class="code sev- ">152 examples that may remain uncovered by the rule set, default: 0.0.
153 than apriori precision of the investigated class.
+ class="code sev- ">153 select_best_candidate : bool = False
154 max_rule_count : int = 0
+ class="code sev- ">154 Flag determining if best candidate should be selected from growing phase;
155 Maximum number of rules to be generated (for classification data sets it
+ class="code sev- ">155 default: False.
156 applies to a single class); 0 indicates no limit.
+ class="code sev- ">156 complementary_conditions : bool = False
157 approximate_induction: bool = False
+ class="code sev- ">157 If enabled, complementary conditions in the form a = !{value} for nominal
158 Use an approximate induction heuristic which does not check all possible
+ class="code sev- ">158 attributes are supported.
159 splits; note: this is an experimental feature and currently works only for
+ class="code sev- ">159 control_apriori_precision : bool = True
160 classification data sets, results may change in future;
+ class="code sev- ">160 When inducing classification rules, verify if candidate precision is higher
161 approximate_bins_count: int = 100
+ class="code sev- ">161 than apriori precision of the investigated class.
162 maximum number of bins for an attribute evaluated in the approximate
+ class="code sev- ">162 max_rule_count : int = 0
163 induction.
+ class="code sev- ">163 Maximum number of rules to be generated (for classification data sets it
164 """
+ class="code sev- ">164 applies to a single class); 0 indicates no limit.
165 BaseOperator . __init__ (
+ class="code sev- ">165 approximate_induction: bool = False
166 self ,
+ class="code sev- ">166 Use an approximate induction heuristic which does not check all possible
167 minsupp_new = minsupp_new ,
+ class="code sev- ">167 splits; note: this is an experimental feature and currently works only for
168 induction_measure = induction_measure ,
+ class="code sev- ">168 classification data sets, results may change in future;
169 pruning_measure = pruning_measure ,
+ class="code sev- ">169 approximate_bins_count: int = 100
170 voting_measure = voting_measure ,
+ class="code sev- ">170 maximum number of bins for an attribute evaluated in the approximate
171 max_growing = max_growing ,
+ class="code sev- ">171 induction.
172 enable_pruning = enable_pruning ,
+ class="code sev- ">172 """
173 ignore_missing = ignore_missing ,
+ class="code sev- ">173 BaseOperator . __init__ (
174 max_uncovered_fraction = max_uncovered_fraction ,
+ class="code sev- ">174 self ,
175 select_best_candidate = select_best_candidate ,
+ class="code sev- ">175 minsupp_new = minsupp_new ,
176 complementary_conditions = complementary_conditions ,
+ class="code sev- ">176 induction_measure = induction_measure ,
177 control_apriori_precision = control_apriori_precision ,
+ class="code sev- ">177 pruning_measure = pruning_measure ,
178 max_rule_count = max_rule_count ,
+ class="code sev- ">178 voting_measure = voting_measure ,
179 approximate_induction = approximate_induction ,
+ class="code sev- ">179 max_growing = max_growing ,
180 approximate_bins_count = approximate_bins_count ,
+ class="code sev- ">180 enable_pruning = enable_pruning ,
181 )
+ class="code sev- ">181 ignore_missing = ignore_missing ,
182 BaseClassifier . __init__ ( self )
+ class="code sev- ">182 max_uncovered_fraction = max_uncovered_fraction ,
183 self . _remap_to_numeric = False
+ class="code sev- ">183 select_best_candidate = select_best_candidate ,
184 self . label_unique_values = []
+ class="code sev- ">184 complementary_conditions = complementary_conditions ,
185 self . model : RuleSet [ ClassificationRule ] = None
+ class="code sev- ">185 control_apriori_precision = control_apriori_precision ,
186
+ class="code sev- ">186 max_rule_count = max_rule_count ,
187 def _map_result ( self , predicted_example_set ) -> np . ndarray :
+ class="code sev- ">187 approximate_induction = approximate_induction ,
188 prediction : np . ndarray
+ class="code sev- ">188 approximate_bins_count = approximate_bins_count ,
189 if self . _remap_to_numeric :
+ class="code sev- ">189 )
190 prediction = PredictionResultMapper . map_to_numerical ( predicted_example_set )
+ class="code sev- ">190 BaseClassifier . __init__ ( self )
191 else :
+ class="code sev- ">191 self . _remap_to_numeric = False
192 prediction = PredictionResultMapper . map_to_nominal ( predicted_example_set )
+ class="code sev- ">192 self . label_unique_values = []
193 return prediction
+ class="code sev- ">193 self . model : RuleSet [ ClassificationRule ] = None
194
195 def _map_confidence ( self , predicted_example_set ) -> np . ndarray :
+ class="code sev- ">195 def _map_result ( self , predicted_example_set ) -> np . ndarray :
196 return PredictionResultMapper . map_confidence (
+ class="code sev- ">196 prediction : np . ndarray
197 predicted_example_set , self . label_unique_values
+ class="code sev- ">197 if self . _remap_to_numeric :
198 )
+ class="code sev- ">198 prediction = PredictionResultMapper . map_to_numerical ( predicted_example_set )
199
+ class="code sev- ">199 else :
200 def _get_unique_label_values ( self , labels : Data ):
+ class="code sev- ">200 prediction = PredictionResultMapper . map_to_nominal ( predicted_example_set )
201 tmp = {}
+ class="code sev- ">201 return prediction
202 for label_value in labels :
+ class="code sev- ">202
203 tmp [ label_value ] = None
+ class="code sev- ">203 def _map_confidence ( self , predicted_example_set ) -> np . ndarray :
204 self . label_unique_values = list ( tmp . keys ())
+ class="code sev- ">204 return PredictionResultMapper . map_confidence (
205 if len ( self . label_unique_values ) > 0 and isinstance (
+ class="code sev- ">205 predicted_example_set , self . label_unique_values
206 self . label_unique_values [ 0 ], bytes
+ class="code sev- ">206 )
207 ):
+ class="code sev- ">207
208 self . label_unique_values = [
+ class="code sev- ">208 def _get_unique_label_values ( self , labels : Data ):
209 item . decode ( "utf-8" ) for item in self . label_unique_values
+ class="code sev- ">209 tmp = {}
210 ]
+ class="code sev- ">210 for label_value in labels :
211
+ class="code sev- ">211 tmp [ label_value ] = None
212 def _prepare_labels ( self , labels : Data ) -> Data :
+ class="code sev- ">212 self . label_unique_values = list ( tmp . keys ())
213 if isinstance ( labels , ( pd . DataFrame , pd . Series )):
+ class="code sev- ">213 if len ( self . label_unique_values ) > 0 and isinstance (
214 if labels . dtypes . name == "bool" :
+ class="code sev- ">214 self . label_unique_values [ 0 ], bytes
215 return labels . astype ( str )
+ class="code sev- ">215 ):
216 if isinstance ( labels . iloc [ 0 ], Number ):
+ class="code sev- ">216 self . label_unique_values = [
217 self . _remap_to_numeric = True
+ class="code sev- ">217 item . decode ( "utf-8" ) for item in self . label_unique_values
218 return labels . astype ( str )
+ class="code sev- ">218 ]
219 else :
+ class="code sev- ">219
220 if isinstance ( labels [ 0 ], bool ) or (
+ class="code sev- ">220 def _prepare_labels ( self , labels : Data ) -> Data :
221 isinstance ( labels , np . ndarray ) and labels . dtype . name == "bool"
+ class="code sev- ">221 if isinstance ( labels , ( pd . DataFrame , pd . Series )):
222 ):
+ class="code sev- ">222 if labels . dtypes . name == "bool" :
223 return np . array ( list ( map ( str , labels )))
+ class="code sev- ">223 return labels . astype ( str )
224 if isinstance ( labels [ 0 ], Number ):
+ class="code sev- ">224 if isinstance ( labels . iloc [ 0 ], Number ):
225 self . _remap_to_numeric = True
226 return np . array ( list ( map ( str , labels )))
+ class="code sev- ">226 return labels . astype ( str )
227 return labels
+ class="code sev- ">227 else :
228
+ class="code sev- ">228 if isinstance ( labels [ 0 ], bool ) or (
229 def fit (
+ class="code sev- ">229 isinstance ( labels , np . ndarray ) and labels . dtype . name == "bool"
230 self , values : Data , labels : Data
+ class="code sev- ">230 ):
231 ) -> RuleClassifier : # pylint: disable=arguments-differ
+ class="code sev- ">231 return np . array ( list ( map ( str , labels )))
232 """Train model on given dataset.
+ class="code sev- ">232 if isinstance ( labels [ 0 ], Number ):
233
+ class="code sev- ">233 self . _remap_to_numeric = True
234 Parameters
+ class="code sev- ">234 return np . array ( list ( map ( str , labels )))
235 ----------
+ class="code sev- ">235 return labels
236 values : :class:`rulekit.operator.Data`
+ class="code sev- ">236
237 attributes
+ class="code sev- ">237 def fit (
238 labels : :class:`rulekit.operator.Data`
+ class="code sev- ">238 self , values : Data , labels : Data
239 labels
+ class="code sev- ">239 ) -> RuleClassifier : # pylint: disable=arguments-differ
240 Returns
+ class="code sev- ">240 """Train model on given dataset.
241 -------
+ class="code sev- ">241
242 self : RuleClassifier
+ class="code sev- ">242 Parameters
243 """
+ class="code sev- ">243 ----------
244 self . _get_unique_label_values ( labels )
+ class="code sev- ">244 values : :class:`rulekit.operator.Data`
245 labels = self . _prepare_labels ( labels )
+ class="code sev- ">245 attributes
246 BaseOperator . fit ( self , values , labels )
+ class="code sev- ">246 labels : :class:`rulekit.operator.Data`
247 return self
+ class="code sev- ">247 labels
248
+ class="code sev- ">248 Returns
249 def predict (
+ class="code sev- ">249 -------
250 self , values : Data , return_metrics : bool = False
+ class="code sev- ">250 self : RuleClassifier
251 ) -> Union [ np . ndarray , tuple [ np . ndarray , ClassificationPredictionMetrics ]]:
+ class="code sev- ">251 """
252 """Perform prediction and returns predicted labels.
+ class="code sev- ">252 self . _get_unique_label_values ( labels )
253
+ class="code sev- ">253 labels = self . _prepare_labels ( labels )
254 Parameters
+ class="code sev- ">254 BaseOperator . fit ( self , values , labels )
255 ----------
+ class="code sev- ">255 return self
256 values : :class:`rulekit.operator.Data`
+ class="code sev- ">256
257 attributes
+ class="code sev- ">257 def predict (
258
+ class="code sev- ">258 self , values : Data , return_metrics : bool = False
259 return_metrics: bool = False
+ class="code sev- ">259 ) -> Union [ np . ndarray , tuple [ np . ndarray , ClassificationPredictionMetrics ]]:
260 Optional flag. If set to *True* method will calculate some additional model
+ class="code sev- ">260 """Perform prediction and returns predicted labels.
261 metrics. Method will then return tuple instead of just predicted labels.
+ class="code sev- ">261
262
+ class="code sev- ">262 Parameters
263 Returns
+ class="code sev- ">263 ----------
264 -------
+ class="code sev- ">264 values : :class:`rulekit.operator.Data`
265 result : Union[np.ndarray, tuple[np.ndarray, :class:`rulekit.classification.\
+ class="code sev- ">265 attributes
266 ClassificationPredictionMetrics`]]
+ class="code sev- ">266
267 If *return_metrics* flag wasn't set it will return just prediction,
+ class="code sev- ">267 return_metrics: bool = False
268 otherwise a tuple will be returned with first element being prediction and
+ class="code sev- ">268 Optional flag. If set to *True* method will calculate some additional model
269 second one being metrics.
+ class="code sev- ">269 metrics. Method will then return tuple instead of just predicted labels.
270 """
+ class="code sev- ">270
271 result_example_set = BaseOperator . predict ( self , values )
+ class="code sev- ">271 Returns
272 y_pred = self . _map_result ( result_example_set )
+ class="code sev- ">272 -------
273 if return_metrics :
+ class="code sev- ">273 result : Union[np.ndarray, tuple[np.ndarray, :class:`rulekit.classification.\
274 metrics_values : dict = BaseClassifier . _calculate_prediction_metrics (
+ class="code sev- ">274 ClassificationPredictionMetrics`]]
275 self , result_example_set
+ class="code sev- ">275 If *return_metrics* flag wasn't set it will return just prediction,
276 )
+ class="code sev- ">276 otherwise a tuple will be returned with first element being prediction and
277 return ( y_pred , metrics_values )
+ class="code sev- ">277 second one being metrics.
278 return y_pred
+ class="code sev- ">278 """
279
+ class="code sev- ">279 result_example_set = BaseOperator . predict ( self , values )
280 def predict_proba (
+ class="code sev- ">280 y_pred = self . _map_result ( result_example_set )
281 self , values : Data , return_metrics : bool = False
+ class="code sev- ">281 if return_metrics :
282 ) -> Union [ np . ndarray , tuple [ np . ndarray , ClassificationPredictionMetrics ]]:
+ class="code sev- ">282 metrics_values : dict = BaseClassifier . _calculate_prediction_metrics (
283 """Perform prediction and returns class probabilities for each example.
+ class="code sev- ">283 self , result_example_set
284
+ class="code sev- ">284 )
285 Parameters
+ class="code sev- ">285 return ( y_pred , metrics_values )
286 ----------
+ class="code sev- ">286 return y_pred
287 values : :class:`rulekit.operator.Data`
+ class="code sev- ">287
288 attributes
+ class="code sev- ">288 def predict_proba (
289
+ class="code sev- ">289 self , values : Data , return_metrics : bool = False
290 return_metrics: bool = False
+ class="code sev- ">290 ) -> Union [ np . ndarray , tuple [ np . ndarray , ClassificationPredictionMetrics ]]:
291 Optional flag. If set to *True* method will calculate some additional model
+ class="code sev- ">291 """Perform prediction and returns class probabilities for each example.
292 metrics. Method will then return tuple instead of just probabilities.
+ class="code sev- ">292
293
+ class="code sev- ">293 Parameters
294 Returns
+ class="code sev- ">294 ----------
295 -------
+ class="code sev- ">295 values : :class:`rulekit.operator.Data`
296 result : Union[np.ndarray, tuple[np.ndarray, :class:`rulekit.classification.\
+ class="code sev- ">296 attributes
297 ClassificationPredictionMetrics`]]
+ class="code sev- ">297
298 If *return_metrics* flag wasn't set it will return just probabilities
+ class="code sev- ">298 return_metrics: bool = False
299 matrix, otherwise a tuple will be returned with first element being
+ class="code sev- ">299 Optional flag. If set to *True* method will calculate some additional model
300 prediction and second one being metrics.
+ class="code sev- ">300 metrics. Method will then return tuple instead of just probabilities.
301 """
+ class="code sev- ">301
302 result_example_set = BaseOperator . predict ( self , values )
+ class="code sev- ">302 Returns
303 mapped_result_example_set = self . _map_confidence ( result_example_set )
+ class="code sev- ">303 -------
304 if return_metrics :
+ class="code sev- ">304 result : Union[np.ndarray, tuple[np.ndarray, :class:`rulekit.classification.\
305 metrics_values : dict = BaseClassifier . _calculate_prediction_metrics (
+ class="code sev- ">305 ClassificationPredictionMetrics`]]
306 self , result_example_set
+ class="code sev- ">306 If *return_metrics* flag wasn't set it will return just probabilities
307 )
+ class="code sev- ">307 matrix, otherwise a tuple will be returned with first element being
308 return ( mapped_result_example_set , metrics_values )
+ class="code sev- ">308 prediction and second one being metrics.
309 return mapped_result_example_set
+ class="code sev- ">309 """
310
+ class="code sev- ">310 result_example_set = BaseOperator . predict ( self , values )
311 def score ( self , values : Data , labels : Data ) -> float :
+ class="code sev- ">311 mapped_result_example_set = self . _map_confidence ( result_example_set )
312 """Return the accuracy on the given test data and labels.
+ class="code sev- ">312 if return_metrics :
313
+ class="code sev- ">313 metrics_values : dict = BaseClassifier . _calculate_prediction_metrics (
314 Parameters
+ class="code sev- ">314 self , result_example_set
315 ----------
+ class="code sev- ">315 )
316 values : :class:`rulekit.operator.Data`
+ class="code sev- ">316 return ( mapped_result_example_set , metrics_values )
317 attributes
+ class="code sev- ">317 return mapped_result_example_set
318 labels : :class:`rulekit.operator.Data`
+ class="code sev- ">318
319 true labels
+ class="code sev- ">319 def score ( self , values : Data , labels : Data ) -> float :
320
+ class="code sev- ">320 """Return the accuracy on the given test data and labels.
321 Returns
+ class="code sev- ">321
322 -------
+ class="code sev- ">322 Parameters
323 score : float
+ class="code sev- ">323 ----------
324 Accuracy of self.predict(values) wrt. labels.
+ class="code sev- ">324 values : :class:`rulekit.operator.Data`
325 """
+ class="code sev- ">325 attributes
326 predicted_labels = self . predict ( values )
+ class="code sev- ">326 labels : :class:`rulekit.operator.Data`
327 return metrics . accuracy_score ( labels , predicted_labels )
+ class="code sev- ">327 true labels
328
329 def __getstate__ ( self ) -> dict :
+ class="code sev- ">329 Returns
330 return {
+ class="code sev- ">330 -------
331 ** BaseOperator . __getstate__ ( self ),
+ class="code sev- ">331 score : float
332 ** {
+ class="code sev- ">332 Accuracy of self.predict(values) wrt. labels.
333 "label_unique_values" : self . label_unique_values ,
+ class="code sev- ">333 """
334 "_remap_to_numeric" : self . _remap_to_numeric ,
+ class="code sev- ">334 predicted_labels = self . predict ( values )
335 },
+ class="code sev- ">335 return metrics . accuracy_score ( labels , predicted_labels )
336 }
+ class="code sev- ">336
337
+ class="code sev- ">337 def __getstate__ ( self ) -> dict :
338 def __setstate__ ( self , state : dict ):
+ class="code sev- ">338 return {
339 BaseOperator . __setstate__ ( self , state )
+ class="code sev- ">339 ** BaseOperator . __getstate__ ( self ),
340 self . _init_classification_rule_performance_classes ()
+ class="code sev- ">340 ** {
341 self . label_unique_values = state [ "label_unique_values" ]
+ class="code sev- ">341 "label_unique_values" : self . label_unique_values ,
342 self . _remap_to_numeric = state [ "_remap_to_numeric" ]
+ class="code sev- ">342 "_remap_to_numeric" : self . _remap_to_numeric ,
343
+ class="code sev- ">343 },
344 def _get_problem_type ( self ) -> ProblemType :
+ class="code sev- ">344 }
345 return ProblemType . CLASSIFICATION
+ class="code sev- ">345
346
+ class="code sev- ">346 def __setstate__ ( self , state : dict ):
347
+ class="code sev- ">347 BaseOperator . __setstate__ ( self , state )
348 class ExpertRuleClassifier ( ExpertKnowledgeOperator , RuleClassifier ):
+ class="code sev- ">348 self . _init_classification_rule_performance_classes ()
349 """Classification model using expert knowledge."""
+ class="code sev- ">349 self . label_unique_values = state [ "label_unique_values" ]
350
+ class="code sev- ">350 self . _remap_to_numeric = state [ "_remap_to_numeric" ]
351 __params_class__ = _ClassificationExpertParams
+ class="code sev- ">351
352
+ class="code sev- ">352 def _get_problem_type ( self ) -> ProblemType :
353 def __init__ ( # pylint: disable=too-many-arguments,too-many-locals
+ class="code sev- ">353 return ProblemType . CLASSIFICATION
354 self ,
+ class="code sev- ">354
355 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
+ class="code sev- ">355
356 induction_measure : Measures = DEFAULT_PARAMS_VALUE [ "induction_measure" ],
+ class="code sev- ">356 class ExpertRuleClassifier ( ExpertKnowledgeOperator , RuleClassifier ):
357 pruning_measure : Union [ Measures , str ] = DEFAULT_PARAMS_VALUE [ "pruning_measure" ],
+ class="code sev- ">357 """Classification model using expert knowledge."""
358 voting_measure : Measures = DEFAULT_PARAMS_VALUE [ "voting_measure" ],
+ class="code sev- ">358
359 max_growing : float = DEFAULT_PARAMS_VALUE [ "max_growing" ],
+ class="code sev- ">359 __params_class__ = _ClassificationExpertParams
360 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
+ class="code sev- ">360
361 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
+ class="code sev- ">361 def __init__ ( # pylint: disable=too-many-arguments,too-many-locals
362 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
+ class="code sev- ">362 self ,
363 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
+ class="code sev- ">363 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
364 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">364 induction_measure : Measures = DEFAULT_PARAMS_VALUE [ "induction_measure" ],
365 "complementary_conditions"
+ class="code sev- ">365 pruning_measure : Union [ Measures , str ] = DEFAULT_PARAMS_VALUE [ "pruning_measure" ],
366 ],
+ class="code sev- ">366 voting_measure : Measures = DEFAULT_PARAMS_VALUE [ "voting_measure" ],
367 control_apriori_precision : bool = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">367 max_growing : float = DEFAULT_PARAMS_VALUE [ "max_growing" ],
368 "control_apriori_precision"
+ class="code sev- ">368 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
369 ],
+ class="code sev- ">369 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
370 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
+ class="code sev- ">370 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
371 approximate_induction : bool = DEFAULT_PARAMS_VALUE [ "approximate_induction" ],
+ class="code sev- ">371 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
372 approximate_bins_count : int = DEFAULT_PARAMS_VALUE [ "approximate_bins_count" ],
+ class="code sev- ">372 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
373 extend_using_preferred : bool = DEFAULT_PARAMS_VALUE [ "extend_using_preferred" ],
+ class="code sev- ">373 "complementary_conditions"
374 extend_using_automatic : bool = DEFAULT_PARAMS_VALUE [ "extend_using_automatic" ],
+ class="code sev- ">374 ],
375 induce_using_preferred : bool = DEFAULT_PARAMS_VALUE [ "induce_using_preferred" ],
+ class="code sev- ">375 control_apriori_precision : bool = DEFAULT_PARAMS_VALUE [
376 induce_using_automatic : bool = DEFAULT_PARAMS_VALUE [ "induce_using_automatic" ],
+ class="code sev- ">376 "control_apriori_precision"
377 consider_other_classes : bool = DEFAULT_PARAMS_VALUE [ "consider_other_classes" ],
+ class="code sev- ">377 ],
378 preferred_conditions_per_rule : int = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">378 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
379 "preferred_conditions_per_rule"
+ class="code sev- ">379 approximate_induction : bool = DEFAULT_PARAMS_VALUE [ "approximate_induction" ],
380 ],
+ class="code sev- ">380 approximate_bins_count : int = DEFAULT_PARAMS_VALUE [ "approximate_bins_count" ],
381 preferred_attributes_per_rule : int = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">381 extend_using_preferred : bool = DEFAULT_PARAMS_VALUE [ "extend_using_preferred" ],
382 "preferred_attributes_per_rule"
+ class="code sev- ">382 extend_using_automatic : bool = DEFAULT_PARAMS_VALUE [ "extend_using_automatic" ],
383 ],
+ class="code sev- ">383 induce_using_preferred : bool = DEFAULT_PARAMS_VALUE [ "induce_using_preferred" ],
384 ):
+ class="code sev- ">384 induce_using_automatic : bool = DEFAULT_PARAMS_VALUE [ "induce_using_automatic" ],
385 """
+ class="code sev- ">385 consider_other_classes : bool = DEFAULT_PARAMS_VALUE [ "consider_other_classes" ],
386 Parameters
+ class="code sev- ">386 preferred_conditions_per_rule : int = DEFAULT_PARAMS_VALUE [
387 ----------
+ class="code sev- ">387 "preferred_conditions_per_rule"
388 minsupp_new : float = 5.0
+ class="code sev- ">388 ],
389 a minimum number (or fraction, if value < 1.0) of previously uncovered examples
+ class="code sev- ">389 preferred_attributes_per_rule : int = DEFAULT_PARAMS_VALUE [
390 to be covered by a new rule (positive examples for classification problems);
+ class="code sev- ">390 "preferred_attributes_per_rule"
391 default: 5,
+ class="code sev- ">391 ],
392
+ class="code sev- ">392 ):
393 induction_measure : :class:`rulekit.params.Measures` = \
+ class="code sev- ">393 """
394 :class:`rulekit.params.Measures.Correlation`
+ class="code sev- ">394 Parameters
395 measure used during induction; default measure is correlation
+ class="code sev- ">395 ----------
396 pruning_measure : Union[:class:`rulekit.params.Measures`, str] = \
+ class="code sev- ">396 minsupp_new : float = 5.0
397 :class:`rulekit.params.Measures.Correlation`
+ class="code sev- ">397 a minimum number (or fraction, if value < 1.0) of previously uncovered examples
398 measure used during pruning. Could be user defined (string), for example
+ class="code sev- ">398 to be covered by a new rule (positive examples for classification problems);
399 :code:`2 * p / n`; default measure is correlation
+ class="code sev- ">399 default: 5,
400 voting_measure : :class:`rulekit.params.Measures` = \
+ class="code sev- ">400
401 :class:`rulekit.params.Measures.Correlation`
+ class="code sev- ">401 induction_measure : :class:`rulekit.params.Measures` = \
402 measure used during voting; default measure is correlation
+ class="code sev- ">402 :class:`rulekit.params.Measures.Correlation`
403 max_growing : int = 0.0
+ class="code sev- ">403 measure used during induction; default measure is correlation
404 non-negative integer representing maximum number of conditions which can be
+ class="code sev- ">404 pruning_measure : Union[:class:`rulekit.params.Measures`, str] = \
405 added to the rule in the growing phase (use this parameter for large
+ class="code sev- ">405 :class:`rulekit.params.Measures.Correlation`
406 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
+ class="code sev- ">406 measure used during pruning. Could be user defined (string), for example
407 enable_pruning : bool = True
+ class="code sev- ">407 :code:`2 * p / n`; default measure is correlation
408 enable or disable pruning, default is True.
+ class="code sev- ">408 voting_measure : :class:`rulekit.params.Measures` = \
409 ignore_missing : bool = False
+ class="code sev- ">409 :class:`rulekit.params.Measures.Correlation`
410 boolean telling whether missing values should be ignored (by default, a
+ class="code sev- ">410 measure used during voting; default measure is correlation
411 missing value of given attribute is always considered as not fulfilling the
+ class="code sev- ">411 max_growing : int = 0.0
412 condition build upon that attribute); default: False.
+ class="code sev- ">412 non-negative integer representing maximum number of conditions which can be
413 max_uncovered_fraction : float = 0.0
+ class="code sev- ">413 added to the rule in the growing phase (use this parameter for large
414 Floating-point number from [0,1] interval representing maximum fraction of
+ class="code sev- ">414 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
415 examples that may remain uncovered by the rule set, default: 0.0.
+ class="code sev- ">415 enable_pruning : bool = True
416 select_best_candidate : bool = False
+ class="code sev- ">416 enable or disable pruning, default is True.
417 Flag determining if best candidate should be selected from growing phase;
+ class="code sev- ">417 ignore_missing : bool = False
418 default: False.
+ class="code sev- ">418 boolean telling whether missing values should be ignored (by default, a
419 complementary_conditions : bool = False
+ class="code sev- ">419 missing value of given attribute is always considered as not fulfilling the
420 If enabled, complementary conditions in the form a = !{value} for nominal
+ class="code sev- ">420 condition build upon that attribute); default: False.
421 attributes
+ class="code sev- ">421 max_uncovered_fraction : float = 0.0
422 are supported.
+ class="code sev- ">422 Floating-point number from [0,1] interval representing maximum fraction of
423 control_apriori_precision : bool = True
+ class="code sev- ">423 examples that may remain uncovered by the rule set, default: 0.0.
424 When inducing classification rules, verify if candidate precision is higher
+ class="code sev- ">424 select_best_candidate : bool = False
425 than apriori precision of the investigated class.
+ class="code sev- ">425 Flag determining if best candidate should be selected from growing phase;
426 max_rule_count : int = 0
+ class="code sev- ">426 default: False.
427 Maximum number of rules to be generated (for classification data sets it
+ class="code sev- ">427 complementary_conditions : bool = False
428 applies to a single class); 0 indicates no limit.
+ class="code sev- ">428 If enabled, complementary conditions in the form a = !{value} for nominal
429 approximate_induction: bool = False
+ class="code sev- ">429 attributes
430 Use an approximate induction heuristic which does not check all possible
+ class="code sev- ">430 are supported.
431 splits; note: this is an experimental feature and currently works only for
+ class="code sev- ">431 control_apriori_precision : bool = True
432 classification data sets, results may change in future;
+ class="code sev- ">432 When inducing classification rules, verify if candidate precision is higher
433 approximate_bins_count: int = 100
+ class="code sev- ">433 than apriori precision of the investigated class.
434 maximum number of bins for an attribute evaluated in the approximate
+ class="code sev- ">434 max_rule_count : int = 0
435 induction.
+ class="code sev- ">435 Maximum number of rules to be generated (for classification data sets it
436
+ class="code sev- ">436 applies to a single class); 0 indicates no limit.
437 extend_using_preferred : bool = False
+ class="code sev- ">437 approximate_induction: bool = False
438 boolean indicating whether initial rules should be extended with a use of
+ class="code sev- ">438 Use an approximate induction heuristic which does not check all possible
439 preferred conditions and attributes; default is False
+ class="code sev- ">439 splits; note: this is an experimental feature and currently works only for
440 extend_using_automatic : bool = False
+ class="code sev- ">440 classification data sets, results may change in future;
441 boolean indicating whether initial rules should be extended with a use of
+ class="code sev- ">441 approximate_bins_count: int = 100
442 automatic conditions and attributes; default is False
+ class="code sev- ">442 maximum number of bins for an attribute evaluated in the approximate
443 induce_using_preferred : bool = False
+ class="code sev- ">443 induction.
444 boolean indicating whether new rules should be induced with a use of
+ class="code sev- ">444
445 preferred conditions and attributes; default is False
+ class="code sev- ">445 extend_using_preferred : bool = False
446 induce_using_automatic : bool = False
+ class="code sev- ">446 boolean indicating whether initial rules should be extended with a use of
447 boolean indicating whether new rules should be induced with a use of
+ class="code sev- ">447 preferred conditions and attributes; default is False
448 automatic conditions and attributes; default is False
+ class="code sev- ">448 extend_using_automatic : bool = False
449 consider_other_classes : bool = False
+ class="code sev- ">449 boolean indicating whether initial rules should be extended with a use of
450 boolean indicating whether automatic induction should be performed for
+ class="code sev- ">450 automatic conditions and attributes; default is False
451 classes for which no user's knowledge has been defined
+ class="code sev- ">451 induce_using_preferred : bool = False
452 (classification only); default is False.
+ class="code sev- ">452 boolean indicating whether new rules should be induced with a use of
453 preferred_conditions_per_rule : int = None
+ class="code sev- ">453 preferred conditions and attributes; default is False
454 maximum number of preferred conditions per rule; default: unlimited,
+ class="code sev- ">454 induce_using_automatic : bool = False
455 preferred_attributes_per_rule : int = None
+ class="code sev- ">455 boolean indicating whether new rules should be induced with a use of
456 maximum number of preferred attributes per rule; default: unlimited.
+ class="code sev- ">456 automatic conditions and attributes; default is False
457 """
+ class="code sev- ">457 consider_other_classes : bool = False
458 self . _remap_to_numeric = False
+ class="code sev- ">458 boolean indicating whether automatic induction should be performed for
459 RuleClassifier . __init__ (
+ class="code sev- ">459 classes for which no user's knowledge has been defined
460 self ,
+ class="code sev- ">460 (classification only); default is False.
461 minsupp_new = minsupp_new ,
+ class="code sev- ">461 preferred_conditions_per_rule : int = None
462 induction_measure = induction_measure ,
+ class="code sev- ">462 maximum number of preferred conditions per rule; default: unlimited,
463 pruning_measure = pruning_measure ,
+ class="code sev- ">463 preferred_attributes_per_rule : int = None
464 voting_measure = voting_measure ,
+ class="code sev- ">464 maximum number of preferred attributes per rule; default: unlimited.
465 max_growing = max_growing ,
+ class="code sev- ">465 """
466 enable_pruning = enable_pruning ,
+ class="code sev- ">466 self . _remap_to_numeric = False
467 ignore_missing = ignore_missing ,
+ class="code sev- ">467 RuleClassifier . __init__ (
468 max_uncovered_fraction = max_uncovered_fraction ,
+ class="code sev- ">468 self ,
469 select_best_candidate = select_best_candidate ,
+ class="code sev- ">469 minsupp_new = minsupp_new ,
470 complementary_conditions = complementary_conditions ,
+ class="code sev- ">470 induction_measure = induction_measure ,
471 control_apriori_precision = control_apriori_precision ,
+ class="code sev- ">471 pruning_measure = pruning_measure ,
472 max_rule_count = max_rule_count ,
+ class="code sev- ">472 voting_measure = voting_measure ,
473 approximate_induction = approximate_induction ,
+ class="code sev- ">473 max_growing = max_growing ,
474 approximate_bins_count = approximate_bins_count ,
+ class="code sev- ">474 enable_pruning = enable_pruning ,
475 )
+ class="code sev- ">475 ignore_missing = ignore_missing ,
476 ExpertKnowledgeOperator . __init__ (
+ class="code sev- ">476 max_uncovered_fraction = max_uncovered_fraction ,
477 self ,
+ class="code sev- ">477 select_best_candidate = select_best_candidate ,
478 minsupp_new = minsupp_new ,
+ class="code sev- ">478 complementary_conditions = complementary_conditions ,
479 induction_measure = induction_measure ,
+ class="code sev- ">479 control_apriori_precision = control_apriori_precision ,
480 pruning_measure = pruning_measure ,
+ class="code sev- ">480 max_rule_count = max_rule_count ,
481 voting_measure = voting_measure ,
+ class="code sev- ">481 approximate_induction = approximate_induction ,
482 max_growing = max_growing ,
+ class="code sev- ">482 approximate_bins_count = approximate_bins_count ,
483 enable_pruning = enable_pruning ,
+ class="code sev- ">483 )
484 ignore_missing = ignore_missing ,
+ class="code sev- ">484 ExpertKnowledgeOperator . __init__ (
485 max_uncovered_fraction = max_uncovered_fraction ,
+ class="code sev- ">485 self ,
486 select_best_candidate = select_best_candidate ,
+ class="code sev- ">486 minsupp_new = minsupp_new ,
487 complementary_conditions = complementary_conditions ,
+ class="code sev- ">487 induction_measure = induction_measure ,
488 extend_using_preferred = extend_using_preferred ,
+ class="code sev- ">488 pruning_measure = pruning_measure ,
489 extend_using_automatic = extend_using_automatic ,
+ class="code sev- ">489 voting_measure = voting_measure ,
490 induce_using_preferred = induce_using_preferred ,
+ class="code sev- ">490 max_growing = max_growing ,
491 induce_using_automatic = induce_using_automatic ,
+ class="code sev- ">491 enable_pruning = enable_pruning ,
492 consider_other_classes = consider_other_classes ,
+ class="code sev- ">492 ignore_missing = ignore_missing ,
493 preferred_conditions_per_rule = preferred_conditions_per_rule ,
+ class="code sev- ">493 max_uncovered_fraction = max_uncovered_fraction ,
494 preferred_attributes_per_rule = preferred_attributes_per_rule ,
+ class="code sev- ">494 select_best_candidate = select_best_candidate ,
495 control_apriori_precision = control_apriori_precision ,
+ class="code sev- ">495 complementary_conditions = complementary_conditions ,
496 max_rule_count = max_rule_count ,
+ class="code sev- ">496 extend_using_preferred = extend_using_preferred ,
497 approximate_induction = approximate_induction ,
+ class="code sev- ">497 extend_using_automatic = extend_using_automatic ,
498 approximate_bins_count = approximate_bins_count ,
+ class="code sev- ">498 induce_using_preferred = induce_using_preferred ,
499 )
+ class="code sev- ">499 induce_using_automatic = induce_using_automatic ,
500 self . model : RuleSet [ ClassificationRule ] = None
+ class="code sev- ">500 consider_other_classes = consider_other_classes ,
501
+ class="code sev- ">501 preferred_conditions_per_rule = preferred_conditions_per_rule ,
502 def fit ( # pylint: disable=arguments-differ,too-many-arguments
+ class="code sev- ">502 preferred_attributes_per_rule = preferred_attributes_per_rule ,
503 self ,
+ class="code sev- ">503 control_apriori_precision = control_apriori_precision ,
504 values : Data ,
+ class="code sev- ">504 max_rule_count = max_rule_count ,
505 labels : Data ,
+ class="code sev- ">505 approximate_induction = approximate_induction ,
506 expert_rules : list [ Union [ str , tuple [ str , str ]]] = None ,
+ class="code sev- ">506 approximate_bins_count = approximate_bins_count ,
507 expert_preferred_conditions : list [ Union [ str , tuple [ str , str ]]] = None ,
+ class="code sev- ">507 )
508 expert_forbidden_conditions : list [ Union [ str , tuple [ str , str ]]] = None ,
+ class="code sev- ">508 self . model : RuleSet [ ClassificationRule ] = None
509 ) -> ExpertRuleClassifier :
+ class="code sev- ">509
510 """Train model on given dataset.
+ class="code sev- ">510 def fit ( # pylint: disable=arguments-differ,too-many-arguments
511
+ class="code sev- ">511 self ,
512 Parameters
+ class="code sev- ">512 values : Data ,
513 ----------
+ class="code sev- ">513 labels : Data ,
514 values : :class:`rulekit.operator.Data`
+ class="code sev- ">514 expert_rules : list [ Union [ str , tuple [ str , str ]]] = None ,
515 attributes
+ class="code sev- ">515 expert_preferred_conditions : list [ Union [ str , tuple [ str , str ]]] = None ,
516 labels : :class:`rulekit.operator.Data`
+ class="code sev- ">516 expert_forbidden_conditions : list [ Union [ str , tuple [ str , str ]]] = None ,
517 labels
+ class="code sev- ">517 ) -> ExpertRuleClassifier :
518
+ class="code sev- ">518 """Train model on given dataset.
519 expert_rules : List[Union[str, Tuple[str, str]]]
+ class="code sev- ">519
520 set of initial rules, either passed as a list of strings representing rules
+ class="code sev- ">520 Parameters
521 or as list of tuples where first element is name of the rule and second one
+ class="code sev- ">521 ----------
522 is rule string.
+ class="code sev- ">522 values : :class:`rulekit.operator.Data`
523 expert_preferred_conditions : List[Union[str, Tuple[str, str]]]
+ class="code sev- ">523 attributes
524 multiset of preferred conditions (used also for specifying preferred
+ class="code sev- ">524 labels : :class:`rulekit.operator.Data`
525 attributes by using special value Any). Either passed as a list of strings
+ class="code sev- ">525 labels
526 representing rules or as list of tuples where first element is name of the
+ class="code sev- ">526
527 rule and second one is rule string.
+ class="code sev- ">527 expert_rules : List[Union[str, Tuple[str, str]]]
528 expert_forbidden_conditions : List[Union[str, Tuple[str, str]]]
+ class="code sev- ">528 set of initial rules, either passed as a list of strings representing rules
529 set of forbidden conditions (used also for specifying forbidden attributes
+ class="code sev- ">529 or as list of tuples where first element is name of the rule and second one
530 by using special value Any). Either passed as a list of strings representing
+ class="code sev- ">530 is rule string.
531 rules or as list of tuples where first element is name of the rule and
+ class="code sev- ">531 expert_preferred_conditions : List[Union[str, Tuple[str, str]]]
532 second one is rule string.
+ class="code sev- ">532 multiset of preferred conditions (used also for specifying preferred
533 Returns
+ class="code sev- ">533 attributes by using special value Any). Either passed as a list of strings
534 -------
+ class="code sev- ">534 representing rules or as list of tuples where first element is name of the
535 self : ExpertRuleClassifier
+ class="code sev- ">535 rule and second one is rule string.
536 """
+ class="code sev- ">536 expert_forbidden_conditions : List[Union[str, Tuple[str, str]]]
537 if isinstance ( labels , ( pd . DataFrame , pd . Series )):
+ class="code sev- ">537 set of forbidden conditions (used also for specifying forbidden attributes
538 if isinstance ( labels . iloc [ 0 ], Number ):
+ class="code sev- ">538 by using special value Any). Either passed as a list of strings representing
539 self . _remap_to_numeric = True
+ class="code sev- ">539 rules or as list of tuples where first element is name of the rule and
540 labels = labels . astype ( str )
+ class="code sev- ">540 second one is rule string.
541 else :
+ class="code sev- ">541 Returns
542 if isinstance ( labels [ 0 ], Number ):
+ class="code sev- ">542 -------
543 self . _remap_to_numeric = True
+ class="code sev- ">543 self : ExpertRuleClassifier
544 labels = list ( map ( str , labels ))
+ class="code sev- ">544 """
545 self . _get_unique_label_values ( labels )
+ class="code sev- ">545 if isinstance ( labels , ( pd . DataFrame , pd . Series )):
546 self . _prepare_labels ( labels )
+ class="code sev- ">546 if isinstance ( labels . iloc [ 0 ], Number ):
547 return ExpertKnowledgeOperator . fit (
+ class="code sev- ">547 self . _remap_to_numeric = True
548 self ,
+ class="code sev- ">548 labels = labels . astype ( str )
549 values ,
+ class="code sev- ">549 else :
550 labels ,
+ class="code sev- ">550 if isinstance ( labels [ 0 ], Number ):
551 expert_rules = expert_rules ,
+ class="code sev- ">551 self . _remap_to_numeric = True
552 expert_preferred_conditions = expert_preferred_conditions ,
+ class="code sev- ">552 labels = list ( map ( str , labels ))
553 expert_forbidden_conditions = expert_forbidden_conditions ,
+ class="code sev- ">553 self . _get_unique_label_values ( labels )
554 )
+ class="code sev- ">554 self . _prepare_labels ( labels )
555
+ class="code sev- ">555 return ExpertKnowledgeOperator . fit (
556 def predict (
+ class="code sev- ">556 self ,
557 self , values : Data , return_metrics : bool = False
+ class="code sev- ">557 values ,
558 ) -> Union [ np . ndarray , tuple [ np . ndarray , ClassificationPredictionMetrics ]]:
+ class="code sev- ">558 labels ,
559 return RuleClassifier . predict ( self , values , return_metrics )
+ class="code sev- ">559 expert_rules = expert_rules ,
560
+ class="code sev- ">560 expert_preferred_conditions = expert_preferred_conditions ,
561 def __getstate__ ( self ) -> dict :
+ class="code sev- ">561 expert_forbidden_conditions = expert_forbidden_conditions ,
562 return {
+ class="code sev- ">562 )
563 ** BaseOperator . __getstate__ ( self ),
+ class="code sev- ">563
564 ** { "_remap_to_numeric" : self . _remap_to_numeric },
+ class="code sev- ">564 def predict (
565 }
+ class="code sev- ">565 self , values : Data , return_metrics : bool = False
566
+ class="code sev- ">566 ) -> Union [ np . ndarray , tuple [ np . ndarray , ClassificationPredictionMetrics ]]:
567 def __setstate__ ( self , state : dict ):
+ class="code sev- ">567 return RuleClassifier . predict ( self , values , return_metrics )
568 BaseOperator . __setstate__ ( self , state )
+ class="code sev- ">568
569 self . _remap_to_numeric = state [ "_remap_to_numeric" ]
+ class="code sev- ">569 def __getstate__ ( self ) -> dict :
570
+ class="code sev- ">570 return {
571 def _get_problem_type ( self ) -> ProblemType :
+ class="code sev- ">571 ** BaseOperator . __getstate__ ( self ),
572 return ProblemType . CLASSIFICATION
+ class="code sev- ">572 ** { "_remap_to_numeric" : self . _remap_to_numeric },
573
+ class="code sev- ">573 }
574
575 class ContrastSetRuleClassifier ( BaseOperator , BaseClassifier ):
+ class="code sev- ">575 def __setstate__ ( self , state : dict ):
576 """Contrast set classification model."""
+ class="code sev- ">576 BaseOperator . __setstate__ ( self , state )
577
+ class="code sev- ">577 self . _remap_to_numeric = state [ "_remap_to_numeric" ]
578 __params_class__ = ContrastSetModelParams
+ class="code sev- ">578
579
+ class="code sev- ">579 def _get_problem_type ( self ) -> ProblemType :
580 def __init__ ( # pylint: disable=too-many-arguments,too-many-locals
+ class="code sev- ">580 return ProblemType . CLASSIFICATION
581 self ,
+ class="code sev- ">581
582 minsupp_all : Tuple [ float , float , float , float ] = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">582
583 "minsupp_all"
+ class="code sev- ">583 class ContrastSetRuleClassifier ( BaseOperator , BaseClassifier ):
584 ],
+ class="code sev- ">584 """Contrast set classification model."""
585 max_neg2pos : float = DEFAULT_PARAMS_VALUE [ "max_neg2pos" ],
+ class="code sev- ">585
586 max_passes_count : int = DEFAULT_PARAMS_VALUE [ "max_passes_count" ],
+ class="code sev- ">586 __params_class__ = ContrastSetModelParams
587 penalty_strength : float = DEFAULT_PARAMS_VALUE [ "penalty_strength" ],
+ class="code sev- ">587
588 penalty_saturation : float = DEFAULT_PARAMS_VALUE [ "penalty_saturation" ],
+ class="code sev- ">588 def __init__ ( # pylint: disable=too-many-arguments,too-many-locals
589 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
+ class="code sev- ">589 self ,
590 induction_measure : Measures = DEFAULT_PARAMS_VALUE [ "induction_measure" ],
+ class="code sev- ">590 minsupp_all : Tuple [ float , float , float , float ] = DEFAULT_PARAMS_VALUE [
591 pruning_measure : Union [ Measures , str ] = DEFAULT_PARAMS_VALUE [ "pruning_measure" ],
+ class="code sev- ">591 "minsupp_all"
592 voting_measure : Measures = DEFAULT_PARAMS_VALUE [ "voting_measure" ],
+ class="code sev- ">592 ],
593 max_growing : float = DEFAULT_PARAMS_VALUE [ "max_growing" ],
+ class="code sev- ">593 max_neg2pos : float = DEFAULT_PARAMS_VALUE [ "max_neg2pos" ],
594 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
+ class="code sev- ">594 max_passes_count : int = DEFAULT_PARAMS_VALUE [ "max_passes_count" ],
595 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
+ class="code sev- ">595 penalty_strength : float = DEFAULT_PARAMS_VALUE [ "penalty_strength" ],
596 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
+ class="code sev- ">596 penalty_saturation : float = DEFAULT_PARAMS_VALUE [ "penalty_saturation" ],
597 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
+ class="code sev- ">597 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
598 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">598 induction_measure : Measures = DEFAULT_PARAMS_VALUE [ "induction_measure" ],
599 "complementary_conditions"
+ class="code sev- ">599 pruning_measure : Union [ Measures , str ] = DEFAULT_PARAMS_VALUE [ "pruning_measure" ],
600 ],
+ class="code sev- ">600 voting_measure : Measures = DEFAULT_PARAMS_VALUE [ "voting_measure" ],
601 control_apriori_precision : bool = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">601 max_growing : float = DEFAULT_PARAMS_VALUE [ "max_growing" ],
602 "control_apriori_precision"
+ class="code sev- ">602 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
603 ],
+ class="code sev- ">603 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
604 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
+ class="code sev- ">604 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
605 approximate_induction : bool = DEFAULT_PARAMS_VALUE [ "approximate_induction" ],
+ class="code sev- ">605 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
606 approximate_bins_count : int = DEFAULT_PARAMS_VALUE [ "approximate_bins_count" ],
+ class="code sev- ">606 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
607 ):
+ class="code sev- ">607 "complementary_conditions"
608 """
+ class="code sev- ">608 ],
609 Parameters
+ class="code sev- ">609 control_apriori_precision : bool = DEFAULT_PARAMS_VALUE [
610 ----------
+ class="code sev- ">610 "control_apriori_precision"
611 minsupp_all: Tuple[float, float, float, float]
+ class="code sev- ">611 ],
612 a minimum positive support of a contrast set (p/P). When multiple values
+ class="code sev- ">612 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
613 are specified, a metainduction is performed; Default and recommended
+ class="code sev- ">613 approximate_induction : bool = DEFAULT_PARAMS_VALUE [ "approximate_induction" ],
614 sequence is: 0.8, 0.5, 0.2, 0.1
+ class="code sev- ">614 approximate_bins_count : int = DEFAULT_PARAMS_VALUE [ "approximate_bins_count" ],
615 max_neg2pos: float
+ class="code sev- ">615 ):
616 a maximum ratio of negative to positive supports (nP/pN); Default is 0.5
+ class="code sev- ">616 """
617 max_passes_count: int
+ class="code sev- ">617 Parameters
618 a maximum number of sequential covering passes for a single minsupp-all;
+ class="code sev- ">618 ----------
619 Default is 5
+ class="code sev- ">619 minsupp_all: Tuple[float, float, float, float]
620 penalty_strength: float
+ class="code sev- ">620 a minimum positive support of a contrast set (p/P). When multiple values
621 (s) - penalty strength; Default is 0.5
+ class="code sev- ">621 are specified, a metainduction is performed; Default and recommended
622 penalty_saturation: float
+ class="code sev- ">622 sequence is: 0.8, 0.5, 0.2, 0.1
623 the value of p_new / P at which penalty reward saturates; Default is 0.2.
+ class="code sev- ">623 max_neg2pos: float
624 minsupp_new : float = 5.0
+ class="code sev- ">624 a maximum ratio of negative to positive supports (nP/pN); Default is 0.5
625 a minimum number (or fraction, if value < 1.0) of previously uncovered
+ class="code sev- ">625 max_passes_count: int
626 examples to be covered by a new rule (positive examples for classification
+ class="code sev- ">626 a maximum number of sequential covering passes for a single minsupp-all;
627 problems); default: 5,
+ class="code sev- ">627 Default is 5
628 induction_measure : :class:`rulekit.params.Measures` = \
+ class="code sev- ">628 penalty_strength: float
629 :class:`rulekit.params.Measures.Correlation`
+ class="code sev- ">629 (s) - penalty strength; Default is 0.5
630 measure used during induction; default measure is correlation
+ class="code sev- ">630 penalty_saturation: float
631 pruning_measure : Union[:class:`rulekit.params.Measures`, str] = \
+ class="code sev- ">631 the value of p_new / P at which penalty reward saturates; Default is 0.2.
632 :class:`rulekit.params.Measures.Correlation`
+ class="code sev- ">632 minsupp_new : float = 5.0
633 measure used during pruning. Could be user defined (string), for example
+ class="code sev- ">633 a minimum number (or fraction, if value < 1.0) of previously uncovered
634 :code:`2 * p / n`; default measure is correlation
+ class="code sev- ">634 examples to be covered by a new rule (positive examples for classification
635 voting_measure : :class:`rulekit.params.Measures` = \
+ class="code sev- ">635 problems); default: 5,
636 :class:`rulekit.params.Measures.Correlation`
+ class="code sev- ">636 induction_measure : :class:`rulekit.params.Measures` = \
637 measure used during voting; default measure is correlation
+ class="code sev- ">637 :class:`rulekit.params.Measures.Correlation`
638 max_growing : int = 0.0
+ class="code sev- ">638 measure used during induction; default measure is correlation
639 non-negative integer representing maximum number of conditions which can be
+ class="code sev- ">639 pruning_measure : Union[:class:`rulekit.params.Measures`, str] = \
640 added to the rule in the growing phase (use this parameter for large
+ class="code sev- ">640 :class:`rulekit.params.Measures.Correlation`
641 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
+ class="code sev- ">641 measure used during pruning. Could be user defined (string), for example
642 enable_pruning : bool = True
+ class="code sev- ">642 :code:`2 * p / n`; default measure is correlation
643 enable or disable pruning, default is True.
+ class="code sev- ">643 voting_measure : :class:`rulekit.params.Measures` = \
644 ignore_missing : bool = False
+ class="code sev- ">644 :class:`rulekit.params.Measures.Correlation`
645 boolean telling whether missing values should be ignored (by default, a
+ class="code sev- ">645 measure used during voting; default measure is correlation
646 missing value of given attribute is always considered as not fulfilling the
+ class="code sev- ">646 max_growing : int = 0.0
647 condition build upon that attribute); default: False.
+ class="code sev- ">647 non-negative integer representing maximum number of conditions which can be
648 max_uncovered_fraction : float = 0.0
+ class="code sev- ">648 added to the rule in the growing phase (use this parameter for large
649 Floating-point number from [0,1] interval representing maximum fraction of
+ class="code sev- ">649 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
650 examples that may remain uncovered by the rule set, default: 0.0.
+ class="code sev- ">650 enable_pruning : bool = True
651 select_best_candidate : bool = False
+ class="code sev- ">651 enable or disable pruning, default is True.
652 Flag determining if best candidate should be selected from growing phase;
+ class="code sev- ">652 ignore_missing : bool = False
653 default: False.
+ class="code sev- ">653 boolean telling whether missing values should be ignored (by default, a
654 complementary_conditions : bool = False
+ class="code sev- ">654 missing value of given attribute is always considered as not fulfilling the
655 If enabled, complementary conditions in the form a = !{value} for nominal
+ class="code sev- ">655 condition build upon that attribute); default: False.
656 attributes are supported.
+ class="code sev- ">656 max_uncovered_fraction : float = 0.0
657 control_apriori_precision : bool = True
+ class="code sev- ">657 Floating-point number from [0,1] interval representing maximum fraction of
658 When inducing classification rules, verify if candidate precision is higher
+ class="code sev- ">658 examples that may remain uncovered by the rule set, default: 0.0.
659 than apriori precision of the investigated class.
+ class="code sev- ">659 select_best_candidate : bool = False
660 max_rule_count : int = 0
+ class="code sev- ">660 Flag determining if best candidate should be selected from growing phase;
661 Maximum number of rules to be generated (for classification data sets it
+ class="code sev- ">661 default: False.
662 applies to a single class); 0 indicates no limit.
+ class="code sev- ">662 complementary_conditions : bool = False
663 approximate_induction: bool = False
+ class="code sev- ">663 If enabled, complementary conditions in the form a = !{value} for nominal
664 Use an approximate induction heuristic which does not check all possible
+ class="code sev- ">664 attributes are supported.
665 splits; note: this is an experimental feature and currently works only for
+ class="code sev- ">665 control_apriori_precision : bool = True
666 classification data sets, results may change in future;
+ class="code sev- ">666 When inducing classification rules, verify if candidate precision is higher
667 approximate_bins_count: int = 100
+ class="code sev- ">667 than apriori precision of the investigated class.
668 maximum number of bins for an attribute evaluated in the approximate
+ class="code sev- ">668 max_rule_count : int = 0
669 induction.
+ class="code sev- ">669 Maximum number of rules to be generated (for classification data sets it
670 """
+ class="code sev- ">670 applies to a single class); 0 indicates no limit.
671 BaseOperator . __init__ (
+ class="code sev- ">671 approximate_induction: bool = False
672 self ,
+ class="code sev- ">672 Use an approximate induction heuristic which does not check all possible
673 minsupp_all = minsupp_all ,
+ class="code sev- ">673 splits; note: this is an experimental feature and currently works only for
674 max_neg2pos = max_neg2pos ,
+ class="code sev- ">674 classification data sets, results may change in future;
675 max_passes_count = max_passes_count ,
+ class="code sev- ">675 approximate_bins_count: int = 100
676 penalty_strength = penalty_strength ,
+ class="code sev- ">676 maximum number of bins for an attribute evaluated in the approximate
677 penalty_saturation = penalty_saturation ,
+ class="code sev- ">677 induction.
678 minsupp_new = minsupp_new ,
+ class="code sev- ">678 """
679 induction_measure = induction_measure ,
+ class="code sev- ">679 BaseOperator . __init__ (
680 pruning_measure = pruning_measure ,
+ class="code sev- ">680 self ,
681 voting_measure = voting_measure ,
+ class="code sev- ">681 minsupp_all = minsupp_all ,
682 max_growing = max_growing ,
+ class="code sev- ">682 max_neg2pos = max_neg2pos ,
683 enable_pruning = enable_pruning ,
+ class="code sev- ">683 max_passes_count = max_passes_count ,
684 ignore_missing = ignore_missing ,
+ class="code sev- ">684 penalty_strength = penalty_strength ,
685 max_uncovered_fraction = max_uncovered_fraction ,
+ class="code sev- ">685 penalty_saturation = penalty_saturation ,
686 select_best_candidate = select_best_candidate ,
+ class="code sev- ">686 minsupp_new = minsupp_new ,
687 complementary_conditions = complementary_conditions ,
+ class="code sev- ">687 induction_measure = induction_measure ,
688 control_apriori_precision = control_apriori_precision ,
+ class="code sev- ">688 pruning_measure = pruning_measure ,
689 max_rule_count = max_rule_count ,
+ class="code sev- ">689 voting_measure = voting_measure ,
690 approximate_induction = approximate_induction ,
+ class="code sev- ">690 max_growing = max_growing ,
691 approximate_bins_count = approximate_bins_count ,
+ class="code sev- ">691 enable_pruning = enable_pruning ,
692 )
+ class="code sev- ">692 ignore_missing = ignore_missing ,
693 BaseClassifier . __init__ ( self )
+ class="code sev- ">693 max_uncovered_fraction = max_uncovered_fraction ,
694 self . contrast_attribute : str = None
+ class="code sev- ">694 select_best_candidate = select_best_candidate ,
695 self . _remap_to_numeric = False
+ class="code sev- ">695 complementary_conditions = complementary_conditions ,
696 self . label_unique_values = []
+ class="code sev- ">696 control_apriori_precision = control_apriori_precision ,
697 self . model : RuleSet [ ClassificationRule ] = None
+ class="code sev- ">697 max_rule_count = max_rule_count ,
698
+ class="code sev- ">698 approximate_induction = approximate_induction ,
699 def _map_result ( self , predicted_example_set ) -> np . ndarray :
+ class="code sev- ">699 approximate_bins_count = approximate_bins_count ,
700 prediction : np . ndarray
+ class="code sev- ">700 )
701 if self . _remap_to_numeric :
+ class="code sev- ">701 BaseClassifier . __init__ ( self )
702 prediction = PredictionResultMapper . map_to_numerical ( predicted_example_set )
+ class="code sev- ">702 self . contrast_attribute : str = None
703 else :
+ class="code sev- ">703 self . _remap_to_numeric = False
704 prediction = PredictionResultMapper . map_to_nominal ( predicted_example_set )
+ class="code sev- ">704 self . label_unique_values = []
705 return prediction
+ class="code sev- ">705 self . model : RuleSet [ ClassificationRule ] = None
706
707 def _get_unique_label_values ( self , labels : Data ):
+ class="code sev- ">707 def _map_result ( self , predicted_example_set ) -> np . ndarray :
708 tmp = {}
+ class="code sev- ">708 prediction : np . ndarray
709 for label_value in labels :
+ class="code sev- ">709 if self . _remap_to_numeric :
710 tmp [ label_value ] = None
+ class="code sev- ">710 prediction = PredictionResultMapper . map_to_numerical ( predicted_example_set )
711 self . label_unique_values = list ( tmp . keys ())
+ class="code sev- ">711 else :
712 if len ( self . label_unique_values ) > 0 and isinstance (
+ class="code sev- ">712 prediction = PredictionResultMapper . map_to_nominal ( predicted_example_set )
713 self . label_unique_values [ 0 ], bytes
+ class="code sev- ">713 return prediction
714 ):
+ class="code sev- ">714
715 self . label_unique_values = [
+ class="code sev- ">715 def _get_unique_label_values ( self , labels : Data ):
716 item . decode ( "utf-8" ) for item in self . label_unique_values
+ class="code sev- ">716 tmp = {}
717 ]
+ class="code sev- ">717 for label_value in labels :
718
+ class="code sev- ">718 tmp [ label_value ] = None
719 def fit (
+ class="code sev- ">719 self . label_unique_values = list ( tmp . keys ())
720 self , values : Data , labels : Data , contrast_attribute : str
+ class="code sev- ">720 if len ( self . label_unique_values ) > 0 and isinstance (
721 ) -> ContrastSetRuleClassifier : # pylint: disable=arguments-differ
+ class="code sev- ">721 self . label_unique_values [ 0 ], bytes
722 """Train model on given dataset.
+ class="code sev- ">722 ):
723
+ class="code sev- ">723 self . label_unique_values = [
724 Parameters
+ class="code sev- ">724 item . decode ( "utf-8" ) for item in self . label_unique_values
725 ----------
+ class="code sev- ">725 ]
726 values : :class:`rulekit.operator.Data`
+ class="code sev- ">726
727 attributes
+ class="code sev- ">727 def fit (
728 labels : :class:`rulekit.operator.Data`
+ class="code sev- ">728 self , values : Data , labels : Data , contrast_attribute : str
729 labels
+ class="code sev- ">729 ) -> ContrastSetRuleClassifier : # pylint: disable=arguments-differ
730 contrast_attribute: str
+ class="code sev- ">730 """Train model on given dataset.
731 group attribute
+ class="code sev- ">731
732 Returns
+ class="code sev- ">732 Parameters
733 -------
+ class="code sev- ">733 ----------
734 self : ContrastSetRuleClassifier
+ class="code sev- ">734 values : :class:`rulekit.operator.Data`
735 """
+ class="code sev- ">735 attributes
736 RuleClassifier . _get_unique_label_values ( # pylint: disable=protected-access
+ class="code sev- ">736 labels : :class:`rulekit.operator.Data`
737 self , labels
+ class="code sev- ">737 labels
738 )
+ class="code sev- ">738 contrast_attribute: str
-
-
-
-
- E501
-
- Line too long (92 > 88 characters)
-
- 739 RuleClassifier . _prepare_labels ( # pylint: disable=protected-access,protected-access
+ class="code sev- ">
739 group attribute
740 self , labels
+ class="code sev- ">740 Returns
741 )
+ class="code sev- ">741 -------
742 BaseOperator . fit ( self , values , labels , contrast_attribute = contrast_attribute )
+ class="code sev- ">742 self : ContrastSetRuleClassifier
743 self . contrast_attribute = contrast_attribute
+ class="code sev- ">743 """
744 return self
+ class="code sev- ">744 RuleClassifier . _get_unique_label_values ( # pylint: disable=protected-access
745
+ class="code sev- ">745 self , labels
746 def predict (
+ class="code sev- ">746 )
747 self , values : Data , return_metrics : bool = False
+ class="code sev-2 le">
+
+
+
+
+ E501
+
+ Line too long (92 > 88 characters)
+
+ 747 RuleClassifier . _prepare_labels ( # pylint: disable=protected-access,protected-access
748 ) -> Union [ np . ndarray , tuple [ np . ndarray , ClassificationPredictionMetrics ]]:
+ class="code sev- ">748 self , labels
749 """Perform prediction and returns predicted labels.
+ class="code sev- ">749 )
750
+ class="code sev- ">750 BaseOperator . fit ( self , values , labels , contrast_attribute = contrast_attribute )
751 Parameters
+ class="code sev- ">751 self . contrast_attribute = contrast_attribute
752 ----------
+ class="code sev- ">752 return self
753 values : :class:`rulekit.operator.Data`
+ class="code sev- ">753
754 attributes
+ class="code sev- ">754 def predict (
755
+ class="code sev- ">755 self , values : Data , return_metrics : bool = False
756 return_metrics: bool = False
+ class="code sev- ">756 ) -> Union [ np . ndarray , tuple [ np . ndarray , ClassificationPredictionMetrics ]]:
757 Optional flag. If set to *True* method will calculate some additional model
+ class="code sev- ">757 """Perform prediction and returns predicted labels.
758 metrics. Method will then return tuple instead of just predicted labels.
+ class="code sev- ">758
759
+ class="code sev- ">759 Parameters
760 Returns
+ class="code sev- ">760 ----------
761 -------
+ class="code sev- ">761 values : :class:`rulekit.operator.Data`
762 result : Union[np.ndarray, tuple[np.ndarray, :class:`rulekit.classification.\
+ class="code sev- ">762 attributes
763 ClassificationPredictionMetrics`]]
+ class="code sev- ">763
764 If *return_metrics* flag wasn't set it will return just prediction,
+ class="code sev- ">764 return_metrics: bool = False
765 otherwise a tuple will be returned with first element being prediction and
+ class="code sev- ">765 Optional flag. If set to *True* method will calculate some additional model
766 second one being metrics.
+ class="code sev- ">766 metrics. Method will then return tuple instead of just predicted labels.
767 """
+ class="code sev- ">767
768 return RuleClassifier . predict ( self , values , return_metrics )
+ class="code sev- ">768 Returns
769
+ class="code sev- ">769 -------
770 def predict_proba (
+ class="code sev- ">770 result : Union[np.ndarray, tuple[np.ndarray, :class:`rulekit.classification.\
771 self , values : Data , return_metrics : bool = False
+ class="code sev- ">771 ClassificationPredictionMetrics`]]
772 ) -> Union [ np . ndarray , tuple [ np . ndarray , ClassificationPredictionMetrics ]]:
+ class="code sev- ">772 If *return_metrics* flag wasn't set it will return just prediction,
773 """Perform prediction and returns class probabilities for each example.
+ class="code sev- ">773 otherwise a tuple will be returned with first element being prediction and
774
+ class="code sev- ">774 second one being metrics.
775 Parameters
+ class="code sev- ">775 """
776 ----------
+ class="code sev- ">776 return RuleClassifier . predict ( self , values , return_metrics )
777 values : :class:`rulekit.operator.Data`
+ class="code sev- ">777
778 attributes
+ class="code sev- ">778 def predict_proba (
779
+ class="code sev- ">779 self , values : Data , return_metrics : bool = False
780 return_metrics: bool = False
+ class="code sev- ">780 ) -> Union [ np . ndarray , tuple [ np . ndarray , ClassificationPredictionMetrics ]]:
781 Optional flag. If set to *True* method will calculate some additional model
+ class="code sev- ">781 """Perform prediction and returns class probabilities for each example.
782 metrics. Method will then return tuple instead of just probabilities.
+ class="code sev- ">782
783
+ class="code sev- ">783 Parameters
784 Returns
+ class="code sev- ">784 ----------
785 -------
+ class="code sev- ">785 values : :class:`rulekit.operator.Data`
786 result : Union[np.ndarray, tuple[np.ndarray, :class:`rulekit.classification.\
+ class="code sev- ">786 attributes
787 ClassificationPredictionMetrics`]]
+ class="code sev- ">787
788 If *return_metrics* flag wasn't set it will return just probabilities
+ class="code sev- ">788 return_metrics: bool = False
789 matrix, otherwise a tuple will be returned with first element being
+ class="code sev- ">789 Optional flag. If set to *True* method will calculate some additional model
790 prediction and second one being metrics.
+ class="code sev- ">790 metrics. Method will then return tuple instead of just probabilities.
791 """
+ class="code sev- ">791
792 return RuleClassifier . predict_proba ( self , values , return_metrics )
+ class="code sev- ">792 Returns
793
+ class="code sev- ">793 -------
794 def score ( self , values : Data , labels : Data ) -> float :
+ class="code sev- ">794 result : Union[np.ndarray, tuple[np.ndarray, :class:`rulekit.classification.\
795 """Return the accuracy on the given test data and labels.
+ class="code sev- ">795 ClassificationPredictionMetrics`]]
796
+ class="code sev- ">796 If *return_metrics* flag wasn't set it will return just probabilities
797 Parameters
+ class="code sev- ">797 matrix, otherwise a tuple will be returned with first element being
798 ----------
+ class="code sev- ">798 prediction and second one being metrics.
799 values : :class:`rulekit.operator.Data`
+ class="code sev- ">799 """
800 attributes
+ class="code sev- ">800 return RuleClassifier . predict_proba ( self , values , return_metrics )
801 labels : :class:`rulekit.operator.Data`
+ class="code sev- ">801
802 true labels
+ class="code sev- ">802 def score ( self , values : Data , labels : Data ) -> float :
803
+ class="code sev- ">803 """Return the accuracy on the given test data and labels.
804 Returns
+ class="code sev- ">804
805 -------
+ class="code sev- ">805 Parameters
806 score : float
+ class="code sev- ">806 ----------
807 Accuracy of self.predict(values) wrt. labels.
+ class="code sev- ">807 values : :class:`rulekit.operator.Data`
808 """
+ class="code sev- ">808 attributes
809 return RuleClassifier . score ( self , values , labels )
+ class="code sev- ">809 labels : :class:`rulekit.operator.Data`
810
+ class="code sev- ">810 true labels
811 def __getstate__ ( self ) -> dict :
+ class="code sev- ">811
812 return {
+ class="code sev- ">812 Returns
813 ** BaseOperator . __getstate__ ( self ),
+ class="code sev- ">813 -------
814 ** {
+ class="code sev- ">814 score : float
815 "label_unique_values" : self . label_unique_values ,
+ class="code sev- ">815 Accuracy of self.predict(values) wrt. labels.
816 "_remap_to_numeric" : self . _remap_to_numeric ,
+ class="code sev- ">816 """
817 "contrast_attribute" : self . contrast_attribute ,
+ class="code sev- ">817 return RuleClassifier . score ( self , values , labels )
818 },
+ class="code sev- ">818
819 }
+ class="code sev- ">819 def __getstate__ ( self ) -> dict :
820
+ class="code sev- ">820 return {
821 def __setstate__ ( self , state : dict ):
+ class="code sev- ">821 ** BaseOperator . __getstate__ ( self ),
822 BaseOperator . __setstate__ ( self , state )
+ class="code sev- ">822 ** {
823 self . _init_classification_rule_performance_classes ()
+ class="code sev- ">823 "label_unique_values" : self . label_unique_values ,
824 self . label_unique_values = state [ "label_unique_values" ]
+ class="code sev- ">824 "_remap_to_numeric" : self . _remap_to_numeric ,
825 self . _remap_to_numeric = state [ "_remap_to_numeric" ]
+ class="code sev- ">825 "contrast_attribute" : self . contrast_attribute ,
826 self . contrast_attribute = state [ "contrast_attribute" ]
+ class="code sev- ">826 },
827
+ class="code sev- ">827 }
828 def _get_problem_type ( self ) -> ProblemType :
+ class="code sev- ">828
829 return ProblemType . CONTRAST_CLASSIFICATION
+ class="code sev- ">829 def __setstate__ ( self , state : dict ):
+
+ 830 BaseOperator . __setstate__ ( self , state )
+
+ 831 self . _init_classification_rule_performance_classes ()
+
+ 832 self . label_unique_values = state [ "label_unique_values" ]
+
+ 833 self . _remap_to_numeric = state [ "_remap_to_numeric" ]
+
+ 834 self . contrast_attribute = state [ "contrast_attribute" ]
+
+ 835
+
+ 836 def _get_problem_type ( self ) -> ProblemType :
+
+ 837 return ProblemType . CONTRAST_CLASSIFICATION
diff --git a/docs/reports/flake8/rulekit.regression.report.html b/docs/reports/flake8/rulekit.regression.report.html
index 8025a76..4856698 100644
--- a/docs/reports/flake8/rulekit.regression.report.html
+++ b/docs/reports/flake8/rulekit.regression.report.html
@@ -60,8 +60,8 @@
diff --git a/docs/reports/flake8/rulekit.regression.source.html b/docs/reports/flake8/rulekit.regression.source.html
index daab125..ce23a47 100644
--- a/docs/reports/flake8/rulekit.regression.source.html
+++ b/docs/reports/flake8/rulekit.regression.source.html
@@ -23,19 +23,19 @@
class="code sev- ">2 """
3
+ class="code sev- ">3 from __future__ import annotations
4 from __future__ import annotations
+ class="code sev- ">4
5
+ class="code sev- ">5 from numbers import Number
6 from numbers import Number
+ class="code sev- ">6 from typing import Tuple
7 from typing import Tuple , Union
+ class="code sev- ">7 from typing import Union
8
@@ -56,1579 +56,1597 @@
class="code sev- ">13 from rulekit._helpers import PredictionResultMapper
14 from rulekit._operator import BaseOperator , Data , ExpertKnowledgeOperator
+ class="code sev- ">14 from rulekit._operator import BaseOperator
15 from rulekit._problem_types import ProblemType
+ class="code sev- ">15 from rulekit._operator import Data
16 from rulekit.params import ( DEFAULT_PARAMS_VALUE , ContrastSetModelParams ,
+ class="code sev- ">16 from rulekit._operator import ExpertKnowledgeOperator
17 ExpertModelParams , Measures , ModelsParams )
+ class="code sev- ">17 from rulekit._problem_types import ProblemType
18 from rulekit.rules import RegressionRule , RuleSet
+ class="code sev- ">18 from rulekit.params import ContrastSetModelParams
19
+ class="code sev- ">19 from rulekit.params import DEFAULT_PARAMS_VALUE
20
+ class="code sev- ">20 from rulekit.params import ExpertModelParams
21 class _RegressionModelParams ( ModelsParams ):
+ class="code sev- ">21 from rulekit.params import Measures
22 mean_based_regression : bool = DEFAULT_PARAMS_VALUE [ "mean_based_regression" ]
+ class="code sev- ">22 from rulekit.params import ModelsParams
23
+ class="code sev- ">23 from rulekit.rules import RegressionRule
24
+ class="code sev- ">24 from rulekit.rules import RuleSet
25 class _RegressionExpertModelParams ( _RegressionModelParams , ExpertModelParams ):
+ class="code sev- ">25
26 pass
+ class="code sev- ">26
27
+ class="code sev- ">27 class _RegressionModelParams ( ModelsParams ):
28
+ class="code sev- ">28 mean_based_regression : bool = DEFAULT_PARAMS_VALUE [ "mean_based_regression" ]
29 class RuleRegressor ( BaseOperator ):
+ class="code sev- ">29
30 """Regression model."""
+ class="code sev- ">30
31
+ class="code sev- ">31 class _RegressionExpertModelParams ( _RegressionModelParams , ExpertModelParams ):
32 __params_class__ = _RegressionModelParams
+ class="code sev- ">32 pass
33
34 def __init__ ( # pylint: disable=too-many-arguments
+ class="code sev- ">34
35 self ,
+ class="code sev- ">35 class RuleRegressor ( BaseOperator ):
36 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
+ class="code sev- ">36 """Regression model."""
37 induction_measure : Measures = DEFAULT_PARAMS_VALUE [ "induction_measure" ],
+ class="code sev- ">37
38 pruning_measure : Union [ Measures , str ] = DEFAULT_PARAMS_VALUE [ "pruning_measure" ],
+ class="code sev- ">38 __params_class__ = _RegressionModelParams
39 voting_measure : Measures = DEFAULT_PARAMS_VALUE [ "voting_measure" ],
+ class="code sev- ">39
40 max_growing : float = DEFAULT_PARAMS_VALUE [ "max_growing" ],
+ class="code sev- ">40 def __init__ ( # pylint: disable=too-many-arguments
41 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
+ class="code sev- ">41 self ,
42 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
+ class="code sev- ">42 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
43 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
+ class="code sev- ">43 induction_measure : Measures = DEFAULT_PARAMS_VALUE [ "induction_measure" ],
44 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
+ class="code sev- ">44 pruning_measure : Union [ Measures , str ] = DEFAULT_PARAMS_VALUE [ "pruning_measure" ],
45 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">45 voting_measure : Measures = DEFAULT_PARAMS_VALUE [ "voting_measure" ],
46 "complementary_conditions"
+ class="code sev- ">46 max_growing : float = DEFAULT_PARAMS_VALUE [ "max_growing" ],
47 ],
+ class="code sev- ">47 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
48 mean_based_regression : bool = DEFAULT_PARAMS_VALUE [ "mean_based_regression" ],
+ class="code sev- ">48 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
49 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
+ class="code sev- ">49 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
50 ):
+ class="code sev- ">50 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
51 """
+ class="code sev- ">51 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
52 Parameters
+ class="code sev- ">52 "complementary_conditions"
53 ----------
+ class="code sev- ">53 ],
54 minsupp_new : float = 5.0
+ class="code sev- ">54 mean_based_regression : bool = DEFAULT_PARAMS_VALUE [ "mean_based_regression" ],
55 a minimum number (or fraction, if value < 1.0) of previously uncovered
+ class="code sev- ">55 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
56 examples to be covered by a new rule (positive examples for classification
+ class="code sev- ">56 ):
57 problems); default: 5,
+ class="code sev- ">57 """
58 induction_measure : :class:`rulekit.params.Measures` = \
+ class="code sev- ">58 Parameters
59 :class:`rulekit.params.Measures.Correlation`
+ class="code sev- ">59 ----------
60 measure used during induction; default measure is correlation
+ class="code sev- ">60 minsupp_new : float = 5.0
61 pruning_measure : Union[:class:`rulekit.params.Measures`, str] = \
+ class="code sev- ">61 a minimum number (or fraction, if value < 1.0) of previously uncovered
62 :class:`rulekit.params.Measures.Correlation`
+ class="code sev- ">62 examples to be covered by a new rule (positive examples for classification
63 measure used during pruning. Could be user defined (string), for example
+ class="code sev- ">63 problems); default: 5,
64 :code:`2 * p / n`; default measure is correlation
+ class="code sev- ">64 induction_measure : :class:`rulekit.params.Measures` = \
65 voting_measure : :class:`rulekit.params.Measures` = \
+ class="code sev- ">65 :class:`rulekit.params.Measures.Correlation`
66 :class:`rulekit.params.Measures.Correlation`
+ class="code sev- ">66 measure used during induction; default measure is correlation
67 measure used during voting; default measure is correlation
+ class="code sev- ">67 pruning_measure : Union[:class:`rulekit.params.Measures`, str] = \
68 max_growing : int = 0.0
+ class="code sev- ">68 :class:`rulekit.params.Measures.Correlation`
69 non-negative integer representing maximum number of conditions which can be
+ class="code sev- ">69 measure used during pruning. Could be user defined (string), for example
70 added to the rule in the growing phase (use this parameter for large
+ class="code sev- ">70 :code:`2 * p / n`; default measure is correlation
71 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
+ class="code sev- ">71 voting_measure : :class:`rulekit.params.Measures` = \
72 enable_pruning : bool = True
+ class="code sev- ">72 :class:`rulekit.params.Measures.Correlation`
73 enable or disable pruning, default is True.
+ class="code sev- ">73 measure used during voting; default measure is correlation
74 ignore_missing : bool = False
+ class="code sev- ">74 max_growing : int = 0.0
75 boolean telling whether missing values should be ignored (by default, a
+ class="code sev- ">75 non-negative integer representing maximum number of conditions which can be
76 missing value of given attribute is always considered as not fulfilling the
+ class="code sev- ">76 added to the rule in the growing phase (use this parameter for large
77 condition build upon that attribute); default: False.
+ class="code sev- ">77 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
78 max_uncovered_fraction : float = 0.0
+ class="code sev- ">78 enable_pruning : bool = True
79 Floating-point number from [0,1] interval representing maximum fraction of
+ class="code sev- ">79 enable or disable pruning, default is True.
80 examples that may remain uncovered by the rule set, default: 0.0.
+ class="code sev- ">80 ignore_missing : bool = False
81 select_best_candidate : bool = False
+ class="code sev- ">81 boolean telling whether missing values should be ignored (by default, a
82 Flag determining if best candidate should be selected from growing phase;
+ class="code sev- ">82 missing value of given attribute is always considered as not fulfilling the
83 default: False.
+ class="code sev- ">83 condition build upon that attribute); default: False.
84 complementary_conditions : bool = False
+ class="code sev- ">84 max_uncovered_fraction : float = 0.0
85 If enabled, complementary conditions in the form a = !{value} for nominal
+ class="code sev- ">85 Floating-point number from [0,1] interval representing maximum fraction of
86 attributes are supported.
+ class="code sev- ">86 examples that may remain uncovered by the rule set, default: 0.0.
87 mean_based_regression : bool = True
+ class="code sev- ">87 select_best_candidate : bool = False
88 Enable fast induction of mean-based regression rules instead of default
+ class="code sev- ">88 Flag determining if best candidate should be selected from growing phase;
89 median-based.
+ class="code sev- ">89 default: False.
90 max_rule_count : int = 0
+ class="code sev- ">90 complementary_conditions : bool = False
91 Maximum number of rules to be generated; 0 indicates no limit. Default: 0
+ class="code sev- ">91 If enabled, complementary conditions in the form a = !{value} for nominal
92 """
+ class="code sev- ">92 attributes are supported.
93 super () . __init__ (
+ class="code sev- ">93 mean_based_regression : bool = True
94 minsupp_new = minsupp_new ,
+ class="code sev- ">94 Enable fast induction of mean-based regression rules instead of default
95 induction_measure = induction_measure ,
+ class="code sev- ">95 median-based.
96 pruning_measure = pruning_measure ,
+ class="code sev- ">96 max_rule_count : int = 0
97 voting_measure = voting_measure ,
+ class="code sev- ">97 Maximum number of rules to be generated; 0 indicates no limit. Default: 0
98 max_growing = max_growing ,
+ class="code sev- ">98 """
99 enable_pruning = enable_pruning ,
+ class="code sev- ">99 super () . __init__ (
100 ignore_missing = ignore_missing ,
+ class="code sev- ">100 minsupp_new = minsupp_new ,
101 max_uncovered_fraction = max_uncovered_fraction ,
+ class="code sev- ">101 induction_measure = induction_measure ,
102 select_best_candidate = select_best_candidate ,
+ class="code sev- ">102 pruning_measure = pruning_measure ,
103 complementary_conditions = complementary_conditions ,
+ class="code sev- ">103 voting_measure = voting_measure ,
104 mean_based_regression = mean_based_regression ,
+ class="code sev- ">104 max_growing = max_growing ,
105 max_rule_count = max_rule_count ,
+ class="code sev- ">105 enable_pruning = enable_pruning ,
106 )
+ class="code sev- ">106 ignore_missing = ignore_missing ,
107 self . model : RuleSet [ RegressionRule ] = None
+ class="code sev- ">107 max_uncovered_fraction = max_uncovered_fraction ,
108
+ class="code sev- ">108 select_best_candidate = select_best_candidate ,
109 def _validate_labels ( self , labels : Data ):
+ class="code sev- ">109 complementary_conditions = complementary_conditions ,
110 if isinstance ( labels , ( pd . DataFrame , pd . Series )):
+ class="code sev- ">110 mean_based_regression = mean_based_regression ,
111 first_label = labels . iloc [ 0 ]
+ class="code sev- ">111 max_rule_count = max_rule_count ,
112 else :
+ class="code sev- ">112 )
113 first_label = labels [ 0 ]
+ class="code sev- ">113 self . model : RuleSet [ RegressionRule ] = None
114 if not isinstance ( first_label , Number ):
+ class="code sev- ">114
115 raise ValueError (
+ class="code sev- ">115 def _validate_labels ( self , labels : Data ):
116 f " { self . __class__ . __name__ } requires lables values to be numeric"
+ class="code sev- ">116 if isinstance ( labels , ( pd . DataFrame , pd . Series )):
117 )
+ class="code sev- ">117 first_label = labels . iloc [ 0 ]
118
+ class="code sev- ">118 else :
119 def fit ( # pylint: disable=arguments-differ
+ class="code sev- ">119 first_label = labels [ 0 ]
120 self , values : Data , labels : Data
+ class="code sev- ">120 if not isinstance ( first_label , Number ):
121 ) -> RuleRegressor :
+ class="code sev- ">121 raise ValueError (
122 """Train model on given dataset.
+ class="code sev- ">122 f " { self . __class__ . __name__ } requires lables values to be numeric"
123
+ class="code sev- ">123 )
124 Parameters
+ class="code sev- ">124
125 ----------
+ class="code sev- ">125 def fit ( # pylint: disable=arguments-differ
126 values : :class:`rulekit.operator.Data`
+ class="code sev- ">126 self , values : Data , labels : Data
127 attributes
+ class="code sev- ">127 ) -> RuleRegressor :
128 labels : :class:`rulekit.operator.Data`
+ class="code sev- ">128 """Train model on given dataset.
129 target values
+ class="code sev- ">129
130 Returns
+ class="code sev- ">130 Parameters
131 -------
+ class="code sev- ">131 ----------
132 self : RuleRegressor
+ class="code sev- ">132 values : :class:`rulekit.operator.Data`
133 """
+ class="code sev- ">133 attributes
134 self . _validate_labels ( labels )
+ class="code sev- ">134 labels : :class:`rulekit.operator.Data`
135 super () . fit ( values , labels )
+ class="code sev- ">135 target values
136 return self
+ class="code sev- ">136 Returns
137
+ class="code sev- ">137 -------
138 def predict ( self , values : Data ) -> np . ndarray :
+ class="code sev- ">138 self : RuleRegressor
139 """Perform prediction and returns predicted values.
+ class="code sev- ">139 """
140
+ class="code sev- ">140 self . _validate_labels ( labels )
141 Parameters
+ class="code sev- ">141 super () . fit ( values , labels )
142 ----------
+ class="code sev- ">142 return self
143 values : :class:`rulekit.operator.Data`
+ class="code sev- ">143
144 attributes
+ class="code sev- ">144 def predict ( self , values : Data ) -> np . ndarray :
145
+ class="code sev- ">145 """Perform prediction and returns predicted values.
146 Returns
+ class="code sev- ">146
147 -------
+ class="code sev- ">147 Parameters
148 result : np.ndarray
+ class="code sev- ">148 ----------
149 predicted values
+ class="code sev- ">149 values : :class:`rulekit.operator.Data`
150 """
+ class="code sev- ">150 attributes
151 return self . _map_result ( super () . predict ( values ))
+ class="code sev- ">151
152
+ class="code sev- ">152 Returns
153 def score ( self , values : Data , labels : Data ) -> float :
+ class="code sev- ">153 -------
154 """Return the coefficient of determination R2 of the prediction
+ class="code sev- ">154 result : np.ndarray
155
+ class="code sev- ">155 predicted values
156 Parameters
+ class="code sev- ">156 """
157 ----------
+ class="code sev- ">157 return self . _map_result ( super () . predict ( values ))
158 values : :class:`rulekit.operator.Data`
+ class="code sev- ">158
159 attributes
+ class="code sev- ">159 def score ( self , values : Data , labels : Data ) -> float :
160 labels : :class:`rulekit.operator.Data`
+ class="code sev- ">160 """Return the coefficient of determination R2 of the prediction
161 true target values
+ class="code sev- ">161
162
+ class="code sev- ">162 Parameters
163 Returns
+ class="code sev- ">163 ----------
164 -------
+ class="code sev- ">164 values : :class:`rulekit.operator.Data`
165 score : float
+ class="code sev- ">165 attributes
166 R2 of self.predict(values) wrt. labels.
+ class="code sev- ">166 labels : :class:`rulekit.operator.Data`
167 """
+ class="code sev- ">167 true target values
168 predicted_labels = self . predict ( values )
+ class="code sev- ">168
169 return metrics . r2_score ( labels , predicted_labels )
+ class="code sev- ">169 Returns
170
+ class="code sev- ">170 -------
171 def _map_result ( self , predicted_example_set ) -> np . ndarray :
+ class="code sev- ">171 score : float
172 return PredictionResultMapper . map_to_numerical (
+ class="code sev- ">172 R2 of self.predict(values) wrt. labels.
173 predicted_example_set , remap = False
+ class="code sev- ">173 """
174 )
+ class="code sev- ">174 predicted_labels = self . predict ( values )
175
+ class="code sev- ">175 return metrics . r2_score ( labels , predicted_labels )
176 def _get_problem_type ( self ) -> ProblemType :
+ class="code sev- ">176
177 return ProblemType . REGRESSION
+ class="code sev- ">177 def _map_result ( self , predicted_example_set ) -> np . ndarray :
178
+ class="code sev- ">178 return PredictionResultMapper . map_to_numerical (
179
+ class="code sev- ">179 predicted_example_set , remap = False
180 class ExpertRuleRegressor ( ExpertKnowledgeOperator , RuleRegressor ):
+ class="code sev- ">180 )
181 """Expert Regression model."""
+ class="code sev- ">181
182
+ class="code sev- ">182 def _get_problem_type ( self ) -> ProblemType :
183 __params_class__ = _RegressionExpertModelParams
+ class="code sev- ">183 return ProblemType . REGRESSION
184
185 def __init__ ( # pylint: disable=too-many-arguments,too-many-locals
+ class="code sev- ">185
186 self ,
+ class="code sev- ">186 class ExpertRuleRegressor ( ExpertKnowledgeOperator , RuleRegressor ):
187 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
+ class="code sev- ">187 """Expert Regression model."""
188 induction_measure : Measures = DEFAULT_PARAMS_VALUE [ "induction_measure" ],
+ class="code sev- ">188
189 pruning_measure : Union [ Measures , str ] = DEFAULT_PARAMS_VALUE [ "pruning_measure" ],
+ class="code sev- ">189 __params_class__ = _RegressionExpertModelParams
190 voting_measure : Measures = DEFAULT_PARAMS_VALUE [ "voting_measure" ],
+ class="code sev- ">190
191 max_growing : float = DEFAULT_PARAMS_VALUE [ "max_growing" ],
+ class="code sev- ">191 def __init__ ( # pylint: disable=too-many-arguments,too-many-locals
192 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
+ class="code sev- ">192 self ,
193 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
+ class="code sev- ">193 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
194 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
+ class="code sev- ">194 induction_measure : Measures = DEFAULT_PARAMS_VALUE [ "induction_measure" ],
195 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
+ class="code sev- ">195 pruning_measure : Union [ Measures , str ] = DEFAULT_PARAMS_VALUE [ "pruning_measure" ],
196 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">196 voting_measure : Measures = DEFAULT_PARAMS_VALUE [ "voting_measure" ],
197 "complementary_conditions"
+ class="code sev- ">197 max_growing : float = DEFAULT_PARAMS_VALUE [ "max_growing" ],
198 ],
+ class="code sev- ">198 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
199 mean_based_regression : bool = DEFAULT_PARAMS_VALUE [ "mean_based_regression" ],
+ class="code sev- ">199 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
200 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
+ class="code sev- ">200 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
201 extend_using_preferred : bool = DEFAULT_PARAMS_VALUE [ "extend_using_preferred" ],
+ class="code sev- ">201 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
202 extend_using_automatic : bool = DEFAULT_PARAMS_VALUE [ "extend_using_automatic" ],
+ class="code sev- ">202 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
203 induce_using_preferred : bool = DEFAULT_PARAMS_VALUE [ "induce_using_preferred" ],
+ class="code sev- ">203 "complementary_conditions"
204 induce_using_automatic : bool = DEFAULT_PARAMS_VALUE [ "induce_using_automatic" ],
+ class="code sev- ">204 ],
205 preferred_conditions_per_rule : int = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">205 mean_based_regression : bool = DEFAULT_PARAMS_VALUE [ "mean_based_regression" ],
206 "preferred_conditions_per_rule"
+ class="code sev- ">206 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
207 ],
+ class="code sev- ">207 extend_using_preferred : bool = DEFAULT_PARAMS_VALUE [ "extend_using_preferred" ],
208 preferred_attributes_per_rule : int = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">208 extend_using_automatic : bool = DEFAULT_PARAMS_VALUE [ "extend_using_automatic" ],
209 "preferred_attributes_per_rule"
+ class="code sev- ">209 induce_using_preferred : bool = DEFAULT_PARAMS_VALUE [ "induce_using_preferred" ],
210 ],
+ class="code sev- ">210 induce_using_automatic : bool = DEFAULT_PARAMS_VALUE [ "induce_using_automatic" ],
211 ):
+ class="code sev- ">211 preferred_conditions_per_rule : int = DEFAULT_PARAMS_VALUE [
212 """
+ class="code sev- ">212 "preferred_conditions_per_rule"
213 Parameters
+ class="code sev- ">213 ],
214 ----------
+ class="code sev- ">214 preferred_attributes_per_rule : int = DEFAULT_PARAMS_VALUE [
215 minsupp_new : float = 5.0
+ class="code sev- ">215 "preferred_attributes_per_rule"
216 a minimum number (or fraction, if value < 1.0) of previously uncovered
+ class="code sev- ">216 ],
217 examples to be covered by a new rule (positive examples for classification
+ class="code sev- ">217 ):
218 problems); default: 5,
+ class="code sev- ">218 """
219 induction_measure : :class:`rulekit.params.Measures` = \
+ class="code sev- ">219 Parameters
220 :class:`rulekit.params.Measures.Correlation`
+ class="code sev- ">220 ----------
221 measure used during induction; default measure is correlation
+ class="code sev- ">221 minsupp_new : float = 5.0
222 pruning_measure : Union[:class:`rulekit.params.Measures`, str] = \
+ class="code sev- ">222 a minimum number (or fraction, if value < 1.0) of previously uncovered
223 :class:`rulekit.params.Measures.Correlation`
+ class="code sev- ">223 examples to be covered by a new rule (positive examples for classification
224 measure used during pruning. Could be user defined (string), for example
+ class="code sev- ">224 problems); default: 5,
225 :code:`2 * p / n`; default measure is correlation
+ class="code sev- ">225 induction_measure : :class:`rulekit.params.Measures` = \
226 voting_measure : :class:`rulekit.params.Measures` = \
+ class="code sev- ">226 :class:`rulekit.params.Measures.Correlation`
227 :class:`rulekit.params.Measures.Correlation`
+ class="code sev- ">227 measure used during induction; default measure is correlation
228 measure used during voting; default measure is correlation
+ class="code sev- ">228 pruning_measure : Union[:class:`rulekit.params.Measures`, str] = \
229 max_growing : int = 0.0
+ class="code sev- ">229 :class:`rulekit.params.Measures.Correlation`
230 non-negative integer representing maximum number of conditions which can be
+ class="code sev- ">230 measure used during pruning. Could be user defined (string), for example
231 added to the rule in the growing phase (use this parameter for large
+ class="code sev- ">231 :code:`2 * p / n`; default measure is correlation
-
-
-
-
- E501
-
- Line too long (89 > 88 characters)
-
- 232 datasets if execution time is prohibitive); 0 indicates no limit; default: 0,
+ class="code sev- ">
232 voting_measure : :class:`rulekit.params.Measures` = \
233 enable_pruning : bool = True
+ class="code sev- ">233 :class:`rulekit.params.Measures.Correlation`
234 enable or disable pruning, default is True.
+ class="code sev- ">234 measure used during voting; default measure is correlation
235 ignore_missing : bool = False
+ class="code sev- ">235 max_growing : int = 0.0
236 boolean telling whether missing values should be ignored (by default, a
+ class="code sev- ">236 non-negative integer representing maximum number of conditions which can be
237 missing value of given attribute is always considered as not fulfilling the
+ class="code sev- ">237 added to the rule in the growing phase (use this parameter for large
238 condition build upon that attribute); default: False.
+ class="code sev-2 le">
+
+
+
+
+ E501
+
+ Line too long (89 > 88 characters)
+
+ 238 datasets if execution time is prohibitive); 0 indicates no limit; default: 0,
239 max_uncovered_fraction : float = 0.0
+ class="code sev- ">239 enable_pruning : bool = True
240 Floating-point number from [0,1] interval representing maximum fraction of
+ class="code sev- ">240 enable or disable pruning, default is True.
241 examples that may remain uncovered by the rule set, default: 0.0.
+ class="code sev- ">241 ignore_missing : bool = False
242 select_best_candidate : bool = False
+ class="code sev- ">242 boolean telling whether missing values should be ignored (by default, a
243 Flag determining if best candidate should be selected from growing phase;
+ class="code sev- ">243 missing value of given attribute is always considered as not fulfilling the
244 default: False.
+ class="code sev- ">244 condition build upon that attribute); default: False.
245 complementary_conditions : bool = False
+ class="code sev- ">245 max_uncovered_fraction : float = 0.0
246 If enabled, complementary conditions in the form a = !{value} for nominal
+ class="code sev- ">246 Floating-point number from [0,1] interval representing maximum fraction of
247 attributes are supported.
+ class="code sev- ">247 examples that may remain uncovered by the rule set, default: 0.0.
248 mean_based_regression : bool = True
+ class="code sev- ">248 select_best_candidate : bool = False
249 Enable fast induction of mean-based regression rules instead of default
+ class="code sev- ">249 Flag determining if best candidate should be selected from growing phase;
250 median-based.
+ class="code sev- ">250 default: False.
251 max_rule_count : int = 0
+ class="code sev- ">251 complementary_conditions : bool = False
252 Maximum number of rules to be generated (for classification data sets it
+ class="code sev- ">252 If enabled, complementary conditions in the form a = !{value} for nominal
253 applies to a single class); 0 indicates no limit.
+ class="code sev- ">253 attributes are supported.
254
+ class="code sev- ">254 mean_based_regression : bool = True
255 extend_using_preferred : bool = False
+ class="code sev- ">255 Enable fast induction of mean-based regression rules instead of default
256 boolean indicating whether initial rules should be extended with a use of
+ class="code sev- ">256 median-based.
257 preferred conditions and attributes; default is False
+ class="code sev- ">257 max_rule_count : int = 0
258 extend_using_automatic : bool = False
+ class="code sev- ">258 Maximum number of rules to be generated (for classification data sets it
259 boolean indicating whether initial rules should be extended with a use of
+ class="code sev- ">259 applies to a single class); 0 indicates no limit.
260 automatic conditions and attributes; default is False
+ class="code sev- ">260
261 induce_using_preferred : bool = False
+ class="code sev- ">261 extend_using_preferred : bool = False
262 boolean indicating whether new rules should be induced with a use of
+ class="code sev- ">262 boolean indicating whether initial rules should be extended with a use of
263 preferred conditions and attributes; default is False
264 induce_using_automatic : bool = False
+ class="code sev- ">264 extend_using_automatic : bool = False
265 boolean indicating whether new rules should be induced with a use of
+ class="code sev- ">265 boolean indicating whether initial rules should be extended with a use of
266 automatic conditions and attributes; default is False
267 preferred_conditions_per_rule : int = None
+ class="code sev- ">267 induce_using_preferred : bool = False
268 maximum number of preferred conditions per rule; default: unlimited,
+ class="code sev- ">268 boolean indicating whether new rules should be induced with a use of
269 preferred_attributes_per_rule : int = None
+ class="code sev- ">269 preferred conditions and attributes; default is False
270 maximum number of preferred attributes per rule; default: unlimited.
+ class="code sev- ">270 induce_using_automatic : bool = False
271 """
+ class="code sev- ">271 boolean indicating whether new rules should be induced with a use of
272 RuleRegressor . __init__ (
+ class="code sev- ">272 automatic conditions and attributes; default is False
273 self ,
+ class="code sev- ">273 preferred_conditions_per_rule : int = None
274 minsupp_new = minsupp_new ,
+ class="code sev- ">274 maximum number of preferred conditions per rule; default: unlimited,
275 induction_measure = induction_measure ,
+ class="code sev- ">275 preferred_attributes_per_rule : int = None
276 pruning_measure = pruning_measure ,
+ class="code sev- ">276 maximum number of preferred attributes per rule; default: unlimited.
277 voting_measure = voting_measure ,
+ class="code sev- ">277 """
278 max_growing = max_growing ,
+ class="code sev- ">278 RuleRegressor . __init__ (
279 enable_pruning = enable_pruning ,
+ class="code sev- ">279 self ,
280 ignore_missing = ignore_missing ,
+ class="code sev- ">280 minsupp_new = minsupp_new ,
281 max_uncovered_fraction = max_uncovered_fraction ,
+ class="code sev- ">281 induction_measure = induction_measure ,
282 select_best_candidate = select_best_candidate ,
+ class="code sev- ">282 pruning_measure = pruning_measure ,
283 complementary_conditions = complementary_conditions ,
+ class="code sev- ">283 voting_measure = voting_measure ,
284 mean_based_regression = mean_based_regression ,
+ class="code sev- ">284 max_growing = max_growing ,
285 max_rule_count = max_rule_count ,
+ class="code sev- ">285 enable_pruning = enable_pruning ,
286 )
+ class="code sev- ">286 ignore_missing = ignore_missing ,
287 ExpertKnowledgeOperator . __init__ (
+ class="code sev- ">287 max_uncovered_fraction = max_uncovered_fraction ,
288 self ,
+ class="code sev- ">288 select_best_candidate = select_best_candidate ,
289 minsupp_new = minsupp_new ,
+ class="code sev- ">289 complementary_conditions = complementary_conditions ,
290 induction_measure = induction_measure ,
+ class="code sev- ">290 mean_based_regression = mean_based_regression ,
291 pruning_measure = pruning_measure ,
+ class="code sev- ">291 max_rule_count = max_rule_count ,
292 voting_measure = voting_measure ,
+ class="code sev- ">292 )
293 max_growing = max_growing ,
+ class="code sev- ">293 ExpertKnowledgeOperator . __init__ (
294 enable_pruning = enable_pruning ,
+ class="code sev- ">294 self ,
295 ignore_missing = ignore_missing ,
+ class="code sev- ">295 minsupp_new = minsupp_new ,
296 max_uncovered_fraction = max_uncovered_fraction ,
+ class="code sev- ">296 induction_measure = induction_measure ,
297 select_best_candidate = select_best_candidate ,
+ class="code sev- ">297 pruning_measure = pruning_measure ,
298 extend_using_preferred = extend_using_preferred ,
+ class="code sev- ">298 voting_measure = voting_measure ,
299 extend_using_automatic = extend_using_automatic ,
+ class="code sev- ">299 max_growing = max_growing ,
300 induce_using_preferred = induce_using_preferred ,
+ class="code sev- ">300 enable_pruning = enable_pruning ,
301 induce_using_automatic = induce_using_automatic ,
+ class="code sev- ">301 ignore_missing = ignore_missing ,
302 preferred_conditions_per_rule = preferred_conditions_per_rule ,
+ class="code sev- ">302 max_uncovered_fraction = max_uncovered_fraction ,
303 preferred_attributes_per_rule = preferred_attributes_per_rule ,
+ class="code sev- ">303 select_best_candidate = select_best_candidate ,
304 complementary_conditions = complementary_conditions ,
+ class="code sev- ">304 extend_using_preferred = extend_using_preferred ,
305 mean_based_regression = mean_based_regression ,
+ class="code sev- ">305 extend_using_automatic = extend_using_automatic ,
306 max_rule_count = max_rule_count ,
+ class="code sev- ">306 induce_using_preferred = induce_using_preferred ,
307 )
+ class="code sev- ">307 induce_using_automatic = induce_using_automatic ,
308 self . model : RuleSet [ RegressionRule ] = None
+ class="code sev- ">308 preferred_conditions_per_rule = preferred_conditions_per_rule ,
309
+ class="code sev- ">309 preferred_attributes_per_rule = preferred_attributes_per_rule ,
310 def fit ( # pylint: disable=arguments-differ,too-many-arguments
+ class="code sev- ">310 complementary_conditions = complementary_conditions ,
311 self ,
+ class="code sev- ">311 mean_based_regression = mean_based_regression ,
312 values : Data ,
+ class="code sev- ">312 max_rule_count = max_rule_count ,
313 labels : Data ,
+ class="code sev- ">313 )
314 expert_rules : list [ Union [ str , tuple [ str , str ]]] = None ,
+ class="code sev- ">314 self . model : RuleSet [ RegressionRule ] = None
315 expert_preferred_conditions : list [ Union [ str , tuple [ str , str ]]] = None ,
+ class="code sev- ">315
316 expert_forbidden_conditions : list [ Union [ str , tuple [ str , str ]]] = None ,
+ class="code sev- ">316 def fit ( # pylint: disable=arguments-differ,too-many-arguments
317 ) -> ExpertRuleRegressor :
+ class="code sev- ">317 self ,
318 """Train model on given dataset.
+ class="code sev- ">318 values : Data ,
319
+ class="code sev- ">319 labels : Data ,
320 Parameters
+ class="code sev- ">320 expert_rules : list [ Union [ str , tuple [ str , str ]]] = None ,
321 ----------
+ class="code sev- ">321 expert_preferred_conditions : list [ Union [ str , tuple [ str , str ]]] = None ,
322 values : :class:`rulekit.operator.Data`
+ class="code sev- ">322 expert_forbidden_conditions : list [ Union [ str , tuple [ str , str ]]] = None ,
323 attributes
+ class="code sev- ">323 ) -> ExpertRuleRegressor :
324 labels : :class:`rulekit.operator.Data`
+ class="code sev- ">324 """Train model on given dataset.
325 target values
+ class="code sev- ">325
326
+ class="code sev- ">326 Parameters
327 expert_rules : List[Union[str, Tuple[str, str]]]
+ class="code sev- ">327 ----------
328 set of initial rules, either passed as a list of strings representing rules
+ class="code sev- ">328 values : :class:`rulekit.operator.Data`
329 or as list of tuples where first element is name of the rule and second one
+ class="code sev- ">329 attributes
330 is rule string.
+ class="code sev- ">330 labels : :class:`rulekit.operator.Data`
331 expert_preferred_conditions : List[Union[str, Tuple[str, str]]]
+ class="code sev- ">331 target values
332 multiset of preferred conditions (used also for specifying preferred
+ class="code sev- ">332
333 attributes by using special value Any). Either passed as a list of strings
+ class="code sev- ">333 expert_rules : List[Union[str, Tuple[str, str]]]
334 representing rules or as list of tuples where first element is name of the
+ class="code sev- ">334 set of initial rules, either passed as a list of strings representing rules
335 rule and second one is rule string.
+ class="code sev- ">335 or as list of tuples where first element is name of the rule and second one
336 expert_forbidden_conditions : List[Union[str, Tuple[str, str]]]
+ class="code sev- ">336 is rule string.
337 set of forbidden conditions (used also for specifying forbidden attributes
+ class="code sev- ">337 expert_preferred_conditions : List[Union[str, Tuple[str, str]]]
338 by using special valye Any). Either passed as a list of strings representing
+ class="code sev- ">338 multiset of preferred conditions (used also for specifying preferred
339 rules or as list of tuples where first element is name of the rule and
+ class="code sev- ">339 attributes by using special value Any). Either passed as a list of strings
340 second one is rule string.
+ class="code sev- ">340 representing rules or as list of tuples where first element is name of the
341 Returns
+ class="code sev- ">341 rule and second one is rule string.
342 -------
+ class="code sev- ">342 expert_forbidden_conditions : List[Union[str, Tuple[str, str]]]
343 self : ExpertRuleRegressor
+ class="code sev- ">343 set of forbidden conditions (used also for specifying forbidden attributes
344 """
+ class="code sev- ">344 by using special valye Any). Either passed as a list of strings representing
345 self . _validate_labels ( labels )
+ class="code sev- ">345 rules or as list of tuples where first element is name of the rule and
346 return ExpertKnowledgeOperator . fit (
+ class="code sev- ">346 second one is rule string.
347 self ,
+ class="code sev- ">347 Returns
348 values ,
+ class="code sev- ">348 -------
349 labels ,
+ class="code sev- ">349 self : ExpertRuleRegressor
350 expert_rules = expert_rules ,
+ class="code sev- ">350 """
351 expert_preferred_conditions = expert_preferred_conditions ,
+ class="code sev- ">351 self . _validate_labels ( labels )
352 expert_forbidden_conditions = expert_forbidden_conditions ,
+ class="code sev- ">352 return ExpertKnowledgeOperator . fit (
353 )
+ class="code sev- ">353 self ,
354
+ class="code sev- ">354 values ,
355 def predict ( self , values : Data ) -> np . ndarray :
+ class="code sev- ">355 labels ,
356 return self . _map_result ( ExpertKnowledgeOperator . predict ( self , values ))
+ class="code sev- ">356 expert_rules = expert_rules ,
357
+ class="code sev- ">357 expert_preferred_conditions = expert_preferred_conditions ,
358 def _get_problem_type ( self ) -> ProblemType :
+ class="code sev- ">358 expert_forbidden_conditions = expert_forbidden_conditions ,
359 return ProblemType . REGRESSION
+ class="code sev- ">359 )
360
361
+ class="code sev- ">361 def predict ( self , values : Data ) -> np . ndarray :
362 class ContrastSetRuleRegressor ( BaseOperator ):
+ class="code sev- ">362 return self . _map_result ( ExpertKnowledgeOperator . predict ( self , values ))
363 """Contrast set regression model."""
+ class="code sev- ">363
364
+ class="code sev- ">364 def _get_problem_type ( self ) -> ProblemType :
365 __params_class__ = ContrastSetModelParams
+ class="code sev- ">365 return ProblemType . REGRESSION
366
367 def __init__ ( # pylint: disable=too-many-arguments,too-many-locals
+ class="code sev- ">367
368 self ,
+ class="code sev- ">368 class ContrastSetRuleRegressor ( BaseOperator ):
369 minsupp_all : Tuple [ float , float , float , float ] = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">369 """Contrast set regression model."""
370 "minsupp_all"
+ class="code sev- ">370
371 ],
+ class="code sev- ">371 __params_class__ = ContrastSetModelParams
372 max_neg2pos : float = DEFAULT_PARAMS_VALUE [ "max_neg2pos" ],
+ class="code sev- ">372
373 max_passes_count : int = DEFAULT_PARAMS_VALUE [ "max_passes_count" ],
+ class="code sev- ">373 def __init__ ( # pylint: disable=too-many-arguments,too-many-locals
374 penalty_strength : float = DEFAULT_PARAMS_VALUE [ "penalty_strength" ],
+ class="code sev- ">374 self ,
375 penalty_saturation : float = DEFAULT_PARAMS_VALUE [ "penalty_saturation" ],
+ class="code sev- ">375 minsupp_all : Tuple [ float , float , float , float ] = DEFAULT_PARAMS_VALUE [
376 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
+ class="code sev- ">376 "minsupp_all"
377 induction_measure : Measures = DEFAULT_PARAMS_VALUE [ "induction_measure" ],
+ class="code sev- ">377 ],
378 pruning_measure : Union [ Measures , str ] = DEFAULT_PARAMS_VALUE [ "pruning_measure" ],
+ class="code sev- ">378 max_neg2pos : float = DEFAULT_PARAMS_VALUE [ "max_neg2pos" ],
379 voting_measure : Measures = DEFAULT_PARAMS_VALUE [ "voting_measure" ],
+ class="code sev- ">379 max_passes_count : int = DEFAULT_PARAMS_VALUE [ "max_passes_count" ],
380 max_growing : float = DEFAULT_PARAMS_VALUE [ "max_growing" ],
+ class="code sev- ">380 penalty_strength : float = DEFAULT_PARAMS_VALUE [ "penalty_strength" ],
381 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
+ class="code sev- ">381 penalty_saturation : float = DEFAULT_PARAMS_VALUE [ "penalty_saturation" ],
382 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
+ class="code sev- ">382 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
383 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
+ class="code sev- ">383 induction_measure : Measures = DEFAULT_PARAMS_VALUE [ "induction_measure" ],
384 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
+ class="code sev- ">384 pruning_measure : Union [ Measures , str ] = DEFAULT_PARAMS_VALUE [ "pruning_measure" ],
385 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">385 voting_measure : Measures = DEFAULT_PARAMS_VALUE [ "voting_measure" ],
386 "complementary_conditions"
+ class="code sev- ">386 max_growing : float = DEFAULT_PARAMS_VALUE [ "max_growing" ],
387 ],
+ class="code sev- ">387 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
388 mean_based_regression : bool = DEFAULT_PARAMS_VALUE [ "mean_based_regression" ],
+ class="code sev- ">388 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
389 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
+ class="code sev- ">389 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
390 ):
+ class="code sev- ">390 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
391 """
+ class="code sev- ">391 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
392 Parameters
+ class="code sev- ">392 "complementary_conditions"
393 ----------
+ class="code sev- ">393 ],
394 minsupp_all: Tuple[float, float, float, float]
+ class="code sev- ">394 mean_based_regression : bool = DEFAULT_PARAMS_VALUE [ "mean_based_regression" ],
395 a minimum positive support of a contrast set (p/P). When multiple values are
+ class="code sev- ">395 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
396 specified, a metainduction is performed; Default and recommended sequence
+ class="code sev- ">396 ):
397 is: 0.8, 0.5, 0.2, 0.1
+ class="code sev- ">397 """
398 max_neg2pos: float
+ class="code sev- ">398 Parameters
399 a maximum ratio of negative to positive supports (nP/pN); Default is 0.5
+ class="code sev- ">399 ----------
400 max_passes_count: int
+ class="code sev- ">400 minsupp_all: Tuple[float, float, float, float]
401 a maximum number of sequential covering passes for a single minsupp-all;
+ class="code sev- ">401 a minimum positive support of a contrast set (p/P). When multiple values are
402 Default is 5
+ class="code sev- ">402 specified, a metainduction is performed; Default and recommended sequence
403 penalty_strength: float
+ class="code sev- ">403 is: 0.8, 0.5, 0.2, 0.1
404 (s) - penalty strength; Default is 0.5
+ class="code sev- ">404 max_neg2pos: float
405 penalty_saturation: float
+ class="code sev- ">405 a maximum ratio of negative to positive supports (nP/pN); Default is 0.5
406 the value of p_new / P at which penalty reward saturates; Default is 0.2.
+ class="code sev- ">406 max_passes_count: int
407 minsupp_new : float = 5.0
+ class="code sev- ">407 a maximum number of sequential covering passes for a single minsupp-all;
408 a minimum number (or fraction, if value < 1.0) of previously uncovered
+ class="code sev- ">408 Default is 5
409 examples to be covered by a new rule (positive examples for classification
+ class="code sev- ">409 penalty_strength: float
410 problems); default: 5,
+ class="code sev- ">410 (s) - penalty strength; Default is 0.5
411 induction_measure : :class:`rulekit.params.Measures` = \
+ class="code sev- ">411 penalty_saturation: float
412 :class:`rulekit.params.Measures.Correlation`
+ class="code sev- ">412 the value of p_new / P at which penalty reward saturates; Default is 0.2.
413 measure used during induction; default measure is correlation
+ class="code sev- ">413 minsupp_new : float = 5.0
414 pruning_measure : Union[:class:`rulekit.params.Measures`, str] = \
+ class="code sev- ">414 a minimum number (or fraction, if value < 1.0) of previously uncovered
415 :class:`rulekit.params.Measures.Correlation`
+ class="code sev- ">415 examples to be covered by a new rule (positive examples for classification
416 measure used during pruning. Could be user defined (string), for example
+ class="code sev- ">416 problems); default: 5,
417 :code:`2 * p / n`; default measure is correlation
+ class="code sev- ">417 induction_measure : :class:`rulekit.params.Measures` = \
418 voting_measure : :class:`rulekit.params.Measures` = \
+ class="code sev- ">418 :class:`rulekit.params.Measures.Correlation`
419 :class:`rulekit.params.Measures.Correlation`
+ class="code sev- ">419 measure used during induction; default measure is correlation
420 measure used during voting; default measure is correlation
+ class="code sev- ">420 pruning_measure : Union[:class:`rulekit.params.Measures`, str] = \
421 max_growing : int = 0.0
+ class="code sev- ">421 :class:`rulekit.params.Measures.Correlation`
422 non-negative integer representing maximum number of conditions which can be
+ class="code sev- ">422 measure used during pruning. Could be user defined (string), for example
423 added to the rule in the growing phase (use this parameter for large
+ class="code sev- ">423 :code:`2 * p / n`; default measure is correlation
424 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
+ class="code sev- ">424 voting_measure : :class:`rulekit.params.Measures` = \
425 enable_pruning : bool = True
+ class="code sev- ">425 :class:`rulekit.params.Measures.Correlation`
426 enable or disable pruning, default is True.
+ class="code sev- ">426 measure used during voting; default measure is correlation
427 ignore_missing : bool = False
+ class="code sev- ">427 max_growing : int = 0.0
428 boolean telling whether missing values should be ignored (by default, a
+ class="code sev- ">428 non-negative integer representing maximum number of conditions which can be
429 missing value of given attribute is always considered as not fulfilling the
+ class="code sev- ">429 added to the rule in the growing phase (use this parameter for large
430 condition build upon that attribute); default: False.
+ class="code sev- ">430 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
431 max_uncovered_fraction : float = 0.0
+ class="code sev- ">431 enable_pruning : bool = True
432 Floating-point number from [0,1] interval representing maximum fraction of
+ class="code sev- ">432 enable or disable pruning, default is True.
433 examples that may remain uncovered by the rule set, default: 0.0.
+ class="code sev- ">433 ignore_missing : bool = False
434 select_best_candidate : bool = False
+ class="code sev- ">434 boolean telling whether missing values should be ignored (by default, a
435 Flag determining if best candidate should be selected from growing phase;
+ class="code sev- ">435 missing value of given attribute is always considered as not fulfilling the
436 default: False.
+ class="code sev- ">436 condition build upon that attribute); default: False.
437 complementary_conditions : bool = False
+ class="code sev- ">437 max_uncovered_fraction : float = 0.0
438 If enabled, complementary conditions in the form a = !{value} for nominal
+ class="code sev- ">438 Floating-point number from [0,1] interval representing maximum fraction of
439 attributes are supported.
+ class="code sev- ">439 examples that may remain uncovered by the rule set, default: 0.0.
440 mean_based_regression : bool = True
+ class="code sev- ">440 select_best_candidate : bool = False
441 Enable fast induction of mean-based regression rules instead of default
+ class="code sev- ">441 Flag determining if best candidate should be selected from growing phase;
442 median-based.
+ class="code sev- ">442 default: False.
443 max_rule_count : int = 0
+ class="code sev- ">443 complementary_conditions : bool = False
444 Maximum number of rules to be generated; 0 indicates no limit.
+ class="code sev- ">444 If enabled, complementary conditions in the form a = !{value} for nominal
445 """
+ class="code sev- ">445 attributes are supported.
446 super () . __init__ (
+ class="code sev- ">446 mean_based_regression : bool = True
447 minsupp_all = minsupp_all ,
+ class="code sev- ">447 Enable fast induction of mean-based regression rules instead of default
448 max_neg2pos = max_neg2pos ,
+ class="code sev- ">448 median-based.
449 max_passes_count = max_passes_count ,
+ class="code sev- ">449 max_rule_count : int = 0
450 penalty_strength = penalty_strength ,
+ class="code sev- ">450 Maximum number of rules to be generated; 0 indicates no limit.
451 penalty_saturation = penalty_saturation ,
+ class="code sev- ">451 """
452 minsupp_new = minsupp_new ,
+ class="code sev- ">452 super () . __init__ (
453 induction_measure = induction_measure ,
+ class="code sev- ">453 minsupp_all = minsupp_all ,
454 pruning_measure = pruning_measure ,
+ class="code sev- ">454 max_neg2pos = max_neg2pos ,
455 voting_measure = voting_measure ,
+ class="code sev- ">455 max_passes_count = max_passes_count ,
456 max_growing = max_growing ,
+ class="code sev- ">456 penalty_strength = penalty_strength ,
457 enable_pruning = enable_pruning ,
+ class="code sev- ">457 penalty_saturation = penalty_saturation ,
458 ignore_missing = ignore_missing ,
+ class="code sev- ">458 minsupp_new = minsupp_new ,
459 max_uncovered_fraction = max_uncovered_fraction ,
+ class="code sev- ">459 induction_measure = induction_measure ,
460 select_best_candidate = select_best_candidate ,
+ class="code sev- ">460 pruning_measure = pruning_measure ,
461 complementary_conditions = complementary_conditions ,
+ class="code sev- ">461 voting_measure = voting_measure ,
462 mean_based_regression = mean_based_regression ,
+ class="code sev- ">462 max_growing = max_growing ,
463 max_rule_count = max_rule_count ,
+ class="code sev- ">463 enable_pruning = enable_pruning ,
464 )
+ class="code sev- ">464 ignore_missing = ignore_missing ,
465 self . contrast_attribute : str = None
+ class="code sev- ">465 max_uncovered_fraction = max_uncovered_fraction ,
466 self . model : RuleSet [ RegressionRule ] = None
+ class="code sev- ">466 select_best_candidate = select_best_candidate ,
467
+ class="code sev- ">467 complementary_conditions = complementary_conditions ,
468 def fit (
+ class="code sev- ">468 mean_based_regression = mean_based_regression ,
469 self , values : Data , labels : Data , contrast_attribute : str
+ class="code sev- ">469 max_rule_count = max_rule_count ,
470 ) -> ContrastSetRuleRegressor : # pylint: disable=arguments-differ
+ class="code sev- ">470 )
471 """Train model on given dataset.
+ class="code sev- ">471 self . contrast_attribute : str = None
472
+ class="code sev- ">472 self . model : RuleSet [ RegressionRule ] = None
473 Parameters
+ class="code sev- ">473
474 ----------
+ class="code sev- ">474 def fit (
475 values : :class:`rulekit.operator.Data`
+ class="code sev- ">475 self , values : Data , labels : Data , contrast_attribute : str
476 attributes
+ class="code sev- ">476 ) -> ContrastSetRuleRegressor : # pylint: disable=arguments-differ
477 labels : :class:`rulekit.operator.Data`
+ class="code sev- ">477 """Train model on given dataset.
478 target values
+ class="code sev- ">478
479 contrast_attribute: str
+ class="code sev- ">479 Parameters
480 group attribute
+ class="code sev- ">480 ----------
481 Returns
+ class="code sev- ">481 values : :class:`rulekit.operator.Data`
482 -------
+ class="code sev- ">482 attributes
483 self : ContrastSetRuleRegressor
+ class="code sev- ">483 labels : :class:`rulekit.operator.Data`
484 """
+ class="code sev- ">484 target values
485 RuleRegressor . _validate_labels ( self , labels ) # pylint: disable=protected-access
+ class="code sev- ">485 contrast_attribute: str
486 super () . fit ( values , labels , contrast_attribute = contrast_attribute )
+ class="code sev- ">486 group attribute
487 self . contrast_attribute = contrast_attribute
+ class="code sev- ">487 Returns
488 return self
+ class="code sev- ">488 -------
489
+ class="code sev- ">489 self : ContrastSetRuleRegressor
490 def predict ( self , values : Data ) -> np . ndarray :
+ class="code sev- ">490 """
491 """Perform prediction and returns predicted values.
+ class="code sev- ">491 RuleRegressor . _validate_labels ( self , labels ) # pylint: disable=protected-access
492
+ class="code sev- ">492 super () . fit ( values , labels , contrast_attribute = contrast_attribute )
493 Parameters
+ class="code sev- ">493 self . contrast_attribute = contrast_attribute
494 ----------
+ class="code sev- ">494 return self
495 values : :class:`rulekit.operator.Data`
+ class="code sev- ">495
496 attributes
+ class="code sev- ">496 def predict ( self , values : Data ) -> np . ndarray :
497
+ class="code sev- ">497 """Perform prediction and returns predicted values.
498 Returns
+ class="code sev- ">498
499 -------
+ class="code sev- ">499 Parameters
500 result : np.ndarray
+ class="code sev- ">500 ----------
501 predicted values
+ class="code sev- ">501 values : :class:`rulekit.operator.Data`
502 """
+ class="code sev- ">502 attributes
503 return RuleRegressor . predict ( self , values )
+ class="code sev- ">503
504
+ class="code sev- ">504 Returns
505 def score ( self , values : Data , labels : Data ) -> float :
+ class="code sev- ">505 -------
506 """Return the coefficient of determination R2 of the prediction
+ class="code sev- ">506 result : np.ndarray
507
+ class="code sev- ">507 predicted values
508 Parameters
+ class="code sev- ">508 """
509 ----------
+ class="code sev- ">509 return RuleRegressor . predict ( self , values )
510 values : :class:`rulekit.operator.Data`
+ class="code sev- ">510
511 attributes
+ class="code sev- ">511 def score ( self , values : Data , labels : Data ) -> float :
512 labels : :class:`rulekit.operator.Data`
+ class="code sev- ">512 """Return the coefficient of determination R2 of the prediction
513 true target values
+ class="code sev- ">513
514
+ class="code sev- ">514 Parameters
515 Returns
+ class="code sev- ">515 ----------
516 -------
+ class="code sev- ">516 values : :class:`rulekit.operator.Data`
517 score : float
+ class="code sev- ">517 attributes
518 R2 of self.predict(values) wrt. labels.
+ class="code sev- ">518 labels : :class:`rulekit.operator.Data`
519 """
+ class="code sev- ">519 true target values
520 return RuleRegressor . score ( self , values , labels )
+ class="code sev- ">520
521
+ class="code sev- ">521 Returns
522 def __getstate__ ( self ) -> dict :
+ class="code sev- ">522 -------
523 return {
+ class="code sev- ">523 score : float
524 ** BaseOperator . __getstate__ ( self ),
+ class="code sev- ">524 R2 of self.predict(values) wrt. labels.
525 ** {
+ class="code sev- ">525 """
526 "contrast_attribute" : self . contrast_attribute ,
+ class="code sev- ">526 return RuleRegressor . score ( self , values , labels )
527 },
+ class="code sev- ">527
528 }
+ class="code sev- ">528 def __getstate__ ( self ) -> dict :
529
+ class="code sev- ">529 return {
530 def __setstate__ ( self , state : dict ):
+ class="code sev- ">530 ** BaseOperator . __getstate__ ( self ),
531 BaseOperator . __setstate__ ( self , state )
+ class="code sev- ">531 ** {
532 self . contrast_attribute = state [ "contrast_attribute" ]
+ class="code sev- ">532 "contrast_attribute" : self . contrast_attribute ,
533
+ class="code sev- ">533 },
534 def _get_problem_type ( self ) -> ProblemType :
+ class="code sev- ">534 }
535 return ProblemType . CONTRAST_REGRESSION
+ class="code sev- ">535
+
+ 536 def __setstate__ ( self , state : dict ):
+
+ 537 BaseOperator . __setstate__ ( self , state )
+
+ 538 self . contrast_attribute = state [ "contrast_attribute" ]
+
+ 539
+
+ 540 def _get_problem_type ( self ) -> ProblemType :
+
+ 541 return ProblemType . CONTRAST_REGRESSION
diff --git a/docs/reports/flake8/rulekit.survival.report.html b/docs/reports/flake8/rulekit.survival.report.html
index 0b8389f..5f71c74 100644
--- a/docs/reports/flake8/rulekit.survival.report.html
+++ b/docs/reports/flake8/rulekit.survival.report.html
@@ -64,22 +64,22 @@
Line too long (94 > 88 characters):
-
- 56 self . model . _java_object . getTrainingEstimator () # pylint: disable=protected-access
+
+ 62 self . model . _java_object . getTrainingEstimator () # pylint: disable=protected-access
Line too long (93 > 88 characters):
-
- 265 def __init__ ( # pylint: disable=super-init-not-called,too-many-arguments,too-many-locals
+
+ 271 def __init__ ( # pylint: disable=super-init-not-called,too-many-arguments,too-many-locals
Line too long (112 > 88 characters):
-
- 557 survival_time_attribute = SurvivalRules . _prepare_survival_attribute ( # pylint: disable=protected-access
+
+ 563 survival_time_attribute = SurvivalRules . _prepare_survival_attribute ( # pylint: disable=protected-access
diff --git a/docs/reports/flake8/rulekit.survival.source.html b/docs/reports/flake8/rulekit.survival.source.html
index 84e748d..ef17356 100644
--- a/docs/reports/flake8/rulekit.survival.source.html
+++ b/docs/reports/flake8/rulekit.survival.source.html
@@ -23,745 +23,745 @@
class="code sev- ">2 """
3
+ class="code sev- ">3 from __future__ import annotations
4 from __future__ import annotations
+ class="code sev- ">4
5
+ class="code sev- ">5 from typing import Optional
6 from typing import Optional , Tuple , Union
+ class="code sev- ">6 from typing import Tuple
7
+ class="code sev- ">7 from typing import Union
8 import numpy as np
+ class="code sev- ">8
9 import pandas as pd
+ class="code sev- ">9 import numpy as np
10 from jpype import JClass
+ class="code sev- ">10 import pandas as pd
11 from pydantic import BaseModel # pylint: disable=no-name-in-module
+ class="code sev- ">11 from jpype import JClass
12
+ class="code sev- ">12 from pydantic import BaseModel # pylint: disable=no-name-in-module
13 from rulekit._helpers import ExampleSetFactory , PredictionResultMapper
+ class="code sev- ">13
14 from rulekit._operator import BaseOperator , Data , ExpertKnowledgeOperator
+ class="code sev- ">14 from rulekit._helpers import ExampleSetFactory
15 from rulekit._problem_types import ProblemType
+ class="code sev- ">15 from rulekit._helpers import PredictionResultMapper
16 from rulekit.kaplan_meier import KaplanMeierEstimator
+ class="code sev- ">16 from rulekit._operator import BaseOperator
17 from rulekit.params import ( DEFAULT_PARAMS_VALUE , ContrastSetModelParams ,
+ class="code sev- ">17 from rulekit._operator import Data
18 ExpertModelParams )
+ class="code sev- ">18 from rulekit._operator import ExpertKnowledgeOperator
19 from rulekit.rules import RuleSet , SurvivalRule
+ class="code sev- ">19 from rulekit._problem_types import ProblemType
20
+ class="code sev- ">20 from rulekit.kaplan_meier import KaplanMeierEstimator
21 _DEFAULT_SURVIVAL_TIME_ATTR : str = "survival_time"
+ class="code sev- ">21 from rulekit.params import ContrastSetModelParams
22
+ class="code sev- ">22 from rulekit.params import DEFAULT_PARAMS_VALUE
23
+ class="code sev- ">23 from rulekit.params import ExpertModelParams
24 class _SurvivalModelsParams ( BaseModel ):
+ class="code sev- ">24 from rulekit.rules import RuleSet
25 survival_time_attr : Optional [ str ]
+ class="code sev- ">25 from rulekit.rules import SurvivalRule
26 minsupp_new : Optional [ float ] = DEFAULT_PARAMS_VALUE [ "minsupp_new" ]
+ class="code sev- ">26
27 max_growing : Optional [ float ] = DEFAULT_PARAMS_VALUE [ "max_growing" ]
+ class="code sev- ">27 _DEFAULT_SURVIVAL_TIME_ATTR : str = "survival_time"
28 enable_pruning : Optional [ bool ] = DEFAULT_PARAMS_VALUE [ "enable_pruning" ]
+ class="code sev- ">28
29 ignore_missing : Optional [ bool ] = DEFAULT_PARAMS_VALUE [ "ignore_missing" ]
+ class="code sev- ">29
30 max_uncovered_fraction : Optional [ float ] = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">30 class _SurvivalModelsParams ( BaseModel ):
31 "max_uncovered_fraction"
+ class="code sev- ">31 survival_time_attr : Optional [ str ]
32 ]
+ class="code sev- ">32 minsupp_new : Optional [ float ] = DEFAULT_PARAMS_VALUE [ "minsupp_new" ]
33 select_best_candidate : Optional [ bool ] = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">33 max_growing : Optional [ float ] = DEFAULT_PARAMS_VALUE [ "max_growing" ]
34 "select_best_candidate"
+ class="code sev- ">34 enable_pruning : Optional [ bool ] = DEFAULT_PARAMS_VALUE [ "enable_pruning" ]
35 ]
+ class="code sev- ">35 ignore_missing : Optional [ bool ] = DEFAULT_PARAMS_VALUE [ "ignore_missing" ]
36 complementary_conditions : Optional [ bool ] = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">36 max_uncovered_fraction : Optional [ float ] = DEFAULT_PARAMS_VALUE [
37 "complementary_conditions"
+ class="code sev- ">37 "max_uncovered_fraction"
38 ]
39
+ class="code sev- ">39 select_best_candidate : Optional [ bool ] = DEFAULT_PARAMS_VALUE [
40
+ class="code sev- ">40 "select_best_candidate"
41 class _SurvivalExpertModelParams ( _SurvivalModelsParams , ExpertModelParams ):
+ class="code sev- ">41 ]
42 pass
+ class="code sev- ">42 complementary_conditions : Optional [ bool ] = DEFAULT_PARAMS_VALUE [
43
+ class="code sev- ">43 "complementary_conditions"
44
+ class="code sev- ">44 ]
45 class _BaseSurvivalRulesModel :
+ class="code sev- ">45
46
47 model : RuleSet [ SurvivalRule ]
+ class="code sev- ">47 class _SurvivalExpertModelParams ( _SurvivalModelsParams , ExpertModelParams ):
48
+ class="code sev- ">48 pass
49 def get_train_set_kaplan_meier ( self ) -> KaplanMeierEstimator :
+ class="code sev- ">49
50 """Returns train set KaplanMeier estimator
+ class="code sev- ">50
51
+ class="code sev- ">51 class _BaseSurvivalRulesModel :
52 Returns:
+ class="code sev- ">52
53 KaplanMeierEstimator: estimator
+ class="code sev- ">53 model : RuleSet [ SurvivalRule ]
54 """
+ class="code sev- ">54
55 return KaplanMeierEstimator (
+ class="code sev- ">55 def get_train_set_kaplan_meier ( self ) -> KaplanMeierEstimator :
-
-
-
-
- E501
-
- Line too long (94 > 88 characters)
-
- 56 self . model . _java_object . getTrainingEstimator () # pylint: disable=protected-access
+ class="code sev- ">
56 """Returns train set KaplanMeier estimator
57 )
+ class="code sev- ">57
58
+ class="code sev- ">58 Returns:
59
+ class="code sev- ">59 KaplanMeierEstimator: estimator
60 class SurvivalRules ( BaseOperator , _BaseSurvivalRulesModel ):
+ class="code sev- ">60 """
61 """Survival model."""
+ class="code sev- ">61 return KaplanMeierEstimator (
62
+ class="code sev-2 le">
+
+
+
+
+ E501
+
+ Line too long (94 > 88 characters)
+
+ 62 self . model . _java_object . getTrainingEstimator () # pylint: disable=protected-access
63 __params_class__ = _SurvivalModelsParams
+ class="code sev- ">63 )
64
65 def __init__ ( # pylint: disable=super-init-not-called,too-many-arguments
+ class="code sev- ">65
66 self ,
+ class="code sev- ">66 class SurvivalRules ( BaseOperator , _BaseSurvivalRulesModel ):
67 survival_time_attr : str = None ,
+ class="code sev- ">67 """Survival model."""
68 minsupp_new : int = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
+ class="code sev- ">68
69 max_growing : int = DEFAULT_PARAMS_VALUE [ "max_growing" ],
+ class="code sev- ">69 __params_class__ = _SurvivalModelsParams
70 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
+ class="code sev- ">70
71 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
+ class="code sev- ">71 def __init__ ( # pylint: disable=super-init-not-called,too-many-arguments
72 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
+ class="code sev- ">72 self ,
73 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
+ class="code sev- ">73 survival_time_attr : str = None ,
74 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">74 minsupp_new : int = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
75 "complementary_conditions"
+ class="code sev- ">75 max_growing : int = DEFAULT_PARAMS_VALUE [ "max_growing" ],
76 ],
+ class="code sev- ">76 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
77 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
+ class="code sev- ">77 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
78 ):
+ class="code sev- ">78 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
79 """
+ class="code sev- ">79 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
80 Parameters
+ class="code sev- ">80 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
81 ----------
+ class="code sev- ">81 "complementary_conditions"
82 survival_time_attr : str
+ class="code sev- ">82 ],
83 name of column containing survival time data (use when data passed to model
+ class="code sev- ">83 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
84 is padnas dataframe).
+ class="code sev- ">84 ):
85 minsupp_new : float = 5.0
+ class="code sev- ">85 """
86 a minimum number (or fraction, if value < 1.0) of previously uncovered
+ class="code sev- ">86 Parameters
87 examples to be covered by a new rule (positive examples for classification
+ class="code sev- ">87 ----------
88 problems); default: 5,
+ class="code sev- ">88 survival_time_attr : str
89 max_growing : int = 0.0
+ class="code sev- ">89 name of column containing survival time data (use when data passed to model
90 non-negative integer representing maximum number of conditions which can be
+ class="code sev- ">90 is padnas dataframe).
91 added to the rule in the growing phase (use this parameter for large
+ class="code sev- ">91 minsupp_new : float = 5.0
92 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
+ class="code sev- ">92 a minimum number (or fraction, if value < 1.0) of previously uncovered
93 enable_pruning : bool = True
+ class="code sev- ">93 examples to be covered by a new rule (positive examples for classification
94 enable or disable pruning, default is True.
+ class="code sev- ">94 problems); default: 5,
95 ignore_missing : bool = False
+ class="code sev- ">95 max_growing : int = 0.0
96 boolean telling whether missing values should be ignored (by default, a
+ class="code sev- ">96 non-negative integer representing maximum number of conditions which can be
97 missing value of given attribute is always considered as not fulfilling the
+ class="code sev- ">97 added to the rule in the growing phase (use this parameter for large
98 condition build upon that attribute); default: False.
+ class="code sev- ">98 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
99 max_uncovered_fraction : float = 0.0
+ class="code sev- ">99 enable_pruning : bool = True
100 Floating-point number from [0,1] interval representing maximum fraction of
+ class="code sev- ">100 enable or disable pruning, default is True.
101 examples that may remain uncovered by the rule set, default: 0.0.
+ class="code sev- ">101 ignore_missing : bool = False
102 select_best_candidate : bool = False
+ class="code sev- ">102 boolean telling whether missing values should be ignored (by default, a
103 Flag determining if best candidate should be selected from growing phase;
+ class="code sev- ">103 missing value of given attribute is always considered as not fulfilling the
104 default: False.
+ class="code sev- ">104 condition build upon that attribute); default: False.
105 complementary_conditions : bool = False
+ class="code sev- ">105 max_uncovered_fraction : float = 0.0
106 If enabled, complementary conditions in the form a = !{value} for nominal
+ class="code sev- ">106 Floating-point number from [0,1] interval representing maximum fraction of
107 attributes are supported.
+ class="code sev- ">107 examples that may remain uncovered by the rule set, default: 0.0.
108 max_rule_count : int = 0
+ class="code sev- ">108 select_best_candidate : bool = False
109 Maximum number of rules to be generated (for classification data sets it
+ class="code sev- ">109 Flag determining if best candidate should be selected from growing phase;
110 applies to a single class); 0 indicates no limit.
+ class="code sev- ">110 default: False.
111 """
+ class="code sev- ">111 complementary_conditions : bool = False
112 self . _params = None
+ class="code sev- ">112 If enabled, complementary conditions in the form a = !{value} for nominal
113 self . _rule_generator = None
+ class="code sev- ">113 attributes are supported.
114 self . _configurator = None
+ class="code sev- ">114 max_rule_count : int = 0
115 self . _initialize_rulekit ()
+ class="code sev- ">115 Maximum number of rules to be generated (for classification data sets it
116 self . set_params (
+ class="code sev- ">116 applies to a single class); 0 indicates no limit.
117 survival_time_attr = survival_time_attr ,
+ class="code sev- ">117 """
118 minsupp_new = minsupp_new ,
+ class="code sev- ">118 self . _params = None
119 max_growing = max_growing ,
+ class="code sev- ">119 self . _rule_generator = None
120 enable_pruning = enable_pruning ,
+ class="code sev- ">120 self . _configurator = None
121 ignore_missing = ignore_missing ,
+ class="code sev- ">121 self . _initialize_rulekit ()
122 max_uncovered_fraction = max_uncovered_fraction ,
+ class="code sev- ">122 self . set_params (
123 select_best_candidate = select_best_candidate ,
+ class="code sev- ">123 survival_time_attr = survival_time_attr ,
124 complementary_conditions = complementary_conditions ,
+ class="code sev- ">124 minsupp_new = minsupp_new ,
125 max_rule_count = max_rule_count ,
+ class="code sev- ">125 max_growing = max_growing ,
126 )
+ class="code sev- ">126 enable_pruning = enable_pruning ,
127 self . model : RuleSet [ SurvivalRule ] = None
+ class="code sev- ">127 ignore_missing = ignore_missing ,
128
+ class="code sev- ">128 max_uncovered_fraction = max_uncovered_fraction ,
129 def set_params ( self , ** kwargs ) -> object :
+ class="code sev- ">129 select_best_candidate = select_best_candidate ,
130 """Set models hyperparameters. Parameters are the same as in constructor."""
+ class="code sev- ">130 complementary_conditions = complementary_conditions ,
131 self . survival_time_attr = kwargs . get ( "survival_time_attr" )
+ class="code sev- ">131 max_rule_count = max_rule_count ,
132 return BaseOperator . set_params ( self , ** kwargs )
+ class="code sev- ">132 )
133
+ class="code sev- ">133 self . model : RuleSet [ SurvivalRule ] = None
134 @staticmethod
+ class="code sev- ">134
135 def _append_survival_time_columns (
+ class="code sev- ">135 def set_params ( self , ** kwargs ) -> object :
136 values , survival_time : Union [ pd . Series , np . ndarray , list ]
+ class="code sev- ">136 """Set models hyperparameters. Parameters are the same as in constructor."""
137 ) -> Optional [ str ]:
+ class="code sev- ">137 self . survival_time_attr = kwargs . get ( "survival_time_attr" )
138 survival_time_attr : str = _DEFAULT_SURVIVAL_TIME_ATTR
+ class="code sev- ">138 return BaseOperator . set_params ( self , ** kwargs )
139 if isinstance ( survival_time , pd . Series ):
+ class="code sev- ">139
140 if survival_time . name is None :
+ class="code sev- ">140 @staticmethod
141 survival_time . name = survival_time_attr
+ class="code sev- ">141 def _append_survival_time_columns (
142 else :
+ class="code sev- ">142 values , survival_time : Union [ pd . Series , np . ndarray , list ]
143 survival_time_attr = survival_time . name
+ class="code sev- ">143 ) -> Optional [ str ]:
144 values [ survival_time . name ] = survival_time
+ class="code sev- ">144 survival_time_attr : str = _DEFAULT_SURVIVAL_TIME_ATTR
145 elif isinstance ( survival_time , np . ndarray ):
+ class="code sev- ">145 if isinstance ( survival_time , pd . Series ):
146 np . append ( values , survival_time , axis = 1 )
+ class="code sev- ">146 if survival_time . name is None :
147 elif isinstance ( survival_time , list ):
+ class="code sev- ">147 survival_time . name = survival_time_attr
148 for index , row in enumerate ( values ):
+ class="code sev- ">148 else :
149 row . append ( survival_time [ index ])
+ class="code sev- ">149 survival_time_attr = survival_time . name
150 else :
+ class="code sev- ">150 values [ survival_time . name ] = survival_time
151 raise ValueError (
+ class="code sev- ">151 elif isinstance ( survival_time , np . ndarray ):
152 "Data values must be instance of either pandas DataFrame, numpy array"
+ class="code sev- ">152 np . append ( values , survival_time , axis = 1 )
153 " or list"
+ class="code sev- ">153 elif isinstance ( survival_time , list ):
154 )
+ class="code sev- ">154 for index , row in enumerate ( values ):
155 return survival_time_attr
+ class="code sev- ">155 row . append ( survival_time [ index ])
156
+ class="code sev- ">156 else :
157 def _prepare_survival_attribute (
+ class="code sev- ">157 raise ValueError (
158 self , survival_time : Optional [ Data ], values : Data
+ class="code sev- ">158 "Data values must be instance of either pandas DataFrame, numpy array"
159 ) -> str :
+ class="code sev- ">159 " or list"
160 if self . survival_time_attr is None and survival_time is None :
+ class="code sev- ">160 )
161 raise ValueError (
+ class="code sev- ">161 return survival_time_attr
162 'No "survival_time" attribute name was specified. '
+ class="code sev- ">162
163 + "Specify it using method set_params"
+ class="code sev- ">163 def _prepare_survival_attribute (
164 )
+ class="code sev- ">164 self , survival_time : Optional [ Data ], values : Data
165 if survival_time is not None :
+ class="code sev- ">165 ) -> str :
166 return SurvivalRules . _append_survival_time_columns ( values , survival_time )
+ class="code sev- ">166 if self . survival_time_attr is None and survival_time is None :
167 return self . survival_time_attr
+ class="code sev- ">167 raise ValueError (
168
+ class="code sev- ">168 'No "survival_time" attribute name was specified. '
169 def fit (
+ class="code sev- ">169 + "Specify it using method set_params"
170 self , values : Data , labels : Data , survival_time : Data = None
+ class="code sev- ">170 )
171 ) -> SurvivalRules : # pylint: disable=arguments-differ
+ class="code sev- ">171 if survival_time is not None :
172 """Train model on given dataset.
+ class="code sev- ">172 return SurvivalRules . _append_survival_time_columns ( values , survival_time )
173
+ class="code sev- ">173 return self . survival_time_attr
174 Parameters
+ class="code sev- ">174
175 ----------
+ class="code sev- ">175 def fit (
176 values : :class:`rulekit.operator.Data`
+ class="code sev- ">176 self , values : Data , labels : Data , survival_time : Data = None
177 attributes
+ class="code sev- ">177 ) -> SurvivalRules : # pylint: disable=arguments-differ
178 labels : :class:`rulekit.operator.Data`
+ class="code sev- ">178 """Train model on given dataset.
179 survival status
+ class="code sev- ">179
180 survival_time: :class:`rulekit.operator.Data`
+ class="code sev- ">180 Parameters
181 data about survival time. Could be omitted when *survival_time_attr*
+ class="code sev- ">181 ----------
182 parameter was specified.
+ class="code sev- ">182 values : :class:`rulekit.operator.Data`
183
+ class="code sev- ">183 attributes
184 Returns
+ class="code sev- ">184 labels : :class:`rulekit.operator.Data`
185 -------
+ class="code sev- ">185 survival status
186 self : SurvivalRules
+ class="code sev- ">186 survival_time: :class:`rulekit.operator.Data`
187 """
+ class="code sev- ">187 data about survival time. Could be omitted when *survival_time_attr*
188 survival_time_attribute = self . _prepare_survival_attribute (
+ class="code sev- ">188 parameter was specified.
189 survival_time , values
+ class="code sev- ">189
190 )
+ class="code sev- ">190 Returns
191 super () . fit ( values , labels , survival_time_attribute )
+ class="code sev- ">191 -------
192 return self
+ class="code sev- ">192 self : SurvivalRules
193
+ class="code sev- ">193 """
194 def predict ( self , values : Data ) -> np . ndarray :
+ class="code sev- ">194 survival_time_attribute = self . _prepare_survival_attribute (
195 """Perform prediction and return estimated survival function for each example.
+ class="code sev- ">195 survival_time , values
196
+ class="code sev- ">196 )
197 Parameters
+ class="code sev- ">197 super () . fit ( values , labels , survival_time_attribute )
198 ----------
+ class="code sev- ">198 return self
199 values : :class:`rulekit.operator.Data`
+ class="code sev- ">199
200 attributes
+ class="code sev- ">200 def predict ( self , values : Data ) -> np . ndarray :
201
+ class="code sev- ">201 """Perform prediction and return estimated survival function for each example.
202 Returns
+ class="code sev- ">202
203 -------
+ class="code sev- ">203 Parameters
204 result : np.ndarray
+ class="code sev- ">204 ----------
205 Each row represent single example from dataset and contains estimated
+ class="code sev- ">205 values : :class:`rulekit.operator.Data`
206 survival function for that example. Estimated survival function is returned
+ class="code sev- ">206 attributes
207 as a dictionary containing times and corresponding probabilities.
+ class="code sev- ">207
208 """
+ class="code sev- ">208 Returns
209 return PredictionResultMapper . map_survival ( super () . predict ( values ))
+ class="code sev- ">209 -------
210
+ class="code sev- ">210 result : np.ndarray
211 def score ( self , values : Data , labels : Data , survival_time : Data = None ) -> float :
+ class="code sev- ">211 Each row represent single example from dataset and contains estimated
212 """Return the Integrated Brier Score on the given dataset and labels
+ class="code sev- ">212 survival function for that example. Estimated survival function is returned
213 (event status indicator).
+ class="code sev- ">213 as a dictionary containing times and corresponding probabilities.
214
+ class="code sev- ">214 """
215 Integrated Brier Score (IBS) - the Brier score (BS) represents the squared
+ class="code sev- ">215 return PredictionResultMapper . map_survival ( super () . predict ( values ))
216 difference between true event status at time T and predicted event status at
+ class="code sev- ">216
217 that time; the Integrated Brier score summarizes the prediction error over all
+ class="code sev- ">217 def score ( self , values : Data , labels : Data , survival_time : Data = None ) -> float :
218 observations and over all times in a test set.
+ class="code sev- ">218 """Return the Integrated Brier Score on the given dataset and labels
219
+ class="code sev- ">219 (event status indicator).
220 Parameters
+ class="code sev- ">220
221 ----------
+ class="code sev- ">221 Integrated Brier Score (IBS) - the Brier score (BS) represents the squared
222 values : :class:`rulekit.operator.Data`
+ class="code sev- ">222 difference between true event status at time T and predicted event status at
223 attributes
+ class="code sev- ">223 that time; the Integrated Brier score summarizes the prediction error over all
224 labels : :class:`rulekit.operator.Data`
+ class="code sev- ">224 observations and over all times in a test set.
225 survival status
+ class="code sev- ">225
226 survival_time: :class:`rulekit.operator.Data`
+ class="code sev- ">226 Parameters
227 data about survival time. Could be omitted when *survival_time_attr*
+ class="code sev- ">227 ----------
228 parameter was specified
+ class="code sev- ">228 values : :class:`rulekit.operator.Data`
229
+ class="code sev- ">229 attributes
230 Returns
+ class="code sev- ">230 labels : :class:`rulekit.operator.Data`
231 -------
+ class="code sev- ">231 survival status
232 score : float
+ class="code sev- ">232 survival_time: :class:`rulekit.operator.Data`
233 Integrated Brier Score of self.predict(values) wrt. labels.
+ class="code sev- ">233 data about survival time. Could be omitted when *survival_time_attr*
234 """
+ class="code sev- ">234 parameter was specified
235
236 survival_time_attribute = self . _prepare_survival_attribute (
+ class="code sev- ">236 Returns
237 survival_time , values
+ class="code sev- ">237 -------
238 )
+ class="code sev- ">238 score : float
239 example_set = ExampleSetFactory ( self . _get_problem_type ()) . make (
+ class="code sev- ">239 Integrated Brier Score of self.predict(values) wrt. labels.
240 values , labels , survival_time_attribute = survival_time_attribute
+ class="code sev- ">240 """
241 )
+ class="code sev- ">241
242
+ class="code sev- ">242 survival_time_attribute = self . _prepare_survival_attribute (
243 predicted_example_set = (
+ class="code sev- ">243 survival_time , values
244 self . model . _java_object . apply ( # pylint: disable=protected-access
+ class="code sev- ">244 )
245 example_set
+ class="code sev- ">245 example_set = ExampleSetFactory ( self . _get_problem_type ()) . make (
246 )
+ class="code sev- ">246 values , labels , survival_time_attribute = survival_time_attribute
247 )
@@ -770,1117 +770,1135 @@
class="code sev- ">248
249 IntegratedBrierScore = JClass ( # pylint: disable=invalid-name
+ class="code sev- ">249 predicted_example_set = (
250 "adaa.analytics.rules.logic.performance.IntegratedBrierScore"
+ class="code sev- ">250 self . model . _java_object . apply ( # pylint: disable=protected-access
251 )
+ class="code sev- ">251 example_set
252 integrated_brier_score = IntegratedBrierScore ()
+ class="code sev- ">252 )
253 ibs = integrated_brier_score . countExample ( predicted_example_set ) . getValue ()
+ class="code sev- ">253 )
254 return float ( ibs )
+ class="code sev- ">254
255
+ class="code sev- ">255 IntegratedBrierScore = JClass ( # pylint: disable=invalid-name
256 def _get_problem_type ( self ) -> ProblemType :
+ class="code sev- ">256 "adaa.analytics.rules.logic.performance.IntegratedBrierScore"
257 return ProblemType . SURVIVAL
+ class="code sev- ">257 )
258
+ class="code sev- ">258 integrated_brier_score = IntegratedBrierScore ()
259
+ class="code sev- ">259 ibs = integrated_brier_score . countExample ( predicted_example_set ) . getValue ()
260 class ExpertSurvivalRules ( ExpertKnowledgeOperator , SurvivalRules ):
+ class="code sev- ">260 return float ( ibs )
261 """Expert Survival model."""
+ class="code sev- ">261
262
+ class="code sev- ">262 def _get_problem_type ( self ) -> ProblemType :
263 __params_class__ = _SurvivalExpertModelParams
+ class="code sev- ">263 return ProblemType . SURVIVAL
264
-
-
-
-
- E501
-
- Line too long (93 > 88 characters)
-
- 265 def __init__ ( # pylint: disable=super-init-not-called,too-many-arguments,too-many-locals
+ class="code sev- ">
265
266 self ,
+ class="code sev- ">266 class ExpertSurvivalRules ( ExpertKnowledgeOperator , SurvivalRules ):
267 survival_time_attr : str = None ,
+ class="code sev- ">267 """Expert Survival model."""
268 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
+ class="code sev- ">268
269 max_growing : int = DEFAULT_PARAMS_VALUE [ "max_growing" ],
+ class="code sev- ">269 __params_class__ = _SurvivalExpertModelParams
270 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
+ class="code sev- ">270
271 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
+ class="code sev-2 le">
+
+
+
+
+ E501
+
+ Line too long (93 > 88 characters)
+
+ 271 def __init__ ( # pylint: disable=super-init-not-called,too-many-arguments,too-many-locals
272 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
+ class="code sev- ">272 self ,
273 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
+ class="code sev- ">273 survival_time_attr : str = None ,
274 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">274 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
275 "complementary_conditions"
+ class="code sev- ">275 max_growing : int = DEFAULT_PARAMS_VALUE [ "max_growing" ],
276 ],
+ class="code sev- ">276 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
277 extend_using_preferred : bool = DEFAULT_PARAMS_VALUE [ "extend_using_preferred" ],
+ class="code sev- ">277 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
278 extend_using_automatic : bool = DEFAULT_PARAMS_VALUE [ "extend_using_automatic" ],
+ class="code sev- ">278 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
279 induce_using_preferred : bool = DEFAULT_PARAMS_VALUE [ "induce_using_preferred" ],
+ class="code sev- ">279 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
280 induce_using_automatic : bool = DEFAULT_PARAMS_VALUE [ "induce_using_automatic" ],
+ class="code sev- ">280 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
281 preferred_conditions_per_rule : int = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">281 "complementary_conditions"
282 "preferred_conditions_per_rule"
+ class="code sev- ">282 ],
283 ],
+ class="code sev- ">283 extend_using_preferred : bool = DEFAULT_PARAMS_VALUE [ "extend_using_preferred" ],
284 preferred_attributes_per_rule : int = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">284 extend_using_automatic : bool = DEFAULT_PARAMS_VALUE [ "extend_using_automatic" ],
285 "preferred_attributes_per_rule"
+ class="code sev- ">285 induce_using_preferred : bool = DEFAULT_PARAMS_VALUE [ "induce_using_preferred" ],
286 ],
+ class="code sev- ">286 induce_using_automatic : bool = DEFAULT_PARAMS_VALUE [ "induce_using_automatic" ],
287 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
+ class="code sev- ">287 preferred_conditions_per_rule : int = DEFAULT_PARAMS_VALUE [
288 ):
+ class="code sev- ">288 "preferred_conditions_per_rule"
289 """
+ class="code sev- ">289 ],
290 Parameters
+ class="code sev- ">290 preferred_attributes_per_rule : int = DEFAULT_PARAMS_VALUE [
291 ----------
+ class="code sev- ">291 "preferred_attributes_per_rule"
292 minsupp_new : float = 5.0
+ class="code sev- ">292 ],
293 a minimum number (or fraction, if value < 1.0) of previously uncovered
+ class="code sev- ">293 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
294 examples to be covered by a new rule (positive examples for classification
+ class="code sev- ">294 ):
295 problems); default: 5,
+ class="code sev- ">295 """
296 survival_time_attr : str
+ class="code sev- ">296 Parameters
297 name of column containing survival time data (use when data passed to model
+ class="code sev- ">297 ----------
298 is pandas dataframe).
+ class="code sev- ">298 minsupp_new : float = 5.0
299 max_growing : int = 0.0
+ class="code sev- ">299 a minimum number (or fraction, if value < 1.0) of previously uncovered
300 non-negative integer representing maximum number of conditions which can be
+ class="code sev- ">300 examples to be covered by a new rule (positive examples for classification
301 added to the rule in the growing phase (use this parameter for large
+ class="code sev- ">301 problems); default: 5,
302 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
+ class="code sev- ">302 survival_time_attr : str
303 enable_pruning : bool = True
+ class="code sev- ">303 name of column containing survival time data (use when data passed to model
304 enable or disable pruning, default is True.
+ class="code sev- ">304 is pandas dataframe).
305 ignore_missing : bool = False
+ class="code sev- ">305 max_growing : int = 0.0
306 boolean telling whether missing values should be ignored (by default, a
+ class="code sev- ">306 non-negative integer representing maximum number of conditions which can be
307 missing value of given attribute is always considered as not fulfilling the
+ class="code sev- ">307 added to the rule in the growing phase (use this parameter for large
308 condition build upon that attribute); default: False.
+ class="code sev- ">308 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
309 max_uncovered_fraction : float = 0.0
+ class="code sev- ">309 enable_pruning : bool = True
310 Floating-point number from [0,1] interval representing maximum fraction of
+ class="code sev- ">310 enable or disable pruning, default is True.
311 examples that may remain uncovered by the rule set, default: 0.0.
+ class="code sev- ">311 ignore_missing : bool = False
312 select_best_candidate : bool = False
+ class="code sev- ">312 boolean telling whether missing values should be ignored (by default, a
313 Flag determining if best candidate should be selected from growing phase;
+ class="code sev- ">313 missing value of given attribute is always considered as not fulfilling the
314 default: False.
+ class="code sev- ">314 condition build upon that attribute); default: False.
315 complementary_conditions : bool = False
+ class="code sev- ">315 max_uncovered_fraction : float = 0.0
316 If enabled, complementary conditions in the form a = !{value} for nominal
+ class="code sev- ">316 Floating-point number from [0,1] interval representing maximum fraction of
317 attributes are supported.
+ class="code sev- ">317 examples that may remain uncovered by the rule set, default: 0.0.
318 max_rule_count : int = 0
+ class="code sev- ">318 select_best_candidate : bool = False
319 Maximum number of rules to be generated (for classification data sets it
+ class="code sev- ">319 Flag determining if best candidate should be selected from growing phase;
320 applies to a single class); 0 indicates no limit.
+ class="code sev- ">320 default: False.
321
+ class="code sev- ">321 complementary_conditions : bool = False
322 extend_using_preferred : bool = False
+ class="code sev- ">322 If enabled, complementary conditions in the form a = !{value} for nominal
323 boolean indicating whether initial rules should be extended with a use of
+ class="code sev- ">323 attributes are supported.
324 preferred conditions and attributes; default is False
+ class="code sev- ">324 max_rule_count : int = 0
325 extend_using_automatic : bool = False
+ class="code sev- ">325 Maximum number of rules to be generated (for classification data sets it
326 boolean indicating whether initial rules should be extended with a use of
+ class="code sev- ">326 applies to a single class); 0 indicates no limit.
327 automatic conditions and attributes; default is False
+ class="code sev- ">327
328 induce_using_preferred : bool = False
+ class="code sev- ">328 extend_using_preferred : bool = False
329 boolean indicating whether new rules should be induced with a use of
+ class="code sev- ">329 boolean indicating whether initial rules should be extended with a use of
330 preferred conditions and attributes; default is False
331 induce_using_automatic : bool = False
+ class="code sev- ">331 extend_using_automatic : bool = False
332 boolean indicating whether new rules should be induced with a use of
+ class="code sev- ">332 boolean indicating whether initial rules should be extended with a use of
333 automatic conditions and attributes; default is False
334 preferred_conditions_per_rule : int = None
+ class="code sev- ">334 induce_using_preferred : bool = False
335 maximum number of preferred conditions per rule; default: unlimited,
+ class="code sev- ">335 boolean indicating whether new rules should be induced with a use of
336 preferred_attributes_per_rule : int = None
+ class="code sev- ">336 preferred conditions and attributes; default is False
337 maximum number of preferred attributes per rule; default: unlimited.
+ class="code sev- ">337 induce_using_automatic : bool = False
338 """
+ class="code sev- ">338 boolean indicating whether new rules should be induced with a use of
339 self . _params = None
+ class="code sev- ">339 automatic conditions and attributes; default is False
340 self . _rule_generator = None
+ class="code sev- ">340 preferred_conditions_per_rule : int = None
341 self . _configurator = None
+ class="code sev- ">341 maximum number of preferred conditions per rule; default: unlimited,
342 self . _initialize_rulekit ()
+ class="code sev- ">342 preferred_attributes_per_rule : int = None
343 self . set_params (
+ class="code sev- ">343 maximum number of preferred attributes per rule; default: unlimited.
344 survival_time_attr = survival_time_attr ,
+ class="code sev- ">344 """
345 minsupp_new = minsupp_new ,
+ class="code sev- ">345 self . _params = None
346 max_growing = max_growing ,
+ class="code sev- ">346 self . _rule_generator = None
347 enable_pruning = enable_pruning ,
+ class="code sev- ">347 self . _configurator = None
348 ignore_missing = ignore_missing ,
+ class="code sev- ">348 self . _initialize_rulekit ()
349 max_uncovered_fraction = max_uncovered_fraction ,
+ class="code sev- ">349 self . set_params (
350 select_best_candidate = select_best_candidate ,
+ class="code sev- ">350 survival_time_attr = survival_time_attr ,
351 extend_using_preferred = extend_using_preferred ,
+ class="code sev- ">351 minsupp_new = minsupp_new ,
352 extend_using_automatic = extend_using_automatic ,
+ class="code sev- ">352 max_growing = max_growing ,
353 induce_using_preferred = induce_using_preferred ,
+ class="code sev- ">353 enable_pruning = enable_pruning ,
354 induce_using_automatic = induce_using_automatic ,
+ class="code sev- ">354 ignore_missing = ignore_missing ,
355 preferred_conditions_per_rule = preferred_conditions_per_rule ,
+ class="code sev- ">355 max_uncovered_fraction = max_uncovered_fraction ,
356 preferred_attributes_per_rule = preferred_attributes_per_rule ,
+ class="code sev- ">356 select_best_candidate = select_best_candidate ,
357 complementary_conditions = complementary_conditions ,
+ class="code sev- ">357 extend_using_preferred = extend_using_preferred ,
358 max_rule_count = max_rule_count ,
+ class="code sev- ">358 extend_using_automatic = extend_using_automatic ,
359 )
+ class="code sev- ">359 induce_using_preferred = induce_using_preferred ,
360 self . model : RuleSet [ SurvivalRule ] = None
+ class="code sev- ">360 induce_using_automatic = induce_using_automatic ,
361
+ class="code sev- ">361 preferred_conditions_per_rule = preferred_conditions_per_rule ,
362 def set_params ( self , ** kwargs ) -> object : # pylint: disable=arguments-differ
+ class="code sev- ">362 preferred_attributes_per_rule = preferred_attributes_per_rule ,
363 self . survival_time_attr = kwargs [ "survival_time_attr" ]
+ class="code sev- ">363 complementary_conditions = complementary_conditions ,
364 return ExpertKnowledgeOperator . set_params ( self , ** kwargs )
+ class="code sev- ">364 max_rule_count = max_rule_count ,
365
+ class="code sev- ">365 )
366 def fit ( # pylint: disable=arguments-differ,too-many-arguments
+ class="code sev- ">366 self . model : RuleSet [ SurvivalRule ] = None
367 self ,
+ class="code sev- ">367
368 values : Data ,
+ class="code sev- ">368 def set_params ( self , ** kwargs ) -> object : # pylint: disable=arguments-differ
369 labels : Data ,
+ class="code sev- ">369 self . survival_time_attr = kwargs [ "survival_time_attr" ]
370 survival_time : Data = None ,
+ class="code sev- ">370 return ExpertKnowledgeOperator . set_params ( self , ** kwargs )
371 expert_rules : list [ Union [ str , tuple [ str , str ]]] = None ,
+ class="code sev- ">371
372 expert_preferred_conditions : list [ Union [ str , tuple [ str , str ]]] = None ,
+ class="code sev- ">372 def fit ( # pylint: disable=arguments-differ,too-many-arguments
373 expert_forbidden_conditions : list [ Union [ str , tuple [ str , str ]]] = None ,
+ class="code sev- ">373 self ,
374 ) -> ExpertSurvivalRules :
+ class="code sev- ">374 values : Data ,
375 """Train model on given dataset.
+ class="code sev- ">375 labels : Data ,
376
+ class="code sev- ">376 survival_time : Data = None ,
377 Parameters
+ class="code sev- ">377 expert_rules : list [ Union [ str , tuple [ str , str ]]] = None ,
378 ----------
+ class="code sev- ">378 expert_preferred_conditions : list [ Union [ str , tuple [ str , str ]]] = None ,
379 values : :class:`rulekit.operator.Data`
+ class="code sev- ">379 expert_forbidden_conditions : list [ Union [ str , tuple [ str , str ]]] = None ,
380 attributes
+ class="code sev- ">380 ) -> ExpertSurvivalRules :
381 labels : Data
+ class="code sev- ">381 """Train model on given dataset.
382 survival status
+ class="code sev- ">382
383 survival_time: :class:`rulekit.operator.Data`
+ class="code sev- ">383 Parameters
384 data about survival time. Could be omitted when *survival_time_attr*
+ class="code sev- ">384 ----------
385 parameter was specified.
+ class="code sev- ">385 values : :class:`rulekit.operator.Data`
386 expert_rules : List[Union[str, Tuple[str, str]]]
+ class="code sev- ">386 attributes
387 set of initial rules, either passed as a list of strings representing rules
+ class="code sev- ">387 labels : Data
388 or as list of tuples where first element is name of the rule and second one
+ class="code sev- ">388 survival status
389 is rule string.
+ class="code sev- ">389 survival_time: :class:`rulekit.operator.Data`
390 expert_preferred_conditions : List[Union[str, Tuple[str, str]]]
+ class="code sev- ">390 data about survival time. Could be omitted when *survival_time_attr*
391 multiset of preferred conditions (used also for specifying preferred
+ class="code sev- ">391 parameter was specified.
392 attributes by using special value Any). Either passed as a list of strings
+ class="code sev- ">392 expert_rules : List[Union[str, Tuple[str, str]]]
393 representing rules or as list of tuples where first element is name of the
+ class="code sev- ">393 set of initial rules, either passed as a list of strings representing rules
394 rule and second one is rule string.
+ class="code sev- ">394 or as list of tuples where first element is name of the rule and second one
395 expert_forbidden_conditions : List[Union[str, Tuple[str, str]]]
+ class="code sev- ">395 is rule string.
396 set of forbidden conditions (used also for specifying forbidden attributes
+ class="code sev- ">396 expert_preferred_conditions : List[Union[str, Tuple[str, str]]]
397 by using special valye Any). Either passed as a list of strings representing
+ class="code sev- ">397 multiset of preferred conditions (used also for specifying preferred
398 rules or as list of tuples where first element is name of the rule and
+ class="code sev- ">398 attributes by using special value Any). Either passed as a list of strings
399 second one is rule string.
+ class="code sev- ">399 representing rules or as list of tuples where first element is name of the
400
+ class="code sev- ">400 rule and second one is rule string.
401 Returns
+ class="code sev- ">401 expert_forbidden_conditions : List[Union[str, Tuple[str, str]]]
402 -------
+ class="code sev- ">402 set of forbidden conditions (used also for specifying forbidden attributes
403 self : ExpertSurvivalRules
+ class="code sev- ">403 by using special valye Any). Either passed as a list of strings representing
404 """
+ class="code sev- ">404 rules or as list of tuples where first element is name of the rule and
405 survival_time_attribute = SurvivalRules . _prepare_survival_attribute (
+ class="code sev- ">405 second one is rule string.
406 self , survival_time , values
+ class="code sev- ">406
407 )
+ class="code sev- ">407 Returns
408 return ExpertKnowledgeOperator . fit (
+ class="code sev- ">408 -------
409 self ,
+ class="code sev- ">409 self : ExpertSurvivalRules
410 values = values ,
+ class="code sev- ">410 """
411 labels = labels ,
+ class="code sev- ">411 survival_time_attribute = SurvivalRules . _prepare_survival_attribute (
412 survival_time_attribute = survival_time_attribute ,
+ class="code sev- ">412 self , survival_time , values
413 expert_rules = expert_rules ,
+ class="code sev- ">413 )
414 expert_preferred_conditions = expert_preferred_conditions ,
+ class="code sev- ">414 return ExpertKnowledgeOperator . fit (
415 expert_forbidden_conditions = expert_forbidden_conditions ,
+ class="code sev- ">415 self ,
416 )
+ class="code sev- ">416 values = values ,
417
+ class="code sev- ">417 labels = labels ,
418 def predict ( self , values : Data ) -> np . ndarray :
+ class="code sev- ">418 survival_time_attribute = survival_time_attribute ,
419 return PredictionResultMapper . map_survival (
+ class="code sev- ">419 expert_rules = expert_rules ,
420 ExpertKnowledgeOperator . predict ( self , values )
+ class="code sev- ">420 expert_preferred_conditions = expert_preferred_conditions ,
421 )
+ class="code sev- ">421 expert_forbidden_conditions = expert_forbidden_conditions ,
422
+ class="code sev- ">422 )
423 def _get_problem_type ( self ) -> ProblemType :
+ class="code sev- ">423
424 return ProblemType . SURVIVAL
+ class="code sev- ">424 def predict ( self , values : Data ) -> np . ndarray :
425
+ class="code sev- ">425 return PredictionResultMapper . map_survival (
426
+ class="code sev- ">426 ExpertKnowledgeOperator . predict ( self , values )
427 class _SurvivalContrastSetModelParams ( ContrastSetModelParams , _SurvivalModelsParams ):
+ class="code sev- ">427 )
428 pass
+ class="code sev- ">428
429
+ class="code sev- ">429 def _get_problem_type ( self ) -> ProblemType :
430
+ class="code sev- ">430 return ProblemType . SURVIVAL
431 class ContrastSetSurvivalRules ( BaseOperator , _BaseSurvivalRulesModel ):
+ class="code sev- ">431
432 """Contrast set survival model."""
+ class="code sev- ">432
433
+ class="code sev- ">433 class _SurvivalContrastSetModelParams ( ContrastSetModelParams , _SurvivalModelsParams ):
434 __params_class__ = _SurvivalContrastSetModelParams
+ class="code sev- ">434 pass
435
436 def __init__ ( # pylint: disable=super-init-not-called,too-many-arguments
+ class="code sev- ">436
437 self ,
+ class="code sev- ">437 class ContrastSetSurvivalRules ( BaseOperator , _BaseSurvivalRulesModel ):
438 minsupp_all : Tuple [ float , float , float , float ] = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">438 """Contrast set survival model."""
439 "minsupp_all"
+ class="code sev- ">439
440 ],
+ class="code sev- ">440 __params_class__ = _SurvivalContrastSetModelParams
441 max_neg2pos : float = DEFAULT_PARAMS_VALUE [ "max_neg2pos" ],
+ class="code sev- ">441
442 max_passes_count : int = DEFAULT_PARAMS_VALUE [ "max_passes_count" ],
+ class="code sev- ">442 def __init__ ( # pylint: disable=super-init-not-called,too-many-arguments
443 penalty_strength : float = DEFAULT_PARAMS_VALUE [ "penalty_strength" ],
+ class="code sev- ">443 self ,
444 penalty_saturation : float = DEFAULT_PARAMS_VALUE [ "penalty_saturation" ],
+ class="code sev- ">444 minsupp_all : Tuple [ float , float , float , float ] = DEFAULT_PARAMS_VALUE [
445 survival_time_attr : str = None ,
+ class="code sev- ">445 "minsupp_all"
446 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
+ class="code sev- ">446 ],
447 max_growing : int = DEFAULT_PARAMS_VALUE [ "max_growing" ],
+ class="code sev- ">447 max_neg2pos : float = DEFAULT_PARAMS_VALUE [ "max_neg2pos" ],
448 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
+ class="code sev- ">448 max_passes_count : int = DEFAULT_PARAMS_VALUE [ "max_passes_count" ],
449 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
+ class="code sev- ">449 penalty_strength : float = DEFAULT_PARAMS_VALUE [ "penalty_strength" ],
450 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
+ class="code sev- ">450 penalty_saturation : float = DEFAULT_PARAMS_VALUE [ "penalty_saturation" ],
451 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
+ class="code sev- ">451 survival_time_attr : str = None ,
452 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
+ class="code sev- ">452 minsupp_new : float = DEFAULT_PARAMS_VALUE [ "minsupp_new" ],
453 "complementary_conditions"
+ class="code sev- ">453 max_growing : int = DEFAULT_PARAMS_VALUE [ "max_growing" ],
454 ],
+ class="code sev- ">454 enable_pruning : bool = DEFAULT_PARAMS_VALUE [ "enable_pruning" ],
455 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
+ class="code sev- ">455 ignore_missing : bool = DEFAULT_PARAMS_VALUE [ "ignore_missing" ],
456 ):
+ class="code sev- ">456 max_uncovered_fraction : float = DEFAULT_PARAMS_VALUE [ "max_uncovered_fraction" ],
457 """
+ class="code sev- ">457 select_best_candidate : bool = DEFAULT_PARAMS_VALUE [ "select_best_candidate" ],
458 Parameters
+ class="code sev- ">458 complementary_conditions : bool = DEFAULT_PARAMS_VALUE [
459 ----------
+ class="code sev- ">459 "complementary_conditions"
460 minsupp_all: Tuple[float, float, float, float]
+ class="code sev- ">460 ],
461 a minimum positive support of a contrast set (p/P). When multiple values are
+ class="code sev- ">461 max_rule_count : int = DEFAULT_PARAMS_VALUE [ "max_rule_count" ],
462 specified, a metainduction is performed; Default and recommended sequence
+ class="code sev- ">462 ):
463 is: 0.8, 0.5, 0.2, 0.1
+ class="code sev- ">463 """
464 max_neg2pos: float
+ class="code sev- ">464 Parameters
465 a maximum ratio of negative to positive supports (nP/pN); Default is 0.5
+ class="code sev- ">465 ----------
466 max_passes_count: int
+ class="code sev- ">466 minsupp_all: Tuple[float, float, float, float]
467 a maximum number of sequential covering passes for a single minsupp-all;
+ class="code sev- ">467 a minimum positive support of a contrast set (p/P). When multiple values are
468 Default is 5
+ class="code sev- ">468 specified, a metainduction is performed; Default and recommended sequence
469 penalty_strength: float
+ class="code sev- ">469 is: 0.8, 0.5, 0.2, 0.1
470 (s) - penalty strength; Default is 0.5
+ class="code sev- ">470 max_neg2pos: float
471 penalty_saturation: float
+ class="code sev- ">471 a maximum ratio of negative to positive supports (nP/pN); Default is 0.5
472 the value of p_new / P at which penalty reward saturates; Default is 0.2.
+ class="code sev- ">472 max_passes_count: int
473 survival_time_attr : str
+ class="code sev- ">473 a maximum number of sequential covering passes for a single minsupp-all;
474 name of column containing survival time data (use when data passed to model
+ class="code sev- ">474 Default is 5
475 is pandas dataframe).
+ class="code sev- ">475 penalty_strength: float
476 minsupp_new : float = 5.0
+ class="code sev- ">476 (s) - penalty strength; Default is 0.5
477 a minimum number (or fraction, if value < 1.0) of previously uncovered
+ class="code sev- ">477 penalty_saturation: float
478 examples to be covered by a new rule (positive examples for classification
+ class="code sev- ">478 the value of p_new / P at which penalty reward saturates; Default is 0.2.
479 problems); default: 5,
+ class="code sev- ">479 survival_time_attr : str
480 max_growing : int = 0.0
+ class="code sev- ">480 name of column containing survival time data (use when data passed to model
481 non-negative integer representing maximum number of conditions which can be
+ class="code sev- ">481 is pandas dataframe).
482 added to the rule in the growing phase (use this parameter for large
+ class="code sev- ">482 minsupp_new : float = 5.0
483 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
+ class="code sev- ">483 a minimum number (or fraction, if value < 1.0) of previously uncovered
484 enable_pruning : bool = True
+ class="code sev- ">484 examples to be covered by a new rule (positive examples for classification
485 enable or disable pruning, default is True.
+ class="code sev- ">485 problems); default: 5,
486 ignore_missing : bool = False
+ class="code sev- ">486 max_growing : int = 0.0
487 boolean telling whether missing values should be ignored (by default, a
+ class="code sev- ">487 non-negative integer representing maximum number of conditions which can be
488 missing value of given attribute is always considered as not fulfilling the
+ class="code sev- ">488 added to the rule in the growing phase (use this parameter for large
489 condition build upon that attribute); default: False.
+ class="code sev- ">489 datasets if execution time is prohibitive); 0 indicates no limit; default: 0
490 max_uncovered_fraction : float = 0.0
+ class="code sev- ">490 enable_pruning : bool = True
491 Floating-point number from [0,1] interval representing maximum fraction of
+ class="code sev- ">491 enable or disable pruning, default is True.
492 examples that may remain uncovered by the rule set, default: 0.0.
+ class="code sev- ">492 ignore_missing : bool = False
493 select_best_candidate : bool = False
+ class="code sev- ">493 boolean telling whether missing values should be ignored (by default, a
494 Flag determining if best candidate should be selected from growing phase;
+ class="code sev- ">494 missing value of given attribute is always considered as not fulfilling the
495 default: False.
+ class="code sev- ">495 condition build upon that attribute); default: False.
496 complementary_conditions : bool = False
+ class="code sev- ">496 max_uncovered_fraction : float = 0.0
497 If enabled, complementary conditions in the form a = !{value} for nominal
+ class="code sev- ">497 Floating-point number from [0,1] interval representing maximum fraction of
498 attributes are supported.
+ class="code sev- ">498 examples that may remain uncovered by the rule set, default: 0.0.
499 max_rule_count : int = 0
+ class="code sev- ">499 select_best_candidate : bool = False
500 Maximum number of rules to be generated (for classification data sets it
+ class="code sev- ">500 Flag determining if best candidate should be selected from growing phase;
501 applies to a single class); 0 indicates no limit.
+ class="code sev- ">501 default: False.
502 """
+ class="code sev- ">502 complementary_conditions : bool = False
503 self . _params = None
+ class="code sev- ">503 If enabled, complementary conditions in the form a = !{value} for nominal
504 self . _rule_generator = None
+ class="code sev- ">504 attributes are supported.
505 self . _configurator = None
+ class="code sev- ">505 max_rule_count : int = 0
506 self . contrast_attribute : str = None
+ class="code sev- ">506 Maximum number of rules to be generated (for classification data sets it
507 self . _initialize_rulekit ()
+ class="code sev- ">507 applies to a single class); 0 indicates no limit.
508 self . set_params (
+ class="code sev- ">508 """
509 minsupp_all = minsupp_all ,
+ class="code sev- ">509 self . _params = None
510 max_neg2pos = max_neg2pos ,
+ class="code sev- ">510 self . _rule_generator = None
511 max_passes_count = max_passes_count ,
+ class="code sev- ">511 self . _configurator = None
512 penalty_strength = penalty_strength ,
+ class="code sev- ">512 self . contrast_attribute : str = None
513 penalty_saturation = penalty_saturation ,
+ class="code sev- ">513 self . _initialize_rulekit ()
514 survival_time_attr = survival_time_attr ,
+ class="code sev- ">514 self . set_params (
515 minsupp_new = minsupp_new ,
+ class="code sev- ">515 minsupp_all = minsupp_all ,
516 max_growing = max_growing ,
+ class="code sev- ">516 max_neg2pos = max_neg2pos ,
517 enable_pruning = enable_pruning ,
+ class="code sev- ">517 max_passes_count = max_passes_count ,
518 ignore_missing = ignore_missing ,
+ class="code sev- ">518 penalty_strength = penalty_strength ,
519 max_uncovered_fraction = max_uncovered_fraction ,
+ class="code sev- ">519 penalty_saturation = penalty_saturation ,
520 select_best_candidate = select_best_candidate ,
+ class="code sev- ">520 survival_time_attr = survival_time_attr ,
521 complementary_conditions = complementary_conditions ,
+ class="code sev- ">521 minsupp_new = minsupp_new ,
522 max_rule_count = max_rule_count ,
+ class="code sev- ">522 max_growing = max_growing ,
523 )
+ class="code sev- ">523 enable_pruning = enable_pruning ,
524 self . model : RuleSet [ SurvivalRule ] = None
+ class="code sev- ">524 ignore_missing = ignore_missing ,
525
+ class="code sev- ">525 max_uncovered_fraction = max_uncovered_fraction ,
526 def set_params ( self , ** kwargs ) -> object :
+ class="code sev- ">526 select_best_candidate = select_best_candidate ,
527 """Set models hyperparameters. Parameters are the same as in constructor."""
+ class="code sev- ">527 complementary_conditions = complementary_conditions ,
528 # params validation
+ class="code sev- ">528 max_rule_count = max_rule_count ,
529 self . survival_time_attr = kwargs [ "survival_time_attr" ]
+ class="code sev- ">529 )
530 return BaseOperator . set_params ( self , ** kwargs )
+ class="code sev- ">530 self . model : RuleSet [ SurvivalRule ] = None
531
532 def fit ( # pylint: disable=arguments-renamed
+ class="code sev- ">532 def set_params ( self , ** kwargs ) -> object :
533 self ,
+ class="code sev- ">533 """Set models hyperparameters. Parameters are the same as in constructor."""
534 values : Data ,
+ class="code sev- ">534 # params validation
535 labels : Data ,
+ class="code sev- ">535 self . survival_time_attr = kwargs [ "survival_time_attr" ]
536 contrast_attribute : str ,
+ class="code sev- ">536 return BaseOperator . set_params ( self , ** kwargs )
537 survival_time : Data = None ,
+ class="code sev- ">537
538 ) -> ContrastSetSurvivalRules :
+ class="code sev- ">538 def fit ( # pylint: disable=arguments-renamed
539 """Train model on given dataset.
+ class="code sev- ">539 self ,
540
+ class="code sev- ">540 values : Data ,
541 Parameters
+ class="code sev- ">541 labels : Data ,
542 ----------
+ class="code sev- ">542 contrast_attribute : str ,
543 values : :class:`rulekit.operator.Data`
+ class="code sev- ">543 survival_time : Data = None ,
544 attributes
+ class="code sev- ">544 ) -> ContrastSetSurvivalRules :
545 labels : :class:`rulekit.operator.Data`
+ class="code sev- ">545 """Train model on given dataset.
546 survival status
+ class="code sev- ">546
547 contrast_attribute: str
+ class="code sev- ">547 Parameters
548 group attribute
+ class="code sev- ">548 ----------
549 survival_time: :class:`rulekit.operator.Data`
+ class="code sev- ">549 values : :class:`rulekit.operator.Data`
550 data about survival time. Could be omitted when *survival_time_attr*
+ class="code sev- ">550 attributes
551 parameter was specified.
+ class="code sev- ">551 labels : :class:`rulekit.operator.Data`
552
+ class="code sev- ">552 survival status
553 Returns
+ class="code sev- ">553 contrast_attribute: str
554 -------
+ class="code sev- ">554 group attribute
555 self : ContrastSetSurvivalRules
+ class="code sev- ">555 survival_time: :class:`rulekit.operator.Data`
556 """
+ class="code sev- ">556 data about survival time. Could be omitted when *survival_time_attr*
-
-
-
-
- E501
-
- Line too long (112 > 88 characters)
-
- 557 survival_time_attribute = SurvivalRules . _prepare_survival_attribute ( # pylint: disable=protected-access
+ class="code sev- ">
557 parameter was specified.
558 self , survival_time , values
+ class="code sev- ">558
559 )
+ class="code sev- ">559 Returns
560 super () . fit (
+ class="code sev- ">560 -------
561 values ,
+ class="code sev- ">561 self : ContrastSetSurvivalRules
562 labels ,
+ class="code sev- ">562 """
563 survival_time_attribute = survival_time_attribute ,
+ class="code sev-2 le">
+
+
+
+
+ E501
+
+ Line too long (112 > 88 characters)
+
+ 563 survival_time_attribute = SurvivalRules . _prepare_survival_attribute ( # pylint: disable=protected-access
564 contrast_attribute = contrast_attribute ,
+ class="code sev- ">564 self , survival_time , values
565 )
566 self . contrast_attribute = contrast_attribute
+ class="code sev- ">566 super () . fit (
567 return self
+ class="code sev- ">567 values ,
568
+ class="code sev- ">568 labels ,
569 def predict ( self , values : Data ) -> np . ndarray :
+ class="code sev- ">569 survival_time_attribute = survival_time_attribute ,
570 """Perform prediction and return estimated survival function for each example.
+ class="code sev- ">570 contrast_attribute = contrast_attribute ,
571
+ class="code sev- ">571 )
572 Parameters
+ class="code sev- ">572 self . contrast_attribute = contrast_attribute
573 ----------
+ class="code sev- ">573 return self
574 values : :class:`rulekit.operator.Data`
+ class="code sev- ">574
575 attributes
+ class="code sev- ">575 def predict ( self , values : Data ) -> np . ndarray :
576
+ class="code sev- ">576 """Perform prediction and return estimated survival function for each example.
577 Returns
+ class="code sev- ">577
578 -------
+ class="code sev- ">578 Parameters
579 result : np.ndarray
+ class="code sev- ">579 ----------
580 Each row represent single example from dataset and contains estimated
+ class="code sev- ">580 values : :class:`rulekit.operator.Data`
581 survival function for that example. Estimated survival function is returned
+ class="code sev- ">581 attributes
582 as a dictionary containing times and corresponding probabilities.
+ class="code sev- ">582
583 """
+ class="code sev- ">583 Returns
584 return PredictionResultMapper . map_survival ( super () . predict ( values ))
+ class="code sev- ">584 -------
585
+ class="code sev- ">585 result : np.ndarray
586 def score ( self , values : Data , labels : Data , survival_time : Data = None ) -> float :
+ class="code sev- ">586 Each row represent single example from dataset and contains estimated
587 """Return the Integrated Brier Score on the given dataset and
+ class="code sev- ">587 survival function for that example. Estimated survival function is returned
588 labels(event status indicator).
+ class="code sev- ">588 as a dictionary containing times and corresponding probabilities.
589
+ class="code sev- ">589 """
590 Integrated Brier Score (IBS) - the Brier score (BS) represents the squared
+ class="code sev- ">590 return PredictionResultMapper . map_survival ( super () . predict ( values ))
591 differencebetween true event status at time T and predicted event status at that
+ class="code sev- ">591
592 time; the Integrated Brier score summarizes the prediction error over all
+ class="code sev- ">592 def score ( self , values : Data , labels : Data , survival_time : Data = None ) -> float :
593 observations and over all times in a test set.
+ class="code sev- ">593 """Return the Integrated Brier Score on the given dataset and
594
+ class="code sev- ">594 labels(event status indicator).
595 Parameters
+ class="code sev- ">595
596 ----------
+ class="code sev- ">596 Integrated Brier Score (IBS) - the Brier score (BS) represents the squared
597 values : :class:`rulekit.operator.Data`
+ class="code sev- ">597 differencebetween true event status at time T and predicted event status at that
598 attributes
+ class="code sev- ">598 time; the Integrated Brier score summarizes the prediction error over all
599 labels : :class:`rulekit.operator.Data`
+ class="code sev- ">599 observations and over all times in a test set.
600 survival status
+ class="code sev- ">600
601 survival_time: :class:`rulekit.operator.Data`
+ class="code sev- ">601 Parameters
602 data about survival time. Could be omitted when *survival_time_attr*
+ class="code sev- ">602 ----------
603 parameter was specified
+ class="code sev- ">603 values : :class:`rulekit.operator.Data`
604
+ class="code sev- ">604 attributes
605 Returns
+ class="code sev- ">605 labels : :class:`rulekit.operator.Data`
606 -------
+ class="code sev- ">606 survival status
607 score : float
+ class="code sev- ">607 survival_time: :class:`rulekit.operator.Data`
608 Integrated Brier Score of self.predict(values) wrt. labels.
+ class="code sev- ">608 data about survival time. Could be omitted when *survival_time_attr*
609 """
+ class="code sev- ">609 parameter was specified
610 return SurvivalRules . score ( self , values , labels , survival_time = survival_time )
+ class="code sev- ">610
611
+ class="code sev- ">611 Returns
612 def _get_problem_type ( self ) -> ProblemType :
+ class="code sev- ">612 -------
613 return ProblemType . CONTRAST_SURVIVAL
+ class="code sev- ">613 score : float
+
+ 614 Integrated Brier Score of self.predict(values) wrt. labels.
+
+ 615 """
+
+ 616 return SurvivalRules . score ( self , values , labels , survival_time = survival_time )
+
+ 617
+
+ 618 def _get_problem_type ( self ) -> ProblemType :
+
+ 619 return ProblemType . CONTRAST_SURVIVAL
diff --git a/docs/reports/junit/report.html b/docs/reports/junit/report.html
index 3c44db4..0d42d07 100644
--- a/docs/reports/junit/report.html
+++ b/docs/reports/junit/report.html
@@ -260,29 +260,29 @@
tests.test_classifier.TestClassifier
@@ -290,13 +290,13 @@
tests.test_classifier.TestExperClassifier
@@ -304,11 +304,11 @@
tests.test_regression.TestExpertRegressor
@@ -316,13 +316,13 @@
tests.test_regression.TestRegressor
@@ -330,9 +330,9 @@
tests.test_rulekit.TestRuleKitMainClass
@@ -340,19 +340,19 @@
tests.test_serialization.TestModelSerialization
@@ -360,7 +360,7 @@
tests.test_sklearn_metrics.TestMetrics
@@ -368,7 +368,7 @@
tests.test_statistics.TestRuleClassifier
@@ -376,9 +376,11 @@
tests.test_survival.TestExpertSurvivalRules
@@ -386,11 +388,11 @@
tests.test_survival.TestKaplanMeierEstimator
@@ -398,17 +400,17 @@
tests.test_survival.TestSurvivalRules
@@ -509,6 +511,8 @@
+
+
@@ -542,16 +546,16 @@
Test Suite:
-
+
Results
- Duration 30.906 sec
+ Duration 30.032 sec
- Tests 45
+ Tests 46
Failures 0
@@ -566,11 +570,11 @@ tests.test_classifier.TestClassifier
-
+
Test case: test_classification_accuracy_on_iris
Outcome: Passed
- Duration: 0.974 sec
+ Duration: 0.91 sec
@@ -584,11 +588,11 @@
tests.test_classifier.TestClassifier
-
+
Test case: test_classification_metrics
Outcome: Passed
- Duration: 0.028 sec
+ Duration: 0.027 sec
@@ -602,7 +606,7 @@
tests.test_classifier.TestClassifier
-
+
Test case: test_classification_predict_proba
Outcome: Passed
@@ -620,11 +624,11 @@ tests.test_classifier.TestClassifier
-
+
Test case: test_compare_with_java_results
Outcome: Passed
- Duration: 0.374 sec
+ Duration: 0.394 sec
@@ -638,11 +642,11 @@
tests.test_classifier.TestClassifier
-
+
Test case: test_fit_and_predict_on_boolean_columns
Outcome: Passed
- Duration: 0.157 sec
+ Duration: 0.155 sec
@@ -656,11 +660,11 @@
tests.test_classifier.TestClassifier
-
+
Test case: test_fit_on_integer_labels
Outcome: Passed
- Duration: 0.09 sec
+ Duration: 0.027 sec
@@ -674,11 +678,11 @@
tests.test_classifier.TestClassifier
-
+
Test case: test_getting_examples_coverage
Outcome: Passed
- Duration: 0.017 sec
+ Duration: 0.095 sec
@@ -692,11 +696,11 @@
tests.test_classifier.TestClassifier
-
+
Test case: test_induction_progress_listener
Outcome: Passed
- Duration: 0.065 sec
+ Duration: 0.064 sec
@@ -710,11 +714,11 @@
tests.test_classifier.TestClassifier
-
+
Test case: test_predict_proba
Outcome: Passed
- Duration: 0.155 sec
+ Duration: 0.073 sec
@@ -728,7 +732,7 @@
tests.test_classifier.TestClassifier
-
+
Test case: test_prediction_on_nominal_values
Outcome: Passed
@@ -746,7 +750,7 @@ tests.test_classifier.TestClassifier
-
+
Test case: test_prediction_results_mapping
Outcome: Passed
@@ -764,11 +768,11 @@ tests.test_classifier.TestClassifier
-
+
Test case: test_score
Outcome: Passed
- Duration: 0.015 sec
+ Duration: 0.136 sec
@@ -789,11 +793,11 @@
tests.test_classifier.TestExperClassifier
-
+
Test case: test_compare_with_java_results
Outcome: Passed
- Duration: 0.795 sec
+ Duration: 0.724 sec
@@ -807,11 +811,11 @@
tests.test_classifier.TestExperClassifier
-
+
Test case: test_left_open_intervals_in_expert_induction
Outcome: Passed
- Duration: 0.073 sec
+ Duration: 0.064 sec
@@ -825,11 +829,11 @@
tests.test_classifier.TestExperClassifier
-
+
Test case: test_predict_proba
Outcome: Passed
- Duration: 0.047 sec
+ Duration: 0.07 sec
@@ -843,11 +847,11 @@
tests.test_classifier.TestExperClassifier
-
+
Test case: test_refining_conditions_for_nominal_attributes
Outcome: Passed
- Duration: 0.534 sec
+ Duration: 0.561 sec
@@ -868,11 +872,11 @@
tests.test_regression.TestExpertRegressor
-
+
Test case: test_compare_with_java_results
Outcome: Passed
- Duration: 1.196 sec
+ Duration: 1.08 sec
@@ -886,7 +890,7 @@
tests.test_regression.TestExpertRegressor
-
+
Test case: test_legacy_expert_rules_format
Outcome: Passed
@@ -904,7 +908,7 @@ tests.test_regression.TestExpertRegressor
-
+
Test case: test_refining_conditions_for_nominal_attributes
Outcome: Passed
@@ -929,11 +933,11 @@ tests.test_regression.TestRegressor
-
+
Test case: test_cholesterol
Outcome: Passed
- Duration: 3.309 sec
+ Duration: 3.302 sec
@@ -947,7 +951,7 @@
tests.test_regression.TestRegressor
-
+
Test case: test_compare_with_java_results
Outcome: Passed
@@ -965,11 +969,11 @@ tests.test_regression.TestRegressor
-
+
Test case: test_fit_and_predict_on_boolean_columns
Outcome: Passed
- Duration: 0.495 sec
+ Duration: 0.58 sec
@@ -983,11 +987,11 @@
tests.test_regression.TestRegressor
-
+
Test case: test_induction_progress_listener
Outcome: Passed
- Duration: 0.03 sec
+ Duration: 0.035 sec
@@ -1008,7 +1012,7 @@
tests.test_rulekit.TestRuleKitMainClass
-
+
Test case: test_loading_rulekit_class
Outcome: Passed
@@ -1026,7 +1030,7 @@ tests.test_rulekit.TestRuleKitMainClass
-
+
Test case: test_reading_version
Outcome: Passed
@@ -1051,11 +1055,11 @@ tests.test_serialization.TestModelSerialization
-
+
Test case: test_classifier_serialization
Outcome: Passed
- Duration: 0.085 sec
+ Duration: 0.099 sec
@@ -1069,11 +1073,11 @@
tests.test_serialization.TestModelSerialization
-
+
Test case: test_expert_classifier_serialization
Outcome: Passed
- Duration: 0.031 sec
+ Duration: 0.028 sec
@@ -1087,11 +1091,11 @@
tests.test_serialization.TestModelSerialization
-
+
Test case: test_expert_regressor_serialization
Outcome: Passed
- Duration: 0.068 sec
+ Duration: 0.081 sec
@@ -1105,11 +1109,11 @@
tests.test_serialization.TestModelSerialization
-
+
Test case: test_expert_survival_serialization
Outcome: Passed
- Duration: 0.052 sec
+ Duration: 0.046 sec
@@ -1123,11 +1127,11 @@
tests.test_serialization.TestModelSerialization
-
+
Test case: test_multiple_serialization
Outcome: Passed
- Duration: 0.015 sec
+ Duration: 0.014 sec
@@ -1141,11 +1145,11 @@
tests.test_serialization.TestModelSerialization
-
+
Test case: test_regressor_serialization
Outcome: Passed
- Duration: 4.265 sec
+ Duration: 3.701 sec
@@ -1159,11 +1163,11 @@
tests.test_serialization.TestModelSerialization
-
+
Test case: test_survival_serialization
Outcome: Passed
- Duration: 0.214 sec
+ Duration: 0.306 sec
@@ -1184,11 +1188,11 @@
tests.test_sklearn_metrics.TestMetrics
-
+
Test case: test_classification_accuracy_on_iris
Outcome: Passed
- Duration: 0.014 sec
+ Duration: 0.022 sec
@@ -1209,11 +1213,11 @@
tests.test_statistics.TestRuleClassifier
-
+
Test case: test_classification_accuracy_on_iris
Outcome: Passed
- Duration: 0.01 sec
+ Duration: 0.013 sec
@@ -1234,11 +1238,11 @@
tests.test_survival.TestExpertSurvivalRules
-
+
Test case: test_compare_with_java_results
Outcome: Passed
- Duration: 1.635 sec
+ Duration: 1.892 sec
@@ -1252,11 +1256,29 @@
tests.test_survival.TestExpertSurvivalRules
-
+
Test case: test_refining_conditions_for_nominal_attributes
Outcome: Passed
- Duration: 0.165 sec
+ Duration: 0.191 sec
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Test case: test_refining_conditions_for_numerical_attributes
+ Outcome: Passed
+ Duration: 0.12 sec
@@ -1277,11 +1299,11 @@
tests.test_survival.TestKaplanMeierEstimator
-
+
Test case: test_accessing_at_risk_count
Outcome: Passed
- Duration: 1.242 sec
+ Duration: 1.39 sec
@@ -1295,11 +1317,11 @@
tests.test_survival.TestKaplanMeierEstimator
-
+
Test case: test_accessing_events_count
Outcome: Passed
- Duration: 1.034 sec
+ Duration: 1.089 sec
@@ -1313,11 +1335,11 @@
tests.test_survival.TestKaplanMeierEstimator
-
+
Test case: test_accessing_probabilities
Outcome: Passed
- Duration: 0.999 sec
+ Duration: 1.071 sec
@@ -1338,11 +1360,11 @@
tests.test_survival.TestSurvivalRules
-
+
Test case: test_compare_with_java_results
Outcome: Passed
- Duration: 1.712 sec
+ Duration: 1.507 sec
@@ -1356,11 +1378,11 @@
tests.test_survival.TestSurvivalRules
-
+
Test case: test_fit_and_predict_on_boolean_columns
Outcome: Passed
- Duration: 3.122 sec
+ Duration: 3.02 sec
@@ -1374,11 +1396,11 @@
tests.test_survival.TestSurvivalRules
-
+
Test case: test_getting_training_dataset_kaplan_meier_estimator
Outcome: Passed
- Duration: 1.552 sec
+ Duration: 1.386 sec
@@ -1392,11 +1414,11 @@
tests.test_survival.TestSurvivalRules
-
+
Test case: test_ibs_calculation
Outcome: Passed
- Duration: 1.723 sec
+ Duration: 1.535 sec
@@ -1410,11 +1432,11 @@
tests.test_survival.TestSurvivalRules
-
+
Test case: test_induction_progress_listener
Outcome: Passed
- Duration: 1.065 sec
+ Duration: 0.984 sec
@@ -1428,11 +1450,11 @@
tests.test_survival.TestSurvivalRules
-
+
Test case: test_passing_survival_time_column_to_fit_method
Outcome: Passed
- Duration: 3.172 sec
+ Duration: 2.866 sec
diff --git a/docs/serve/index.html b/docs/serve/index.html
index 7885096..0a38c1c 100644
--- a/docs/serve/index.html
+++ b/docs/serve/index.html
@@ -123,7 +123,14 @@
- v2.1.21.0 (latest)
+ v2.1.21.0
+
+
+
+
+
+
+ v2.1.24.0 (latest)
@@ -137,6 +144,8 @@
+
+
diff --git a/docs/serve/v2.1.24.0/.buildinfo b/docs/serve/v2.1.24.0/.buildinfo
new file mode 100644
index 0000000..093c0ac
--- /dev/null
+++ b/docs/serve/v2.1.24.0/.buildinfo
@@ -0,0 +1,4 @@
+# Sphinx build info version 1
+# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
+config: 12f3af7734ee25ce1367bfd71b5b933c
+tags: 645f666f9bcd5a90fca523b33c5a78b7
diff --git a/docs/serve/v2.1.24.0/_images/rst_tutorials_classification_7_0.png b/docs/serve/v2.1.24.0/_images/rst_tutorials_classification_7_0.png
new file mode 100644
index 0000000..9628e4b
Binary files /dev/null and b/docs/serve/v2.1.24.0/_images/rst_tutorials_classification_7_0.png differ
diff --git a/docs/serve/v2.1.24.0/_images/rst_tutorials_survival_13_1.png b/docs/serve/v2.1.24.0/_images/rst_tutorials_survival_13_1.png
new file mode 100644
index 0000000..f31eca8
Binary files /dev/null and b/docs/serve/v2.1.24.0/_images/rst_tutorials_survival_13_1.png differ
diff --git a/docs/serve/v2.1.24.0/_images/rst_tutorials_survival_15_1.png b/docs/serve/v2.1.24.0/_images/rst_tutorials_survival_15_1.png
new file mode 100644
index 0000000..4acdc53
Binary files /dev/null and b/docs/serve/v2.1.24.0/_images/rst_tutorials_survival_15_1.png differ
diff --git a/docs/serve/v2.1.24.0/_images/rst_tutorials_survival_35_1.png b/docs/serve/v2.1.24.0/_images/rst_tutorials_survival_35_1.png
new file mode 100644
index 0000000..33c7d36
Binary files /dev/null and b/docs/serve/v2.1.24.0/_images/rst_tutorials_survival_35_1.png differ
diff --git a/docs/serve/v2.1.24.0/_sources/index.rst.txt b/docs/serve/v2.1.24.0/_sources/index.rst.txt
new file mode 100644
index 0000000..555fe10
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_sources/index.rst.txt
@@ -0,0 +1,25 @@
+
+RuleKit
+========================================
+
+This package is python wrapper for `RuleKit
`__ library (a versatile tool for rule learning).
+Based on a sequential covering induction algorithm, it is suitable for:
+
+- classification,
+
+- regression,
+
+- survival problems.
+
+This wrapper aims to give an easy way to integrate RuleKit functionality into python projects and notebooks.
+All package models are writen to be compatible with scikit learn library.
+
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Table of contents:
+
+ Quick start <./rst/quick_start.rst>
+ Whats new <./rst/whats_new/Changes in this version.ipynb>
+ Tutorials <./rst/tutorials.rst>
+ Code documentation <./rst/autodoc.rst>
diff --git a/docs/serve/v2.1.24.0/_sources/rst/autodoc.rst.txt b/docs/serve/v2.1.24.0/_sources/rst/autodoc.rst.txt
new file mode 100644
index 0000000..92c55aa
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_sources/rst/autodoc.rst.txt
@@ -0,0 +1,17 @@
+
+Code documentation
+========================================
+
+.. automodule:: rulekit.main
+ :members:
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Table of contents:
+
+ Classification <./autodoc/classification.rst>
+ Regression <./autodoc/regression.rst>
+ Survival <./autodoc/survival.rst>
+ Parameters <./autodoc/params.rst>
+ Rules <./autodoc/rules.rst>
+ Statistics <./autodoc/stats.rst>
diff --git a/docs/serve/v2.1.24.0/_sources/rst/autodoc/classification.rst.txt b/docs/serve/v2.1.24.0/_sources/rst/autodoc/classification.rst.txt
new file mode 100644
index 0000000..078705a
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_sources/rst/autodoc/classification.rst.txt
@@ -0,0 +1,11 @@
+
+Classification
+========================================
+
+.. autoclass:: rulekit.classification.RuleClassifier
+ :members:
+ :inherited-members:
+
+.. autoclass:: rulekit.classification.ExpertRuleClassifier
+ :members:
+ :inherited-members:
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/_sources/rst/autodoc/params.rst.txt b/docs/serve/v2.1.24.0/_sources/rst/autodoc/params.rst.txt
new file mode 100644
index 0000000..43ee18a
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_sources/rst/autodoc/params.rst.txt
@@ -0,0 +1,93 @@
+Parameters
+========================================
+
+
+.. data:: rulekit.operator.Data
+
+ alias of type Union[numpy.ndarray, pandas.core.frame.DataFrame, List]
+
+.. automodule:: rulekit.params
+ :exclude-members: Measures
+
+ .. autoclass:: Measures
+ :show-inheritance:
+
+ .. autoattribute:: Accuracy
+
+ .. autoattribute:: BinaryEntropy
+
+ .. autoattribute:: C1
+
+ .. autoattribute:: C2
+
+ .. autoattribute:: CFoil
+
+ .. autoattribute:: CN2Significnce
+
+ .. autoattribute:: Correlation
+
+ .. autoattribute:: Coverage
+
+ .. autoattribute:: FBayesianConfirmation
+
+ .. autoattribute:: FMeasure
+
+ .. autoattribute:: FullCoverage
+
+ .. autoattribute:: GeoRSS
+
+ .. autoattribute:: GMeasure
+
+ .. autoattribute:: InformationGain
+
+ .. autoattribute:: JMeasure
+
+ .. autoattribute:: Kappa
+
+ .. autoattribute:: Klosgen
+
+ .. autoattribute:: Laplace
+
+ .. autoattribute:: Lift
+
+ .. autoattribute:: LogicalSufficiency
+
+ .. autoattribute:: MEstimate
+
+ .. autoattribute:: MutualSupport
+
+ .. autoattribute:: Novelty
+
+ .. autoattribute:: OddsRatio
+
+ .. autoattribute:: OneWaySupport
+
+ .. autoattribute:: PawlakDependencyFactor
+
+ .. autoattribute:: Q2
+
+ .. autoattribute:: Precision
+
+ .. autoattribute:: RelativeRisk
+
+ .. autoattribute:: Ripper
+
+ .. autoattribute:: RuleInterest
+
+ .. autoattribute:: RSS
+
+ .. autoattribute:: SBayesian
+
+ .. autoattribute:: Sensitivity
+
+ .. autoattribute:: Specificity
+
+ .. autoattribute:: TwoWaySupport
+
+ .. autoattribute:: WeightedLaplace
+
+ .. autoattribute:: WeightedRelativeAccuracy
+
+ .. autoattribute:: YAILS
+
+ .. autoattribute:: LogRank
diff --git a/docs/serve/v2.1.24.0/_sources/rst/autodoc/regression.rst.txt b/docs/serve/v2.1.24.0/_sources/rst/autodoc/regression.rst.txt
new file mode 100644
index 0000000..7fac70e
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_sources/rst/autodoc/regression.rst.txt
@@ -0,0 +1,10 @@
+Regression
+==========
+
+.. autoclass:: rulekit.regression.RuleRegressor
+ :members:
+ :inherited-members:
+
+.. autoclass:: rulekit.regression.ExpertRuleRegressor
+ :members:
+ :inherited-members:
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/_sources/rst/autodoc/rules.rst.txt b/docs/serve/v2.1.24.0/_sources/rst/autodoc/rules.rst.txt
new file mode 100644
index 0000000..bbfb451
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_sources/rst/autodoc/rules.rst.txt
@@ -0,0 +1,5 @@
+Rules
+=====
+
+.. automodule:: rulekit.rules
+ :members:
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/_sources/rst/autodoc/stats.rst.txt b/docs/serve/v2.1.24.0/_sources/rst/autodoc/stats.rst.txt
new file mode 100644
index 0000000..f541dad
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_sources/rst/autodoc/stats.rst.txt
@@ -0,0 +1,5 @@
+Statistics
+==========
+
+.. automodule:: rulekit.stats
+ :members:
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/_sources/rst/autodoc/survival.rst.txt b/docs/serve/v2.1.24.0/_sources/rst/autodoc/survival.rst.txt
new file mode 100644
index 0000000..b7d7d77
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_sources/rst/autodoc/survival.rst.txt
@@ -0,0 +1,10 @@
+Survival
+==========
+
+.. autoclass:: rulekit.survival.SurvivalRules
+ :members:
+ :inherited-members:
+
+.. autoclass:: rulekit.survival.ExpertSurvivalRules
+ :members:
+ :inherited-members:
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/_sources/rst/quick_start.rst.txt b/docs/serve/v2.1.24.0/_sources/rst/quick_start.rst.txt
new file mode 100644
index 0000000..b35dd8d
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_sources/rst/quick_start.rst.txt
@@ -0,0 +1,69 @@
+
+Quick start
+========================================
+
+.. warning::
+ This package is a wrapper for Java library, and requires Java Development Kit version 8
+ or later to be installed on the computer. Both Open JDK and Oracle implementations are supported.
+
+ If you don't have JDK installed on your computer you can quickly set it up using
+ :ref:`install-jdk
` package.
+
+ .. code-block:: bash
+
+ pip install install-jdk
+
+ .. code-block:: python
+
+ import jdk
+
+ jdk.install('11', jre=True)
+
+Installation
+-------------
+
+.. code-block:: bash
+
+ pip install rulekit
+
+.. note::
+
+To check if everything was installed correctly call:
+
+.. code-block:: python
+
+ import rulekit
+ rulekit.__version__
+
+It should run without errors and print package version.
+
+Package usage
+--------------------
+
+Now we are finally ready to use rulekit package and its models.
+
+.. code-block:: python
+
+ from sklearn import datasets
+ from rulekit import RuleKit
+ from rulekit.classification import RuleClassifier
+
+ iris = datasets.load_iris()
+ X = iris.data
+ y = iris.target
+
+ classifier = RuleClassifier()
+ classifier.fit(X, y)
+
+ prediction = classifier.predict(X)
+
+ from sklearn.metrics import accuracy_score
+
+ print('Accuracy: ', accuracy_score(y, prediction))
+
+
+As you may noticed, training and usage of rulekit models is the same as in scikit learn. This
+mean you easily can use scikit: metrics, cross-validation, hyper-parameters tuning etc.
+
+
+For more examples head to :doc:`Tutorials <./tutorials>` section.
diff --git a/docs/serve/v2.1.24.0/_sources/rst/tutorials.rst.txt b/docs/serve/v2.1.24.0/_sources/rst/tutorials.rst.txt
new file mode 100644
index 0000000..ab6b2f1
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_sources/rst/tutorials.rst.txt
@@ -0,0 +1,12 @@
+
+Tutorials
+=========
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Table of contents:
+
+ Classification <./tutorials/classification.ipynb>
+ Regression <./tutorials/regression.ipynb>
+ Survival <./tutorials/survival.ipynb>
+ Expert Rules <./tutorials/expert_rules.ipynb>
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/_sources/rst/tutorials/classification.ipynb.txt b/docs/serve/v2.1.24.0/_sources/rst/tutorials/classification.ipynb.txt
new file mode 100644
index 0000000..1e89340
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_sources/rst/tutorials/classification.ipynb.txt
@@ -0,0 +1,1592 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Classification"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This notebook presents example usage of package for solving classification problem on `seismic-bumps` dataset. You can access dataset [here](https://raw.githubusercontent.com/adaa-polsl/RuleKit/master/data/seismic-bumps/seismic-bumps.arff).\n",
+ "\n",
+ "This tutorial will cover topics such as: \n",
+ "- training model \n",
+ "- changing model hyperparameters \n",
+ "- hyperparameters tuning \n",
+ "- calculating metrics for model \n",
+ "- getting RuleKit inbuilt "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Install dependencies"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%pip install matplotlib"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Summary of the dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " genergy \n",
+ " gimpuls \n",
+ " goenergy \n",
+ " goimpuls \n",
+ " nbumps \n",
+ " nbumps2 \n",
+ " nbumps3 \n",
+ " nbumps4 \n",
+ " nbumps5 \n",
+ " nbumps6 \n",
+ " nbumps7 \n",
+ " nbumps89 \n",
+ " senergy \n",
+ " maxenergy \n",
+ " class \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " count \n",
+ " 2.584000e+03 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " 2584.0 \n",
+ " 2584.0 \n",
+ " 2584.0 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " \n",
+ " \n",
+ " mean \n",
+ " 9.024252e+04 \n",
+ " 538.579334 \n",
+ " 12.375774 \n",
+ " 4.508901 \n",
+ " 0.859520 \n",
+ " 0.393576 \n",
+ " 0.392802 \n",
+ " 0.067724 \n",
+ " 0.004644 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 4975.270898 \n",
+ " 4278.850619 \n",
+ " 0.065789 \n",
+ " \n",
+ " \n",
+ " std \n",
+ " 2.292005e+05 \n",
+ " 562.652536 \n",
+ " 80.319051 \n",
+ " 63.166556 \n",
+ " 1.364616 \n",
+ " 0.783772 \n",
+ " 0.769710 \n",
+ " 0.279059 \n",
+ " 0.068001 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 20450.833222 \n",
+ " 19357.454882 \n",
+ " 0.247962 \n",
+ " \n",
+ " \n",
+ " min \n",
+ " 1.000000e+02 \n",
+ " 2.000000 \n",
+ " -96.000000 \n",
+ " -96.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " \n",
+ " \n",
+ " 25% \n",
+ " 1.166000e+04 \n",
+ " 190.000000 \n",
+ " -37.000000 \n",
+ " -36.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " \n",
+ " \n",
+ " 50% \n",
+ " 2.548500e+04 \n",
+ " 379.000000 \n",
+ " -6.000000 \n",
+ " -6.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " \n",
+ " \n",
+ " 75% \n",
+ " 5.283250e+04 \n",
+ " 669.000000 \n",
+ " 38.000000 \n",
+ " 30.250000 \n",
+ " 1.000000 \n",
+ " 1.000000 \n",
+ " 1.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 2600.000000 \n",
+ " 2000.000000 \n",
+ " 0.000000 \n",
+ " \n",
+ " \n",
+ " max \n",
+ " 2.595650e+06 \n",
+ " 4518.000000 \n",
+ " 1245.000000 \n",
+ " 838.000000 \n",
+ " 9.000000 \n",
+ " 8.000000 \n",
+ " 7.000000 \n",
+ " 3.000000 \n",
+ " 1.000000 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 402000.000000 \n",
+ " 400000.000000 \n",
+ " 1.000000 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " genergy gimpuls goenergy goimpuls nbumps \\\n",
+ "count 2.584000e+03 2584.000000 2584.000000 2584.000000 2584.000000 \n",
+ "mean 9.024252e+04 538.579334 12.375774 4.508901 0.859520 \n",
+ "std 2.292005e+05 562.652536 80.319051 63.166556 1.364616 \n",
+ "min 1.000000e+02 2.000000 -96.000000 -96.000000 0.000000 \n",
+ "25% 1.166000e+04 190.000000 -37.000000 -36.000000 0.000000 \n",
+ "50% 2.548500e+04 379.000000 -6.000000 -6.000000 0.000000 \n",
+ "75% 5.283250e+04 669.000000 38.000000 30.250000 1.000000 \n",
+ "max 2.595650e+06 4518.000000 1245.000000 838.000000 9.000000 \n",
+ "\n",
+ " nbumps2 nbumps3 nbumps4 nbumps5 nbumps6 nbumps7 \\\n",
+ "count 2584.000000 2584.000000 2584.000000 2584.000000 2584.0 2584.0 \n",
+ "mean 0.393576 0.392802 0.067724 0.004644 0.0 0.0 \n",
+ "std 0.783772 0.769710 0.279059 0.068001 0.0 0.0 \n",
+ "min 0.000000 0.000000 0.000000 0.000000 0.0 0.0 \n",
+ "25% 0.000000 0.000000 0.000000 0.000000 0.0 0.0 \n",
+ "50% 0.000000 0.000000 0.000000 0.000000 0.0 0.0 \n",
+ "75% 1.000000 1.000000 0.000000 0.000000 0.0 0.0 \n",
+ "max 8.000000 7.000000 3.000000 1.000000 0.0 0.0 \n",
+ "\n",
+ " nbumps89 senergy maxenergy class \n",
+ "count 2584.0 2584.000000 2584.000000 2584.000000 \n",
+ "mean 0.0 4975.270898 4278.850619 0.065789 \n",
+ "std 0.0 20450.833222 19357.454882 0.247962 \n",
+ "min 0.0 0.000000 0.000000 0.000000 \n",
+ "25% 0.0 0.000000 0.000000 0.000000 \n",
+ "50% 0.0 0.000000 0.000000 0.000000 \n",
+ "75% 0.0 2600.000000 2000.000000 0.000000 \n",
+ "max 0.0 402000.000000 400000.000000 1.000000 "
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import pandas as pd\n",
+ "from rulekit.arff import read_arff\n",
+ "\n",
+ "DATASET_URL: str = (\n",
+ " 'https://raw.githubusercontent.com/'\n",
+ " 'adaa-polsl/RuleKit/refs/heads/master/data/seismic-bumps/'\n",
+ " 'seismic-bumps.arff'\n",
+ ")\n",
+ "\n",
+ "df_full: pd.DataFrame = read_arff(DATASET_URL)\n",
+ "df_full['class'] = df_full['class'].astype(int)\n",
+ "df_full.describe()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Decision class distribution"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAgMAAAGLCAYAAABa0JF/AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAABE1klEQVR4nO3dd3xc1YE2/ufe6UVt1Ltsucu9G4PBBWxjShqQhBACm2R3k81mQ3bfN/tu/2V3s5stIbRAIBASIJRgOhiDwQ033Lst2apWb9Prvff3h4yxLMmW7Zk5U57v56OP7JmR9EiyNY/OOfccSdM0DURERJS2ZNEBiIiISCyWASIiojTHMkBERJTmWAaIiIjSHMsAERFRmmMZICIiSnMsA0RERGmOZYCIiCjNsQwQERGlOZYBIiKiNMcyQEQJbfPmzbj11ltRUlICSZLw+uuvi45ElHJYBogooXm9XsyYMQOPPvqo6ChEKUsvOgAR0cWsXr0aq1evFh2DKKVxZICIiCjNsQwQERGlOZYBIiKiNMcyQERElOZYBoiIiNIcryYgooTm8XhQV1d37u/19fXYv38/HA4HKioqBCYjSh2Spmma6BBERCPZuHEjli5dOuT2e++9F7/97W/jH4goBbEMEBERpTmuGSAiIkpzLANERERpjmWAiIgozbEMEBERpTmWASIiojTHMkBERJTmWAaIiIjSHHcgJEoBgbCCLncQXZ4gus++7nIH0X32db8vjIiqIaJqUFQVEUWDop590TRsMv4VIMlnX3SAzgAYbYDRDpjsgCkDMGYM/Pmz26y5QEYJkFEEZBQDeqPoLwMRXSGWAaIE1+8L4WibC829voEnfHcQ3Z7QoCd7dzBydR/E3HCVKSXA6hgoB5nFAwUhsxRwVAN54wdejLar/BhEFCssA0QJQtM0NPT4cKzNhWNtLhxtHXjd6gyIjjYKGuDrGXjpODTM/dJAOcgbD+RN+Px1wRTAnh/3tEQ0GLcjJhLAH1JwvN2Fo+c98Z9od8MbUoTkaTB/XcjHBTBQEopnAiUzgZJZQOmcgVEGIooblgGiOKjtcGPTyS7sa+7HsTYXGrq9UBPof57QMjAcRzVQNg8onwdULQHyJ4hORJTSWAaIYsATjGBrbTc2nezC5pNdONPvFx3pohKuDFwoowQYez0w9oaBl4wi0YmIUgrLAFGUHGl1YtPJLmw80YV9TX0IK8nzXyvhy8CF8iaeLQbXA2OuH7i6gYiuGMsA0RVy+sLYXDvw5L+ltgud7qDoSFcs6crA+XQmoHopMPlWYOLNXG9AdAVYBoguw8kON9471I6NJztxsMUJJZEm/q9CUpeB80k6oPIaYPJtwORbgMwS0YmIkgLLANEldHuCeGN/K9bubcGRVpfoODGRMmVgEGngyoSaLwDT7wLsBaIDESUslgGiYQQjCj442oG1e89g88kuRFJkBGAkqVkGziPrgXE3ArPuBiasGthhkYjOYRkgOs/hM078YVcT3jrQClfgKnf1SyIpXwbOZ80Dpt8JzLwbKJoqOg1RQmAZoLTnC0Xw1oFWvLCzCQdanKLjCJFWZeB8xTOAWfcAM746cP4CUZpiGaC0dbTVhRd2NeKNfa1Xv7d/kkvbMvAZUyYw8+vA/O8CudWi0xDFHcsApZ2NJzrx6Md1+LShT3SUhJH2ZeAcCR/MfhS2mpW4pjpPdBiiuOFBRZQ2PjregYc21GF/c7/oKJSgVEsuHthlh3vbTkwrzcJ3l4zFzdOKoZMl0dGIYoojA5TyPjjagYc/qsXBNF0PMBocGRiws/zbuKt22aDbyh0W/MniMbhrXgUsRp2gZESxxTJAKUnTNLx/ZKAEpOreANHEMgBoOiNWS4/huMc67P3ZVgPuXVSF7y4ZC5uJg6qUWlgGKKVomob3DrfjoQ21ON7uFh0nabAMAI1lt+H6uq9e8nF5dhP+asV4fG1+BacPKGWwDFBKUFUN7xxqw8Mf1eJkh0d0nKTDMgDcr/8ZPvJUjvrx4wrs+MmqSVgxpTCGqYjig2WAkpqqanjrYCse/qgOdZ0sAVcq3cvAEaUSa8I/u6K3XTQ2F3+3ZjKmlmZFORVR/LAMUNLa29SHv3/tMI62cU3A1Ur3MvD3+D6eCyy+4reXJOD2GSX4m1WTUJptiWIyovhgGaCk4/SF8R/rjuHFT5vBf73Rkc5loEfKxTz/g1Bx9VcKmPQyvrW4Ct9fOg6ZZp5/QMmDS2Ipqbyyuxn/8d5x9HhDoqNQingVy6NSBAAgGFHxxKbTeGV3C36wbBy+sbASBp0clfdNFEscGaCkcLLDjb977RB3DYyRdB0ZCMCERcGH0afZY/L+x+TZ8H9XTcSqqcUxef9E0cKRAUpo/pCCX26oxVNbTqf8McIUfx/J18SsCABAfbcXf/bcXiybVID/+NI0FGSaY/axiK4GRwYoYX1wtAP//OZhnOkPiI6S8tJxZECFhDXh/8IxpSQuHy/basC/3FaD22eWxuXjEV0OjgxQwmnp8+Gf3zyCD491io5CKWy/PC1uRQAA+n1h/PDF/Vh/pAM//cJUOGzGuH1sokthGaCEEVZUPLWlHr/ccBKBsCo6DqW4JyOrhXzcdw61YWd9L372pWm4kRsWUYLgNAElhIZuL77/wl6eIyBIuk0TNMtluM73c9Ex8KXZpfjn22p4GSIJx2teSLi3D7ZizUObWQQobl5QbxIdAQCwdu8ZrPzFZmyp7RIdhdIcRwZImEBYwT++fhAv72kVHSXtpdPIgEvKwDz/IwgisX4bv3tBBf5uzWRYjZy9pfjjyAAJcarTjVX/+xGLAMXdO9INCVcEAOD5nU1Y9eAW7KrvFR2F0hDLAMXdiztOY/WDm9DQx10EKb7C0OOhwCrRMUbU1OvDV3+9Hf/2zlFEFC6ipfjheBTFTSCs4IHnd+Ld430AeA48xd82eR7a1BzRMS5K1YAnt9TjSKsLj909G9lWXoJIsceRAYqL2nYnVvz8g7NFgEiMR0JrREcYtW2nenDbI5+gtsMtOgqlAZYBirnnt9VhzUNb0OJWREehNHZcnoBPI2NFx7gsTb0+fPGxbdhwrEN0FEpxLAMUM4Gwgj97Zhv+7s0TCKmcFiCxnlESd63AxXiCEXznd7vx2MY60VEohXHNAMVEc48HX3t8K0cDKCF0yfl4yTdfdIwrpmrAz9edwIl2N/7zy9NhNkTnyGWiz3BkgKJuR20bVv9iI4sAJYxXtBVIhR93b+xvxV1PbEeHi4d3UXQl//8OSijPbTyEe57eDU+E0wKUGPySBb8KLBcdI2oOtDhx2yNbcaC5X3QUSiEsAxQViqLgH5/fiH9Y14iwxn9WlDg+kBbDrVlFx4iqDlcQdz6xHa/vOyM6CqUI/tSmq+b2eHHPg2/hd4e80Lh/ACUQFTIeCt4sOkZMBCMq/uql/fjZe8egqtxVnq4OywBdldauHnzlF+9hW1fibe9KtEc3A3VKkegYMfXEptP47u/3IBjhGh26ciwDdMVO1Lfgzoc+wgmvRXQUomE9HkrNUYELfXisA3/y293wh1gI6MqwDNAV2XnoBL7x5Da0hFNrLpZSR4NciQ3hGtEx4mZrXTe++fROeIIR0VEoCbEM0GXRNA3vbdmN7zx/EF2qTXQcohE9r94kOkLcfdrQh7uf3AGnLyw6CiUZlgEaNVVV8fy7m/DjtxvgAkcEKHE5pSw8G7hWdAwhDrQ48dUnd6DHExQdhZIIywCNSiQSwRN/XI+fbuqBT+IaAUpsb0hLEUL6Lmo91ubCnU9sRyc3J6JRYhmgSwqFwnji5ffw4G4vgrJZdByiiwrDgEf8yXkOQTSd6vLiq0/uQJebIwR0aSwDdFH+QAC/evFNPLrPxyJASWGzvACdWqboGAnhdJcXX+eUAY0CywCNyO3x4rHn1uLJg0H4dHbRcYguSYOER0JrRMdIKLWdHtz91E70eUOio1ACYxmgYfU5XXjs93/E744r8OizRMchGpWj8iTsi1SKjpFwjre78Y3f7ORVBjQilgEawu3x4qkXXsPLtSqceofoOESj9htltegICetIqwv3PL0TrgALAQ3FMkCD+AMB/PaVN/HH2iB6jAWi4xCNWrtchLXBuaJjJLSDLU7c/8yn3LqYhmAZoHNCoTCeW/sOXjzYhw5jqeg4RJflZW2F6AhJYXdjH37y6iHRMSjBsAwQgIEjiF9+ez2e39WCMybOuVJy8UlWPB5YJjpG0nht3xk8+nGd6BiUQFgGCJqm4Y31G/Hs5hNoMFeLjkN02dZJS+DTeOnr5fjv9Sfw3qE20TEoQbAMpDlN07Bu4zb8Zv1e1JknAJBERyK6LAp0eCjAhYOXS9OAB14+gEMtTtFRKAGwDKS5Lbv24sl3tuGYaRI0FgFKQrvkWWhQ80XHSEr+sIJv/+5TdHDb4rTHMpDGdu0/jKfWrsch/Xio/KdASerx8M2iIyS1DlcQ3352N/whXmGQzvgMkKYOHa/FMy+/if0Yg3AaH+hCye2UPAabwpNEx0h6h8448cDL+6FpmugoJAjLQBqqa2jC0y+9joOhArikDNFxiK7Y79WVoiOkjPcOt+O/158QHYMEYRlIM82t7XjyhbU42ifhjL5YdByiK9Yn5eD3gcWiY6SURz8+hbV7W0THIAFYBtJIn9OFp/7wGk60OXHaMlF0HEpwZ1wqvrHWj9yfu2H5Nxem/cqD3a0Xn1cORjT83YYAKh90w/SvLlQ96MbT+z4/IOeDUxFMeNiDzJ+5cM9rfoSUz4elnQENEx72oLFfHVW+17AcCnRX9snRiH6y9hB2N/SKjkFxphcdgOIjEongxTfW4WhdIxodCxBW2ANpZH1+DYuf9mLpGD3eu9uKfKuE2l4VOeaLX3Fy5x/96PBo+M1tFoxzyGhzq1DPPt+rmoavr/Xjb681YmW1Hl95xY9f7wnjL+YbAQA/+TCAP5trQGX2pf9tBmHCo4Ebr/rzpKFCERV/+vs9eP37i1HusIqOQ3HCMpAm1m/ejq2f7kNX3gz0hY2i41CC+89PgijPkvHM7ZZzt43JufiT9Lq6CDY1RHD6hxlwWAZKQ9V5T+zdPg3dPg3fm2eEWS/htgl6HOsaGGnY1hzBp60KHrl5dBsHbZQXokfjepdY6fGG8P0X9mLtn18DvY6/OKQDfpfTwMFjJ/H6+x/DnVGFhnCm6DiUBN48EcHcYh3ueMWHgv9yY9YTHjy5J3SJtwljbokOP/8kiNL/dWPCwx789foA/OGBoYF8q4Riu4T1pyLwhTVsaVIwvVCHsKLhz98J4IlbLNDJl97rQoOEh4NrovJ50sgOtjjx0IZa0TEoTlgGUlxnTy9eeP09dIf0OKLy8CEandN9Kn61O4TxDhnvf8OKP59rxF+uC+DZ/SMXgtN9KrY2KTjcqeK1u6x4cJUJfzwaxvfeHdjQRpIkvHyHBT/dHETNYx7MKpJx/ywD/mNrCEur9DDrgcVPezHxEQ8e2TXyxzko1+CwUhb1z5mGenTjKexr6hMdg+KA0wQpLBgM4fm176KuuR21OQuhKNxhkEZH1YC5JTr8+/KBYftZxToc7lTx+J4w7p05/DSTqgGSBDz/JQuyzBIAHf53JfCVl/147GYzLAYJ11bo8el37Ofe5mSPgt8dDGPfn9qw5BkvfrjAiNXj9Zj6mBdLKnWYXjh0geBTEW49HC+KquGBlw/gnb+8FlYjny5SGUcGUpSmaXjrw03Ytf8Q2nNnwa3wPzKNXnGGhCn5g388TM6T0eQceaV/cYaM0gzpbBH4/G00AC2u4d/uT98O4H9uMkHVgH3tKu6oMaDAJuP6Kh02NQy9cqFVLsZboVlX9knRFanv9uLf3jkmOgbFGMtAitp98Cje/WgrnNkT0BK2iY5DSWZxuQ4negY/gZ/sUVGZNfKPjMXlOrS6NXhC2qC3kSWgLHPo2/1mbwgOi4TbJhqgnP1QYeXz18owu+H9QbvpCj4bulrP72zCxyc6RcegGGIZSEEtbR148Y334IIFx5RC0XEoCf1ooQk7WhT8+5Yg6npVvHAojF/vDeH78z6fIvjbDwP45mv+c3//+jQDcq0S7nvDj6NdCjY3RvA3HwRx/0wDLIbBU1SdXhX/uiWIh1cPTEPkWCRMzpPx4I4QtjdHsKE+gsXlg0ezPJIdT/mXxvCzpov5P388iD7vxReRUvJiGUgxPn8Az7/2Ds50dKHBMpEnEdIVmVeqw2t3WfCHw2FMfcyDn24O4sGVZtw9/fNzLNo82qBpA7tRwgf3WNEf0DD3117cvdaPWyfo8dDqoZcL/nBdAD9eZEJJxuc/gn77BQtePBLGLX/w42+uMWFe6eD1Au9KS+AHL4sVpcsdxN+uPSQ6BsWIpPFkipShaRqef+1dvP3hZkSKarDblys6EiWJBvPXRUe4qAh0WBp6EM0q/02L9t93zMBX5vBqjlTDkYEUsnXXPqzfvB05hSU44M8RHYcoanbIc1kEEsS/vHkELX0+0TEoylgGUkTTmTa88s56mIwGHNFKEdb4raXU8Vj4ZtER6Cx3MIIfv3wAqspB5VTCZ4wUEIlE8Md3P0RnTx8Uxxg0BSyXfiOiJFErV2NbeLzoGHSenfW9eGrradExKIpYBlLAJ7v3Y++hoygrK8MOV7boOERR9Vt1legINIz/Xn8SJzvcomNQlLAMJLmunj68uX4TzCYzjoQL4VN5pCuljh4pF38ILBQdg4YRiqj4l7eOiI5BUcIykMQ0TcOb6zeipb0D5vwKHPfxuFFKLa9iOVSw4CaqT+p68OHRDtExKApYBpLYviPHsfXTfSgtKsInrhzuKUApJQAzHgvcKDoGXcK/v3sMYWXkbaopObAMJCmP14fX130ERVXRpCtGX8Rw6TciSiIb5GvQr3Er7UR3utuL329vFB2DrhLLQJJ6f9M2nDjViNySSuxzZ4iOQxRVKiQ8HFwjOgaN0i831KLfx62KkxnLQBKqa2jCB5u3oyDPgZ2eXCicHqAUs1+ejuNKsegYNEpOfxgPflgrOgZdBZaBJBMKhbH2vY/g8njhtZWgNWQSHYko6n4dWS06Al2m53Y04lSXR3QMukIsA0lm88492H/0OCrLS7HHkyk6DlHUNctlWBeaLjoGXaaIquHf3zkmOgZdIZaBJNLe1YO3N2yG3WpDi+qAk4sGKQW9oN4kOgJdoQ3HO7Gltkt0DLoCLANJQlVVvL5uA9o6u1FcVIC9HrvoSERR55Iy8HTgetEx6Cr869vHoPDcgqTDMpAk9hw6hu17D6KytBjH/RnwKnrRkYii7m1pKYLgiFcyO9HhxoufNomOQZeJZSAJBIMhvPfxVmgaYLZl4ABHBSgFhaHHw4GVomNQFPzig5NwB8KiY9BlYBlIArv2H8aJUw2oKC3GYa8NAZ4/QCnoE3k+2tQc0TEoCro9ITzycZ3oGHQZWAYSnM8fwPubt8FoNEAymHCIowKUoh4JcZOhVPLbTxrQ6Q6IjkGjxDKQ4Lbt3o9TDc0oLynCEa8NYY3fMko9x+UJ2B0ZIzoGRVEwouLprQ2iY9Ao8ZklgbncHqzfvB02mxXQGXGEowKUop5RVomOQDHw/I5GuLh2ICmwDCSwLbv2oulMO8qKC3HUa0OQowKUgjrlfLwUnC86BsWAOxjBczt4iFEy4LNLgurtd+LDrTuRnZUBTdLjsJent1FqekW7EfxRlLqe3tqAQFgRHYMugf8DE9S23fvR1tGF4oJ8HPNZeQUBpSS/ZMHjgWWiY1AMdXuCeGVPi+gYdAksAwmo3+XGhk92ITsrE5os8woCSlnrpWvh1qyiY1CMPbn5NHclTHAsAwlo+54DaOvoRnFBHk77LfBzVIBSkAIZDwVvFh2D4qCp14d1h9tFx6CLYBlIMC63Bxu27kRmhh06nQ7HuVaAUtRe3QycUgpFx6A4+e22etER6CJYBhLM9r0Hcaa9EyVF+egN69EZNoqORBQTj4c4KpBOPm3ow+EzTtExaAQsAwnE4/Vhw9adsNtt0Ot0OO7jXCqlpga5EhvCNaJjUJw9/QlHBxIVy0AC+fTAETS3tqO0MB8RDTjFMkAp6jn1JtERSIC3D7Shyx0UHYOGwTKQIBRFwZZde2E2maDX61Hvt3CTIUpJTikLvw1cJzoGCRBSVLywk8cbJyI+2ySIk6cbcbqpBYUFuQDAKQJKWW9IyxCBXnQMEuS5nY0IRVTRMegCLAMJYs/BYwiGQrBbregL69ERMomORBR1IRjxiH+l6BgkUJc7iA+PdYiOQRdgGUgAfU4Xdh04hLycgbPcT3BUgFLUFnk+OrVM0TFIsDf3t4qOQBdgGUgAB46eRGdPH/Ic2VA0oJZlgFKQBgmPhNaIjkEJ4OMTnfAEI6Jj0HlYBgRTFAWffLofZqMROp2OCwcpZR2RJ2FfpFJ0DEoAwYiK9Ue4I2Ei4bOOYHUNzahrbEJRQR4ALhyk1PUbZbXoCJRA3jrAqYJEwjIg2O6DRxAIBGG3WdEf0aGdCwcpBbXLRXgtOFd0DEogW+u60ecNiY5BZ7EMCOR0e7Br/2Hk5mQDAE7wHAJKUS9pN4qOQAkmrGh4j4cXJQyWAYH2HzmOzu5e5OfmQNOAOr9FdCSiqPNKVjwRWCo6BiUgThUkDpYBQVRVxbbdB2A8u3CwK2zgUcWUkt6XlsCnmUXHoAS0s74Hna6A6BgElgFh6hqaUVvfhOKzCwebAvxhSalHgQ6/DPB0QhqeqgFvH2wTHYPAMiDM7oNH4PMHYLcNXD3QHOTCQUo9u+RZaFTzRMegBPbWQU4VJAKWAQFc5xYOZgEAvIqMnrBRcCqi6Hs8zFEBurh9Tf1o7vWJjpH2WAYEOFnfhK6ePuTnDmw/3MwpAkpBp+Qx2BSeJDoGJQFOFYjHMiDAiVP1UDUNev3AyW1NnCKgFPQ7dZXoCJQk3uRVBcKxDMRZOBzBwaO1yMqwAwAUDWhlGaAU0yvl4LnANaJjUJI41ubCqS6P6BhpjWUgzhpaWtHZ0wtH9sB6gdagCRGeRUAp5nUshwJeKkujt7W2W3SEtMZnoTirrW9CIBiExTwwGsCrCCjVBGHCI4GbRMegJLOrvld0hLTGMhBHmqZh/5HjMJtMkCQJABcPUurZKC9Cr2YXHYOSzE6WAaFYBuKos6cXTa3tcJy9pLAvrIdb0QtORRQ9GiQ8FFwjOgYloW5PEHWdXDcgCstAHNXVN8Hp9pxbPMhdBynVHJRrcEQpFR2DkhSnCsRhGYijo7WnIUsSZHngy871ApRqnoqsFh2BktjO+h7REdIWy0Cc+PwBHDl5CjnZmQCAoCqhI8RdByl1nJFL8FZolugYlMQ4MiAOy0CcnGpsRndvPxxZA+sFOkJGaJAEpyKKnhdVXkFAV6fNGUBTD7cmFoFlIE5q65ugKAqMRgMAoDtsEJyIKHo8kh1PBW4QHYNSwA5OFQjBMhAHqqpi3+Hj504oBIBuThFQCnlHuh5+8N80Xb2dpzlVIALLQBy0tHWgrbPr3K6DAEcGKHVEoMPDAS4cpOjgIkIxWAbioK6hGV6f/9zIgE+R4VO5VSulhh3yXLSoDtExKEW09PnR2u8XHSPtsAzEQdOZdsiyfG7XwR6OClAKeTTETYYoujg6EH8sAzGmaRpONTbBZrWcu41TBJQqTsrjsD0yTnQMSjFcNxB/LAMx1u9yo7vPOXjxIMsApYhn1ZWiI1AK2tXAMhBvLAMx1tbZDY/XN6gMcJqAUkG3lIc/BBaKjkEpqKHbi1BEFR0jrbAMxFh7ZzciEQVGw0ABCCgyPDyciFLAq1gOFVwIS9GnakBjj1d0jLTCMhBjZ9o7IZ230SCnCCgVBGDGrwIrRMegFHa6m2UgnlgGYkjTNNTWN8HG9QKUYjbI16Bfs4mOQSnsdBfLQDyxDMSQ0+1Bd18/7FaWAUodKiQ8HOTlhBRb9d0e0RHSCstADLV3dsPj9cJu+/yyQi4epGS3T56O40qx6BiU4uo5TRBXLAMx1NbZjXBYgck4sGd7QJXg5uJBSnJPRrj1MMUepwnii2UghgYWD36+erCfowKU5JrlMqwLTRcdg9JAjzcEpz8sOkbaYBmIkYGdB5thtZrP3eZReBkWJbfnuckQxRGnCuKHZSBGXB4vOrt7By0eZBmgZOaSMvFMYInoGJRGTndxEWG8sAzESPvZnQcz7CwDlBrelm5AEJzqovjhyED8sAzESHtXN0KRyLmdBwGWAUpeYejxcIBTBBRf3HgoflgGYqTP6QY0bdACQpYBSlafyPPRpuaIjkFphlcUxA/LQIx09/ZBpxv85O9lGaAk9UiImwxR/DX2eKFpmugYaYFlIEY6u3thMhnP/T2oSghr/HJT8jkmT8TuyBjRMSgN+UIK2l0B0THSAp+dYkBVVfT0O2E2fl4GfBwVoCT1jLJKdARKY+1OloF4YBmIAbfXB78/MGhkwK/yS03Jp1POx8vBeaJjUBrr58ZDccFnqBhwutwIhkIsA5T0XtZuBH9MkEj9vpDoCGmB/8tjwOn2IBgMDZom8HOagJKMT7LgicAy0TEozfX7ODIQDywDMeD2eKFq2qCrCTgyQMnmA+lauDXrpR9IFEN9LANxwWeoGPD4/ENuC7AMUBJRIOOh4M2iYxDByWmCuOAzVAz4fH5ceGUspwkomezRzcQppVB0DCKODMQJy0AMON0eyOftPAhwZICSyxMhjgpQYuDVBPHBZ6gY6HO6Bp1JAACqoCxEl6tBrsSG8BTRMYgAAL5gRHSEtMAyEAP9LjcMBv2g27ihJiWL36s8kIgShz+siI6QFlgGokxVVbg8XhguGBnQNGmEtyBKHP1SNp4NXCs6BtE5/hDLQDywDESZzx9AKBSGQc+RAUo+b0hLEYH+0g8kihMfy0BcsAxEWSAYQkRRoNcPvnqAawYo0YVgxKN+ThFQYuE0QXywDESZpmnQNA3SBVcTcJqAEt1meQE6tUzRMYgG4TRBfLAMRJmqqcBwZUBQHqLR0CDhYV5OSAkopKiIKBxbjTWWgSjTtIGXC8cBWAYokR2RJ+FApFJ0DKJhRVT+BI01loEoU1UVGjhNQMnlN8pq0RGIRmTS86kq1vgVjrKBNQPD3B7/KESj9lpwrugIRMMy6uUhv1xR9LEMRJmmacAwIwOc8SIiunxmjgrEBb/KUXZuZOCCIsuRASKiy2c28JC3eGAZiLJzlxaCawaIiK4Wy0B8sAxEmXp21euFU1wcGSAiunxmA5+m4oFf5SgbcdMhQXmIiJKZSc+RgXhgGYgyVRu4tPDCRQN6iXWAiOhycWQgPvhVjrLPFhBeOE1glnk9ARHR5eKagfhgGYgyVR3YgvDCBYQsA0REl4/TBPHBMhBlmqYNuwMhywAR0eXjNEF88KscZdpw2w+CZYCI6EpwmiA+WAaizGI2Qa/TIxyJDLqdZYCI6PJxZCA++FWOMovFDINBjwjLABHRVTNzzUBcsAxEmdVshkHPkQEiomiwGFkG4oFlIMqsFpYBIqJoKcw0i46QFlgGokyWZdjtVoTDF5QBnSIoERFR8ip3WEVHSAssAzGQZbcPGRmwcGSAiOiyleVYREdICywDMZCVaR8yMmBiGSAiuiySxDIQLywDMZCVkQFFGTwtoJcAg8RCQEQ0Wvl2E3cgjBOWgRiwWodf8MLRASKi0eN6gfhhGYgBq9k89KQicN0AEdHlKOcUQdywDMSA1WIGhtmW2MorCoiIRq0shyMD8cIyEANWixmSJEFVB48E5OgjI7wFERFdqNzBkYF4YRmIgZE2HsoxhAUlIiJKPuUcGYgbloEYsJgHzie48PJCB0cGiIhGjdME8cMyEANWixn6YUYGsvQRyBj+iGMiIvqcTpZQks2tiOOFZSAGMu02WC1m+APBQbfLEpDN0QEioksqyjRDr+NTVLzwKx0DOp0OFSVF8Pn8Q+7jugEiokvjzoPxxTIQIxUlRQiFhz7x84oCIqJL44ZD8cUyECP5uQ4AgHbBfgMOjgwQEV3SpKIM0RHSCstAjBTkOWDQ64eMDnBkgIjo0mZV5IiOkFZYBmIkPzcHVqsF3gvWDdh1Cg8sIiK6CKNOxtTSTNEx0grLQIxkZ2YgOzMDPn9g0O2SxNEBIqKLqSnN5GmFccYyECOSJKGytHjIyADAKwqIiC5mVjmnCOKNZSCGSosLoChDDyfiyAAR0chmV2aLjpB2WAZiqCDXAQ28ooCI6HLM5uLBuGMZiKGCXAfMJuOQnQgHygC3JSYiulBRphkl2dxwKN5YBmIoPzcHNosFPv/gdQNmWeNUARHRMGZVZIuOkJZYBmLIZrUgNycL3guuKACAElNwmLcgIkpvnCIQg2UghiRJQlVZKfzDlIFiY0hAIiKixMbFg2KwDMRYcWEeVGXoJkPFpiAkrhsgIjrHqJNRU5IlOkZaYhmIseKCfMg6GeHI4DUCJlmDg+sGiIjOmVySCbOBmw2JwDIQY5VlxcjKsMPp8gy5r5jrBoiIzpnNxYPCsAzEWHZmBspLiuB0uYfcxzJARPQ5Hk4kDstAHNRMrEYgOPSJv9gYgsx1A0REkCXgmupc0THSFstAHFSWFkOn0w05ztgoayjiVQVERJhRno08u0l0jLTFMhAHlWUlyM7MgNM9dN1AmXnoZYdEROlmxeRC0RHSGstAHGRl2FFZVgync+i6gXKuGyAiwo1TWAZEYhmIkynjqxEMDZ0SyDFEYNfxEkMiSl8VDismFGaIjpHWWAbiZGxFKYwGw7ALCcs4OkBEaWz55ALREdIey0CcjKkoRa4jG739riH3caqAiNLZjVwvIBzLQJyYTSZMnVA97H4DJaYg9NLQLYuJiFJdlsWAeWMcomOkPZaBOJo0bgxUTYOqDn7iN8gaqnhVARGloZU1hTDo+FQkGr8DcVRdVT6wNfEwlxiOt/oEJCIiEmvN9BLREQgsA3FVkOtARUkR+oZZN1BiDMEmKwJSERGJ4bAZsZi7DiYEloE4kiQJ06dMgD8QgKZpF9wHjOPoABGlkZU1hdBziiAh8LsQZxPHVsFiNsPr8w+5j1MFRJRO1kzjFEGiYBmIs+rKMoypKEVHd8+Q+7L1CvINPKuAiFJfnt2IRZwiSBgsA3EmyzIWzp4Ovz845KoCgKMDRJQeVk0tgk6WRMegs1gGBJg+eTxysjLQ5xy6kLDa4oeOxxoTUYq7e0Gl6Ah0HpYBAQrzcjF14jh0dvcOuc8ka6jgngNElMLmVzkwuThTdAw6D8uAIPNm1AAAwuGhhxRxqoCIUtm911SJjkAXYBkQpGbiOBTkOdDVM3R0oMwUhJl7DhBRCirOMmNlDc8iSDQsA4LYrBYsmDl12HUDsgSMswy99JCIKNndvaCCewskIH5HBJoxZSJMRiO8fu45QESpz6iX8bX5FaJj0DBYBgQaP6YCFWXF6OwaOlWQa4ggl3sOEFEKuWVaMXLtJtExaBgsAwLp9Xosmj0dHp9vyPbEADDV5hWQiogoNrhwMHGxDAg2bdJ4ZGdmoN/lHnJftcWPDN3Qqw2IiJLNzPJszCjPFh2DRsAyIFhpUQEmVY8Zds8BWQKm24ced0xElGy+xVGBhMYyIJgkSZg/swaKqiCiDL2ccILVBysvMySiJJZnN+HmacWiY9BFsAwkgGmTxqMg14GOrqGHF+kkYBpHB4goiX19fjmMej7dJDJ+dxJAZoYd1y+ci75+57CHF02y+rgJERElJYNOwt0LeQ5BomMZSBCL581EniMHncPsSGiQNdTwygIiSkIra4pQmGkWHYMugWUgQRTkOnDd/Fno6ukb9jLDKTYvDNLQUQMiokQlS8APlo0XHYNGgWUggVy3YA4c2Vno6u0bcp9J1jCFowNElES+OKsME4syRMegUWAZSCAlhfm4Zs4MdHb1jLgJkY6jA0SUBIx6GQ/cNEF0DBolloEEc/3COcjKsKO3f+gBRhadikk8s4CIksA3F1aiNNsiOgaNEstAgikvKcL8mdPQ3tk17OjAdLsHMobeTkSUKDLMevzFsnGiY9BlYBlIMJIk4fpFc2CzWuF0Dd1fwKZTMY6jA0SUwP7s+mpkW42iY9BlYBlIQNWV5Zg9bTJaO7uGvX8GRweIKEEVZppw/+IxomPQZWIZSECSJGHporkwG41weYZeQZClV7jvABElpB8unwCLUSc6Bl0mloEENWncGEyfPB5n2jqGvX9WhptnFhBRQhmbb8Nd88pFx6ArwDKQoCRJwrLF86HX6eDxDV0jYJQ1zM8cesUBEZEo/2flROhkSXQMugIsAwmsZkI1aiaOw5nW4UcHxln9KDIG45yKiGiomeXZWDWVJxMmK5aBBKbT6bD82gWQdTLcw6wdAIBrspyQuJiQiAT729WTREegq8AykOBm1UzEvBlT0Ximbdh9BxyGCBcTEpFQSyfmY8HYXNEx6CqwDCQ4WZZx+003wJGViY6unmEfMzvDDQsXExKRAAadhJ+sniw6Bl0lloEkUF5ShJuuX4Tu3n6EI5Eh93MxIRGJ8r0bxvEwohTAMpAkVly7EOOqytHY0jbs/eOtfhRyMSERxdHk4kxuO5wiWAaShN1mxW03Xg9FUeDxDr8dMRcTElG86GQJ//WV6TDo+DSSCvhdTCJzZ9Rg3owaNLa0DruYMNcQwWQuJiSiOPjeDdWYWpolOgZFCctAEpFlGV9YuRTZmRno6B5+MeHcDDfMXExIRDE0Lt+KHywbLzoGRRHLQJKpKC3GjUsWobunDxEuJiSiONNJwC/umg2jnk8fqYTfzSR043ULMbaybMTFhBOsfpSbAnFORUTp4LtLxmJaGacHUo2kDTf5TAlvx96DePTZl1BaVAC7zTrkfp8iY21XPgIqTw8TTQ360L/lOfhqt0P1OWEsGIucFd+FqXgCAKB/6/PwHtsCxd0FSdbDWDQO2Uu+CVPJxFG9f+eOV9C/6VlkzLkNjhXfPXd774Yn4T28AZLBjOzr74W9Zum5+7zHt8J7eAMKvvJP0f1kKaWNzbXgvR9dD5OeP1dSDUcGktS8GTWYO33KiIsJrToVS7L74x+MhuhZ9zACDfuRd8uPUXz/IzCPmYWOF/8eEXc3AMDgKIXjxj9D8f2PovDun0OfVYiOl/4Bis95yfcdbDsJ9/51MORXDbrdV7cT3mObUHDnT5Fzw33oXffwufenBr3o3/w7OG7686h/rpS6ZAn436/OZhFIUSwDSUqn0+H2mwYWE3Z29w77mApzEJOsvLpAJDUchO/EJ8heeh/M5VNhyClB9rV3w5BTDPe+9wAAtik3wFI1E4bsIhjzK5Gz7NvQQj6EOusv/r5DfnS/9d/IXfUDyGb7oPvCPc0wl0+DqXg8bFOuh2S0IuIcOPCq7+NnkDHrZugzC2LzSVNK+vZ1YzCzPFt0DIoRloEkVlVeghXXLURXTx9CofCwj1mY6UKWfvj7KA5UBdBUSDrDoJslvQnBliNDHq4pYbj3r4NkssFYMOai77r3g1/BUj0PlqqZQ+4z5o9BqL0OSsCDYHsdtEgQ+pwSBFqOINRxChlzbr2qT4vSS5XDgh/fNLppK0pOetEB6OqsumExjtaexvG6ekwaNwaSNPgscb2sYWl2P97szoMKnjMeb7LJClPJJDi3vQhDbjl0tmx4j21GsPU49DmfH/fqq9uF7jd/Di0chM6eg8K7fgqddeRFWt6jmxBqP4Xie38x7P2WsXNgq7kB7c/+CJLeiLw1P4JsMKH3/ceQu+ZHcO97F+69b0NnyYRj5V/AmF8Z9c+dUoME4H+/OovTAymOCwhTQF1DE/7nid9BkmWUFOYP+5iDHht2ubgCWIRwXxt63vslgs2HAUmGsagahpxSBNvrUPqdxwEAaigAxdsL1eeC+8D7CDQdRPE9/wOdLXvI+4u4utD27I9QeNdPz40etL/wExgLxg5aQHih/q0vQA16YZ+2Ah0v/wNK7n8U/rpdcO99G8Xf+mVMPndKft+/oRp/s4rHE6c6loEU8d5HW/H7tW+jsrwENotlyP2aBnzQ60BT0CwgHQEDT/hqyAe93YGuN/4TWsiPgjv+edjHnvn1d2CfdiOyFt055D7fye3oeu3fAOm8WT5NBSABkoSKv34Nkjz4t7hwTzM6X/3/UPyth+A5+AGCLUeR/4WfQA0F0PyLr6D8r16GbBp6VQqlt/mVWXjxTxdDljmqmOo4TZAiVly3ECdON2DH3kOYMmEsZHnwchBJApbk9OH1rnx4FH7bRZCNZshGM5SAB/76vci54b6RH6xp0JTh13qYK2eg+P5HBt3W8+4vYcgtQ+aCLw8pApqmoef9R5Gz7NuQjRZAU6GpZzes+uy1pl7x50WpKdeiw+PfnM8ikCb4rJAiDAY97rptFZpb29HY0ooxFWVDHmOWNSzL6cPbXD8QV/7TewAAekcpIn1t6Nv4NAyOMtinrYAaCsC5/SVYxy2Azu6A4nfBvfdtRNw9sE689tz76Hjx/8EyfhEy59wK2WSF8YJLCSWDCbI5Y8jtAOA58D50lkxYxy0AAJhKJ6N/6wsInjkO/+k9MORWDLkagdKbTtLw5L3z4LAZRUehOGEZSCHFBXn4ypob8fhzr6DP6UJOVuaQxxQYw5iX6cJOrh+IGzXoQ//mZxFxd0NnzoB14jXIXvJNSDo9oKkI97ag6/UNUPwu6CyZMBaNR9Hd/zloUV+4rx0m/+VvM614++Dc/jKKvvFf524zlUxE5vwvovOP/wLZmoW8NT+KyudJqePHy8didlWu6BgUR1wzkGJUVcVza9/Bux9twYSxVTAaDcM+7oPeHDQGhq4tIKL0dl2FBb//3jLRMSjOuM9AipFlGV9avRxTJ41HXUPTsLsTAsCS7H7uP0BEg5TYgF9/e4noGCQAy0AKstusuOdLa5DnyEbjmeEPMzLJGlY5emHhccdEhIEtzF/402thMXL2OB2xDKSoyrIS3HnLSoRCYfQ5h59rztArWOnohUHiSnKidKaDiofumoaqAq4lSlcsAyls8byZuPG6hTjT1oFgKDTsY/KMYSzL6YMELh0hSld/eW0xVkyvEh2DBGIZSGGSJOFLq5dj+uQJqKtvhqoOPwJQbg5icdalT8gjotSzcowJP7xlrugYJBjLQIqzWS2458u3oLQoH3X1Iy8onGTzYZbdHed0RCTS+AwFj9x/vegYlABYBtJAeUkR7rvrC8iw29DQ0jri4+ZkujHe4otjMiISpcAYwvPfuwEGw/CXH1N6YRlIEzUTqnHPl28BNKCto2vEx12X3Y9SUyCOyYgo3rLlIH7/7UUoyBm6MRmlJ5aBNLJg1jTcccuNcHm86Okbfo2ALAHLc/rg4B4ERCnJDj8e/9pUTKwoEh2FEgjLQBqRJAk3LVmEW1csQXtXN9we77CPM8oaVub2wKaLxDkhEcWSRfXjP1ZXYuG0CaKjUIJhGUgzsizji6uWY9k189DY0gp/IDjs42w6FascvTByDwKilGBS/fibRVlYs4RXDtBQLANpyGDQ4+4vrsH8WdNQ19CEcHj4EYAcQwQ3Onqh4x4EREnNqAbwnSkS7rllKSSJJ5bSUCwDacpqMeNbd9yGmgnVOHG6AYoy/AhAsSmEGx290HOEgCgpGdQg7pug4i++dgsMBm41TMNjGUhjjuws/MlXv4iqshLU1jeOuAdBmTnIKQOiJKRXQ/hGdQQ/vPtWmE0m0XEogbEMpLnSogLcf9cXkJuThdONLSMWgiJTCDfn9sDMg42IkoJeDeOrVQH89T23wmoxi45DCY5lgDBhbCW++ZXbYDTocaa9c8TH5RnDWJPbAysLAVFC02kRfLnci//7zdtgs1pEx6EkwDJAAIA50ybjq7evRiAYROtFNiXKMURwS143MnjZIVFCkrUIbi924/9963Zk2G2i41CSYBmgc25YNBdf/8LNCASCaG5tH/FxmXoFt+R1I5sbExElFJ0Wxi0FTvzDfbchK8MuOg4lEUkbaZKY0pKmadiyay+ee/UdKJqKqrKSES9FCigy3ut1oCdsjHNKIrqQSfXj1iIX/va+LyM3J0t0HEoyLAM0rB17D+LZV95EIBTC2IqyEQtBSJXwfq8DHSGuVCYSxR5x4tZiD370ra+gINchOg4lIZYBGtHew8fwzEtvoN/txoQxlSMWgogq4cO+HLQEuWKZKN4c4U6sLvLjB9+6C0X5uaLjUJJiGaCLOnyiDr958TV09fRhwthKyPLwy0wUDfi4LwcNAa5cJoqX0lATbihS8L1v3onSogLRcSiJsQzQJZ083Yin/rAWZ9o7MWFsFXS64QuBqgHbnFk47uMKZqJYkqChyn8S15aZ8N27v4zyEp5ASFeHZYBGpaG5Fb9+/o+obz6DidVV0OtH3tb0uNeK7c4sKOAe6ETRZoCCau9hLK8pwbfuuB35uTmiI1EKYBmgUWtp68Cvn/8jTp5uxMTqMRfd57wrZMCGvhx4FO6FThQtFoQwwXsIaxbW4O4v3swNhShqWAbosnR09+DXz7+KwyfqMGFsJUzGkS8rDCgyPurLQSuvNCC6alnwYnLgGL68YhG+sHIZDx2iqGIZoMvW0+fEU394FfsOHcfYqvKL7nuuasAedwYOeDLimJAoteSpvZgpNeBrt96EZYvn8xhiijqWAboiTrcHz7z0OnbsO4Tigjzk5mRf9PENfjM29WcjrHHTS6LRkqChNNSMORke3HvHLZg9dbLoSJSiWAboigWDIbyx/mO8+9FW6PV6VJYVX/Q3lv6IDh/2OtAfMcQxJVFyssoRVLmPYHZ5Ju6/6wsYW1kmOhKlMJYBuiqapmH7ngN48c116O51YvyYiovOZYZVCZv7s1HP/QiIRlRucKOw5wDmTR2Pb915OwrzuJkQxRbLAEVFfdMZ/O7Vt3Cs9jSqyktht1kv+viDHhs+dWVC4+WHROcYJBXTDe0w9tTh+oVzcPcX1/DkQYoLlgGKGqfbgz+8/i627NqHnOxMFOXnXfTxrUEjPurLQUDVxSkhUeLKN4QwOVIHzdePNcuuxZdWr4DRyCk1ig+WAYqqSCSCdRs/wRvrNyIciWBsRdmIWxgDgE+R8YkzC42cNqA0JUHDNIsT9u7DyMqw40url2P54vkX/X9DFG0sAxQT+44cx/Nr38WZ9g6MG1Nx0f0IAOCUz4JtrkwEOUpAacSui2C2vgWhrkbUTByHr92+CuOqKkTHojTEMkAxc6a9E8+tfRv7Dh9HWXERsrMuvtcARwkonYw1+1DqPgq9pmDFdQtw+01LL7nWhihWWAYoprw+P15990N8sHk7bDYrSosKLrlhSp3Pgu3OLAS5JwGlIIOkYo6lE1r7CVSWFuOOW27C3OlTuJEQCcUyQDGnqio2bt+NV975AC63B2Mryy45beBTZGx3ZvESREoppaYAxoVOI+LpxaI5M3DnrTehINchOhYRywDFT219E155ez0OHa9FniMHBXmOS/421Bww4RNnFg88oqRm10Uwx9qLcNtJZGdl4IurlmHporkXPf2TKJ5YBiiu/IEA3t+0Des+/gRur29UowQRVcJejx2HPHbuS0BJRYaGaXYPKiIt6OrswtRJA4sEqyvLRUcjGoRlgIQ4eboRL7+9HoeP1yE/d3SjBL1hPbb2Z6MzfPHyQJQISk0BLLD3o7etAbIk46YlC3HrjTfw2GFKSCwDJIw/EMC6jduwbuMn8Hh9GFNRCrPp4scdaxpw0mfFXncGvLwMkRJQhi6C+ZkuOCLdaDrThjHlpbjjlpswe+okLhKkhMUyQMKdPN2IV9/9EAeP1yIrwz6qKw4UDTjqteGAx84dDCkhGCUVMzPcGG/oR/OZVsiShEVzZ+BLq5YjPzdHdDyii2IZoIQQDIawaecevP3hJnR296GirBiZo9iTPaxKOOy14ZDHjhAvRSQBJGiYZPVhdoYLfV0d6HO6MLG6CrfddANm1XA0gJIDywAllNaOLrz+/sfYsfcgZFlGVVnxqFZcB1QJBz12HPXaEGEpoDgpNwWwINMFOdCPpjPtyM/NxqobFmPpNfNhtZhFxyMaNZYBSjiqqmL3gSN4/f2PcaqpBQW5jlEtMAQG9ifY787AcZ8VKq88oJjQUG4KYobdgxzJg8aWNkgAFs2ZjltWXI+y4kLRAYkuG8sAJSyn24P1m7bh4+270dvXj8KCPOTlZI+qFLgjOux1Z6DOb+HliBQVEjRUW/yYbvcgSw6hpb0DHq8PE6urcMvyJZg9dRIPF6KkxTJACa+1owsfbd2FrZ/uRb/Lg5KifORkZY6qFPSF9djjzkBDwAywFNAV0EsqJlp9mGbzwqaLoLO7F109vSgtKsTqpYtx7fxZl7wKhijRsQxQ0mhsacWHW3Zix76D8Pr8KC0qQFbmxQ8/+kx3yIADHjsaA2ZOH9ComGUFU2xeTLF5YZY19LvcaGntQE5WBpYtno/l1y6AIztLdEyiqGAZoKSiaRpONTbj/U3bsefgUQSCQVSUFo/6tDefIuOEz4rjPiu83OKYhmHXRTDN7sFEix86SYXL7UFrRxdMRiMWzJqKm5ddh/KSItExiaKKZYCSkqZpOFZXj/c3bsP+oyegRCIoLyuGzTK63d1UDWgOmHHMZ0VL0AROIZBDH8Z0uwdjLX5I0NDT50RHVzdsVgumT56AZYvno2ZCNS8VpJTEMkBJTVVVHDxWi/c3fYLDJ05BkiRUlBZd1hyuK6LDMa8NJ/0WBLmBUVqRoKHUFESNzYtycxCqqqKzpxddPX3IycrE/Bk1uG7BHIyrKmcJoJTGMkApIRKJYO/h43h/0zacOFUPvU6PkqKCy7rWO6IB9X4LjnltPP8gxeUbQqi2+FFt8cOiUxFRFLR3dqPP6UK+IwfXzZ+FxfNm8TJBShssA5RSQqEwdh88gvVbduB0YwvC4QgK8h3Izc66rMu+esJ6HPPaUOe3cBOjFJGpi6Da4sc4qw9ZegXAwL+XMx2d8Pn8KCkswA2L5mLh7OncPpjSDssApaRIJIJjdfXYsfcg9h4+jr5+J+x2G4oL8i55ZPL5QqqE034LGgNmtAZNULi2IKmYZQVjLX6Ms/hRYAyfu90fCKClrRORSASVZcVYds18zJ85FZkZdoFpicRhGaCU197Vg72HjmHrrr1obm2HBqAwPxfZmRmXNQ8cViW0BE1oCpjRFDRxfUGC0ksqKs0BVFv8KDMFIZ/9FmuaBpfbg7bObkiShPFjKrB88XzMnjYZFjO3Dqb0xjJAaSMYDOHQiTps270fh0/UweX2IDsrE4X5uTCM4vyD86ka0BEyojFgRlPADBcvUxRKBw3FpiCqLX5UmQMwyJ//WPP6/ejs7oXX60eG3YqJ1WOw9Jp5mD5pPAwGft+IAJYBSkOapqGlrQOfHjiCbbv3o7WzC3qdHkUFeciwWa9o1XhfWH+uGHSGDeClirElQUO+IYwSUxAlpiAKjCHoz/uSB0MhdPX0welyw2QyoqKkGAtmTcO0SeNQXlLEKwOILsAyQGnN6/PjwNET2LprH06cboDXF0BWph25OdlXfOqcT5HRFDCjMWBGW8jIBYhRIEGDwxBGiTGEElMQRcbQoN/+ASCiKOjp7UdPXz90soziwnzMm1GD6ZMnoLqybFSnXxKlK5YBIgzsV3C6qQV7Dx3DnkPH0NHdg2AwBKvFDEdONjLttiv6bVLVgN6wAR1hAzpDRnSEjPBwSmFUsvVnf/M3hlBsCsIkD/1Rpaoq+pwudPf0QVFV5DmyMXvqFMysmYhJ46p4ZgDRKLEMEF0gHI6gvvkMTpxuwN5Dx9HS1g63xwej0YDcnCxkZ2ZCp7vy3/Z9ioyOkBGdISO6wwb0hA0IpfnogV5SkaOPINcQRvHZJ3+rTh32sZqmweXxoqu7F8FQCNmZGZgyoRpzp09BzYRqXhFAdAVYBoguQlVVtHZ04cSpBhw8Vova+kb0u9yQJAk52ZlwZGfBaDBc9cdxRXToCRvOlYOesAH+FLxaQYKGDJ2CHEMYDn0EDkMYDkMYmToFIw28aJoGr8+PfpcbLrcHmqYhw2bDmIpSLJg1DTUTq1GYlxvfT4QoxbAMEF2G7t5+1NY34sjJUzh8og7dvf1QVAWZdjscOVmwms1RW5wWUCV4FR08im7Y115FBy1BFypaZQWZ+giy9BFk6hRknf1zhj4yaKHfcDRNgy8QgNPphtPtgaqqsFosyHNko2ZCNaory1BZVoLSogIuBCSKEpYBoivk9flRW9+EE6fqse/ICXR298IfDEKCBLvNiswMGzJsVuh0sfkNX9UAvyrDM0xR8Ck6KJoEBYCqSVDP//O515d+ItVJKkySBpOsfv4iaTCe/3f588cYZRVWWR2yuO9iNE1DIBiC0zXw5B+JRGAxm+HIzsKU8WMwbkwFqspKUFKYz0WARDHCMkAUBeFwBM2t7Whp70BjSxuOn6pHd28/PF4fVFWF2WSC3WaF3WaF1RK90YOrpWgYXBTOlgX92Sd3XQxiqqoKnz8Ar88Pp9uDcDgCk9GAnKwMTKwegwljK1FVVoKy4kIYjVc/BUNEl8YyQBQDqqqiq7cPLW2dONPeiZOnG9Dc2g6P1wdfIAgJgNFggM1mhd1qgc1quayzE5KBpmkIhkLw+vzw+vzw+QNQFRWSBFgsA5/zuMoyTBw3BlVlJZd92iQRRQ/LAFGcBIJBdHT1oL2rB22d3WhoPoOmM21we33w+vznHifJMkxGA0xGI0xGI8ymgdd6vS5hRhQ+o2kawpEI/IEg/IEA/IEgAoEgNE2DBsBkNMBmscCRnYUx5SUoKSpAfq4DhXkO5DtyYDLxdEiiRMAyQCRQOBxBR3cPOnt64XJ74XR70NfvQmdPL7p7++DzBxAMhRAMhRCJDJy0p2mAwaD/vDCYjNDpdJAlCdJ5L7J89rUkQZLkc38fjqZpUFUV4YiCSCSCiHL2dURB+NzfB25TVQ2yLEE7G0av18NiNsFqMSM/14GyogLkOXKQm5OF3JwsFOQ6kHGF+zQQUXywDBAlqM8uqXO6PXB7vHC5PXCefd3V24eunj709TvhD4agKgpUTTv7pH72taZB09Rzf//sBZI07NJBWZah1+mg1+th0A+81ut0sFktsNutyLBakWG3wW6zwmwywWIeeMnOzIAjJws5mZnc658oSbEMECUxRVHg9voQCoehKCoURYGqqgN/VpWzrwduP//P6me3qSokSDCbP39y/+yJ3mwywWwyptxaBiIaimWAiIgozbHyExERpTmWAaIYePTRR1FVVQWz2YwFCxZg165doiMREY2IZYAoyl566SU88MAD+Kd/+ifs3bsXM2bMwMqVK9HZ2Sk6GhHRsLhmgCjKFixYgHnz5uGRRx4BMLABUXl5OX7wgx/gJz/5ieB0RERDcWSAKIpCoRD27NmDFStWnLtNlmWsWLEC27dvF5iMiGhkLANEUdTd3Q1FUVBYWDjo9sLCQrS3twtKRUR0cSwDREREaY5lgCiK8vLyoNPp0NHRMej2jo4OFBUVCUpFRHRxLANEUWQ0GjFnzhxs2LDh3G2qqmLDhg1YtGiRwGRERCPjRuJEUfbAAw/g3nvvxdy5czF//nw8+OCD8Hq9uO+++0RHIyIaFssAUZTddddd6Orqwj/+4z+ivb0dM2fOxLp164YsKiQiShTcZ4CIiCjNcc0AERFRmmMZICIiSnMsA0RERGmOZYCIiCjNsQwQERGlOZYBIiKiNMcyQERElOZYBoiIiNIcywAREVGaYxkgIiJKcywDREREae7/B/6Vvdek679dAAAAAElFTkSuQmCC",
+ "text/plain": [
+ "
"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "groups = df_full['class'].value_counts()\n",
+ "sizes = [groups[0], groups[1]]\n",
+ "labels = [str(e) for e in groups.index]\n",
+ "\n",
+ "fig1, ax1 = plt.subplots()\n",
+ "ax1.pie(sizes, labels=labels, autopct='%1.1f%%', shadow=True, startangle=90)\n",
+ "ax1.axis('equal')\n",
+ "\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Helper function for calculating metrics"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import math\n",
+ "from sklearn import metrics\n",
+ "import numpy as np\n",
+ "from rulekit.classification import RuleClassifier\n",
+ "\n",
+ "\n",
+ "X: pd.DataFrame = df_full.drop(['class'], axis=1)\n",
+ "y: pd.Series = df_full['class']\n",
+ "\n",
+ "\n",
+ "def get_prediction_metrics(\n",
+ " measure: str,\n",
+ " y_pred: np.ndarray,\n",
+ " y_true: pd.Series,\n",
+ " classification_metrics: dict\n",
+ ") -> tuple[pd.DataFrame, np.ndarray]:\n",
+ " confusion_matrix: np.ndarray = metrics.confusion_matrix(y_true, y_pred)\n",
+ " tn, fp, fn, tp = confusion_matrix.ravel()\n",
+ " sensitivity: float = tp / (tp + fn)\n",
+ " specificity: float = tn / (tn + fp)\n",
+ " npv: float = tn / (tn + fn)\n",
+ " ppv: float = tp / (tp + fp)\n",
+ "\n",
+ " dictionary = {\n",
+ " 'Measure': measure,\n",
+ " 'Accuracy': metrics.accuracy_score(y_true, y_pred),\n",
+ " 'MAE': metrics.mean_absolute_error(y_true, y_pred),\n",
+ " 'Kappa': metrics.cohen_kappa_score(y_true, y_pred),\n",
+ " 'Balanced accuracy': metrics.balanced_accuracy_score(y_true, y_pred),\n",
+ " 'Logistic loss': metrics.log_loss(y_true, y_pred),\n",
+ " 'Precision': metrics.log_loss(y_true, y_pred),\n",
+ " 'Sensitivity': sensitivity,\n",
+ " 'Specificity': specificity,\n",
+ " 'NPV': npv,\n",
+ " 'PPV': ppv,\n",
+ " 'psep': ppv + npv - 1,\n",
+ " 'Fall-out': fp / (fp + tn),\n",
+ " \"Youden's J statistic\": sensitivity + specificity - 1,\n",
+ " 'Lift': (tp / (tp + fp)) / ((tp + fn) / (tp + tn + fp + fn)),\n",
+ " 'F-measure': 2 * tp / (2 * tp + fp + fn),\n",
+ " 'Fowlkes-Mallows index': metrics.fowlkes_mallows_score(y_true, y_pred),\n",
+ " 'False positive': fp,\n",
+ " 'False negative': fn,\n",
+ " 'True positive': tp,\n",
+ " 'True negative': tn,\n",
+ " 'Rules per example': classification_metrics['rules_per_example'],\n",
+ " 'Voting conflicts': classification_metrics['voting_conflicts'],\n",
+ " 'Geometric mean': math.sqrt(specificity * sensitivity),\n",
+ " 'Geometric mean': math.sqrt(specificity * sensitivity),\n",
+ " }\n",
+ " return pd.DataFrame.from_records([dictionary], index='Measure'), confusion_matrix\n",
+ "\n",
+ "\n",
+ "def get_ruleset_stats(\n",
+ " measure: str,\n",
+ " model: RuleClassifier\n",
+ ") -> pd.DataFrame:\n",
+ " return pd.DataFrame.from_records(\n",
+ " [{'Measure': measure, **model.stats.__dict__}],\n",
+ " index='Measure'\n",
+ " )"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Rule induction on full dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " time_total_s \n",
+ " time_growing_s \n",
+ " time_pruning_s \n",
+ " rules_count \n",
+ " conditions_per_rule \n",
+ " induced_conditions_per_rule \n",
+ " avg_rule_coverage \n",
+ " avg_rule_precision \n",
+ " avg_rule_quality \n",
+ " pvalue \n",
+ " FDR_pvalue \n",
+ " FWER_pvalue \n",
+ " fraction_significant \n",
+ " fraction_FDR_significant \n",
+ " fraction_FWER_significant \n",
+ " \n",
+ " \n",
+ " Measure \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " C2 \n",
+ " 1.218550 \n",
+ " 1.036229 \n",
+ " 0.111458 \n",
+ " 35 \n",
+ " 4.742857 \n",
+ " 22.142857 \n",
+ " 0.259410 \n",
+ " 0.670793 \n",
+ " 0.322125 \n",
+ " 0.005729 \n",
+ " 0.005879 \n",
+ " 0.010640 \n",
+ " 0.971429 \n",
+ " 0.971429 \n",
+ " 0.885714 \n",
+ " \n",
+ " \n",
+ " Correlation \n",
+ " 0.471475 \n",
+ " 0.339709 \n",
+ " 0.123223 \n",
+ " 21 \n",
+ " 5.142857 \n",
+ " 51.666667 \n",
+ " 0.306612 \n",
+ " 0.469157 \n",
+ " 0.201772 \n",
+ " 0.016841 \n",
+ " 0.017345 \n",
+ " 0.026655 \n",
+ " 0.904762 \n",
+ " 0.904762 \n",
+ " 0.857143 \n",
+ " \n",
+ " \n",
+ " RSS \n",
+ " 1.514044 \n",
+ " 1.327209 \n",
+ " 0.171176 \n",
+ " 14 \n",
+ " 3.714286 \n",
+ " 64.428571 \n",
+ " 0.473795 \n",
+ " 0.484564 \n",
+ " 0.253249 \n",
+ " 0.041892 \n",
+ " 0.044068 \n",
+ " 0.068063 \n",
+ " 0.785714 \n",
+ " 0.785714 \n",
+ " 0.714286 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " time_total_s time_growing_s time_pruning_s rules_count \\\n",
+ "Measure \n",
+ "C2 1.218550 1.036229 0.111458 35 \n",
+ "Correlation 0.471475 0.339709 0.123223 21 \n",
+ "RSS 1.514044 1.327209 0.171176 14 \n",
+ "\n",
+ " conditions_per_rule induced_conditions_per_rule \\\n",
+ "Measure \n",
+ "C2 4.742857 22.142857 \n",
+ "Correlation 5.142857 51.666667 \n",
+ "RSS 3.714286 64.428571 \n",
+ "\n",
+ " avg_rule_coverage avg_rule_precision avg_rule_quality \\\n",
+ "Measure \n",
+ "C2 0.259410 0.670793 0.322125 \n",
+ "Correlation 0.306612 0.469157 0.201772 \n",
+ "RSS 0.473795 0.484564 0.253249 \n",
+ "\n",
+ " pvalue FDR_pvalue FWER_pvalue fraction_significant \\\n",
+ "Measure \n",
+ "C2 0.005729 0.005879 0.010640 0.971429 \n",
+ "Correlation 0.016841 0.017345 0.026655 0.904762 \n",
+ "RSS 0.041892 0.044068 0.068063 0.785714 \n",
+ "\n",
+ " fraction_FDR_significant fraction_FWER_significant \n",
+ "Measure \n",
+ "C2 0.971429 0.885714 \n",
+ "Correlation 0.904762 0.857143 \n",
+ "RSS 0.785714 0.714286 "
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " Accuracy \n",
+ " MAE \n",
+ " Kappa \n",
+ " Balanced accuracy \n",
+ " Logistic loss \n",
+ " Precision \n",
+ " Sensitivity \n",
+ " Specificity \n",
+ " NPV \n",
+ " PPV \n",
+ " ... \n",
+ " Lift \n",
+ " F-measure \n",
+ " Fowlkes-Mallows index \n",
+ " False positive \n",
+ " False negative \n",
+ " True positive \n",
+ " True negative \n",
+ " Rules per example \n",
+ " Voting conflicts \n",
+ " Geometric mean \n",
+ " \n",
+ " \n",
+ " Measure \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " C2 \n",
+ " 0.932663 \n",
+ " 0.067337 \n",
+ " 0.433613 \n",
+ " 0.709693 \n",
+ " 2.427088 \n",
+ " 2.427088 \n",
+ " 0.452941 \n",
+ " 0.966446 \n",
+ " 0.961665 \n",
+ " 0.487342 \n",
+ " ... \n",
+ " 7.407595 \n",
+ " 0.469512 \n",
+ " 0.928703 \n",
+ " 81 \n",
+ " 93 \n",
+ " 77 \n",
+ " 2333 \n",
+ " 9.079334 \n",
+ " 2146.0 \n",
+ " 0.661622 \n",
+ " \n",
+ " \n",
+ " Correlation \n",
+ " 0.827399 \n",
+ " 0.172601 \n",
+ " 0.246689 \n",
+ " 0.729909 \n",
+ " 6.221157 \n",
+ " 6.221157 \n",
+ " 0.617647 \n",
+ " 0.842171 \n",
+ " 0.969018 \n",
+ " 0.216049 \n",
+ " ... \n",
+ " 3.283951 \n",
+ " 0.320122 \n",
+ " 0.823757 \n",
+ " 381 \n",
+ " 65 \n",
+ " 105 \n",
+ " 2033 \n",
+ " 6.438854 \n",
+ " 1993.0 \n",
+ " 0.721224 \n",
+ " \n",
+ " \n",
+ " RSS \n",
+ " 0.788313 \n",
+ " 0.211687 \n",
+ " 0.207458 \n",
+ " 0.725394 \n",
+ " 7.629984 \n",
+ " 7.629984 \n",
+ " 0.652941 \n",
+ " 0.797846 \n",
+ " 0.970277 \n",
+ " 0.185309 \n",
+ " ... \n",
+ " 2.816694 \n",
+ " 0.288687 \n",
+ " 0.789800 \n",
+ " 488 \n",
+ " 59 \n",
+ " 111 \n",
+ " 1926 \n",
+ " 6.633127 \n",
+ " 2085.0 \n",
+ " 0.721766 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
3 rows × 23 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " Accuracy MAE Kappa Balanced accuracy Logistic loss \\\n",
+ "Measure \n",
+ "C2 0.932663 0.067337 0.433613 0.709693 2.427088 \n",
+ "Correlation 0.827399 0.172601 0.246689 0.729909 6.221157 \n",
+ "RSS 0.788313 0.211687 0.207458 0.725394 7.629984 \n",
+ "\n",
+ " Precision Sensitivity Specificity NPV PPV ... \\\n",
+ "Measure ... \n",
+ "C2 2.427088 0.452941 0.966446 0.961665 0.487342 ... \n",
+ "Correlation 6.221157 0.617647 0.842171 0.969018 0.216049 ... \n",
+ "RSS 7.629984 0.652941 0.797846 0.970277 0.185309 ... \n",
+ "\n",
+ " Lift F-measure Fowlkes-Mallows index False positive \\\n",
+ "Measure \n",
+ "C2 7.407595 0.469512 0.928703 81 \n",
+ "Correlation 3.283951 0.320122 0.823757 381 \n",
+ "RSS 2.816694 0.288687 0.789800 488 \n",
+ "\n",
+ " False negative True positive True negative Rules per example \\\n",
+ "Measure \n",
+ "C2 93 77 2333 9.079334 \n",
+ "Correlation 65 105 2033 6.438854 \n",
+ "RSS 59 111 1926 6.633127 \n",
+ "\n",
+ " Voting conflicts Geometric mean \n",
+ "Measure \n",
+ "C2 2146.0 0.661622 \n",
+ "Correlation 1993.0 0.721224 \n",
+ "RSS 2085.0 0.721766 \n",
+ "\n",
+ "[3 rows x 23 columns]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Confusion matrix - C2\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 2333 \n",
+ " 81 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 93 \n",
+ " 77 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 0 1\n",
+ "0 2333 81\n",
+ "1 93 77"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Confusion matrix - Correlation\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 2033 \n",
+ " 381 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 65 \n",
+ " 105 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 0 1\n",
+ "0 2033 381\n",
+ "1 65 105"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Confusion matrix - RSS\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1926 \n",
+ " 488 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 59 \n",
+ " 111 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 0 1\n",
+ "0 1926 488\n",
+ "1 59 111"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "from rulekit.classification import RuleClassifier\n",
+ "from rulekit.rules import RuleSet, ClassificationRule\n",
+ "from rulekit.params import Measures\n",
+ "from IPython.display import display\n",
+ "\n",
+ "# C2\n",
+ "clf = RuleClassifier(\n",
+ " induction_measure=Measures.C2,\n",
+ " pruning_measure=Measures.C2,\n",
+ " voting_measure=Measures.C2,\n",
+ ")\n",
+ "clf.fit(X, y)\n",
+ "c2_ruleset: RuleSet[ClassificationRule] = clf.model\n",
+ "prediction, classification_metrics = clf.predict(X, return_metrics=True)\n",
+ "\n",
+ "prediction_metric, c2_confusion_matrix = get_prediction_metrics('C2', prediction, y, classification_metrics)\n",
+ "model_stats = get_ruleset_stats('C2', clf.model)\n",
+ "\n",
+ "# Correlation\n",
+ "clf = RuleClassifier(\n",
+ " induction_measure=Measures.Correlation,\n",
+ " pruning_measure=Measures.Correlation,\n",
+ " voting_measure=Measures.Correlation,\n",
+ ")\n",
+ "clf.fit(X, y)\n",
+ "corr_ruleset: RuleSet[ClassificationRule] = clf.model\n",
+ "prediction, classification_metrics = clf.predict(X, return_metrics=True)\n",
+ "\n",
+ "tmp, corr_confusion_matrix = get_prediction_metrics('Correlation', prediction, y, classification_metrics)\n",
+ "prediction_metric = pd.concat([prediction_metric, tmp])\n",
+ "model_stats = pd.concat([model_stats, get_ruleset_stats('Correlation', clf.model)])\n",
+ "\n",
+ "# RSS\n",
+ "clf = RuleClassifier(\n",
+ " induction_measure=Measures.RSS,\n",
+ " pruning_measure=Measures.RSS,\n",
+ " voting_measure=Measures.RSS,\n",
+ ")\n",
+ "clf.fit(X, y)\n",
+ "rss_ruleset: RuleSet[ClassificationRule] = clf.model\n",
+ "prediction, classification_metrics = clf.predict(X, return_metrics=True)\n",
+ "tmp, rss_confusion_matrix = get_prediction_metrics('RSS', prediction, y, classification_metrics)\n",
+ "prediction_metric = pd.concat([prediction_metric, tmp])\n",
+ "model_stats = pd.concat([model_stats, get_ruleset_stats('RSS', clf.model)])\n",
+ "\n",
+ "display(model_stats)\n",
+ "display(prediction_metric)\n",
+ "\n",
+ "print('Confusion matrix - C2')\n",
+ "display(pd.DataFrame(c2_confusion_matrix))\n",
+ "\n",
+ "print('Confusion matrix - Correlation')\n",
+ "display(pd.DataFrame(corr_confusion_matrix))\n",
+ "\n",
+ "print('Confusion matrix - RSS')\n",
+ "display(pd.DataFrame(rss_confusion_matrix))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### C2 Measure generated rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF gimpuls = (-inf, 32.50) THEN class = {0}\n",
+ "IF nbumps = (-inf, 0.50) AND goenergy = <-84.50, inf) AND goimpuls = (-inf, -0.50) AND genergy = (-inf, 13675) THEN class = {0}\n",
+ "IF genergy = (-inf, 17640) AND nbumps = (-inf, 0.50) AND goenergy = <-84.50, inf) THEN class = {0}\n",
+ "IF genergy = <1625, 17640) AND maxenergy = (-inf, 3500) AND gimpuls = (-inf, 772.50) THEN class = {0}\n",
+ "IF shift = {N} AND nbumps = (-inf, 0.50) AND goenergy = <-73.50, inf) THEN class = {0}\n",
+ "IF shift = {N} AND senergy = (-inf, 6150) AND genergy = <1865, inf) AND goimpuls = (-inf, 230.50) THEN class = {0}\n",
+ "IF senergy = (-inf, 550) AND gimpuls = (-inf, 380.50) AND goimpuls = (-inf, 96.50) AND goenergy = (-inf, 118) THEN class = {0}\n",
+ "IF senergy = (-inf, 550) AND genergy = (-inf, 31790) AND goenergy = <-84.50, 114.50) THEN class = {0}\n",
+ "IF senergy = (-inf, 550) AND goenergy = <-84.50, 87.50) AND gimpuls = (-inf, 1342.50) AND goimpuls = (-inf, 96) THEN class = {0}\n",
+ "IF senergy = (-inf, 550) AND goimpuls = (-inf, 233.50) THEN class = {0}\n",
+ "IF genergy = <1865, 28515) AND goenergy = (-inf, 105.50) AND nbumps = (-inf, 4.50) THEN class = {0}\n",
+ "IF nbumps = <0.50, 1.50) AND gimpuls = (-inf, 1210) AND goimpuls = (-inf, 233.50) AND goenergy = <-72.50, inf) AND genergy = <12550, inf) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 514.50) AND nbumps = (-inf, 6.50) AND goimpuls = (-inf, 96.50) AND goenergy = <-84.50, inf) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 1832.50) AND goimpuls = (-inf, 312) THEN class = {0}\n",
+ "IF nbumps3 = (-inf, 2.50) AND nbumps = (-inf, 6.50) AND goenergy = <-88.50, inf) THEN class = {0}\n",
+ "IF genergy = (-inf, 748755) AND goimpuls = (-inf, 95.50) AND maxenergy = (-inf, 55000) AND gimpuls = (-inf, 3096) THEN class = {0}\n",
+ "IF nbumps3 = <3.50, inf) AND gimpuls = <364, 1459.50) AND senergy = <10150, inf) THEN class = {1}\n",
+ "IF gimpuls = <2208.50, inf) AND genergy = <513615, 1005720) AND nbumps2 = <0.50, inf) AND nbumps = (-inf, 3.50) THEN class = {1}\n",
+ "IF gimpuls = <1328, inf) AND goenergy = (-inf, -29.50) AND goimpuls = <-31.50, -14.50) AND nbumps4 = (-inf, 1.50) THEN class = {1}\n",
+ "IF gimpuls = <1328, 2109) AND goimpuls = (-inf, -5.50) AND senergy = <350, 36350) AND genergy = <159155, 586025) AND nbumps2 = (-inf, 3.50) AND goenergy = <-41.50, inf) THEN class = {1}\n",
+ "IF nbumps3 = <0.50, 1.50) AND gimpuls = <1408, 1959) AND goimpuls = <-20.50, 13.50) AND senergy = (-inf, 54950) THEN class = {1}\n",
+ "IF senergy = <750, 38250) AND genergy = <254130, 1133675) AND goenergy = <-16.50, inf) AND gimpuls = <1438.50, inf) AND goimpuls = <-5, inf) THEN class = {1}\n",
+ "IF nbumps = <4.50, inf) AND nbumps3 = <1.50, 4.50) AND gimpuls = <203.50, inf) AND senergy = <4300, 131700) AND goenergy = <-41.50, inf) THEN class = {1}\n",
+ "IF nbumps = <2.50, 4.50) AND gimpuls = <740.50, inf) AND genergy = <38935, 127440) AND senergy = (-inf, 14750) AND goimpuls = (-inf, 68.50) THEN class = {1}\n",
+ "IF nbumps = <2.50, inf) AND gimpuls = <379, 1742) AND senergy = (-inf, 31100) AND genergy = (-inf, 211170) AND goenergy = (-inf, 123.50) AND goimpuls = (-inf, 19.50) THEN class = {1}\n",
+ "IF gimpuls = <1139.50, inf) AND goimpuls = <-46, 116.50) AND senergy = (-inf, 38250) AND genergy = <46580, 1877915) AND goenergy = (-inf, 183) AND shift = {W} AND nbumps3 = (-inf, 1.50) AND nbumps2 = (-inf, 2.50) THEN class = {1}\n",
+ "IF nbumps = <1.50, 3.50) AND gimpuls = <521.50, 2344.50) AND nbumps2 = <0.50, inf) AND genergy = <34605, 656965) AND goenergy = (-inf, 137) AND goimpuls = <-39, 41.50) AND maxenergy = <450, inf) THEN class = {1}\n",
+ "IF nbumps = <1.50, 3.50) AND nbumps2 = <0.50, inf) AND genergy = <18870, inf) AND nbumps3 = (-inf, 1.50) AND gimpuls = <160, inf) AND senergy = <550, inf) AND goimpuls = <-62.50, 8.50) AND goenergy = (-inf, -1.50) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) AND gimpuls = <95, 1603.50) AND goenergy = (-inf, 131) AND goimpuls = <-70.50, 119) AND nbumps2 = (-inf, 4.50) AND nbumps3 = <0.50, inf) AND genergy = (-inf, 614380) AND maxenergy = (-inf, 25000) AND senergy = <2250, inf) THEN class = {1}\n",
+ "IF goenergy = <-59.50, 186) AND genergy = <12415, 129940) AND gimpuls = <121.50, 793) AND senergy = <150, 1350) AND ghazard = {a} AND goimpuls = <-53.50, inf) THEN class = {1}\n",
+ "IF genergy = <42215, 94300) AND gimpuls = <133.50, 813.50) AND ghazard = {a} AND goenergy = <-74.50, 160) AND senergy = (-inf, 11100) AND nbumps = (-inf, 3.50) AND nbumps3 = (-inf, 0.50) THEN class = {1}\n",
+ "IF gimpuls = <537.50, 796) AND shift = {W} AND genergy = <17635, 36470) AND goimpuls = <-36.50, inf) AND goenergy = <-37.50, inf) AND nbumps = (-inf, 0.50) THEN class = {1}\n",
+ "IF genergy = <18800, 52205) AND shift = {W} AND ghazard = {a} AND goimpuls = <-28.50, inf) AND goenergy = (-inf, 181) AND gimpuls = <380.50, 524.50) AND nbumps = (-inf, 0.50) THEN class = {1}\n",
+ "IF gimpuls = <184.50, inf) AND goenergy = <-55.50, 128.50) AND genergy = <7265, inf) AND goimpuls = <-60.50, 37.50) AND nbumps = (-inf, 7.50) AND nbumps2 = (-inf, 4.50) AND maxenergy = (-inf, 25000) AND senergy = (-inf, 31350) THEN class = {1}\n",
+ "IF gimpuls = <32.50, inf) AND goimpuls = <-74.50, inf) AND ghazard = {a} AND genergy = <1510, inf) AND goenergy = <-89.50, 124.50) THEN class = {1}\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in c2_ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Correlation Measure generated rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1252.50) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 1331) AND goimpuls = (-inf, 312) AND nbumps5 = (-inf, 0.50) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 1253.50) AND nbumps3 = (-inf, 2.50) AND nbumps = (-inf, 7) THEN class = {0}\n",
+ "IF nbumps4 = (-inf, 2.50) THEN class = {0}\n",
+ "IF nbumps2 = <0.50, 2.50) AND maxenergy = <1500, inf) AND senergy = (-inf, 36050) AND nbumps3 = <0.50, 4.50) AND goimpuls = <-34, 95) AND genergy = (-inf, 662435) AND gimpuls = <994.50, 1959) THEN class = {1}\n",
+ "IF nbumps2 = <0.50, inf) AND maxenergy = <1500, inf) AND goimpuls = <-55, 95) AND nbumps = (-inf, 6.50) AND genergy = <61250, 662435) AND goenergy = (-inf, 96) AND nbumps3 = <0.50, inf) AND gimpuls = <712, 2257.50) AND senergy = (-inf, 31100) THEN class = {1}\n",
+ "IF nbumps2 = <0.50, inf) AND genergy = <58310, 934630) AND goenergy = (-inf, 186) AND senergy = (-inf, 40650) AND maxenergy = <1500, inf) AND gimpuls = <538.50, inf) AND goimpuls = <-55, inf) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) AND nbumps2 = <0.50, inf) AND gimpuls = <521.50, 2374) AND genergy = <58310, 799855) AND senergy = <650, 36050) AND goimpuls = <-71, 58.50) AND ghazard = {a} THEN class = {1}\n",
+ "IF nbumps = <1.50, 6.50) AND nbumps2 = <0.50, inf) AND gimpuls = <521.50, 2374) AND genergy = <34360, inf) AND maxenergy = <350, inf) AND goimpuls = <-55, 95) AND senergy = <550, inf) AND nbumps4 = (-inf, 1.50) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) AND gimpuls = <306, inf) AND genergy = <28325, inf) AND goimpuls = (-inf, 19.50) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) AND nbumps2 = <0.50, inf) AND gimpuls = <153.50, 321) AND genergy = <14295, 36250) AND goimpuls = <-60.50, inf) AND senergy = (-inf, 40500) AND nbumps3 = (-inf, 3.50) THEN class = {1}\n",
+ "IF genergy = <96260, 1062020) AND goimpuls = <-29, inf) AND senergy = <850, 7500) AND nbumps3 = (-inf, 1.50) AND gimpuls = <1404, 2965.50) AND nbumps = (-inf, 3.50) AND goenergy = (-inf, 69.50) THEN class = {1}\n",
+ "IF gimpuls = <1253.50, inf) AND goenergy = <-50.50, 131.50) AND genergy = <46580, 1789250) AND nbumps = (-inf, 7.50) AND shift = {W} AND goimpuls = <-60.50, 118) AND senergy = (-inf, 95850) AND ghazard = {a} THEN class = {1}\n",
+ "IF senergy = <550, inf) AND shift = {W} AND genergy = <10495, inf) AND gimpuls = <160, inf) AND goenergy = (-inf, 126) THEN class = {1}\n",
+ "IF senergy = <350, inf) AND goimpuls = <-74.50, inf) AND gimpuls = <32.50, inf) AND goenergy = <-78.50, inf) AND maxenergy = <250, inf) THEN class = {1}\n",
+ "IF genergy = <43150, inf) AND gimpuls = <133.50, inf) AND goenergy = (-inf, 176.50) THEN class = {1}\n",
+ "IF shift = {W} AND genergy = <31760, 49585) AND gimpuls = <362.50, 771) AND goimpuls = <-27.50, inf) AND goenergy = <-3.50, inf) AND maxenergy = (-inf, 650) THEN class = {1}\n",
+ "IF shift = {W} AND genergy = <20485, 43280) AND gimpuls = <380.50, 796) AND goimpuls = <-37, 142.50) AND goenergy = <-37.50, 181) AND nbumps = (-inf, 0.50) THEN class = {1}\n",
+ "IF gimpuls = <177.50, inf) AND genergy = <7265, inf) AND goimpuls = (-inf, 241.50) AND goenergy = (-inf, 124.50) THEN class = {1}\n",
+ "IF gimpuls = <54.50, 90) AND genergy = <1510, 4905) AND goimpuls = <-72.50, 28.50) AND seismoacoustic = {a} THEN class = {1}\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in corr_ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### RSS Measure generated rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF nbumps = (-inf, 1.50) AND genergy = (-inf, 126350) THEN class = {0}\n",
+ "IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 2168) AND goimpuls = (-inf, 96.50) THEN class = {0}\n",
+ "IF genergy = (-inf, 44750) AND nbumps3 = (-inf, 2.50) AND goenergy = (-inf, 105.50) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 725.50) AND nbumps3 = (-inf, 3.50) AND nbumps4 = (-inf, 2.50) AND goimpuls = (-inf, 117) AND goenergy = <-88.50, inf) THEN class = {0}\n",
+ "IF nbumps2 = (-inf, 1.50) AND nbumps = (-inf, 4.50) THEN class = {0}\n",
+ "IF goimpuls = (-inf, 312) AND nbumps5 = (-inf, 0.50) AND goenergy = <-88.50, inf) THEN class = {0}\n",
+ "IF gimpuls = <521.50, inf) AND genergy = <57680, inf) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) THEN class = {1}\n",
+ "IF senergy = <550, inf) AND shift = {W} AND genergy = <10495, inf) THEN class = {1}\n",
+ "IF nbumps = <0.50, inf) AND goimpuls = <-74.50, inf) AND gimpuls = <32.50, inf) AND goenergy = <-78.50, 124.50) THEN class = {1}\n",
+ "IF genergy = <34315, 49585) AND ghazard = {a} AND gimpuls = <396, 1445.50) AND goenergy = <7, inf) AND goimpuls = <-19, inf) AND senergy = (-inf, 350) THEN class = {1}\n",
+ "IF genergy = <26200, 78890) AND gimpuls = <133.50, 813.50) AND goenergy = <-74.50, 297.50) AND goimpuls = <-71, inf) AND nbumps = (-inf, 3.50) AND senergy = (-inf, 1850) THEN class = {1}\n",
+ "IF genergy = <18585, 25305) AND shift = {W} AND gimpuls = <240, 588.50) AND goimpuls = <-42.50, 133) AND goenergy = <-45.50, inf) AND senergy = (-inf, 450) THEN class = {1}\n",
+ "IF gimpuls = <54.50, inf) AND goimpuls = <-74.50, 28.50) AND genergy = <1510, inf) AND ghazard = {a} AND nbumps4 = (-inf, 1.50) AND senergy = (-inf, 92850) THEN class = {1}\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in rss_ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Stratified K-Folds cross-validation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from IPython.display import display\n",
+ "from sklearn.model_selection import StratifiedKFold\n",
+ "\n",
+ "N_SPLITS: int = 10\n",
+ "\n",
+ "skf = StratifiedKFold(n_splits=10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "C:\\Users\\cezar\\AppData\\Local\\Temp\\ipykernel_13196\\4002598548.py:22: RuntimeWarning: invalid value encountered in scalar divide\n",
+ " ppv: float = tp / (tp + fp)\n",
+ "C:\\Users\\cezar\\AppData\\Local\\Temp\\ipykernel_13196\\4002598548.py:39: RuntimeWarning: invalid value encountered in scalar divide\n",
+ " 'Lift': (tp / (tp + fp)) / ((tp + fn) / (tp + tn + fp + fn)),\n",
+ "C:\\Users\\cezar\\AppData\\Local\\Temp\\ipykernel_13196\\4002598548.py:22: RuntimeWarning: invalid value encountered in scalar divide\n",
+ " ppv: float = tp / (tp + fp)\n",
+ "C:\\Users\\cezar\\AppData\\Local\\Temp\\ipykernel_13196\\4002598548.py:39: RuntimeWarning: invalid value encountered in scalar divide\n",
+ " 'Lift': (tp / (tp + fp)) / ((tp + fn) / (tp + tn + fp + fn)),\n"
+ ]
+ }
+ ],
+ "source": [
+ "c2_ruleset_stats = pd.DataFrame()\n",
+ "c2_prediction_metrics = pd.DataFrame()\n",
+ "c2_confusion_matrix = np.array([[0.0, 0.0], [0.0, 0.0]])\n",
+ "\n",
+ "for train_index, test_index in skf.split(X, y):\n",
+ " x_train, x_test = X.iloc[train_index], X.iloc[test_index]\n",
+ " y_train, y_test = y.iloc[train_index], y.iloc[test_index]\n",
+ "\n",
+ " clf = RuleClassifier(\n",
+ " induction_measure=Measures.C2,\n",
+ " pruning_measure=Measures.C2,\n",
+ " voting_measure=Measures.C2,\n",
+ " )\n",
+ " clf.fit(x_train, y_train)\n",
+ " c2_ruleset = clf.model\n",
+ " prediction, classification_metrics = clf.predict(x_test, return_metrics=True)\n",
+ " tmp, confusion_matrix = get_prediction_metrics('C2', prediction, y_test, classification_metrics)\n",
+ " \n",
+ " c2_prediction_metrics = pd.concat([c2_prediction_metrics, tmp])\n",
+ " c2_ruleset_stats = pd.concat([c2_ruleset_stats, get_ruleset_stats('C2', c2_ruleset)])\n",
+ " c2_confusion_matrix += confusion_matrix\n",
+ "\n",
+ "c2_confusion_matrix /= N_SPLITS"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Rules characteristics "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "time_total_s 0.292132\n",
+ "time_growing_s 0.227262\n",
+ "time_pruning_s 0.047455\n",
+ "rules_count 34.200000\n",
+ "conditions_per_rule 4.720378\n",
+ "induced_conditions_per_rule 21.124536\n",
+ "avg_rule_coverage 0.239541\n",
+ "avg_rule_precision 0.690010\n",
+ "avg_rule_quality 0.337021\n",
+ "pvalue 0.014757\n",
+ "FDR_pvalue 0.015234\n",
+ "FWER_pvalue 0.030014\n",
+ "fraction_significant 0.909792\n",
+ "fraction_FDR_significant 0.909792\n",
+ "fraction_FWER_significant 0.872710\n",
+ "dtype: float64"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(c2_ruleset_stats.mean())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Rules evaluation (average)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Accuracy 0.855063\n",
+ "MAE 0.144937\n",
+ "Kappa 0.107556\n",
+ "Balanced accuracy 0.567020\n",
+ "Logistic loss 5.224070\n",
+ "Precision 5.224070\n",
+ "Sensitivity 0.235294\n",
+ "Specificity 0.898747\n",
+ "NPV 0.945594\n",
+ "PPV 0.495355\n",
+ "psep 0.443788\n",
+ "Fall-out 0.101253\n",
+ "Youden's J statistic 0.134041\n",
+ "Lift 7.520255\n",
+ "F-measure 0.145015\n",
+ "Fowlkes-Mallows index 0.870605\n",
+ "False positive 24.500000\n",
+ "False negative 13.000000\n",
+ "True positive 4.000000\n",
+ "True negative 216.900000\n",
+ "Rules per example 7.871479\n",
+ "Voting conflicts 179.000000\n",
+ "Geometric mean 0.344832\n",
+ "dtype: float64"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(c2_prediction_metrics.mean())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Confusion matrix (average)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 216.9 \n",
+ " 24.5 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 13.0 \n",
+ " 4.0 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 0 1\n",
+ "0 216.9 24.5\n",
+ "1 13.0 4.0"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(pd.DataFrame(c2_confusion_matrix))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Hyperparameters tuning\n",
+ "\n",
+ "This one gonna take a while..."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Best BAC: 0.626780 using {'induction_measure': , 'minsupp_new': 5, 'pruning_measure': , 'voting_measure': }\n"
+ ]
+ }
+ ],
+ "source": [
+ "from sklearn.model_selection import StratifiedKFold\n",
+ "from sklearn.model_selection import GridSearchCV\n",
+ "from rulekit.params import Measures\n",
+ "\n",
+ "N_SPLITS: int = 3\n",
+ "\n",
+ "# define models and parameters\n",
+ "model = RuleClassifier()\n",
+ "minsupp_new = range(3, 15, 2)\n",
+ "measures_choice = [Measures.C2, Measures.RSS, Measures.WeightedLaplace, Measures.Correlation]\n",
+ "\n",
+ "# define grid search\n",
+ "grid = {\n",
+ " 'minsupp_new': minsupp_new, \n",
+ " 'induction_measure': measures_choice, \n",
+ " 'pruning_measure': measures_choice, \n",
+ " 'voting_measure': measures_choice\n",
+ "}\n",
+ "cv = StratifiedKFold(n_splits=N_SPLITS)\n",
+ "grid_search = GridSearchCV(\n",
+ " estimator=model, \n",
+ " param_grid=grid, \n",
+ " cv=cv, \n",
+ " scoring='balanced_accuracy', \n",
+ " n_jobs=3\n",
+ ")\n",
+ "grid_result = grid_search.fit(X, y)\n",
+ "\n",
+ "# summarize results\n",
+ "print(\"Best BAC: %f using %s\" % (grid_result.best_score_, grid_result.best_params_))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Building model with tuned hyperparameters\n",
+ "\n",
+ "### Split dataset to train and test (80%/20%)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import pandas as pd\n",
+ "from sklearn.model_selection import train_test_split\n",
+ "from IPython.display import display\n",
+ "\n",
+ "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=True)\n",
+ "\n",
+ "\n",
+ "clf = RuleClassifier(**grid_result.best_params_)\n",
+ "clf.fit(X_train, y_train)\n",
+ "ruleset: RuleSet[ClassificationRule] = clf.model\n",
+ "ruleset_stats = get_ruleset_stats('Best', ruleset)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Rules evaluation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "time_total_s 0.173054\n",
+ "time_growing_s 0.120460\n",
+ "time_pruning_s 0.029986\n",
+ "rules_count 29.000000\n",
+ "conditions_per_rule 2.689655\n",
+ "induced_conditions_per_rule 15.310345\n",
+ "avg_rule_coverage 0.491183\n",
+ "avg_rule_precision 0.736226\n",
+ "avg_rule_quality 1.309334\n",
+ "pvalue 0.019831\n",
+ "FDR_pvalue 0.019993\n",
+ "FWER_pvalue 0.024284\n",
+ "fraction_significant 0.931034\n",
+ "fraction_FDR_significant 0.931034\n",
+ "fraction_FWER_significant 0.931034\n",
+ "dtype: float64"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(ruleset_stats.mean())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Validate model on test dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Accuracy 0.808511\n",
+ "MAE 0.191489\n",
+ "Kappa 0.170010\n",
+ "Balanced accuracy 0.679398\n",
+ "Logistic loss 6.901976\n",
+ "Precision 6.901976\n",
+ "Sensitivity 0.533333\n",
+ "Specificity 0.825462\n",
+ "NPV 0.966346\n",
+ "PPV 0.158416\n",
+ "psep 0.124762\n",
+ "Fall-out 0.174538\n",
+ "Youden's J statistic 0.358795\n",
+ "Lift 2.730033\n",
+ "F-measure 0.244275\n",
+ "Fowlkes-Mallows index 0.809997\n",
+ "False positive 85.000000\n",
+ "False negative 14.000000\n",
+ "True positive 16.000000\n",
+ "True negative 402.000000\n",
+ "Rules per example 14.034816\n",
+ "Voting conflicts 360.000000\n",
+ "Geometric mean 0.663511\n",
+ "dtype: float64"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 402 \n",
+ " 85 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 14 \n",
+ " 16 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 0 1\n",
+ "0 402 85\n",
+ "1 14 16"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "prediction, classification_metrics = clf.predict(X_test, return_metrics=True)\n",
+ "prediction_metrics, confusion_matrix = get_prediction_metrics('Best', prediction, y_test, classification_metrics)\n",
+ "\n",
+ "display(prediction_metrics.mean())\n",
+ "display(pd.DataFrame(confusion_matrix))"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "tutorials_env",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.0"
+ },
+ "orig_nbformat": 2
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/docs/serve/v2.1.24.0/_sources/rst/tutorials/expert_rules.ipynb.txt b/docs/serve/v2.1.24.0/_sources/rst/tutorials/expert_rules.ipynb.txt
new file mode 100644
index 0000000..70e5c29
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_sources/rst/tutorials/expert_rules.ipynb.txt
@@ -0,0 +1,631 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Expert Rules"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This notebook presents example usage of user-guided rule induction which follows the scheme introduced by the [GuideR](https://www.sciencedirect.com/science/article/abs/pii/S0950705119300802?dgcid=coauthor) algorithm (Sikora et al, 2019). \n",
+ "Each problem (classification, regression, survival) in addition to the basic class has an expert class, i.e. RuleClassifier and ExpertRuleClassifier. Expert classes allow you to define set of initial rules, preferred conditions and forbidden conditions. \n",
+ "This tutorial will show you how to define rules and conditions\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Classification"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Load dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "from rulekit.arff import read_arff\n",
+ "\n",
+ "CLASSIFICATION_DATASET_URL: str = (\n",
+ " 'https://raw.githubusercontent.com/'\n",
+ " 'adaa-polsl/RuleKit/refs/heads/master/data/seismic-bumps/'\n",
+ " 'seismic-bumps.arff'\n",
+ ")\n",
+ "\n",
+ "df: pd.DataFrame = read_arff(CLASSIFICATION_DATASET_URL)\n",
+ "X, y = df.drop(['class'], axis=1), df['class']"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Define expert knowledge"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "expert_rules: list[tuple[str, str]] = [\n",
+ " ('rule-0', 'IF [[gimpuls = <-inf, 750)]] THEN class = {0}'),\n",
+ " ('rule-1', 'IF [[gimpuls = <750, inf)]] THEN class = {1}')\n",
+ "]\n",
+ "\n",
+ "expert_preferred_conditions: list[tuple[str, str]] = [\n",
+ " ('preferred-condition-0', '1: IF [[seismic = {a}]] THEN class = {0}'),\n",
+ " ('preferred-attribute-0', '1: IF [[gimpuls = Any]] THEN class = {1}')\n",
+ "]\n",
+ "\n",
+ "expert_forbidden_conditions: list[tuple[str, str]] = [\n",
+ " ('forb-attribute-0', '1: IF [[seismoacoustic = Any]] THEN class = {0}'),\n",
+ " ('forb-attribute-1', 'inf: IF [[ghazard = Any]] THEN class = {1}')\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Rule induction"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from rulekit.classification import ExpertRuleClassifier\n",
+ "from rulekit.rules import RuleSet, ClassificationRule\n",
+ "\n",
+ "clf = ExpertRuleClassifier(\n",
+ " minsupp_new=8,\n",
+ " max_growing=0,\n",
+ " extend_using_preferred=True,\n",
+ " extend_using_automatic=True,\n",
+ " induce_using_preferred=True,\n",
+ " induce_using_automatic=True\n",
+ ")\n",
+ "clf.fit(\n",
+ " X, y,\n",
+ " expert_rules=expert_rules,\n",
+ " expert_preferred_conditions=expert_preferred_conditions,\n",
+ " expert_forbidden_conditions=expert_forbidden_conditions\n",
+ ")\n",
+ "ruleset: RuleSet[ClassificationRule] = clf.model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF [[gimpuls = <-inf, 750)]] AND [seismic = {a}] AND nbumps = (-inf, 1.50) AND nbumps4 = (-inf, 0.50) THEN class = {0}\n",
+ "IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1252.50) THEN class = {0}\n",
+ "IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1342.50) AND goimpuls = (-inf, 312) THEN class = {0}\n",
+ "IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1427.50) THEN class = {0}\n",
+ "IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1653.50) AND genergy = (-inf, 1006585) AND goimpuls = (-inf, 312) THEN class = {0}\n",
+ "IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1752) THEN class = {0}\n",
+ "IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 2733) AND goimpuls = (-inf, 312) THEN class = {0}\n",
+ "IF nbumps = (-inf, 1.50) AND genergy = <634250, inf) AND gimpuls = <2965, inf) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 1331) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 1655.50) AND genergy = (-inf, 386010) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 1686) AND nbumps2 = (-inf, 1.50) AND goimpuls = (-inf, 312) AND nbumps5 = (-inf, 0.50) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) AND genergy = (-inf, 386010) AND gimpuls = (-inf, 2892) AND goimpuls = (-inf, 312) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 2068.50) AND goimpuls = (-inf, 312) AND nbumps2 = (-inf, 1.50) AND genergy = (-inf, 1004565) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 2184.50) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 1253.50) AND nbumps3 = (-inf, 1.50) AND nbumps2 = (-inf, 2.50) THEN class = {0}\n",
+ "IF nbumps = (-inf, 3.50) AND goimpuls = (-inf, 96.50) AND gimpuls = (-inf, 901) AND senergy = (-inf, 3850) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 1253.50) AND nbumps3 = (-inf, 1.50) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 1253.50) AND nbumps2 = (-inf, 1.50) AND senergy = (-inf, 9600) AND nbumps3 = (-inf, 2.50) AND goimpuls = (-inf, 312) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 1253.50) AND nbumps2 = (-inf, 1.50) AND nbumps3 = (-inf, 2.50) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 1253.50) AND senergy = (-inf, 8100) AND nbumps2 = (-inf, 2.50) AND goimpuls = (-inf, 312) THEN class = {0}\n",
+ "IF maxenergy = (-inf, 5500) AND gimpuls = (-inf, 901) AND goenergy = <-40.50, 68.50) AND ghazard = {a} AND goimpuls = <-39.50, inf) AND senergy = <1150, inf) AND nbumps2 = <1.50, inf) THEN class = {0}\n",
+ "IF nbumps2 = (-inf, 1.50) AND nbumps3 = (-inf, 3.50) AND nbumps = (-inf, 6.50) AND gimpuls = (-inf, 695.50) AND goimpuls = <-54.50, inf) AND goenergy = <-48.50, inf) AND genergy = <10915, inf) AND maxenergy = <2500, inf) AND senergy = <3950, inf) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 1253.50) AND nbumps = (-inf, 4.50) AND nbumps2 = (-inf, 2.50) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 1253.50) AND nbumps3 = (-inf, 2.50) AND nbumps = (-inf, 5.50) THEN class = {0}\n",
+ "IF nbumps3 = (-inf, 3.50) AND nbumps4 = (-inf, 2.50) AND maxenergy = (-inf, 75000) AND genergy = (-inf, 378500) AND gimpuls = (-inf, 901) THEN class = {0}\n",
+ "IF senergy = (-inf, 85450) AND goimpuls = (-inf, 312) AND gimpuls = (-inf, 1139.50) THEN class = {0}\n",
+ "IF nbumps2 = (-inf, 0.50) AND nbumps3 = (-inf, 2.50) AND goimpuls = <-35.50, inf) AND nbumps = <1.50, inf) AND gimpuls = <1150.50, inf) THEN class = {0}\n",
+ "IF senergy = (-inf, 5750) AND genergy = (-inf, 508210) AND goenergy = <-18.50, inf) AND nbumps2 = <1.50, inf) AND gimpuls = <927, inf) THEN class = {0}\n",
+ "IF senergy = (-inf, 5750) THEN class = {0}\n",
+ "IF nbumps3 = (-inf, 2.50) AND nbumps2 = (-inf, 2.50) AND gimpuls = (-inf, 2489.50) AND genergy = (-inf, 318735) THEN class = {0}\n",
+ "IF nbumps2 = (-inf, 1.50) AND goenergy = <-36.50, inf) AND goimpuls = (-inf, 6.50) AND genergy = <392530, inf) AND senergy = <6750, inf) THEN class = {0}\n",
+ "IF nbumps = (-inf, 4.50) AND nbumps2 = (-inf, 2.50) AND gimpuls = (-inf, 3881.50) THEN class = {0}\n",
+ "IF [[gimpuls = <750, inf)]] AND nbumps2 = <0.50, inf) AND genergy = <61250, 662435) AND maxenergy = <1500, inf) AND nbumps = (-inf, 7.50) AND nbumps3 = <0.50, inf) AND seismoacoustic = {a} AND goenergy = (-inf, 11) AND senergy = (-inf, 31200) THEN class = {1}\n",
+ "IF [gimpuls = <1253.50, inf)] AND genergy = <96260, 673155) AND seismic = {b} AND maxenergy = (-inf, 7500) AND goenergy = <-40.50, 87) AND seismoacoustic = {a} AND nbumps = (-inf, 3.50) AND senergy = (-inf, 10000) THEN class = {1}\n",
+ "IF nbumps2 = <0.50, inf) AND maxenergy = <1500, inf) AND gimpuls = <538.50, 1959) AND nbumps = (-inf, 6.50) AND senergy = (-inf, 36050) AND genergy = <61250, 662435) AND goenergy = (-inf, 96) AND nbumps3 = <0.50, 4.50) AND goimpuls = <-34, 95) THEN class = {1}\n",
+ "IF nbumps2 = <0.50, inf) AND genergy = <58310, 934630) AND goenergy = (-inf, 186) AND senergy = (-inf, 40650) AND maxenergy = <1500, inf) AND gimpuls = <538.50, inf) AND goimpuls = <-55, inf) THEN class = {1}\n",
+ "IF nbumps = <1.50, 4.50) AND nbumps2 = <0.50, 3.50) AND gimpuls = <521.50, inf) AND genergy = <58310, 799855) AND nbumps4 = (-inf, 1.50) AND senergy = <850, inf) AND goimpuls = <-39, 64.50) AND nbumps3 = (-inf, 2.50) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) AND nbumps2 = <0.50, 4.50) AND gimpuls = <521.50, inf) AND genergy = <34360, 1161025) AND goenergy = (-inf, 186) AND nbumps3 = (-inf, 6) AND maxenergy = <450, 45000) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) AND nbumps2 = <0.50, inf) AND genergy = <34880, inf) AND gimpuls = <281.50, inf) AND goenergy = (-inf, 135.50) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) AND nbumps2 = <0.50, inf) AND gimpuls = <153.50, 498) AND genergy = <18870, 33010) AND senergy = (-inf, 40500) AND goenergy = (-inf, 106.50) AND nbumps3 = (-inf, 1.50) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) AND goenergy = (-inf, 131) AND gimpuls = <176, inf) THEN class = {1}\n",
+ "IF gimpuls = <1253.50, inf) AND goenergy = (-inf, 131.50) AND genergy = <54930, 1062020) AND shift = {W} AND goimpuls = <-60.50, 109) AND senergy = (-inf, 36050) AND nbumps2 = (-inf, 2.50) THEN class = {1}\n",
+ "IF nbumps2 = <0.50, inf) AND gimpuls = <98.50, inf) AND goimpuls = <-70.50, inf) AND maxenergy = <550, inf) THEN class = {1}\n",
+ "IF goimpuls = <-74.50, inf) AND gimpuls = <32.50, inf) AND goenergy = <-78.50, inf) AND senergy = <850, inf) THEN class = {1}\n",
+ "IF genergy = <48545, inf) AND gimpuls = <131, inf) AND goenergy = (-inf, 176.50) THEN class = {1}\n",
+ "IF shift = {W} AND genergy = <32795, 49585) AND gimpuls = <396, 1445.50) AND goimpuls = <-19, inf) AND senergy = (-inf, 350) AND goenergy = <-4, inf) THEN class = {1}\n",
+ "IF genergy = <16805, 32020) AND gimpuls = <537.50, 796) AND goimpuls = <-36.50, inf) AND goenergy = <-37.50, inf) AND senergy = (-inf, 250) THEN class = {1}\n",
+ "IF shift = {W} AND genergy = <19670, 40735) AND gimpuls = <240, 470.50) AND goenergy = <-37.50, 181) AND goimpuls = <-42.50, inf) THEN class = {1}\n",
+ "IF gimpuls = <54.50, inf) AND senergy = (-inf, 115450) AND goimpuls = <-74.50, inf) AND genergy = <1510, inf) THEN class = {1}\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Regression"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Load dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "REGRESSION_DATSET_URL: str = (\n",
+ " 'https://raw.githubusercontent.com/'\n",
+ " 'adaa-polsl/RuleKit/master/data/methane/'\n",
+ " 'methane-train.arff'\n",
+ ")\n",
+ "df: pd.DataFrame = read_arff(REGRESSION_DATSET_URL)\n",
+ "X, y = df.drop(['MM116_pred'], axis=1), df['MM116_pred']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " MM31 \n",
+ " MM116 \n",
+ " AS038 \n",
+ " PG072 \n",
+ " PD \n",
+ " BA13 \n",
+ " DMM116 \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 0.46 \n",
+ " 1.3 \n",
+ " 2.4 \n",
+ " 2.0 \n",
+ " 1.0 \n",
+ " 1076.0 \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 0.46 \n",
+ " 1.3 \n",
+ " 2.2 \n",
+ " 1.9 \n",
+ " 1.0 \n",
+ " 1076.0 \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " 0.49 \n",
+ " 1.3 \n",
+ " 2.2 \n",
+ " 1.9 \n",
+ " 1.0 \n",
+ " 1076.0 \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " 0.50 \n",
+ " 1.3 \n",
+ " 2.3 \n",
+ " 1.9 \n",
+ " 1.0 \n",
+ " 1076.0 \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " 0.54 \n",
+ " 1.3 \n",
+ " 2.3 \n",
+ " 1.9 \n",
+ " 1.0 \n",
+ " 1076.0 \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 13363 \n",
+ " 0.64 \n",
+ " 1.2 \n",
+ " 2.4 \n",
+ " 1.8 \n",
+ " 1.0 \n",
+ " 1077.0 \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ " 13364 \n",
+ " 0.59 \n",
+ " 1.2 \n",
+ " 2.4 \n",
+ " 1.8 \n",
+ " 1.0 \n",
+ " 1077.0 \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ " 13365 \n",
+ " 0.60 \n",
+ " 1.1 \n",
+ " 2.2 \n",
+ " 1.8 \n",
+ " 1.0 \n",
+ " 1077.0 \n",
+ " -0.1 \n",
+ " \n",
+ " \n",
+ " 13366 \n",
+ " 0.64 \n",
+ " 1.1 \n",
+ " 2.2 \n",
+ " 1.8 \n",
+ " 1.0 \n",
+ " 1077.0 \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ " 13367 \n",
+ " 0.65 \n",
+ " 1.2 \n",
+ " 2.2 \n",
+ " 1.7 \n",
+ " 0.0 \n",
+ " 1077.0 \n",
+ " 0.1 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
13368 rows × 7 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " MM31 MM116 AS038 PG072 PD BA13 DMM116\n",
+ "0 0.46 1.3 2.4 2.0 1.0 1076.0 0.0\n",
+ "1 0.46 1.3 2.2 1.9 1.0 1076.0 0.0\n",
+ "2 0.49 1.3 2.2 1.9 1.0 1076.0 0.0\n",
+ "3 0.50 1.3 2.3 1.9 1.0 1076.0 0.0\n",
+ "4 0.54 1.3 2.3 1.9 1.0 1076.0 0.0\n",
+ "... ... ... ... ... ... ... ...\n",
+ "13363 0.64 1.2 2.4 1.8 1.0 1077.0 0.0\n",
+ "13364 0.59 1.2 2.4 1.8 1.0 1077.0 0.0\n",
+ "13365 0.60 1.1 2.2 1.8 1.0 1077.0 -0.1\n",
+ "13366 0.64 1.1 2.2 1.8 1.0 1077.0 0.0\n",
+ "13367 0.65 1.2 2.2 1.7 0.0 1077.0 0.1\n",
+ "\n",
+ "[13368 rows x 7 columns]"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "X"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Define rules and conditions"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "expert_preferred_conditions = [\n",
+ " (\n",
+ " 'preferred-condition-0',\n",
+ " '3: IF PD = <0.5, inf) THEN'\n",
+ " ),\n",
+ " (\n",
+ " 'preferred-condition-1',\n",
+ " '5: IF PD = <0.5, inf) AND MM116 = (-inf, 1.0) THEN'\n",
+ " )\n",
+ "]\n",
+ "\n",
+ "expert_forbidden_conditions = [\n",
+ " ('forb-attribute-0', 'inf: IF DMM116 = Any THEN')\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Rule induction"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from rulekit.regression import ExpertRuleRegressor\n",
+ "from rulekit.rules import RegressionRule\n",
+ "from rulekit.exceptions import RuleKitJavaException\n",
+ "\n",
+ "reg = ExpertRuleRegressor(\n",
+ " minsupp_new=5,\n",
+ " max_growing=0,\n",
+ " mean_based_regression=True,\n",
+ " extend_using_preferred=True,\n",
+ " extend_using_automatic=False,\n",
+ " induce_using_preferred=True,\n",
+ " induce_using_automatic=True\n",
+ ")\n",
+ "reg.fit(\n",
+ " X, y,\n",
+ " expert_preferred_conditions=expert_preferred_conditions,\n",
+ " expert_forbidden_conditions=expert_forbidden_conditions,\n",
+ ")\n",
+ "\n",
+ "ruleset: RuleSet[RegressionRule] = reg.model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF [PD = <0.50, inf)] AND PG072 = (-inf, 2.05) THEN MM116_pred = {1.01} [0.77,1.25]\n",
+ "IF [PD = <0.50, inf)] THEN MM116_pred = {1.01} [0.77,1.25]\n",
+ "IF MM31 = (-inf, 0.23) THEN MM116_pred = {0.40} [0.39,0.41]\n",
+ "IF MM116 = (-inf, 0.45) AND MM31 = <0.18, 0.24) THEN MM116_pred = {0.40} [0.38,0.42]\n",
+ "IF MM31 = (-inf, 0.25) THEN MM116_pred = {0.44} [0.37,0.51]\n",
+ "IF MM116 = <0.25, inf) AND AS038 = <2, 2.45) AND PD = (-inf, 0.50) AND PG072 = (-inf, 1.95) AND BA13 = (-inf, 1075.50) AND MM31 = <0.23, inf) THEN MM116_pred = {0.71} [0.50,0.93]\n",
+ "IF MM116 = (-inf, 0.25) AND BA13 = (-inf, 1075.50) AND MM31 = <0.19, inf) AND AS038 = <2.35, 2.45) AND PG072 = <1.75, 1.95) AND PD = (-inf, 0.50) THEN MM116_pred = {0.25} [0.20,0.30]\n",
+ "IF MM116 = (-inf, 0.45) AND BA13 = (-inf, 1077.50) AND MM31 = <0.18, inf) THEN MM116_pred = {0.40} [0.37,0.43]\n",
+ "IF MM116 = (-inf, 0.55) AND MM31 = (-inf, 0.32) THEN MM116_pred = {0.45} [0.39,0.51]\n",
+ "IF MM116 = <0.45, 0.65) THEN MM116_pred = {0.55} [0.49,0.61]\n",
+ "IF MM31 = <0.18, 0.27) AND MM116 = (-inf, 0.75) THEN MM116_pred = {0.46} [0.39,0.53]\n",
+ "IF MM116 = <0.45, 0.85) AND MM31 = <0.25, inf) THEN MM116_pred = {0.70} [0.56,0.84]\n",
+ "IF MM116 = <0.75, inf) THEN MM116_pred = {1.01} [0.82,1.19]\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Survival"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Load dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "SURVIVAL_DATASET_URL: str = (\n",
+ " 'https://raw.githubusercontent.com/'\n",
+ " 'adaa-polsl/RuleKit/master/data/bmt/'\n",
+ " 'bmt.arff'\n",
+ ")\n",
+ "df: pd.DataFrame = read_arff(SURVIVAL_DATASET_URL)\n",
+ "df['survival_status'] = df['survival_status'].astype(int).astype(str)\n",
+ "\n",
+ "\n",
+ "X, y = df.drop(['survival_status'], axis=1), df['survival_status']"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Define rules and conditions"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "expert_rules = [\n",
+ " (\n",
+ " 'rule-0',\n",
+ " 'IF [[CD34kgx10d6 = (-inf, 10.0)]] AND [[extcGvHD = {0}]] THEN'\n",
+ " )\n",
+ "]\n",
+ "\n",
+ "expert_preferred_conditions = [\n",
+ " (\n",
+ " 'attr-preferred-0',\n",
+ " 'inf: IF [CD34kgx10d6 = Any] THEN'\n",
+ " )\n",
+ "]\n",
+ "\n",
+ "\n",
+ "expert_forbidden_conditions = [\n",
+ " ('attr-forbidden-0', 'IF [ANCrecovery = Any] THEN')\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Rule induction"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from rulekit.survival import ExpertSurvivalRules\n",
+ "from rulekit.rules import SurvivalRule\n",
+ "\n",
+ "srv = ExpertSurvivalRules(\n",
+ " survival_time_attr='survival_time',\n",
+ " minsupp_new=5,\n",
+ " max_growing=0,\n",
+ " extend_using_preferred=False,\n",
+ " extend_using_automatic=False,\n",
+ " induce_using_preferred=True,\n",
+ " induce_using_automatic=True\n",
+ ")\n",
+ "srv.fit(\n",
+ " X, y,\n",
+ " expert_rules=expert_rules,\n",
+ " expert_preferred_conditions=expert_preferred_conditions,\n",
+ " expert_forbidden_conditions=expert_forbidden_conditions\n",
+ ")\n",
+ "ruleset: RuleSet[SurvivalRule] = srv.model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF [[CD34kgx10d6 = (-inf, 10)]] AND [[extcGvHD = {0}]] THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND PLTrecovery = <500142.50, inf) THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND Recipientage = <17.85, inf) AND RecipientRh = {1} THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND PLTrecovery = <26, inf) AND Recipientage = <14.30, inf) AND Relapse = {0} THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND PLTrecovery = <26, inf) AND Recipientage = <12, 18.85) AND Gendermatch = {0} AND Donorage = (-inf, 40.64) THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND CD3dCD34 = (-inf, 10.97) AND Donorage = (-inf, 49.19) AND PLTrecovery = (-inf, 500142.50) AND Txpostrelapse = {0} AND extcGvHD = {1} THEN \n",
+ "IF [CD34kgx10d6 = <11.86, inf)] AND Relapse = {0} THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND RecipientRh = {1} AND CD3dCD34 = <6.64, inf) THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND Recipientageint = {2} AND CD3dCD34 = <0.94, inf) AND Donorage = <36.03, inf) THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND PLTrecovery = <22.50, inf) THEN \n",
+ "IF [CD34kgx10d6 = <11.86, inf)] THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND CD3dCD34 = <0.89, inf) AND Rbodymass = <36.50, inf) AND Recipientage = <9.20, inf) AND IIIV = {1} AND PLTrecovery = (-inf, 22.50) AND Stemcellsource = {1} THEN \n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in ruleset.rules:\n",
+ " print(rule)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "tutorials_env",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.0"
+ },
+ "orig_nbformat": 2
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/docs/serve/v2.1.24.0/_sources/rst/tutorials/regression.ipynb.txt b/docs/serve/v2.1.24.0/_sources/rst/tutorials/regression.ipynb.txt
new file mode 100644
index 0000000..95245b7
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_sources/rst/tutorials/regression.ipynb.txt
@@ -0,0 +1,1487 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Regression"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This notebook presents example usage of package for solving regression problem on `methane` dataset. You can download training dataset [here](https://raw.githubusercontent.com/adaa-polsl/RuleKit/master/data/methane/methane-train.arff) and test dataset [here](https://raw.githubusercontent.com/adaa-polsl/RuleKit/master/data/methane/methane-test.arff)\n",
+ "\n",
+ "This tutorial will cover topics such as: \n",
+ "- training model \n",
+ "- changing model hyperparameters \n",
+ "- hyperparameters tuning \n",
+ "- calculating metrics for model \n",
+ "- getting RuleKit inbuilt "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Summary of the dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "from rulekit.arff import read_arff\n",
+ "\n",
+ "\n",
+ "BASE_DATASET_URL: str = (\n",
+ " 'https://raw.githubusercontent.com/'\n",
+ " 'adaa-polsl/RuleKit/master/data/methane/'\n",
+ ")\n",
+ "TRAIN_DATASET_URL: str = BASE_DATASET_URL + 'methane-train.arff'\n",
+ "TEST_DATASET_URL: str = BASE_DATASET_URL + 'methane-test.arff'\n",
+ "\n",
+ "train_df = read_arff(TRAIN_DATASET_URL)\n",
+ "test_df = read_arff(TEST_DATASET_URL)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Train file"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Train file overview:\n",
+ "Name: methane-train\n",
+ "Objects number: 13368; Attributes number: 8\n",
+ "Basic attribute statistics:\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " MM31 \n",
+ " MM116 \n",
+ " AS038 \n",
+ " PG072 \n",
+ " PD \n",
+ " BA13 \n",
+ " DMM116 \n",
+ " MM116_pred \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " count \n",
+ " 13368.000000 \n",
+ " 13368.000000 \n",
+ " 13368.000000 \n",
+ " 13368.000000 \n",
+ " 13368.000000 \n",
+ " 13368.000000 \n",
+ " 13368.000000 \n",
+ " 13368.00000 \n",
+ " \n",
+ " \n",
+ " mean \n",
+ " 0.363960 \n",
+ " 0.775007 \n",
+ " 2.294734 \n",
+ " 1.835600 \n",
+ " 0.308573 \n",
+ " 1073.443372 \n",
+ " -0.000007 \n",
+ " 0.79825 \n",
+ " \n",
+ " \n",
+ " std \n",
+ " 0.117105 \n",
+ " 0.269366 \n",
+ " 0.142504 \n",
+ " 0.106681 \n",
+ " 0.461922 \n",
+ " 3.162811 \n",
+ " 0.043566 \n",
+ " 0.28649 \n",
+ " \n",
+ " \n",
+ " min \n",
+ " 0.170000 \n",
+ " 0.200000 \n",
+ " 1.400000 \n",
+ " 1.100000 \n",
+ " 0.000000 \n",
+ " 1067.000000 \n",
+ " -1.800000 \n",
+ " 0.20000 \n",
+ " \n",
+ " \n",
+ " 25% \n",
+ " 0.260000 \n",
+ " 0.500000 \n",
+ " 2.300000 \n",
+ " 1.800000 \n",
+ " 0.000000 \n",
+ " 1070.000000 \n",
+ " 0.000000 \n",
+ " 0.50000 \n",
+ " \n",
+ " \n",
+ " 50% \n",
+ " 0.360000 \n",
+ " 0.800000 \n",
+ " 2.300000 \n",
+ " 1.800000 \n",
+ " 0.000000 \n",
+ " 1075.000000 \n",
+ " 0.000000 \n",
+ " 0.80000 \n",
+ " \n",
+ " \n",
+ " 75% \n",
+ " 0.450000 \n",
+ " 1.000000 \n",
+ " 2.400000 \n",
+ " 1.900000 \n",
+ " 1.000000 \n",
+ " 1076.000000 \n",
+ " 0.000000 \n",
+ " 1.00000 \n",
+ " \n",
+ " \n",
+ " max \n",
+ " 0.820000 \n",
+ " 2.200000 \n",
+ " 2.700000 \n",
+ " 2.600000 \n",
+ " 1.000000 \n",
+ " 1078.000000 \n",
+ " 0.800000 \n",
+ " 2.20000 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " MM31 MM116 AS038 PG072 PD \\\n",
+ "count 13368.000000 13368.000000 13368.000000 13368.000000 13368.000000 \n",
+ "mean 0.363960 0.775007 2.294734 1.835600 0.308573 \n",
+ "std 0.117105 0.269366 0.142504 0.106681 0.461922 \n",
+ "min 0.170000 0.200000 1.400000 1.100000 0.000000 \n",
+ "25% 0.260000 0.500000 2.300000 1.800000 0.000000 \n",
+ "50% 0.360000 0.800000 2.300000 1.800000 0.000000 \n",
+ "75% 0.450000 1.000000 2.400000 1.900000 1.000000 \n",
+ "max 0.820000 2.200000 2.700000 2.600000 1.000000 \n",
+ "\n",
+ " BA13 DMM116 MM116_pred \n",
+ "count 13368.000000 13368.000000 13368.00000 \n",
+ "mean 1073.443372 -0.000007 0.79825 \n",
+ "std 3.162811 0.043566 0.28649 \n",
+ "min 1067.000000 -1.800000 0.20000 \n",
+ "25% 1070.000000 0.000000 0.50000 \n",
+ "50% 1075.000000 0.000000 0.80000 \n",
+ "75% 1076.000000 0.000000 1.00000 \n",
+ "max 1078.000000 0.800000 2.20000 "
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "print(\"Train file overview:\")\n",
+ "print(f\"Name: methane-train\")\n",
+ "print(f\"Objects number: {train_df.shape[0]}; Attributes number: {train_df.shape[1]}\")\n",
+ "print(\"Basic attribute statistics:\")\n",
+ "train_df.describe()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Test file"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Test file overview:\n",
+ "Name: methane-test\n",
+ "Objects number: 5728; Attributes number: 8\n",
+ "Basic attribute statistics:\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " MM31 \n",
+ " MM116 \n",
+ " AS038 \n",
+ " PG072 \n",
+ " PD \n",
+ " BA13 \n",
+ " DMM116 \n",
+ " MM116_pred \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " count \n",
+ " 5728.000000 \n",
+ " 5728.000000 \n",
+ " 5728.000000 \n",
+ " 5728.000000 \n",
+ " 5728.000000 \n",
+ " 5728.000000 \n",
+ " 5728.000000 \n",
+ " 5728.000000 \n",
+ " \n",
+ " \n",
+ " mean \n",
+ " 0.556652 \n",
+ " 1.006913 \n",
+ " 2.236627 \n",
+ " 1.819239 \n",
+ " 0.538408 \n",
+ " 1072.691690 \n",
+ " -0.000017 \n",
+ " 1.042458 \n",
+ " \n",
+ " \n",
+ " std \n",
+ " 0.114682 \n",
+ " 0.167983 \n",
+ " 0.104913 \n",
+ " 0.078865 \n",
+ " 0.498566 \n",
+ " 2.799559 \n",
+ " 0.046849 \n",
+ " 0.171393 \n",
+ " \n",
+ " \n",
+ " min \n",
+ " 0.350000 \n",
+ " 0.500000 \n",
+ " 1.800000 \n",
+ " 1.600000 \n",
+ " 0.000000 \n",
+ " 1067.000000 \n",
+ " -0.400000 \n",
+ " 0.600000 \n",
+ " \n",
+ " \n",
+ " 25% \n",
+ " 0.460000 \n",
+ " 0.900000 \n",
+ " 2.200000 \n",
+ " 1.800000 \n",
+ " 0.000000 \n",
+ " 1071.000000 \n",
+ " 0.000000 \n",
+ " 0.900000 \n",
+ " \n",
+ " \n",
+ " 50% \n",
+ " 0.550000 \n",
+ " 1.000000 \n",
+ " 2.200000 \n",
+ " 1.800000 \n",
+ " 1.000000 \n",
+ " 1073.000000 \n",
+ " 0.000000 \n",
+ " 1.000000 \n",
+ " \n",
+ " \n",
+ " 75% \n",
+ " 0.640000 \n",
+ " 1.100000 \n",
+ " 2.300000 \n",
+ " 1.900000 \n",
+ " 1.000000 \n",
+ " 1075.000000 \n",
+ " 0.000000 \n",
+ " 1.200000 \n",
+ " \n",
+ " \n",
+ " max \n",
+ " 0.980000 \n",
+ " 1.600000 \n",
+ " 2.700000 \n",
+ " 2.100000 \n",
+ " 1.000000 \n",
+ " 1078.000000 \n",
+ " 0.300000 \n",
+ " 1.600000 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " MM31 MM116 AS038 PG072 PD \\\n",
+ "count 5728.000000 5728.000000 5728.000000 5728.000000 5728.000000 \n",
+ "mean 0.556652 1.006913 2.236627 1.819239 0.538408 \n",
+ "std 0.114682 0.167983 0.104913 0.078865 0.498566 \n",
+ "min 0.350000 0.500000 1.800000 1.600000 0.000000 \n",
+ "25% 0.460000 0.900000 2.200000 1.800000 0.000000 \n",
+ "50% 0.550000 1.000000 2.200000 1.800000 1.000000 \n",
+ "75% 0.640000 1.100000 2.300000 1.900000 1.000000 \n",
+ "max 0.980000 1.600000 2.700000 2.100000 1.000000 \n",
+ "\n",
+ " BA13 DMM116 MM116_pred \n",
+ "count 5728.000000 5728.000000 5728.000000 \n",
+ "mean 1072.691690 -0.000017 1.042458 \n",
+ "std 2.799559 0.046849 0.171393 \n",
+ "min 1067.000000 -0.400000 0.600000 \n",
+ "25% 1071.000000 0.000000 0.900000 \n",
+ "50% 1073.000000 0.000000 1.000000 \n",
+ "75% 1075.000000 0.000000 1.200000 \n",
+ "max 1078.000000 0.300000 1.600000 "
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "print(\"\\nTest file overview:\")\n",
+ "print(f\"Name: methane-test\")\n",
+ "print(f\"Objects number: {test_df.shape[0]}; Attributes number: {test_df.shape[1]}\")\n",
+ "print(\"Basic attribute statistics:\")\n",
+ "test_df.describe()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Helper function for calculating metrics"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sklearn import metrics\n",
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "from math import sqrt\n",
+ "\n",
+ "\n",
+ "def get_regression_metrics(measure: str, y_pred, y_true) -> pd.DataFrame:\n",
+ " relative_error = 0\n",
+ " squared_relative_error = 0\n",
+ " relative_error_lenient = 0\n",
+ " relative_error_strict = 0\n",
+ " nae_denominator = 0\n",
+ " avg = sum(y_true) / len(y_pred)\n",
+ "\n",
+ " for i in range(0, len(y_pred)):\n",
+ " true = y_true[i]\n",
+ " predicted = y_pred[i]\n",
+ "\n",
+ " relative_error += abs((true - predicted) / true)\n",
+ " squared_relative_error += (\n",
+ " abs((true - predicted) / true) *\n",
+ " abs((true - predicted) / true)\n",
+ " )\n",
+ " relative_error_lenient += (\n",
+ " abs((true - predicted) / max(true, predicted))\n",
+ " )\n",
+ " relative_error_strict += abs((true - predicted) / min(true, predicted))\n",
+ " nae_denominator += abs(avg - true)\n",
+ "\n",
+ " relative_error /= len(y_pred)\n",
+ " squared_relative_error /= len(y_pred)\n",
+ " relative_error_lenient /= len(y_pred)\n",
+ " relative_error_strict /= len(y_pred)\n",
+ " nae_denominator /= len(y_pred)\n",
+ " correlation = np.mean(np.corrcoef(y_true, y_pred))\n",
+ "\n",
+ " dictionary = {\n",
+ " 'Measure': measure,\n",
+ " 'absolute_error': metrics.mean_absolute_error(y_true, y_pred),\n",
+ " 'relative_error': relative_error,\n",
+ " 'relative_error_lenient': relative_error_lenient,\n",
+ " 'relative_error_strict': relative_error_strict,\n",
+ " 'normalized_absolute_error': metrics.mean_absolute_error(y_true, y_pred) / nae_denominator,\n",
+ " 'squared_error': metrics.mean_squared_error(y_true, y_pred),\n",
+ " 'root_mean_squared_error': metrics.mean_squared_error(y_true, y_pred, squared=False),\n",
+ " 'root_relative_squared_error': sqrt(squared_relative_error),\n",
+ " 'correlation': correlation,\n",
+ " 'squared_correlation': np.power(correlation, 2),\n",
+ " }\n",
+ " return pd.DataFrame.from_records([dictionary], index='Measure')\n",
+ "\n",
+ "\n",
+ "def get_ruleset_stats(measure: str, model) -> pd.DataFrame:\n",
+ " tmp = model.parameters.__dict__\n",
+ " del tmp['_java_object']\n",
+ " return pd.DataFrame.from_records(\n",
+ " [{'Measure': measure, **tmp, **model.stats.__dict__}],\n",
+ " index='Measure'\n",
+ " )"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Rule induction on training dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "X_train: pd.DataFrame = train_df.drop(['MM116_pred'], axis=1)\n",
+ "y_train: pd.Series = train_df['MM116_pred']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "c:\\Users\\cezar\\OneDrive\\Pulpit\\EMAG\\GIT\\PythonRulekit\\tutorials_env\\Lib\\site-packages\\sklearn\\metrics\\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.\n",
+ " warnings.warn(\n",
+ "c:\\Users\\cezar\\OneDrive\\Pulpit\\EMAG\\GIT\\PythonRulekit\\tutorials_env\\Lib\\site-packages\\sklearn\\metrics\\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.\n",
+ " warnings.warn(\n",
+ "c:\\Users\\cezar\\OneDrive\\Pulpit\\EMAG\\GIT\\PythonRulekit\\tutorials_env\\Lib\\site-packages\\sklearn\\metrics\\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.\n",
+ " warnings.warn(\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " minimum_covered \n",
+ " maximum_uncovered_fraction \n",
+ " ignore_missing \n",
+ " pruning_enabled \n",
+ " max_growing_condition \n",
+ " time_total_s \n",
+ " time_growing_s \n",
+ " time_pruning_s \n",
+ " rules_count \n",
+ " conditions_per_rule \n",
+ " induced_conditions_per_rule \n",
+ " avg_rule_coverage \n",
+ " avg_rule_precision \n",
+ " avg_rule_quality \n",
+ " pvalue \n",
+ " FDR_pvalue \n",
+ " FWER_pvalue \n",
+ " fraction_significant \n",
+ " fraction_FDR_significant \n",
+ " fraction_FWER_significant \n",
+ " \n",
+ " \n",
+ " Measure \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " C2 \n",
+ " 0.05 \n",
+ " 0.0 \n",
+ " False \n",
+ " True \n",
+ " 0.0 \n",
+ " 27.670397 \n",
+ " 1.978997 \n",
+ " 25.637769 \n",
+ " 11 \n",
+ " 3.272727 \n",
+ " 33.727273 \n",
+ " 0.345683 \n",
+ " 0.874767 \n",
+ " 0.732356 \n",
+ " 1.612636e-177 \n",
+ " 1.612636e-177 \n",
+ " 1.612636e-177 \n",
+ " 1.0 \n",
+ " 1.0 \n",
+ " 1.0 \n",
+ " \n",
+ " \n",
+ " Correlation \n",
+ " 0.05 \n",
+ " 0.0 \n",
+ " False \n",
+ " True \n",
+ " 0.0 \n",
+ " 17.739791 \n",
+ " 0.836199 \n",
+ " 16.871719 \n",
+ " 7 \n",
+ " 2.714286 \n",
+ " 35.285714 \n",
+ " 0.334990 \n",
+ " 0.862965 \n",
+ " 0.800819 \n",
+ " 3.046280e-37 \n",
+ " 3.046280e-37 \n",
+ " 3.046280e-37 \n",
+ " 1.0 \n",
+ " 1.0 \n",
+ " 1.0 \n",
+ " \n",
+ " \n",
+ " RSS \n",
+ " 0.05 \n",
+ " 0.0 \n",
+ " False \n",
+ " True \n",
+ " 0.0 \n",
+ " 34.929544 \n",
+ " 1.020750 \n",
+ " 33.894867 \n",
+ " 6 \n",
+ " 2.333333 \n",
+ " 38.166667 \n",
+ " 0.417440 \n",
+ " 0.855115 \n",
+ " 0.786208 \n",
+ " 6.242568e-40 \n",
+ " 6.242568e-40 \n",
+ " 6.242568e-40 \n",
+ " 1.0 \n",
+ " 1.0 \n",
+ " 1.0 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " minimum_covered maximum_uncovered_fraction ignore_missing \\\n",
+ "Measure \n",
+ "C2 0.05 0.0 False \n",
+ "Correlation 0.05 0.0 False \n",
+ "RSS 0.05 0.0 False \n",
+ "\n",
+ " pruning_enabled max_growing_condition time_total_s \\\n",
+ "Measure \n",
+ "C2 True 0.0 27.670397 \n",
+ "Correlation True 0.0 17.739791 \n",
+ "RSS True 0.0 34.929544 \n",
+ "\n",
+ " time_growing_s time_pruning_s rules_count conditions_per_rule \\\n",
+ "Measure \n",
+ "C2 1.978997 25.637769 11 3.272727 \n",
+ "Correlation 0.836199 16.871719 7 2.714286 \n",
+ "RSS 1.020750 33.894867 6 2.333333 \n",
+ "\n",
+ " induced_conditions_per_rule avg_rule_coverage \\\n",
+ "Measure \n",
+ "C2 33.727273 0.345683 \n",
+ "Correlation 35.285714 0.334990 \n",
+ "RSS 38.166667 0.417440 \n",
+ "\n",
+ " avg_rule_precision avg_rule_quality pvalue \\\n",
+ "Measure \n",
+ "C2 0.874767 0.732356 1.612636e-177 \n",
+ "Correlation 0.862965 0.800819 3.046280e-37 \n",
+ "RSS 0.855115 0.786208 6.242568e-40 \n",
+ "\n",
+ " FDR_pvalue FWER_pvalue fraction_significant \\\n",
+ "Measure \n",
+ "C2 1.612636e-177 1.612636e-177 1.0 \n",
+ "Correlation 3.046280e-37 3.046280e-37 1.0 \n",
+ "RSS 6.242568e-40 6.242568e-40 1.0 \n",
+ "\n",
+ " fraction_FDR_significant fraction_FWER_significant \n",
+ "Measure \n",
+ "C2 1.0 1.0 \n",
+ "Correlation 1.0 1.0 \n",
+ "RSS 1.0 1.0 "
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " absolute_error \n",
+ " relative_error \n",
+ " relative_error_lenient \n",
+ " relative_error_strict \n",
+ " normalized_absolute_error \n",
+ " squared_error \n",
+ " root_mean_squared_error \n",
+ " root_relative_squared_error \n",
+ " correlation \n",
+ " squared_correlation \n",
+ " \n",
+ " \n",
+ " Measure \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " C2 \n",
+ " 0.089929 \n",
+ " 0.114526 \n",
+ " 0.101069 \n",
+ " 0.125935 \n",
+ " 0.382694 \n",
+ " 0.019753 \n",
+ " 0.140547 \n",
+ " 0.167429 \n",
+ " 0.937881 \n",
+ " 0.879620 \n",
+ " \n",
+ " \n",
+ " Correlation \n",
+ " 0.088561 \n",
+ " 0.112319 \n",
+ " 0.099635 \n",
+ " 0.125846 \n",
+ " 0.376872 \n",
+ " 0.020912 \n",
+ " 0.144609 \n",
+ " 0.184988 \n",
+ " 0.941044 \n",
+ " 0.885563 \n",
+ " \n",
+ " \n",
+ " RSS \n",
+ " 0.092552 \n",
+ " 0.111375 \n",
+ " 0.102026 \n",
+ " 0.124544 \n",
+ " 0.393860 \n",
+ " 0.020544 \n",
+ " 0.143331 \n",
+ " 0.153866 \n",
+ " 0.945779 \n",
+ " 0.894498 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " absolute_error relative_error relative_error_lenient \\\n",
+ "Measure \n",
+ "C2 0.089929 0.114526 0.101069 \n",
+ "Correlation 0.088561 0.112319 0.099635 \n",
+ "RSS 0.092552 0.111375 0.102026 \n",
+ "\n",
+ " relative_error_strict normalized_absolute_error squared_error \\\n",
+ "Measure \n",
+ "C2 0.125935 0.382694 0.019753 \n",
+ "Correlation 0.125846 0.376872 0.020912 \n",
+ "RSS 0.124544 0.393860 0.020544 \n",
+ "\n",
+ " root_mean_squared_error root_relative_squared_error \\\n",
+ "Measure \n",
+ "C2 0.140547 0.167429 \n",
+ "Correlation 0.144609 0.184988 \n",
+ "RSS 0.143331 0.153866 \n",
+ "\n",
+ " correlation squared_correlation \n",
+ "Measure \n",
+ "C2 0.937881 0.879620 \n",
+ "Correlation 0.941044 0.885563 \n",
+ "RSS 0.945779 0.894498 "
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "from rulekit.regression import RuleRegressor\n",
+ "from rulekit.rules import RuleSet, RegressionRule\n",
+ "from rulekit.params import Measures\n",
+ "\n",
+ "# C2\n",
+ "c2_reg = RuleRegressor(\n",
+ " induction_measure=Measures.C2,\n",
+ " pruning_measure=Measures.C2,\n",
+ " voting_measure=Measures.C2,\n",
+ ")\n",
+ "c2_reg.fit(X_train, y_train)\n",
+ "c2_ruleset: RuleSet[RegressionRule] = c2_reg.model\n",
+ "predictions: np.ndarray = c2_reg.predict(X_train)\n",
+ "\n",
+ "regression_metrics = get_regression_metrics('C2', predictions, y_train)\n",
+ "ruleset_stats = get_ruleset_stats('C2', c2_ruleset)\n",
+ "\n",
+ "\n",
+ "# Correlation\n",
+ "corr_reg = RuleRegressor(\n",
+ " induction_measure=Measures.Correlation,\n",
+ " pruning_measure=Measures.Correlation,\n",
+ " voting_measure=Measures.Correlation,\n",
+ " mean_based_regression=True\n",
+ ")\n",
+ "corr_reg.fit(X_train, y_train)\n",
+ "corr_ruleset: RuleSet[RegressionRule] = corr_reg.model\n",
+ "predictions: np.ndarray = corr_reg.predict(X_train)\n",
+ "\n",
+ "tmp = get_regression_metrics('Correlation', predictions, y_train)\n",
+ "regression_metrics = pd.concat([regression_metrics, tmp])\n",
+ "ruleset_stats = pd.concat([ruleset_stats, get_ruleset_stats('Correlation', corr_ruleset)])\n",
+ "\n",
+ "\n",
+ "# RSS\n",
+ "rss_reg = RuleRegressor(\n",
+ " induction_measure=Measures.RSS,\n",
+ " pruning_measure=Measures.RSS,\n",
+ " voting_measure=Measures.RSS,\n",
+ " mean_based_regression=True\n",
+ ")\n",
+ "rss_reg.fit(X_train, y_train)\n",
+ "rss_ruleset: RuleSet[RegressionRule] = rss_reg.model\n",
+ "predictions: np.ndarray = rss_reg.predict(X_train)\n",
+ "\n",
+ "tmp = get_regression_metrics('RSS', predictions, y_train)\n",
+ "regression_metrics = pd.concat([regression_metrics, tmp])\n",
+ "ruleset_stats = pd.concat([ruleset_stats, get_ruleset_stats('RSS', rss_ruleset)])\n",
+ "\n",
+ "\n",
+ "display(ruleset_stats)\n",
+ "display(regression_metrics)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### C2 Measure generated rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF MM116 = <0.35, 0.45) AND MM31 = (-inf, 0.24) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.40} [0.39,0.42]\n",
+ "IF MM116 = (-inf, 0.55) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.45} [0.39,0.52]\n",
+ "IF MM31 = <0.19, 0.30) AND MM116 = (-inf, 0.95) AND AS038 = (-inf, 2.45) AND PG072 = <1.55, inf) AND DMM116 = (-inf, 0.15) THEN MM116_pred = {0.50} [0.38,0.61]\n",
+ "IF MM116 = <1.05, 1.35) AND MM31 = <0.28, inf) THEN MM116_pred = {1.19} [1.08,1.31]\n",
+ "IF MM116 = <0.95, 1.25) AND DMM116 = (-inf, 0.40) THEN MM116_pred = {1.11} [0.99,1.22]\n",
+ "IF MM116 = <0.85, 1.15) AND DMM116 = <-0.35, 0.25) THEN MM116_pred = {1.00} [0.89,1.12]\n",
+ "IF MM31 = (-inf, 0.34) AND MM116 = (-inf, 0.85) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.53} [0.39,0.66]\n",
+ "IF MM31 = <0.18, 0.37) AND AS038 = <2.15, 2.55) AND DMM116 = <-0.15, 0.05) AND MM116 = <0.25, 0.85) AND PG072 = <1.55, inf) AND BA13 = <1070.50, inf) THEN MM116_pred = {0.55} [0.40,0.70]\n",
+ "IF MM116 = <0.75, 1.05) AND DMM116 = <-0.15, 0.15) AND PG072 = (-inf, 2.05) AND MM31 = (-inf, 0.53) AND BA13 = (-inf, 1073.50) THEN MM116_pred = {0.91} [0.80,1.02]\n",
+ "IF MM116 = <0.65, 1.45) AND MM31 = (-inf, 0.67) AND DMM116 = <-0.35, 0.25) AND PG072 = (-inf, 2.35) THEN MM116_pred = {0.96} [0.78,1.14]\n",
+ "IF MM31 = <0.28, 0.76) AND PG072 = (-inf, 2.35) THEN MM116_pred = {0.93} [0.70,1.16]\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in c2_ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Correlation Measure generated rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF MM116 = (-inf, 0.45) AND MM31 = <0.18, 0.24) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.40} [0.38,0.42]\n",
+ "IF MM116 = (-inf, 0.55) AND MM31 = (-inf, 0.32) THEN MM116_pred = {0.45} [0.39,0.51]\n",
+ "IF MM31 = <0.18, 0.31) AND MM116 = (-inf, 0.85) AND AS038 = (-inf, 2.55) AND PG072 = <1.55, inf) AND DMM116 = <-0.30, 0.15) THEN MM116_pred = {0.50} [0.39,0.60]\n",
+ "IF MM116 = <1.05, 1.35) THEN MM116_pred = {1.19} [1.08,1.31]\n",
+ "IF MM116 = <0.85, 1.15) AND DMM116 = <-0.35, inf) THEN MM116_pred = {1.00} [0.89,1.12]\n",
+ "IF MM116 = <0.45, 0.85) AND DMM116 = <-0.15, inf) AND PG072 = <1.55, inf) AND MM31 = <0.31, inf) THEN MM116_pred = {0.77} [0.66,0.88]\n",
+ "IF MM31 = <0.23, inf) AND PG072 = (-inf, 2.35) THEN MM116_pred = {0.85} [0.59,1.11]\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in corr_ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### RSS Measure generated rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF MM116 = (-inf, 0.45) AND MM31 = <0.18, 0.25) AND PG072 = (-inf, 2.05) THEN MM116_pred = {0.40} [0.38,0.43]\n",
+ "IF MM116 = (-inf, 0.55) AND DMM116 = <-0.15, inf) THEN MM116_pred = {0.45} [0.39,0.52]\n",
+ "IF MM116 = <0.45, 0.75) THEN MM116_pred = {0.60} [0.49,0.71]\n",
+ "IF DMM116 = <-0.35, inf) AND MM31 = <0.31, inf) AND MM116 = (-inf, 1.05) THEN MM116_pred = {0.87} [0.72,1.02]\n",
+ "IF MM116 = <0.85, 1.45) AND DMM116 = <-0.50, inf) THEN MM116_pred = {1.05} [0.90,1.21]\n",
+ "IF MM31 = <0.23, inf) AND MM116 = <0.25, inf) AND PG072 = (-inf, 2.35) THEN MM116_pred = {0.85} [0.59,1.11]\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in rss_ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Evaluation on a test set"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "X_test = test_df.drop(['MM116_pred'], axis=1)\n",
+ "y_test = test_df['MM116_pred']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "c:\\Users\\cezar\\OneDrive\\Pulpit\\EMAG\\GIT\\PythonRulekit\\tutorials_env\\Lib\\site-packages\\sklearn\\metrics\\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.\n",
+ " warnings.warn(\n",
+ "c:\\Users\\cezar\\OneDrive\\Pulpit\\EMAG\\GIT\\PythonRulekit\\tutorials_env\\Lib\\site-packages\\sklearn\\metrics\\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.\n",
+ " warnings.warn(\n",
+ "c:\\Users\\cezar\\OneDrive\\Pulpit\\EMAG\\GIT\\PythonRulekit\\tutorials_env\\Lib\\site-packages\\sklearn\\metrics\\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.\n",
+ " warnings.warn(\n"
+ ]
+ }
+ ],
+ "source": [
+ "# C2\n",
+ "c2_predictions = c2_reg.predict(X_test)\n",
+ "c2_regression_metrics = get_regression_metrics('C2', c2_predictions, y_test)\n",
+ "\n",
+ "# Correlation\n",
+ "corr_predictions = corr_reg.predict(X_test)\n",
+ "corr_regression_metrics = get_regression_metrics('Correlation', corr_predictions, y_test)\n",
+ "\n",
+ "# RSS\n",
+ "rss_predictions = rss_reg.predict(X_test)\n",
+ "rss_regression_metrics = get_regression_metrics('RSS', rss_predictions, y_test)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " absolute_error \n",
+ " relative_error \n",
+ " relative_error_lenient \n",
+ " relative_error_strict \n",
+ " normalized_absolute_error \n",
+ " squared_error \n",
+ " root_mean_squared_error \n",
+ " root_relative_squared_error \n",
+ " correlation \n",
+ " squared_correlation \n",
+ " \n",
+ " \n",
+ " Measure \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " C2 \n",
+ " 0.107227 \n",
+ " 0.100574 \n",
+ " 0.094935 \n",
+ " 0.112747 \n",
+ " 0.739328 \n",
+ " 0.020326 \n",
+ " 0.142569 \n",
+ " 0.126236 \n",
+ " 0.835385 \n",
+ " 0.697868 \n",
+ " \n",
+ " \n",
+ " Correlation \n",
+ " 0.105350 \n",
+ " 0.091827 \n",
+ " 0.090950 \n",
+ " 0.109321 \n",
+ " 0.726385 \n",
+ " 0.021890 \n",
+ " 0.147951 \n",
+ " 0.119472 \n",
+ " 0.866898 \n",
+ " 0.751512 \n",
+ " \n",
+ " \n",
+ " RSS \n",
+ " 0.128302 \n",
+ " 0.113411 \n",
+ " 0.111947 \n",
+ " 0.134690 \n",
+ " 0.884639 \n",
+ " 0.027270 \n",
+ " 0.165136 \n",
+ " 0.134849 \n",
+ " 0.866442 \n",
+ " 0.750722 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " absolute_error relative_error relative_error_lenient \\\n",
+ "Measure \n",
+ "C2 0.107227 0.100574 0.094935 \n",
+ "Correlation 0.105350 0.091827 0.090950 \n",
+ "RSS 0.128302 0.113411 0.111947 \n",
+ "\n",
+ " relative_error_strict normalized_absolute_error squared_error \\\n",
+ "Measure \n",
+ "C2 0.112747 0.739328 0.020326 \n",
+ "Correlation 0.109321 0.726385 0.021890 \n",
+ "RSS 0.134690 0.884639 0.027270 \n",
+ "\n",
+ " root_mean_squared_error root_relative_squared_error \\\n",
+ "Measure \n",
+ "C2 0.142569 0.126236 \n",
+ "Correlation 0.147951 0.119472 \n",
+ "RSS 0.165136 0.134849 \n",
+ "\n",
+ " correlation squared_correlation \n",
+ "Measure \n",
+ "C2 0.835385 0.697868 \n",
+ "Correlation 0.866898 0.751512 \n",
+ "RSS 0.866442 0.750722 "
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(pd.concat([c2_regression_metrics, corr_regression_metrics, rss_regression_metrics]))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Hyperparameters tuning\n",
+ "\n",
+ "This one gonna take a while..."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Best RMSE: -0.191976 using {'induction_measure': , 'minsupp_new': 6, 'pruning_measure': , 'voting_measure': }\n"
+ ]
+ }
+ ],
+ "source": [
+ "from sklearn.model_selection import KFold\n",
+ "from sklearn.model_selection import GridSearchCV\n",
+ "\n",
+ "\n",
+ "# define models and parameters\n",
+ "model = RuleRegressor(mean_based_regression=True)\n",
+ "minsupp_new = range(5, 7)\n",
+ "measures_choice = [Measures.C2, Measures.Correlation, Measures.RSS]\n",
+ "\n",
+ "# define grid search\n",
+ "grid = {\n",
+ " 'minsupp_new': minsupp_new, \n",
+ " 'induction_measure': measures_choice, \n",
+ " 'pruning_measure': measures_choice, \n",
+ " 'voting_measure': measures_choice\n",
+ "}\n",
+ "cv = KFold(n_splits=2)\n",
+ "grid_search = GridSearchCV(estimator=model, param_grid=grid, cv=cv, scoring='neg_root_mean_squared_error')\n",
+ "grid_result = grid_search.fit(X_train, y_train)\n",
+ "\n",
+ "# summarize results\n",
+ "print(\"Best RMSE: %f using %s\" % (grid_result.best_score_, grid_result.best_params_))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Prediction using the model selected from the tuning"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "reg: RuleRegressor = grid_result.best_estimator_\n",
+ "ruleset: RuleSet[RegressionRule] = reg.model\n",
+ "ruleset_stats = get_ruleset_stats('', ruleset)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Generated rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF MM31 = (-inf, 0.23) THEN MM116_pred = {0.40} [0.39,0.41]\n",
+ "IF MM116 = <0.35, 0.45) AND MM31 = (-inf, 0.24) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.40} [0.39,0.42]\n",
+ "IF MM116 = <0.35, 0.45) AND MM31 = (-inf, 0.24) THEN MM116_pred = {0.40} [0.38,0.42]\n",
+ "IF MM31 = <0.24, 0.25) AND AS038 = (-inf, 2.45) AND DMM116 = <-0.05, inf) AND PD = (-inf, 0.50) THEN MM116_pred = {0.50} [0.47,0.54]\n",
+ "IF MM116 = (-inf, 0.45) AND MM31 = <0.24, 0.25) AND PG072 = (-inf, 2.05) AND AS038 = (-inf, 2.45) AND PD = <0.50, inf) THEN MM116_pred = {0.41} [0.38,0.44]\n",
+ "IF MM31 = <0.24, 0.25) AND PD = (-inf, 0.50) THEN MM116_pred = {0.51} [0.47,0.54]\n",
+ "IF MM31 = (-inf, 0.26) AND DMM116 = <-0.05, 0.05) THEN MM116_pred = {0.46} [0.36,0.55]\n",
+ "IF MM116 = (-inf, 0.45) THEN MM116_pred = {0.40} [0.37,0.44]\n",
+ "IF MM31 = <0.23, 0.24) AND BA13 = (-inf, 1075.50) AND MM116 = <0.45, inf) THEN MM116_pred = {0.50} [0.48,0.52]\n",
+ "IF MM116 = <0.45, 0.55) AND PG072 = <1.65, inf) AND DMM116 = <-0.05, inf) AND PD = (-inf, 0.50) AND MM31 = <0.23, inf) THEN MM116_pred = {0.51} [0.48,0.53]\n",
+ "IF MM116 = <0.45, 0.55) AND PG072 = <1.65, inf) AND MM31 = <0.23, 0.29) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.51} [0.48,0.53]\n",
+ "IF MM116 = <0.35, 0.55) AND MM31 = (-inf, 0.26) AND BA13 = <1077.50, inf) AND DMM116 = (-inf, -0.05) THEN MM116_pred = {0.54} [0.48,0.60]\n",
+ "IF MM116 = <0.45, 0.55) AND PG072 = <1.65, inf) AND AS038 = (-inf, 2.45) AND PD = (-inf, 0.50) AND BA13 = (-inf, 1077.50) AND MM31 = <0.23, inf) THEN MM116_pred = {0.50} [0.48,0.53]\n",
+ "IF MM116 = <0.45, 0.55) AND MM31 = <0.28, 0.30) AND DMM116 = <-0.05, 0.05) AND AS038 = <2.25, 2.35) AND PG072 = <1.75, 1.95) AND BA13 = <1075.50, 1076.50) AND PD = <0.50, inf) THEN MM116_pred = {0.55} [0.50,0.60]\n",
+ "IF MM116 = (-inf, 0.55) AND MM31 = <0.29, 0.30) AND PG072 = (-inf, 1.95) AND BA13 = (-inf, 1076.50) AND PD = <0.50, inf) THEN MM116_pred = {0.55} [0.50,0.60]\n",
+ "IF MM116 = (-inf, 0.55) THEN MM116_pred = {0.45} [0.39,0.52]\n",
+ "IF MM31 = <0.26, 0.27) AND MM116 = <0.55, 0.65) AND PG072 = <1.75, 1.85) AND AS038 = <2.25, 2.45) AND DMM116 = <-0.05, 0.05) AND PD = (-inf, 0.50) AND BA13 = <1074.50, 1077.50) THEN MM116_pred = {0.60} [NaN,NaN]\n",
+ "IF MM116 = <0.45, 0.65) AND MM31 = <0.23, inf) THEN MM116_pred = {0.55} [0.49,0.61]\n",
+ "IF MM116 = <0.55, 0.75) THEN MM116_pred = {0.67} [0.58,0.77]\n",
+ "IF MM116 = <0.75, 0.85) THEN MM116_pred = {0.83} [0.76,0.90]\n",
+ "IF MM116 = <0.85, inf) THEN MM116_pred = {1.06} [0.88,1.24]\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Ruleset evaluation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " minimum_covered \n",
+ " maximum_uncovered_fraction \n",
+ " ignore_missing \n",
+ " pruning_enabled \n",
+ " max_growing_condition \n",
+ " time_total_s \n",
+ " time_growing_s \n",
+ " time_pruning_s \n",
+ " rules_count \n",
+ " conditions_per_rule \n",
+ " induced_conditions_per_rule \n",
+ " avg_rule_coverage \n",
+ " avg_rule_precision \n",
+ " avg_rule_quality \n",
+ " pvalue \n",
+ " FDR_pvalue \n",
+ " FWER_pvalue \n",
+ " fraction_significant \n",
+ " fraction_FDR_significant \n",
+ " fraction_FWER_significant \n",
+ " \n",
+ " \n",
+ " Measure \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 6.0 \n",
+ " 0.0 \n",
+ " False \n",
+ " True \n",
+ " 0.0 \n",
+ " 12.151842 \n",
+ " 1.240354 \n",
+ " 10.883363 \n",
+ " 21 \n",
+ " 3.190476 \n",
+ " 29.809524 \n",
+ " 0.116152 \n",
+ " 0.849723 \n",
+ " NaN \n",
+ " NaN \n",
+ " NaN \n",
+ " NaN \n",
+ " 0.952381 \n",
+ " 0.952381 \n",
+ " 0.952381 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " minimum_covered maximum_uncovered_fraction ignore_missing \\\n",
+ "Measure \n",
+ " 6.0 0.0 False \n",
+ "\n",
+ " pruning_enabled max_growing_condition time_total_s time_growing_s \\\n",
+ "Measure \n",
+ " True 0.0 12.151842 1.240354 \n",
+ "\n",
+ " time_pruning_s rules_count conditions_per_rule \\\n",
+ "Measure \n",
+ " 10.883363 21 3.190476 \n",
+ "\n",
+ " induced_conditions_per_rule avg_rule_coverage avg_rule_precision \\\n",
+ "Measure \n",
+ " 29.809524 0.116152 0.849723 \n",
+ "\n",
+ " avg_rule_quality pvalue FDR_pvalue FWER_pvalue \\\n",
+ "Measure \n",
+ " NaN NaN NaN NaN \n",
+ "\n",
+ " fraction_significant fraction_FDR_significant \\\n",
+ "Measure \n",
+ " 0.952381 0.952381 \n",
+ "\n",
+ " fraction_FWER_significant \n",
+ "Measure \n",
+ " 0.952381 "
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(ruleset_stats)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Validate model on test dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "c:\\Users\\cezar\\OneDrive\\Pulpit\\EMAG\\GIT\\PythonRulekit\\tutorials_env\\Lib\\site-packages\\sklearn\\metrics\\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.\n",
+ " warnings.warn(\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "absolute_error 0.111355\n",
+ "relative_error 0.103524\n",
+ "relative_error_lenient 0.097884\n",
+ "relative_error_strict 0.114888\n",
+ "normalized_absolute_error 0.767792\n",
+ "squared_error 0.019642\n",
+ "root_mean_squared_error 0.140148\n",
+ "root_relative_squared_error 0.125609\n",
+ "correlation 0.801204\n",
+ "squared_correlation 0.641927\n",
+ "Name: , dtype: float64"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "predictions = reg.predict(X_test)\n",
+ "regression_metrics = get_regression_metrics('', predictions, y_test)\n",
+ "display(regression_metrics.iloc[0])"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "tutorials_env",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.0"
+ },
+ "metadata": {
+ "interpreter": {
+ "hash": "62266c16fff41e971c13e9cb2ad3d47e4ef45d0678714c255381eb9fdcbd7032"
+ }
+ },
+ "orig_nbformat": 2
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/docs/serve/v2.1.24.0/_sources/rst/tutorials/survival.ipynb.txt b/docs/serve/v2.1.24.0/_sources/rst/tutorials/survival.ipynb.txt
new file mode 100644
index 0000000..6d70e02
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_sources/rst/tutorials/survival.ipynb.txt
@@ -0,0 +1,1318 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "-Uy-yBGsd9W1"
+ },
+ "source": [
+ "# Survival analysis"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This notebook presents example usage of package for solving survival problem on `bmt` dataset. You can access dataset [here](https://raw.githubusercontent.com/adaa-polsl/RuleKit/master/data/bmt/bmt.arff) \n",
+ "\n",
+ "This tutorial will cover topics such as: \n",
+ "- training model \n",
+ "- changing model hyperparameters \n",
+ "- hyperparameters tuning \n",
+ "- calculating metrics for model "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Install dependencies"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%pip install matplotlib "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "KjtU7PA8eOTr"
+ },
+ "source": [
+ "## Summary of the dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "Tp1TpfCkd58n"
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " Recipientgender \n",
+ " Stemcellsource \n",
+ " Donorage \n",
+ " Donorage35 \n",
+ " IIIV \n",
+ " Gendermatch \n",
+ " DonorABO \n",
+ " RecipientABO \n",
+ " RecipientRh \n",
+ " ABOmatch \n",
+ " ... \n",
+ " extcGvHD \n",
+ " CD34kgx10d6 \n",
+ " CD3dCD34 \n",
+ " CD3dkgx10d8 \n",
+ " Rbodymass \n",
+ " ANCrecovery \n",
+ " PLTrecovery \n",
+ " time_to_aGvHD_III_IV \n",
+ " survival_time \n",
+ " survival_status \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1 \n",
+ " 1 \n",
+ " 22.830137 \n",
+ " 0 \n",
+ " 1 \n",
+ " 0 \n",
+ " 1 \n",
+ " 1 \n",
+ " 1 \n",
+ " 0 \n",
+ " ... \n",
+ " 1 \n",
+ " 7.20 \n",
+ " 1.338760 \n",
+ " 5.38 \n",
+ " 35.0 \n",
+ " 19.0 \n",
+ " 51.0 \n",
+ " 32.0 \n",
+ " 999.0 \n",
+ " 0 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 1 \n",
+ " 0 \n",
+ " 23.342466 \n",
+ " 0 \n",
+ " 1 \n",
+ " 0 \n",
+ " -1 \n",
+ " -1 \n",
+ " 1 \n",
+ " 0 \n",
+ " ... \n",
+ " 1 \n",
+ " 4.50 \n",
+ " 11.078295 \n",
+ " 0.41 \n",
+ " 20.6 \n",
+ " 16.0 \n",
+ " 37.0 \n",
+ " 1000000.0 \n",
+ " 163.0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " 1 \n",
+ " 0 \n",
+ " 26.394521 \n",
+ " 0 \n",
+ " 1 \n",
+ " 0 \n",
+ " -1 \n",
+ " -1 \n",
+ " 1 \n",
+ " 0 \n",
+ " ... \n",
+ " 1 \n",
+ " 7.94 \n",
+ " 19.013230 \n",
+ " 0.42 \n",
+ " 23.4 \n",
+ " 23.0 \n",
+ " 20.0 \n",
+ " 1000000.0 \n",
+ " 435.0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " 0 \n",
+ " 0 \n",
+ " 39.684932 \n",
+ " 1 \n",
+ " 1 \n",
+ " 0 \n",
+ " 1 \n",
+ " 2 \n",
+ " 1 \n",
+ " 1 \n",
+ " ... \n",
+ " None \n",
+ " 4.25 \n",
+ " 29.481647 \n",
+ " 0.14 \n",
+ " 50.0 \n",
+ " 23.0 \n",
+ " 29.0 \n",
+ " 19.0 \n",
+ " 53.0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " 0 \n",
+ " 1 \n",
+ " 33.358904 \n",
+ " 0 \n",
+ " 0 \n",
+ " 0 \n",
+ " 1 \n",
+ " 2 \n",
+ " 0 \n",
+ " 1 \n",
+ " ... \n",
+ " 1 \n",
+ " 51.85 \n",
+ " 3.972255 \n",
+ " 13.05 \n",
+ " 9.0 \n",
+ " 14.0 \n",
+ " 14.0 \n",
+ " 1000000.0 \n",
+ " 2043.0 \n",
+ " 0 \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 182 \n",
+ " 1 \n",
+ " 1 \n",
+ " 37.575342 \n",
+ " 1 \n",
+ " 1 \n",
+ " 0 \n",
+ " 1 \n",
+ " 1 \n",
+ " 0 \n",
+ " 0 \n",
+ " ... \n",
+ " 1 \n",
+ " 11.08 \n",
+ " 2.522750 \n",
+ " 4.39 \n",
+ " 44.0 \n",
+ " 15.0 \n",
+ " 22.0 \n",
+ " 16.0 \n",
+ " 385.0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " 183 \n",
+ " 0 \n",
+ " 1 \n",
+ " 22.895890 \n",
+ " 0 \n",
+ " 0 \n",
+ " 0 \n",
+ " 1 \n",
+ " 0 \n",
+ " 1 \n",
+ " 1 \n",
+ " ... \n",
+ " 1 \n",
+ " 4.64 \n",
+ " 1.038858 \n",
+ " 4.47 \n",
+ " 44.5 \n",
+ " 12.0 \n",
+ " 30.0 \n",
+ " 1000000.0 \n",
+ " 634.0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " 184 \n",
+ " 0 \n",
+ " 1 \n",
+ " 27.347945 \n",
+ " 0 \n",
+ " 1 \n",
+ " 0 \n",
+ " 1 \n",
+ " -1 \n",
+ " 1 \n",
+ " 1 \n",
+ " ... \n",
+ " 1 \n",
+ " 7.73 \n",
+ " 1.635559 \n",
+ " 4.73 \n",
+ " 33.0 \n",
+ " 16.0 \n",
+ " 16.0 \n",
+ " 1000000.0 \n",
+ " 1895.0 \n",
+ " 0 \n",
+ " \n",
+ " \n",
+ " 185 \n",
+ " 1 \n",
+ " 1 \n",
+ " 27.780822 \n",
+ " 0 \n",
+ " 1 \n",
+ " 0 \n",
+ " 1 \n",
+ " 0 \n",
+ " 1 \n",
+ " 1 \n",
+ " ... \n",
+ " 0 \n",
+ " 15.41 \n",
+ " 8.077770 \n",
+ " 1.91 \n",
+ " 24.0 \n",
+ " 13.0 \n",
+ " 14.0 \n",
+ " 54.0 \n",
+ " 382.0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " 186 \n",
+ " 1 \n",
+ " 1 \n",
+ " 55.553425 \n",
+ " 1 \n",
+ " 1 \n",
+ " 0 \n",
+ " 1 \n",
+ " 2 \n",
+ " 1 \n",
+ " 1 \n",
+ " ... \n",
+ " 1 \n",
+ " 9.91 \n",
+ " 0.948135 \n",
+ " 10.45 \n",
+ " 37.0 \n",
+ " 18.0 \n",
+ " 20.0 \n",
+ " 1000000.0 \n",
+ " 1109.0 \n",
+ " 0 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
187 rows × 37 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " Recipientgender Stemcellsource Donorage Donorage35 IIIV Gendermatch \\\n",
+ "0 1 1 22.830137 0 1 0 \n",
+ "1 1 0 23.342466 0 1 0 \n",
+ "2 1 0 26.394521 0 1 0 \n",
+ "3 0 0 39.684932 1 1 0 \n",
+ "4 0 1 33.358904 0 0 0 \n",
+ ".. ... ... ... ... ... ... \n",
+ "182 1 1 37.575342 1 1 0 \n",
+ "183 0 1 22.895890 0 0 0 \n",
+ "184 0 1 27.347945 0 1 0 \n",
+ "185 1 1 27.780822 0 1 0 \n",
+ "186 1 1 55.553425 1 1 0 \n",
+ "\n",
+ " DonorABO RecipientABO RecipientRh ABOmatch ... extcGvHD CD34kgx10d6 \\\n",
+ "0 1 1 1 0 ... 1 7.20 \n",
+ "1 -1 -1 1 0 ... 1 4.50 \n",
+ "2 -1 -1 1 0 ... 1 7.94 \n",
+ "3 1 2 1 1 ... None 4.25 \n",
+ "4 1 2 0 1 ... 1 51.85 \n",
+ ".. ... ... ... ... ... ... ... \n",
+ "182 1 1 0 0 ... 1 11.08 \n",
+ "183 1 0 1 1 ... 1 4.64 \n",
+ "184 1 -1 1 1 ... 1 7.73 \n",
+ "185 1 0 1 1 ... 0 15.41 \n",
+ "186 1 2 1 1 ... 1 9.91 \n",
+ "\n",
+ " CD3dCD34 CD3dkgx10d8 Rbodymass ANCrecovery PLTrecovery \\\n",
+ "0 1.338760 5.38 35.0 19.0 51.0 \n",
+ "1 11.078295 0.41 20.6 16.0 37.0 \n",
+ "2 19.013230 0.42 23.4 23.0 20.0 \n",
+ "3 29.481647 0.14 50.0 23.0 29.0 \n",
+ "4 3.972255 13.05 9.0 14.0 14.0 \n",
+ ".. ... ... ... ... ... \n",
+ "182 2.522750 4.39 44.0 15.0 22.0 \n",
+ "183 1.038858 4.47 44.5 12.0 30.0 \n",
+ "184 1.635559 4.73 33.0 16.0 16.0 \n",
+ "185 8.077770 1.91 24.0 13.0 14.0 \n",
+ "186 0.948135 10.45 37.0 18.0 20.0 \n",
+ "\n",
+ " time_to_aGvHD_III_IV survival_time survival_status \n",
+ "0 32.0 999.0 0 \n",
+ "1 1000000.0 163.0 1 \n",
+ "2 1000000.0 435.0 1 \n",
+ "3 19.0 53.0 1 \n",
+ "4 1000000.0 2043.0 0 \n",
+ ".. ... ... ... \n",
+ "182 16.0 385.0 1 \n",
+ "183 1000000.0 634.0 1 \n",
+ "184 1000000.0 1895.0 0 \n",
+ "185 54.0 382.0 1 \n",
+ "186 1000000.0 1109.0 0 \n",
+ "\n",
+ "[187 rows x 37 columns]"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "from rulekit.arff import read_arff\n",
+ "\n",
+ "DATASET_URL: str = (\n",
+ " 'https://raw.githubusercontent.com/'\n",
+ " 'adaa-polsl/RuleKit/master/data/bmt/'\n",
+ " 'bmt.arff'\n",
+ ")\n",
+ "data_df: pd.DataFrame = read_arff(DATASET_URL)\n",
+ "data_df['survival_status'] = data_df['survival_status'].astype(int).astype(str)\n",
+ "data_df\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 378
+ },
+ "id": "y9uVi9SFeZSa",
+ "outputId": "6809c06d-5d8c-48a0-9b6d-3c433574f7f7"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Dataset overview:\n",
+ "Name: bmt\n",
+ "Objects number: 187; Attributes number: 37\n",
+ "Basic attribute statistics:\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " Donorage \n",
+ " Recipientage \n",
+ " CD34kgx10d6 \n",
+ " CD3dCD34 \n",
+ " CD3dkgx10d8 \n",
+ " Rbodymass \n",
+ " ANCrecovery \n",
+ " PLTrecovery \n",
+ " time_to_aGvHD_III_IV \n",
+ " survival_time \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " count \n",
+ " 187.000000 \n",
+ " 187.000000 \n",
+ " 187.000000 \n",
+ " 182.000000 \n",
+ " 182.000000 \n",
+ " 185.000000 \n",
+ " 187.000000 \n",
+ " 187.000000 \n",
+ " 187.000000 \n",
+ " 187.000000 \n",
+ " \n",
+ " \n",
+ " mean \n",
+ " 33.472068 \n",
+ " 9.931551 \n",
+ " 11.891781 \n",
+ " 5.385096 \n",
+ " 4.745714 \n",
+ " 35.801081 \n",
+ " 26752.866310 \n",
+ " 90937.919786 \n",
+ " 775408.042781 \n",
+ " 938.743316 \n",
+ " \n",
+ " \n",
+ " std \n",
+ " 8.271826 \n",
+ " 5.305639 \n",
+ " 9.914386 \n",
+ " 9.598716 \n",
+ " 3.859128 \n",
+ " 19.650922 \n",
+ " 161747.200525 \n",
+ " 288242.407688 \n",
+ " 418425.252689 \n",
+ " 849.589495 \n",
+ " \n",
+ " \n",
+ " min \n",
+ " 18.646575 \n",
+ " 0.600000 \n",
+ " 0.790000 \n",
+ " 0.204132 \n",
+ " 0.040000 \n",
+ " 6.000000 \n",
+ " 9.000000 \n",
+ " 9.000000 \n",
+ " 10.000000 \n",
+ " 6.000000 \n",
+ " \n",
+ " \n",
+ " 25% \n",
+ " 27.039726 \n",
+ " 5.050000 \n",
+ " 5.350000 \n",
+ " 1.786683 \n",
+ " 1.687500 \n",
+ " 19.000000 \n",
+ " 13.000000 \n",
+ " 16.000000 \n",
+ " 1000000.000000 \n",
+ " 168.500000 \n",
+ " \n",
+ " \n",
+ " 50% \n",
+ " 33.550685 \n",
+ " 9.600000 \n",
+ " 9.720000 \n",
+ " 2.734462 \n",
+ " 4.325000 \n",
+ " 33.000000 \n",
+ " 15.000000 \n",
+ " 21.000000 \n",
+ " 1000000.000000 \n",
+ " 676.000000 \n",
+ " \n",
+ " \n",
+ " 75% \n",
+ " 40.117809 \n",
+ " 14.050000 \n",
+ " 15.415000 \n",
+ " 5.823565 \n",
+ " 6.785000 \n",
+ " 50.600000 \n",
+ " 17.000000 \n",
+ " 37.000000 \n",
+ " 1000000.000000 \n",
+ " 1604.000000 \n",
+ " \n",
+ " \n",
+ " max \n",
+ " 55.553425 \n",
+ " 20.200000 \n",
+ " 57.780000 \n",
+ " 99.560970 \n",
+ " 20.020000 \n",
+ " 103.400000 \n",
+ " 1000000.000000 \n",
+ " 1000000.000000 \n",
+ " 1000000.000000 \n",
+ " 3364.000000 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " Donorage Recipientage CD34kgx10d6 CD3dCD34 CD3dkgx10d8 \\\n",
+ "count 187.000000 187.000000 187.000000 182.000000 182.000000 \n",
+ "mean 33.472068 9.931551 11.891781 5.385096 4.745714 \n",
+ "std 8.271826 5.305639 9.914386 9.598716 3.859128 \n",
+ "min 18.646575 0.600000 0.790000 0.204132 0.040000 \n",
+ "25% 27.039726 5.050000 5.350000 1.786683 1.687500 \n",
+ "50% 33.550685 9.600000 9.720000 2.734462 4.325000 \n",
+ "75% 40.117809 14.050000 15.415000 5.823565 6.785000 \n",
+ "max 55.553425 20.200000 57.780000 99.560970 20.020000 \n",
+ "\n",
+ " Rbodymass ANCrecovery PLTrecovery time_to_aGvHD_III_IV \\\n",
+ "count 185.000000 187.000000 187.000000 187.000000 \n",
+ "mean 35.801081 26752.866310 90937.919786 775408.042781 \n",
+ "std 19.650922 161747.200525 288242.407688 418425.252689 \n",
+ "min 6.000000 9.000000 9.000000 10.000000 \n",
+ "25% 19.000000 13.000000 16.000000 1000000.000000 \n",
+ "50% 33.000000 15.000000 21.000000 1000000.000000 \n",
+ "75% 50.600000 17.000000 37.000000 1000000.000000 \n",
+ "max 103.400000 1000000.000000 1000000.000000 1000000.000000 \n",
+ "\n",
+ " survival_time \n",
+ "count 187.000000 \n",
+ "mean 938.743316 \n",
+ "std 849.589495 \n",
+ "min 6.000000 \n",
+ "25% 168.500000 \n",
+ "50% 676.000000 \n",
+ "75% 1604.000000 \n",
+ "max 3364.000000 "
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "print(\"Dataset overview:\")\n",
+ "print(f\"Name: bmt\")\n",
+ "print(f\"Objects number: {data_df.shape[0]}; Attributes number: {data_df.shape[1]}\")\n",
+ "print(\"Basic attribute statistics:\")\n",
+ "data_df.describe()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "dattexxGmaqJ"
+ },
+ "source": [
+ "## Helper function for creating ruleset characteristics dataframe"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "id": "aLCZkT_SmU4a"
+ },
+ "outputs": [],
+ "source": [
+ "def get_ruleset_stats(model) -> pd.DataFrame:\n",
+ " tmp = model.parameters.__dict__\n",
+ " del tmp['_java_object']\n",
+ " return pd.DataFrame.from_records([{**tmp, **model.stats.__dict__}])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "u4wOfecjme_d"
+ },
+ "source": [
+ "## Rule induction on full dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "id": "TrO-LyN2mpiP"
+ },
+ "outputs": [],
+ "source": [
+ "X: pd.DataFrame = data_df.drop(['survival_status'], axis=1)\n",
+ "y: pd.Series = data_df['survival_status']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "id": "c5tmU4IHnFjw"
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " minimum_covered \n",
+ " maximum_uncovered_fraction \n",
+ " ignore_missing \n",
+ " pruning_enabled \n",
+ " max_growing_condition \n",
+ " time_total_s \n",
+ " time_growing_s \n",
+ " time_pruning_s \n",
+ " rules_count \n",
+ " conditions_per_rule \n",
+ " induced_conditions_per_rule \n",
+ " avg_rule_coverage \n",
+ " avg_rule_precision \n",
+ " avg_rule_quality \n",
+ " pvalue \n",
+ " FDR_pvalue \n",
+ " FWER_pvalue \n",
+ " fraction_significant \n",
+ " fraction_FDR_significant \n",
+ " fraction_FWER_significant \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 0.05 \n",
+ " 0.0 \n",
+ " False \n",
+ " True \n",
+ " 0.0 \n",
+ " 1.771417 \n",
+ " 0.797513 \n",
+ " 0.902853 \n",
+ " 5 \n",
+ " 3.6 \n",
+ " 65.2 \n",
+ " 0.308021 \n",
+ " 1.0 \n",
+ " 0.999865 \n",
+ " 0.000135 \n",
+ " 0.000147 \n",
+ " 0.000184 \n",
+ " 1.0 \n",
+ " 1.0 \n",
+ " 1.0 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " minimum_covered maximum_uncovered_fraction ignore_missing \\\n",
+ "0 0.05 0.0 False \n",
+ "\n",
+ " pruning_enabled max_growing_condition time_total_s time_growing_s \\\n",
+ "0 True 0.0 1.771417 0.797513 \n",
+ "\n",
+ " time_pruning_s rules_count conditions_per_rule \\\n",
+ "0 0.902853 5 3.6 \n",
+ "\n",
+ " induced_conditions_per_rule avg_rule_coverage avg_rule_precision \\\n",
+ "0 65.2 0.308021 1.0 \n",
+ "\n",
+ " avg_rule_quality pvalue FDR_pvalue FWER_pvalue fraction_significant \\\n",
+ "0 0.999865 0.000135 0.000147 0.000184 1.0 \n",
+ "\n",
+ " fraction_FDR_significant fraction_FWER_significant \n",
+ "0 1.0 1.0 "
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "from rulekit.survival import SurvivalRules\n",
+ "from rulekit.rules import RuleSet, SurvivalRule\n",
+ "\n",
+ "srv = SurvivalRules(survival_time_attr='survival_time')\n",
+ "\n",
+ "srv.fit(X, y)\n",
+ "\n",
+ "ruleset: RuleSet[SurvivalRule] = srv.model\n",
+ "\n",
+ "predictions: np.ndarray = srv.predict(X)\n",
+ "\n",
+ "\n",
+ "ruleset_stats = get_ruleset_stats(ruleset)\n",
+ "\n",
+ "\n",
+ "display(ruleset_stats)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Plot predicted estimators for the first five examples"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "for i in range(5):\n",
+ " plt.step(\n",
+ " predictions[i][\"times\"],\n",
+ " predictions[i][\"probabilities\"],\n",
+ " label=f'Example {i}'\n",
+ " )\n",
+ "plt.legend(title='Example index:')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Plot rules Kaplan-Meier's estimators on top of the training dataset estimator"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "r1: IF Donorage = (-inf, 45.16) AND Relapse = {0} AND Recipientage = (-inf, 17.45) THEN \n",
+ "r2: IF Donorage = (-inf, 43.63) AND HLAmismatch = {0} AND Relapse = {1} THEN \n",
+ "r3: IF PLTrecovery = (-inf, 266) AND time_to_aGvHD_III_IV = <12.50, inf) AND ANCrecovery = <10.50, 19.50) AND Rbodymass = (-inf, 69) AND Donorage = (-inf, 44.06) AND Recipientage = <4.60, inf) AND CD34kgx10d6 = (-inf, 16.98) THEN \n",
+ "r4: IF Donorage = <37.16, inf) AND Recipientage = <5.15, inf) AND time_to_aGvHD_III_IV = <23.50, inf) AND CD3dCD34 = <0.90, 73.72) THEN \n",
+ "r5: IF Recipientage = <17.85, 18.85) THEN \n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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Fi1sjomKikJRUREAoKioyO59srwmV5bY7b236u+9TZs2Nq+HhISgVatWNvt06NCh1jksr7Vs2dIt8btaeno6/vd//xcdOnTA2bNn8eqrr2Lw4MHIzs5GcHCw394Lk8mEadOmYdCgQejVqxcAuOz3oq59SktLodPpoFar3fGWGs3evQCAESNGoH379oiNjcXx48cxc+ZM5OTkYNOmTQD8616cOHECycnJKC8vR1hYGL788kv07NkTx44dC7jPRF33AvCtz0TAJTCBZPDgwdafe/fujaSkJLRv3x6fffaZT/2ykHc98cQT1p/j4+PRu3dvdOrUCVlZWbjvvvu8GJl7TZ48GSdPnsR3333n7VC8rq57MWHCBOvP8fHxiImJwX333YezZ8+iU6dOng7Trbp164Zjx46hpKQEn3/+OcaOHYu9e/d6OyyvqOte9OzZ06c+EwHXhBQZGYng4OBaPciLi4sRHR3tpag8o0WLFujatSvOnDmD6OhoGAwGXL161Waf6vchOjra7n2yvCZXltjr+wxER0fj4sWLNq9XVlbiypUrfn9/OnbsiMjISJw5cwaAf96LKVOm4F//+hf27NmDW2+91brdVb8Xde0THh7uc3881HUv7ElKSgIAm8+Gv9wLpVKJzp07IzExEZmZmejTpw+WLl0akJ+Juu6FPd78TARcAqNUKpGYmIhdu3ZZt5lMJuzatcumjc8fXb9+HWfPnkVMTAwSExOhUChs7kNOTg7y8/Ot9yE5ORknTpyw+fLasWMHwsPDreVEOerQoQOio6Nt3ntpaSkOHDhg896vXr2Kw4cPW/fZvXs3TCaT9Rc2OTkZ3377LSoqKqz77NixA926dfPJJhNH/frrr/j9998RExMDwL/uhRACU6ZMwZdffondu3fXavZy1e9FcnKyzTks+/jSvzEN3Qt7jh07BgA2nw1/uBf2mEwm6PX6gPpM1MVyL+zx6mfCqS6/fmLDhg1CpVKJNWvWiJ9++klMmDBBtGjRwqbXtD946aWXRFZWlsjNzRX79u0TqampIjIyUly8eFEIYR4a2K5dO7F7925x6NAhkZycLJKTk63HW4bD3X///eLYsWNi27ZtonXr1rIYRn3t2jVx9OhRcfToUQFAvPPOO+Lo0aPi/PnzQgjzMOoWLVqIf/7zn+L48ePiwQcftDuMul+/fuLAgQPiu+++E126dLEZOnz16lURFRUlRo8eLU6ePCk2bNggNBqNzw0dru9eXLt2TcyYMUNkZ2eL3NxcsXPnTpGQkCC6dOkiysvLrefwl3sxadIkERERIbKysmyGgZaVlVn3ccXvhWWY6MsvvyxOnTolli1b5nNDZhu6F2fOnBELFiwQhw4dErm5ueKf//yn6Nixo7j77rut5/CXezFr1iyxd+9ekZubK44fPy5mzZolJEkS33zzjRAicD4TQtR/L3ztMxGQCYwQQrz33nuiXbt2QqlUigEDBoj9+/d7OySXGzZsmIiJiRFKpVK0bdtWDBs2TJw5c8b6uk6nE88995xo2bKl0Gg04uGHHxaFhYU258jLyxODBw8WarVaREZGipdeeklUVFR4+q04bc+ePQJArcfYsWOFEOah1K+99pqIiooSKpVK3HfffSInJ8fmHL///rsYPny4CAsLE+Hh4WLcuHHi2rVrNvv88MMP4s477xQqlUq0bdtWLFq0yFNv0WH13YuysjJx//33i9atWwuFQiHat28vxo8fXyuZ95d7Ye8+ABCrV6+27uOq34s9e/aIvn37CqVSKTp27GhzDV/Q0L3Iz88Xd999t2jVqpVQqVSic+fO4uWXX7aZ80MI/7gXTz31lGjfvr1QKpWidevW4r777rMmL0IEzmdCiPrvha99JiQhhHCuZkNERETkXQHXB4aIiIjkjwkMERERyQ4TGCIiIpIdJjBEREQkO0xgiIiISHaYwBAREZHsMIEhIiIi2WECQ0RERLLDBIaIiIhkhwkMERERyQ4TGCIiIpIdJjBEREQkO/8fqX4vTbPH7I4AAAAASUVORK5CYII=",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "from rulekit.kaplan_meier import KaplanMeierEstimator\n",
+ "\n",
+ "# plot rules kaplan-meier curves\n",
+ "for i, rule in enumerate(ruleset.rules):\n",
+ " rule_label: str = f'r{i + 1}'\n",
+ " rule_km: KaplanMeierEstimator = rule.kaplan_meier_estimator\n",
+ " plt.step(\n",
+ " rule_km.times,\n",
+ " rule_km.probabilities,\n",
+ " label=rule_label\n",
+ " )\n",
+ " print(f'{rule_label}: {rule}')\n",
+ "\n",
+ "# plot whole dataset kaplan-meier curve\n",
+ "train_km: KaplanMeierEstimator = srv.get_train_set_kaplan_meier()\n",
+ "plt.step(\n",
+ " train_km.times,\n",
+ " train_km.probabilities,\n",
+ " label='Training set estimator'\n",
+ ")\n",
+ "\n",
+ "plt.legend()\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "GkNBc5iBpwmj"
+ },
+ "source": [
+ "### Rules evaluation on full set"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "id": "9UjrC8r-p59d"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Integrated Brier Score: 0.19651358709002972\n"
+ ]
+ }
+ ],
+ "source": [
+ "integrated_brier_score = srv.score(X, y)\n",
+ "print(f'Integrated Brier Score: {integrated_brier_score}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "FpoSoaKdqAGQ"
+ },
+ "source": [
+ "## Stratified K-Folds cross-validation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "id": "0nNv6a84qTsq"
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import StratifiedKFold\n",
+ "from rulekit.exceptions import RuleKitJavaException\n",
+ "\n",
+ "skf = StratifiedKFold(n_splits=10, shuffle=True, random_state=0)\n",
+ "\n",
+ "ruleset_stats = pd.DataFrame()\n",
+ "survival_metrics = []\n",
+ "\n",
+ "for train_index, test_index in skf.split(X, y):\n",
+ " X_train, X_test = X.iloc[train_index], X.iloc[test_index]\n",
+ " y_train, y_test = y.iloc[train_index], y.iloc[test_index]\n",
+ "\n",
+ " srv = SurvivalRules(\n",
+ " survival_time_attr='survival_time'\n",
+ " )\n",
+ " srv.fit(X_train, y_train)\n",
+ "\n",
+ " ruleset = srv.model\n",
+ "\n",
+ " ibs: float = srv.score(X_test, y_test)\n",
+ "\n",
+ " survival_metrics.append(ibs)\n",
+ " ruleset_stats = pd.concat([ruleset_stats, get_ruleset_stats(ruleset)])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "MfCOH_f3sICm"
+ },
+ "source": [
+ "Ruleset characteristics (average)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "id": "xzbazr51sRd3"
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "minimum_covered 0.050000\n",
+ "maximum_uncovered_fraction 0.000000\n",
+ "ignore_missing 0.000000\n",
+ "pruning_enabled 1.000000\n",
+ "max_growing_condition 0.000000\n",
+ "time_total_s 0.799019\n",
+ "time_growing_s 0.296248\n",
+ "time_pruning_s 0.477474\n",
+ "rules_count 4.000000\n",
+ "conditions_per_rule 2.581667\n",
+ "induced_conditions_per_rule 59.825000\n",
+ "avg_rule_coverage 0.486613\n",
+ "avg_rule_precision 1.000000\n",
+ "avg_rule_quality 0.995955\n",
+ "pvalue 0.004045\n",
+ "FDR_pvalue 0.004061\n",
+ "FWER_pvalue 0.004104\n",
+ "fraction_significant 0.980000\n",
+ "fraction_FDR_significant 0.980000\n",
+ "fraction_FWER_significant 0.980000\n",
+ "dtype: float64"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(ruleset_stats.mean())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "_SmDJho4sVEO"
+ },
+ "source": [
+ "Rules evaluation on dataset (average)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "id": "Co-fNd9nshWB"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Integrated Brier Score: 0.20178456199764142\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(f'Integrated Brier Score: {np.mean(survival_metrics)}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "d-GdQ-wUtzW9"
+ },
+ "source": [
+ "## Hyperparameters tuning\n",
+ "\n",
+ "This one gonna take a while..."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import StratifiedKFold\n",
+ "from sklearn.model_selection import GridSearchCV"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def scorer(estimator: SurvivalRules, X: pd.DataFrame, y: pd.Series) -> float:\n",
+ " return -1 * estimator.score(X, y)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Best Integrated Brier Score: -0.21437408819868886 using {'minsupp_new': 3, 'survival_time_attr': 'survival_time'}\n"
+ ]
+ }
+ ],
+ "source": [
+ "# define models and parameters\n",
+ "model = SurvivalRules(survival_time_attr='survival_time')\n",
+ "\n",
+ "# define grid search\n",
+ "grid = {\n",
+ " 'survival_time_attr': ['survival_time'],\n",
+ " 'minsupp_new': range(1, 10),\n",
+ "}\n",
+ "\n",
+ "cv = StratifiedKFold(n_splits=3)\n",
+ "grid_search = GridSearchCV(estimator=model, param_grid=grid, cv=cv, scoring=scorer)\n",
+ "grid_result = grid_search.fit(X, y)\n",
+ "\n",
+ "# summarize results\n",
+ "print(\n",
+ " 'Best Integrated Brier Score: '\n",
+ " f'{grid_result.best_score_} using {grid_result.best_params_}'\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Building model with tuned hyperparameters\n",
+ "\n",
+ "### Split dataset to train and test (80%/20%)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import train_test_split\n",
+ "\n",
+ "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=True, stratify=y)\n",
+ "\n",
+ "srv = SurvivalRules(\n",
+ " survival_time_attr='survival_time',\n",
+ " minsupp_new=5\n",
+ ")\n",
+ "srv.fit(X_train, y_train)\n",
+ "ruleset: RuleSet[SurvivalRule] = srv.model\n",
+ "ruleset_stats: pd.DataFrame = get_ruleset_stats(ruleset)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Rules evaluation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "minimum_covered 5.0\n",
+ "maximum_uncovered_fraction 0.0\n",
+ "ignore_missing False\n",
+ "pruning_enabled True\n",
+ "max_growing_condition 0.0\n",
+ "time_total_s 0.594173\n",
+ "time_growing_s 0.244234\n",
+ "time_pruning_s 0.312523\n",
+ "rules_count 4\n",
+ "conditions_per_rule 2.25\n",
+ "induced_conditions_per_rule 55.25\n",
+ "avg_rule_coverage 0.389262\n",
+ "avg_rule_precision 1.0\n",
+ "avg_rule_quality 1.0\n",
+ "pvalue 0.0\n",
+ "FDR_pvalue 0.0\n",
+ "FWER_pvalue 0.0\n",
+ "fraction_significant 1.0\n",
+ "fraction_FDR_significant 1.0\n",
+ "fraction_FWER_significant 1.0\n",
+ "Name: 0, dtype: object"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(ruleset_stats.iloc[0])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Validate model on test dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Integrated Brier Score: 0.14054870564224475\n"
+ ]
+ }
+ ],
+ "source": [
+ "integrated_brier_score = srv.score(X_test, y_test)\n",
+ "print(f'Integrated Brier Score: {integrated_brier_score}')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "predictions = srv.predict(X_test)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Text(0.5, 1.0, 'Predicted Kaplan-Meier curves for 5 examples from test set')"
+ ]
+ },
+ "execution_count": 29,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "for i in range(5):\n",
+ " plt.step(\n",
+ " predictions[i][\"times\"], \n",
+ " predictions[i][\"probabilities\"],\n",
+ " label=f'Example {i}'\n",
+ " )\n",
+ "plt.legend(title='Examples indices:')\n",
+ "plt.title('Predicted Kaplan-Meier curves for 5 examples from test set')"
+ ]
+ }
+ ],
+ "metadata": {
+ "colab": {
+ "collapsed_sections": [],
+ "name": "Raport_przezyciowy.ipynb",
+ "provenance": [],
+ "toc_visible": true
+ },
+ "kernelspec": {
+ "display_name": "tutorials_env",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.0"
+ },
+ "metadata": {
+ "interpreter": {
+ "hash": "62266c16fff41e971c13e9cb2ad3d47e4ef45d0678714c255381eb9fdcbd7032"
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/docs/serve/v2.1.24.0/_sources/rst/whats_new/Changes in this version.ipynb.txt b/docs/serve/v2.1.24.0/_sources/rst/whats_new/Changes in this version.ipynb.txt
new file mode 100644
index 0000000..401e665
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_sources/rst/whats_new/Changes in this version.ipynb.txt
@@ -0,0 +1,76 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# What's new in RuleKit version 2.1.24.0?\n",
+ "\n",
+ "\n",
+ "### 1. Revert breaking changes in expert rules induction for regression and survival \n",
+ "The latest version 2.1.21.0 introduced some groundbreaking changes, which you can read more\n",
+ "about them in the latest [release note](https://github.com/adaa-polsl/RuleKit-python/releases/tag/v2.1.21.0).\n",
+ "Now rules and expert conditions can be defined in both the old and new formats, see example below."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# both variants will work the same\n",
+ "expert_rules = [\n",
+ " (\n",
+ " 'rule-0',\n",
+ " 'IF [[CD34kgx10d6 = (-inf, 10.0)]] AND [[extcGvHD = {0}]] THEN survival_status = {NaN}'\n",
+ " ),\n",
+ " (\n",
+ " 'rule-0',\n",
+ " 'IF [[CD34kgx10d6 = (-inf, 10.0)]] AND [[extcGvHD = {0}]] THEN'\n",
+ " ),\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 2. Upgrade to new version of RuleKit\n",
+ "\n",
+ "In the new version of the Java RuleKit library, many bugs regarding expert induction have been corrected."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Other changes\n",
+ "\n",
+ "* Improve flake8 score\n",
+ "* Add more unit tests."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "tutorials_env",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/docs/serve/v2.1.24.0/_static/_sphinx_javascript_frameworks_compat.js b/docs/serve/v2.1.24.0/_static/_sphinx_javascript_frameworks_compat.js
new file mode 100644
index 0000000..8141580
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/_sphinx_javascript_frameworks_compat.js
@@ -0,0 +1,123 @@
+/* Compatability shim for jQuery and underscores.js.
+ *
+ * Copyright Sphinx contributors
+ * Released under the two clause BSD licence
+ */
+
+/**
+ * small helper function to urldecode strings
+ *
+ * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL
+ */
+jQuery.urldecode = function(x) {
+ if (!x) {
+ return x
+ }
+ return decodeURIComponent(x.replace(/\+/g, ' '));
+};
+
+/**
+ * small helper function to urlencode strings
+ */
+jQuery.urlencode = encodeURIComponent;
+
+/**
+ * This function returns the parsed url parameters of the
+ * current request. Multiple values per key are supported,
+ * it will always return arrays of strings for the value parts.
+ */
+jQuery.getQueryParameters = function(s) {
+ if (typeof s === 'undefined')
+ s = document.location.search;
+ var parts = s.substr(s.indexOf('?') + 1).split('&');
+ var result = {};
+ for (var i = 0; i < parts.length; i++) {
+ var tmp = parts[i].split('=', 2);
+ var key = jQuery.urldecode(tmp[0]);
+ var value = jQuery.urldecode(tmp[1]);
+ if (key in result)
+ result[key].push(value);
+ else
+ result[key] = [value];
+ }
+ return result;
+};
+
+/**
+ * highlight a given string on a jquery object by wrapping it in
+ * span elements with the given class name.
+ */
+jQuery.fn.highlightText = function(text, className) {
+ function highlight(node, addItems) {
+ if (node.nodeType === 3) {
+ var val = node.nodeValue;
+ var pos = val.toLowerCase().indexOf(text);
+ if (pos >= 0 &&
+ !jQuery(node.parentNode).hasClass(className) &&
+ !jQuery(node.parentNode).hasClass("nohighlight")) {
+ var span;
+ var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
+ if (isInSVG) {
+ span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
+ } else {
+ span = document.createElement("span");
+ span.className = className;
+ }
+ span.appendChild(document.createTextNode(val.substr(pos, text.length)));
+ node.parentNode.insertBefore(span, node.parentNode.insertBefore(
+ document.createTextNode(val.substr(pos + text.length)),
+ node.nextSibling));
+ node.nodeValue = val.substr(0, pos);
+ if (isInSVG) {
+ var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
+ var bbox = node.parentElement.getBBox();
+ rect.x.baseVal.value = bbox.x;
+ rect.y.baseVal.value = bbox.y;
+ rect.width.baseVal.value = bbox.width;
+ rect.height.baseVal.value = bbox.height;
+ rect.setAttribute('class', className);
+ addItems.push({
+ "parent": node.parentNode,
+ "target": rect});
+ }
+ }
+ }
+ else if (!jQuery(node).is("button, select, textarea")) {
+ jQuery.each(node.childNodes, function() {
+ highlight(this, addItems);
+ });
+ }
+ }
+ var addItems = [];
+ var result = this.each(function() {
+ highlight(this, addItems);
+ });
+ for (var i = 0; i < addItems.length; ++i) {
+ jQuery(addItems[i].parent).before(addItems[i].target);
+ }
+ return result;
+};
+
+/*
+ * backward compatibility for jQuery.browser
+ * This will be supported until firefox bug is fixed.
+ */
+if (!jQuery.browser) {
+ jQuery.uaMatch = function(ua) {
+ ua = ua.toLowerCase();
+
+ var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
+ /(webkit)[ \/]([\w.]+)/.exec(ua) ||
+ /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
+ /(msie) ([\w.]+)/.exec(ua) ||
+ ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
+ [];
+
+ return {
+ browser: match[ 1 ] || "",
+ version: match[ 2 ] || "0"
+ };
+ };
+ jQuery.browser = {};
+ jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
+}
diff --git a/docs/serve/v2.1.24.0/_static/basic.css b/docs/serve/v2.1.24.0/_static/basic.css
new file mode 100644
index 0000000..30fee9d
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/basic.css
@@ -0,0 +1,925 @@
+/*
+ * basic.css
+ * ~~~~~~~~~
+ *
+ * Sphinx stylesheet -- basic theme.
+ *
+ * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+/* -- main layout ----------------------------------------------------------- */
+
+div.clearer {
+ clear: both;
+}
+
+div.section::after {
+ display: block;
+ content: '';
+ clear: left;
+}
+
+/* -- relbar ---------------------------------------------------------------- */
+
+div.related {
+ width: 100%;
+ font-size: 90%;
+}
+
+div.related h3 {
+ display: none;
+}
+
+div.related ul {
+ margin: 0;
+ padding: 0 0 0 10px;
+ list-style: none;
+}
+
+div.related li {
+ display: inline;
+}
+
+div.related li.right {
+ float: right;
+ margin-right: 5px;
+}
+
+/* -- sidebar --------------------------------------------------------------- */
+
+div.sphinxsidebarwrapper {
+ padding: 10px 5px 0 10px;
+}
+
+div.sphinxsidebar {
+ float: left;
+ width: 230px;
+ margin-left: -100%;
+ font-size: 90%;
+ word-wrap: break-word;
+ overflow-wrap : break-word;
+}
+
+div.sphinxsidebar ul {
+ list-style: none;
+}
+
+div.sphinxsidebar ul ul,
+div.sphinxsidebar ul.want-points {
+ margin-left: 20px;
+ list-style: square;
+}
+
+div.sphinxsidebar ul ul {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+div.sphinxsidebar form {
+ margin-top: 10px;
+}
+
+div.sphinxsidebar input {
+ border: 1px solid #98dbcc;
+ font-family: sans-serif;
+ font-size: 1em;
+}
+
+div.sphinxsidebar #searchbox form.search {
+ overflow: hidden;
+}
+
+div.sphinxsidebar #searchbox input[type="text"] {
+ float: left;
+ width: 80%;
+ padding: 0.25em;
+ box-sizing: border-box;
+}
+
+div.sphinxsidebar #searchbox input[type="submit"] {
+ float: left;
+ width: 20%;
+ border-left: none;
+ padding: 0.25em;
+ box-sizing: border-box;
+}
+
+
+img {
+ border: 0;
+ max-width: 100%;
+}
+
+/* -- search page ----------------------------------------------------------- */
+
+ul.search {
+ margin: 10px 0 0 20px;
+ padding: 0;
+}
+
+ul.search li {
+ padding: 5px 0 5px 20px;
+ background-image: url(file.png);
+ background-repeat: no-repeat;
+ background-position: 0 7px;
+}
+
+ul.search li a {
+ font-weight: bold;
+}
+
+ul.search li p.context {
+ color: #888;
+ margin: 2px 0 0 30px;
+ text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+ font-weight: bold;
+}
+
+/* -- index page ------------------------------------------------------------ */
+
+table.contentstable {
+ width: 90%;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+table.contentstable p.biglink {
+ line-height: 150%;
+}
+
+a.biglink {
+ font-size: 1.3em;
+}
+
+span.linkdescr {
+ font-style: italic;
+ padding-top: 5px;
+ font-size: 90%;
+}
+
+/* -- general index --------------------------------------------------------- */
+
+table.indextable {
+ width: 100%;
+}
+
+table.indextable td {
+ text-align: left;
+ vertical-align: top;
+}
+
+table.indextable ul {
+ margin-top: 0;
+ margin-bottom: 0;
+ list-style-type: none;
+}
+
+table.indextable > tbody > tr > td > ul {
+ padding-left: 0em;
+}
+
+table.indextable tr.pcap {
+ height: 10px;
+}
+
+table.indextable tr.cap {
+ margin-top: 10px;
+ background-color: #f2f2f2;
+}
+
+img.toggler {
+ margin-right: 3px;
+ margin-top: 3px;
+ cursor: pointer;
+}
+
+div.modindex-jumpbox {
+ border-top: 1px solid #ddd;
+ border-bottom: 1px solid #ddd;
+ margin: 1em 0 1em 0;
+ padding: 0.4em;
+}
+
+div.genindex-jumpbox {
+ border-top: 1px solid #ddd;
+ border-bottom: 1px solid #ddd;
+ margin: 1em 0 1em 0;
+ padding: 0.4em;
+}
+
+/* -- domain module index --------------------------------------------------- */
+
+table.modindextable td {
+ padding: 2px;
+ border-collapse: collapse;
+}
+
+/* -- general body styles --------------------------------------------------- */
+
+div.body {
+ min-width: 360px;
+ max-width: 800px;
+}
+
+div.body p, div.body dd, div.body li, div.body blockquote {
+ -moz-hyphens: auto;
+ -ms-hyphens: auto;
+ -webkit-hyphens: auto;
+ hyphens: auto;
+}
+
+a.headerlink {
+ visibility: hidden;
+}
+
+a:visited {
+ color: #551A8B;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink,
+caption:hover > a.headerlink,
+p.caption:hover > a.headerlink,
+div.code-block-caption:hover > a.headerlink {
+ visibility: visible;
+}
+
+div.body p.caption {
+ text-align: inherit;
+}
+
+div.body td {
+ text-align: left;
+}
+
+.first {
+ margin-top: 0 !important;
+}
+
+p.rubric {
+ margin-top: 30px;
+ font-weight: bold;
+}
+
+img.align-left, figure.align-left, .figure.align-left, object.align-left {
+ clear: left;
+ float: left;
+ margin-right: 1em;
+}
+
+img.align-right, figure.align-right, .figure.align-right, object.align-right {
+ clear: right;
+ float: right;
+ margin-left: 1em;
+}
+
+img.align-center, figure.align-center, .figure.align-center, object.align-center {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+img.align-default, figure.align-default, .figure.align-default {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.align-left {
+ text-align: left;
+}
+
+.align-center {
+ text-align: center;
+}
+
+.align-default {
+ text-align: center;
+}
+
+.align-right {
+ text-align: right;
+}
+
+/* -- sidebars -------------------------------------------------------------- */
+
+div.sidebar,
+aside.sidebar {
+ margin: 0 0 0.5em 1em;
+ border: 1px solid #ddb;
+ padding: 7px;
+ background-color: #ffe;
+ width: 40%;
+ float: right;
+ clear: right;
+ overflow-x: auto;
+}
+
+p.sidebar-title {
+ font-weight: bold;
+}
+
+nav.contents,
+aside.topic,
+div.admonition, div.topic, blockquote {
+ clear: left;
+}
+
+/* -- topics ---------------------------------------------------------------- */
+
+nav.contents,
+aside.topic,
+div.topic {
+ border: 1px solid #ccc;
+ padding: 7px;
+ margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 10px;
+}
+
+/* -- admonitions ----------------------------------------------------------- */
+
+div.admonition {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding: 7px;
+}
+
+div.admonition dt {
+ font-weight: bold;
+}
+
+p.admonition-title {
+ margin: 0px 10px 5px 0px;
+ font-weight: bold;
+}
+
+div.body p.centered {
+ text-align: center;
+ margin-top: 25px;
+}
+
+/* -- content of sidebars/topics/admonitions -------------------------------- */
+
+div.sidebar > :last-child,
+aside.sidebar > :last-child,
+nav.contents > :last-child,
+aside.topic > :last-child,
+div.topic > :last-child,
+div.admonition > :last-child {
+ margin-bottom: 0;
+}
+
+div.sidebar::after,
+aside.sidebar::after,
+nav.contents::after,
+aside.topic::after,
+div.topic::after,
+div.admonition::after,
+blockquote::after {
+ display: block;
+ content: '';
+ clear: both;
+}
+
+/* -- tables ---------------------------------------------------------------- */
+
+table.docutils {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ border: 0;
+ border-collapse: collapse;
+}
+
+table.align-center {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+table.align-default {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+table caption span.caption-number {
+ font-style: italic;
+}
+
+table caption span.caption-text {
+}
+
+table.docutils td, table.docutils th {
+ padding: 1px 8px 1px 5px;
+ border-top: 0;
+ border-left: 0;
+ border-right: 0;
+ border-bottom: 1px solid #aaa;
+}
+
+th {
+ text-align: left;
+ padding-right: 5px;
+}
+
+table.citation {
+ border-left: solid 1px gray;
+ margin-left: 1px;
+}
+
+table.citation td {
+ border-bottom: none;
+}
+
+th > :first-child,
+td > :first-child {
+ margin-top: 0px;
+}
+
+th > :last-child,
+td > :last-child {
+ margin-bottom: 0px;
+}
+
+/* -- figures --------------------------------------------------------------- */
+
+div.figure, figure {
+ margin: 0.5em;
+ padding: 0.5em;
+}
+
+div.figure p.caption, figcaption {
+ padding: 0.3em;
+}
+
+div.figure p.caption span.caption-number,
+figcaption span.caption-number {
+ font-style: italic;
+}
+
+div.figure p.caption span.caption-text,
+figcaption span.caption-text {
+}
+
+/* -- field list styles ----------------------------------------------------- */
+
+table.field-list td, table.field-list th {
+ border: 0 !important;
+}
+
+.field-list ul {
+ margin: 0;
+ padding-left: 1em;
+}
+
+.field-list p {
+ margin: 0;
+}
+
+.field-name {
+ -moz-hyphens: manual;
+ -ms-hyphens: manual;
+ -webkit-hyphens: manual;
+ hyphens: manual;
+}
+
+/* -- hlist styles ---------------------------------------------------------- */
+
+table.hlist {
+ margin: 1em 0;
+}
+
+table.hlist td {
+ vertical-align: top;
+}
+
+/* -- object description styles --------------------------------------------- */
+
+.sig {
+ font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
+}
+
+.sig-name, code.descname {
+ background-color: transparent;
+ font-weight: bold;
+}
+
+.sig-name {
+ font-size: 1.1em;
+}
+
+code.descname {
+ font-size: 1.2em;
+}
+
+.sig-prename, code.descclassname {
+ background-color: transparent;
+}
+
+.optional {
+ font-size: 1.3em;
+}
+
+.sig-paren {
+ font-size: larger;
+}
+
+.sig-param.n {
+ font-style: italic;
+}
+
+/* C++ specific styling */
+
+.sig-inline.c-texpr,
+.sig-inline.cpp-texpr {
+ font-family: unset;
+}
+
+.sig.c .k, .sig.c .kt,
+.sig.cpp .k, .sig.cpp .kt {
+ color: #0033B3;
+}
+
+.sig.c .m,
+.sig.cpp .m {
+ color: #1750EB;
+}
+
+.sig.c .s, .sig.c .sc,
+.sig.cpp .s, .sig.cpp .sc {
+ color: #067D17;
+}
+
+
+/* -- other body styles ----------------------------------------------------- */
+
+ol.arabic {
+ list-style: decimal;
+}
+
+ol.loweralpha {
+ list-style: lower-alpha;
+}
+
+ol.upperalpha {
+ list-style: upper-alpha;
+}
+
+ol.lowerroman {
+ list-style: lower-roman;
+}
+
+ol.upperroman {
+ list-style: upper-roman;
+}
+
+:not(li) > ol > li:first-child > :first-child,
+:not(li) > ul > li:first-child > :first-child {
+ margin-top: 0px;
+}
+
+:not(li) > ol > li:last-child > :last-child,
+:not(li) > ul > li:last-child > :last-child {
+ margin-bottom: 0px;
+}
+
+ol.simple ol p,
+ol.simple ul p,
+ul.simple ol p,
+ul.simple ul p {
+ margin-top: 0;
+}
+
+ol.simple > li:not(:first-child) > p,
+ul.simple > li:not(:first-child) > p {
+ margin-top: 0;
+}
+
+ol.simple p,
+ul.simple p {
+ margin-bottom: 0;
+}
+
+aside.footnote > span,
+div.citation > span {
+ float: left;
+}
+aside.footnote > span:last-of-type,
+div.citation > span:last-of-type {
+ padding-right: 0.5em;
+}
+aside.footnote > p {
+ margin-left: 2em;
+}
+div.citation > p {
+ margin-left: 4em;
+}
+aside.footnote > p:last-of-type,
+div.citation > p:last-of-type {
+ margin-bottom: 0em;
+}
+aside.footnote > p:last-of-type:after,
+div.citation > p:last-of-type:after {
+ content: "";
+ clear: both;
+}
+
+dl.field-list {
+ display: grid;
+ grid-template-columns: fit-content(30%) auto;
+}
+
+dl.field-list > dt {
+ font-weight: bold;
+ word-break: break-word;
+ padding-left: 0.5em;
+ padding-right: 5px;
+}
+
+dl.field-list > dd {
+ padding-left: 0.5em;
+ margin-top: 0em;
+ margin-left: 0em;
+ margin-bottom: 0em;
+}
+
+dl {
+ margin-bottom: 15px;
+}
+
+dd > :first-child {
+ margin-top: 0px;
+}
+
+dd ul, dd table {
+ margin-bottom: 10px;
+}
+
+dd {
+ margin-top: 3px;
+ margin-bottom: 10px;
+ margin-left: 30px;
+}
+
+.sig dd {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+.sig dl {
+ margin-top: 0px;
+ margin-bottom: 0px;
+}
+
+dl > dd:last-child,
+dl > dd:last-child > :last-child {
+ margin-bottom: 0;
+}
+
+dt:target, span.highlighted {
+ background-color: #fbe54e;
+}
+
+rect.highlighted {
+ fill: #fbe54e;
+}
+
+dl.glossary dt {
+ font-weight: bold;
+ font-size: 1.1em;
+}
+
+.versionmodified {
+ font-style: italic;
+}
+
+.system-message {
+ background-color: #fda;
+ padding: 5px;
+ border: 3px solid red;
+}
+
+.footnote:target {
+ background-color: #ffa;
+}
+
+.line-block {
+ display: block;
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+.line-block .line-block {
+ margin-top: 0;
+ margin-bottom: 0;
+ margin-left: 1.5em;
+}
+
+.guilabel, .menuselection {
+ font-family: sans-serif;
+}
+
+.accelerator {
+ text-decoration: underline;
+}
+
+.classifier {
+ font-style: oblique;
+}
+
+.classifier:before {
+ font-style: normal;
+ margin: 0 0.5em;
+ content: ":";
+ display: inline-block;
+}
+
+abbr, acronym {
+ border-bottom: dotted 1px;
+ cursor: help;
+}
+
+.translated {
+ background-color: rgba(207, 255, 207, 0.2)
+}
+
+.untranslated {
+ background-color: rgba(255, 207, 207, 0.2)
+}
+
+/* -- code displays --------------------------------------------------------- */
+
+pre {
+ overflow: auto;
+ overflow-y: hidden; /* fixes display issues on Chrome browsers */
+}
+
+pre, div[class*="highlight-"] {
+ clear: both;
+}
+
+span.pre {
+ -moz-hyphens: none;
+ -ms-hyphens: none;
+ -webkit-hyphens: none;
+ hyphens: none;
+ white-space: nowrap;
+}
+
+div[class*="highlight-"] {
+ margin: 1em 0;
+}
+
+td.linenos pre {
+ border: 0;
+ background-color: transparent;
+ color: #aaa;
+}
+
+table.highlighttable {
+ display: block;
+}
+
+table.highlighttable tbody {
+ display: block;
+}
+
+table.highlighttable tr {
+ display: flex;
+}
+
+table.highlighttable td {
+ margin: 0;
+ padding: 0;
+}
+
+table.highlighttable td.linenos {
+ padding-right: 0.5em;
+}
+
+table.highlighttable td.code {
+ flex: 1;
+ overflow: hidden;
+}
+
+.highlight .hll {
+ display: block;
+}
+
+div.highlight pre,
+table.highlighttable pre {
+ margin: 0;
+}
+
+div.code-block-caption + div {
+ margin-top: 0;
+}
+
+div.code-block-caption {
+ margin-top: 1em;
+ padding: 2px 5px;
+ font-size: small;
+}
+
+div.code-block-caption code {
+ background-color: transparent;
+}
+
+table.highlighttable td.linenos,
+span.linenos,
+div.highlight span.gp { /* gp: Generic.Prompt */
+ user-select: none;
+ -webkit-user-select: text; /* Safari fallback only */
+ -webkit-user-select: none; /* Chrome/Safari */
+ -moz-user-select: none; /* Firefox */
+ -ms-user-select: none; /* IE10+ */
+}
+
+div.code-block-caption span.caption-number {
+ padding: 0.1em 0.3em;
+ font-style: italic;
+}
+
+div.code-block-caption span.caption-text {
+}
+
+div.literal-block-wrapper {
+ margin: 1em 0;
+}
+
+code.xref, a code {
+ background-color: transparent;
+ font-weight: bold;
+}
+
+h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
+ background-color: transparent;
+}
+
+.viewcode-link {
+ float: right;
+}
+
+.viewcode-back {
+ float: right;
+ font-family: sans-serif;
+}
+
+div.viewcode-block:target {
+ margin: -1px -10px;
+ padding: 0 10px;
+}
+
+/* -- math display ---------------------------------------------------------- */
+
+img.math {
+ vertical-align: middle;
+}
+
+div.body div.math p {
+ text-align: center;
+}
+
+span.eqno {
+ float: right;
+}
+
+span.eqno a.headerlink {
+ position: absolute;
+ z-index: 1;
+}
+
+div.math:hover a.headerlink {
+ visibility: visible;
+}
+
+/* -- printout stylesheet --------------------------------------------------- */
+
+@media print {
+ div.document,
+ div.documentwrapper,
+ div.bodywrapper {
+ margin: 0 !important;
+ width: 100%;
+ }
+
+ div.sphinxsidebar,
+ div.related,
+ div.footer,
+ #top-link {
+ display: none;
+ }
+}
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/_static/check-solid.svg b/docs/serve/v2.1.24.0/_static/check-solid.svg
new file mode 100644
index 0000000..92fad4b
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/check-solid.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/docs/serve/v2.1.24.0/_static/clipboard.min.js b/docs/serve/v2.1.24.0/_static/clipboard.min.js
new file mode 100644
index 0000000..54b3c46
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/clipboard.min.js
@@ -0,0 +1,7 @@
+/*!
+ * clipboard.js v2.0.8
+ * https://clipboardjs.com/
+ *
+ * Licensed MIT © Zeno Rocha
+ */
+!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1
+
+
+
+
diff --git a/docs/serve/v2.1.24.0/_static/copybutton.css b/docs/serve/v2.1.24.0/_static/copybutton.css
new file mode 100644
index 0000000..f1916ec
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/copybutton.css
@@ -0,0 +1,94 @@
+/* Copy buttons */
+button.copybtn {
+ position: absolute;
+ display: flex;
+ top: .3em;
+ right: .3em;
+ width: 1.7em;
+ height: 1.7em;
+ opacity: 0;
+ transition: opacity 0.3s, border .3s, background-color .3s;
+ user-select: none;
+ padding: 0;
+ border: none;
+ outline: none;
+ border-radius: 0.4em;
+ /* The colors that GitHub uses */
+ border: #1b1f2426 1px solid;
+ background-color: #f6f8fa;
+ color: #57606a;
+}
+
+button.copybtn.success {
+ border-color: #22863a;
+ color: #22863a;
+}
+
+button.copybtn svg {
+ stroke: currentColor;
+ width: 1.5em;
+ height: 1.5em;
+ padding: 0.1em;
+}
+
+div.highlight {
+ position: relative;
+}
+
+/* Show the copybutton */
+.highlight:hover button.copybtn, button.copybtn.success {
+ opacity: 1;
+}
+
+.highlight button.copybtn:hover {
+ background-color: rgb(235, 235, 235);
+}
+
+.highlight button.copybtn:active {
+ background-color: rgb(187, 187, 187);
+}
+
+/**
+ * A minimal CSS-only tooltip copied from:
+ * https://codepen.io/mildrenben/pen/rVBrpK
+ *
+ * To use, write HTML like the following:
+ *
+ * Short
+ */
+ .o-tooltip--left {
+ position: relative;
+ }
+
+ .o-tooltip--left:after {
+ opacity: 0;
+ visibility: hidden;
+ position: absolute;
+ content: attr(data-tooltip);
+ padding: .2em;
+ font-size: .8em;
+ left: -.2em;
+ background: grey;
+ color: white;
+ white-space: nowrap;
+ z-index: 2;
+ border-radius: 2px;
+ transform: translateX(-102%) translateY(0);
+ transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1);
+}
+
+.o-tooltip--left:hover:after {
+ display: block;
+ opacity: 1;
+ visibility: visible;
+ transform: translateX(-100%) translateY(0);
+ transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1);
+ transition-delay: .5s;
+}
+
+/* By default the copy button shouldn't show up when printing a page */
+@media print {
+ button.copybtn {
+ display: none;
+ }
+}
diff --git a/docs/serve/v2.1.24.0/_static/copybutton.js b/docs/serve/v2.1.24.0/_static/copybutton.js
new file mode 100644
index 0000000..2ea7ff3
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/copybutton.js
@@ -0,0 +1,248 @@
+// Localization support
+const messages = {
+ 'en': {
+ 'copy': 'Copy',
+ 'copy_to_clipboard': 'Copy to clipboard',
+ 'copy_success': 'Copied!',
+ 'copy_failure': 'Failed to copy',
+ },
+ 'es' : {
+ 'copy': 'Copiar',
+ 'copy_to_clipboard': 'Copiar al portapapeles',
+ 'copy_success': '¡Copiado!',
+ 'copy_failure': 'Error al copiar',
+ },
+ 'de' : {
+ 'copy': 'Kopieren',
+ 'copy_to_clipboard': 'In die Zwischenablage kopieren',
+ 'copy_success': 'Kopiert!',
+ 'copy_failure': 'Fehler beim Kopieren',
+ },
+ 'fr' : {
+ 'copy': 'Copier',
+ 'copy_to_clipboard': 'Copier dans le presse-papier',
+ 'copy_success': 'Copié !',
+ 'copy_failure': 'Échec de la copie',
+ },
+ 'ru': {
+ 'copy': 'Скопировать',
+ 'copy_to_clipboard': 'Скопировать в буфер',
+ 'copy_success': 'Скопировано!',
+ 'copy_failure': 'Не удалось скопировать',
+ },
+ 'zh-CN': {
+ 'copy': '复制',
+ 'copy_to_clipboard': '复制到剪贴板',
+ 'copy_success': '复制成功!',
+ 'copy_failure': '复制失败',
+ },
+ 'it' : {
+ 'copy': 'Copiare',
+ 'copy_to_clipboard': 'Copiato negli appunti',
+ 'copy_success': 'Copiato!',
+ 'copy_failure': 'Errore durante la copia',
+ }
+}
+
+let locale = 'en'
+if( document.documentElement.lang !== undefined
+ && messages[document.documentElement.lang] !== undefined ) {
+ locale = document.documentElement.lang
+}
+
+let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT;
+if (doc_url_root == '#') {
+ doc_url_root = '';
+}
+
+/**
+ * SVG files for our copy buttons
+ */
+let iconCheck = `
+ ${messages[locale]['copy_success']}
+
+
+ `
+
+// If the user specified their own SVG use that, otherwise use the default
+let iconCopy = ``;
+if (!iconCopy) {
+ iconCopy = `
+ ${messages[locale]['copy_to_clipboard']}
+
+
+
+ `
+}
+
+/**
+ * Set up copy/paste for code blocks
+ */
+
+const runWhenDOMLoaded = cb => {
+ if (document.readyState != 'loading') {
+ cb()
+ } else if (document.addEventListener) {
+ document.addEventListener('DOMContentLoaded', cb)
+ } else {
+ document.attachEvent('onreadystatechange', function() {
+ if (document.readyState == 'complete') cb()
+ })
+ }
+}
+
+const codeCellId = index => `codecell${index}`
+
+// Clears selected text since ClipboardJS will select the text when copying
+const clearSelection = () => {
+ if (window.getSelection) {
+ window.getSelection().removeAllRanges()
+ } else if (document.selection) {
+ document.selection.empty()
+ }
+}
+
+// Changes tooltip text for a moment, then changes it back
+// We want the timeout of our `success` class to be a bit shorter than the
+// tooltip and icon change, so that we can hide the icon before changing back.
+var timeoutIcon = 2000;
+var timeoutSuccessClass = 1500;
+
+const temporarilyChangeTooltip = (el, oldText, newText) => {
+ el.setAttribute('data-tooltip', newText)
+ el.classList.add('success')
+ // Remove success a little bit sooner than we change the tooltip
+ // So that we can use CSS to hide the copybutton first
+ setTimeout(() => el.classList.remove('success'), timeoutSuccessClass)
+ setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon)
+}
+
+// Changes the copy button icon for two seconds, then changes it back
+const temporarilyChangeIcon = (el) => {
+ el.innerHTML = iconCheck;
+ setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon)
+}
+
+const addCopyButtonToCodeCells = () => {
+ // If ClipboardJS hasn't loaded, wait a bit and try again. This
+ // happens because we load ClipboardJS asynchronously.
+ if (window.ClipboardJS === undefined) {
+ setTimeout(addCopyButtonToCodeCells, 250)
+ return
+ }
+
+ // Add copybuttons to all of our code cells
+ const COPYBUTTON_SELECTOR = 'div.highlight pre';
+ const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR)
+ codeCells.forEach((codeCell, index) => {
+ const id = codeCellId(index)
+ codeCell.setAttribute('id', id)
+
+ const clipboardButton = id =>
+ `
+ ${iconCopy}
+ `
+ codeCell.insertAdjacentHTML('afterend', clipboardButton(id))
+ })
+
+function escapeRegExp(string) {
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
+}
+
+/**
+ * Removes excluded text from a Node.
+ *
+ * @param {Node} target Node to filter.
+ * @param {string} exclude CSS selector of nodes to exclude.
+ * @returns {DOMString} Text from `target` with text removed.
+ */
+function filterText(target, exclude) {
+ const clone = target.cloneNode(true); // clone as to not modify the live DOM
+ if (exclude) {
+ // remove excluded nodes
+ clone.querySelectorAll(exclude).forEach(node => node.remove());
+ }
+ return clone.innerText;
+}
+
+// Callback when a copy button is clicked. Will be passed the node that was clicked
+// should then grab the text and replace pieces of text that shouldn't be used in output
+function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") {
+ var regexp;
+ var match;
+
+ // Do we check for line continuation characters and "HERE-documents"?
+ var useLineCont = !!lineContinuationChar
+ var useHereDoc = !!hereDocDelim
+
+ // create regexp to capture prompt and remaining line
+ if (isRegexp) {
+ regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)')
+ } else {
+ regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)')
+ }
+
+ const outputLines = [];
+ var promptFound = false;
+ var gotLineCont = false;
+ var gotHereDoc = false;
+ const lineGotPrompt = [];
+ for (const line of textContent.split('\n')) {
+ match = line.match(regexp)
+ if (match || gotLineCont || gotHereDoc) {
+ promptFound = regexp.test(line)
+ lineGotPrompt.push(promptFound)
+ if (removePrompts && promptFound) {
+ outputLines.push(match[2])
+ } else {
+ outputLines.push(line)
+ }
+ gotLineCont = line.endsWith(lineContinuationChar) & useLineCont
+ if (line.includes(hereDocDelim) & useHereDoc)
+ gotHereDoc = !gotHereDoc
+ } else if (!onlyCopyPromptLines) {
+ outputLines.push(line)
+ } else if (copyEmptyLines && line.trim() === '') {
+ outputLines.push(line)
+ }
+ }
+
+ // If no lines with the prompt were found then just use original lines
+ if (lineGotPrompt.some(v => v === true)) {
+ textContent = outputLines.join('\n');
+ }
+
+ // Remove a trailing newline to avoid auto-running when pasting
+ if (textContent.endsWith("\n")) {
+ textContent = textContent.slice(0, -1)
+ }
+ return textContent
+}
+
+
+var copyTargetText = (trigger) => {
+ var target = document.querySelector(trigger.attributes['data-clipboard-target'].value);
+
+ // get filtered text
+ let exclude = '.linenos';
+
+ let text = filterText(target, exclude);
+ return formatCopyText(text, '', false, true, true, true, '', '')
+}
+
+ // Initialize with a callback so we can modify the text before copy
+ const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText})
+
+ // Update UI with error/success messages
+ clipboard.on('success', event => {
+ clearSelection()
+ temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success'])
+ temporarilyChangeIcon(event.trigger)
+ })
+
+ clipboard.on('error', event => {
+ temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure'])
+ })
+}
+
+runWhenDOMLoaded(addCopyButtonToCodeCells)
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/_static/copybutton_funcs.js b/docs/serve/v2.1.24.0/_static/copybutton_funcs.js
new file mode 100644
index 0000000..dbe1aaa
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/copybutton_funcs.js
@@ -0,0 +1,73 @@
+function escapeRegExp(string) {
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
+}
+
+/**
+ * Removes excluded text from a Node.
+ *
+ * @param {Node} target Node to filter.
+ * @param {string} exclude CSS selector of nodes to exclude.
+ * @returns {DOMString} Text from `target` with text removed.
+ */
+export function filterText(target, exclude) {
+ const clone = target.cloneNode(true); // clone as to not modify the live DOM
+ if (exclude) {
+ // remove excluded nodes
+ clone.querySelectorAll(exclude).forEach(node => node.remove());
+ }
+ return clone.innerText;
+}
+
+// Callback when a copy button is clicked. Will be passed the node that was clicked
+// should then grab the text and replace pieces of text that shouldn't be used in output
+export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") {
+ var regexp;
+ var match;
+
+ // Do we check for line continuation characters and "HERE-documents"?
+ var useLineCont = !!lineContinuationChar
+ var useHereDoc = !!hereDocDelim
+
+ // create regexp to capture prompt and remaining line
+ if (isRegexp) {
+ regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)')
+ } else {
+ regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)')
+ }
+
+ const outputLines = [];
+ var promptFound = false;
+ var gotLineCont = false;
+ var gotHereDoc = false;
+ const lineGotPrompt = [];
+ for (const line of textContent.split('\n')) {
+ match = line.match(regexp)
+ if (match || gotLineCont || gotHereDoc) {
+ promptFound = regexp.test(line)
+ lineGotPrompt.push(promptFound)
+ if (removePrompts && promptFound) {
+ outputLines.push(match[2])
+ } else {
+ outputLines.push(line)
+ }
+ gotLineCont = line.endsWith(lineContinuationChar) & useLineCont
+ if (line.includes(hereDocDelim) & useHereDoc)
+ gotHereDoc = !gotHereDoc
+ } else if (!onlyCopyPromptLines) {
+ outputLines.push(line)
+ } else if (copyEmptyLines && line.trim() === '') {
+ outputLines.push(line)
+ }
+ }
+
+ // If no lines with the prompt were found then just use original lines
+ if (lineGotPrompt.some(v => v === true)) {
+ textContent = outputLines.join('\n');
+ }
+
+ // Remove a trailing newline to avoid auto-running when pasting
+ if (textContent.endsWith("\n")) {
+ textContent = textContent.slice(0, -1)
+ }
+ return textContent
+}
diff --git a/docs/serve/v2.1.24.0/_static/css/badge_only.css b/docs/serve/v2.1.24.0/_static/css/badge_only.css
new file mode 100644
index 0000000..c718cee
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/css/badge_only.css
@@ -0,0 +1 @@
+.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/_static/css/fonts/Roboto-Slab-Bold.woff b/docs/serve/v2.1.24.0/_static/css/fonts/Roboto-Slab-Bold.woff
new file mode 100644
index 0000000..6cb6000
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/css/fonts/Roboto-Slab-Bold.woff differ
diff --git a/docs/serve/v2.1.24.0/_static/css/fonts/Roboto-Slab-Bold.woff2 b/docs/serve/v2.1.24.0/_static/css/fonts/Roboto-Slab-Bold.woff2
new file mode 100644
index 0000000..7059e23
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/css/fonts/Roboto-Slab-Bold.woff2 differ
diff --git a/docs/serve/v2.1.24.0/_static/css/fonts/Roboto-Slab-Regular.woff b/docs/serve/v2.1.24.0/_static/css/fonts/Roboto-Slab-Regular.woff
new file mode 100644
index 0000000..f815f63
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/css/fonts/Roboto-Slab-Regular.woff differ
diff --git a/docs/serve/v2.1.24.0/_static/css/fonts/Roboto-Slab-Regular.woff2 b/docs/serve/v2.1.24.0/_static/css/fonts/Roboto-Slab-Regular.woff2
new file mode 100644
index 0000000..f2c76e5
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/css/fonts/Roboto-Slab-Regular.woff2 differ
diff --git a/docs/serve/v2.1.24.0/_static/css/fonts/fontawesome-webfont.eot b/docs/serve/v2.1.24.0/_static/css/fonts/fontawesome-webfont.eot
new file mode 100644
index 0000000..e9f60ca
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/css/fonts/fontawesome-webfont.eot differ
diff --git a/docs/serve/v2.1.24.0/_static/css/fonts/fontawesome-webfont.svg b/docs/serve/v2.1.24.0/_static/css/fonts/fontawesome-webfont.svg
new file mode 100644
index 0000000..855c845
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/css/fonts/fontawesome-webfont.svg
@@ -0,0 +1,2671 @@
+
+
+
+
+Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016
+ By ,,,
+Copyright Dave Gandy 2016. All rights reserved.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/serve/v2.1.24.0/_static/css/fonts/fontawesome-webfont.ttf b/docs/serve/v2.1.24.0/_static/css/fonts/fontawesome-webfont.ttf
new file mode 100644
index 0000000..35acda2
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/css/fonts/fontawesome-webfont.ttf differ
diff --git a/docs/serve/v2.1.24.0/_static/css/fonts/fontawesome-webfont.woff b/docs/serve/v2.1.24.0/_static/css/fonts/fontawesome-webfont.woff
new file mode 100644
index 0000000..400014a
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/css/fonts/fontawesome-webfont.woff differ
diff --git a/docs/serve/v2.1.24.0/_static/css/fonts/fontawesome-webfont.woff2 b/docs/serve/v2.1.24.0/_static/css/fonts/fontawesome-webfont.woff2
new file mode 100644
index 0000000..4d13fc6
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/css/fonts/fontawesome-webfont.woff2 differ
diff --git a/docs/serve/v2.1.24.0/_static/css/fonts/lato-bold-italic.woff b/docs/serve/v2.1.24.0/_static/css/fonts/lato-bold-italic.woff
new file mode 100644
index 0000000..88ad05b
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/css/fonts/lato-bold-italic.woff differ
diff --git a/docs/serve/v2.1.24.0/_static/css/fonts/lato-bold-italic.woff2 b/docs/serve/v2.1.24.0/_static/css/fonts/lato-bold-italic.woff2
new file mode 100644
index 0000000..c4e3d80
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/css/fonts/lato-bold-italic.woff2 differ
diff --git a/docs/serve/v2.1.24.0/_static/css/fonts/lato-bold.woff b/docs/serve/v2.1.24.0/_static/css/fonts/lato-bold.woff
new file mode 100644
index 0000000..c6dff51
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/css/fonts/lato-bold.woff differ
diff --git a/docs/serve/v2.1.24.0/_static/css/fonts/lato-bold.woff2 b/docs/serve/v2.1.24.0/_static/css/fonts/lato-bold.woff2
new file mode 100644
index 0000000..bb19504
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/css/fonts/lato-bold.woff2 differ
diff --git a/docs/serve/v2.1.24.0/_static/css/fonts/lato-normal-italic.woff b/docs/serve/v2.1.24.0/_static/css/fonts/lato-normal-italic.woff
new file mode 100644
index 0000000..76114bc
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/css/fonts/lato-normal-italic.woff differ
diff --git a/docs/serve/v2.1.24.0/_static/css/fonts/lato-normal-italic.woff2 b/docs/serve/v2.1.24.0/_static/css/fonts/lato-normal-italic.woff2
new file mode 100644
index 0000000..3404f37
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/css/fonts/lato-normal-italic.woff2 differ
diff --git a/docs/serve/v2.1.24.0/_static/css/fonts/lato-normal.woff b/docs/serve/v2.1.24.0/_static/css/fonts/lato-normal.woff
new file mode 100644
index 0000000..ae1307f
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/css/fonts/lato-normal.woff differ
diff --git a/docs/serve/v2.1.24.0/_static/css/fonts/lato-normal.woff2 b/docs/serve/v2.1.24.0/_static/css/fonts/lato-normal.woff2
new file mode 100644
index 0000000..3bf9843
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/css/fonts/lato-normal.woff2 differ
diff --git a/docs/serve/v2.1.24.0/_static/css/theme.css b/docs/serve/v2.1.24.0/_static/css/theme.css
new file mode 100644
index 0000000..19a446a
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/css/theme.css
@@ -0,0 +1,4 @@
+html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*!
+ * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
+ * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block}
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/_static/doctools.js b/docs/serve/v2.1.24.0/_static/doctools.js
new file mode 100644
index 0000000..d06a71d
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/doctools.js
@@ -0,0 +1,156 @@
+/*
+ * doctools.js
+ * ~~~~~~~~~~~
+ *
+ * Base JavaScript utilities for all Sphinx HTML documentation.
+ *
+ * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+"use strict";
+
+const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([
+ "TEXTAREA",
+ "INPUT",
+ "SELECT",
+ "BUTTON",
+]);
+
+const _ready = (callback) => {
+ if (document.readyState !== "loading") {
+ callback();
+ } else {
+ document.addEventListener("DOMContentLoaded", callback);
+ }
+};
+
+/**
+ * Small JavaScript module for the documentation.
+ */
+const Documentation = {
+ init: () => {
+ Documentation.initDomainIndexTable();
+ Documentation.initOnKeyListeners();
+ },
+
+ /**
+ * i18n support
+ */
+ TRANSLATIONS: {},
+ PLURAL_EXPR: (n) => (n === 1 ? 0 : 1),
+ LOCALE: "unknown",
+
+ // gettext and ngettext don't access this so that the functions
+ // can safely bound to a different name (_ = Documentation.gettext)
+ gettext: (string) => {
+ const translated = Documentation.TRANSLATIONS[string];
+ switch (typeof translated) {
+ case "undefined":
+ return string; // no translation
+ case "string":
+ return translated; // translation exists
+ default:
+ return translated[0]; // (singular, plural) translation tuple exists
+ }
+ },
+
+ ngettext: (singular, plural, n) => {
+ const translated = Documentation.TRANSLATIONS[singular];
+ if (typeof translated !== "undefined")
+ return translated[Documentation.PLURAL_EXPR(n)];
+ return n === 1 ? singular : plural;
+ },
+
+ addTranslations: (catalog) => {
+ Object.assign(Documentation.TRANSLATIONS, catalog.messages);
+ Documentation.PLURAL_EXPR = new Function(
+ "n",
+ `return (${catalog.plural_expr})`
+ );
+ Documentation.LOCALE = catalog.locale;
+ },
+
+ /**
+ * helper function to focus on search bar
+ */
+ focusSearchBar: () => {
+ document.querySelectorAll("input[name=q]")[0]?.focus();
+ },
+
+ /**
+ * Initialise the domain index toggle buttons
+ */
+ initDomainIndexTable: () => {
+ const toggler = (el) => {
+ const idNumber = el.id.substr(7);
+ const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`);
+ if (el.src.substr(-9) === "minus.png") {
+ el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`;
+ toggledRows.forEach((el) => (el.style.display = "none"));
+ } else {
+ el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`;
+ toggledRows.forEach((el) => (el.style.display = ""));
+ }
+ };
+
+ const togglerElements = document.querySelectorAll("img.toggler");
+ togglerElements.forEach((el) =>
+ el.addEventListener("click", (event) => toggler(event.currentTarget))
+ );
+ togglerElements.forEach((el) => (el.style.display = ""));
+ if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler);
+ },
+
+ initOnKeyListeners: () => {
+ // only install a listener if it is really needed
+ if (
+ !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS &&
+ !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS
+ )
+ return;
+
+ document.addEventListener("keydown", (event) => {
+ // bail for input elements
+ if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return;
+ // bail with special keys
+ if (event.altKey || event.ctrlKey || event.metaKey) return;
+
+ if (!event.shiftKey) {
+ switch (event.key) {
+ case "ArrowLeft":
+ if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;
+
+ const prevLink = document.querySelector('link[rel="prev"]');
+ if (prevLink && prevLink.href) {
+ window.location.href = prevLink.href;
+ event.preventDefault();
+ }
+ break;
+ case "ArrowRight":
+ if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;
+
+ const nextLink = document.querySelector('link[rel="next"]');
+ if (nextLink && nextLink.href) {
+ window.location.href = nextLink.href;
+ event.preventDefault();
+ }
+ break;
+ }
+ }
+
+ // some keyboard layouts may need Shift to get /
+ switch (event.key) {
+ case "/":
+ if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break;
+ Documentation.focusSearchBar();
+ event.preventDefault();
+ }
+ });
+ },
+};
+
+// quick alias for translations
+const _ = Documentation.gettext;
+
+_ready(Documentation.init);
diff --git a/docs/serve/v2.1.24.0/_static/documentation_options.js b/docs/serve/v2.1.24.0/_static/documentation_options.js
new file mode 100644
index 0000000..a948c6e
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/documentation_options.js
@@ -0,0 +1,13 @@
+const DOCUMENTATION_OPTIONS = {
+ VERSION: 'f',
+ LANGUAGE: 'en',
+ COLLAPSE_INDEX: false,
+ BUILDER: 'html',
+ FILE_SUFFIX: '.html',
+ LINK_SUFFIX: '.html',
+ HAS_SOURCE: true,
+ SOURCELINK_SUFFIX: '.txt',
+ NAVIGATION_WITH_KEYS: false,
+ SHOW_SEARCH_SUMMARY: true,
+ ENABLE_SEARCH_SHORTCUTS: true,
+};
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/_static/file.png b/docs/serve/v2.1.24.0/_static/file.png
new file mode 100644
index 0000000..a858a41
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/file.png differ
diff --git a/docs/serve/v2.1.24.0/_static/jquery.js b/docs/serve/v2.1.24.0/_static/jquery.js
new file mode 100644
index 0000000..c4c6022
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/jquery.js
@@ -0,0 +1,2 @@
+/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */
+!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML=" ",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML=" ";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML=" ",y.option=!!ce.lastChild;var ge={thead:[1,""],col:[2,""],tr:[2,""],td:[3,""],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML=" ",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document);
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/_static/js/html5shiv.min.js b/docs/serve/v2.1.24.0/_static/js/html5shiv.min.js
new file mode 100644
index 0000000..cd1c674
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/js/html5shiv.min.js
@@ -0,0 +1,4 @@
+/**
+* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
+*/
+!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML=" ",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document);
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/_static/js/theme.js b/docs/serve/v2.1.24.0/_static/js/theme.js
new file mode 100644
index 0000000..1fddb6e
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/js/theme.js
@@ -0,0 +1 @@
+!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap(""),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(' '),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0
+ var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
+ var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
+ var s_v = "^(" + C + ")?" + v; // vowel in stem
+
+ this.stemWord = function (w) {
+ var stem;
+ var suffix;
+ var firstch;
+ var origword = w;
+
+ if (w.length < 3)
+ return w;
+
+ var re;
+ var re2;
+ var re3;
+ var re4;
+
+ firstch = w.substr(0,1);
+ if (firstch == "y")
+ w = firstch.toUpperCase() + w.substr(1);
+
+ // Step 1a
+ re = /^(.+?)(ss|i)es$/;
+ re2 = /^(.+?)([^s])s$/;
+
+ if (re.test(w))
+ w = w.replace(re,"$1$2");
+ else if (re2.test(w))
+ w = w.replace(re2,"$1$2");
+
+ // Step 1b
+ re = /^(.+?)eed$/;
+ re2 = /^(.+?)(ed|ing)$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ re = new RegExp(mgr0);
+ if (re.test(fp[1])) {
+ re = /.$/;
+ w = w.replace(re,"");
+ }
+ }
+ else if (re2.test(w)) {
+ var fp = re2.exec(w);
+ stem = fp[1];
+ re2 = new RegExp(s_v);
+ if (re2.test(stem)) {
+ w = stem;
+ re2 = /(at|bl|iz)$/;
+ re3 = new RegExp("([^aeiouylsz])\\1$");
+ re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
+ if (re2.test(w))
+ w = w + "e";
+ else if (re3.test(w)) {
+ re = /.$/;
+ w = w.replace(re,"");
+ }
+ else if (re4.test(w))
+ w = w + "e";
+ }
+ }
+
+ // Step 1c
+ re = /^(.+?)y$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ stem = fp[1];
+ re = new RegExp(s_v);
+ if (re.test(stem))
+ w = stem + "i";
+ }
+
+ // Step 2
+ re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ stem = fp[1];
+ suffix = fp[2];
+ re = new RegExp(mgr0);
+ if (re.test(stem))
+ w = stem + step2list[suffix];
+ }
+
+ // Step 3
+ re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ stem = fp[1];
+ suffix = fp[2];
+ re = new RegExp(mgr0);
+ if (re.test(stem))
+ w = stem + step3list[suffix];
+ }
+
+ // Step 4
+ re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
+ re2 = /^(.+?)(s|t)(ion)$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ stem = fp[1];
+ re = new RegExp(mgr1);
+ if (re.test(stem))
+ w = stem;
+ }
+ else if (re2.test(w)) {
+ var fp = re2.exec(w);
+ stem = fp[1] + fp[2];
+ re2 = new RegExp(mgr1);
+ if (re2.test(stem))
+ w = stem;
+ }
+
+ // Step 5
+ re = /^(.+?)e$/;
+ if (re.test(w)) {
+ var fp = re.exec(w);
+ stem = fp[1];
+ re = new RegExp(mgr1);
+ re2 = new RegExp(meq1);
+ re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
+ if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
+ w = stem;
+ }
+ re = /ll$/;
+ re2 = new RegExp(mgr1);
+ if (re.test(w) && re2.test(w)) {
+ re = /.$/;
+ w = w.replace(re,"");
+ }
+
+ // and turn initial Y back to y
+ if (firstch == "y")
+ w = firstch.toLowerCase() + w.substr(1);
+ return w;
+ }
+}
+
diff --git a/docs/serve/v2.1.24.0/_static/minus.png b/docs/serve/v2.1.24.0/_static/minus.png
new file mode 100644
index 0000000..d96755f
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/minus.png differ
diff --git a/docs/serve/v2.1.24.0/_static/nbsphinx-broken-thumbnail.svg b/docs/serve/v2.1.24.0/_static/nbsphinx-broken-thumbnail.svg
new file mode 100644
index 0000000..4919ca8
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/nbsphinx-broken-thumbnail.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/docs/serve/v2.1.24.0/_static/nbsphinx-code-cells.css b/docs/serve/v2.1.24.0/_static/nbsphinx-code-cells.css
new file mode 100644
index 0000000..a3fb27c
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/nbsphinx-code-cells.css
@@ -0,0 +1,259 @@
+/* remove conflicting styling from Sphinx themes */
+div.nbinput.container div.prompt *,
+div.nboutput.container div.prompt *,
+div.nbinput.container div.input_area pre,
+div.nboutput.container div.output_area pre,
+div.nbinput.container div.input_area .highlight,
+div.nboutput.container div.output_area .highlight {
+ border: none;
+ padding: 0;
+ margin: 0;
+ box-shadow: none;
+}
+
+div.nbinput.container > div[class*=highlight],
+div.nboutput.container > div[class*=highlight] {
+ margin: 0;
+}
+
+div.nbinput.container div.prompt *,
+div.nboutput.container div.prompt * {
+ background: none;
+}
+
+div.nboutput.container div.output_area .highlight,
+div.nboutput.container div.output_area pre {
+ background: unset;
+}
+
+div.nboutput.container div.output_area div.highlight {
+ color: unset; /* override Pygments text color */
+}
+
+/* avoid gaps between output lines */
+div.nboutput.container div[class*=highlight] pre {
+ line-height: normal;
+}
+
+/* input/output containers */
+div.nbinput.container,
+div.nboutput.container {
+ display: -webkit-flex;
+ display: flex;
+ align-items: flex-start;
+ margin: 0;
+ width: 100%;
+}
+@media (max-width: 540px) {
+ div.nbinput.container,
+ div.nboutput.container {
+ flex-direction: column;
+ }
+}
+
+/* input container */
+div.nbinput.container {
+ padding-top: 5px;
+}
+
+/* last container */
+div.nblast.container {
+ padding-bottom: 5px;
+}
+
+/* input prompt */
+div.nbinput.container div.prompt pre,
+/* for sphinx_immaterial theme: */
+div.nbinput.container div.prompt pre > code {
+ color: #307FC1;
+}
+
+/* output prompt */
+div.nboutput.container div.prompt pre,
+/* for sphinx_immaterial theme: */
+div.nboutput.container div.prompt pre > code {
+ color: #BF5B3D;
+}
+
+/* all prompts */
+div.nbinput.container div.prompt,
+div.nboutput.container div.prompt {
+ width: 4.5ex;
+ padding-top: 5px;
+ position: relative;
+ user-select: none;
+}
+
+div.nbinput.container div.prompt > div,
+div.nboutput.container div.prompt > div {
+ position: absolute;
+ right: 0;
+ margin-right: 0.3ex;
+}
+
+@media (max-width: 540px) {
+ div.nbinput.container div.prompt,
+ div.nboutput.container div.prompt {
+ width: unset;
+ text-align: left;
+ padding: 0.4em;
+ }
+ div.nboutput.container div.prompt.empty {
+ padding: 0;
+ }
+
+ div.nbinput.container div.prompt > div,
+ div.nboutput.container div.prompt > div {
+ position: unset;
+ }
+}
+
+/* disable scrollbars and line breaks on prompts */
+div.nbinput.container div.prompt pre,
+div.nboutput.container div.prompt pre {
+ overflow: hidden;
+ white-space: pre;
+}
+
+/* input/output area */
+div.nbinput.container div.input_area,
+div.nboutput.container div.output_area {
+ -webkit-flex: 1;
+ flex: 1;
+ overflow: auto;
+}
+@media (max-width: 540px) {
+ div.nbinput.container div.input_area,
+ div.nboutput.container div.output_area {
+ width: 100%;
+ }
+}
+
+/* input area */
+div.nbinput.container div.input_area {
+ border: 1px solid #e0e0e0;
+ border-radius: 2px;
+ /*background: #f5f5f5;*/
+}
+
+/* override MathJax center alignment in output cells */
+div.nboutput.container div[class*=MathJax] {
+ text-align: left !important;
+}
+
+/* override sphinx.ext.imgmath center alignment in output cells */
+div.nboutput.container div.math p {
+ text-align: left;
+}
+
+/* standard error */
+div.nboutput.container div.output_area.stderr {
+ background: #fdd;
+}
+
+/* ANSI colors */
+.ansi-black-fg { color: #3E424D; }
+.ansi-black-bg { background-color: #3E424D; }
+.ansi-black-intense-fg { color: #282C36; }
+.ansi-black-intense-bg { background-color: #282C36; }
+.ansi-red-fg { color: #E75C58; }
+.ansi-red-bg { background-color: #E75C58; }
+.ansi-red-intense-fg { color: #B22B31; }
+.ansi-red-intense-bg { background-color: #B22B31; }
+.ansi-green-fg { color: #00A250; }
+.ansi-green-bg { background-color: #00A250; }
+.ansi-green-intense-fg { color: #007427; }
+.ansi-green-intense-bg { background-color: #007427; }
+.ansi-yellow-fg { color: #DDB62B; }
+.ansi-yellow-bg { background-color: #DDB62B; }
+.ansi-yellow-intense-fg { color: #B27D12; }
+.ansi-yellow-intense-bg { background-color: #B27D12; }
+.ansi-blue-fg { color: #208FFB; }
+.ansi-blue-bg { background-color: #208FFB; }
+.ansi-blue-intense-fg { color: #0065CA; }
+.ansi-blue-intense-bg { background-color: #0065CA; }
+.ansi-magenta-fg { color: #D160C4; }
+.ansi-magenta-bg { background-color: #D160C4; }
+.ansi-magenta-intense-fg { color: #A03196; }
+.ansi-magenta-intense-bg { background-color: #A03196; }
+.ansi-cyan-fg { color: #60C6C8; }
+.ansi-cyan-bg { background-color: #60C6C8; }
+.ansi-cyan-intense-fg { color: #258F8F; }
+.ansi-cyan-intense-bg { background-color: #258F8F; }
+.ansi-white-fg { color: #C5C1B4; }
+.ansi-white-bg { background-color: #C5C1B4; }
+.ansi-white-intense-fg { color: #A1A6B2; }
+.ansi-white-intense-bg { background-color: #A1A6B2; }
+
+.ansi-default-inverse-fg { color: #FFFFFF; }
+.ansi-default-inverse-bg { background-color: #000000; }
+
+.ansi-bold { font-weight: bold; }
+.ansi-underline { text-decoration: underline; }
+
+
+div.nbinput.container div.input_area div[class*=highlight] > pre,
+div.nboutput.container div.output_area div[class*=highlight] > pre,
+div.nboutput.container div.output_area div[class*=highlight].math,
+div.nboutput.container div.output_area.rendered_html,
+div.nboutput.container div.output_area > div.output_javascript,
+div.nboutput.container div.output_area:not(.rendered_html) > img{
+ padding: 5px;
+ margin: 0;
+}
+
+/* fix copybtn overflow problem in chromium (needed for 'sphinx_copybutton') */
+div.nbinput.container div.input_area > div[class^='highlight'],
+div.nboutput.container div.output_area > div[class^='highlight']{
+ overflow-y: hidden;
+}
+
+/* hide copy button on prompts for 'sphinx_copybutton' extension ... */
+.prompt .copybtn,
+/* ... and 'sphinx_immaterial' theme */
+.prompt .md-clipboard.md-icon {
+ display: none;
+}
+
+/* Some additional styling taken form the Jupyter notebook CSS */
+.jp-RenderedHTMLCommon table,
+div.rendered_html table {
+ border: none;
+ border-collapse: collapse;
+ border-spacing: 0;
+ color: black;
+ font-size: 12px;
+ table-layout: fixed;
+}
+.jp-RenderedHTMLCommon thead,
+div.rendered_html thead {
+ border-bottom: 1px solid black;
+ vertical-align: bottom;
+}
+.jp-RenderedHTMLCommon tr,
+.jp-RenderedHTMLCommon th,
+.jp-RenderedHTMLCommon td,
+div.rendered_html tr,
+div.rendered_html th,
+div.rendered_html td {
+ text-align: right;
+ vertical-align: middle;
+ padding: 0.5em 0.5em;
+ line-height: normal;
+ white-space: normal;
+ max-width: none;
+ border: none;
+}
+.jp-RenderedHTMLCommon th,
+div.rendered_html th {
+ font-weight: bold;
+}
+.jp-RenderedHTMLCommon tbody tr:nth-child(odd),
+div.rendered_html tbody tr:nth-child(odd) {
+ background: #f5f5f5;
+}
+.jp-RenderedHTMLCommon tbody tr:hover,
+div.rendered_html tbody tr:hover {
+ background: rgba(66, 165, 245, 0.2);
+}
+
diff --git a/docs/serve/v2.1.24.0/_static/nbsphinx-gallery.css b/docs/serve/v2.1.24.0/_static/nbsphinx-gallery.css
new file mode 100644
index 0000000..365c27a
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/nbsphinx-gallery.css
@@ -0,0 +1,31 @@
+.nbsphinx-gallery {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
+ gap: 5px;
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+.nbsphinx-gallery > a {
+ padding: 5px;
+ border: 1px dotted currentColor;
+ border-radius: 2px;
+ text-align: center;
+}
+
+.nbsphinx-gallery > a:hover {
+ border-style: solid;
+}
+
+.nbsphinx-gallery img {
+ max-width: 100%;
+ max-height: 100%;
+}
+
+.nbsphinx-gallery > a > div:first-child {
+ display: flex;
+ align-items: start;
+ justify-content: center;
+ height: 120px;
+ margin-bottom: 5px;
+}
diff --git a/docs/serve/v2.1.24.0/_static/nbsphinx-no-thumbnail.svg b/docs/serve/v2.1.24.0/_static/nbsphinx-no-thumbnail.svg
new file mode 100644
index 0000000..9dca758
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/nbsphinx-no-thumbnail.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/docs/serve/v2.1.24.0/_static/plus.png b/docs/serve/v2.1.24.0/_static/plus.png
new file mode 100644
index 0000000..7107cec
Binary files /dev/null and b/docs/serve/v2.1.24.0/_static/plus.png differ
diff --git a/docs/serve/v2.1.24.0/_static/pygments.css b/docs/serve/v2.1.24.0/_static/pygments.css
new file mode 100644
index 0000000..84ab303
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/pygments.css
@@ -0,0 +1,75 @@
+pre { line-height: 125%; }
+td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
+span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
+td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
+span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
+.highlight .hll { background-color: #ffffcc }
+.highlight { background: #f8f8f8; }
+.highlight .c { color: #3D7B7B; font-style: italic } /* Comment */
+.highlight .err { border: 1px solid #FF0000 } /* Error */
+.highlight .k { color: #008000; font-weight: bold } /* Keyword */
+.highlight .o { color: #666666 } /* Operator */
+.highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
+.highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #9C6500 } /* Comment.Preproc */
+.highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
+.highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
+.highlight .gd { color: #A00000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
+.highlight .gr { color: #E40000 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #008400 } /* Generic.Inserted */
+.highlight .go { color: #717171 } /* Generic.Output */
+.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #0044DD } /* Generic.Traceback */
+.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #008000 } /* Keyword.Pseudo */
+.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #B00040 } /* Keyword.Type */
+.highlight .m { color: #666666 } /* Literal.Number */
+.highlight .s { color: #BA2121 } /* Literal.String */
+.highlight .na { color: #687822 } /* Name.Attribute */
+.highlight .nb { color: #008000 } /* Name.Builtin */
+.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.highlight .no { color: #880000 } /* Name.Constant */
+.highlight .nd { color: #AA22FF } /* Name.Decorator */
+.highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */
+.highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #0000FF } /* Name.Function */
+.highlight .nl { color: #767600 } /* Name.Label */
+.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #19177C } /* Name.Variable */
+.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mb { color: #666666 } /* Literal.Number.Bin */
+.highlight .mf { color: #666666 } /* Literal.Number.Float */
+.highlight .mh { color: #666666 } /* Literal.Number.Hex */
+.highlight .mi { color: #666666 } /* Literal.Number.Integer */
+.highlight .mo { color: #666666 } /* Literal.Number.Oct */
+.highlight .sa { color: #BA2121 } /* Literal.String.Affix */
+.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
+.highlight .sc { color: #BA2121 } /* Literal.String.Char */
+.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */
+.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
+.highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
+.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
+.highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
+.highlight .sx { color: #008000 } /* Literal.String.Other */
+.highlight .sr { color: #A45A77 } /* Literal.String.Regex */
+.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
+.highlight .ss { color: #19177C } /* Literal.String.Symbol */
+.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
+.highlight .fm { color: #0000FF } /* Name.Function.Magic */
+.highlight .vc { color: #19177C } /* Name.Variable.Class */
+.highlight .vg { color: #19177C } /* Name.Variable.Global */
+.highlight .vi { color: #19177C } /* Name.Variable.Instance */
+.highlight .vm { color: #19177C } /* Name.Variable.Magic */
+.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/_static/searchtools.js b/docs/serve/v2.1.24.0/_static/searchtools.js
new file mode 100644
index 0000000..7918c3f
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/searchtools.js
@@ -0,0 +1,574 @@
+/*
+ * searchtools.js
+ * ~~~~~~~~~~~~~~~~
+ *
+ * Sphinx JavaScript utilities for the full-text search.
+ *
+ * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+"use strict";
+
+/**
+ * Simple result scoring code.
+ */
+if (typeof Scorer === "undefined") {
+ var Scorer = {
+ // Implement the following function to further tweak the score for each result
+ // The function takes a result array [docname, title, anchor, descr, score, filename]
+ // and returns the new score.
+ /*
+ score: result => {
+ const [docname, title, anchor, descr, score, filename] = result
+ return score
+ },
+ */
+
+ // query matches the full name of an object
+ objNameMatch: 11,
+ // or matches in the last dotted part of the object name
+ objPartialMatch: 6,
+ // Additive scores depending on the priority of the object
+ objPrio: {
+ 0: 15, // used to be importantResults
+ 1: 5, // used to be objectResults
+ 2: -5, // used to be unimportantResults
+ },
+ // Used when the priority is not in the mapping.
+ objPrioDefault: 0,
+
+ // query found in title
+ title: 15,
+ partialTitle: 7,
+ // query found in terms
+ term: 5,
+ partialTerm: 2,
+ };
+}
+
+const _removeChildren = (element) => {
+ while (element && element.lastChild) element.removeChild(element.lastChild);
+};
+
+/**
+ * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
+ */
+const _escapeRegExp = (string) =>
+ string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
+
+const _displayItem = (item, searchTerms, highlightTerms) => {
+ const docBuilder = DOCUMENTATION_OPTIONS.BUILDER;
+ const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX;
+ const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX;
+ const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY;
+ const contentRoot = document.documentElement.dataset.content_root;
+
+ const [docName, title, anchor, descr, score, _filename] = item;
+
+ let listItem = document.createElement("li");
+ let requestUrl;
+ let linkUrl;
+ if (docBuilder === "dirhtml") {
+ // dirhtml builder
+ let dirname = docName + "/";
+ if (dirname.match(/\/index\/$/))
+ dirname = dirname.substring(0, dirname.length - 6);
+ else if (dirname === "index/") dirname = "";
+ requestUrl = contentRoot + dirname;
+ linkUrl = requestUrl;
+ } else {
+ // normal html builders
+ requestUrl = contentRoot + docName + docFileSuffix;
+ linkUrl = docName + docLinkSuffix;
+ }
+ let linkEl = listItem.appendChild(document.createElement("a"));
+ linkEl.href = linkUrl + anchor;
+ linkEl.dataset.score = score;
+ linkEl.innerHTML = title;
+ if (descr) {
+ listItem.appendChild(document.createElement("span")).innerHTML =
+ " (" + descr + ")";
+ // highlight search terms in the description
+ if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js
+ highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted"));
+ }
+ else if (showSearchSummary)
+ fetch(requestUrl)
+ .then((responseData) => responseData.text())
+ .then((data) => {
+ if (data)
+ listItem.appendChild(
+ Search.makeSearchSummary(data, searchTerms)
+ );
+ // highlight search terms in the summary
+ if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js
+ highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted"));
+ });
+ Search.output.appendChild(listItem);
+};
+const _finishSearch = (resultCount) => {
+ Search.stopPulse();
+ Search.title.innerText = _("Search Results");
+ if (!resultCount)
+ Search.status.innerText = Documentation.gettext(
+ "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories."
+ );
+ else
+ Search.status.innerText = _(
+ `Search finished, found ${resultCount} page(s) matching the search query.`
+ );
+};
+const _displayNextItem = (
+ results,
+ resultCount,
+ searchTerms,
+ highlightTerms,
+) => {
+ // results left, load the summary and display it
+ // this is intended to be dynamic (don't sub resultsCount)
+ if (results.length) {
+ _displayItem(results.pop(), searchTerms, highlightTerms);
+ setTimeout(
+ () => _displayNextItem(results, resultCount, searchTerms, highlightTerms),
+ 5
+ );
+ }
+ // search finished, update title and status message
+ else _finishSearch(resultCount);
+};
+
+/**
+ * Default splitQuery function. Can be overridden in ``sphinx.search`` with a
+ * custom function per language.
+ *
+ * The regular expression works by splitting the string on consecutive characters
+ * that are not Unicode letters, numbers, underscores, or emoji characters.
+ * This is the same as ``\W+`` in Python, preserving the surrogate pair area.
+ */
+if (typeof splitQuery === "undefined") {
+ var splitQuery = (query) => query
+ .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu)
+ .filter(term => term) // remove remaining empty strings
+}
+
+/**
+ * Search Module
+ */
+const Search = {
+ _index: null,
+ _queued_query: null,
+ _pulse_status: -1,
+
+ htmlToText: (htmlString) => {
+ const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html');
+ htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() });
+ const docContent = htmlElement.querySelector('[role="main"]');
+ if (docContent !== undefined) return docContent.textContent;
+ console.warn(
+ "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template."
+ );
+ return "";
+ },
+
+ init: () => {
+ const query = new URLSearchParams(window.location.search).get("q");
+ document
+ .querySelectorAll('input[name="q"]')
+ .forEach((el) => (el.value = query));
+ if (query) Search.performSearch(query);
+ },
+
+ loadIndex: (url) =>
+ (document.body.appendChild(document.createElement("script")).src = url),
+
+ setIndex: (index) => {
+ Search._index = index;
+ if (Search._queued_query !== null) {
+ const query = Search._queued_query;
+ Search._queued_query = null;
+ Search.query(query);
+ }
+ },
+
+ hasIndex: () => Search._index !== null,
+
+ deferQuery: (query) => (Search._queued_query = query),
+
+ stopPulse: () => (Search._pulse_status = -1),
+
+ startPulse: () => {
+ if (Search._pulse_status >= 0) return;
+
+ const pulse = () => {
+ Search._pulse_status = (Search._pulse_status + 1) % 4;
+ Search.dots.innerText = ".".repeat(Search._pulse_status);
+ if (Search._pulse_status >= 0) window.setTimeout(pulse, 500);
+ };
+ pulse();
+ },
+
+ /**
+ * perform a search for something (or wait until index is loaded)
+ */
+ performSearch: (query) => {
+ // create the required interface elements
+ const searchText = document.createElement("h2");
+ searchText.textContent = _("Searching");
+ const searchSummary = document.createElement("p");
+ searchSummary.classList.add("search-summary");
+ searchSummary.innerText = "";
+ const searchList = document.createElement("ul");
+ searchList.classList.add("search");
+
+ const out = document.getElementById("search-results");
+ Search.title = out.appendChild(searchText);
+ Search.dots = Search.title.appendChild(document.createElement("span"));
+ Search.status = out.appendChild(searchSummary);
+ Search.output = out.appendChild(searchList);
+
+ const searchProgress = document.getElementById("search-progress");
+ // Some themes don't use the search progress node
+ if (searchProgress) {
+ searchProgress.innerText = _("Preparing search...");
+ }
+ Search.startPulse();
+
+ // index already loaded, the browser was quick!
+ if (Search.hasIndex()) Search.query(query);
+ else Search.deferQuery(query);
+ },
+
+ /**
+ * execute search (requires search index to be loaded)
+ */
+ query: (query) => {
+ const filenames = Search._index.filenames;
+ const docNames = Search._index.docnames;
+ const titles = Search._index.titles;
+ const allTitles = Search._index.alltitles;
+ const indexEntries = Search._index.indexentries;
+
+ // stem the search terms and add them to the correct list
+ const stemmer = new Stemmer();
+ const searchTerms = new Set();
+ const excludedTerms = new Set();
+ const highlightTerms = new Set();
+ const objectTerms = new Set(splitQuery(query.toLowerCase().trim()));
+ splitQuery(query.trim()).forEach((queryTerm) => {
+ const queryTermLower = queryTerm.toLowerCase();
+
+ // maybe skip this "word"
+ // stopwords array is from language_data.js
+ if (
+ stopwords.indexOf(queryTermLower) !== -1 ||
+ queryTerm.match(/^\d+$/)
+ )
+ return;
+
+ // stem the word
+ let word = stemmer.stemWord(queryTermLower);
+ // select the correct list
+ if (word[0] === "-") excludedTerms.add(word.substr(1));
+ else {
+ searchTerms.add(word);
+ highlightTerms.add(queryTermLower);
+ }
+ });
+
+ if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js
+ localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" "))
+ }
+
+ // console.debug("SEARCH: searching for:");
+ // console.info("required: ", [...searchTerms]);
+ // console.info("excluded: ", [...excludedTerms]);
+
+ // array of [docname, title, anchor, descr, score, filename]
+ let results = [];
+ _removeChildren(document.getElementById("search-progress"));
+
+ const queryLower = query.toLowerCase();
+ for (const [title, foundTitles] of Object.entries(allTitles)) {
+ if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) {
+ for (const [file, id] of foundTitles) {
+ let score = Math.round(100 * queryLower.length / title.length)
+ results.push([
+ docNames[file],
+ titles[file] !== title ? `${titles[file]} > ${title}` : title,
+ id !== null ? "#" + id : "",
+ null,
+ score,
+ filenames[file],
+ ]);
+ }
+ }
+ }
+
+ // search for explicit entries in index directives
+ for (const [entry, foundEntries] of Object.entries(indexEntries)) {
+ if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) {
+ for (const [file, id] of foundEntries) {
+ let score = Math.round(100 * queryLower.length / entry.length)
+ results.push([
+ docNames[file],
+ titles[file],
+ id ? "#" + id : "",
+ null,
+ score,
+ filenames[file],
+ ]);
+ }
+ }
+ }
+
+ // lookup as object
+ objectTerms.forEach((term) =>
+ results.push(...Search.performObjectSearch(term, objectTerms))
+ );
+
+ // lookup as search terms in fulltext
+ results.push(...Search.performTermsSearch(searchTerms, excludedTerms));
+
+ // let the scorer override scores with a custom scoring function
+ if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item)));
+
+ // now sort the results by score (in opposite order of appearance, since the
+ // display function below uses pop() to retrieve items) and then
+ // alphabetically
+ results.sort((a, b) => {
+ const leftScore = a[4];
+ const rightScore = b[4];
+ if (leftScore === rightScore) {
+ // same score: sort alphabetically
+ const leftTitle = a[1].toLowerCase();
+ const rightTitle = b[1].toLowerCase();
+ if (leftTitle === rightTitle) return 0;
+ return leftTitle > rightTitle ? -1 : 1; // inverted is intentional
+ }
+ return leftScore > rightScore ? 1 : -1;
+ });
+
+ // remove duplicate search results
+ // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept
+ let seen = new Set();
+ results = results.reverse().reduce((acc, result) => {
+ let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(',');
+ if (!seen.has(resultStr)) {
+ acc.push(result);
+ seen.add(resultStr);
+ }
+ return acc;
+ }, []);
+
+ results = results.reverse();
+
+ // for debugging
+ //Search.lastresults = results.slice(); // a copy
+ // console.info("search results:", Search.lastresults);
+
+ // print the results
+ _displayNextItem(results, results.length, searchTerms, highlightTerms);
+ },
+
+ /**
+ * search for object names
+ */
+ performObjectSearch: (object, objectTerms) => {
+ const filenames = Search._index.filenames;
+ const docNames = Search._index.docnames;
+ const objects = Search._index.objects;
+ const objNames = Search._index.objnames;
+ const titles = Search._index.titles;
+
+ const results = [];
+
+ const objectSearchCallback = (prefix, match) => {
+ const name = match[4]
+ const fullname = (prefix ? prefix + "." : "") + name;
+ const fullnameLower = fullname.toLowerCase();
+ if (fullnameLower.indexOf(object) < 0) return;
+
+ let score = 0;
+ const parts = fullnameLower.split(".");
+
+ // check for different match types: exact matches of full name or
+ // "last name" (i.e. last dotted part)
+ if (fullnameLower === object || parts.slice(-1)[0] === object)
+ score += Scorer.objNameMatch;
+ else if (parts.slice(-1)[0].indexOf(object) > -1)
+ score += Scorer.objPartialMatch; // matches in last name
+
+ const objName = objNames[match[1]][2];
+ const title = titles[match[0]];
+
+ // If more than one term searched for, we require other words to be
+ // found in the name/title/description
+ const otherTerms = new Set(objectTerms);
+ otherTerms.delete(object);
+ if (otherTerms.size > 0) {
+ const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase();
+ if (
+ [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0)
+ )
+ return;
+ }
+
+ let anchor = match[3];
+ if (anchor === "") anchor = fullname;
+ else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname;
+
+ const descr = objName + _(", in ") + title;
+
+ // add custom score for some objects according to scorer
+ if (Scorer.objPrio.hasOwnProperty(match[2]))
+ score += Scorer.objPrio[match[2]];
+ else score += Scorer.objPrioDefault;
+
+ results.push([
+ docNames[match[0]],
+ fullname,
+ "#" + anchor,
+ descr,
+ score,
+ filenames[match[0]],
+ ]);
+ };
+ Object.keys(objects).forEach((prefix) =>
+ objects[prefix].forEach((array) =>
+ objectSearchCallback(prefix, array)
+ )
+ );
+ return results;
+ },
+
+ /**
+ * search for full-text terms in the index
+ */
+ performTermsSearch: (searchTerms, excludedTerms) => {
+ // prepare search
+ const terms = Search._index.terms;
+ const titleTerms = Search._index.titleterms;
+ const filenames = Search._index.filenames;
+ const docNames = Search._index.docnames;
+ const titles = Search._index.titles;
+
+ const scoreMap = new Map();
+ const fileMap = new Map();
+
+ // perform the search on the required terms
+ searchTerms.forEach((word) => {
+ const files = [];
+ const arr = [
+ { files: terms[word], score: Scorer.term },
+ { files: titleTerms[word], score: Scorer.title },
+ ];
+ // add support for partial matches
+ if (word.length > 2) {
+ const escapedWord = _escapeRegExp(word);
+ Object.keys(terms).forEach((term) => {
+ if (term.match(escapedWord) && !terms[word])
+ arr.push({ files: terms[term], score: Scorer.partialTerm });
+ });
+ Object.keys(titleTerms).forEach((term) => {
+ if (term.match(escapedWord) && !titleTerms[word])
+ arr.push({ files: titleTerms[word], score: Scorer.partialTitle });
+ });
+ }
+
+ // no match but word was a required one
+ if (arr.every((record) => record.files === undefined)) return;
+
+ // found search word in contents
+ arr.forEach((record) => {
+ if (record.files === undefined) return;
+
+ let recordFiles = record.files;
+ if (recordFiles.length === undefined) recordFiles = [recordFiles];
+ files.push(...recordFiles);
+
+ // set score for the word in each file
+ recordFiles.forEach((file) => {
+ if (!scoreMap.has(file)) scoreMap.set(file, {});
+ scoreMap.get(file)[word] = record.score;
+ });
+ });
+
+ // create the mapping
+ files.forEach((file) => {
+ if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1)
+ fileMap.get(file).push(word);
+ else fileMap.set(file, [word]);
+ });
+ });
+
+ // now check if the files don't contain excluded terms
+ const results = [];
+ for (const [file, wordList] of fileMap) {
+ // check if all requirements are matched
+
+ // as search terms with length < 3 are discarded
+ const filteredTermCount = [...searchTerms].filter(
+ (term) => term.length > 2
+ ).length;
+ if (
+ wordList.length !== searchTerms.size &&
+ wordList.length !== filteredTermCount
+ )
+ continue;
+
+ // ensure that none of the excluded terms is in the search result
+ if (
+ [...excludedTerms].some(
+ (term) =>
+ terms[term] === file ||
+ titleTerms[term] === file ||
+ (terms[term] || []).includes(file) ||
+ (titleTerms[term] || []).includes(file)
+ )
+ )
+ break;
+
+ // select one (max) score for the file.
+ const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w]));
+ // add result to the result list
+ results.push([
+ docNames[file],
+ titles[file],
+ "",
+ null,
+ score,
+ filenames[file],
+ ]);
+ }
+ return results;
+ },
+
+ /**
+ * helper function to return a node containing the
+ * search summary for a given text. keywords is a list
+ * of stemmed words.
+ */
+ makeSearchSummary: (htmlText, keywords) => {
+ const text = Search.htmlToText(htmlText);
+ if (text === "") return null;
+
+ const textLower = text.toLowerCase();
+ const actualStartPosition = [...keywords]
+ .map((k) => textLower.indexOf(k.toLowerCase()))
+ .filter((i) => i > -1)
+ .slice(-1)[0];
+ const startWithContext = Math.max(actualStartPosition - 120, 0);
+
+ const top = startWithContext === 0 ? "" : "...";
+ const tail = startWithContext + 240 < text.length ? "..." : "";
+
+ let summary = document.createElement("p");
+ summary.classList.add("context");
+ summary.textContent = top + text.substr(startWithContext, 240).trim() + tail;
+
+ return summary;
+ },
+};
+
+_ready(Search.init);
diff --git a/docs/serve/v2.1.24.0/_static/sphinx_highlight.js b/docs/serve/v2.1.24.0/_static/sphinx_highlight.js
new file mode 100644
index 0000000..8a96c69
--- /dev/null
+++ b/docs/serve/v2.1.24.0/_static/sphinx_highlight.js
@@ -0,0 +1,154 @@
+/* Highlighting utilities for Sphinx HTML documentation. */
+"use strict";
+
+const SPHINX_HIGHLIGHT_ENABLED = true
+
+/**
+ * highlight a given string on a node by wrapping it in
+ * span elements with the given class name.
+ */
+const _highlight = (node, addItems, text, className) => {
+ if (node.nodeType === Node.TEXT_NODE) {
+ const val = node.nodeValue;
+ const parent = node.parentNode;
+ const pos = val.toLowerCase().indexOf(text);
+ if (
+ pos >= 0 &&
+ !parent.classList.contains(className) &&
+ !parent.classList.contains("nohighlight")
+ ) {
+ let span;
+
+ const closestNode = parent.closest("body, svg, foreignObject");
+ const isInSVG = closestNode && closestNode.matches("svg");
+ if (isInSVG) {
+ span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
+ } else {
+ span = document.createElement("span");
+ span.classList.add(className);
+ }
+
+ span.appendChild(document.createTextNode(val.substr(pos, text.length)));
+ const rest = document.createTextNode(val.substr(pos + text.length));
+ parent.insertBefore(
+ span,
+ parent.insertBefore(
+ rest,
+ node.nextSibling
+ )
+ );
+ node.nodeValue = val.substr(0, pos);
+ /* There may be more occurrences of search term in this node. So call this
+ * function recursively on the remaining fragment.
+ */
+ _highlight(rest, addItems, text, className);
+
+ if (isInSVG) {
+ const rect = document.createElementNS(
+ "http://www.w3.org/2000/svg",
+ "rect"
+ );
+ const bbox = parent.getBBox();
+ rect.x.baseVal.value = bbox.x;
+ rect.y.baseVal.value = bbox.y;
+ rect.width.baseVal.value = bbox.width;
+ rect.height.baseVal.value = bbox.height;
+ rect.setAttribute("class", className);
+ addItems.push({ parent: parent, target: rect });
+ }
+ }
+ } else if (node.matches && !node.matches("button, select, textarea")) {
+ node.childNodes.forEach((el) => _highlight(el, addItems, text, className));
+ }
+};
+const _highlightText = (thisNode, text, className) => {
+ let addItems = [];
+ _highlight(thisNode, addItems, text, className);
+ addItems.forEach((obj) =>
+ obj.parent.insertAdjacentElement("beforebegin", obj.target)
+ );
+};
+
+/**
+ * Small JavaScript module for the documentation.
+ */
+const SphinxHighlight = {
+
+ /**
+ * highlight the search words provided in localstorage in the text
+ */
+ highlightSearchWords: () => {
+ if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight
+
+ // get and clear terms from localstorage
+ const url = new URL(window.location);
+ const highlight =
+ localStorage.getItem("sphinx_highlight_terms")
+ || url.searchParams.get("highlight")
+ || "";
+ localStorage.removeItem("sphinx_highlight_terms")
+ url.searchParams.delete("highlight");
+ window.history.replaceState({}, "", url);
+
+ // get individual terms from highlight string
+ const terms = highlight.toLowerCase().split(/\s+/).filter(x => x);
+ if (terms.length === 0) return; // nothing to do
+
+ // There should never be more than one element matching "div.body"
+ const divBody = document.querySelectorAll("div.body");
+ const body = divBody.length ? divBody[0] : document.querySelector("body");
+ window.setTimeout(() => {
+ terms.forEach((term) => _highlightText(body, term, "highlighted"));
+ }, 10);
+
+ const searchBox = document.getElementById("searchbox");
+ if (searchBox === null) return;
+ searchBox.appendChild(
+ document
+ .createRange()
+ .createContextualFragment(
+ '' +
+ '' +
+ _("Hide Search Matches") +
+ "
"
+ )
+ );
+ },
+
+ /**
+ * helper function to hide the search marks again
+ */
+ hideSearchWords: () => {
+ document
+ .querySelectorAll("#searchbox .highlight-link")
+ .forEach((el) => el.remove());
+ document
+ .querySelectorAll("span.highlighted")
+ .forEach((el) => el.classList.remove("highlighted"));
+ localStorage.removeItem("sphinx_highlight_terms")
+ },
+
+ initEscapeListener: () => {
+ // only install a listener if it is really needed
+ if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return;
+
+ document.addEventListener("keydown", (event) => {
+ // bail for input elements
+ if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return;
+ // bail with special keys
+ if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return;
+ if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) {
+ SphinxHighlight.hideSearchWords();
+ event.preventDefault();
+ }
+ });
+ },
+};
+
+_ready(() => {
+ /* Do not call highlightSearchWords() when we are on the search page.
+ * It will highlight words from the *previous* search query.
+ */
+ if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords();
+ SphinxHighlight.initEscapeListener();
+});
diff --git a/docs/serve/v2.1.24.0/genindex.html b/docs/serve/v2.1.24.0/genindex.html
new file mode 100644
index 0000000..b923c12
--- /dev/null
+++ b/docs/serve/v2.1.24.0/genindex.html
@@ -0,0 +1,669 @@
+
+
+
+
+
+ Index — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rulekit v2.1.24.0
+
+
+
+
+
+
+
+
+
+
Index
+
+
+
A
+ |
B
+ |
C
+ |
D
+ |
E
+ |
F
+ |
G
+ |
I
+ |
J
+ |
K
+ |
L
+ |
M
+ |
N
+ |
O
+ |
P
+ |
Q
+ |
R
+ |
S
+ |
T
+ |
V
+ |
W
+ |
Y
+
+
+
A
+
+
+
B
+
+
+
C
+
+
+
D
+
+
+
E
+
+
+
F
+
+
+
G
+
+
+
I
+
+
+
J
+
+
+
K
+
+
+
L
+
+
+
M
+
+
+
N
+
+
+
O
+
+
+
P
+
+
+
Q
+
+
+
R
+
+
+
S
+
+
+
T
+
+
+
V
+
+
+
W
+
+
+
Y
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/index.html b/docs/serve/v2.1.24.0/index.html
new file mode 100644
index 0000000..86f8318
--- /dev/null
+++ b/docs/serve/v2.1.24.0/index.html
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+ RuleKit — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rulekit v2.1.24.0
+
+
+
+
+
+
+
+
+
+RuleKit
+This package is python wrapper for RuleKit library (a versatile tool for rule learning).
+Based on a sequential covering induction algorithm, it is suitable for:
+
+classification,
+regression,
+survival problems.
+
+This wrapper aims to give an easy way to integrate RuleKit functionality into python projects and notebooks.
+All package models are writen to be compatible with scikit learn library.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/objects.inv b/docs/serve/v2.1.24.0/objects.inv
new file mode 100644
index 0000000..7e35513
Binary files /dev/null and b/docs/serve/v2.1.24.0/objects.inv differ
diff --git a/docs/serve/v2.1.24.0/py-modindex.html b/docs/serve/v2.1.24.0/py-modindex.html
new file mode 100644
index 0000000..84b7bc3
--- /dev/null
+++ b/docs/serve/v2.1.24.0/py-modindex.html
@@ -0,0 +1,149 @@
+
+
+
+
+
+ Python Module Index — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rulekit v2.1.24.0
+
+
+
+
+
+
+
+ Python Module Index
+
+
+
+
+
+
+
+
+
+
Python Module Index
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/rst/autodoc.html b/docs/serve/v2.1.24.0/rst/autodoc.html
new file mode 100644
index 0000000..ae8570e
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/autodoc.html
@@ -0,0 +1,236 @@
+
+
+
+
+
+
+ Code documentation — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rulekit v2.1.24.0
+
+
+
+
+
+
+
+
+
+Code documentation
+Contains classes for initializing RuleKit Java backend
+
+
+class rulekit.main. RuleKit
+Class used for initializing RuleKit. It starts JVM underhood and setups it
+with jars.
+
+
Note
+
Since version 1.7.0 there is no need to manually initialize RuleKit.
+
+You may just skip the RuleKit.init() line. However in certain scenarios when
+you want use a custom RuleKit jar file or modify Java VM parameters, this class
+can be used.
+
+
+version
+version of RuleKit jar used by wrapper (not equal to python package version).
+
+Type:
+str
+
+
+
+
+
+
+static configure_java_logger ( log_file_path : str , verbosity_level : int = 1 )
+Enable Java debug logging. You probably don’t need to use this
+method unless you want too deep dive into the process of rules inductions
+
+or your’re debugging some issues.
+
+
+Parameters:
+
+log_file_path (str ) – Path to the file where logs will be stored
+verbosity_level (int , optional ) – Verbosity level.
+Minimum value is 1, maximum value is 2, default value is 1.
+
+
+
+
+
+
+
+static get_java_logger_config ( ) → _RuleKitJavaLoggerConfig | None
+Returns the Java logger configuration configured using
+configure_java_logger method
+
+Returns:
+Java logger configuration
+
+Return type:
+Optional[_RuleKitJavaLoggerConfig]
+
+
+
+
+
+
+static init ( initial_heap_size : int | None = None , max_heap_size : int | None = None , rulekit_jar_file_path : str | None = None )
+Initialize package.
+This method configure and starts JVM and load RuleKit jar file.
+
+
Note
+
Since version 1.7.0 it don’t have to be called before using any
+
+operator class. However in certain scenarios when you want use a custom RuleKit
+jar file or modify Java VM parameters, this method can be used.
+
+Parameters:
+
+initial_heap_size (int ) – JVM initial heap size in mb
+max_heap_size (int ) – JVM max heap size in mb
+rulekit_jar_file_path (str ) –
Path to the RuleKit jar file. This parameters.
+.. note:
+You probably don 't need to use this parameter unless you want to use
+your own custom version of RuleKit jar file . Otherwise leave it as it
+is and the package will use the official RuleKit release jar file .
+
+
+
+
+
+Raises:
+Exception – If failed to load RuleKit jar file.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/rst/autodoc/classification.html b/docs/serve/v2.1.24.0/rst/autodoc/classification.html
new file mode 100644
index 0000000..92a3c24
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/autodoc/classification.html
@@ -0,0 +1,603 @@
+
+
+
+
+
+
+ Classification — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rulekit v2.1.24.0
+
+
+
+
+
+
+
+
+
+Classification
+
+
+class rulekit.classification. RuleClassifier ( minsupp_new : float = 0.05 , induction_measure : Measures = Measures.Correlation , pruning_measure : Measures | str = Measures.Correlation , voting_measure : Measures = Measures.Correlation , max_growing : float = 0.0 , enable_pruning : bool = True , ignore_missing : bool = False , max_uncovered_fraction : float = 0.0 , select_best_candidate : bool = False , complementary_conditions : bool = False , control_apriori_precision : bool = True , max_rule_count : int = 0 , approximate_induction : bool = False , approximate_bins_count : int = 100 )
+Classification model.
+
+Parameters:
+
+minsupp_new (float = 5.0 ) – a minimum number (or fraction, if value < 1.0) of previously uncovered
+examples to be covered by a new rule (positive examples for classification
+problems); default: 5,
+induction_measure (rulekit.params.Measures
= rulekit.params. Measures.Correlation
) – measure used during induction; default measure is correlation
+pruning_measure (Union[rulekit.params.Measures
, str] = rulekit.params.Measures.Correlation
) –
+measure used during pruning. Could be user defined (string), for example 2 * p / n
; default measure is correlation
+
+
+
+voting_measure (rulekit.params.Measures
= rulekit.params.Measures.Correlation
) – measure used during voting; default measure is correlation
+max_growing (int = 0.0 ) – non-negative integer representing maximum number of conditions which can be
+added to the rule in the growing phase (use this parameter for large
+datasets if execution time is prohibitive); 0 indicates no limit; default: 0
+enable_pruning (bool = True ) – enable or disable pruning, default is True.
+ignore_missing (bool = False ) – boolean telling whether missing values should be ignored (by default, a
+missing valueof given attribute is always cconsidered as not fulfilling the
+condition build upon that attribute); default: False.
+max_uncovered_fraction (float = 0.0 ) – Floating-point number from [0,1] interval representing maximum fraction of
+examples that may remain uncovered by the rule set, default: 0.0.
+select_best_candidate (bool = False ) – Flag determining if best candidate should be selected from growing phase;
+default: False.
+complementary_conditions (bool = False ) – If enabled, complementary conditions in the form a = !{value} for nominal
+attributes are supported.
+control_apriori_precision (bool = True ) – When inducing classification rules, verify if candidate precision is higher
+than apriori precision of the investigated class.
+max_rule_count (int = 0 ) – Maximum number of rules to be generated (for classification data sets it
+applies to a single class); 0 indicates no limit.
+approximate_induction (bool = False ) – Use an approximate induction heuristic which does not check all possible
+splits; note: this is an experimental feature and currently works only for
+classification data sets, results may change in future;
+approximate_bins_count (int = 100 ) – maximum number of bins for an attribute evaluated in the approximate
+induction.
+
+
+
+
+
+add_event_listener ( listener : RuleInductionProgressListener )
+
+Add event listener object to the operator which allows to monitor rule induction progress.
+
+
+Example
+>>> from rulekit.events import RuleInductionProgressListener
+>>> from rulekit.classification import RuleClassifier
+>>>
+>>> class MyEventListener ( RuleInductionProgressListener ):
+>>> def on_new_rule ( self , rule ):
+>>> print ( 'Do something with new rule' , rule )
+>>>
+>>> operator = RuleClassifier ()
+>>> operator . add_event_listener ( MyEventListener ())
+
+
+
+Parameters:
+listener (RuleInductionProgressListener ) – listener object
+
+
+
+
+
+
+fit ( values : ndarray | DataFrame | list , labels : ndarray | DataFrame | list ) → RuleClassifier
+Train model on given dataset.
+
+Parameters:
+
+
+Returns:
+self
+
+Return type:
+RuleClassifier
+
+
+
+
+
+
+get_coverage_matrix ( values : ndarray | DataFrame | list ) → ndarray
+Calculates coverage matrix for ruleset.
+
+Parameters:
+values (rulekit.operator.Data
) – dataset
+
+Returns:
+coverage_matrix – Each row of the matrix represent single example from dataset and every
+column represent on rule from rule set. Value 1 in the matrix cell means
+that rule covered certain example, value 0 means that it doesn’t.
+
+Return type:
+np.ndarray
+
+
+
+
+
+
+get_metadata_routing ( ) → None
+
+
Warning
+
Scikit-learn metadata routing is not supported yet.
+
+
+Raises:
+NotImplementedError – _description_
+
+
+
+
+
+
+get_params ( deep : bool = True ) → dict [ str , Any ]
+
+Parameters:
+deep (rulekit.operator.Data
) – Parameter for scikit-learn compatibility. Not used.
+
+Returns:
+hyperparameters – Dictionary containing model hyperparameters.
+
+Return type:
+np.ndarray
+
+
+
+
+
+
+predict ( values : ndarray | DataFrame | list , return_metrics : bool = False ) → ndarray | tuple [ ndarray , ClassificationPredictionMetrics ]
+Perform prediction and returns predicted labels.
+
+Parameters:
+
+values (rulekit.operator.Data
) – attributes
+return_metrics (bool = False ) – Optional flag. If set to True method will calculate some additional model
+metrics. Method will then return tuple instead of just predicted labels.
+
+
+Returns:
+result – If return_metrics flag wasn’t set it will return just prediction,
+otherwise a tuple will be returned with first element being prediction and
+second one being metrics.
+
+Return type:
+Union[np.ndarray, tuple[np.ndarray, rulekit.classification. ClassificationPredictionMetrics
]]
+
+
+
+
+
+
+predict_proba ( values : ndarray | DataFrame | list , return_metrics : bool = False ) → ndarray | tuple [ ndarray , ClassificationPredictionMetrics ]
+Perform prediction and returns class probabilities for each example.
+
+Parameters:
+
+values (rulekit.operator.Data
) – attributes
+return_metrics (bool = False ) – Optional flag. If set to True method will calculate some additional model
+metrics. Method will then return tuple instead of just probabilities.
+
+
+Returns:
+result – If return_metrics flag wasn’t set it will return just probabilities
+matrix, otherwise a tuple will be returned with first element being
+prediction and second one being metrics.
+
+Return type:
+Union[np.ndarray, tuple[np.ndarray, rulekit.classification. ClassificationPredictionMetrics
]]
+
+
+
+
+
+
+score ( values : ndarray | DataFrame | list , labels : ndarray | DataFrame | list ) → float
+Return the accuracy on the given test data and labels.
+
+Parameters:
+
+
+Returns:
+score – Accuracy of self.predict(values) wrt. labels.
+
+Return type:
+float
+
+
+
+
+
+
+set_params ( ** kwargs ) → object
+Set models hyperparameters. Parameters are the same as in constructor.
+
+
+
+
+
+
+class rulekit.classification. ExpertRuleClassifier ( minsupp_new : float = 0.05 , induction_measure : Measures = Measures.Correlation , pruning_measure : Measures | str = Measures.Correlation , voting_measure : Measures = Measures.Correlation , max_growing : float = 0.0 , enable_pruning : bool = True , ignore_missing : bool = False , max_uncovered_fraction : float = 0.0 , select_best_candidate : bool = False , complementary_conditions : bool = False , control_apriori_precision : bool = True , max_rule_count : int = 0 , approximate_induction : bool = False , approximate_bins_count : int = 100 , extend_using_preferred : bool = False , extend_using_automatic : bool = False , induce_using_preferred : bool = False , induce_using_automatic : bool = False , consider_other_classes : bool = False , preferred_conditions_per_rule : int = 2147483647 , preferred_attributes_per_rule : int = 2147483647 )
+Classification model using expert knowledge.
+
+Parameters:
+
+minsupp_new (float = 5.0 ) –
+fraction (a minimum number ( or ) –
+examples (if value < 1.0 ) of previously uncovered ) –
+problems ) ; (to be covered by a new rule ( positive examples for classification ) –
+default (5 , ) –
+induction_measure (rulekit.params.Measures
= rulekit.params.Measures.Correlation
) – measure used during induction; default measure is correlation
+pruning_measure (Union[rulekit.params.Measures
, str] = rulekit.params.Measures.Correlation
) –
+measure used during pruning. Could be user defined (string), for example 2 * p / n
; default measure is correlation
+
+
+
+voting_measure (rulekit.params.Measures
= rulekit.params.Measures.Correlation
) – measure used during voting; default measure is correlation
+max_growing (int = 0.0 ) – non-negative integer representing maximum number of conditions which can be
+added to the rule in the growing phase (use this parameter for large
+datasets if execution time is prohibitive); 0 indicates no limit; default: 0
+enable_pruning (bool = True ) – enable or disable pruning, default is True.
+ignore_missing (bool = False ) – boolean telling whether missing values should be ignored (by default, a
+missing value of given attribute is always considered as not fulfilling the
+condition build upon that attribute); default: False.
+max_uncovered_fraction (float = 0.0 ) – Floating-point number from [0,1] interval representing maximum fraction of
+examples that may remain uncovered by the rule set, default: 0.0.
+select_best_candidate (bool = False ) – Flag determining if best candidate should be selected from growing phase;
+default: False.
+complementary_conditions (bool = False ) – If enabled, complementary conditions in the form a = !{value} for nominal
+attributes
+are supported.
+control_apriori_precision (bool = True ) – When inducing classification rules, verify if candidate precision is higher
+than apriori precision of the investigated class.
+max_rule_count (int = 0 ) – Maximum number of rules to be generated (for classification data sets it
+applies to a single class); 0 indicates no limit.
+approximate_induction (bool = False ) – Use an approximate induction heuristic which does not check all possible
+splits; note: this is an experimental feature and currently works only for
+classification data sets, results may change in future;
+approximate_bins_count (int = 100 ) – maximum number of bins for an attribute evaluated in the approximate
+induction.
+extend_using_preferred (bool = False ) – boolean indicating whether initial rules should be extended with a use of
+preferred conditions and attributes; default is False
+extend_using_automatic (bool = False ) – boolean indicating whether initial rules should be extended with a use of
+automatic conditions and attributes; default is False
+induce_using_preferred (bool = False ) – boolean indicating whether new rules should be induced with a use of
+preferred conditions and attributes; default is False
+induce_using_automatic (bool = False ) – boolean indicating whether new rules should be induced with a use of
+automatic conditions and attributes; default is False
+consider_other_classes (bool = False ) – boolean indicating whether automatic induction should be performed for
+classes for which no user’s knowledge has been defined
+(classification only); default is False.
+preferred_conditions_per_rule (int = None ) – maximum number of preferred conditions per rule; default: unlimited,
+preferred_attributes_per_rule (int = None ) – maximum number of preferred attributes per rule; default: unlimited.
+
+
+
+
+
+add_event_listener ( listener : RuleInductionProgressListener )
+
+Add event listener object to the operator which allows to monitor rule induction progress.
+
+
+Example
+>>> from rulekit.events import RuleInductionProgressListener
+>>> from rulekit.classification import RuleClassifier
+>>>
+>>> class MyEventListener ( RuleInductionProgressListener ):
+>>> def on_new_rule ( self , rule ):
+>>> print ( 'Do something with new rule' , rule )
+>>>
+>>> operator = RuleClassifier ()
+>>> operator . add_event_listener ( MyEventListener ())
+
+
+
+Parameters:
+listener (RuleInductionProgressListener ) – listener object
+
+
+
+
+
+
+fit ( values : ndarray | DataFrame | list , labels : ndarray | DataFrame | list , expert_rules : list [ str | tuple [ str , str ] ] | None = None , expert_preferred_conditions : list [ str | tuple [ str , str ] ] | None = None , expert_forbidden_conditions : list [ str | tuple [ str , str ] ] | None = None ) → ExpertRuleClassifier
+Train model on given dataset.
+
+Parameters:
+
+values (rulekit.operator.Data
) – attributes
+labels (rulekit.operator.Data
) – labels
+expert_rules (List [ Union [ str , Tuple [ str , str ] ] ] ) – set of initial rules, either passed as a list of strings representing rules
+or as list of tuples where first element is name of the rule and second one
+is rule string.
+expert_preferred_conditions (List [ Union [ str , Tuple [ str , str ] ] ] ) – multiset of preferred conditions (used also for specifying preferred
+attributes by using special value Any). Either passed as a list of strings
+representing rules or as list of tuples where first element is name of the
+rule and second one is rule string.
+expert_forbidden_conditions (List [ Union [ str , Tuple [ str , str ] ] ] ) – set of forbidden conditions (used also for specifying forbidden attributes
+by using special value Any). Either passed as a list of strings representing
+rules or as list of tuples where first element is name of the rule and
+second one is rule string.
+
+
+Returns:
+self
+
+Return type:
+ExpertRuleClassifier
+
+
+
+
+
+
+get_coverage_matrix ( values : ndarray | DataFrame | list ) → ndarray
+Calculates coverage matrix for ruleset.
+
+Parameters:
+values (rulekit.operator.Data
) – dataset
+
+Returns:
+coverage_matrix – Each row of the matrix represent single example from dataset and every
+column represent on rule from rule set. Value 1 in the matrix cell means
+that rule covered certain example, value 0 means that it doesn’t.
+
+Return type:
+np.ndarray
+
+
+
+
+
+
+get_metadata_routing ( ) → None
+
+
Warning
+
Scikit-learn metadata routing is not supported yet.
+
+
+Raises:
+NotImplementedError – _description_
+
+
+
+
+
+
+get_params ( deep : bool = True ) → dict [ str , Any ]
+
+Parameters:
+deep (rulekit.operator.Data
) – Parameter for scikit-learn compatibility. Not used.
+
+Returns:
+hyperparameters – Dictionary containing model hyperparameters.
+
+Return type:
+np.ndarray
+
+
+
+
+
+
+predict ( values : ndarray | DataFrame | list , return_metrics : bool = False ) → ndarray | tuple [ ndarray , ClassificationPredictionMetrics ]
+Perform prediction and returns predicted labels.
+
+Parameters:
+
+values (rulekit.operator.Data
) – attributes
+return_metrics (bool = False ) – Optional flag. If set to True method will calculate some additional model
+metrics. Method will then return tuple instead of just predicted labels.
+
+
+Returns:
+result – If return_metrics flag wasn’t set it will return just prediction,
+otherwise a tuple will be returned with first element being prediction and
+second one being metrics.
+
+Return type:
+Union[np.ndarray, tuple[np.ndarray, rulekit.classification. ClassificationPredictionMetrics
]]
+
+
+
+
+
+
+predict_proba ( values : ndarray | DataFrame | list , return_metrics : bool = False ) → ndarray | tuple [ ndarray , ClassificationPredictionMetrics ]
+Perform prediction and returns class probabilities for each example.
+
+Parameters:
+
+values (rulekit.operator.Data
) – attributes
+return_metrics (bool = False ) – Optional flag. If set to True method will calculate some additional model
+metrics. Method will then return tuple instead of just probabilities.
+
+
+Returns:
+result – If return_metrics flag wasn’t set it will return just probabilities
+matrix, otherwise a tuple will be returned with first element being
+prediction and second one being metrics.
+
+Return type:
+Union[np.ndarray, tuple[np.ndarray, rulekit.classification. ClassificationPredictionMetrics
]]
+
+
+
+
+
+
+score ( values : ndarray | DataFrame | list , labels : ndarray | DataFrame | list ) → float
+Return the accuracy on the given test data and labels.
+
+Parameters:
+
+
+Returns:
+score – Accuracy of self.predict(values) wrt. labels.
+
+Return type:
+float
+
+
+
+
+
+
+set_params ( ** kwargs ) → object
+Set models hyperparameters. Parameters are the same as in constructor.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/rst/autodoc/params.html b/docs/serve/v2.1.24.0/rst/autodoc/params.html
new file mode 100644
index 0000000..d294eb6
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/autodoc/params.html
@@ -0,0 +1,391 @@
+
+
+
+
+
+
+ Parameters — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rulekit v2.1.24.0
+
+
+
+
+
+
+
+
+
+Parameters
+
+
+rulekit.operator. Data
+alias of type Union[numpy.ndarray, pandas.core.frame.DataFrame, List]
+
+
+Contains constants and classes for specyfing models parameters
+
+
+class rulekit.params. Measures ( value )
+Bases: Enum
+Enum for different measures used during induction, pruning and voting.
+You can ream more about each measure and its implementation
+#41-rule-quality>`_ .
+` here <https://github.com/adaa-polsl/RuleKit/wiki/4-Quality-and-evaluation
+
+
+Accuracy = 'Accuracy'
+
+
+
+
+BinaryEntropy = 'BinaryEntropy'
+
+
+
+
+C1 = 'C1'
+
+
+
+
+C2 = 'C2'
+
+
+
+
+CFoil = 'CFoil'
+
+
+
+
+CN2Significnce = 'CN2Significnce'
+
+
+
+
+Correlation = 'Correlation'
+
+
+
+
+Coverage = 'Coverage'
+
+
+
+
+FBayesianConfirmation = 'FBayesianConfirmation'
+
+
+
+
+FMeasure = 'FMeasure'
+
+
+
+
+FullCoverage = 'FullCoverage'
+
+
+
+
+
+
+
+
+GMeasure = 'GMeasure'
+
+
+
+
+InformationGain = 'InformationGain'
+
+
+
+
+JMeasure = 'JMeasure'
+
+
+
+
+Kappa = 'Kappa'
+
+
+
+
+Klosgen = 'Klosgen'
+
+
+
+
+Laplace = 'Laplace'
+
+
+
+
+Lift = 'Lift'
+
+
+
+
+LogicalSufficiency = 'LogicalSufficiency'
+
+
+
+
+MEstimate = 'MEstimate'
+
+
+
+
+MutualSupport = 'MutualSupport'
+
+
+
+
+Novelty = 'Novelty'
+
+
+
+
+OddsRatio = 'OddsRatio'
+
+
+
+
+OneWaySupport = 'OneWaySupport'
+
+
+
+
+PawlakDependencyFactor = 'PawlakDependencyFactor'
+
+
+
+
+Q2 = 'Q2'
+
+
+
+
+Precision = 'Precision'
+
+
+
+
+RelativeRisk = 'RelativeRisk'
+
+
+
+
+Ripper = 'Ripper'
+
+
+
+
+RuleInterest = 'RuleInterest'
+
+
+
+
+
+
+
+
+SBayesian = 'SBayesian'
+
+
+
+
+Sensitivity = 'Sensitivity'
+
+
+
+
+Specificity = 'Specificity'
+
+
+
+
+TwoWaySupport = 'TwoWaySupport'
+
+
+
+
+WeightedLaplace = 'WeightedLaplace'
+
+
+
+
+WeightedRelativeAccuracy = 'WeightedRelativeAccuracy'
+
+
+
+
+YAILS = 'YAILS'
+
+
+
+
+LogRank = 'LogRank'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/rst/autodoc/regression.html b/docs/serve/v2.1.24.0/rst/autodoc/regression.html
new file mode 100644
index 0000000..5475637
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/autodoc/regression.html
@@ -0,0 +1,529 @@
+
+
+
+
+
+
+ Regression — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rulekit v2.1.24.0
+
+
+
+
+
+
+
+
+
+Regression
+
+
+class rulekit.regression. RuleRegressor ( minsupp_new : float = 0.05 , induction_measure : Measures = Measures.Correlation , pruning_measure : Measures | str = Measures.Correlation , voting_measure : Measures = Measures.Correlation , max_growing : float = 0.0 , enable_pruning : bool = True , ignore_missing : bool = False , max_uncovered_fraction : float = 0.0 , select_best_candidate : bool = False , complementary_conditions : bool = False , mean_based_regression : bool = True , max_rule_count : int = 0 )
+Regression model.
+
+Parameters:
+
+minsupp_new (float = 5.0 ) – a minimum number (or fraction, if value < 1.0) of previously uncovered
+examples to be covered by a new rule (positive examples for classification
+problems); default: 5,
+induction_measure (rulekit.params.Measures
= rulekit.params.Measures.Correlation
) – measure used during induction; default measure is correlation
+pruning_measure (Union[rulekit.params.Measures
, str] = rulekit.params.Measures.Correlation
) –
+measure used during pruning. Could be user defined (string), for example 2 * p / n
; default measure is correlation
+
+
+
+voting_measure (rulekit.params.Measures
= rulekit.params.Measures.Correlation
) – measure used during voting; default measure is correlation
+max_growing (int = 0.0 ) – non-negative integer representing maximum number of conditions which can be
+added to the rule in the growing phase (use this parameter for large
+datasets if execution time is prohibitive); 0 indicates no limit; default: 0
+enable_pruning (bool = True ) – enable or disable pruning, default is True.
+ignore_missing (bool = False ) – boolean telling whether missing values should be ignored (by default, a
+missing value of given attribute is always considered as not fulfilling the
+condition build upon that attribute); default: False.
+max_uncovered_fraction (float = 0.0 ) – Floating-point number from [0,1] interval representing maximum fraction of
+examples that may remain uncovered by the rule set, default: 0.0.
+select_best_candidate (bool = False ) –
+Flag determining if best candidate should be selected from growing phase; default: False.
+
+
+
+complementary_conditions (bool = False ) – If enabled, complementary conditions in the form a = !{value} for nominal
+attributes are supported.
+mean_based_regression (bool = True ) – Enable fast induction of mean-based regression rules instead of default
+median-based.
+max_rule_count (int = 0 ) – Maximum number of rules to be generated; 0 indicates no limit. Default: 0
+
+
+
+
+
+add_event_listener ( listener : RuleInductionProgressListener )
+
+Add event listener object to the operator which allows to monitor rule induction progress.
+
+
+Example
+>>> from rulekit.events import RuleInductionProgressListener
+>>> from rulekit.classification import RuleClassifier
+>>>
+>>> class MyEventListener ( RuleInductionProgressListener ):
+>>> def on_new_rule ( self , rule ):
+>>> print ( 'Do something with new rule' , rule )
+>>>
+>>> operator = RuleClassifier ()
+>>> operator . add_event_listener ( MyEventListener ())
+
+
+
+Parameters:
+listener (RuleInductionProgressListener ) – listener object
+
+
+
+
+
+
+fit ( values : ndarray | DataFrame | list , labels : ndarray | DataFrame | list ) → RuleRegressor
+Train model on given dataset.
+
+Parameters:
+
+
+Returns:
+self
+
+Return type:
+RuleRegressor
+
+
+
+
+
+
+get_coverage_matrix ( values : ndarray | DataFrame | list ) → ndarray
+Calculates coverage matrix for ruleset.
+
+Parameters:
+values (rulekit.operator.Data
) – dataset
+
+Returns:
+coverage_matrix – Each row of the matrix represent single example from dataset and every
+column represent on rule from rule set. Value 1 in the matrix cell means
+that rule covered certain example, value 0 means that it doesn’t.
+
+Return type:
+np.ndarray
+
+
+
+
+
+
+get_metadata_routing ( ) → None
+
+
Warning
+
Scikit-learn metadata routing is not supported yet.
+
+
+Raises:
+NotImplementedError – _description_
+
+
+
+
+
+
+get_params ( deep : bool = True ) → dict [ str , Any ]
+
+Parameters:
+deep (rulekit.operator.Data
) – Parameter for scikit-learn compatibility. Not used.
+
+Returns:
+hyperparameters – Dictionary containing model hyperparameters.
+
+Return type:
+np.ndarray
+
+
+
+
+
+
+predict ( values : ndarray | DataFrame | list ) → ndarray
+Perform prediction and returns predicted values.
+
+Parameters:
+values (rulekit.operator.Data
) – attributes
+
+Returns:
+result – predicted values
+
+Return type:
+np.ndarray
+
+
+
+
+
+
+score ( values : ndarray | DataFrame | list , labels : ndarray | DataFrame | list ) → float
+Return the coefficient of determination R2 of the prediction
+
+Parameters:
+
+
+Returns:
+score – R2 of self.predict(values) wrt. labels.
+
+Return type:
+float
+
+
+
+
+
+
+set_params ( ** kwargs ) → object
+Set models hyperparameters. Parameters are the same as in constructor.
+
+
+
+
+
+
+class rulekit.regression. ExpertRuleRegressor ( minsupp_new : float = 0.05 , induction_measure : Measures = Measures.Correlation , pruning_measure : Measures | str = Measures.Correlation , voting_measure : Measures = Measures.Correlation , max_growing : float = 0.0 , enable_pruning : bool = True , ignore_missing : bool = False , max_uncovered_fraction : float = 0.0 , select_best_candidate : bool = False , complementary_conditions : bool = False , mean_based_regression : bool = True , max_rule_count : int = 0 , extend_using_preferred : bool = False , extend_using_automatic : bool = False , induce_using_preferred : bool = False , induce_using_automatic : bool = False , preferred_conditions_per_rule : int = 2147483647 , preferred_attributes_per_rule : int = 2147483647 )
+Expert Regression model.
+
+Parameters:
+
+minsupp_new (float = 5.0 ) – a minimum number (or fraction, if value < 1.0) of previously uncovered
+examples to be covered by a new rule (positive examples for classification
+problems); default: 5,
+induction_measure (rulekit.params.Measures
= rulekit.params.Measures.Correlation
) – measure used during induction; default measure is correlation
+pruning_measure (Union[rulekit.params.Measures
, str] = rulekit.params.Measures.Correlation
) –
+measure used during pruning. Could be user defined (string), for example 2 * p / n
; default measure is correlation
+
+
+
+voting_measure (rulekit.params.Measures
= rulekit.params.Measures.Correlation
) – measure used during voting; default measure is correlation
+max_growing (int = 0.0 ) – non-negative integer representing maximum number of conditions which can be
+added to the rule in the growing phase (use this parameter for large
+datasets if execution time is prohibitive); 0 indicates no limit; default: 0,
+enable_pruning (bool = True ) – enable or disable pruning, default is True.
+ignore_missing (bool = False ) – boolean telling whether missing values should be ignored (by default, a
+missing value of given attribute is always considered as not fulfilling the
+condition build upon that attribute); default: False.
+max_uncovered_fraction (float = 0.0 ) – Floating-point number from [0,1] interval representing maximum fraction of
+examples that may remain uncovered by the rule set, default: 0.0.
+select_best_candidate (bool = False ) – Flag determining if best candidate should be selected from growing phase;
+default: False.
+complementary_conditions (bool = False ) – If enabled, complementary conditions in the form a = !{value} for nominal
+attributes are supported.
+mean_based_regression (bool = True ) – Enable fast induction of mean-based regression rules instead of default
+median-based.
+max_rule_count (int = 0 ) – Maximum number of rules to be generated (for classification data sets it
+applies to a single class); 0 indicates no limit.
+extend_using_preferred (bool = False ) – boolean indicating whether initial rules should be extended with a use of
+preferred conditions and attributes; default is False
+extend_using_automatic (bool = False ) – boolean indicating whether initial rules should be extended with a use of
+automatic conditions and attributes; default is False
+induce_using_preferred (bool = False ) – boolean indicating whether new rules should be induced with a use of
+preferred conditions and attributes; default is False
+induce_using_automatic (bool = False ) – boolean indicating whether new rules should be induced with a use of
+automatic conditions and attributes; default is False
+preferred_conditions_per_rule (int = None ) – maximum number of preferred conditions per rule; default: unlimited,
+preferred_attributes_per_rule (int = None ) – maximum number of preferred attributes per rule; default: unlimited.
+
+
+
+
+
+add_event_listener ( listener : RuleInductionProgressListener )
+
+Add event listener object to the operator which allows to monitor rule induction progress.
+
+
+Example
+>>> from rulekit.events import RuleInductionProgressListener
+>>> from rulekit.classification import RuleClassifier
+>>>
+>>> class MyEventListener ( RuleInductionProgressListener ):
+>>> def on_new_rule ( self , rule ):
+>>> print ( 'Do something with new rule' , rule )
+>>>
+>>> operator = RuleClassifier ()
+>>> operator . add_event_listener ( MyEventListener ())
+
+
+
+Parameters:
+listener (RuleInductionProgressListener ) – listener object
+
+
+
+
+
+
+fit ( values : ndarray | DataFrame | list , labels : ndarray | DataFrame | list , expert_rules : list [ str | tuple [ str , str ] ] | None = None , expert_preferred_conditions : list [ str | tuple [ str , str ] ] | None = None , expert_forbidden_conditions : list [ str | tuple [ str , str ] ] | None = None ) → ExpertRuleRegressor
+Train model on given dataset.
+
+Parameters:
+
+values (rulekit.operator.Data
) – attributes
+labels (rulekit.operator.Data
) – target values
+expert_rules (List [ Union [ str , Tuple [ str , str ] ] ] ) – set of initial rules, either passed as a list of strings representing rules
+or as list of tuples where first element is name of the rule and second one
+is rule string.
+expert_preferred_conditions (List [ Union [ str , Tuple [ str , str ] ] ] ) – multiset of preferred conditions (used also for specifying preferred
+attributes by using special value Any). Either passed as a list of strings
+representing rules or as list of tuples where first element is name of the
+rule and second one is rule string.
+expert_forbidden_conditions (List [ Union [ str , Tuple [ str , str ] ] ] ) – set of forbidden conditions (used also for specifying forbidden attributes
+by using special valye Any). Either passed as a list of strings representing
+rules or as list of tuples where first element is name of the rule and
+second one is rule string.
+
+
+Returns:
+self
+
+Return type:
+ExpertRuleRegressor
+
+
+
+
+
+
+get_coverage_matrix ( values : ndarray | DataFrame | list ) → ndarray
+Calculates coverage matrix for ruleset.
+
+Parameters:
+values (rulekit.operator.Data
) – dataset
+
+Returns:
+coverage_matrix – Each row of the matrix represent single example from dataset and every
+column represent on rule from rule set. Value 1 in the matrix cell means
+that rule covered certain example, value 0 means that it doesn’t.
+
+Return type:
+np.ndarray
+
+
+
+
+
+
+get_metadata_routing ( ) → None
+
+
Warning
+
Scikit-learn metadata routing is not supported yet.
+
+
+Raises:
+NotImplementedError – _description_
+
+
+
+
+
+
+get_params ( deep : bool = True ) → dict [ str , Any ]
+
+Parameters:
+deep (rulekit.operator.Data
) – Parameter for scikit-learn compatibility. Not used.
+
+Returns:
+hyperparameters – Dictionary containing model hyperparameters.
+
+Return type:
+np.ndarray
+
+
+
+
+
+
+predict ( values : ndarray | DataFrame | list ) → ndarray
+Perform prediction and returns predicted values.
+
+Parameters:
+values (rulekit.operator.Data
) – attributes
+
+Returns:
+result – predicted values
+
+Return type:
+np.ndarray
+
+
+
+
+
+
+score ( values : ndarray | DataFrame | list , labels : ndarray | DataFrame | list ) → float
+Return the coefficient of determination R2 of the prediction
+
+Parameters:
+
+
+Returns:
+score – R2 of self.predict(values) wrt. labels.
+
+Return type:
+float
+
+
+
+
+
+
+set_params ( ** kwargs ) → object
+Set models hyperparameters. Parameters are the same as in constructor.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/rst/autodoc/rules.html b/docs/serve/v2.1.24.0/rst/autodoc/rules.html
new file mode 100644
index 0000000..cc0aa52
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/autodoc/rules.html
@@ -0,0 +1,479 @@
+
+
+
+
+
+
+ Rules — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rulekit v2.1.24.0
+
+
+
+
+
+
+
+
+
+Rules
+Contains classes representing rules and rulesets.
+
+
+class rulekit.rules. BaseRule ( java_object )
+Base class representing single rule.
+
+
+
+
+get_covering_information ( ) → dict
+Returns information about rule covering
+
+Returns:
+covering_data – Dictionary containing covering information.
+
+Return type:
+dict
+
+
+
+
+
+
+print_stats ( )
+Prints rule statistics as formatted text.
+
+
+
+
+property pvalue : float
+Rule significance.
+
+
+
+
+property stats : RuleStatistics
+Rule statistics.
+
+
+
+
+property weight : float
+Rule weight
+
+
+
+
+property weighted_N : float
+Number of negatives in the training set (accounting weights).
+
+
+
+
+property weighted_P : float
+Number of positives in the training set (accounting weights).
+
+
+
+
+property weighted_n : float
+Number of negatives covered by the rule (accounting weights).
+
+
+
+
+property weighted_p : float
+Number of positives covered by the rule (accounting weights).
+
+
+
+
+
+
+class rulekit.rules. ClassificationRule ( java_object )
+Class representing classification rule
+
+
+
+
+property decision_class : str
+Decision class of the rule
+
+
+
+
+
+
+class rulekit.rules. InductionParameters ( java_object )
+Induction parameters.
+
+
+property induction_measure : Measures | str
+Returns:
+Union[Measures, str]: Measure used for induction
+
+
+
+
+property pruning_measure : Measures | str
+Returns:
+Union[Measures, str]: Measure used for pruning
+
+
+
+
+property voting_measure : Measures | str
+Returns:
+Union[Measures, str]: Measure used for voting
+
+
+
+
+
+
+class rulekit.rules. RegressionRule ( java_object )
+Class representing regression rule
+
+
+
+
+property conclusion_value : float
+Value from the rule’s conclusion
+
+
+
+
+
+
+class rulekit.rules. RuleSet ( java_object )
+Class representing ruleset.
+
+
+
+
+calculate_avg_rule_coverage ( ) → float
+
+Returns:
+count – Average rule coverage.
+
+Return type:
+float
+
+
+
+
+
+
+calculate_avg_rule_precision ( ) → float
+
+Returns:
+count – Average rule precision.
+
+Return type:
+float
+
+
+
+
+
+
+calculate_avg_rule_quality ( ) → float
+
+Returns:
+count – Average rule quality.
+
+Return type:
+float
+
+
+
+
+
+
+calculate_conditions_count ( ) → float
+
+Returns:
+count – Number of conditions.
+
+Return type:
+float
+
+
+
+
+
+
+calculate_induced_conditions_count ( ) → float
+
+Returns:
+count – Number of induced conditions.
+
+Return type:
+float
+
+
+
+
+
+
+calculate_significance ( alpha : float ) → dict
+
+Parameters:
+alpha (float ) –
+
+Returns:
+count – Significance of the rule set.
+
+Return type:
+float
+
+
+
+
+
+
+calculate_significance_fdr ( alpha : float ) → dict
+
+Returns:
+count – Significance of the rule set with false discovery rate correction.
+Dictionary contains two fields: fraction (fraction of rules significant
+at assumed level) and p (average p-value of all rules).
+
+Return type:
+dict
+
+
+
+
+
+
+calculate_significance_fwer ( alpha : float ) → dict
+
+Returns:
+count – Significance of the rule set with familiy-wise error rate correction.
+Dictionary contains two fields: fraction (fraction of rules significant
+at assumed level) and p (average p-value of all rules).
+
+Return type:
+dict
+
+
+
+
+
+
+property growing_time : float
+Time of growing in seconds
+
+
+
+
+property is_voting : bool
+Value indicating whether rules are voting.
+
+
+
+
+property parameters : object
+Parameters used during rule set induction.
+
+
+
+
+property pruning_time : float
+Time of pruning in seconds
+
+
+
+
+property rules : list [ T ]
+List of rules objects.
+
+
+
+
+property stats : RuleSetStatistics
+Rule set statistics.
+
+
+
+
+property total_time : float
+Time of constructing the rule set in seconds
+
+
+
+
+
+
+class rulekit.rules. SurvivalRule ( java_object )
+Class representing survival rule
+
+
+
+
+property kaplan_meier_estimator : KaplanMeierEstimator
+Kaplan-Meier estimator from the rule concslusion
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/rst/autodoc/stats.html b/docs/serve/v2.1.24.0/rst/autodoc/stats.html
new file mode 100644
index 0000000..e49da74
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/autodoc/stats.html
@@ -0,0 +1,263 @@
+
+
+
+
+
+
+ Statistics — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rulekit v2.1.24.0
+
+
+
+
+
+
+
+
+
+Statistics
+Contains classes describing rules and rulesets statistics and metrics
+
+
+class rulekit.stats. RuleSetStatistics ( ruleset )
+Statistics for ruleset.
+
+
+SIGNIFICANCE_LEVEL
+Significance level, default value is 0.05
+
+Type:
+float
+
+
+
+
+
+time_total_sfloat Time of constructing the rule set in seconds.
+
+time_growing_sfloat Time of growing in seconds.
+
+time_pruning_sfloat Time of pruning in seconds.
+
+rules_countint Number of rules in ruleset.
+
+conditions_per_rulefloat Average number of conditions per rule.
+
+induced_conditions_per_rulefloat Average number of induced conditions.
+
+avg_rule_coveragefloat Average rule coverage.
+
+avg_rule_precisionfloat Average rule precision.
+
+avg_rule_qualityfloat Average rule quality.
+
+pvaluefloat rule set significance.
+
+FDR_pvaluefloat Significance of the rule set with false discovery rate correction.
+
+FWER_pvaluefloat Significance of the rule set with familiy-wise error rate correction.
+
+fraction_significantfloat Fraction of rules significant at assumed level
+
+fraction_FDR_significantfloat Fraction of rules significant, set with false discovery rate correction, at assumed level.
+
+fraction_FWER_significantfloat Fraction of rules significant, set with familiy-wise error rate correction, at assumed level.
+
+
+
+
+
+
+class rulekit.stats. RuleStatistics ( rule )
+Statistics for single rule.
+
+
+p
+Number of positives covered by the rule (accounting weights).
+
+Type:
+float
+
+
+
+
+
+
+n
+Number of negatives covered by the rule (accounting weights).
+
+Type:
+float
+
+
+
+
+
+
+P
+Number of positives in the training set (accounting weights).
+
+Type:
+float
+
+
+
+
+
+
+N
+Number of negatives in the training set (accounting weights).
+
+Type:
+float
+
+
+
+
+
+
+weight
+Rule weight.
+
+Type:
+float
+
+
+
+
+
+
+pvalue
+Rule significance.
+
+Type:
+float
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/rst/autodoc/survival.html b/docs/serve/v2.1.24.0/rst/autodoc/survival.html
new file mode 100644
index 0000000..561859e
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/autodoc/survival.html
@@ -0,0 +1,575 @@
+
+
+
+
+
+
+ Survival — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rulekit v2.1.24.0
+
+
+
+
+
+
+
+
+
+Survival
+
+
+class rulekit.survival. SurvivalRules ( survival_time_attr : str | None = None , minsupp_new : int = 0.05 , max_growing : int = 0.0 , enable_pruning : bool = True , ignore_missing : bool = False , max_uncovered_fraction : float = 0.0 , select_best_candidate : bool = False , complementary_conditions : bool = False , max_rule_count : int = 0 )
+Survival model.
+
+Parameters:
+
+survival_time_attr (str ) – name of column containing survival time data (use when data passed to model
+is padnas dataframe).
+minsupp_new (float = 5.0 ) – a minimum number (or fraction, if value < 1.0) of previously uncovered
+examples to be covered by a new rule (positive examples for classification
+problems); default: 5,
+max_growing (int = 0.0 ) – non-negative integer representing maximum number of conditions which can be
+added to the rule in the growing phase (use this parameter for large
+datasets if execution time is prohibitive); 0 indicates no limit; default: 0
+enable_pruning (bool = True ) – enable or disable pruning, default is True.
+ignore_missing (bool = False ) – boolean telling whether missing values should be ignored (by default, a
+missing value of given attribute is always considered as not fulfilling the
+condition build upon that attribute); default: False.
+max_uncovered_fraction (float = 0.0 ) – Floating-point number from [0,1] interval representing maximum fraction of
+examples that may remain uncovered by the rule set, default: 0.0.
+select_best_candidate (bool = False ) –
+Flag determining if best candidate should be selected from growing phase; default: False.
+
+
+
+complementary_conditions (bool = False ) – If enabled, complementary conditions in the form a = !{value} for nominal
+attributes are supported.
+max_rule_count (int = 0 ) – Maximum number of rules to be generated (for classification data sets it
+applies to a single class); 0 indicates no limit.
+
+
+
+
+
+add_event_listener ( listener : RuleInductionProgressListener )
+
+Add event listener object to the operator which allows to monitor rule induction progress.
+
+
+Example
+>>> from rulekit.events import RuleInductionProgressListener
+>>> from rulekit.classification import RuleClassifier
+>>>
+>>> class MyEventListener ( RuleInductionProgressListener ):
+>>> def on_new_rule ( self , rule ):
+>>> print ( 'Do something with new rule' , rule )
+>>>
+>>> operator = RuleClassifier ()
+>>> operator . add_event_listener ( MyEventListener ())
+
+
+
+Parameters:
+listener (RuleInductionProgressListener ) – listener object
+
+
+
+
+
+
+fit ( values : ndarray | DataFrame | list , labels : ndarray | DataFrame | list , survival_time : ndarray | DataFrame | list | None = None ) → SurvivalRules
+Train model on given dataset.
+
+Parameters:
+
+
+Returns:
+self
+
+Return type:
+SurvivalRules
+
+
+
+
+
+
+get_coverage_matrix ( values : ndarray | DataFrame | list ) → ndarray
+Calculates coverage matrix for ruleset.
+
+Parameters:
+values (rulekit.operator.Data
) – dataset
+
+Returns:
+coverage_matrix – Each row of the matrix represent single example from dataset and every
+column represent on rule from rule set. Value 1 in the matrix cell means
+that rule covered certain example, value 0 means that it doesn’t.
+
+Return type:
+np.ndarray
+
+
+
+
+
+
+get_metadata_routing ( ) → None
+
+
Warning
+
Scikit-learn metadata routing is not supported yet.
+
+
+Raises:
+NotImplementedError – _description_
+
+
+
+
+
+
+get_params ( deep : bool = True ) → dict [ str , Any ]
+
+Parameters:
+deep (rulekit.operator.Data
) – Parameter for scikit-learn compatibility. Not used.
+
+Returns:
+hyperparameters – Dictionary containing model hyperparameters.
+
+Return type:
+np.ndarray
+
+
+
+
+
+
+get_train_set_kaplan_meier ( ) → KaplanMeierEstimator
+Returns train set KaplanMeier estimator
+
+Returns:
+estimator
+
+Return type:
+KaplanMeierEstimator
+
+
+
+
+
+
+predict ( values : ndarray | DataFrame | list ) → ndarray
+Perform prediction and return estimated survival function for each example.
+
+Parameters:
+values (rulekit.operator.Data
) – attributes
+
+Returns:
+result – Each row represent single example from dataset and contains estimated
+survival function for that example. Estimated survival function is returned
+as a dictionary containing times and corresponding probabilities.
+
+Return type:
+np.ndarray
+
+
+
+
+
+
+score ( values : ndarray | DataFrame | list , labels : ndarray | DataFrame | list , survival_time : ndarray | DataFrame | list | None = None ) → float
+
+Return the Integrated Brier Score on the given dataset and labels (event status indicator).
+
+
+Integrated Brier Score (IBS) - the Brier score (BS) represents the squared
+difference between true event status at time T and predicted event status at
+that time; the Integrated Brier score summarizes the prediction error over all
+observations and over all times in a test set.
+
+Parameters:
+
+
+Returns:
+score – Integrated Brier Score of self.predict(values) wrt. labels.
+
+Return type:
+float
+
+
+
+
+
+
+set_params ( ** kwargs ) → object
+Set models hyperparameters. Parameters are the same as in constructor.
+
+
+
+
+
+
+class rulekit.survival. ExpertSurvivalRules ( survival_time_attr : str | None = None , minsupp_new : float = 0.05 , max_growing : int = 0.0 , enable_pruning : bool = True , ignore_missing : bool = False , max_uncovered_fraction : float = 0.0 , select_best_candidate : bool = False , complementary_conditions : bool = False , extend_using_preferred : bool = False , extend_using_automatic : bool = False , induce_using_preferred : bool = False , induce_using_automatic : bool = False , preferred_conditions_per_rule : int = 2147483647 , preferred_attributes_per_rule : int = 2147483647 , max_rule_count : int = 0 )
+Expert Survival model.
+
+Parameters:
+
+minsupp_new (float = 5.0 ) – a minimum number (or fraction, if value < 1.0) of previously uncovered
+examples to be covered by a new rule (positive examples for classification
+problems); default: 5,
+survival_time_attr (str ) – name of column containing survival time data (use when data passed to model
+is pandas dataframe).
+max_growing (int = 0.0 ) – non-negative integer representing maximum number of conditions which can be
+added to the rule in the growing phase (use this parameter for large
+datasets if execution time is prohibitive); 0 indicates no limit; default: 0
+enable_pruning (bool = True ) – enable or disable pruning, default is True.
+ignore_missing (bool = False ) – boolean telling whether missing values should be ignored (by default, a
+missing value of given attribute is always considered as not fulfilling the
+condition build upon that attribute); default: False.
+max_uncovered_fraction (float = 0.0 ) – Floating-point number from [0,1] interval representing maximum fraction of
+examples that may remain uncovered by the rule set, default: 0.0.
+select_best_candidate (bool = False ) –
+Flag determining if best candidate should be selected from growing phase; default: False.
+
+
+
+complementary_conditions (bool = False ) – If enabled, complementary conditions in the form a = !{value} for nominal
+attributes are supported.
+max_rule_count (int = 0 ) – Maximum number of rules to be generated (for classification data sets it
+applies to a single class); 0 indicates no limit.
+extend_using_preferred (bool = False ) – boolean indicating whether initial rules should be extended with a use of
+preferred conditions and attributes; default is False
+extend_using_automatic (bool = False ) – boolean indicating whether initial rules should be extended with a use of
+automatic conditions and attributes; default is False
+induce_using_preferred (bool = False ) – boolean indicating whether new rules should be induced with a use of
+preferred conditions and attributes; default is False
+induce_using_automatic (bool = False ) – boolean indicating whether new rules should be induced with a use of
+automatic conditions and attributes; default is False
+preferred_conditions_per_rule (int = None ) – maximum number of preferred conditions per rule; default: unlimited,
+preferred_attributes_per_rule (int = None ) – maximum number of preferred attributes per rule; default: unlimited.
+
+
+
+
+
+add_event_listener ( listener : RuleInductionProgressListener )
+
+Add event listener object to the operator which allows to monitor rule induction progress.
+
+
+Example
+>>> from rulekit.events import RuleInductionProgressListener
+>>> from rulekit.classification import RuleClassifier
+>>>
+>>> class MyEventListener ( RuleInductionProgressListener ):
+>>> def on_new_rule ( self , rule ):
+>>> print ( 'Do something with new rule' , rule )
+>>>
+>>> operator = RuleClassifier ()
+>>> operator . add_event_listener ( MyEventListener ())
+
+
+
+Parameters:
+listener (RuleInductionProgressListener ) – listener object
+
+
+
+
+
+
+fit ( values : ndarray | DataFrame | list , labels : ndarray | DataFrame | list , survival_time : ndarray | DataFrame | list | None = None , expert_rules : list [ str | tuple [ str , str ] ] | None = None , expert_preferred_conditions : list [ str | tuple [ str , str ] ] | None = None , expert_forbidden_conditions : list [ str | tuple [ str , str ] ] | None = None ) → ExpertSurvivalRules
+Train model on given dataset.
+
+Parameters:
+
+values (rulekit.operator.Data
) – attributes
+labels (Data ) – survival status
+survival_time (rulekit.operator.Data
) – data about survival time. Could be omitted when survival_time_attr
+parameter was specified.
+expert_rules (List [ Union [ str , Tuple [ str , str ] ] ] ) – set of initial rules, either passed as a list of strings representing rules
+or as list of tuples where first element is name of the rule and second one
+is rule string.
+expert_preferred_conditions (List [ Union [ str , Tuple [ str , str ] ] ] ) – multiset of preferred conditions (used also for specifying preferred
+attributes by using special value Any). Either passed as a list of strings
+representing rules or as list of tuples where first element is name of the
+rule and second one is rule string.
+expert_forbidden_conditions (List [ Union [ str , Tuple [ str , str ] ] ] ) – set of forbidden conditions (used also for specifying forbidden attributes
+by using special valye Any). Either passed as a list of strings representing
+rules or as list of tuples where first element is name of the rule and
+second one is rule string.
+
+
+Returns:
+self
+
+Return type:
+ExpertSurvivalRules
+
+
+
+
+
+
+get_coverage_matrix ( values : ndarray | DataFrame | list ) → ndarray
+Calculates coverage matrix for ruleset.
+
+Parameters:
+values (rulekit.operator.Data
) – dataset
+
+Returns:
+coverage_matrix – Each row of the matrix represent single example from dataset and every
+column represent on rule from rule set. Value 1 in the matrix cell means
+that rule covered certain example, value 0 means that it doesn’t.
+
+Return type:
+np.ndarray
+
+
+
+
+
+
+get_metadata_routing ( ) → None
+
+
Warning
+
Scikit-learn metadata routing is not supported yet.
+
+
+Raises:
+NotImplementedError – _description_
+
+
+
+
+
+
+get_params ( deep : bool = True ) → dict [ str , Any ]
+
+Parameters:
+deep (rulekit.operator.Data
) – Parameter for scikit-learn compatibility. Not used.
+
+Returns:
+hyperparameters – Dictionary containing model hyperparameters.
+
+Return type:
+np.ndarray
+
+
+
+
+
+
+get_train_set_kaplan_meier ( ) → KaplanMeierEstimator
+Returns train set KaplanMeier estimator
+
+Returns:
+estimator
+
+Return type:
+KaplanMeierEstimator
+
+
+
+
+
+
+predict ( values : ndarray | DataFrame | list ) → ndarray
+Perform prediction and return estimated survival function for each example.
+
+Parameters:
+values (rulekit.operator.Data
) – attributes
+
+Returns:
+result – Each row represent single example from dataset and contains estimated
+survival function for that example. Estimated survival function is returned
+as a dictionary containing times and corresponding probabilities.
+
+Return type:
+np.ndarray
+
+
+
+
+
+
+score ( values : ndarray | DataFrame | list , labels : ndarray | DataFrame | list , survival_time : ndarray | DataFrame | list | None = None ) → float
+
+Return the Integrated Brier Score on the given dataset and labels (event status indicator).
+
+
+Integrated Brier Score (IBS) - the Brier score (BS) represents the squared
+difference between true event status at time T and predicted event status at
+that time; the Integrated Brier score summarizes the prediction error over all
+observations and over all times in a test set.
+
+Parameters:
+
+
+Returns:
+score – Integrated Brier Score of self.predict(values) wrt. labels.
+
+Return type:
+float
+
+
+
+
+
+
+set_params ( ** kwargs ) → object
+Set models hyperparameters. Parameters are the same as in constructor.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/rst/quick_start.html b/docs/serve/v2.1.24.0/rst/quick_start.html
new file mode 100644
index 0000000..a87f484
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/quick_start.html
@@ -0,0 +1,174 @@
+
+
+
+
+
+
+ Quick start — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rulekit v2.1.24.0
+
+
+
+
+
+
+
+
+
+Quick start
+
+
Warning
+
This package is a wrapper for Java library, and requires Java Development Kit version 8
+or later to be installed on the computer. Both Open JDK and Oracle implementations are supported.
+
If you don’t have JDK installed on your computer you can quickly set it up using
+install-jdk package.
+
pip install install-jdk
+
+
+
import jdk
+
+jdk . install ( '11' , jre = True )
+
+
+
+
+Installation
+
+To check if everything was installed correctly call:
+import rulekit
+rulekit . __version__
+
+
+It should run without errors and print package version.
+
+
+Package usage
+Now we are finally ready to use rulekit package and its models.
+from sklearn import datasets
+from rulekit import RuleKit
+from rulekit.classification import RuleClassifier
+
+iris = datasets . load_iris ()
+X = iris . data
+y = iris . target
+
+classifier = RuleClassifier ()
+classifier . fit ( X , y )
+
+prediction = classifier . predict ( X )
+
+from sklearn.metrics import accuracy_score
+
+print ( 'Accuracy: ' , accuracy_score ( y , prediction ))
+
+
+As you may noticed, training and usage of rulekit models is the same as in scikit learn. This
+mean you easily can use scikit: metrics, cross-validation, hyper-parameters tuning etc.
+For more examples head to Tutorials section.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/rst/tutorials.html b/docs/serve/v2.1.24.0/rst/tutorials.html
new file mode 100644
index 0000000..05d4f8b
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/tutorials.html
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+ Tutorials — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/rst/tutorials/classification.html b/docs/serve/v2.1.24.0/rst/tutorials/classification.html
new file mode 100644
index 0000000..affd96d
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/tutorials/classification.html
@@ -0,0 +1,1458 @@
+
+
+
+
+
+
+ Classification — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rulekit v2.1.24.0
+
+
+
+
+
+
+
+
+
+Classification
+This notebook presents example usage of package for solving classification problem on seismic-bumps
dataset. You can access dataset here .
+
+
This tutorial will cover topics such as:
+
- training model
+
- changing model hyperparameters
+
- hyperparameters tuning
+
- calculating metrics for model
+
- getting RuleKit inbuilt
+
+
+Install dependencies
+
+
+
+Summary of the dataset
+
+
+
+
+
+
+
+
+
+
+ genergy
+ gimpuls
+ goenergy
+ goimpuls
+ nbumps
+ nbumps2
+ nbumps3
+ nbumps4
+ nbumps5
+ nbumps6
+ nbumps7
+ nbumps89
+ senergy
+ maxenergy
+ class
+
+
+
+
+ count
+ 2.584000e+03
+ 2584.000000
+ 2584.000000
+ 2584.000000
+ 2584.000000
+ 2584.000000
+ 2584.000000
+ 2584.000000
+ 2584.000000
+ 2584.0
+ 2584.0
+ 2584.0
+ 2584.000000
+ 2584.000000
+ 2584.000000
+
+
+ mean
+ 9.024252e+04
+ 538.579334
+ 12.375774
+ 4.508901
+ 0.859520
+ 0.393576
+ 0.392802
+ 0.067724
+ 0.004644
+ 0.0
+ 0.0
+ 0.0
+ 4975.270898
+ 4278.850619
+ 0.065789
+
+
+ std
+ 2.292005e+05
+ 562.652536
+ 80.319051
+ 63.166556
+ 1.364616
+ 0.783772
+ 0.769710
+ 0.279059
+ 0.068001
+ 0.0
+ 0.0
+ 0.0
+ 20450.833222
+ 19357.454882
+ 0.247962
+
+
+ min
+ 1.000000e+02
+ 2.000000
+ -96.000000
+ -96.000000
+ 0.000000
+ 0.000000
+ 0.000000
+ 0.000000
+ 0.000000
+ 0.0
+ 0.0
+ 0.0
+ 0.000000
+ 0.000000
+ 0.000000
+
+
+ 25%
+ 1.166000e+04
+ 190.000000
+ -37.000000
+ -36.000000
+ 0.000000
+ 0.000000
+ 0.000000
+ 0.000000
+ 0.000000
+ 0.0
+ 0.0
+ 0.0
+ 0.000000
+ 0.000000
+ 0.000000
+
+
+ 50%
+ 2.548500e+04
+ 379.000000
+ -6.000000
+ -6.000000
+ 0.000000
+ 0.000000
+ 0.000000
+ 0.000000
+ 0.000000
+ 0.0
+ 0.0
+ 0.0
+ 0.000000
+ 0.000000
+ 0.000000
+
+
+ 75%
+ 5.283250e+04
+ 669.000000
+ 38.000000
+ 30.250000
+ 1.000000
+ 1.000000
+ 1.000000
+ 0.000000
+ 0.000000
+ 0.0
+ 0.0
+ 0.0
+ 2600.000000
+ 2000.000000
+ 0.000000
+
+
+ max
+ 2.595650e+06
+ 4518.000000
+ 1245.000000
+ 838.000000
+ 9.000000
+ 8.000000
+ 7.000000
+ 3.000000
+ 1.000000
+ 0.0
+ 0.0
+ 0.0
+ 402000.000000
+ 400000.000000
+ 1.000000
+
+
+
+
+
+
+Decision class distribution
+
+
+
+
+
+
+
+
+
+
+
+Helper function for calculating metrics
+
+
+
+Rule induction on full dataset
+
+
+
+
+
+
+
+
+
+
+
+ time_total_s
+ time_growing_s
+ time_pruning_s
+ rules_count
+ conditions_per_rule
+ induced_conditions_per_rule
+ avg_rule_coverage
+ avg_rule_precision
+ avg_rule_quality
+ pvalue
+ FDR_pvalue
+ FWER_pvalue
+ fraction_significant
+ fraction_FDR_significant
+ fraction_FWER_significant
+
+
+ Measure
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ C2
+ 1.218550
+ 1.036229
+ 0.111458
+ 35
+ 4.742857
+ 22.142857
+ 0.259410
+ 0.670793
+ 0.322125
+ 0.005729
+ 0.005879
+ 0.010640
+ 0.971429
+ 0.971429
+ 0.885714
+
+
+ Correlation
+ 0.471475
+ 0.339709
+ 0.123223
+ 21
+ 5.142857
+ 51.666667
+ 0.306612
+ 0.469157
+ 0.201772
+ 0.016841
+ 0.017345
+ 0.026655
+ 0.904762
+ 0.904762
+ 0.857143
+
+
+ RSS
+ 1.514044
+ 1.327209
+ 0.171176
+ 14
+ 3.714286
+ 64.428571
+ 0.473795
+ 0.484564
+ 0.253249
+ 0.041892
+ 0.044068
+ 0.068063
+ 0.785714
+ 0.785714
+ 0.714286
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Accuracy
+ MAE
+ Kappa
+ Balanced accuracy
+ Logistic loss
+ Precision
+ Sensitivity
+ Specificity
+ NPV
+ PPV
+ ...
+ Lift
+ F-measure
+ Fowlkes-Mallows index
+ False positive
+ False negative
+ True positive
+ True negative
+ Rules per example
+ Voting conflicts
+ Geometric mean
+
+
+ Measure
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ C2
+ 0.932663
+ 0.067337
+ 0.433613
+ 0.709693
+ 2.427088
+ 2.427088
+ 0.452941
+ 0.966446
+ 0.961665
+ 0.487342
+ ...
+ 7.407595
+ 0.469512
+ 0.928703
+ 81
+ 93
+ 77
+ 2333
+ 9.079334
+ 2146.0
+ 0.661622
+
+
+ Correlation
+ 0.827399
+ 0.172601
+ 0.246689
+ 0.729909
+ 6.221157
+ 6.221157
+ 0.617647
+ 0.842171
+ 0.969018
+ 0.216049
+ ...
+ 3.283951
+ 0.320122
+ 0.823757
+ 381
+ 65
+ 105
+ 2033
+ 6.438854
+ 1993.0
+ 0.721224
+
+
+ RSS
+ 0.788313
+ 0.211687
+ 0.207458
+ 0.725394
+ 7.629984
+ 7.629984
+ 0.652941
+ 0.797846
+ 0.970277
+ 0.185309
+ ...
+ 2.816694
+ 0.288687
+ 0.789800
+ 488
+ 59
+ 111
+ 1926
+ 6.633127
+ 2085.0
+ 0.721766
+
+
+
+
3 rows × 23 columns
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 1
+
+
+
+
+ 0
+ 2333
+ 81
+
+
+ 1
+ 93
+ 77
+
+
+
+
+
+
+
+
+
+
+Confusion matrix - Correlation
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 1
+
+
+
+
+ 0
+ 2033
+ 381
+
+
+ 1
+ 65
+ 105
+
+
+
+
+
+
+
+
+
+
+Confusion matrix - RSS
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 1
+
+
+
+
+ 0
+ 1926
+ 488
+
+
+ 1
+ 59
+ 111
+
+
+
+
+
+
+C2 Measure generated rules
+
+
+
+
+
+
+IF gimpuls = (-inf, 32.50) THEN class = {0}
+IF nbumps = (-inf, 0.50) AND goenergy = <-84.50, inf) AND goimpuls = (-inf, -0.50) AND genergy = (-inf, 13675) THEN class = {0}
+IF genergy = (-inf, 17640) AND nbumps = (-inf, 0.50) AND goenergy = <-84.50, inf) THEN class = {0}
+IF genergy = <1625, 17640) AND maxenergy = (-inf, 3500) AND gimpuls = (-inf, 772.50) THEN class = {0}
+IF shift = {N} AND nbumps = (-inf, 0.50) AND goenergy = <-73.50, inf) THEN class = {0}
+IF shift = {N} AND senergy = (-inf, 6150) AND genergy = <1865, inf) AND goimpuls = (-inf, 230.50) THEN class = {0}
+IF senergy = (-inf, 550) AND gimpuls = (-inf, 380.50) AND goimpuls = (-inf, 96.50) AND goenergy = (-inf, 118) THEN class = {0}
+IF senergy = (-inf, 550) AND genergy = (-inf, 31790) AND goenergy = <-84.50, 114.50) THEN class = {0}
+IF senergy = (-inf, 550) AND goenergy = <-84.50, 87.50) AND gimpuls = (-inf, 1342.50) AND goimpuls = (-inf, 96) THEN class = {0}
+IF senergy = (-inf, 550) AND goimpuls = (-inf, 233.50) THEN class = {0}
+IF genergy = <1865, 28515) AND goenergy = (-inf, 105.50) AND nbumps = (-inf, 4.50) THEN class = {0}
+IF nbumps = <0.50, 1.50) AND gimpuls = (-inf, 1210) AND goimpuls = (-inf, 233.50) AND goenergy = <-72.50, inf) AND genergy = <12550, inf) THEN class = {0}
+IF gimpuls = (-inf, 514.50) AND nbumps = (-inf, 6.50) AND goimpuls = (-inf, 96.50) AND goenergy = <-84.50, inf) THEN class = {0}
+IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 1832.50) AND goimpuls = (-inf, 312) THEN class = {0}
+IF nbumps3 = (-inf, 2.50) AND nbumps = (-inf, 6.50) AND goenergy = <-88.50, inf) THEN class = {0}
+IF genergy = (-inf, 748755) AND goimpuls = (-inf, 95.50) AND maxenergy = (-inf, 55000) AND gimpuls = (-inf, 3096) THEN class = {0}
+IF nbumps3 = <3.50, inf) AND gimpuls = <364, 1459.50) AND senergy = <10150, inf) THEN class = {1}
+IF gimpuls = <2208.50, inf) AND genergy = <513615, 1005720) AND nbumps2 = <0.50, inf) AND nbumps = (-inf, 3.50) THEN class = {1}
+IF gimpuls = <1328, inf) AND goenergy = (-inf, -29.50) AND goimpuls = <-31.50, -14.50) AND nbumps4 = (-inf, 1.50) THEN class = {1}
+IF gimpuls = <1328, 2109) AND goimpuls = (-inf, -5.50) AND senergy = <350, 36350) AND genergy = <159155, 586025) AND nbumps2 = (-inf, 3.50) AND goenergy = <-41.50, inf) THEN class = {1}
+IF nbumps3 = <0.50, 1.50) AND gimpuls = <1408, 1959) AND goimpuls = <-20.50, 13.50) AND senergy = (-inf, 54950) THEN class = {1}
+IF senergy = <750, 38250) AND genergy = <254130, 1133675) AND goenergy = <-16.50, inf) AND gimpuls = <1438.50, inf) AND goimpuls = <-5, inf) THEN class = {1}
+IF nbumps = <4.50, inf) AND nbumps3 = <1.50, 4.50) AND gimpuls = <203.50, inf) AND senergy = <4300, 131700) AND goenergy = <-41.50, inf) THEN class = {1}
+IF nbumps = <2.50, 4.50) AND gimpuls = <740.50, inf) AND genergy = <38935, 127440) AND senergy = (-inf, 14750) AND goimpuls = (-inf, 68.50) THEN class = {1}
+IF nbumps = <2.50, inf) AND gimpuls = <379, 1742) AND senergy = (-inf, 31100) AND genergy = (-inf, 211170) AND goenergy = (-inf, 123.50) AND goimpuls = (-inf, 19.50) THEN class = {1}
+IF gimpuls = <1139.50, inf) AND goimpuls = <-46, 116.50) AND senergy = (-inf, 38250) AND genergy = <46580, 1877915) AND goenergy = (-inf, 183) AND shift = {W} AND nbumps3 = (-inf, 1.50) AND nbumps2 = (-inf, 2.50) THEN class = {1}
+IF nbumps = <1.50, 3.50) AND gimpuls = <521.50, 2344.50) AND nbumps2 = <0.50, inf) AND genergy = <34605, 656965) AND goenergy = (-inf, 137) AND goimpuls = <-39, 41.50) AND maxenergy = <450, inf) THEN class = {1}
+IF nbumps = <1.50, 3.50) AND nbumps2 = <0.50, inf) AND genergy = <18870, inf) AND nbumps3 = (-inf, 1.50) AND gimpuls = <160, inf) AND senergy = <550, inf) AND goimpuls = <-62.50, 8.50) AND goenergy = (-inf, -1.50) THEN class = {1}
+IF nbumps = <1.50, inf) AND gimpuls = <95, 1603.50) AND goenergy = (-inf, 131) AND goimpuls = <-70.50, 119) AND nbumps2 = (-inf, 4.50) AND nbumps3 = <0.50, inf) AND genergy = (-inf, 614380) AND maxenergy = (-inf, 25000) AND senergy = <2250, inf) THEN class = {1}
+IF goenergy = <-59.50, 186) AND genergy = <12415, 129940) AND gimpuls = <121.50, 793) AND senergy = <150, 1350) AND ghazard = {a} AND goimpuls = <-53.50, inf) THEN class = {1}
+IF genergy = <42215, 94300) AND gimpuls = <133.50, 813.50) AND ghazard = {a} AND goenergy = <-74.50, 160) AND senergy = (-inf, 11100) AND nbumps = (-inf, 3.50) AND nbumps3 = (-inf, 0.50) THEN class = {1}
+IF gimpuls = <537.50, 796) AND shift = {W} AND genergy = <17635, 36470) AND goimpuls = <-36.50, inf) AND goenergy = <-37.50, inf) AND nbumps = (-inf, 0.50) THEN class = {1}
+IF genergy = <18800, 52205) AND shift = {W} AND ghazard = {a} AND goimpuls = <-28.50, inf) AND goenergy = (-inf, 181) AND gimpuls = <380.50, 524.50) AND nbumps = (-inf, 0.50) THEN class = {1}
+IF gimpuls = <184.50, inf) AND goenergy = <-55.50, 128.50) AND genergy = <7265, inf) AND goimpuls = <-60.50, 37.50) AND nbumps = (-inf, 7.50) AND nbumps2 = (-inf, 4.50) AND maxenergy = (-inf, 25000) AND senergy = (-inf, 31350) THEN class = {1}
+IF gimpuls = <32.50, inf) AND goimpuls = <-74.50, inf) AND ghazard = {a} AND genergy = <1510, inf) AND goenergy = <-89.50, 124.50) THEN class = {1}
+
+
+
+
+Correlation Measure generated rules
+
+
+
+
+
+
+IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1252.50) THEN class = {0}
+IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 1331) AND goimpuls = (-inf, 312) AND nbumps5 = (-inf, 0.50) THEN class = {0}
+IF nbumps = (-inf, 2.50) THEN class = {0}
+IF gimpuls = (-inf, 1253.50) AND nbumps3 = (-inf, 2.50) AND nbumps = (-inf, 7) THEN class = {0}
+IF nbumps4 = (-inf, 2.50) THEN class = {0}
+IF nbumps2 = <0.50, 2.50) AND maxenergy = <1500, inf) AND senergy = (-inf, 36050) AND nbumps3 = <0.50, 4.50) AND goimpuls = <-34, 95) AND genergy = (-inf, 662435) AND gimpuls = <994.50, 1959) THEN class = {1}
+IF nbumps2 = <0.50, inf) AND maxenergy = <1500, inf) AND goimpuls = <-55, 95) AND nbumps = (-inf, 6.50) AND genergy = <61250, 662435) AND goenergy = (-inf, 96) AND nbumps3 = <0.50, inf) AND gimpuls = <712, 2257.50) AND senergy = (-inf, 31100) THEN class = {1}
+IF nbumps2 = <0.50, inf) AND genergy = <58310, 934630) AND goenergy = (-inf, 186) AND senergy = (-inf, 40650) AND maxenergy = <1500, inf) AND gimpuls = <538.50, inf) AND goimpuls = <-55, inf) THEN class = {1}
+IF nbumps = <1.50, inf) AND nbumps2 = <0.50, inf) AND gimpuls = <521.50, 2374) AND genergy = <58310, 799855) AND senergy = <650, 36050) AND goimpuls = <-71, 58.50) AND ghazard = {a} THEN class = {1}
+IF nbumps = <1.50, 6.50) AND nbumps2 = <0.50, inf) AND gimpuls = <521.50, 2374) AND genergy = <34360, inf) AND maxenergy = <350, inf) AND goimpuls = <-55, 95) AND senergy = <550, inf) AND nbumps4 = (-inf, 1.50) THEN class = {1}
+IF nbumps = <1.50, inf) AND gimpuls = <306, inf) AND genergy = <28325, inf) AND goimpuls = (-inf, 19.50) THEN class = {1}
+IF nbumps = <1.50, inf) AND nbumps2 = <0.50, inf) AND gimpuls = <153.50, 321) AND genergy = <14295, 36250) AND goimpuls = <-60.50, inf) AND senergy = (-inf, 40500) AND nbumps3 = (-inf, 3.50) THEN class = {1}
+IF genergy = <96260, 1062020) AND goimpuls = <-29, inf) AND senergy = <850, 7500) AND nbumps3 = (-inf, 1.50) AND gimpuls = <1404, 2965.50) AND nbumps = (-inf, 3.50) AND goenergy = (-inf, 69.50) THEN class = {1}
+IF gimpuls = <1253.50, inf) AND goenergy = <-50.50, 131.50) AND genergy = <46580, 1789250) AND nbumps = (-inf, 7.50) AND shift = {W} AND goimpuls = <-60.50, 118) AND senergy = (-inf, 95850) AND ghazard = {a} THEN class = {1}
+IF senergy = <550, inf) AND shift = {W} AND genergy = <10495, inf) AND gimpuls = <160, inf) AND goenergy = (-inf, 126) THEN class = {1}
+IF senergy = <350, inf) AND goimpuls = <-74.50, inf) AND gimpuls = <32.50, inf) AND goenergy = <-78.50, inf) AND maxenergy = <250, inf) THEN class = {1}
+IF genergy = <43150, inf) AND gimpuls = <133.50, inf) AND goenergy = (-inf, 176.50) THEN class = {1}
+IF shift = {W} AND genergy = <31760, 49585) AND gimpuls = <362.50, 771) AND goimpuls = <-27.50, inf) AND goenergy = <-3.50, inf) AND maxenergy = (-inf, 650) THEN class = {1}
+IF shift = {W} AND genergy = <20485, 43280) AND gimpuls = <380.50, 796) AND goimpuls = <-37, 142.50) AND goenergy = <-37.50, 181) AND nbumps = (-inf, 0.50) THEN class = {1}
+IF gimpuls = <177.50, inf) AND genergy = <7265, inf) AND goimpuls = (-inf, 241.50) AND goenergy = (-inf, 124.50) THEN class = {1}
+IF gimpuls = <54.50, 90) AND genergy = <1510, 4905) AND goimpuls = <-72.50, 28.50) AND seismoacoustic = {a} THEN class = {1}
+
+
+
+
+
+
+Stratified K-Folds cross-validation
+
+
+
+
+
+
+
+C:\Users\cezar\AppData\Local\Temp\ipykernel_13196\4002598548.py:22: RuntimeWarning: invalid value encountered in scalar divide
+ ppv: float = tp / (tp + fp)
+C:\Users\cezar\AppData\Local\Temp\ipykernel_13196\4002598548.py:39: RuntimeWarning: invalid value encountered in scalar divide
+ 'Lift': (tp / (tp + fp)) / ((tp + fn) / (tp + tn + fp + fn)),
+C:\Users\cezar\AppData\Local\Temp\ipykernel_13196\4002598548.py:22: RuntimeWarning: invalid value encountered in scalar divide
+ ppv: float = tp / (tp + fp)
+C:\Users\cezar\AppData\Local\Temp\ipykernel_13196\4002598548.py:39: RuntimeWarning: invalid value encountered in scalar divide
+ 'Lift': (tp / (tp + fp)) / ((tp + fn) / (tp + tn + fp + fn)),
+
+
+Rules characteristics
+
+
+
+
+
+
+time_total_s 0.292132
+time_growing_s 0.227262
+time_pruning_s 0.047455
+rules_count 34.200000
+conditions_per_rule 4.720378
+induced_conditions_per_rule 21.124536
+avg_rule_coverage 0.239541
+avg_rule_precision 0.690010
+avg_rule_quality 0.337021
+pvalue 0.014757
+FDR_pvalue 0.015234
+FWER_pvalue 0.030014
+fraction_significant 0.909792
+fraction_FDR_significant 0.909792
+fraction_FWER_significant 0.872710
+dtype: float64
+
+
+Rules evaluation (average)
+
+
+
+
+
+
+Accuracy 0.855063
+MAE 0.144937
+Kappa 0.107556
+Balanced accuracy 0.567020
+Logistic loss 5.224070
+Precision 5.224070
+Sensitivity 0.235294
+Specificity 0.898747
+NPV 0.945594
+PPV 0.495355
+psep 0.443788
+Fall-out 0.101253
+Youden's J statistic 0.134041
+Lift 7.520255
+F-measure 0.145015
+Fowlkes-Mallows index 0.870605
+False positive 24.500000
+False negative 13.000000
+True positive 4.000000
+True negative 216.900000
+Rules per example 7.871479
+Voting conflicts 179.000000
+Geometric mean 0.344832
+dtype: float64
+
+
+Confusion matrix (average)
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 1
+
+
+
+
+ 0
+ 216.9
+ 24.5
+
+
+ 1
+ 13.0
+ 4.0
+
+
+
+
+
+
+
+Hyperparameters tuning
+This one gonna take a while…
+
+
+
+
+
+
+Best BAC: 0.626780 using {'induction_measure': <Measures.WeightedLaplace: 'WeightedLaplace'>, 'minsupp_new': 5, 'pruning_measure': <Measures.RSS: 'RSS'>, 'voting_measure': <Measures.WeightedLaplace: 'WeightedLaplace'>}
+
+
+
+
+Building model with tuned hyperparameters
+
+Split dataset to train and test (80%/20%).
+
+Rules evaluation
+
+
+
+
+
+
+time_total_s 0.173054
+time_growing_s 0.120460
+time_pruning_s 0.029986
+rules_count 29.000000
+conditions_per_rule 2.689655
+induced_conditions_per_rule 15.310345
+avg_rule_coverage 0.491183
+avg_rule_precision 0.736226
+avg_rule_quality 1.309334
+pvalue 0.019831
+FDR_pvalue 0.019993
+FWER_pvalue 0.024284
+fraction_significant 0.931034
+fraction_FDR_significant 0.931034
+fraction_FWER_significant 0.931034
+dtype: float64
+
+
+
+
+Validate model on test dataset
+
+
+
+
+
+
+Accuracy 0.808511
+MAE 0.191489
+Kappa 0.170010
+Balanced accuracy 0.679398
+Logistic loss 6.901976
+Precision 6.901976
+Sensitivity 0.533333
+Specificity 0.825462
+NPV 0.966346
+PPV 0.158416
+psep 0.124762
+Fall-out 0.174538
+Youden's J statistic 0.358795
+Lift 2.730033
+F-measure 0.244275
+Fowlkes-Mallows index 0.809997
+False positive 85.000000
+False negative 14.000000
+True positive 16.000000
+True negative 402.000000
+Rules per example 14.034816
+Voting conflicts 360.000000
+Geometric mean 0.663511
+dtype: float64
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 1
+
+
+
+
+ 0
+ 402
+ 85
+
+
+ 1
+ 14
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/rst/tutorials/classification.ipynb b/docs/serve/v2.1.24.0/rst/tutorials/classification.ipynb
new file mode 100644
index 0000000..39d04aa
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/tutorials/classification.ipynb
@@ -0,0 +1,1591 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Classification"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This notebook presents example usage of package for solving classification problem on `seismic-bumps` dataset. You can access dataset [here](https://raw.githubusercontent.com/adaa-polsl/RuleKit/master/data/seismic-bumps/seismic-bumps.arff).\n",
+ "\n",
+ "This tutorial will cover topics such as: \n",
+ "- training model \n",
+ "- changing model hyperparameters \n",
+ "- hyperparameters tuning \n",
+ "- calculating metrics for model \n",
+ "- getting RuleKit inbuilt "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Install dependencies"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%pip install matplotlib"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Summary of the dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " genergy \n",
+ " gimpuls \n",
+ " goenergy \n",
+ " goimpuls \n",
+ " nbumps \n",
+ " nbumps2 \n",
+ " nbumps3 \n",
+ " nbumps4 \n",
+ " nbumps5 \n",
+ " nbumps6 \n",
+ " nbumps7 \n",
+ " nbumps89 \n",
+ " senergy \n",
+ " maxenergy \n",
+ " class \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " count \n",
+ " 2.584000e+03 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " 2584.0 \n",
+ " 2584.0 \n",
+ " 2584.0 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " 2584.000000 \n",
+ " \n",
+ " \n",
+ " mean \n",
+ " 9.024252e+04 \n",
+ " 538.579334 \n",
+ " 12.375774 \n",
+ " 4.508901 \n",
+ " 0.859520 \n",
+ " 0.393576 \n",
+ " 0.392802 \n",
+ " 0.067724 \n",
+ " 0.004644 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 4975.270898 \n",
+ " 4278.850619 \n",
+ " 0.065789 \n",
+ " \n",
+ " \n",
+ " std \n",
+ " 2.292005e+05 \n",
+ " 562.652536 \n",
+ " 80.319051 \n",
+ " 63.166556 \n",
+ " 1.364616 \n",
+ " 0.783772 \n",
+ " 0.769710 \n",
+ " 0.279059 \n",
+ " 0.068001 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 20450.833222 \n",
+ " 19357.454882 \n",
+ " 0.247962 \n",
+ " \n",
+ " \n",
+ " min \n",
+ " 1.000000e+02 \n",
+ " 2.000000 \n",
+ " -96.000000 \n",
+ " -96.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " \n",
+ " \n",
+ " 25% \n",
+ " 1.166000e+04 \n",
+ " 190.000000 \n",
+ " -37.000000 \n",
+ " -36.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " \n",
+ " \n",
+ " 50% \n",
+ " 2.548500e+04 \n",
+ " 379.000000 \n",
+ " -6.000000 \n",
+ " -6.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " \n",
+ " \n",
+ " 75% \n",
+ " 5.283250e+04 \n",
+ " 669.000000 \n",
+ " 38.000000 \n",
+ " 30.250000 \n",
+ " 1.000000 \n",
+ " 1.000000 \n",
+ " 1.000000 \n",
+ " 0.000000 \n",
+ " 0.000000 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 2600.000000 \n",
+ " 2000.000000 \n",
+ " 0.000000 \n",
+ " \n",
+ " \n",
+ " max \n",
+ " 2.595650e+06 \n",
+ " 4518.000000 \n",
+ " 1245.000000 \n",
+ " 838.000000 \n",
+ " 9.000000 \n",
+ " 8.000000 \n",
+ " 7.000000 \n",
+ " 3.000000 \n",
+ " 1.000000 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 0.0 \n",
+ " 402000.000000 \n",
+ " 400000.000000 \n",
+ " 1.000000 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " genergy gimpuls goenergy goimpuls nbumps \\\n",
+ "count 2.584000e+03 2584.000000 2584.000000 2584.000000 2584.000000 \n",
+ "mean 9.024252e+04 538.579334 12.375774 4.508901 0.859520 \n",
+ "std 2.292005e+05 562.652536 80.319051 63.166556 1.364616 \n",
+ "min 1.000000e+02 2.000000 -96.000000 -96.000000 0.000000 \n",
+ "25% 1.166000e+04 190.000000 -37.000000 -36.000000 0.000000 \n",
+ "50% 2.548500e+04 379.000000 -6.000000 -6.000000 0.000000 \n",
+ "75% 5.283250e+04 669.000000 38.000000 30.250000 1.000000 \n",
+ "max 2.595650e+06 4518.000000 1245.000000 838.000000 9.000000 \n",
+ "\n",
+ " nbumps2 nbumps3 nbumps4 nbumps5 nbumps6 nbumps7 \\\n",
+ "count 2584.000000 2584.000000 2584.000000 2584.000000 2584.0 2584.0 \n",
+ "mean 0.393576 0.392802 0.067724 0.004644 0.0 0.0 \n",
+ "std 0.783772 0.769710 0.279059 0.068001 0.0 0.0 \n",
+ "min 0.000000 0.000000 0.000000 0.000000 0.0 0.0 \n",
+ "25% 0.000000 0.000000 0.000000 0.000000 0.0 0.0 \n",
+ "50% 0.000000 0.000000 0.000000 0.000000 0.0 0.0 \n",
+ "75% 1.000000 1.000000 0.000000 0.000000 0.0 0.0 \n",
+ "max 8.000000 7.000000 3.000000 1.000000 0.0 0.0 \n",
+ "\n",
+ " nbumps89 senergy maxenergy class \n",
+ "count 2584.0 2584.000000 2584.000000 2584.000000 \n",
+ "mean 0.0 4975.270898 4278.850619 0.065789 \n",
+ "std 0.0 20450.833222 19357.454882 0.247962 \n",
+ "min 0.0 0.000000 0.000000 0.000000 \n",
+ "25% 0.0 0.000000 0.000000 0.000000 \n",
+ "50% 0.0 0.000000 0.000000 0.000000 \n",
+ "75% 0.0 2600.000000 2000.000000 0.000000 \n",
+ "max 0.0 402000.000000 400000.000000 1.000000 "
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import pandas as pd\n",
+ "from rulekit.arff import read_arff\n",
+ "\n",
+ "DATASET_URL: str = (\n",
+ " 'https://raw.githubusercontent.com/'\n",
+ " 'adaa-polsl/RuleKit/refs/heads/master/data/seismic-bumps/'\n",
+ " 'seismic-bumps.arff'\n",
+ ")\n",
+ "\n",
+ "df_full: pd.DataFrame = read_arff(DATASET_URL)\n",
+ "df_full['class'] = df_full['class'].astype(int)\n",
+ "df_full.describe()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Decision class distribution"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "groups = df_full['class'].value_counts()\n",
+ "sizes = [groups[0], groups[1]]\n",
+ "labels = [str(e) for e in groups.index]\n",
+ "\n",
+ "fig1, ax1 = plt.subplots()\n",
+ "ax1.pie(sizes, labels=labels, autopct='%1.1f%%', shadow=True, startangle=90)\n",
+ "ax1.axis('equal')\n",
+ "\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Helper function for calculating metrics"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import math\n",
+ "from sklearn import metrics\n",
+ "import numpy as np\n",
+ "from rulekit.classification import RuleClassifier\n",
+ "\n",
+ "\n",
+ "X: pd.DataFrame = df_full.drop(['class'], axis=1)\n",
+ "y: pd.Series = df_full['class']\n",
+ "\n",
+ "\n",
+ "def get_prediction_metrics(\n",
+ " measure: str,\n",
+ " y_pred: np.ndarray,\n",
+ " y_true: pd.Series,\n",
+ " classification_metrics: dict\n",
+ ") -> tuple[pd.DataFrame, np.ndarray]:\n",
+ " confusion_matrix: np.ndarray = metrics.confusion_matrix(y_true, y_pred)\n",
+ " tn, fp, fn, tp = confusion_matrix.ravel()\n",
+ " sensitivity: float = tp / (tp + fn)\n",
+ " specificity: float = tn / (tn + fp)\n",
+ " npv: float = tn / (tn + fn)\n",
+ " ppv: float = tp / (tp + fp)\n",
+ "\n",
+ " dictionary = {\n",
+ " 'Measure': measure,\n",
+ " 'Accuracy': metrics.accuracy_score(y_true, y_pred),\n",
+ " 'MAE': metrics.mean_absolute_error(y_true, y_pred),\n",
+ " 'Kappa': metrics.cohen_kappa_score(y_true, y_pred),\n",
+ " 'Balanced accuracy': metrics.balanced_accuracy_score(y_true, y_pred),\n",
+ " 'Logistic loss': metrics.log_loss(y_true, y_pred),\n",
+ " 'Precision': metrics.log_loss(y_true, y_pred),\n",
+ " 'Sensitivity': sensitivity,\n",
+ " 'Specificity': specificity,\n",
+ " 'NPV': npv,\n",
+ " 'PPV': ppv,\n",
+ " 'psep': ppv + npv - 1,\n",
+ " 'Fall-out': fp / (fp + tn),\n",
+ " \"Youden's J statistic\": sensitivity + specificity - 1,\n",
+ " 'Lift': (tp / (tp + fp)) / ((tp + fn) / (tp + tn + fp + fn)),\n",
+ " 'F-measure': 2 * tp / (2 * tp + fp + fn),\n",
+ " 'Fowlkes-Mallows index': metrics.fowlkes_mallows_score(y_true, y_pred),\n",
+ " 'False positive': fp,\n",
+ " 'False negative': fn,\n",
+ " 'True positive': tp,\n",
+ " 'True negative': tn,\n",
+ " 'Rules per example': classification_metrics['rules_per_example'],\n",
+ " 'Voting conflicts': classification_metrics['voting_conflicts'],\n",
+ " 'Geometric mean': math.sqrt(specificity * sensitivity),\n",
+ " 'Geometric mean': math.sqrt(specificity * sensitivity),\n",
+ " }\n",
+ " return pd.DataFrame.from_records([dictionary], index='Measure'), confusion_matrix\n",
+ "\n",
+ "\n",
+ "def get_ruleset_stats(\n",
+ " measure: str,\n",
+ " model: RuleClassifier\n",
+ ") -> pd.DataFrame:\n",
+ " return pd.DataFrame.from_records(\n",
+ " [{'Measure': measure, **model.stats.__dict__}],\n",
+ " index='Measure'\n",
+ " )"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Rule induction on full dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " time_total_s \n",
+ " time_growing_s \n",
+ " time_pruning_s \n",
+ " rules_count \n",
+ " conditions_per_rule \n",
+ " induced_conditions_per_rule \n",
+ " avg_rule_coverage \n",
+ " avg_rule_precision \n",
+ " avg_rule_quality \n",
+ " pvalue \n",
+ " FDR_pvalue \n",
+ " FWER_pvalue \n",
+ " fraction_significant \n",
+ " fraction_FDR_significant \n",
+ " fraction_FWER_significant \n",
+ " \n",
+ " \n",
+ " Measure \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " C2 \n",
+ " 1.218550 \n",
+ " 1.036229 \n",
+ " 0.111458 \n",
+ " 35 \n",
+ " 4.742857 \n",
+ " 22.142857 \n",
+ " 0.259410 \n",
+ " 0.670793 \n",
+ " 0.322125 \n",
+ " 0.005729 \n",
+ " 0.005879 \n",
+ " 0.010640 \n",
+ " 0.971429 \n",
+ " 0.971429 \n",
+ " 0.885714 \n",
+ " \n",
+ " \n",
+ " Correlation \n",
+ " 0.471475 \n",
+ " 0.339709 \n",
+ " 0.123223 \n",
+ " 21 \n",
+ " 5.142857 \n",
+ " 51.666667 \n",
+ " 0.306612 \n",
+ " 0.469157 \n",
+ " 0.201772 \n",
+ " 0.016841 \n",
+ " 0.017345 \n",
+ " 0.026655 \n",
+ " 0.904762 \n",
+ " 0.904762 \n",
+ " 0.857143 \n",
+ " \n",
+ " \n",
+ " RSS \n",
+ " 1.514044 \n",
+ " 1.327209 \n",
+ " 0.171176 \n",
+ " 14 \n",
+ " 3.714286 \n",
+ " 64.428571 \n",
+ " 0.473795 \n",
+ " 0.484564 \n",
+ " 0.253249 \n",
+ " 0.041892 \n",
+ " 0.044068 \n",
+ " 0.068063 \n",
+ " 0.785714 \n",
+ " 0.785714 \n",
+ " 0.714286 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " time_total_s time_growing_s time_pruning_s rules_count \\\n",
+ "Measure \n",
+ "C2 1.218550 1.036229 0.111458 35 \n",
+ "Correlation 0.471475 0.339709 0.123223 21 \n",
+ "RSS 1.514044 1.327209 0.171176 14 \n",
+ "\n",
+ " conditions_per_rule induced_conditions_per_rule \\\n",
+ "Measure \n",
+ "C2 4.742857 22.142857 \n",
+ "Correlation 5.142857 51.666667 \n",
+ "RSS 3.714286 64.428571 \n",
+ "\n",
+ " avg_rule_coverage avg_rule_precision avg_rule_quality \\\n",
+ "Measure \n",
+ "C2 0.259410 0.670793 0.322125 \n",
+ "Correlation 0.306612 0.469157 0.201772 \n",
+ "RSS 0.473795 0.484564 0.253249 \n",
+ "\n",
+ " pvalue FDR_pvalue FWER_pvalue fraction_significant \\\n",
+ "Measure \n",
+ "C2 0.005729 0.005879 0.010640 0.971429 \n",
+ "Correlation 0.016841 0.017345 0.026655 0.904762 \n",
+ "RSS 0.041892 0.044068 0.068063 0.785714 \n",
+ "\n",
+ " fraction_FDR_significant fraction_FWER_significant \n",
+ "Measure \n",
+ "C2 0.971429 0.885714 \n",
+ "Correlation 0.904762 0.857143 \n",
+ "RSS 0.785714 0.714286 "
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " Accuracy \n",
+ " MAE \n",
+ " Kappa \n",
+ " Balanced accuracy \n",
+ " Logistic loss \n",
+ " Precision \n",
+ " Sensitivity \n",
+ " Specificity \n",
+ " NPV \n",
+ " PPV \n",
+ " ... \n",
+ " Lift \n",
+ " F-measure \n",
+ " Fowlkes-Mallows index \n",
+ " False positive \n",
+ " False negative \n",
+ " True positive \n",
+ " True negative \n",
+ " Rules per example \n",
+ " Voting conflicts \n",
+ " Geometric mean \n",
+ " \n",
+ " \n",
+ " Measure \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " C2 \n",
+ " 0.932663 \n",
+ " 0.067337 \n",
+ " 0.433613 \n",
+ " 0.709693 \n",
+ " 2.427088 \n",
+ " 2.427088 \n",
+ " 0.452941 \n",
+ " 0.966446 \n",
+ " 0.961665 \n",
+ " 0.487342 \n",
+ " ... \n",
+ " 7.407595 \n",
+ " 0.469512 \n",
+ " 0.928703 \n",
+ " 81 \n",
+ " 93 \n",
+ " 77 \n",
+ " 2333 \n",
+ " 9.079334 \n",
+ " 2146.0 \n",
+ " 0.661622 \n",
+ " \n",
+ " \n",
+ " Correlation \n",
+ " 0.827399 \n",
+ " 0.172601 \n",
+ " 0.246689 \n",
+ " 0.729909 \n",
+ " 6.221157 \n",
+ " 6.221157 \n",
+ " 0.617647 \n",
+ " 0.842171 \n",
+ " 0.969018 \n",
+ " 0.216049 \n",
+ " ... \n",
+ " 3.283951 \n",
+ " 0.320122 \n",
+ " 0.823757 \n",
+ " 381 \n",
+ " 65 \n",
+ " 105 \n",
+ " 2033 \n",
+ " 6.438854 \n",
+ " 1993.0 \n",
+ " 0.721224 \n",
+ " \n",
+ " \n",
+ " RSS \n",
+ " 0.788313 \n",
+ " 0.211687 \n",
+ " 0.207458 \n",
+ " 0.725394 \n",
+ " 7.629984 \n",
+ " 7.629984 \n",
+ " 0.652941 \n",
+ " 0.797846 \n",
+ " 0.970277 \n",
+ " 0.185309 \n",
+ " ... \n",
+ " 2.816694 \n",
+ " 0.288687 \n",
+ " 0.789800 \n",
+ " 488 \n",
+ " 59 \n",
+ " 111 \n",
+ " 1926 \n",
+ " 6.633127 \n",
+ " 2085.0 \n",
+ " 0.721766 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
3 rows × 23 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " Accuracy MAE Kappa Balanced accuracy Logistic loss \\\n",
+ "Measure \n",
+ "C2 0.932663 0.067337 0.433613 0.709693 2.427088 \n",
+ "Correlation 0.827399 0.172601 0.246689 0.729909 6.221157 \n",
+ "RSS 0.788313 0.211687 0.207458 0.725394 7.629984 \n",
+ "\n",
+ " Precision Sensitivity Specificity NPV PPV ... \\\n",
+ "Measure ... \n",
+ "C2 2.427088 0.452941 0.966446 0.961665 0.487342 ... \n",
+ "Correlation 6.221157 0.617647 0.842171 0.969018 0.216049 ... \n",
+ "RSS 7.629984 0.652941 0.797846 0.970277 0.185309 ... \n",
+ "\n",
+ " Lift F-measure Fowlkes-Mallows index False positive \\\n",
+ "Measure \n",
+ "C2 7.407595 0.469512 0.928703 81 \n",
+ "Correlation 3.283951 0.320122 0.823757 381 \n",
+ "RSS 2.816694 0.288687 0.789800 488 \n",
+ "\n",
+ " False negative True positive True negative Rules per example \\\n",
+ "Measure \n",
+ "C2 93 77 2333 9.079334 \n",
+ "Correlation 65 105 2033 6.438854 \n",
+ "RSS 59 111 1926 6.633127 \n",
+ "\n",
+ " Voting conflicts Geometric mean \n",
+ "Measure \n",
+ "C2 2146.0 0.661622 \n",
+ "Correlation 1993.0 0.721224 \n",
+ "RSS 2085.0 0.721766 \n",
+ "\n",
+ "[3 rows x 23 columns]"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Confusion matrix - C2\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 2333 \n",
+ " 81 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 93 \n",
+ " 77 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 0 1\n",
+ "0 2333 81\n",
+ "1 93 77"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Confusion matrix - Correlation\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 2033 \n",
+ " 381 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 65 \n",
+ " 105 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 0 1\n",
+ "0 2033 381\n",
+ "1 65 105"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Confusion matrix - RSS\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1926 \n",
+ " 488 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 59 \n",
+ " 111 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 0 1\n",
+ "0 1926 488\n",
+ "1 59 111"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "from rulekit.classification import RuleClassifier\n",
+ "from rulekit.rules import RuleSet, ClassificationRule\n",
+ "from rulekit.params import Measures\n",
+ "from IPython.display import display\n",
+ "\n",
+ "# C2\n",
+ "clf = RuleClassifier(\n",
+ " induction_measure=Measures.C2,\n",
+ " pruning_measure=Measures.C2,\n",
+ " voting_measure=Measures.C2,\n",
+ ")\n",
+ "clf.fit(X, y)\n",
+ "c2_ruleset: RuleSet[ClassificationRule] = clf.model\n",
+ "prediction, classification_metrics = clf.predict(X, return_metrics=True)\n",
+ "\n",
+ "prediction_metric, c2_confusion_matrix = get_prediction_metrics('C2', prediction, y, classification_metrics)\n",
+ "model_stats = get_ruleset_stats('C2', clf.model)\n",
+ "\n",
+ "# Correlation\n",
+ "clf = RuleClassifier(\n",
+ " induction_measure=Measures.Correlation,\n",
+ " pruning_measure=Measures.Correlation,\n",
+ " voting_measure=Measures.Correlation,\n",
+ ")\n",
+ "clf.fit(X, y)\n",
+ "corr_ruleset: RuleSet[ClassificationRule] = clf.model\n",
+ "prediction, classification_metrics = clf.predict(X, return_metrics=True)\n",
+ "\n",
+ "tmp, corr_confusion_matrix = get_prediction_metrics('Correlation', prediction, y, classification_metrics)\n",
+ "prediction_metric = pd.concat([prediction_metric, tmp])\n",
+ "model_stats = pd.concat([model_stats, get_ruleset_stats('Correlation', clf.model)])\n",
+ "\n",
+ "# RSS\n",
+ "clf = RuleClassifier(\n",
+ " induction_measure=Measures.RSS,\n",
+ " pruning_measure=Measures.RSS,\n",
+ " voting_measure=Measures.RSS,\n",
+ ")\n",
+ "clf.fit(X, y)\n",
+ "rss_ruleset: RuleSet[ClassificationRule] = clf.model\n",
+ "prediction, classification_metrics = clf.predict(X, return_metrics=True)\n",
+ "tmp, rss_confusion_matrix = get_prediction_metrics('RSS', prediction, y, classification_metrics)\n",
+ "prediction_metric = pd.concat([prediction_metric, tmp])\n",
+ "model_stats = pd.concat([model_stats, get_ruleset_stats('RSS', clf.model)])\n",
+ "\n",
+ "display(model_stats)\n",
+ "display(prediction_metric)\n",
+ "\n",
+ "print('Confusion matrix - C2')\n",
+ "display(pd.DataFrame(c2_confusion_matrix))\n",
+ "\n",
+ "print('Confusion matrix - Correlation')\n",
+ "display(pd.DataFrame(corr_confusion_matrix))\n",
+ "\n",
+ "print('Confusion matrix - RSS')\n",
+ "display(pd.DataFrame(rss_confusion_matrix))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### C2 Measure generated rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF gimpuls = (-inf, 32.50) THEN class = {0}\n",
+ "IF nbumps = (-inf, 0.50) AND goenergy = <-84.50, inf) AND goimpuls = (-inf, -0.50) AND genergy = (-inf, 13675) THEN class = {0}\n",
+ "IF genergy = (-inf, 17640) AND nbumps = (-inf, 0.50) AND goenergy = <-84.50, inf) THEN class = {0}\n",
+ "IF genergy = <1625, 17640) AND maxenergy = (-inf, 3500) AND gimpuls = (-inf, 772.50) THEN class = {0}\n",
+ "IF shift = {N} AND nbumps = (-inf, 0.50) AND goenergy = <-73.50, inf) THEN class = {0}\n",
+ "IF shift = {N} AND senergy = (-inf, 6150) AND genergy = <1865, inf) AND goimpuls = (-inf, 230.50) THEN class = {0}\n",
+ "IF senergy = (-inf, 550) AND gimpuls = (-inf, 380.50) AND goimpuls = (-inf, 96.50) AND goenergy = (-inf, 118) THEN class = {0}\n",
+ "IF senergy = (-inf, 550) AND genergy = (-inf, 31790) AND goenergy = <-84.50, 114.50) THEN class = {0}\n",
+ "IF senergy = (-inf, 550) AND goenergy = <-84.50, 87.50) AND gimpuls = (-inf, 1342.50) AND goimpuls = (-inf, 96) THEN class = {0}\n",
+ "IF senergy = (-inf, 550) AND goimpuls = (-inf, 233.50) THEN class = {0}\n",
+ "IF genergy = <1865, 28515) AND goenergy = (-inf, 105.50) AND nbumps = (-inf, 4.50) THEN class = {0}\n",
+ "IF nbumps = <0.50, 1.50) AND gimpuls = (-inf, 1210) AND goimpuls = (-inf, 233.50) AND goenergy = <-72.50, inf) AND genergy = <12550, inf) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 514.50) AND nbumps = (-inf, 6.50) AND goimpuls = (-inf, 96.50) AND goenergy = <-84.50, inf) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 1832.50) AND goimpuls = (-inf, 312) THEN class = {0}\n",
+ "IF nbumps3 = (-inf, 2.50) AND nbumps = (-inf, 6.50) AND goenergy = <-88.50, inf) THEN class = {0}\n",
+ "IF genergy = (-inf, 748755) AND goimpuls = (-inf, 95.50) AND maxenergy = (-inf, 55000) AND gimpuls = (-inf, 3096) THEN class = {0}\n",
+ "IF nbumps3 = <3.50, inf) AND gimpuls = <364, 1459.50) AND senergy = <10150, inf) THEN class = {1}\n",
+ "IF gimpuls = <2208.50, inf) AND genergy = <513615, 1005720) AND nbumps2 = <0.50, inf) AND nbumps = (-inf, 3.50) THEN class = {1}\n",
+ "IF gimpuls = <1328, inf) AND goenergy = (-inf, -29.50) AND goimpuls = <-31.50, -14.50) AND nbumps4 = (-inf, 1.50) THEN class = {1}\n",
+ "IF gimpuls = <1328, 2109) AND goimpuls = (-inf, -5.50) AND senergy = <350, 36350) AND genergy = <159155, 586025) AND nbumps2 = (-inf, 3.50) AND goenergy = <-41.50, inf) THEN class = {1}\n",
+ "IF nbumps3 = <0.50, 1.50) AND gimpuls = <1408, 1959) AND goimpuls = <-20.50, 13.50) AND senergy = (-inf, 54950) THEN class = {1}\n",
+ "IF senergy = <750, 38250) AND genergy = <254130, 1133675) AND goenergy = <-16.50, inf) AND gimpuls = <1438.50, inf) AND goimpuls = <-5, inf) THEN class = {1}\n",
+ "IF nbumps = <4.50, inf) AND nbumps3 = <1.50, 4.50) AND gimpuls = <203.50, inf) AND senergy = <4300, 131700) AND goenergy = <-41.50, inf) THEN class = {1}\n",
+ "IF nbumps = <2.50, 4.50) AND gimpuls = <740.50, inf) AND genergy = <38935, 127440) AND senergy = (-inf, 14750) AND goimpuls = (-inf, 68.50) THEN class = {1}\n",
+ "IF nbumps = <2.50, inf) AND gimpuls = <379, 1742) AND senergy = (-inf, 31100) AND genergy = (-inf, 211170) AND goenergy = (-inf, 123.50) AND goimpuls = (-inf, 19.50) THEN class = {1}\n",
+ "IF gimpuls = <1139.50, inf) AND goimpuls = <-46, 116.50) AND senergy = (-inf, 38250) AND genergy = <46580, 1877915) AND goenergy = (-inf, 183) AND shift = {W} AND nbumps3 = (-inf, 1.50) AND nbumps2 = (-inf, 2.50) THEN class = {1}\n",
+ "IF nbumps = <1.50, 3.50) AND gimpuls = <521.50, 2344.50) AND nbumps2 = <0.50, inf) AND genergy = <34605, 656965) AND goenergy = (-inf, 137) AND goimpuls = <-39, 41.50) AND maxenergy = <450, inf) THEN class = {1}\n",
+ "IF nbumps = <1.50, 3.50) AND nbumps2 = <0.50, inf) AND genergy = <18870, inf) AND nbumps3 = (-inf, 1.50) AND gimpuls = <160, inf) AND senergy = <550, inf) AND goimpuls = <-62.50, 8.50) AND goenergy = (-inf, -1.50) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) AND gimpuls = <95, 1603.50) AND goenergy = (-inf, 131) AND goimpuls = <-70.50, 119) AND nbumps2 = (-inf, 4.50) AND nbumps3 = <0.50, inf) AND genergy = (-inf, 614380) AND maxenergy = (-inf, 25000) AND senergy = <2250, inf) THEN class = {1}\n",
+ "IF goenergy = <-59.50, 186) AND genergy = <12415, 129940) AND gimpuls = <121.50, 793) AND senergy = <150, 1350) AND ghazard = {a} AND goimpuls = <-53.50, inf) THEN class = {1}\n",
+ "IF genergy = <42215, 94300) AND gimpuls = <133.50, 813.50) AND ghazard = {a} AND goenergy = <-74.50, 160) AND senergy = (-inf, 11100) AND nbumps = (-inf, 3.50) AND nbumps3 = (-inf, 0.50) THEN class = {1}\n",
+ "IF gimpuls = <537.50, 796) AND shift = {W} AND genergy = <17635, 36470) AND goimpuls = <-36.50, inf) AND goenergy = <-37.50, inf) AND nbumps = (-inf, 0.50) THEN class = {1}\n",
+ "IF genergy = <18800, 52205) AND shift = {W} AND ghazard = {a} AND goimpuls = <-28.50, inf) AND goenergy = (-inf, 181) AND gimpuls = <380.50, 524.50) AND nbumps = (-inf, 0.50) THEN class = {1}\n",
+ "IF gimpuls = <184.50, inf) AND goenergy = <-55.50, 128.50) AND genergy = <7265, inf) AND goimpuls = <-60.50, 37.50) AND nbumps = (-inf, 7.50) AND nbumps2 = (-inf, 4.50) AND maxenergy = (-inf, 25000) AND senergy = (-inf, 31350) THEN class = {1}\n",
+ "IF gimpuls = <32.50, inf) AND goimpuls = <-74.50, inf) AND ghazard = {a} AND genergy = <1510, inf) AND goenergy = <-89.50, 124.50) THEN class = {1}\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in c2_ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Correlation Measure generated rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1252.50) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 1331) AND goimpuls = (-inf, 312) AND nbumps5 = (-inf, 0.50) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 1253.50) AND nbumps3 = (-inf, 2.50) AND nbumps = (-inf, 7) THEN class = {0}\n",
+ "IF nbumps4 = (-inf, 2.50) THEN class = {0}\n",
+ "IF nbumps2 = <0.50, 2.50) AND maxenergy = <1500, inf) AND senergy = (-inf, 36050) AND nbumps3 = <0.50, 4.50) AND goimpuls = <-34, 95) AND genergy = (-inf, 662435) AND gimpuls = <994.50, 1959) THEN class = {1}\n",
+ "IF nbumps2 = <0.50, inf) AND maxenergy = <1500, inf) AND goimpuls = <-55, 95) AND nbumps = (-inf, 6.50) AND genergy = <61250, 662435) AND goenergy = (-inf, 96) AND nbumps3 = <0.50, inf) AND gimpuls = <712, 2257.50) AND senergy = (-inf, 31100) THEN class = {1}\n",
+ "IF nbumps2 = <0.50, inf) AND genergy = <58310, 934630) AND goenergy = (-inf, 186) AND senergy = (-inf, 40650) AND maxenergy = <1500, inf) AND gimpuls = <538.50, inf) AND goimpuls = <-55, inf) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) AND nbumps2 = <0.50, inf) AND gimpuls = <521.50, 2374) AND genergy = <58310, 799855) AND senergy = <650, 36050) AND goimpuls = <-71, 58.50) AND ghazard = {a} THEN class = {1}\n",
+ "IF nbumps = <1.50, 6.50) AND nbumps2 = <0.50, inf) AND gimpuls = <521.50, 2374) AND genergy = <34360, inf) AND maxenergy = <350, inf) AND goimpuls = <-55, 95) AND senergy = <550, inf) AND nbumps4 = (-inf, 1.50) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) AND gimpuls = <306, inf) AND genergy = <28325, inf) AND goimpuls = (-inf, 19.50) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) AND nbumps2 = <0.50, inf) AND gimpuls = <153.50, 321) AND genergy = <14295, 36250) AND goimpuls = <-60.50, inf) AND senergy = (-inf, 40500) AND nbumps3 = (-inf, 3.50) THEN class = {1}\n",
+ "IF genergy = <96260, 1062020) AND goimpuls = <-29, inf) AND senergy = <850, 7500) AND nbumps3 = (-inf, 1.50) AND gimpuls = <1404, 2965.50) AND nbumps = (-inf, 3.50) AND goenergy = (-inf, 69.50) THEN class = {1}\n",
+ "IF gimpuls = <1253.50, inf) AND goenergy = <-50.50, 131.50) AND genergy = <46580, 1789250) AND nbumps = (-inf, 7.50) AND shift = {W} AND goimpuls = <-60.50, 118) AND senergy = (-inf, 95850) AND ghazard = {a} THEN class = {1}\n",
+ "IF senergy = <550, inf) AND shift = {W} AND genergy = <10495, inf) AND gimpuls = <160, inf) AND goenergy = (-inf, 126) THEN class = {1}\n",
+ "IF senergy = <350, inf) AND goimpuls = <-74.50, inf) AND gimpuls = <32.50, inf) AND goenergy = <-78.50, inf) AND maxenergy = <250, inf) THEN class = {1}\n",
+ "IF genergy = <43150, inf) AND gimpuls = <133.50, inf) AND goenergy = (-inf, 176.50) THEN class = {1}\n",
+ "IF shift = {W} AND genergy = <31760, 49585) AND gimpuls = <362.50, 771) AND goimpuls = <-27.50, inf) AND goenergy = <-3.50, inf) AND maxenergy = (-inf, 650) THEN class = {1}\n",
+ "IF shift = {W} AND genergy = <20485, 43280) AND gimpuls = <380.50, 796) AND goimpuls = <-37, 142.50) AND goenergy = <-37.50, 181) AND nbumps = (-inf, 0.50) THEN class = {1}\n",
+ "IF gimpuls = <177.50, inf) AND genergy = <7265, inf) AND goimpuls = (-inf, 241.50) AND goenergy = (-inf, 124.50) THEN class = {1}\n",
+ "IF gimpuls = <54.50, 90) AND genergy = <1510, 4905) AND goimpuls = <-72.50, 28.50) AND seismoacoustic = {a} THEN class = {1}\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in corr_ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### RSS Measure generated rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF nbumps = (-inf, 1.50) AND genergy = (-inf, 126350) THEN class = {0}\n",
+ "IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 2168) AND goimpuls = (-inf, 96.50) THEN class = {0}\n",
+ "IF genergy = (-inf, 44750) AND nbumps3 = (-inf, 2.50) AND goenergy = (-inf, 105.50) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 725.50) AND nbumps3 = (-inf, 3.50) AND nbumps4 = (-inf, 2.50) AND goimpuls = (-inf, 117) AND goenergy = <-88.50, inf) THEN class = {0}\n",
+ "IF nbumps2 = (-inf, 1.50) AND nbumps = (-inf, 4.50) THEN class = {0}\n",
+ "IF goimpuls = (-inf, 312) AND nbumps5 = (-inf, 0.50) AND goenergy = <-88.50, inf) THEN class = {0}\n",
+ "IF gimpuls = <521.50, inf) AND genergy = <57680, inf) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) THEN class = {1}\n",
+ "IF senergy = <550, inf) AND shift = {W} AND genergy = <10495, inf) THEN class = {1}\n",
+ "IF nbumps = <0.50, inf) AND goimpuls = <-74.50, inf) AND gimpuls = <32.50, inf) AND goenergy = <-78.50, 124.50) THEN class = {1}\n",
+ "IF genergy = <34315, 49585) AND ghazard = {a} AND gimpuls = <396, 1445.50) AND goenergy = <7, inf) AND goimpuls = <-19, inf) AND senergy = (-inf, 350) THEN class = {1}\n",
+ "IF genergy = <26200, 78890) AND gimpuls = <133.50, 813.50) AND goenergy = <-74.50, 297.50) AND goimpuls = <-71, inf) AND nbumps = (-inf, 3.50) AND senergy = (-inf, 1850) THEN class = {1}\n",
+ "IF genergy = <18585, 25305) AND shift = {W} AND gimpuls = <240, 588.50) AND goimpuls = <-42.50, 133) AND goenergy = <-45.50, inf) AND senergy = (-inf, 450) THEN class = {1}\n",
+ "IF gimpuls = <54.50, inf) AND goimpuls = <-74.50, 28.50) AND genergy = <1510, inf) AND ghazard = {a} AND nbumps4 = (-inf, 1.50) AND senergy = (-inf, 92850) THEN class = {1}\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in rss_ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Stratified K-Folds cross-validation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from IPython.display import display\n",
+ "from sklearn.model_selection import StratifiedKFold\n",
+ "\n",
+ "N_SPLITS: int = 10\n",
+ "\n",
+ "skf = StratifiedKFold(n_splits=10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "C:\\Users\\cezar\\AppData\\Local\\Temp\\ipykernel_13196\\4002598548.py:22: RuntimeWarning: invalid value encountered in scalar divide\n",
+ " ppv: float = tp / (tp + fp)\n",
+ "C:\\Users\\cezar\\AppData\\Local\\Temp\\ipykernel_13196\\4002598548.py:39: RuntimeWarning: invalid value encountered in scalar divide\n",
+ " 'Lift': (tp / (tp + fp)) / ((tp + fn) / (tp + tn + fp + fn)),\n",
+ "C:\\Users\\cezar\\AppData\\Local\\Temp\\ipykernel_13196\\4002598548.py:22: RuntimeWarning: invalid value encountered in scalar divide\n",
+ " ppv: float = tp / (tp + fp)\n",
+ "C:\\Users\\cezar\\AppData\\Local\\Temp\\ipykernel_13196\\4002598548.py:39: RuntimeWarning: invalid value encountered in scalar divide\n",
+ " 'Lift': (tp / (tp + fp)) / ((tp + fn) / (tp + tn + fp + fn)),\n"
+ ]
+ }
+ ],
+ "source": [
+ "c2_ruleset_stats = pd.DataFrame()\n",
+ "c2_prediction_metrics = pd.DataFrame()\n",
+ "c2_confusion_matrix = np.array([[0.0, 0.0], [0.0, 0.0]])\n",
+ "\n",
+ "for train_index, test_index in skf.split(X, y):\n",
+ " x_train, x_test = X.iloc[train_index], X.iloc[test_index]\n",
+ " y_train, y_test = y.iloc[train_index], y.iloc[test_index]\n",
+ "\n",
+ " clf = RuleClassifier(\n",
+ " induction_measure=Measures.C2,\n",
+ " pruning_measure=Measures.C2,\n",
+ " voting_measure=Measures.C2,\n",
+ " )\n",
+ " clf.fit(x_train, y_train)\n",
+ " c2_ruleset = clf.model\n",
+ " prediction, classification_metrics = clf.predict(x_test, return_metrics=True)\n",
+ " tmp, confusion_matrix = get_prediction_metrics('C2', prediction, y_test, classification_metrics)\n",
+ " \n",
+ " c2_prediction_metrics = pd.concat([c2_prediction_metrics, tmp])\n",
+ " c2_ruleset_stats = pd.concat([c2_ruleset_stats, get_ruleset_stats('C2', c2_ruleset)])\n",
+ " c2_confusion_matrix += confusion_matrix\n",
+ "\n",
+ "c2_confusion_matrix /= N_SPLITS"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Rules characteristics "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "time_total_s 0.292132\n",
+ "time_growing_s 0.227262\n",
+ "time_pruning_s 0.047455\n",
+ "rules_count 34.200000\n",
+ "conditions_per_rule 4.720378\n",
+ "induced_conditions_per_rule 21.124536\n",
+ "avg_rule_coverage 0.239541\n",
+ "avg_rule_precision 0.690010\n",
+ "avg_rule_quality 0.337021\n",
+ "pvalue 0.014757\n",
+ "FDR_pvalue 0.015234\n",
+ "FWER_pvalue 0.030014\n",
+ "fraction_significant 0.909792\n",
+ "fraction_FDR_significant 0.909792\n",
+ "fraction_FWER_significant 0.872710\n",
+ "dtype: float64"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(c2_ruleset_stats.mean())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Rules evaluation (average)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Accuracy 0.855063\n",
+ "MAE 0.144937\n",
+ "Kappa 0.107556\n",
+ "Balanced accuracy 0.567020\n",
+ "Logistic loss 5.224070\n",
+ "Precision 5.224070\n",
+ "Sensitivity 0.235294\n",
+ "Specificity 0.898747\n",
+ "NPV 0.945594\n",
+ "PPV 0.495355\n",
+ "psep 0.443788\n",
+ "Fall-out 0.101253\n",
+ "Youden's J statistic 0.134041\n",
+ "Lift 7.520255\n",
+ "F-measure 0.145015\n",
+ "Fowlkes-Mallows index 0.870605\n",
+ "False positive 24.500000\n",
+ "False negative 13.000000\n",
+ "True positive 4.000000\n",
+ "True negative 216.900000\n",
+ "Rules per example 7.871479\n",
+ "Voting conflicts 179.000000\n",
+ "Geometric mean 0.344832\n",
+ "dtype: float64"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(c2_prediction_metrics.mean())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Confusion matrix (average)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 216.9 \n",
+ " 24.5 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 13.0 \n",
+ " 4.0 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 0 1\n",
+ "0 216.9 24.5\n",
+ "1 13.0 4.0"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(pd.DataFrame(c2_confusion_matrix))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Hyperparameters tuning\n",
+ "\n",
+ "This one gonna take a while..."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Best BAC: 0.626780 using {'induction_measure': , 'minsupp_new': 5, 'pruning_measure': , 'voting_measure': }\n"
+ ]
+ }
+ ],
+ "source": [
+ "from sklearn.model_selection import StratifiedKFold\n",
+ "from sklearn.model_selection import GridSearchCV\n",
+ "from rulekit.params import Measures\n",
+ "\n",
+ "N_SPLITS: int = 3\n",
+ "\n",
+ "# define models and parameters\n",
+ "model = RuleClassifier()\n",
+ "minsupp_new = range(3, 15, 2)\n",
+ "measures_choice = [Measures.C2, Measures.RSS, Measures.WeightedLaplace, Measures.Correlation]\n",
+ "\n",
+ "# define grid search\n",
+ "grid = {\n",
+ " 'minsupp_new': minsupp_new, \n",
+ " 'induction_measure': measures_choice, \n",
+ " 'pruning_measure': measures_choice, \n",
+ " 'voting_measure': measures_choice\n",
+ "}\n",
+ "cv = StratifiedKFold(n_splits=N_SPLITS)\n",
+ "grid_search = GridSearchCV(\n",
+ " estimator=model, \n",
+ " param_grid=grid, \n",
+ " cv=cv, \n",
+ " scoring='balanced_accuracy', \n",
+ " n_jobs=3\n",
+ ")\n",
+ "grid_result = grid_search.fit(X, y)\n",
+ "\n",
+ "# summarize results\n",
+ "print(\"Best BAC: %f using %s\" % (grid_result.best_score_, grid_result.best_params_))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Building model with tuned hyperparameters\n",
+ "\n",
+ "### Split dataset to train and test (80%/20%)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import pandas as pd\n",
+ "from sklearn.model_selection import train_test_split\n",
+ "from IPython.display import display\n",
+ "\n",
+ "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=True)\n",
+ "\n",
+ "\n",
+ "clf = RuleClassifier(**grid_result.best_params_)\n",
+ "clf.fit(X_train, y_train)\n",
+ "ruleset: RuleSet[ClassificationRule] = clf.model\n",
+ "ruleset_stats = get_ruleset_stats('Best', ruleset)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Rules evaluation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "time_total_s 0.173054\n",
+ "time_growing_s 0.120460\n",
+ "time_pruning_s 0.029986\n",
+ "rules_count 29.000000\n",
+ "conditions_per_rule 2.689655\n",
+ "induced_conditions_per_rule 15.310345\n",
+ "avg_rule_coverage 0.491183\n",
+ "avg_rule_precision 0.736226\n",
+ "avg_rule_quality 1.309334\n",
+ "pvalue 0.019831\n",
+ "FDR_pvalue 0.019993\n",
+ "FWER_pvalue 0.024284\n",
+ "fraction_significant 0.931034\n",
+ "fraction_FDR_significant 0.931034\n",
+ "fraction_FWER_significant 0.931034\n",
+ "dtype: float64"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(ruleset_stats.mean())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Validate model on test dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Accuracy 0.808511\n",
+ "MAE 0.191489\n",
+ "Kappa 0.170010\n",
+ "Balanced accuracy 0.679398\n",
+ "Logistic loss 6.901976\n",
+ "Precision 6.901976\n",
+ "Sensitivity 0.533333\n",
+ "Specificity 0.825462\n",
+ "NPV 0.966346\n",
+ "PPV 0.158416\n",
+ "psep 0.124762\n",
+ "Fall-out 0.174538\n",
+ "Youden's J statistic 0.358795\n",
+ "Lift 2.730033\n",
+ "F-measure 0.244275\n",
+ "Fowlkes-Mallows index 0.809997\n",
+ "False positive 85.000000\n",
+ "False negative 14.000000\n",
+ "True positive 16.000000\n",
+ "True negative 402.000000\n",
+ "Rules per example 14.034816\n",
+ "Voting conflicts 360.000000\n",
+ "Geometric mean 0.663511\n",
+ "dtype: float64"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 402 \n",
+ " 85 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 14 \n",
+ " 16 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " 0 1\n",
+ "0 402 85\n",
+ "1 14 16"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "prediction, classification_metrics = clf.predict(X_test, return_metrics=True)\n",
+ "prediction_metrics, confusion_matrix = get_prediction_metrics('Best', prediction, y_test, classification_metrics)\n",
+ "\n",
+ "display(prediction_metrics.mean())\n",
+ "display(pd.DataFrame(confusion_matrix))"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "tutorials_env",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/docs/serve/v2.1.24.0/rst/tutorials/expert_rules.html b/docs/serve/v2.1.24.0/rst/tutorials/expert_rules.html
new file mode 100644
index 0000000..4eb8b12
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/tutorials/expert_rules.html
@@ -0,0 +1,661 @@
+
+
+
+
+
+
+ Expert Rules — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rulekit v2.1.24.0
+
+
+
+
+
+
+
+
+
+Expert Rules
+
+
This notebook presents example usage of user-guided rule induction which follows the scheme introduced by the
GuideR algorithm (Sikora et al, 2019).
+
Each problem (classification, regression, survival) in addition to the basic class has an expert class, i.e. RuleClassifier and ExpertRuleClassifier. Expert classes allow you to define set of initial rules, preferred conditions and forbidden conditions.
+
This tutorial will show you how to define rules and conditions
+
+
+Classification
+
+
+Define expert knowledge
+
+
+
+Rule induction
+
+
+
+
+
+
+
+IF [[gimpuls = <-inf, 750)]] AND [seismic = {a}] AND nbumps = (-inf, 1.50) AND nbumps4 = (-inf, 0.50) THEN class = {0}
+IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1252.50) THEN class = {0}
+IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1342.50) AND goimpuls = (-inf, 312) THEN class = {0}
+IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1427.50) THEN class = {0}
+IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1653.50) AND genergy = (-inf, 1006585) AND goimpuls = (-inf, 312) THEN class = {0}
+IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1752) THEN class = {0}
+IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 2733) AND goimpuls = (-inf, 312) THEN class = {0}
+IF nbumps = (-inf, 1.50) AND genergy = <634250, inf) AND gimpuls = <2965, inf) THEN class = {0}
+IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 1331) THEN class = {0}
+IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 1655.50) AND genergy = (-inf, 386010) THEN class = {0}
+IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 1686) AND nbumps2 = (-inf, 1.50) AND goimpuls = (-inf, 312) AND nbumps5 = (-inf, 0.50) THEN class = {0}
+IF nbumps = (-inf, 2.50) AND genergy = (-inf, 386010) AND gimpuls = (-inf, 2892) AND goimpuls = (-inf, 312) THEN class = {0}
+IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 2068.50) AND goimpuls = (-inf, 312) AND nbumps2 = (-inf, 1.50) AND genergy = (-inf, 1004565) THEN class = {0}
+IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 2184.50) THEN class = {0}
+IF gimpuls = (-inf, 1253.50) AND nbumps3 = (-inf, 1.50) AND nbumps2 = (-inf, 2.50) THEN class = {0}
+IF nbumps = (-inf, 3.50) AND goimpuls = (-inf, 96.50) AND gimpuls = (-inf, 901) AND senergy = (-inf, 3850) THEN class = {0}
+IF gimpuls = (-inf, 1253.50) AND nbumps3 = (-inf, 1.50) THEN class = {0}
+IF gimpuls = (-inf, 1253.50) AND nbumps2 = (-inf, 1.50) AND senergy = (-inf, 9600) AND nbumps3 = (-inf, 2.50) AND goimpuls = (-inf, 312) THEN class = {0}
+IF gimpuls = (-inf, 1253.50) AND nbumps2 = (-inf, 1.50) AND nbumps3 = (-inf, 2.50) THEN class = {0}
+IF gimpuls = (-inf, 1253.50) AND senergy = (-inf, 8100) AND nbumps2 = (-inf, 2.50) AND goimpuls = (-inf, 312) THEN class = {0}
+IF maxenergy = (-inf, 5500) AND gimpuls = (-inf, 901) AND goenergy = <-40.50, 68.50) AND ghazard = {a} AND goimpuls = <-39.50, inf) AND senergy = <1150, inf) AND nbumps2 = <1.50, inf) THEN class = {0}
+IF nbumps2 = (-inf, 1.50) AND nbumps3 = (-inf, 3.50) AND nbumps = (-inf, 6.50) AND gimpuls = (-inf, 695.50) AND goimpuls = <-54.50, inf) AND goenergy = <-48.50, inf) AND genergy = <10915, inf) AND maxenergy = <2500, inf) AND senergy = <3950, inf) THEN class = {0}
+IF gimpuls = (-inf, 1253.50) AND nbumps = (-inf, 4.50) AND nbumps2 = (-inf, 2.50) THEN class = {0}
+IF gimpuls = (-inf, 1253.50) AND nbumps3 = (-inf, 2.50) AND nbumps = (-inf, 5.50) THEN class = {0}
+IF nbumps3 = (-inf, 3.50) AND nbumps4 = (-inf, 2.50) AND maxenergy = (-inf, 75000) AND genergy = (-inf, 378500) AND gimpuls = (-inf, 901) THEN class = {0}
+IF senergy = (-inf, 85450) AND goimpuls = (-inf, 312) AND gimpuls = (-inf, 1139.50) THEN class = {0}
+IF nbumps2 = (-inf, 0.50) AND nbumps3 = (-inf, 2.50) AND goimpuls = <-35.50, inf) AND nbumps = <1.50, inf) AND gimpuls = <1150.50, inf) THEN class = {0}
+IF senergy = (-inf, 5750) AND genergy = (-inf, 508210) AND goenergy = <-18.50, inf) AND nbumps2 = <1.50, inf) AND gimpuls = <927, inf) THEN class = {0}
+IF senergy = (-inf, 5750) THEN class = {0}
+IF nbumps3 = (-inf, 2.50) AND nbumps2 = (-inf, 2.50) AND gimpuls = (-inf, 2489.50) AND genergy = (-inf, 318735) THEN class = {0}
+IF nbumps2 = (-inf, 1.50) AND goenergy = <-36.50, inf) AND goimpuls = (-inf, 6.50) AND genergy = <392530, inf) AND senergy = <6750, inf) THEN class = {0}
+IF nbumps = (-inf, 4.50) AND nbumps2 = (-inf, 2.50) AND gimpuls = (-inf, 3881.50) THEN class = {0}
+IF [[gimpuls = <750, inf)]] AND nbumps2 = <0.50, inf) AND genergy = <61250, 662435) AND maxenergy = <1500, inf) AND nbumps = (-inf, 7.50) AND nbumps3 = <0.50, inf) AND seismoacoustic = {a} AND goenergy = (-inf, 11) AND senergy = (-inf, 31200) THEN class = {1}
+IF [gimpuls = <1253.50, inf)] AND genergy = <96260, 673155) AND seismic = {b} AND maxenergy = (-inf, 7500) AND goenergy = <-40.50, 87) AND seismoacoustic = {a} AND nbumps = (-inf, 3.50) AND senergy = (-inf, 10000) THEN class = {1}
+IF nbumps2 = <0.50, inf) AND maxenergy = <1500, inf) AND gimpuls = <538.50, 1959) AND nbumps = (-inf, 6.50) AND senergy = (-inf, 36050) AND genergy = <61250, 662435) AND goenergy = (-inf, 96) AND nbumps3 = <0.50, 4.50) AND goimpuls = <-34, 95) THEN class = {1}
+IF nbumps2 = <0.50, inf) AND genergy = <58310, 934630) AND goenergy = (-inf, 186) AND senergy = (-inf, 40650) AND maxenergy = <1500, inf) AND gimpuls = <538.50, inf) AND goimpuls = <-55, inf) THEN class = {1}
+IF nbumps = <1.50, 4.50) AND nbumps2 = <0.50, 3.50) AND gimpuls = <521.50, inf) AND genergy = <58310, 799855) AND nbumps4 = (-inf, 1.50) AND senergy = <850, inf) AND goimpuls = <-39, 64.50) AND nbumps3 = (-inf, 2.50) THEN class = {1}
+IF nbumps = <1.50, inf) AND nbumps2 = <0.50, 4.50) AND gimpuls = <521.50, inf) AND genergy = <34360, 1161025) AND goenergy = (-inf, 186) AND nbumps3 = (-inf, 6) AND maxenergy = <450, 45000) THEN class = {1}
+IF nbumps = <1.50, inf) AND nbumps2 = <0.50, inf) AND genergy = <34880, inf) AND gimpuls = <281.50, inf) AND goenergy = (-inf, 135.50) THEN class = {1}
+IF nbumps = <1.50, inf) AND nbumps2 = <0.50, inf) AND gimpuls = <153.50, 498) AND genergy = <18870, 33010) AND senergy = (-inf, 40500) AND goenergy = (-inf, 106.50) AND nbumps3 = (-inf, 1.50) THEN class = {1}
+IF nbumps = <1.50, inf) AND goenergy = (-inf, 131) AND gimpuls = <176, inf) THEN class = {1}
+IF gimpuls = <1253.50, inf) AND goenergy = (-inf, 131.50) AND genergy = <54930, 1062020) AND shift = {W} AND goimpuls = <-60.50, 109) AND senergy = (-inf, 36050) AND nbumps2 = (-inf, 2.50) THEN class = {1}
+IF nbumps2 = <0.50, inf) AND gimpuls = <98.50, inf) AND goimpuls = <-70.50, inf) AND maxenergy = <550, inf) THEN class = {1}
+IF goimpuls = <-74.50, inf) AND gimpuls = <32.50, inf) AND goenergy = <-78.50, inf) AND senergy = <850, inf) THEN class = {1}
+IF genergy = <48545, inf) AND gimpuls = <131, inf) AND goenergy = (-inf, 176.50) THEN class = {1}
+IF shift = {W} AND genergy = <32795, 49585) AND gimpuls = <396, 1445.50) AND goimpuls = <-19, inf) AND senergy = (-inf, 350) AND goenergy = <-4, inf) THEN class = {1}
+IF genergy = <16805, 32020) AND gimpuls = <537.50, 796) AND goimpuls = <-36.50, inf) AND goenergy = <-37.50, inf) AND senergy = (-inf, 250) THEN class = {1}
+IF shift = {W} AND genergy = <19670, 40735) AND gimpuls = <240, 470.50) AND goenergy = <-37.50, 181) AND goimpuls = <-42.50, inf) THEN class = {1}
+IF gimpuls = <54.50, inf) AND senergy = (-inf, 115450) AND goimpuls = <-74.50, inf) AND genergy = <1510, inf) THEN class = {1}
+
+
+
+
+
+Regression
+
+Load dataset
+
+
+
+
+
+
+
+
+
+
+
+ MM31
+ MM116
+ AS038
+ PG072
+ PD
+ BA13
+ DMM116
+
+
+
+
+ 0
+ 0.46
+ 1.3
+ 2.4
+ 2.0
+ 1.0
+ 1076.0
+ 0.0
+
+
+ 1
+ 0.46
+ 1.3
+ 2.2
+ 1.9
+ 1.0
+ 1076.0
+ 0.0
+
+
+ 2
+ 0.49
+ 1.3
+ 2.2
+ 1.9
+ 1.0
+ 1076.0
+ 0.0
+
+
+ 3
+ 0.50
+ 1.3
+ 2.3
+ 1.9
+ 1.0
+ 1076.0
+ 0.0
+
+
+ 4
+ 0.54
+ 1.3
+ 2.3
+ 1.9
+ 1.0
+ 1076.0
+ 0.0
+
+
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+
+
+ 13363
+ 0.64
+ 1.2
+ 2.4
+ 1.8
+ 1.0
+ 1077.0
+ 0.0
+
+
+ 13364
+ 0.59
+ 1.2
+ 2.4
+ 1.8
+ 1.0
+ 1077.0
+ 0.0
+
+
+ 13365
+ 0.60
+ 1.1
+ 2.2
+ 1.8
+ 1.0
+ 1077.0
+ -0.1
+
+
+ 13366
+ 0.64
+ 1.1
+ 2.2
+ 1.8
+ 1.0
+ 1077.0
+ 0.0
+
+
+ 13367
+ 0.65
+ 1.2
+ 2.2
+ 1.7
+ 0.0
+ 1077.0
+ 0.1
+
+
+
+
13368 rows × 7 columns
+
+
+
+
+Define rules and conditions
+
+
+
+Rule induction
+
+
+
+
+
+
+
+IF [PD = <0.50, inf)] AND PG072 = (-inf, 2.05) THEN MM116_pred = {1.01} [0.77,1.25]
+IF [PD = <0.50, inf)] THEN MM116_pred = {1.01} [0.77,1.25]
+IF MM31 = (-inf, 0.23) THEN MM116_pred = {0.40} [0.39,0.41]
+IF MM116 = (-inf, 0.45) AND MM31 = <0.18, 0.24) THEN MM116_pred = {0.40} [0.38,0.42]
+IF MM31 = (-inf, 0.25) THEN MM116_pred = {0.44} [0.37,0.51]
+IF MM116 = <0.25, inf) AND AS038 = <2, 2.45) AND PD = (-inf, 0.50) AND PG072 = (-inf, 1.95) AND BA13 = (-inf, 1075.50) AND MM31 = <0.23, inf) THEN MM116_pred = {0.71} [0.50,0.93]
+IF MM116 = (-inf, 0.25) AND BA13 = (-inf, 1075.50) AND MM31 = <0.19, inf) AND AS038 = <2.35, 2.45) AND PG072 = <1.75, 1.95) AND PD = (-inf, 0.50) THEN MM116_pred = {0.25} [0.20,0.30]
+IF MM116 = (-inf, 0.45) AND BA13 = (-inf, 1077.50) AND MM31 = <0.18, inf) THEN MM116_pred = {0.40} [0.37,0.43]
+IF MM116 = (-inf, 0.55) AND MM31 = (-inf, 0.32) THEN MM116_pred = {0.45} [0.39,0.51]
+IF MM116 = <0.45, 0.65) THEN MM116_pred = {0.55} [0.49,0.61]
+IF MM31 = <0.18, 0.27) AND MM116 = (-inf, 0.75) THEN MM116_pred = {0.46} [0.39,0.53]
+IF MM116 = <0.45, 0.85) AND MM31 = <0.25, inf) THEN MM116_pred = {0.70} [0.56,0.84]
+IF MM116 = <0.75, inf) THEN MM116_pred = {1.01} [0.82,1.19]
+
+
+
+
+
+Survival
+
+
+Define rules and conditions
+
+
+
+Rule induction
+
+
+
+
+
+
+
+IF [[CD34kgx10d6 = (-inf, 10)]] AND [[extcGvHD = {0}]] THEN
+IF [CD34kgx10d6 = (-inf, 11.86)] AND PLTrecovery = <500142.50, inf) THEN
+IF [CD34kgx10d6 = (-inf, 11.86)] AND Recipientage = <17.85, inf) AND RecipientRh = {1} THEN
+IF [CD34kgx10d6 = (-inf, 11.86)] AND PLTrecovery = <26, inf) AND Recipientage = <14.30, inf) AND Relapse = {0} THEN
+IF [CD34kgx10d6 = (-inf, 11.86)] AND PLTrecovery = <26, inf) AND Recipientage = <12, 18.85) AND Gendermatch = {0} AND Donorage = (-inf, 40.64) THEN
+IF [CD34kgx10d6 = (-inf, 11.86)] AND CD3dCD34 = (-inf, 10.97) AND Donorage = (-inf, 49.19) AND PLTrecovery = (-inf, 500142.50) AND Txpostrelapse = {0} AND extcGvHD = {1} THEN
+IF [CD34kgx10d6 = <11.86, inf)] AND Relapse = {0} THEN
+IF [CD34kgx10d6 = (-inf, 11.86)] AND RecipientRh = {1} AND CD3dCD34 = <6.64, inf) THEN
+IF [CD34kgx10d6 = (-inf, 11.86)] AND Recipientageint = {2} AND CD3dCD34 = <0.94, inf) AND Donorage = <36.03, inf) THEN
+IF [CD34kgx10d6 = (-inf, 11.86)] AND PLTrecovery = <22.50, inf) THEN
+IF [CD34kgx10d6 = <11.86, inf)] THEN
+IF [CD34kgx10d6 = (-inf, 11.86)] AND CD3dCD34 = <0.89, inf) AND Rbodymass = <36.50, inf) AND Recipientage = <9.20, inf) AND IIIV = {1} AND PLTrecovery = (-inf, 22.50) AND Stemcellsource = {1} THEN
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/rst/tutorials/expert_rules.ipynb b/docs/serve/v2.1.24.0/rst/tutorials/expert_rules.ipynb
new file mode 100644
index 0000000..efe64fb
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/tutorials/expert_rules.ipynb
@@ -0,0 +1,630 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Expert Rules"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This notebook presents example usage of user-guided rule induction which follows the scheme introduced by the [GuideR](https://www.sciencedirect.com/science/article/abs/pii/S0950705119300802?dgcid=coauthor) algorithm (Sikora et al, 2019). \n",
+ "Each problem (classification, regression, survival) in addition to the basic class has an expert class, i.e. RuleClassifier and ExpertRuleClassifier. Expert classes allow you to define set of initial rules, preferred conditions and forbidden conditions. \n",
+ "This tutorial will show you how to define rules and conditions\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Classification"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Load dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "from rulekit.arff import read_arff\n",
+ "\n",
+ "CLASSIFICATION_DATASET_URL: str = (\n",
+ " 'https://raw.githubusercontent.com/'\n",
+ " 'adaa-polsl/RuleKit/refs/heads/master/data/seismic-bumps/'\n",
+ " 'seismic-bumps.arff'\n",
+ ")\n",
+ "\n",
+ "df: pd.DataFrame = read_arff(CLASSIFICATION_DATASET_URL)\n",
+ "X, y = df.drop(['class'], axis=1), df['class']"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Define expert knowledge"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "expert_rules: list[tuple[str, str]] = [\n",
+ " ('rule-0', 'IF [[gimpuls = <-inf, 750)]] THEN class = {0}'),\n",
+ " ('rule-1', 'IF [[gimpuls = <750, inf)]] THEN class = {1}')\n",
+ "]\n",
+ "\n",
+ "expert_preferred_conditions: list[tuple[str, str]] = [\n",
+ " ('preferred-condition-0', '1: IF [[seismic = {a}]] THEN class = {0}'),\n",
+ " ('preferred-attribute-0', '1: IF [[gimpuls = Any]] THEN class = {1}')\n",
+ "]\n",
+ "\n",
+ "expert_forbidden_conditions: list[tuple[str, str]] = [\n",
+ " ('forb-attribute-0', '1: IF [[seismoacoustic = Any]] THEN class = {0}'),\n",
+ " ('forb-attribute-1', 'inf: IF [[ghazard = Any]] THEN class = {1}')\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Rule induction"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from rulekit.classification import ExpertRuleClassifier\n",
+ "from rulekit.rules import RuleSet, ClassificationRule\n",
+ "\n",
+ "clf = ExpertRuleClassifier(\n",
+ " minsupp_new=8,\n",
+ " max_growing=0,\n",
+ " extend_using_preferred=True,\n",
+ " extend_using_automatic=True,\n",
+ " induce_using_preferred=True,\n",
+ " induce_using_automatic=True\n",
+ ")\n",
+ "clf.fit(\n",
+ " X, y,\n",
+ " expert_rules=expert_rules,\n",
+ " expert_preferred_conditions=expert_preferred_conditions,\n",
+ " expert_forbidden_conditions=expert_forbidden_conditions\n",
+ ")\n",
+ "ruleset: RuleSet[ClassificationRule] = clf.model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF [[gimpuls = <-inf, 750)]] AND [seismic = {a}] AND nbumps = (-inf, 1.50) AND nbumps4 = (-inf, 0.50) THEN class = {0}\n",
+ "IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1252.50) THEN class = {0}\n",
+ "IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1342.50) AND goimpuls = (-inf, 312) THEN class = {0}\n",
+ "IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1427.50) THEN class = {0}\n",
+ "IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1653.50) AND genergy = (-inf, 1006585) AND goimpuls = (-inf, 312) THEN class = {0}\n",
+ "IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 1752) THEN class = {0}\n",
+ "IF nbumps = (-inf, 1.50) AND gimpuls = (-inf, 2733) AND goimpuls = (-inf, 312) THEN class = {0}\n",
+ "IF nbumps = (-inf, 1.50) AND genergy = <634250, inf) AND gimpuls = <2965, inf) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 1331) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 1655.50) AND genergy = (-inf, 386010) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 1686) AND nbumps2 = (-inf, 1.50) AND goimpuls = (-inf, 312) AND nbumps5 = (-inf, 0.50) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) AND genergy = (-inf, 386010) AND gimpuls = (-inf, 2892) AND goimpuls = (-inf, 312) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 2068.50) AND goimpuls = (-inf, 312) AND nbumps2 = (-inf, 1.50) AND genergy = (-inf, 1004565) THEN class = {0}\n",
+ "IF nbumps = (-inf, 2.50) AND gimpuls = (-inf, 2184.50) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 1253.50) AND nbumps3 = (-inf, 1.50) AND nbumps2 = (-inf, 2.50) THEN class = {0}\n",
+ "IF nbumps = (-inf, 3.50) AND goimpuls = (-inf, 96.50) AND gimpuls = (-inf, 901) AND senergy = (-inf, 3850) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 1253.50) AND nbumps3 = (-inf, 1.50) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 1253.50) AND nbumps2 = (-inf, 1.50) AND senergy = (-inf, 9600) AND nbumps3 = (-inf, 2.50) AND goimpuls = (-inf, 312) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 1253.50) AND nbumps2 = (-inf, 1.50) AND nbumps3 = (-inf, 2.50) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 1253.50) AND senergy = (-inf, 8100) AND nbumps2 = (-inf, 2.50) AND goimpuls = (-inf, 312) THEN class = {0}\n",
+ "IF maxenergy = (-inf, 5500) AND gimpuls = (-inf, 901) AND goenergy = <-40.50, 68.50) AND ghazard = {a} AND goimpuls = <-39.50, inf) AND senergy = <1150, inf) AND nbumps2 = <1.50, inf) THEN class = {0}\n",
+ "IF nbumps2 = (-inf, 1.50) AND nbumps3 = (-inf, 3.50) AND nbumps = (-inf, 6.50) AND gimpuls = (-inf, 695.50) AND goimpuls = <-54.50, inf) AND goenergy = <-48.50, inf) AND genergy = <10915, inf) AND maxenergy = <2500, inf) AND senergy = <3950, inf) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 1253.50) AND nbumps = (-inf, 4.50) AND nbumps2 = (-inf, 2.50) THEN class = {0}\n",
+ "IF gimpuls = (-inf, 1253.50) AND nbumps3 = (-inf, 2.50) AND nbumps = (-inf, 5.50) THEN class = {0}\n",
+ "IF nbumps3 = (-inf, 3.50) AND nbumps4 = (-inf, 2.50) AND maxenergy = (-inf, 75000) AND genergy = (-inf, 378500) AND gimpuls = (-inf, 901) THEN class = {0}\n",
+ "IF senergy = (-inf, 85450) AND goimpuls = (-inf, 312) AND gimpuls = (-inf, 1139.50) THEN class = {0}\n",
+ "IF nbumps2 = (-inf, 0.50) AND nbumps3 = (-inf, 2.50) AND goimpuls = <-35.50, inf) AND nbumps = <1.50, inf) AND gimpuls = <1150.50, inf) THEN class = {0}\n",
+ "IF senergy = (-inf, 5750) AND genergy = (-inf, 508210) AND goenergy = <-18.50, inf) AND nbumps2 = <1.50, inf) AND gimpuls = <927, inf) THEN class = {0}\n",
+ "IF senergy = (-inf, 5750) THEN class = {0}\n",
+ "IF nbumps3 = (-inf, 2.50) AND nbumps2 = (-inf, 2.50) AND gimpuls = (-inf, 2489.50) AND genergy = (-inf, 318735) THEN class = {0}\n",
+ "IF nbumps2 = (-inf, 1.50) AND goenergy = <-36.50, inf) AND goimpuls = (-inf, 6.50) AND genergy = <392530, inf) AND senergy = <6750, inf) THEN class = {0}\n",
+ "IF nbumps = (-inf, 4.50) AND nbumps2 = (-inf, 2.50) AND gimpuls = (-inf, 3881.50) THEN class = {0}\n",
+ "IF [[gimpuls = <750, inf)]] AND nbumps2 = <0.50, inf) AND genergy = <61250, 662435) AND maxenergy = <1500, inf) AND nbumps = (-inf, 7.50) AND nbumps3 = <0.50, inf) AND seismoacoustic = {a} AND goenergy = (-inf, 11) AND senergy = (-inf, 31200) THEN class = {1}\n",
+ "IF [gimpuls = <1253.50, inf)] AND genergy = <96260, 673155) AND seismic = {b} AND maxenergy = (-inf, 7500) AND goenergy = <-40.50, 87) AND seismoacoustic = {a} AND nbumps = (-inf, 3.50) AND senergy = (-inf, 10000) THEN class = {1}\n",
+ "IF nbumps2 = <0.50, inf) AND maxenergy = <1500, inf) AND gimpuls = <538.50, 1959) AND nbumps = (-inf, 6.50) AND senergy = (-inf, 36050) AND genergy = <61250, 662435) AND goenergy = (-inf, 96) AND nbumps3 = <0.50, 4.50) AND goimpuls = <-34, 95) THEN class = {1}\n",
+ "IF nbumps2 = <0.50, inf) AND genergy = <58310, 934630) AND goenergy = (-inf, 186) AND senergy = (-inf, 40650) AND maxenergy = <1500, inf) AND gimpuls = <538.50, inf) AND goimpuls = <-55, inf) THEN class = {1}\n",
+ "IF nbumps = <1.50, 4.50) AND nbumps2 = <0.50, 3.50) AND gimpuls = <521.50, inf) AND genergy = <58310, 799855) AND nbumps4 = (-inf, 1.50) AND senergy = <850, inf) AND goimpuls = <-39, 64.50) AND nbumps3 = (-inf, 2.50) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) AND nbumps2 = <0.50, 4.50) AND gimpuls = <521.50, inf) AND genergy = <34360, 1161025) AND goenergy = (-inf, 186) AND nbumps3 = (-inf, 6) AND maxenergy = <450, 45000) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) AND nbumps2 = <0.50, inf) AND genergy = <34880, inf) AND gimpuls = <281.50, inf) AND goenergy = (-inf, 135.50) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) AND nbumps2 = <0.50, inf) AND gimpuls = <153.50, 498) AND genergy = <18870, 33010) AND senergy = (-inf, 40500) AND goenergy = (-inf, 106.50) AND nbumps3 = (-inf, 1.50) THEN class = {1}\n",
+ "IF nbumps = <1.50, inf) AND goenergy = (-inf, 131) AND gimpuls = <176, inf) THEN class = {1}\n",
+ "IF gimpuls = <1253.50, inf) AND goenergy = (-inf, 131.50) AND genergy = <54930, 1062020) AND shift = {W} AND goimpuls = <-60.50, 109) AND senergy = (-inf, 36050) AND nbumps2 = (-inf, 2.50) THEN class = {1}\n",
+ "IF nbumps2 = <0.50, inf) AND gimpuls = <98.50, inf) AND goimpuls = <-70.50, inf) AND maxenergy = <550, inf) THEN class = {1}\n",
+ "IF goimpuls = <-74.50, inf) AND gimpuls = <32.50, inf) AND goenergy = <-78.50, inf) AND senergy = <850, inf) THEN class = {1}\n",
+ "IF genergy = <48545, inf) AND gimpuls = <131, inf) AND goenergy = (-inf, 176.50) THEN class = {1}\n",
+ "IF shift = {W} AND genergy = <32795, 49585) AND gimpuls = <396, 1445.50) AND goimpuls = <-19, inf) AND senergy = (-inf, 350) AND goenergy = <-4, inf) THEN class = {1}\n",
+ "IF genergy = <16805, 32020) AND gimpuls = <537.50, 796) AND goimpuls = <-36.50, inf) AND goenergy = <-37.50, inf) AND senergy = (-inf, 250) THEN class = {1}\n",
+ "IF shift = {W} AND genergy = <19670, 40735) AND gimpuls = <240, 470.50) AND goenergy = <-37.50, 181) AND goimpuls = <-42.50, inf) THEN class = {1}\n",
+ "IF gimpuls = <54.50, inf) AND senergy = (-inf, 115450) AND goimpuls = <-74.50, inf) AND genergy = <1510, inf) THEN class = {1}\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Regression"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Load dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "REGRESSION_DATSET_URL: str = (\n",
+ " 'https://raw.githubusercontent.com/'\n",
+ " 'adaa-polsl/RuleKit/master/data/methane/'\n",
+ " 'methane-train.arff'\n",
+ ")\n",
+ "df: pd.DataFrame = read_arff(REGRESSION_DATSET_URL)\n",
+ "X, y = df.drop(['MM116_pred'], axis=1), df['MM116_pred']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " MM31 \n",
+ " MM116 \n",
+ " AS038 \n",
+ " PG072 \n",
+ " PD \n",
+ " BA13 \n",
+ " DMM116 \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 0.46 \n",
+ " 1.3 \n",
+ " 2.4 \n",
+ " 2.0 \n",
+ " 1.0 \n",
+ " 1076.0 \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 0.46 \n",
+ " 1.3 \n",
+ " 2.2 \n",
+ " 1.9 \n",
+ " 1.0 \n",
+ " 1076.0 \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " 0.49 \n",
+ " 1.3 \n",
+ " 2.2 \n",
+ " 1.9 \n",
+ " 1.0 \n",
+ " 1076.0 \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " 0.50 \n",
+ " 1.3 \n",
+ " 2.3 \n",
+ " 1.9 \n",
+ " 1.0 \n",
+ " 1076.0 \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " 0.54 \n",
+ " 1.3 \n",
+ " 2.3 \n",
+ " 1.9 \n",
+ " 1.0 \n",
+ " 1076.0 \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 13363 \n",
+ " 0.64 \n",
+ " 1.2 \n",
+ " 2.4 \n",
+ " 1.8 \n",
+ " 1.0 \n",
+ " 1077.0 \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ " 13364 \n",
+ " 0.59 \n",
+ " 1.2 \n",
+ " 2.4 \n",
+ " 1.8 \n",
+ " 1.0 \n",
+ " 1077.0 \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ " 13365 \n",
+ " 0.60 \n",
+ " 1.1 \n",
+ " 2.2 \n",
+ " 1.8 \n",
+ " 1.0 \n",
+ " 1077.0 \n",
+ " -0.1 \n",
+ " \n",
+ " \n",
+ " 13366 \n",
+ " 0.64 \n",
+ " 1.1 \n",
+ " 2.2 \n",
+ " 1.8 \n",
+ " 1.0 \n",
+ " 1077.0 \n",
+ " 0.0 \n",
+ " \n",
+ " \n",
+ " 13367 \n",
+ " 0.65 \n",
+ " 1.2 \n",
+ " 2.2 \n",
+ " 1.7 \n",
+ " 0.0 \n",
+ " 1077.0 \n",
+ " 0.1 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
13368 rows × 7 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " MM31 MM116 AS038 PG072 PD BA13 DMM116\n",
+ "0 0.46 1.3 2.4 2.0 1.0 1076.0 0.0\n",
+ "1 0.46 1.3 2.2 1.9 1.0 1076.0 0.0\n",
+ "2 0.49 1.3 2.2 1.9 1.0 1076.0 0.0\n",
+ "3 0.50 1.3 2.3 1.9 1.0 1076.0 0.0\n",
+ "4 0.54 1.3 2.3 1.9 1.0 1076.0 0.0\n",
+ "... ... ... ... ... ... ... ...\n",
+ "13363 0.64 1.2 2.4 1.8 1.0 1077.0 0.0\n",
+ "13364 0.59 1.2 2.4 1.8 1.0 1077.0 0.0\n",
+ "13365 0.60 1.1 2.2 1.8 1.0 1077.0 -0.1\n",
+ "13366 0.64 1.1 2.2 1.8 1.0 1077.0 0.0\n",
+ "13367 0.65 1.2 2.2 1.7 0.0 1077.0 0.1\n",
+ "\n",
+ "[13368 rows x 7 columns]"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "X"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Define rules and conditions"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "expert_preferred_conditions = [\n",
+ " (\n",
+ " 'preferred-condition-0',\n",
+ " '3: IF PD = <0.5, inf) THEN'\n",
+ " ),\n",
+ " (\n",
+ " 'preferred-condition-1',\n",
+ " '5: IF PD = <0.5, inf) AND MM116 = (-inf, 1.0) THEN'\n",
+ " )\n",
+ "]\n",
+ "\n",
+ "expert_forbidden_conditions = [\n",
+ " ('forb-attribute-0', 'inf: IF DMM116 = Any THEN')\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Rule induction"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from rulekit.regression import ExpertRuleRegressor\n",
+ "from rulekit.rules import RegressionRule\n",
+ "from rulekit.exceptions import RuleKitJavaException\n",
+ "\n",
+ "reg = ExpertRuleRegressor(\n",
+ " minsupp_new=5,\n",
+ " max_growing=0,\n",
+ " mean_based_regression=True,\n",
+ " extend_using_preferred=True,\n",
+ " extend_using_automatic=False,\n",
+ " induce_using_preferred=True,\n",
+ " induce_using_automatic=True\n",
+ ")\n",
+ "reg.fit(\n",
+ " X, y,\n",
+ " expert_preferred_conditions=expert_preferred_conditions,\n",
+ " expert_forbidden_conditions=expert_forbidden_conditions,\n",
+ ")\n",
+ "\n",
+ "ruleset: RuleSet[RegressionRule] = reg.model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF [PD = <0.50, inf)] AND PG072 = (-inf, 2.05) THEN MM116_pred = {1.01} [0.77,1.25]\n",
+ "IF [PD = <0.50, inf)] THEN MM116_pred = {1.01} [0.77,1.25]\n",
+ "IF MM31 = (-inf, 0.23) THEN MM116_pred = {0.40} [0.39,0.41]\n",
+ "IF MM116 = (-inf, 0.45) AND MM31 = <0.18, 0.24) THEN MM116_pred = {0.40} [0.38,0.42]\n",
+ "IF MM31 = (-inf, 0.25) THEN MM116_pred = {0.44} [0.37,0.51]\n",
+ "IF MM116 = <0.25, inf) AND AS038 = <2, 2.45) AND PD = (-inf, 0.50) AND PG072 = (-inf, 1.95) AND BA13 = (-inf, 1075.50) AND MM31 = <0.23, inf) THEN MM116_pred = {0.71} [0.50,0.93]\n",
+ "IF MM116 = (-inf, 0.25) AND BA13 = (-inf, 1075.50) AND MM31 = <0.19, inf) AND AS038 = <2.35, 2.45) AND PG072 = <1.75, 1.95) AND PD = (-inf, 0.50) THEN MM116_pred = {0.25} [0.20,0.30]\n",
+ "IF MM116 = (-inf, 0.45) AND BA13 = (-inf, 1077.50) AND MM31 = <0.18, inf) THEN MM116_pred = {0.40} [0.37,0.43]\n",
+ "IF MM116 = (-inf, 0.55) AND MM31 = (-inf, 0.32) THEN MM116_pred = {0.45} [0.39,0.51]\n",
+ "IF MM116 = <0.45, 0.65) THEN MM116_pred = {0.55} [0.49,0.61]\n",
+ "IF MM31 = <0.18, 0.27) AND MM116 = (-inf, 0.75) THEN MM116_pred = {0.46} [0.39,0.53]\n",
+ "IF MM116 = <0.45, 0.85) AND MM31 = <0.25, inf) THEN MM116_pred = {0.70} [0.56,0.84]\n",
+ "IF MM116 = <0.75, inf) THEN MM116_pred = {1.01} [0.82,1.19]\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Survival"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Load dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "SURVIVAL_DATASET_URL: str = (\n",
+ " 'https://raw.githubusercontent.com/'\n",
+ " 'adaa-polsl/RuleKit/master/data/bmt/'\n",
+ " 'bmt.arff'\n",
+ ")\n",
+ "df: pd.DataFrame = read_arff(SURVIVAL_DATASET_URL)\n",
+ "df['survival_status'] = df['survival_status'].astype(int).astype(str)\n",
+ "\n",
+ "\n",
+ "X, y = df.drop(['survival_status'], axis=1), df['survival_status']"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Define rules and conditions"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "expert_rules = [\n",
+ " (\n",
+ " 'rule-0',\n",
+ " 'IF [[CD34kgx10d6 = (-inf, 10.0)]] AND [[extcGvHD = {0}]] THEN'\n",
+ " )\n",
+ "]\n",
+ "\n",
+ "expert_preferred_conditions = [\n",
+ " (\n",
+ " 'attr-preferred-0',\n",
+ " 'inf: IF [CD34kgx10d6 = Any] THEN'\n",
+ " )\n",
+ "]\n",
+ "\n",
+ "\n",
+ "expert_forbidden_conditions = [\n",
+ " ('attr-forbidden-0', 'IF [ANCrecovery = Any] THEN')\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Rule induction"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from rulekit.survival import ExpertSurvivalRules\n",
+ "from rulekit.rules import SurvivalRule\n",
+ "\n",
+ "srv = ExpertSurvivalRules(\n",
+ " survival_time_attr='survival_time',\n",
+ " minsupp_new=5,\n",
+ " max_growing=0,\n",
+ " extend_using_preferred=False,\n",
+ " extend_using_automatic=False,\n",
+ " induce_using_preferred=True,\n",
+ " induce_using_automatic=True\n",
+ ")\n",
+ "srv.fit(\n",
+ " X, y,\n",
+ " expert_rules=expert_rules,\n",
+ " expert_preferred_conditions=expert_preferred_conditions,\n",
+ " expert_forbidden_conditions=expert_forbidden_conditions\n",
+ ")\n",
+ "ruleset: RuleSet[SurvivalRule] = srv.model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF [[CD34kgx10d6 = (-inf, 10)]] AND [[extcGvHD = {0}]] THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND PLTrecovery = <500142.50, inf) THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND Recipientage = <17.85, inf) AND RecipientRh = {1} THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND PLTrecovery = <26, inf) AND Recipientage = <14.30, inf) AND Relapse = {0} THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND PLTrecovery = <26, inf) AND Recipientage = <12, 18.85) AND Gendermatch = {0} AND Donorage = (-inf, 40.64) THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND CD3dCD34 = (-inf, 10.97) AND Donorage = (-inf, 49.19) AND PLTrecovery = (-inf, 500142.50) AND Txpostrelapse = {0} AND extcGvHD = {1} THEN \n",
+ "IF [CD34kgx10d6 = <11.86, inf)] AND Relapse = {0} THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND RecipientRh = {1} AND CD3dCD34 = <6.64, inf) THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND Recipientageint = {2} AND CD3dCD34 = <0.94, inf) AND Donorage = <36.03, inf) THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND PLTrecovery = <22.50, inf) THEN \n",
+ "IF [CD34kgx10d6 = <11.86, inf)] THEN \n",
+ "IF [CD34kgx10d6 = (-inf, 11.86)] AND CD3dCD34 = <0.89, inf) AND Rbodymass = <36.50, inf) AND Recipientage = <9.20, inf) AND IIIV = {1} AND PLTrecovery = (-inf, 22.50) AND Stemcellsource = {1} THEN \n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in ruleset.rules:\n",
+ " print(rule)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "tutorials_env",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/docs/serve/v2.1.24.0/rst/tutorials/regression.html b/docs/serve/v2.1.24.0/rst/tutorials/regression.html
new file mode 100644
index 0000000..56f1f40
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/tutorials/regression.html
@@ -0,0 +1,1329 @@
+
+
+
+
+
+
+ Regression — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rulekit v2.1.24.0
+
+
+
+
+
+
+
+
+
+Regression
+This notebook presents example usage of package for solving regression problem on methane
dataset. You can download training dataset here and test dataset here
+
+
This tutorial will cover topics such as:
+
- training model
+
- changing model hyperparameters
+
- hyperparameters tuning
+
- calculating metrics for model
+
- getting RuleKit inbuilt
+
+
+Summary of the dataset
+
+
+Train file
+
+
+
+
+
+
+Train file overview:
+Name: methane-train
+Objects number: 13368; Attributes number: 8
+Basic attribute statistics:
+
+
+
+
+
+
+
+
+
+
+
+ MM31
+ MM116
+ AS038
+ PG072
+ PD
+ BA13
+ DMM116
+ MM116_pred
+
+
+
+
+ count
+ 13368.000000
+ 13368.000000
+ 13368.000000
+ 13368.000000
+ 13368.000000
+ 13368.000000
+ 13368.000000
+ 13368.00000
+
+
+ mean
+ 0.363960
+ 0.775007
+ 2.294734
+ 1.835600
+ 0.308573
+ 1073.443372
+ -0.000007
+ 0.79825
+
+
+ std
+ 0.117105
+ 0.269366
+ 0.142504
+ 0.106681
+ 0.461922
+ 3.162811
+ 0.043566
+ 0.28649
+
+
+ min
+ 0.170000
+ 0.200000
+ 1.400000
+ 1.100000
+ 0.000000
+ 1067.000000
+ -1.800000
+ 0.20000
+
+
+ 25%
+ 0.260000
+ 0.500000
+ 2.300000
+ 1.800000
+ 0.000000
+ 1070.000000
+ 0.000000
+ 0.50000
+
+
+ 50%
+ 0.360000
+ 0.800000
+ 2.300000
+ 1.800000
+ 0.000000
+ 1075.000000
+ 0.000000
+ 0.80000
+
+
+ 75%
+ 0.450000
+ 1.000000
+ 2.400000
+ 1.900000
+ 1.000000
+ 1076.000000
+ 0.000000
+ 1.00000
+
+
+ max
+ 0.820000
+ 2.200000
+ 2.700000
+ 2.600000
+ 1.000000
+ 1078.000000
+ 0.800000
+ 2.20000
+
+
+
+
+
+
+
+Test file
+
+
+
+
+
+
+
+Test file overview:
+Name: methane-test
+Objects number: 5728; Attributes number: 8
+Basic attribute statistics:
+
+
+
+
+
+
+
+
+
+
+
+ MM31
+ MM116
+ AS038
+ PG072
+ PD
+ BA13
+ DMM116
+ MM116_pred
+
+
+
+
+ count
+ 5728.000000
+ 5728.000000
+ 5728.000000
+ 5728.000000
+ 5728.000000
+ 5728.000000
+ 5728.000000
+ 5728.000000
+
+
+ mean
+ 0.556652
+ 1.006913
+ 2.236627
+ 1.819239
+ 0.538408
+ 1072.691690
+ -0.000017
+ 1.042458
+
+
+ std
+ 0.114682
+ 0.167983
+ 0.104913
+ 0.078865
+ 0.498566
+ 2.799559
+ 0.046849
+ 0.171393
+
+
+ min
+ 0.350000
+ 0.500000
+ 1.800000
+ 1.600000
+ 0.000000
+ 1067.000000
+ -0.400000
+ 0.600000
+
+
+ 25%
+ 0.460000
+ 0.900000
+ 2.200000
+ 1.800000
+ 0.000000
+ 1071.000000
+ 0.000000
+ 0.900000
+
+
+ 50%
+ 0.550000
+ 1.000000
+ 2.200000
+ 1.800000
+ 1.000000
+ 1073.000000
+ 0.000000
+ 1.000000
+
+
+ 75%
+ 0.640000
+ 1.100000
+ 2.300000
+ 1.900000
+ 1.000000
+ 1075.000000
+ 0.000000
+ 1.200000
+
+
+ max
+ 0.980000
+ 1.600000
+ 2.700000
+ 2.100000
+ 1.000000
+ 1078.000000
+ 0.300000
+ 1.600000
+
+
+
+
+
+
+
+
+Helper function for calculating metrics
+
+
+
+Rule induction on training dataset
+
+
+
+
+
+
+
+c:\Users\cezar\OneDrive\Pulpit\EMAG\GIT\PythonRulekit\tutorials_env\Lib\site-packages\sklearn\metrics\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.
+ warnings.warn(
+c:\Users\cezar\OneDrive\Pulpit\EMAG\GIT\PythonRulekit\tutorials_env\Lib\site-packages\sklearn\metrics\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.
+ warnings.warn(
+c:\Users\cezar\OneDrive\Pulpit\EMAG\GIT\PythonRulekit\tutorials_env\Lib\site-packages\sklearn\metrics\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.
+ warnings.warn(
+
+
+
+
+
+
+
+
+
+
+
+
+ minimum_covered
+ maximum_uncovered_fraction
+ ignore_missing
+ pruning_enabled
+ max_growing_condition
+ time_total_s
+ time_growing_s
+ time_pruning_s
+ rules_count
+ conditions_per_rule
+ induced_conditions_per_rule
+ avg_rule_coverage
+ avg_rule_precision
+ avg_rule_quality
+ pvalue
+ FDR_pvalue
+ FWER_pvalue
+ fraction_significant
+ fraction_FDR_significant
+ fraction_FWER_significant
+
+
+ Measure
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ C2
+ 0.05
+ 0.0
+ False
+ True
+ 0.0
+ 27.670397
+ 1.978997
+ 25.637769
+ 11
+ 3.272727
+ 33.727273
+ 0.345683
+ 0.874767
+ 0.732356
+ 1.612636e-177
+ 1.612636e-177
+ 1.612636e-177
+ 1.0
+ 1.0
+ 1.0
+
+
+ Correlation
+ 0.05
+ 0.0
+ False
+ True
+ 0.0
+ 17.739791
+ 0.836199
+ 16.871719
+ 7
+ 2.714286
+ 35.285714
+ 0.334990
+ 0.862965
+ 0.800819
+ 3.046280e-37
+ 3.046280e-37
+ 3.046280e-37
+ 1.0
+ 1.0
+ 1.0
+
+
+ RSS
+ 0.05
+ 0.0
+ False
+ True
+ 0.0
+ 34.929544
+ 1.020750
+ 33.894867
+ 6
+ 2.333333
+ 38.166667
+ 0.417440
+ 0.855115
+ 0.786208
+ 6.242568e-40
+ 6.242568e-40
+ 6.242568e-40
+ 1.0
+ 1.0
+ 1.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ absolute_error
+ relative_error
+ relative_error_lenient
+ relative_error_strict
+ normalized_absolute_error
+ squared_error
+ root_mean_squared_error
+ root_relative_squared_error
+ correlation
+ squared_correlation
+
+
+ Measure
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ C2
+ 0.089929
+ 0.114526
+ 0.101069
+ 0.125935
+ 0.382694
+ 0.019753
+ 0.140547
+ 0.167429
+ 0.937881
+ 0.879620
+
+
+ Correlation
+ 0.088561
+ 0.112319
+ 0.099635
+ 0.125846
+ 0.376872
+ 0.020912
+ 0.144609
+ 0.184988
+ 0.941044
+ 0.885563
+
+
+ RSS
+ 0.092552
+ 0.111375
+ 0.102026
+ 0.124544
+ 0.393860
+ 0.020544
+ 0.143331
+ 0.153866
+ 0.945779
+ 0.894498
+
+
+
+
+
+
+C2 Measure generated rules
+
+
+
+
+
+
+IF MM116 = <0.35, 0.45) AND MM31 = (-inf, 0.24) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.40} [0.39,0.42]
+IF MM116 = (-inf, 0.55) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.45} [0.39,0.52]
+IF MM31 = <0.19, 0.30) AND MM116 = (-inf, 0.95) AND AS038 = (-inf, 2.45) AND PG072 = <1.55, inf) AND DMM116 = (-inf, 0.15) THEN MM116_pred = {0.50} [0.38,0.61]
+IF MM116 = <1.05, 1.35) AND MM31 = <0.28, inf) THEN MM116_pred = {1.19} [1.08,1.31]
+IF MM116 = <0.95, 1.25) AND DMM116 = (-inf, 0.40) THEN MM116_pred = {1.11} [0.99,1.22]
+IF MM116 = <0.85, 1.15) AND DMM116 = <-0.35, 0.25) THEN MM116_pred = {1.00} [0.89,1.12]
+IF MM31 = (-inf, 0.34) AND MM116 = (-inf, 0.85) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.53} [0.39,0.66]
+IF MM31 = <0.18, 0.37) AND AS038 = <2.15, 2.55) AND DMM116 = <-0.15, 0.05) AND MM116 = <0.25, 0.85) AND PG072 = <1.55, inf) AND BA13 = <1070.50, inf) THEN MM116_pred = {0.55} [0.40,0.70]
+IF MM116 = <0.75, 1.05) AND DMM116 = <-0.15, 0.15) AND PG072 = (-inf, 2.05) AND MM31 = (-inf, 0.53) AND BA13 = (-inf, 1073.50) THEN MM116_pred = {0.91} [0.80,1.02]
+IF MM116 = <0.65, 1.45) AND MM31 = (-inf, 0.67) AND DMM116 = <-0.35, 0.25) AND PG072 = (-inf, 2.35) THEN MM116_pred = {0.96} [0.78,1.14]
+IF MM31 = <0.28, 0.76) AND PG072 = (-inf, 2.35) THEN MM116_pred = {0.93} [0.70,1.16]
+
+
+
+
+Correlation Measure generated rules
+
+
+
+
+
+
+IF MM116 = (-inf, 0.45) AND MM31 = <0.18, 0.24) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.40} [0.38,0.42]
+IF MM116 = (-inf, 0.55) AND MM31 = (-inf, 0.32) THEN MM116_pred = {0.45} [0.39,0.51]
+IF MM31 = <0.18, 0.31) AND MM116 = (-inf, 0.85) AND AS038 = (-inf, 2.55) AND PG072 = <1.55, inf) AND DMM116 = <-0.30, 0.15) THEN MM116_pred = {0.50} [0.39,0.60]
+IF MM116 = <1.05, 1.35) THEN MM116_pred = {1.19} [1.08,1.31]
+IF MM116 = <0.85, 1.15) AND DMM116 = <-0.35, inf) THEN MM116_pred = {1.00} [0.89,1.12]
+IF MM116 = <0.45, 0.85) AND DMM116 = <-0.15, inf) AND PG072 = <1.55, inf) AND MM31 = <0.31, inf) THEN MM116_pred = {0.77} [0.66,0.88]
+IF MM31 = <0.23, inf) AND PG072 = (-inf, 2.35) THEN MM116_pred = {0.85} [0.59,1.11]
+
+
+
+
+
+
+Evaluation on a test set
+
+
+
+
+
+
+
+c:\Users\cezar\OneDrive\Pulpit\EMAG\GIT\PythonRulekit\tutorials_env\Lib\site-packages\sklearn\metrics\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.
+ warnings.warn(
+c:\Users\cezar\OneDrive\Pulpit\EMAG\GIT\PythonRulekit\tutorials_env\Lib\site-packages\sklearn\metrics\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.
+ warnings.warn(
+c:\Users\cezar\OneDrive\Pulpit\EMAG\GIT\PythonRulekit\tutorials_env\Lib\site-packages\sklearn\metrics\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.
+ warnings.warn(
+
+
+
+
+
+
+
+
+
+
+
+
+
+ absolute_error
+ relative_error
+ relative_error_lenient
+ relative_error_strict
+ normalized_absolute_error
+ squared_error
+ root_mean_squared_error
+ root_relative_squared_error
+ correlation
+ squared_correlation
+
+
+ Measure
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ C2
+ 0.107227
+ 0.100574
+ 0.094935
+ 0.112747
+ 0.739328
+ 0.020326
+ 0.142569
+ 0.126236
+ 0.835385
+ 0.697868
+
+
+ Correlation
+ 0.105350
+ 0.091827
+ 0.090950
+ 0.109321
+ 0.726385
+ 0.021890
+ 0.147951
+ 0.119472
+ 0.866898
+ 0.751512
+
+
+ RSS
+ 0.128302
+ 0.113411
+ 0.111947
+ 0.134690
+ 0.884639
+ 0.027270
+ 0.165136
+ 0.134849
+ 0.866442
+ 0.750722
+
+
+
+
+
+
+
+Hyperparameters tuning
+This one gonna take a while…
+
+
+
+
+
+
+Best RMSE: -0.191976 using {'induction_measure': <Measures.RSS: 'RSS'>, 'minsupp_new': 6, 'pruning_measure': <Measures.C2: 'C2'>, 'voting_measure': <Measures.C2: 'C2'>}
+
+
+
+
+Prediction using the model selected from the tuning
+
+Generated rules
+
+
+
+
+
+
+IF MM31 = (-inf, 0.23) THEN MM116_pred = {0.40} [0.39,0.41]
+IF MM116 = <0.35, 0.45) AND MM31 = (-inf, 0.24) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.40} [0.39,0.42]
+IF MM116 = <0.35, 0.45) AND MM31 = (-inf, 0.24) THEN MM116_pred = {0.40} [0.38,0.42]
+IF MM31 = <0.24, 0.25) AND AS038 = (-inf, 2.45) AND DMM116 = <-0.05, inf) AND PD = (-inf, 0.50) THEN MM116_pred = {0.50} [0.47,0.54]
+IF MM116 = (-inf, 0.45) AND MM31 = <0.24, 0.25) AND PG072 = (-inf, 2.05) AND AS038 = (-inf, 2.45) AND PD = <0.50, inf) THEN MM116_pred = {0.41} [0.38,0.44]
+IF MM31 = <0.24, 0.25) AND PD = (-inf, 0.50) THEN MM116_pred = {0.51} [0.47,0.54]
+IF MM31 = (-inf, 0.26) AND DMM116 = <-0.05, 0.05) THEN MM116_pred = {0.46} [0.36,0.55]
+IF MM116 = (-inf, 0.45) THEN MM116_pred = {0.40} [0.37,0.44]
+IF MM31 = <0.23, 0.24) AND BA13 = (-inf, 1075.50) AND MM116 = <0.45, inf) THEN MM116_pred = {0.50} [0.48,0.52]
+IF MM116 = <0.45, 0.55) AND PG072 = <1.65, inf) AND DMM116 = <-0.05, inf) AND PD = (-inf, 0.50) AND MM31 = <0.23, inf) THEN MM116_pred = {0.51} [0.48,0.53]
+IF MM116 = <0.45, 0.55) AND PG072 = <1.65, inf) AND MM31 = <0.23, 0.29) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.51} [0.48,0.53]
+IF MM116 = <0.35, 0.55) AND MM31 = (-inf, 0.26) AND BA13 = <1077.50, inf) AND DMM116 = (-inf, -0.05) THEN MM116_pred = {0.54} [0.48,0.60]
+IF MM116 = <0.45, 0.55) AND PG072 = <1.65, inf) AND AS038 = (-inf, 2.45) AND PD = (-inf, 0.50) AND BA13 = (-inf, 1077.50) AND MM31 = <0.23, inf) THEN MM116_pred = {0.50} [0.48,0.53]
+IF MM116 = <0.45, 0.55) AND MM31 = <0.28, 0.30) AND DMM116 = <-0.05, 0.05) AND AS038 = <2.25, 2.35) AND PG072 = <1.75, 1.95) AND BA13 = <1075.50, 1076.50) AND PD = <0.50, inf) THEN MM116_pred = {0.55} [0.50,0.60]
+IF MM116 = (-inf, 0.55) AND MM31 = <0.29, 0.30) AND PG072 = (-inf, 1.95) AND BA13 = (-inf, 1076.50) AND PD = <0.50, inf) THEN MM116_pred = {0.55} [0.50,0.60]
+IF MM116 = (-inf, 0.55) THEN MM116_pred = {0.45} [0.39,0.52]
+IF MM31 = <0.26, 0.27) AND MM116 = <0.55, 0.65) AND PG072 = <1.75, 1.85) AND AS038 = <2.25, 2.45) AND DMM116 = <-0.05, 0.05) AND PD = (-inf, 0.50) AND BA13 = <1074.50, 1077.50) THEN MM116_pred = {0.60} [NaN,NaN]
+IF MM116 = <0.45, 0.65) AND MM31 = <0.23, inf) THEN MM116_pred = {0.55} [0.49,0.61]
+IF MM116 = <0.55, 0.75) THEN MM116_pred = {0.67} [0.58,0.77]
+IF MM116 = <0.75, 0.85) THEN MM116_pred = {0.83} [0.76,0.90]
+IF MM116 = <0.85, inf) THEN MM116_pred = {1.06} [0.88,1.24]
+
+
+Ruleset evaluation
+
+
+
+
+
+
+
+
+
+
+
+ minimum_covered
+ maximum_uncovered_fraction
+ ignore_missing
+ pruning_enabled
+ max_growing_condition
+ time_total_s
+ time_growing_s
+ time_pruning_s
+ rules_count
+ conditions_per_rule
+ induced_conditions_per_rule
+ avg_rule_coverage
+ avg_rule_precision
+ avg_rule_quality
+ pvalue
+ FDR_pvalue
+ FWER_pvalue
+ fraction_significant
+ fraction_FDR_significant
+ fraction_FWER_significant
+
+
+ Measure
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 6.0
+ 0.0
+ False
+ True
+ 0.0
+ 12.151842
+ 1.240354
+ 10.883363
+ 21
+ 3.190476
+ 29.809524
+ 0.116152
+ 0.849723
+ NaN
+ NaN
+ NaN
+ NaN
+ 0.952381
+ 0.952381
+ 0.952381
+
+
+
+
+
+
+Validate model on test dataset
+
+
+
+
+
+
+c:\Users\cezar\OneDrive\Pulpit\EMAG\GIT\PythonRulekit\tutorials_env\Lib\site-packages\sklearn\metrics\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.
+ warnings.warn(
+
+
+
+
+
+
+
+absolute_error 0.111355
+relative_error 0.103524
+relative_error_lenient 0.097884
+relative_error_strict 0.114888
+normalized_absolute_error 0.767792
+squared_error 0.019642
+root_mean_squared_error 0.140148
+root_relative_squared_error 0.125609
+correlation 0.801204
+squared_correlation 0.641927
+Name: , dtype: float64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/rst/tutorials/regression.ipynb b/docs/serve/v2.1.24.0/rst/tutorials/regression.ipynb
new file mode 100644
index 0000000..b396828
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/tutorials/regression.ipynb
@@ -0,0 +1,1486 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Regression"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This notebook presents example usage of package for solving regression problem on `methane` dataset. You can download training dataset [here](https://raw.githubusercontent.com/adaa-polsl/RuleKit/master/data/methane/methane-train.arff) and test dataset [here](https://raw.githubusercontent.com/adaa-polsl/RuleKit/master/data/methane/methane-test.arff)\n",
+ "\n",
+ "This tutorial will cover topics such as: \n",
+ "- training model \n",
+ "- changing model hyperparameters \n",
+ "- hyperparameters tuning \n",
+ "- calculating metrics for model \n",
+ "- getting RuleKit inbuilt "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Summary of the dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "from rulekit.arff import read_arff\n",
+ "\n",
+ "\n",
+ "BASE_DATASET_URL: str = (\n",
+ " 'https://raw.githubusercontent.com/'\n",
+ " 'adaa-polsl/RuleKit/master/data/methane/'\n",
+ ")\n",
+ "TRAIN_DATASET_URL: str = BASE_DATASET_URL + 'methane-train.arff'\n",
+ "TEST_DATASET_URL: str = BASE_DATASET_URL + 'methane-test.arff'\n",
+ "\n",
+ "train_df = read_arff(TRAIN_DATASET_URL)\n",
+ "test_df = read_arff(TEST_DATASET_URL)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Train file"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Train file overview:\n",
+ "Name: methane-train\n",
+ "Objects number: 13368; Attributes number: 8\n",
+ "Basic attribute statistics:\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " MM31 \n",
+ " MM116 \n",
+ " AS038 \n",
+ " PG072 \n",
+ " PD \n",
+ " BA13 \n",
+ " DMM116 \n",
+ " MM116_pred \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " count \n",
+ " 13368.000000 \n",
+ " 13368.000000 \n",
+ " 13368.000000 \n",
+ " 13368.000000 \n",
+ " 13368.000000 \n",
+ " 13368.000000 \n",
+ " 13368.000000 \n",
+ " 13368.00000 \n",
+ " \n",
+ " \n",
+ " mean \n",
+ " 0.363960 \n",
+ " 0.775007 \n",
+ " 2.294734 \n",
+ " 1.835600 \n",
+ " 0.308573 \n",
+ " 1073.443372 \n",
+ " -0.000007 \n",
+ " 0.79825 \n",
+ " \n",
+ " \n",
+ " std \n",
+ " 0.117105 \n",
+ " 0.269366 \n",
+ " 0.142504 \n",
+ " 0.106681 \n",
+ " 0.461922 \n",
+ " 3.162811 \n",
+ " 0.043566 \n",
+ " 0.28649 \n",
+ " \n",
+ " \n",
+ " min \n",
+ " 0.170000 \n",
+ " 0.200000 \n",
+ " 1.400000 \n",
+ " 1.100000 \n",
+ " 0.000000 \n",
+ " 1067.000000 \n",
+ " -1.800000 \n",
+ " 0.20000 \n",
+ " \n",
+ " \n",
+ " 25% \n",
+ " 0.260000 \n",
+ " 0.500000 \n",
+ " 2.300000 \n",
+ " 1.800000 \n",
+ " 0.000000 \n",
+ " 1070.000000 \n",
+ " 0.000000 \n",
+ " 0.50000 \n",
+ " \n",
+ " \n",
+ " 50% \n",
+ " 0.360000 \n",
+ " 0.800000 \n",
+ " 2.300000 \n",
+ " 1.800000 \n",
+ " 0.000000 \n",
+ " 1075.000000 \n",
+ " 0.000000 \n",
+ " 0.80000 \n",
+ " \n",
+ " \n",
+ " 75% \n",
+ " 0.450000 \n",
+ " 1.000000 \n",
+ " 2.400000 \n",
+ " 1.900000 \n",
+ " 1.000000 \n",
+ " 1076.000000 \n",
+ " 0.000000 \n",
+ " 1.00000 \n",
+ " \n",
+ " \n",
+ " max \n",
+ " 0.820000 \n",
+ " 2.200000 \n",
+ " 2.700000 \n",
+ " 2.600000 \n",
+ " 1.000000 \n",
+ " 1078.000000 \n",
+ " 0.800000 \n",
+ " 2.20000 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " MM31 MM116 AS038 PG072 PD \\\n",
+ "count 13368.000000 13368.000000 13368.000000 13368.000000 13368.000000 \n",
+ "mean 0.363960 0.775007 2.294734 1.835600 0.308573 \n",
+ "std 0.117105 0.269366 0.142504 0.106681 0.461922 \n",
+ "min 0.170000 0.200000 1.400000 1.100000 0.000000 \n",
+ "25% 0.260000 0.500000 2.300000 1.800000 0.000000 \n",
+ "50% 0.360000 0.800000 2.300000 1.800000 0.000000 \n",
+ "75% 0.450000 1.000000 2.400000 1.900000 1.000000 \n",
+ "max 0.820000 2.200000 2.700000 2.600000 1.000000 \n",
+ "\n",
+ " BA13 DMM116 MM116_pred \n",
+ "count 13368.000000 13368.000000 13368.00000 \n",
+ "mean 1073.443372 -0.000007 0.79825 \n",
+ "std 3.162811 0.043566 0.28649 \n",
+ "min 1067.000000 -1.800000 0.20000 \n",
+ "25% 1070.000000 0.000000 0.50000 \n",
+ "50% 1075.000000 0.000000 0.80000 \n",
+ "75% 1076.000000 0.000000 1.00000 \n",
+ "max 1078.000000 0.800000 2.20000 "
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "print(\"Train file overview:\")\n",
+ "print(f\"Name: methane-train\")\n",
+ "print(f\"Objects number: {train_df.shape[0]}; Attributes number: {train_df.shape[1]}\")\n",
+ "print(\"Basic attribute statistics:\")\n",
+ "train_df.describe()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Test file"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "Test file overview:\n",
+ "Name: methane-test\n",
+ "Objects number: 5728; Attributes number: 8\n",
+ "Basic attribute statistics:\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " MM31 \n",
+ " MM116 \n",
+ " AS038 \n",
+ " PG072 \n",
+ " PD \n",
+ " BA13 \n",
+ " DMM116 \n",
+ " MM116_pred \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " count \n",
+ " 5728.000000 \n",
+ " 5728.000000 \n",
+ " 5728.000000 \n",
+ " 5728.000000 \n",
+ " 5728.000000 \n",
+ " 5728.000000 \n",
+ " 5728.000000 \n",
+ " 5728.000000 \n",
+ " \n",
+ " \n",
+ " mean \n",
+ " 0.556652 \n",
+ " 1.006913 \n",
+ " 2.236627 \n",
+ " 1.819239 \n",
+ " 0.538408 \n",
+ " 1072.691690 \n",
+ " -0.000017 \n",
+ " 1.042458 \n",
+ " \n",
+ " \n",
+ " std \n",
+ " 0.114682 \n",
+ " 0.167983 \n",
+ " 0.104913 \n",
+ " 0.078865 \n",
+ " 0.498566 \n",
+ " 2.799559 \n",
+ " 0.046849 \n",
+ " 0.171393 \n",
+ " \n",
+ " \n",
+ " min \n",
+ " 0.350000 \n",
+ " 0.500000 \n",
+ " 1.800000 \n",
+ " 1.600000 \n",
+ " 0.000000 \n",
+ " 1067.000000 \n",
+ " -0.400000 \n",
+ " 0.600000 \n",
+ " \n",
+ " \n",
+ " 25% \n",
+ " 0.460000 \n",
+ " 0.900000 \n",
+ " 2.200000 \n",
+ " 1.800000 \n",
+ " 0.000000 \n",
+ " 1071.000000 \n",
+ " 0.000000 \n",
+ " 0.900000 \n",
+ " \n",
+ " \n",
+ " 50% \n",
+ " 0.550000 \n",
+ " 1.000000 \n",
+ " 2.200000 \n",
+ " 1.800000 \n",
+ " 1.000000 \n",
+ " 1073.000000 \n",
+ " 0.000000 \n",
+ " 1.000000 \n",
+ " \n",
+ " \n",
+ " 75% \n",
+ " 0.640000 \n",
+ " 1.100000 \n",
+ " 2.300000 \n",
+ " 1.900000 \n",
+ " 1.000000 \n",
+ " 1075.000000 \n",
+ " 0.000000 \n",
+ " 1.200000 \n",
+ " \n",
+ " \n",
+ " max \n",
+ " 0.980000 \n",
+ " 1.600000 \n",
+ " 2.700000 \n",
+ " 2.100000 \n",
+ " 1.000000 \n",
+ " 1078.000000 \n",
+ " 0.300000 \n",
+ " 1.600000 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " MM31 MM116 AS038 PG072 PD \\\n",
+ "count 5728.000000 5728.000000 5728.000000 5728.000000 5728.000000 \n",
+ "mean 0.556652 1.006913 2.236627 1.819239 0.538408 \n",
+ "std 0.114682 0.167983 0.104913 0.078865 0.498566 \n",
+ "min 0.350000 0.500000 1.800000 1.600000 0.000000 \n",
+ "25% 0.460000 0.900000 2.200000 1.800000 0.000000 \n",
+ "50% 0.550000 1.000000 2.200000 1.800000 1.000000 \n",
+ "75% 0.640000 1.100000 2.300000 1.900000 1.000000 \n",
+ "max 0.980000 1.600000 2.700000 2.100000 1.000000 \n",
+ "\n",
+ " BA13 DMM116 MM116_pred \n",
+ "count 5728.000000 5728.000000 5728.000000 \n",
+ "mean 1072.691690 -0.000017 1.042458 \n",
+ "std 2.799559 0.046849 0.171393 \n",
+ "min 1067.000000 -0.400000 0.600000 \n",
+ "25% 1071.000000 0.000000 0.900000 \n",
+ "50% 1073.000000 0.000000 1.000000 \n",
+ "75% 1075.000000 0.000000 1.200000 \n",
+ "max 1078.000000 0.300000 1.600000 "
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "print(\"\\nTest file overview:\")\n",
+ "print(f\"Name: methane-test\")\n",
+ "print(f\"Objects number: {test_df.shape[0]}; Attributes number: {test_df.shape[1]}\")\n",
+ "print(\"Basic attribute statistics:\")\n",
+ "test_df.describe()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Helper function for calculating metrics"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sklearn import metrics\n",
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "from math import sqrt\n",
+ "\n",
+ "\n",
+ "def get_regression_metrics(measure: str, y_pred, y_true) -> pd.DataFrame:\n",
+ " relative_error = 0\n",
+ " squared_relative_error = 0\n",
+ " relative_error_lenient = 0\n",
+ " relative_error_strict = 0\n",
+ " nae_denominator = 0\n",
+ " avg = sum(y_true) / len(y_pred)\n",
+ "\n",
+ " for i in range(0, len(y_pred)):\n",
+ " true = y_true[i]\n",
+ " predicted = y_pred[i]\n",
+ "\n",
+ " relative_error += abs((true - predicted) / true)\n",
+ " squared_relative_error += (\n",
+ " abs((true - predicted) / true) *\n",
+ " abs((true - predicted) / true)\n",
+ " )\n",
+ " relative_error_lenient += (\n",
+ " abs((true - predicted) / max(true, predicted))\n",
+ " )\n",
+ " relative_error_strict += abs((true - predicted) / min(true, predicted))\n",
+ " nae_denominator += abs(avg - true)\n",
+ "\n",
+ " relative_error /= len(y_pred)\n",
+ " squared_relative_error /= len(y_pred)\n",
+ " relative_error_lenient /= len(y_pred)\n",
+ " relative_error_strict /= len(y_pred)\n",
+ " nae_denominator /= len(y_pred)\n",
+ " correlation = np.mean(np.corrcoef(y_true, y_pred))\n",
+ "\n",
+ " dictionary = {\n",
+ " 'Measure': measure,\n",
+ " 'absolute_error': metrics.mean_absolute_error(y_true, y_pred),\n",
+ " 'relative_error': relative_error,\n",
+ " 'relative_error_lenient': relative_error_lenient,\n",
+ " 'relative_error_strict': relative_error_strict,\n",
+ " 'normalized_absolute_error': metrics.mean_absolute_error(y_true, y_pred) / nae_denominator,\n",
+ " 'squared_error': metrics.mean_squared_error(y_true, y_pred),\n",
+ " 'root_mean_squared_error': metrics.mean_squared_error(y_true, y_pred, squared=False),\n",
+ " 'root_relative_squared_error': sqrt(squared_relative_error),\n",
+ " 'correlation': correlation,\n",
+ " 'squared_correlation': np.power(correlation, 2),\n",
+ " }\n",
+ " return pd.DataFrame.from_records([dictionary], index='Measure')\n",
+ "\n",
+ "\n",
+ "def get_ruleset_stats(measure: str, model) -> pd.DataFrame:\n",
+ " tmp = model.parameters.__dict__\n",
+ " del tmp['_java_object']\n",
+ " return pd.DataFrame.from_records(\n",
+ " [{'Measure': measure, **tmp, **model.stats.__dict__}],\n",
+ " index='Measure'\n",
+ " )"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Rule induction on training dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "X_train: pd.DataFrame = train_df.drop(['MM116_pred'], axis=1)\n",
+ "y_train: pd.Series = train_df['MM116_pred']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "c:\\Users\\cezar\\OneDrive\\Pulpit\\EMAG\\GIT\\PythonRulekit\\tutorials_env\\Lib\\site-packages\\sklearn\\metrics\\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.\n",
+ " warnings.warn(\n",
+ "c:\\Users\\cezar\\OneDrive\\Pulpit\\EMAG\\GIT\\PythonRulekit\\tutorials_env\\Lib\\site-packages\\sklearn\\metrics\\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.\n",
+ " warnings.warn(\n",
+ "c:\\Users\\cezar\\OneDrive\\Pulpit\\EMAG\\GIT\\PythonRulekit\\tutorials_env\\Lib\\site-packages\\sklearn\\metrics\\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.\n",
+ " warnings.warn(\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " minimum_covered \n",
+ " maximum_uncovered_fraction \n",
+ " ignore_missing \n",
+ " pruning_enabled \n",
+ " max_growing_condition \n",
+ " time_total_s \n",
+ " time_growing_s \n",
+ " time_pruning_s \n",
+ " rules_count \n",
+ " conditions_per_rule \n",
+ " induced_conditions_per_rule \n",
+ " avg_rule_coverage \n",
+ " avg_rule_precision \n",
+ " avg_rule_quality \n",
+ " pvalue \n",
+ " FDR_pvalue \n",
+ " FWER_pvalue \n",
+ " fraction_significant \n",
+ " fraction_FDR_significant \n",
+ " fraction_FWER_significant \n",
+ " \n",
+ " \n",
+ " Measure \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " C2 \n",
+ " 0.05 \n",
+ " 0.0 \n",
+ " False \n",
+ " True \n",
+ " 0.0 \n",
+ " 27.670397 \n",
+ " 1.978997 \n",
+ " 25.637769 \n",
+ " 11 \n",
+ " 3.272727 \n",
+ " 33.727273 \n",
+ " 0.345683 \n",
+ " 0.874767 \n",
+ " 0.732356 \n",
+ " 1.612636e-177 \n",
+ " 1.612636e-177 \n",
+ " 1.612636e-177 \n",
+ " 1.0 \n",
+ " 1.0 \n",
+ " 1.0 \n",
+ " \n",
+ " \n",
+ " Correlation \n",
+ " 0.05 \n",
+ " 0.0 \n",
+ " False \n",
+ " True \n",
+ " 0.0 \n",
+ " 17.739791 \n",
+ " 0.836199 \n",
+ " 16.871719 \n",
+ " 7 \n",
+ " 2.714286 \n",
+ " 35.285714 \n",
+ " 0.334990 \n",
+ " 0.862965 \n",
+ " 0.800819 \n",
+ " 3.046280e-37 \n",
+ " 3.046280e-37 \n",
+ " 3.046280e-37 \n",
+ " 1.0 \n",
+ " 1.0 \n",
+ " 1.0 \n",
+ " \n",
+ " \n",
+ " RSS \n",
+ " 0.05 \n",
+ " 0.0 \n",
+ " False \n",
+ " True \n",
+ " 0.0 \n",
+ " 34.929544 \n",
+ " 1.020750 \n",
+ " 33.894867 \n",
+ " 6 \n",
+ " 2.333333 \n",
+ " 38.166667 \n",
+ " 0.417440 \n",
+ " 0.855115 \n",
+ " 0.786208 \n",
+ " 6.242568e-40 \n",
+ " 6.242568e-40 \n",
+ " 6.242568e-40 \n",
+ " 1.0 \n",
+ " 1.0 \n",
+ " 1.0 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " minimum_covered maximum_uncovered_fraction ignore_missing \\\n",
+ "Measure \n",
+ "C2 0.05 0.0 False \n",
+ "Correlation 0.05 0.0 False \n",
+ "RSS 0.05 0.0 False \n",
+ "\n",
+ " pruning_enabled max_growing_condition time_total_s \\\n",
+ "Measure \n",
+ "C2 True 0.0 27.670397 \n",
+ "Correlation True 0.0 17.739791 \n",
+ "RSS True 0.0 34.929544 \n",
+ "\n",
+ " time_growing_s time_pruning_s rules_count conditions_per_rule \\\n",
+ "Measure \n",
+ "C2 1.978997 25.637769 11 3.272727 \n",
+ "Correlation 0.836199 16.871719 7 2.714286 \n",
+ "RSS 1.020750 33.894867 6 2.333333 \n",
+ "\n",
+ " induced_conditions_per_rule avg_rule_coverage \\\n",
+ "Measure \n",
+ "C2 33.727273 0.345683 \n",
+ "Correlation 35.285714 0.334990 \n",
+ "RSS 38.166667 0.417440 \n",
+ "\n",
+ " avg_rule_precision avg_rule_quality pvalue \\\n",
+ "Measure \n",
+ "C2 0.874767 0.732356 1.612636e-177 \n",
+ "Correlation 0.862965 0.800819 3.046280e-37 \n",
+ "RSS 0.855115 0.786208 6.242568e-40 \n",
+ "\n",
+ " FDR_pvalue FWER_pvalue fraction_significant \\\n",
+ "Measure \n",
+ "C2 1.612636e-177 1.612636e-177 1.0 \n",
+ "Correlation 3.046280e-37 3.046280e-37 1.0 \n",
+ "RSS 6.242568e-40 6.242568e-40 1.0 \n",
+ "\n",
+ " fraction_FDR_significant fraction_FWER_significant \n",
+ "Measure \n",
+ "C2 1.0 1.0 \n",
+ "Correlation 1.0 1.0 \n",
+ "RSS 1.0 1.0 "
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " absolute_error \n",
+ " relative_error \n",
+ " relative_error_lenient \n",
+ " relative_error_strict \n",
+ " normalized_absolute_error \n",
+ " squared_error \n",
+ " root_mean_squared_error \n",
+ " root_relative_squared_error \n",
+ " correlation \n",
+ " squared_correlation \n",
+ " \n",
+ " \n",
+ " Measure \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " C2 \n",
+ " 0.089929 \n",
+ " 0.114526 \n",
+ " 0.101069 \n",
+ " 0.125935 \n",
+ " 0.382694 \n",
+ " 0.019753 \n",
+ " 0.140547 \n",
+ " 0.167429 \n",
+ " 0.937881 \n",
+ " 0.879620 \n",
+ " \n",
+ " \n",
+ " Correlation \n",
+ " 0.088561 \n",
+ " 0.112319 \n",
+ " 0.099635 \n",
+ " 0.125846 \n",
+ " 0.376872 \n",
+ " 0.020912 \n",
+ " 0.144609 \n",
+ " 0.184988 \n",
+ " 0.941044 \n",
+ " 0.885563 \n",
+ " \n",
+ " \n",
+ " RSS \n",
+ " 0.092552 \n",
+ " 0.111375 \n",
+ " 0.102026 \n",
+ " 0.124544 \n",
+ " 0.393860 \n",
+ " 0.020544 \n",
+ " 0.143331 \n",
+ " 0.153866 \n",
+ " 0.945779 \n",
+ " 0.894498 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " absolute_error relative_error relative_error_lenient \\\n",
+ "Measure \n",
+ "C2 0.089929 0.114526 0.101069 \n",
+ "Correlation 0.088561 0.112319 0.099635 \n",
+ "RSS 0.092552 0.111375 0.102026 \n",
+ "\n",
+ " relative_error_strict normalized_absolute_error squared_error \\\n",
+ "Measure \n",
+ "C2 0.125935 0.382694 0.019753 \n",
+ "Correlation 0.125846 0.376872 0.020912 \n",
+ "RSS 0.124544 0.393860 0.020544 \n",
+ "\n",
+ " root_mean_squared_error root_relative_squared_error \\\n",
+ "Measure \n",
+ "C2 0.140547 0.167429 \n",
+ "Correlation 0.144609 0.184988 \n",
+ "RSS 0.143331 0.153866 \n",
+ "\n",
+ " correlation squared_correlation \n",
+ "Measure \n",
+ "C2 0.937881 0.879620 \n",
+ "Correlation 0.941044 0.885563 \n",
+ "RSS 0.945779 0.894498 "
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "from rulekit.regression import RuleRegressor\n",
+ "from rulekit.rules import RuleSet, RegressionRule\n",
+ "from rulekit.params import Measures\n",
+ "\n",
+ "# C2\n",
+ "c2_reg = RuleRegressor(\n",
+ " induction_measure=Measures.C2,\n",
+ " pruning_measure=Measures.C2,\n",
+ " voting_measure=Measures.C2,\n",
+ ")\n",
+ "c2_reg.fit(X_train, y_train)\n",
+ "c2_ruleset: RuleSet[RegressionRule] = c2_reg.model\n",
+ "predictions: np.ndarray = c2_reg.predict(X_train)\n",
+ "\n",
+ "regression_metrics = get_regression_metrics('C2', predictions, y_train)\n",
+ "ruleset_stats = get_ruleset_stats('C2', c2_ruleset)\n",
+ "\n",
+ "\n",
+ "# Correlation\n",
+ "corr_reg = RuleRegressor(\n",
+ " induction_measure=Measures.Correlation,\n",
+ " pruning_measure=Measures.Correlation,\n",
+ " voting_measure=Measures.Correlation,\n",
+ " mean_based_regression=True\n",
+ ")\n",
+ "corr_reg.fit(X_train, y_train)\n",
+ "corr_ruleset: RuleSet[RegressionRule] = corr_reg.model\n",
+ "predictions: np.ndarray = corr_reg.predict(X_train)\n",
+ "\n",
+ "tmp = get_regression_metrics('Correlation', predictions, y_train)\n",
+ "regression_metrics = pd.concat([regression_metrics, tmp])\n",
+ "ruleset_stats = pd.concat([ruleset_stats, get_ruleset_stats('Correlation', corr_ruleset)])\n",
+ "\n",
+ "\n",
+ "# RSS\n",
+ "rss_reg = RuleRegressor(\n",
+ " induction_measure=Measures.RSS,\n",
+ " pruning_measure=Measures.RSS,\n",
+ " voting_measure=Measures.RSS,\n",
+ " mean_based_regression=True\n",
+ ")\n",
+ "rss_reg.fit(X_train, y_train)\n",
+ "rss_ruleset: RuleSet[RegressionRule] = rss_reg.model\n",
+ "predictions: np.ndarray = rss_reg.predict(X_train)\n",
+ "\n",
+ "tmp = get_regression_metrics('RSS', predictions, y_train)\n",
+ "regression_metrics = pd.concat([regression_metrics, tmp])\n",
+ "ruleset_stats = pd.concat([ruleset_stats, get_ruleset_stats('RSS', rss_ruleset)])\n",
+ "\n",
+ "\n",
+ "display(ruleset_stats)\n",
+ "display(regression_metrics)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### C2 Measure generated rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF MM116 = <0.35, 0.45) AND MM31 = (-inf, 0.24) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.40} [0.39,0.42]\n",
+ "IF MM116 = (-inf, 0.55) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.45} [0.39,0.52]\n",
+ "IF MM31 = <0.19, 0.30) AND MM116 = (-inf, 0.95) AND AS038 = (-inf, 2.45) AND PG072 = <1.55, inf) AND DMM116 = (-inf, 0.15) THEN MM116_pred = {0.50} [0.38,0.61]\n",
+ "IF MM116 = <1.05, 1.35) AND MM31 = <0.28, inf) THEN MM116_pred = {1.19} [1.08,1.31]\n",
+ "IF MM116 = <0.95, 1.25) AND DMM116 = (-inf, 0.40) THEN MM116_pred = {1.11} [0.99,1.22]\n",
+ "IF MM116 = <0.85, 1.15) AND DMM116 = <-0.35, 0.25) THEN MM116_pred = {1.00} [0.89,1.12]\n",
+ "IF MM31 = (-inf, 0.34) AND MM116 = (-inf, 0.85) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.53} [0.39,0.66]\n",
+ "IF MM31 = <0.18, 0.37) AND AS038 = <2.15, 2.55) AND DMM116 = <-0.15, 0.05) AND MM116 = <0.25, 0.85) AND PG072 = <1.55, inf) AND BA13 = <1070.50, inf) THEN MM116_pred = {0.55} [0.40,0.70]\n",
+ "IF MM116 = <0.75, 1.05) AND DMM116 = <-0.15, 0.15) AND PG072 = (-inf, 2.05) AND MM31 = (-inf, 0.53) AND BA13 = (-inf, 1073.50) THEN MM116_pred = {0.91} [0.80,1.02]\n",
+ "IF MM116 = <0.65, 1.45) AND MM31 = (-inf, 0.67) AND DMM116 = <-0.35, 0.25) AND PG072 = (-inf, 2.35) THEN MM116_pred = {0.96} [0.78,1.14]\n",
+ "IF MM31 = <0.28, 0.76) AND PG072 = (-inf, 2.35) THEN MM116_pred = {0.93} [0.70,1.16]\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in c2_ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Correlation Measure generated rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF MM116 = (-inf, 0.45) AND MM31 = <0.18, 0.24) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.40} [0.38,0.42]\n",
+ "IF MM116 = (-inf, 0.55) AND MM31 = (-inf, 0.32) THEN MM116_pred = {0.45} [0.39,0.51]\n",
+ "IF MM31 = <0.18, 0.31) AND MM116 = (-inf, 0.85) AND AS038 = (-inf, 2.55) AND PG072 = <1.55, inf) AND DMM116 = <-0.30, 0.15) THEN MM116_pred = {0.50} [0.39,0.60]\n",
+ "IF MM116 = <1.05, 1.35) THEN MM116_pred = {1.19} [1.08,1.31]\n",
+ "IF MM116 = <0.85, 1.15) AND DMM116 = <-0.35, inf) THEN MM116_pred = {1.00} [0.89,1.12]\n",
+ "IF MM116 = <0.45, 0.85) AND DMM116 = <-0.15, inf) AND PG072 = <1.55, inf) AND MM31 = <0.31, inf) THEN MM116_pred = {0.77} [0.66,0.88]\n",
+ "IF MM31 = <0.23, inf) AND PG072 = (-inf, 2.35) THEN MM116_pred = {0.85} [0.59,1.11]\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in corr_ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### RSS Measure generated rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF MM116 = (-inf, 0.45) AND MM31 = <0.18, 0.25) AND PG072 = (-inf, 2.05) THEN MM116_pred = {0.40} [0.38,0.43]\n",
+ "IF MM116 = (-inf, 0.55) AND DMM116 = <-0.15, inf) THEN MM116_pred = {0.45} [0.39,0.52]\n",
+ "IF MM116 = <0.45, 0.75) THEN MM116_pred = {0.60} [0.49,0.71]\n",
+ "IF DMM116 = <-0.35, inf) AND MM31 = <0.31, inf) AND MM116 = (-inf, 1.05) THEN MM116_pred = {0.87} [0.72,1.02]\n",
+ "IF MM116 = <0.85, 1.45) AND DMM116 = <-0.50, inf) THEN MM116_pred = {1.05} [0.90,1.21]\n",
+ "IF MM31 = <0.23, inf) AND MM116 = <0.25, inf) AND PG072 = (-inf, 2.35) THEN MM116_pred = {0.85} [0.59,1.11]\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in rss_ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Evaluation on a test set"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "X_test = test_df.drop(['MM116_pred'], axis=1)\n",
+ "y_test = test_df['MM116_pred']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "c:\\Users\\cezar\\OneDrive\\Pulpit\\EMAG\\GIT\\PythonRulekit\\tutorials_env\\Lib\\site-packages\\sklearn\\metrics\\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.\n",
+ " warnings.warn(\n",
+ "c:\\Users\\cezar\\OneDrive\\Pulpit\\EMAG\\GIT\\PythonRulekit\\tutorials_env\\Lib\\site-packages\\sklearn\\metrics\\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.\n",
+ " warnings.warn(\n",
+ "c:\\Users\\cezar\\OneDrive\\Pulpit\\EMAG\\GIT\\PythonRulekit\\tutorials_env\\Lib\\site-packages\\sklearn\\metrics\\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.\n",
+ " warnings.warn(\n"
+ ]
+ }
+ ],
+ "source": [
+ "# C2\n",
+ "c2_predictions = c2_reg.predict(X_test)\n",
+ "c2_regression_metrics = get_regression_metrics('C2', c2_predictions, y_test)\n",
+ "\n",
+ "# Correlation\n",
+ "corr_predictions = corr_reg.predict(X_test)\n",
+ "corr_regression_metrics = get_regression_metrics('Correlation', corr_predictions, y_test)\n",
+ "\n",
+ "# RSS\n",
+ "rss_predictions = rss_reg.predict(X_test)\n",
+ "rss_regression_metrics = get_regression_metrics('RSS', rss_predictions, y_test)\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " absolute_error \n",
+ " relative_error \n",
+ " relative_error_lenient \n",
+ " relative_error_strict \n",
+ " normalized_absolute_error \n",
+ " squared_error \n",
+ " root_mean_squared_error \n",
+ " root_relative_squared_error \n",
+ " correlation \n",
+ " squared_correlation \n",
+ " \n",
+ " \n",
+ " Measure \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " C2 \n",
+ " 0.107227 \n",
+ " 0.100574 \n",
+ " 0.094935 \n",
+ " 0.112747 \n",
+ " 0.739328 \n",
+ " 0.020326 \n",
+ " 0.142569 \n",
+ " 0.126236 \n",
+ " 0.835385 \n",
+ " 0.697868 \n",
+ " \n",
+ " \n",
+ " Correlation \n",
+ " 0.105350 \n",
+ " 0.091827 \n",
+ " 0.090950 \n",
+ " 0.109321 \n",
+ " 0.726385 \n",
+ " 0.021890 \n",
+ " 0.147951 \n",
+ " 0.119472 \n",
+ " 0.866898 \n",
+ " 0.751512 \n",
+ " \n",
+ " \n",
+ " RSS \n",
+ " 0.128302 \n",
+ " 0.113411 \n",
+ " 0.111947 \n",
+ " 0.134690 \n",
+ " 0.884639 \n",
+ " 0.027270 \n",
+ " 0.165136 \n",
+ " 0.134849 \n",
+ " 0.866442 \n",
+ " 0.750722 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " absolute_error relative_error relative_error_lenient \\\n",
+ "Measure \n",
+ "C2 0.107227 0.100574 0.094935 \n",
+ "Correlation 0.105350 0.091827 0.090950 \n",
+ "RSS 0.128302 0.113411 0.111947 \n",
+ "\n",
+ " relative_error_strict normalized_absolute_error squared_error \\\n",
+ "Measure \n",
+ "C2 0.112747 0.739328 0.020326 \n",
+ "Correlation 0.109321 0.726385 0.021890 \n",
+ "RSS 0.134690 0.884639 0.027270 \n",
+ "\n",
+ " root_mean_squared_error root_relative_squared_error \\\n",
+ "Measure \n",
+ "C2 0.142569 0.126236 \n",
+ "Correlation 0.147951 0.119472 \n",
+ "RSS 0.165136 0.134849 \n",
+ "\n",
+ " correlation squared_correlation \n",
+ "Measure \n",
+ "C2 0.835385 0.697868 \n",
+ "Correlation 0.866898 0.751512 \n",
+ "RSS 0.866442 0.750722 "
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(pd.concat([c2_regression_metrics, corr_regression_metrics, rss_regression_metrics]))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Hyperparameters tuning\n",
+ "\n",
+ "This one gonna take a while..."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Best RMSE: -0.191976 using {'induction_measure': , 'minsupp_new': 6, 'pruning_measure': , 'voting_measure': }\n"
+ ]
+ }
+ ],
+ "source": [
+ "from sklearn.model_selection import KFold\n",
+ "from sklearn.model_selection import GridSearchCV\n",
+ "\n",
+ "\n",
+ "# define models and parameters\n",
+ "model = RuleRegressor(mean_based_regression=True)\n",
+ "minsupp_new = range(5, 7)\n",
+ "measures_choice = [Measures.C2, Measures.Correlation, Measures.RSS]\n",
+ "\n",
+ "# define grid search\n",
+ "grid = {\n",
+ " 'minsupp_new': minsupp_new, \n",
+ " 'induction_measure': measures_choice, \n",
+ " 'pruning_measure': measures_choice, \n",
+ " 'voting_measure': measures_choice\n",
+ "}\n",
+ "cv = KFold(n_splits=2)\n",
+ "grid_search = GridSearchCV(estimator=model, param_grid=grid, cv=cv, scoring='neg_root_mean_squared_error')\n",
+ "grid_result = grid_search.fit(X_train, y_train)\n",
+ "\n",
+ "# summarize results\n",
+ "print(\"Best RMSE: %f using %s\" % (grid_result.best_score_, grid_result.best_params_))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Prediction using the model selected from the tuning"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "reg: RuleRegressor = grid_result.best_estimator_\n",
+ "ruleset: RuleSet[RegressionRule] = reg.model\n",
+ "ruleset_stats = get_ruleset_stats('', ruleset)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Generated rules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "IF MM31 = (-inf, 0.23) THEN MM116_pred = {0.40} [0.39,0.41]\n",
+ "IF MM116 = <0.35, 0.45) AND MM31 = (-inf, 0.24) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.40} [0.39,0.42]\n",
+ "IF MM116 = <0.35, 0.45) AND MM31 = (-inf, 0.24) THEN MM116_pred = {0.40} [0.38,0.42]\n",
+ "IF MM31 = <0.24, 0.25) AND AS038 = (-inf, 2.45) AND DMM116 = <-0.05, inf) AND PD = (-inf, 0.50) THEN MM116_pred = {0.50} [0.47,0.54]\n",
+ "IF MM116 = (-inf, 0.45) AND MM31 = <0.24, 0.25) AND PG072 = (-inf, 2.05) AND AS038 = (-inf, 2.45) AND PD = <0.50, inf) THEN MM116_pred = {0.41} [0.38,0.44]\n",
+ "IF MM31 = <0.24, 0.25) AND PD = (-inf, 0.50) THEN MM116_pred = {0.51} [0.47,0.54]\n",
+ "IF MM31 = (-inf, 0.26) AND DMM116 = <-0.05, 0.05) THEN MM116_pred = {0.46} [0.36,0.55]\n",
+ "IF MM116 = (-inf, 0.45) THEN MM116_pred = {0.40} [0.37,0.44]\n",
+ "IF MM31 = <0.23, 0.24) AND BA13 = (-inf, 1075.50) AND MM116 = <0.45, inf) THEN MM116_pred = {0.50} [0.48,0.52]\n",
+ "IF MM116 = <0.45, 0.55) AND PG072 = <1.65, inf) AND DMM116 = <-0.05, inf) AND PD = (-inf, 0.50) AND MM31 = <0.23, inf) THEN MM116_pred = {0.51} [0.48,0.53]\n",
+ "IF MM116 = <0.45, 0.55) AND PG072 = <1.65, inf) AND MM31 = <0.23, 0.29) AND DMM116 = <-0.05, inf) THEN MM116_pred = {0.51} [0.48,0.53]\n",
+ "IF MM116 = <0.35, 0.55) AND MM31 = (-inf, 0.26) AND BA13 = <1077.50, inf) AND DMM116 = (-inf, -0.05) THEN MM116_pred = {0.54} [0.48,0.60]\n",
+ "IF MM116 = <0.45, 0.55) AND PG072 = <1.65, inf) AND AS038 = (-inf, 2.45) AND PD = (-inf, 0.50) AND BA13 = (-inf, 1077.50) AND MM31 = <0.23, inf) THEN MM116_pred = {0.50} [0.48,0.53]\n",
+ "IF MM116 = <0.45, 0.55) AND MM31 = <0.28, 0.30) AND DMM116 = <-0.05, 0.05) AND AS038 = <2.25, 2.35) AND PG072 = <1.75, 1.95) AND BA13 = <1075.50, 1076.50) AND PD = <0.50, inf) THEN MM116_pred = {0.55} [0.50,0.60]\n",
+ "IF MM116 = (-inf, 0.55) AND MM31 = <0.29, 0.30) AND PG072 = (-inf, 1.95) AND BA13 = (-inf, 1076.50) AND PD = <0.50, inf) THEN MM116_pred = {0.55} [0.50,0.60]\n",
+ "IF MM116 = (-inf, 0.55) THEN MM116_pred = {0.45} [0.39,0.52]\n",
+ "IF MM31 = <0.26, 0.27) AND MM116 = <0.55, 0.65) AND PG072 = <1.75, 1.85) AND AS038 = <2.25, 2.45) AND DMM116 = <-0.05, 0.05) AND PD = (-inf, 0.50) AND BA13 = <1074.50, 1077.50) THEN MM116_pred = {0.60} [NaN,NaN]\n",
+ "IF MM116 = <0.45, 0.65) AND MM31 = <0.23, inf) THEN MM116_pred = {0.55} [0.49,0.61]\n",
+ "IF MM116 = <0.55, 0.75) THEN MM116_pred = {0.67} [0.58,0.77]\n",
+ "IF MM116 = <0.75, 0.85) THEN MM116_pred = {0.83} [0.76,0.90]\n",
+ "IF MM116 = <0.85, inf) THEN MM116_pred = {1.06} [0.88,1.24]\n"
+ ]
+ }
+ ],
+ "source": [
+ "for rule in ruleset.rules:\n",
+ " print(rule)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Ruleset evaluation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " minimum_covered \n",
+ " maximum_uncovered_fraction \n",
+ " ignore_missing \n",
+ " pruning_enabled \n",
+ " max_growing_condition \n",
+ " time_total_s \n",
+ " time_growing_s \n",
+ " time_pruning_s \n",
+ " rules_count \n",
+ " conditions_per_rule \n",
+ " induced_conditions_per_rule \n",
+ " avg_rule_coverage \n",
+ " avg_rule_precision \n",
+ " avg_rule_quality \n",
+ " pvalue \n",
+ " FDR_pvalue \n",
+ " FWER_pvalue \n",
+ " fraction_significant \n",
+ " fraction_FDR_significant \n",
+ " fraction_FWER_significant \n",
+ " \n",
+ " \n",
+ " Measure \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 6.0 \n",
+ " 0.0 \n",
+ " False \n",
+ " True \n",
+ " 0.0 \n",
+ " 12.151842 \n",
+ " 1.240354 \n",
+ " 10.883363 \n",
+ " 21 \n",
+ " 3.190476 \n",
+ " 29.809524 \n",
+ " 0.116152 \n",
+ " 0.849723 \n",
+ " NaN \n",
+ " NaN \n",
+ " NaN \n",
+ " NaN \n",
+ " 0.952381 \n",
+ " 0.952381 \n",
+ " 0.952381 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " minimum_covered maximum_uncovered_fraction ignore_missing \\\n",
+ "Measure \n",
+ " 6.0 0.0 False \n",
+ "\n",
+ " pruning_enabled max_growing_condition time_total_s time_growing_s \\\n",
+ "Measure \n",
+ " True 0.0 12.151842 1.240354 \n",
+ "\n",
+ " time_pruning_s rules_count conditions_per_rule \\\n",
+ "Measure \n",
+ " 10.883363 21 3.190476 \n",
+ "\n",
+ " induced_conditions_per_rule avg_rule_coverage avg_rule_precision \\\n",
+ "Measure \n",
+ " 29.809524 0.116152 0.849723 \n",
+ "\n",
+ " avg_rule_quality pvalue FDR_pvalue FWER_pvalue \\\n",
+ "Measure \n",
+ " NaN NaN NaN NaN \n",
+ "\n",
+ " fraction_significant fraction_FDR_significant \\\n",
+ "Measure \n",
+ " 0.952381 0.952381 \n",
+ "\n",
+ " fraction_FWER_significant \n",
+ "Measure \n",
+ " 0.952381 "
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(ruleset_stats)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Validate model on test dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "c:\\Users\\cezar\\OneDrive\\Pulpit\\EMAG\\GIT\\PythonRulekit\\tutorials_env\\Lib\\site-packages\\sklearn\\metrics\\_regression.py:492: FutureWarning: 'squared' is deprecated in version 1.4 and will be removed in 1.6. To calculate the root mean squared error, use the function'root_mean_squared_error'.\n",
+ " warnings.warn(\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "absolute_error 0.111355\n",
+ "relative_error 0.103524\n",
+ "relative_error_lenient 0.097884\n",
+ "relative_error_strict 0.114888\n",
+ "normalized_absolute_error 0.767792\n",
+ "squared_error 0.019642\n",
+ "root_mean_squared_error 0.140148\n",
+ "root_relative_squared_error 0.125609\n",
+ "correlation 0.801204\n",
+ "squared_correlation 0.641927\n",
+ "Name: , dtype: float64"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "predictions = reg.predict(X_test)\n",
+ "regression_metrics = get_regression_metrics('', predictions, y_test)\n",
+ "display(regression_metrics.iloc[0])"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "tutorials_env",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.0"
+ },
+ "metadata": {
+ "interpreter": {
+ "hash": "62266c16fff41e971c13e9cb2ad3d47e4ef45d0678714c255381eb9fdcbd7032"
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/docs/serve/v2.1.24.0/rst/tutorials/survival.html b/docs/serve/v2.1.24.0/rst/tutorials/survival.html
new file mode 100644
index 0000000..79c3f78
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/tutorials/survival.html
@@ -0,0 +1,1159 @@
+
+
+
+
+
+
+ Survival analysis — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rulekit v2.1.24.0
+
+
+
+
+
+
+
+
+
+Survival analysis
+This notebook presents example usage of package for solving survival problem on bmt
dataset. You can access dataset here
+
+
This tutorial will cover topics such as:
+
- training model
+
- changing model hyperparameters
+
- hyperparameters tuning
+
- calculating metrics for model
+
+
+Install dependencies
+
+
+
+Summary of the dataset
+
+
+
+
+
+
+
+
+
+
+
+ Recipientgender
+ Stemcellsource
+ Donorage
+ Donorage35
+ IIIV
+ Gendermatch
+ DonorABO
+ RecipientABO
+ RecipientRh
+ ABOmatch
+ ...
+ extcGvHD
+ CD34kgx10d6
+ CD3dCD34
+ CD3dkgx10d8
+ Rbodymass
+ ANCrecovery
+ PLTrecovery
+ time_to_aGvHD_III_IV
+ survival_time
+ survival_status
+
+
+
+
+ 0
+ 1
+ 1
+ 22.830137
+ 0
+ 1
+ 0
+ 1
+ 1
+ 1
+ 0
+ ...
+ 1
+ 7.20
+ 1.338760
+ 5.38
+ 35.0
+ 19.0
+ 51.0
+ 32.0
+ 999.0
+ 0
+
+
+ 1
+ 1
+ 0
+ 23.342466
+ 0
+ 1
+ 0
+ -1
+ -1
+ 1
+ 0
+ ...
+ 1
+ 4.50
+ 11.078295
+ 0.41
+ 20.6
+ 16.0
+ 37.0
+ 1000000.0
+ 163.0
+ 1
+
+
+ 2
+ 1
+ 0
+ 26.394521
+ 0
+ 1
+ 0
+ -1
+ -1
+ 1
+ 0
+ ...
+ 1
+ 7.94
+ 19.013230
+ 0.42
+ 23.4
+ 23.0
+ 20.0
+ 1000000.0
+ 435.0
+ 1
+
+
+ 3
+ 0
+ 0
+ 39.684932
+ 1
+ 1
+ 0
+ 1
+ 2
+ 1
+ 1
+ ...
+ None
+ 4.25
+ 29.481647
+ 0.14
+ 50.0
+ 23.0
+ 29.0
+ 19.0
+ 53.0
+ 1
+
+
+ 4
+ 0
+ 1
+ 33.358904
+ 0
+ 0
+ 0
+ 1
+ 2
+ 0
+ 1
+ ...
+ 1
+ 51.85
+ 3.972255
+ 13.05
+ 9.0
+ 14.0
+ 14.0
+ 1000000.0
+ 2043.0
+ 0
+
+
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+
+
+ 182
+ 1
+ 1
+ 37.575342
+ 1
+ 1
+ 0
+ 1
+ 1
+ 0
+ 0
+ ...
+ 1
+ 11.08
+ 2.522750
+ 4.39
+ 44.0
+ 15.0
+ 22.0
+ 16.0
+ 385.0
+ 1
+
+
+ 183
+ 0
+ 1
+ 22.895890
+ 0
+ 0
+ 0
+ 1
+ 0
+ 1
+ 1
+ ...
+ 1
+ 4.64
+ 1.038858
+ 4.47
+ 44.5
+ 12.0
+ 30.0
+ 1000000.0
+ 634.0
+ 1
+
+
+ 184
+ 0
+ 1
+ 27.347945
+ 0
+ 1
+ 0
+ 1
+ -1
+ 1
+ 1
+ ...
+ 1
+ 7.73
+ 1.635559
+ 4.73
+ 33.0
+ 16.0
+ 16.0
+ 1000000.0
+ 1895.0
+ 0
+
+
+ 185
+ 1
+ 1
+ 27.780822
+ 0
+ 1
+ 0
+ 1
+ 0
+ 1
+ 1
+ ...
+ 0
+ 15.41
+ 8.077770
+ 1.91
+ 24.0
+ 13.0
+ 14.0
+ 54.0
+ 382.0
+ 1
+
+
+ 186
+ 1
+ 1
+ 55.553425
+ 1
+ 1
+ 0
+ 1
+ 2
+ 1
+ 1
+ ...
+ 1
+ 9.91
+ 0.948135
+ 10.45
+ 37.0
+ 18.0
+ 20.0
+ 1000000.0
+ 1109.0
+ 0
+
+
+
+
187 rows × 37 columns
+
+
+
+
+
+
+
+
+Dataset overview:
+Name: bmt
+Objects number: 187; Attributes number: 37
+Basic attribute statistics:
+
+
+
+
+
+
+
+
+
+
+
+ Donorage
+ Recipientage
+ CD34kgx10d6
+ CD3dCD34
+ CD3dkgx10d8
+ Rbodymass
+ ANCrecovery
+ PLTrecovery
+ time_to_aGvHD_III_IV
+ survival_time
+
+
+
+
+ count
+ 187.000000
+ 187.000000
+ 187.000000
+ 182.000000
+ 182.000000
+ 185.000000
+ 187.000000
+ 187.000000
+ 187.000000
+ 187.000000
+
+
+ mean
+ 33.472068
+ 9.931551
+ 11.891781
+ 5.385096
+ 4.745714
+ 35.801081
+ 26752.866310
+ 90937.919786
+ 775408.042781
+ 938.743316
+
+
+ std
+ 8.271826
+ 5.305639
+ 9.914386
+ 9.598716
+ 3.859128
+ 19.650922
+ 161747.200525
+ 288242.407688
+ 418425.252689
+ 849.589495
+
+
+ min
+ 18.646575
+ 0.600000
+ 0.790000
+ 0.204132
+ 0.040000
+ 6.000000
+ 9.000000
+ 9.000000
+ 10.000000
+ 6.000000
+
+
+ 25%
+ 27.039726
+ 5.050000
+ 5.350000
+ 1.786683
+ 1.687500
+ 19.000000
+ 13.000000
+ 16.000000
+ 1000000.000000
+ 168.500000
+
+
+ 50%
+ 33.550685
+ 9.600000
+ 9.720000
+ 2.734462
+ 4.325000
+ 33.000000
+ 15.000000
+ 21.000000
+ 1000000.000000
+ 676.000000
+
+
+ 75%
+ 40.117809
+ 14.050000
+ 15.415000
+ 5.823565
+ 6.785000
+ 50.600000
+ 17.000000
+ 37.000000
+ 1000000.000000
+ 1604.000000
+
+
+ max
+ 55.553425
+ 20.200000
+ 57.780000
+ 99.560970
+ 20.020000
+ 103.400000
+ 1000000.000000
+ 1000000.000000
+ 1000000.000000
+ 3364.000000
+
+
+
+
+
+
+
+Helper function for creating ruleset characteristics dataframe
+
+
+
+Rule induction on full dataset
+
+
+
+
+
+
+
+
+
+
+
+
+ minimum_covered
+ maximum_uncovered_fraction
+ ignore_missing
+ pruning_enabled
+ max_growing_condition
+ time_total_s
+ time_growing_s
+ time_pruning_s
+ rules_count
+ conditions_per_rule
+ induced_conditions_per_rule
+ avg_rule_coverage
+ avg_rule_precision
+ avg_rule_quality
+ pvalue
+ FDR_pvalue
+ FWER_pvalue
+ fraction_significant
+ fraction_FDR_significant
+ fraction_FWER_significant
+
+
+
+
+ 0
+ 0.05
+ 0.0
+ False
+ True
+ 0.0
+ 1.771417
+ 0.797513
+ 0.902853
+ 5
+ 3.6
+ 65.2
+ 0.308021
+ 1.0
+ 0.999865
+ 0.000135
+ 0.000147
+ 0.000184
+ 1.0
+ 1.0
+ 1.0
+
+
+
+
+
+
+
+Plot predicted estimators for the first five examples
+
+
+
+
+
+<matplotlib.legend.Legend at 0x289deb3a180>
+
+
+
+
+
+
+
+
+
+
+
+Plot rules Kaplan-Meier’s estimators on top of the training dataset estimator
+
+
+
+
+
+
+r1: IF Donorage = (-inf, 45.16) AND Relapse = {0} AND Recipientage = (-inf, 17.45) THEN
+r2: IF Donorage = (-inf, 43.63) AND HLAmismatch = {0} AND Relapse = {1} THEN
+r3: IF PLTrecovery = (-inf, 266) AND time_to_aGvHD_III_IV = <12.50, inf) AND ANCrecovery = <10.50, 19.50) AND Rbodymass = (-inf, 69) AND Donorage = (-inf, 44.06) AND Recipientage = <4.60, inf) AND CD34kgx10d6 = (-inf, 16.98) THEN
+r4: IF Donorage = <37.16, inf) AND Recipientage = <5.15, inf) AND time_to_aGvHD_III_IV = <23.50, inf) AND CD3dCD34 = <0.90, 73.72) THEN
+r5: IF Recipientage = <17.85, 18.85) THEN
+
+
+
+
+
+
+
+
+
+
+Rules evaluation on full set
+
+
+
+
+
+
+Integrated Brier Score: 0.19651358709002972
+
+
+
+
+
+Stratified K-Folds cross-validation
+
+Ruleset characteristics (average)
+
+
+
+
+
+
+minimum_covered 0.050000
+maximum_uncovered_fraction 0.000000
+ignore_missing 0.000000
+pruning_enabled 1.000000
+max_growing_condition 0.000000
+time_total_s 0.799019
+time_growing_s 0.296248
+time_pruning_s 0.477474
+rules_count 4.000000
+conditions_per_rule 2.581667
+induced_conditions_per_rule 59.825000
+avg_rule_coverage 0.486613
+avg_rule_precision 1.000000
+avg_rule_quality 0.995955
+pvalue 0.004045
+FDR_pvalue 0.004061
+FWER_pvalue 0.004104
+fraction_significant 0.980000
+fraction_FDR_significant 0.980000
+fraction_FWER_significant 0.980000
+dtype: float64
+
+
+Rules evaluation on dataset (average)
+
+
+
+
+
+
+Integrated Brier Score: 0.20178456199764142
+
+
+
+
+Hyperparameters tuning
+This one gonna take a while…
+
+
+
+
+
+
+
+
+Best Integrated Brier Score: -0.21437408819868886 using {'minsupp_new': 3, 'survival_time_attr': 'survival_time'}
+
+
+
+
+Building model with tuned hyperparameters
+
+Split dataset to train and test (80%/20%)
+
+Rules evaluation
+
+
+
+
+
+
+minimum_covered 5.0
+maximum_uncovered_fraction 0.0
+ignore_missing False
+pruning_enabled True
+max_growing_condition 0.0
+time_total_s 0.594173
+time_growing_s 0.244234
+time_pruning_s 0.312523
+rules_count 4
+conditions_per_rule 2.25
+induced_conditions_per_rule 55.25
+avg_rule_coverage 0.389262
+avg_rule_precision 1.0
+avg_rule_quality 1.0
+pvalue 0.0
+FDR_pvalue 0.0
+FWER_pvalue 0.0
+fraction_significant 1.0
+fraction_FDR_significant 1.0
+fraction_FWER_significant 1.0
+Name: 0, dtype: object
+
+
+
+
+Validate model on test dataset
+
+
+
+
+
+
+Integrated Brier Score: 0.14054870564224475
+
+
+
+
+
+
+
+
+Text(0.5, 1.0, 'Predicted Kaplan-Meier curves for 5 examples from test set')
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/rst/tutorials/survival.ipynb b/docs/serve/v2.1.24.0/rst/tutorials/survival.ipynb
new file mode 100644
index 0000000..6d70e02
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/tutorials/survival.ipynb
@@ -0,0 +1,1318 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "-Uy-yBGsd9W1"
+ },
+ "source": [
+ "# Survival analysis"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This notebook presents example usage of package for solving survival problem on `bmt` dataset. You can access dataset [here](https://raw.githubusercontent.com/adaa-polsl/RuleKit/master/data/bmt/bmt.arff) \n",
+ "\n",
+ "This tutorial will cover topics such as: \n",
+ "- training model \n",
+ "- changing model hyperparameters \n",
+ "- hyperparameters tuning \n",
+ "- calculating metrics for model "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Install dependencies"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%pip install matplotlib "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "KjtU7PA8eOTr"
+ },
+ "source": [
+ "## Summary of the dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "Tp1TpfCkd58n"
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " Recipientgender \n",
+ " Stemcellsource \n",
+ " Donorage \n",
+ " Donorage35 \n",
+ " IIIV \n",
+ " Gendermatch \n",
+ " DonorABO \n",
+ " RecipientABO \n",
+ " RecipientRh \n",
+ " ABOmatch \n",
+ " ... \n",
+ " extcGvHD \n",
+ " CD34kgx10d6 \n",
+ " CD3dCD34 \n",
+ " CD3dkgx10d8 \n",
+ " Rbodymass \n",
+ " ANCrecovery \n",
+ " PLTrecovery \n",
+ " time_to_aGvHD_III_IV \n",
+ " survival_time \n",
+ " survival_status \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 1 \n",
+ " 1 \n",
+ " 22.830137 \n",
+ " 0 \n",
+ " 1 \n",
+ " 0 \n",
+ " 1 \n",
+ " 1 \n",
+ " 1 \n",
+ " 0 \n",
+ " ... \n",
+ " 1 \n",
+ " 7.20 \n",
+ " 1.338760 \n",
+ " 5.38 \n",
+ " 35.0 \n",
+ " 19.0 \n",
+ " 51.0 \n",
+ " 32.0 \n",
+ " 999.0 \n",
+ " 0 \n",
+ " \n",
+ " \n",
+ " 1 \n",
+ " 1 \n",
+ " 0 \n",
+ " 23.342466 \n",
+ " 0 \n",
+ " 1 \n",
+ " 0 \n",
+ " -1 \n",
+ " -1 \n",
+ " 1 \n",
+ " 0 \n",
+ " ... \n",
+ " 1 \n",
+ " 4.50 \n",
+ " 11.078295 \n",
+ " 0.41 \n",
+ " 20.6 \n",
+ " 16.0 \n",
+ " 37.0 \n",
+ " 1000000.0 \n",
+ " 163.0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " 2 \n",
+ " 1 \n",
+ " 0 \n",
+ " 26.394521 \n",
+ " 0 \n",
+ " 1 \n",
+ " 0 \n",
+ " -1 \n",
+ " -1 \n",
+ " 1 \n",
+ " 0 \n",
+ " ... \n",
+ " 1 \n",
+ " 7.94 \n",
+ " 19.013230 \n",
+ " 0.42 \n",
+ " 23.4 \n",
+ " 23.0 \n",
+ " 20.0 \n",
+ " 1000000.0 \n",
+ " 435.0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " 3 \n",
+ " 0 \n",
+ " 0 \n",
+ " 39.684932 \n",
+ " 1 \n",
+ " 1 \n",
+ " 0 \n",
+ " 1 \n",
+ " 2 \n",
+ " 1 \n",
+ " 1 \n",
+ " ... \n",
+ " None \n",
+ " 4.25 \n",
+ " 29.481647 \n",
+ " 0.14 \n",
+ " 50.0 \n",
+ " 23.0 \n",
+ " 29.0 \n",
+ " 19.0 \n",
+ " 53.0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " 4 \n",
+ " 0 \n",
+ " 1 \n",
+ " 33.358904 \n",
+ " 0 \n",
+ " 0 \n",
+ " 0 \n",
+ " 1 \n",
+ " 2 \n",
+ " 0 \n",
+ " 1 \n",
+ " ... \n",
+ " 1 \n",
+ " 51.85 \n",
+ " 3.972255 \n",
+ " 13.05 \n",
+ " 9.0 \n",
+ " 14.0 \n",
+ " 14.0 \n",
+ " 1000000.0 \n",
+ " 2043.0 \n",
+ " 0 \n",
+ " \n",
+ " \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " ... \n",
+ " \n",
+ " \n",
+ " 182 \n",
+ " 1 \n",
+ " 1 \n",
+ " 37.575342 \n",
+ " 1 \n",
+ " 1 \n",
+ " 0 \n",
+ " 1 \n",
+ " 1 \n",
+ " 0 \n",
+ " 0 \n",
+ " ... \n",
+ " 1 \n",
+ " 11.08 \n",
+ " 2.522750 \n",
+ " 4.39 \n",
+ " 44.0 \n",
+ " 15.0 \n",
+ " 22.0 \n",
+ " 16.0 \n",
+ " 385.0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " 183 \n",
+ " 0 \n",
+ " 1 \n",
+ " 22.895890 \n",
+ " 0 \n",
+ " 0 \n",
+ " 0 \n",
+ " 1 \n",
+ " 0 \n",
+ " 1 \n",
+ " 1 \n",
+ " ... \n",
+ " 1 \n",
+ " 4.64 \n",
+ " 1.038858 \n",
+ " 4.47 \n",
+ " 44.5 \n",
+ " 12.0 \n",
+ " 30.0 \n",
+ " 1000000.0 \n",
+ " 634.0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " 184 \n",
+ " 0 \n",
+ " 1 \n",
+ " 27.347945 \n",
+ " 0 \n",
+ " 1 \n",
+ " 0 \n",
+ " 1 \n",
+ " -1 \n",
+ " 1 \n",
+ " 1 \n",
+ " ... \n",
+ " 1 \n",
+ " 7.73 \n",
+ " 1.635559 \n",
+ " 4.73 \n",
+ " 33.0 \n",
+ " 16.0 \n",
+ " 16.0 \n",
+ " 1000000.0 \n",
+ " 1895.0 \n",
+ " 0 \n",
+ " \n",
+ " \n",
+ " 185 \n",
+ " 1 \n",
+ " 1 \n",
+ " 27.780822 \n",
+ " 0 \n",
+ " 1 \n",
+ " 0 \n",
+ " 1 \n",
+ " 0 \n",
+ " 1 \n",
+ " 1 \n",
+ " ... \n",
+ " 0 \n",
+ " 15.41 \n",
+ " 8.077770 \n",
+ " 1.91 \n",
+ " 24.0 \n",
+ " 13.0 \n",
+ " 14.0 \n",
+ " 54.0 \n",
+ " 382.0 \n",
+ " 1 \n",
+ " \n",
+ " \n",
+ " 186 \n",
+ " 1 \n",
+ " 1 \n",
+ " 55.553425 \n",
+ " 1 \n",
+ " 1 \n",
+ " 0 \n",
+ " 1 \n",
+ " 2 \n",
+ " 1 \n",
+ " 1 \n",
+ " ... \n",
+ " 1 \n",
+ " 9.91 \n",
+ " 0.948135 \n",
+ " 10.45 \n",
+ " 37.0 \n",
+ " 18.0 \n",
+ " 20.0 \n",
+ " 1000000.0 \n",
+ " 1109.0 \n",
+ " 0 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
187 rows × 37 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " Recipientgender Stemcellsource Donorage Donorage35 IIIV Gendermatch \\\n",
+ "0 1 1 22.830137 0 1 0 \n",
+ "1 1 0 23.342466 0 1 0 \n",
+ "2 1 0 26.394521 0 1 0 \n",
+ "3 0 0 39.684932 1 1 0 \n",
+ "4 0 1 33.358904 0 0 0 \n",
+ ".. ... ... ... ... ... ... \n",
+ "182 1 1 37.575342 1 1 0 \n",
+ "183 0 1 22.895890 0 0 0 \n",
+ "184 0 1 27.347945 0 1 0 \n",
+ "185 1 1 27.780822 0 1 0 \n",
+ "186 1 1 55.553425 1 1 0 \n",
+ "\n",
+ " DonorABO RecipientABO RecipientRh ABOmatch ... extcGvHD CD34kgx10d6 \\\n",
+ "0 1 1 1 0 ... 1 7.20 \n",
+ "1 -1 -1 1 0 ... 1 4.50 \n",
+ "2 -1 -1 1 0 ... 1 7.94 \n",
+ "3 1 2 1 1 ... None 4.25 \n",
+ "4 1 2 0 1 ... 1 51.85 \n",
+ ".. ... ... ... ... ... ... ... \n",
+ "182 1 1 0 0 ... 1 11.08 \n",
+ "183 1 0 1 1 ... 1 4.64 \n",
+ "184 1 -1 1 1 ... 1 7.73 \n",
+ "185 1 0 1 1 ... 0 15.41 \n",
+ "186 1 2 1 1 ... 1 9.91 \n",
+ "\n",
+ " CD3dCD34 CD3dkgx10d8 Rbodymass ANCrecovery PLTrecovery \\\n",
+ "0 1.338760 5.38 35.0 19.0 51.0 \n",
+ "1 11.078295 0.41 20.6 16.0 37.0 \n",
+ "2 19.013230 0.42 23.4 23.0 20.0 \n",
+ "3 29.481647 0.14 50.0 23.0 29.0 \n",
+ "4 3.972255 13.05 9.0 14.0 14.0 \n",
+ ".. ... ... ... ... ... \n",
+ "182 2.522750 4.39 44.0 15.0 22.0 \n",
+ "183 1.038858 4.47 44.5 12.0 30.0 \n",
+ "184 1.635559 4.73 33.0 16.0 16.0 \n",
+ "185 8.077770 1.91 24.0 13.0 14.0 \n",
+ "186 0.948135 10.45 37.0 18.0 20.0 \n",
+ "\n",
+ " time_to_aGvHD_III_IV survival_time survival_status \n",
+ "0 32.0 999.0 0 \n",
+ "1 1000000.0 163.0 1 \n",
+ "2 1000000.0 435.0 1 \n",
+ "3 19.0 53.0 1 \n",
+ "4 1000000.0 2043.0 0 \n",
+ ".. ... ... ... \n",
+ "182 16.0 385.0 1 \n",
+ "183 1000000.0 634.0 1 \n",
+ "184 1000000.0 1895.0 0 \n",
+ "185 54.0 382.0 1 \n",
+ "186 1000000.0 1109.0 0 \n",
+ "\n",
+ "[187 rows x 37 columns]"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "from rulekit.arff import read_arff\n",
+ "\n",
+ "DATASET_URL: str = (\n",
+ " 'https://raw.githubusercontent.com/'\n",
+ " 'adaa-polsl/RuleKit/master/data/bmt/'\n",
+ " 'bmt.arff'\n",
+ ")\n",
+ "data_df: pd.DataFrame = read_arff(DATASET_URL)\n",
+ "data_df['survival_status'] = data_df['survival_status'].astype(int).astype(str)\n",
+ "data_df\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 378
+ },
+ "id": "y9uVi9SFeZSa",
+ "outputId": "6809c06d-5d8c-48a0-9b6d-3c433574f7f7"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Dataset overview:\n",
+ "Name: bmt\n",
+ "Objects number: 187; Attributes number: 37\n",
+ "Basic attribute statistics:\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " Donorage \n",
+ " Recipientage \n",
+ " CD34kgx10d6 \n",
+ " CD3dCD34 \n",
+ " CD3dkgx10d8 \n",
+ " Rbodymass \n",
+ " ANCrecovery \n",
+ " PLTrecovery \n",
+ " time_to_aGvHD_III_IV \n",
+ " survival_time \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " count \n",
+ " 187.000000 \n",
+ " 187.000000 \n",
+ " 187.000000 \n",
+ " 182.000000 \n",
+ " 182.000000 \n",
+ " 185.000000 \n",
+ " 187.000000 \n",
+ " 187.000000 \n",
+ " 187.000000 \n",
+ " 187.000000 \n",
+ " \n",
+ " \n",
+ " mean \n",
+ " 33.472068 \n",
+ " 9.931551 \n",
+ " 11.891781 \n",
+ " 5.385096 \n",
+ " 4.745714 \n",
+ " 35.801081 \n",
+ " 26752.866310 \n",
+ " 90937.919786 \n",
+ " 775408.042781 \n",
+ " 938.743316 \n",
+ " \n",
+ " \n",
+ " std \n",
+ " 8.271826 \n",
+ " 5.305639 \n",
+ " 9.914386 \n",
+ " 9.598716 \n",
+ " 3.859128 \n",
+ " 19.650922 \n",
+ " 161747.200525 \n",
+ " 288242.407688 \n",
+ " 418425.252689 \n",
+ " 849.589495 \n",
+ " \n",
+ " \n",
+ " min \n",
+ " 18.646575 \n",
+ " 0.600000 \n",
+ " 0.790000 \n",
+ " 0.204132 \n",
+ " 0.040000 \n",
+ " 6.000000 \n",
+ " 9.000000 \n",
+ " 9.000000 \n",
+ " 10.000000 \n",
+ " 6.000000 \n",
+ " \n",
+ " \n",
+ " 25% \n",
+ " 27.039726 \n",
+ " 5.050000 \n",
+ " 5.350000 \n",
+ " 1.786683 \n",
+ " 1.687500 \n",
+ " 19.000000 \n",
+ " 13.000000 \n",
+ " 16.000000 \n",
+ " 1000000.000000 \n",
+ " 168.500000 \n",
+ " \n",
+ " \n",
+ " 50% \n",
+ " 33.550685 \n",
+ " 9.600000 \n",
+ " 9.720000 \n",
+ " 2.734462 \n",
+ " 4.325000 \n",
+ " 33.000000 \n",
+ " 15.000000 \n",
+ " 21.000000 \n",
+ " 1000000.000000 \n",
+ " 676.000000 \n",
+ " \n",
+ " \n",
+ " 75% \n",
+ " 40.117809 \n",
+ " 14.050000 \n",
+ " 15.415000 \n",
+ " 5.823565 \n",
+ " 6.785000 \n",
+ " 50.600000 \n",
+ " 17.000000 \n",
+ " 37.000000 \n",
+ " 1000000.000000 \n",
+ " 1604.000000 \n",
+ " \n",
+ " \n",
+ " max \n",
+ " 55.553425 \n",
+ " 20.200000 \n",
+ " 57.780000 \n",
+ " 99.560970 \n",
+ " 20.020000 \n",
+ " 103.400000 \n",
+ " 1000000.000000 \n",
+ " 1000000.000000 \n",
+ " 1000000.000000 \n",
+ " 3364.000000 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " Donorage Recipientage CD34kgx10d6 CD3dCD34 CD3dkgx10d8 \\\n",
+ "count 187.000000 187.000000 187.000000 182.000000 182.000000 \n",
+ "mean 33.472068 9.931551 11.891781 5.385096 4.745714 \n",
+ "std 8.271826 5.305639 9.914386 9.598716 3.859128 \n",
+ "min 18.646575 0.600000 0.790000 0.204132 0.040000 \n",
+ "25% 27.039726 5.050000 5.350000 1.786683 1.687500 \n",
+ "50% 33.550685 9.600000 9.720000 2.734462 4.325000 \n",
+ "75% 40.117809 14.050000 15.415000 5.823565 6.785000 \n",
+ "max 55.553425 20.200000 57.780000 99.560970 20.020000 \n",
+ "\n",
+ " Rbodymass ANCrecovery PLTrecovery time_to_aGvHD_III_IV \\\n",
+ "count 185.000000 187.000000 187.000000 187.000000 \n",
+ "mean 35.801081 26752.866310 90937.919786 775408.042781 \n",
+ "std 19.650922 161747.200525 288242.407688 418425.252689 \n",
+ "min 6.000000 9.000000 9.000000 10.000000 \n",
+ "25% 19.000000 13.000000 16.000000 1000000.000000 \n",
+ "50% 33.000000 15.000000 21.000000 1000000.000000 \n",
+ "75% 50.600000 17.000000 37.000000 1000000.000000 \n",
+ "max 103.400000 1000000.000000 1000000.000000 1000000.000000 \n",
+ "\n",
+ " survival_time \n",
+ "count 187.000000 \n",
+ "mean 938.743316 \n",
+ "std 849.589495 \n",
+ "min 6.000000 \n",
+ "25% 168.500000 \n",
+ "50% 676.000000 \n",
+ "75% 1604.000000 \n",
+ "max 3364.000000 "
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "print(\"Dataset overview:\")\n",
+ "print(f\"Name: bmt\")\n",
+ "print(f\"Objects number: {data_df.shape[0]}; Attributes number: {data_df.shape[1]}\")\n",
+ "print(\"Basic attribute statistics:\")\n",
+ "data_df.describe()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "dattexxGmaqJ"
+ },
+ "source": [
+ "## Helper function for creating ruleset characteristics dataframe"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "id": "aLCZkT_SmU4a"
+ },
+ "outputs": [],
+ "source": [
+ "def get_ruleset_stats(model) -> pd.DataFrame:\n",
+ " tmp = model.parameters.__dict__\n",
+ " del tmp['_java_object']\n",
+ " return pd.DataFrame.from_records([{**tmp, **model.stats.__dict__}])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "u4wOfecjme_d"
+ },
+ "source": [
+ "## Rule induction on full dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "id": "TrO-LyN2mpiP"
+ },
+ "outputs": [],
+ "source": [
+ "X: pd.DataFrame = data_df.drop(['survival_status'], axis=1)\n",
+ "y: pd.Series = data_df['survival_status']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "id": "c5tmU4IHnFjw"
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " minimum_covered \n",
+ " maximum_uncovered_fraction \n",
+ " ignore_missing \n",
+ " pruning_enabled \n",
+ " max_growing_condition \n",
+ " time_total_s \n",
+ " time_growing_s \n",
+ " time_pruning_s \n",
+ " rules_count \n",
+ " conditions_per_rule \n",
+ " induced_conditions_per_rule \n",
+ " avg_rule_coverage \n",
+ " avg_rule_precision \n",
+ " avg_rule_quality \n",
+ " pvalue \n",
+ " FDR_pvalue \n",
+ " FWER_pvalue \n",
+ " fraction_significant \n",
+ " fraction_FDR_significant \n",
+ " fraction_FWER_significant \n",
+ " \n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 \n",
+ " 0.05 \n",
+ " 0.0 \n",
+ " False \n",
+ " True \n",
+ " 0.0 \n",
+ " 1.771417 \n",
+ " 0.797513 \n",
+ " 0.902853 \n",
+ " 5 \n",
+ " 3.6 \n",
+ " 65.2 \n",
+ " 0.308021 \n",
+ " 1.0 \n",
+ " 0.999865 \n",
+ " 0.000135 \n",
+ " 0.000147 \n",
+ " 0.000184 \n",
+ " 1.0 \n",
+ " 1.0 \n",
+ " 1.0 \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " minimum_covered maximum_uncovered_fraction ignore_missing \\\n",
+ "0 0.05 0.0 False \n",
+ "\n",
+ " pruning_enabled max_growing_condition time_total_s time_growing_s \\\n",
+ "0 True 0.0 1.771417 0.797513 \n",
+ "\n",
+ " time_pruning_s rules_count conditions_per_rule \\\n",
+ "0 0.902853 5 3.6 \n",
+ "\n",
+ " induced_conditions_per_rule avg_rule_coverage avg_rule_precision \\\n",
+ "0 65.2 0.308021 1.0 \n",
+ "\n",
+ " avg_rule_quality pvalue FDR_pvalue FWER_pvalue fraction_significant \\\n",
+ "0 0.999865 0.000135 0.000147 0.000184 1.0 \n",
+ "\n",
+ " fraction_FDR_significant fraction_FWER_significant \n",
+ "0 1.0 1.0 "
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "from rulekit.survival import SurvivalRules\n",
+ "from rulekit.rules import RuleSet, SurvivalRule\n",
+ "\n",
+ "srv = SurvivalRules(survival_time_attr='survival_time')\n",
+ "\n",
+ "srv.fit(X, y)\n",
+ "\n",
+ "ruleset: RuleSet[SurvivalRule] = srv.model\n",
+ "\n",
+ "predictions: np.ndarray = srv.predict(X)\n",
+ "\n",
+ "\n",
+ "ruleset_stats = get_ruleset_stats(ruleset)\n",
+ "\n",
+ "\n",
+ "display(ruleset_stats)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Plot predicted estimators for the first five examples"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "for i in range(5):\n",
+ " plt.step(\n",
+ " predictions[i][\"times\"],\n",
+ " predictions[i][\"probabilities\"],\n",
+ " label=f'Example {i}'\n",
+ " )\n",
+ "plt.legend(title='Example index:')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Plot rules Kaplan-Meier's estimators on top of the training dataset estimator"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "r1: IF Donorage = (-inf, 45.16) AND Relapse = {0} AND Recipientage = (-inf, 17.45) THEN \n",
+ "r2: IF Donorage = (-inf, 43.63) AND HLAmismatch = {0} AND Relapse = {1} THEN \n",
+ "r3: IF PLTrecovery = (-inf, 266) AND time_to_aGvHD_III_IV = <12.50, inf) AND ANCrecovery = <10.50, 19.50) AND Rbodymass = (-inf, 69) AND Donorage = (-inf, 44.06) AND Recipientage = <4.60, inf) AND CD34kgx10d6 = (-inf, 16.98) THEN \n",
+ "r4: IF Donorage = <37.16, inf) AND Recipientage = <5.15, inf) AND time_to_aGvHD_III_IV = <23.50, inf) AND CD3dCD34 = <0.90, 73.72) THEN \n",
+ "r5: IF Recipientage = <17.85, 18.85) THEN \n"
+ ]
+ },
+ {
+ "data": {
+ "image/png": "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Fi1sjomKikJRUREAoKioyO59srwmV5bY7b236u+9TZs2Nq+HhISgVatWNvt06NCh1jksr7Vs2dIt8btaeno6/vd//xcdOnTA2bNn8eqrr2Lw4MHIzs5GcHCw394Lk8mEadOmYdCgQejVqxcAuOz3oq59SktLodPpoFar3fGWGs3evQCAESNGoH379oiNjcXx48cxc+ZM5OTkYNOmTQD8616cOHECycnJKC8vR1hYGL788kv07NkTx44dC7jPRF33AvCtz0TAJTCBZPDgwdafe/fujaSkJLRv3x6fffaZT/2ykHc98cQT1p/j4+PRu3dvdOrUCVlZWbjvvvu8GJl7TZ48GSdPnsR3333n7VC8rq57MWHCBOvP8fHxiImJwX333YezZ8+iU6dOng7Trbp164Zjx46hpKQEn3/+OcaOHYu9e/d6OyyvqOte9OzZ06c+EwHXhBQZGYng4OBaPciLi4sRHR3tpag8o0WLFujatSvOnDmD6OhoGAwGXL161Waf6vchOjra7n2yvCZXltjr+wxER0fj4sWLNq9XVlbiypUrfn9/OnbsiMjISJw5cwaAf96LKVOm4F//+hf27NmDW2+91brdVb8Xde0THh7uc3881HUv7ElKSgIAm8+Gv9wLpVKJzp07IzExEZmZmejTpw+WLl0akJ+Juu6FPd78TARcAqNUKpGYmIhdu3ZZt5lMJuzatcumjc8fXb9+HWfPnkVMTAwSExOhUChs7kNOTg7y8/Ot9yE5ORknTpyw+fLasWMHwsPDreVEOerQoQOio6Nt3ntpaSkOHDhg896vXr2Kw4cPW/fZvXs3TCaT9Rc2OTkZ3377LSoqKqz77NixA926dfPJJhNH/frrr/j9998RExMDwL/uhRACU6ZMwZdffondu3fXavZy1e9FcnKyzTks+/jSvzEN3Qt7jh07BgA2nw1/uBf2mEwm6PX6gPpM1MVyL+zx6mfCqS6/fmLDhg1CpVKJNWvWiJ9++klMmDBBtGjRwqbXtD946aWXRFZWlsjNzRX79u0TqampIjIyUly8eFEIYR4a2K5dO7F7925x6NAhkZycLJKTk63HW4bD3X///eLYsWNi27ZtonXr1rIYRn3t2jVx9OhRcfToUQFAvPPOO+Lo0aPi/PnzQgjzMOoWLVqIf/7zn+L48ePiwQcftDuMul+/fuLAgQPiu+++E126dLEZOnz16lURFRUlRo8eLU6ePCk2bNggNBqNzw0dru9eXLt2TcyYMUNkZ2eL3NxcsXPnTpGQkCC6dOkiysvLrefwl3sxadIkERERIbKysmyGgZaVlVn3ccXvhWWY6MsvvyxOnTolli1b5nNDZhu6F2fOnBELFiwQhw4dErm5ueKf//yn6Nixo7j77rut5/CXezFr1iyxd+9ekZubK44fPy5mzZolJEkS33zzjRAicD4TQtR/L3ztMxGQCYwQQrz33nuiXbt2QqlUigEDBoj9+/d7OySXGzZsmIiJiRFKpVK0bdtWDBs2TJw5c8b6uk6nE88995xo2bKl0Gg04uGHHxaFhYU258jLyxODBw8WarVaREZGipdeeklUVFR4+q04bc+ePQJArcfYsWOFEOah1K+99pqIiooSKpVK3HfffSInJ8fmHL///rsYPny4CAsLE+Hh4WLcuHHi2rVrNvv88MMP4s477xQqlUq0bdtWLFq0yFNv0WH13YuysjJx//33i9atWwuFQiHat28vxo8fXyuZ95d7Ye8+ABCrV6+27uOq34s9e/aIvn37CqVSKTp27GhzDV/Q0L3Iz88Xd999t2jVqpVQqVSic+fO4uWXX7aZ80MI/7gXTz31lGjfvr1QKpWidevW4r777rMmL0IEzmdCiPrvha99JiQhhHCuZkNERETkXQHXB4aIiIjkjwkMERERyQ4TGCIiIpIdJjBEREQkO0xgiIiISHaYwBAREZHsMIEhIiIi2WECQ0RERLLDBIaIiIhkhwkMERERyQ4TGCIiIpIdJjBEREQkO/8fqX4vTbPH7I4AAAAASUVORK5CYII=",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "from rulekit.kaplan_meier import KaplanMeierEstimator\n",
+ "\n",
+ "# plot rules kaplan-meier curves\n",
+ "for i, rule in enumerate(ruleset.rules):\n",
+ " rule_label: str = f'r{i + 1}'\n",
+ " rule_km: KaplanMeierEstimator = rule.kaplan_meier_estimator\n",
+ " plt.step(\n",
+ " rule_km.times,\n",
+ " rule_km.probabilities,\n",
+ " label=rule_label\n",
+ " )\n",
+ " print(f'{rule_label}: {rule}')\n",
+ "\n",
+ "# plot whole dataset kaplan-meier curve\n",
+ "train_km: KaplanMeierEstimator = srv.get_train_set_kaplan_meier()\n",
+ "plt.step(\n",
+ " train_km.times,\n",
+ " train_km.probabilities,\n",
+ " label='Training set estimator'\n",
+ ")\n",
+ "\n",
+ "plt.legend()\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "GkNBc5iBpwmj"
+ },
+ "source": [
+ "### Rules evaluation on full set"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "id": "9UjrC8r-p59d"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Integrated Brier Score: 0.19651358709002972\n"
+ ]
+ }
+ ],
+ "source": [
+ "integrated_brier_score = srv.score(X, y)\n",
+ "print(f'Integrated Brier Score: {integrated_brier_score}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "FpoSoaKdqAGQ"
+ },
+ "source": [
+ "## Stratified K-Folds cross-validation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "id": "0nNv6a84qTsq"
+ },
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import StratifiedKFold\n",
+ "from rulekit.exceptions import RuleKitJavaException\n",
+ "\n",
+ "skf = StratifiedKFold(n_splits=10, shuffle=True, random_state=0)\n",
+ "\n",
+ "ruleset_stats = pd.DataFrame()\n",
+ "survival_metrics = []\n",
+ "\n",
+ "for train_index, test_index in skf.split(X, y):\n",
+ " X_train, X_test = X.iloc[train_index], X.iloc[test_index]\n",
+ " y_train, y_test = y.iloc[train_index], y.iloc[test_index]\n",
+ "\n",
+ " srv = SurvivalRules(\n",
+ " survival_time_attr='survival_time'\n",
+ " )\n",
+ " srv.fit(X_train, y_train)\n",
+ "\n",
+ " ruleset = srv.model\n",
+ "\n",
+ " ibs: float = srv.score(X_test, y_test)\n",
+ "\n",
+ " survival_metrics.append(ibs)\n",
+ " ruleset_stats = pd.concat([ruleset_stats, get_ruleset_stats(ruleset)])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "MfCOH_f3sICm"
+ },
+ "source": [
+ "Ruleset characteristics (average)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "id": "xzbazr51sRd3"
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "minimum_covered 0.050000\n",
+ "maximum_uncovered_fraction 0.000000\n",
+ "ignore_missing 0.000000\n",
+ "pruning_enabled 1.000000\n",
+ "max_growing_condition 0.000000\n",
+ "time_total_s 0.799019\n",
+ "time_growing_s 0.296248\n",
+ "time_pruning_s 0.477474\n",
+ "rules_count 4.000000\n",
+ "conditions_per_rule 2.581667\n",
+ "induced_conditions_per_rule 59.825000\n",
+ "avg_rule_coverage 0.486613\n",
+ "avg_rule_precision 1.000000\n",
+ "avg_rule_quality 0.995955\n",
+ "pvalue 0.004045\n",
+ "FDR_pvalue 0.004061\n",
+ "FWER_pvalue 0.004104\n",
+ "fraction_significant 0.980000\n",
+ "fraction_FDR_significant 0.980000\n",
+ "fraction_FWER_significant 0.980000\n",
+ "dtype: float64"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(ruleset_stats.mean())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "_SmDJho4sVEO"
+ },
+ "source": [
+ "Rules evaluation on dataset (average)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "id": "Co-fNd9nshWB"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Integrated Brier Score: 0.20178456199764142\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(f'Integrated Brier Score: {np.mean(survival_metrics)}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "d-GdQ-wUtzW9"
+ },
+ "source": [
+ "## Hyperparameters tuning\n",
+ "\n",
+ "This one gonna take a while..."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import StratifiedKFold\n",
+ "from sklearn.model_selection import GridSearchCV"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def scorer(estimator: SurvivalRules, X: pd.DataFrame, y: pd.Series) -> float:\n",
+ " return -1 * estimator.score(X, y)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Best Integrated Brier Score: -0.21437408819868886 using {'minsupp_new': 3, 'survival_time_attr': 'survival_time'}\n"
+ ]
+ }
+ ],
+ "source": [
+ "# define models and parameters\n",
+ "model = SurvivalRules(survival_time_attr='survival_time')\n",
+ "\n",
+ "# define grid search\n",
+ "grid = {\n",
+ " 'survival_time_attr': ['survival_time'],\n",
+ " 'minsupp_new': range(1, 10),\n",
+ "}\n",
+ "\n",
+ "cv = StratifiedKFold(n_splits=3)\n",
+ "grid_search = GridSearchCV(estimator=model, param_grid=grid, cv=cv, scoring=scorer)\n",
+ "grid_result = grid_search.fit(X, y)\n",
+ "\n",
+ "# summarize results\n",
+ "print(\n",
+ " 'Best Integrated Brier Score: '\n",
+ " f'{grid_result.best_score_} using {grid_result.best_params_}'\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Building model with tuned hyperparameters\n",
+ "\n",
+ "### Split dataset to train and test (80%/20%)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sklearn.model_selection import train_test_split\n",
+ "\n",
+ "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=True, stratify=y)\n",
+ "\n",
+ "srv = SurvivalRules(\n",
+ " survival_time_attr='survival_time',\n",
+ " minsupp_new=5\n",
+ ")\n",
+ "srv.fit(X_train, y_train)\n",
+ "ruleset: RuleSet[SurvivalRule] = srv.model\n",
+ "ruleset_stats: pd.DataFrame = get_ruleset_stats(ruleset)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Rules evaluation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "minimum_covered 5.0\n",
+ "maximum_uncovered_fraction 0.0\n",
+ "ignore_missing False\n",
+ "pruning_enabled True\n",
+ "max_growing_condition 0.0\n",
+ "time_total_s 0.594173\n",
+ "time_growing_s 0.244234\n",
+ "time_pruning_s 0.312523\n",
+ "rules_count 4\n",
+ "conditions_per_rule 2.25\n",
+ "induced_conditions_per_rule 55.25\n",
+ "avg_rule_coverage 0.389262\n",
+ "avg_rule_precision 1.0\n",
+ "avg_rule_quality 1.0\n",
+ "pvalue 0.0\n",
+ "FDR_pvalue 0.0\n",
+ "FWER_pvalue 0.0\n",
+ "fraction_significant 1.0\n",
+ "fraction_FDR_significant 1.0\n",
+ "fraction_FWER_significant 1.0\n",
+ "Name: 0, dtype: object"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "display(ruleset_stats.iloc[0])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Validate model on test dataset"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Integrated Brier Score: 0.14054870564224475\n"
+ ]
+ }
+ ],
+ "source": [
+ "integrated_brier_score = srv.score(X_test, y_test)\n",
+ "print(f'Integrated Brier Score: {integrated_brier_score}')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "predictions = srv.predict(X_test)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Text(0.5, 1.0, 'Predicted Kaplan-Meier curves for 5 examples from test set')"
+ ]
+ },
+ "execution_count": 29,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "for i in range(5):\n",
+ " plt.step(\n",
+ " predictions[i][\"times\"], \n",
+ " predictions[i][\"probabilities\"],\n",
+ " label=f'Example {i}'\n",
+ " )\n",
+ "plt.legend(title='Examples indices:')\n",
+ "plt.title('Predicted Kaplan-Meier curves for 5 examples from test set')"
+ ]
+ }
+ ],
+ "metadata": {
+ "colab": {
+ "collapsed_sections": [],
+ "name": "Raport_przezyciowy.ipynb",
+ "provenance": [],
+ "toc_visible": true
+ },
+ "kernelspec": {
+ "display_name": "tutorials_env",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.0"
+ },
+ "metadata": {
+ "interpreter": {
+ "hash": "62266c16fff41e971c13e9cb2ad3d47e4ef45d0678714c255381eb9fdcbd7032"
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/docs/serve/v2.1.24.0/rst/whats_new/Changes in this version.html b/docs/serve/v2.1.24.0/rst/whats_new/Changes in this version.html
new file mode 100644
index 0000000..54d47cb
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/whats_new/Changes in this version.html
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+ What’s new in RuleKit version 2.1.24.0? — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rulekit v2.1.24.0
+
+
+
+
+
+
+
+
+
+What’s new in RuleKit version 2.1.24.0?
+
+1. Revert breaking changes in expert rules induction for regression and survival
+The latest version 2.1.21.0 introduced some groundbreaking changes, which you can read more about them in the latest release note . Now rules and expert conditions can be defined in both the old and new formats, see example below.
+
+
+
+2. Upgrade to new version of RuleKit
+In the new version of the Java RuleKit library, many bugs regarding expert induction have been corrected.
+
+
+Other changes
+
+Improve flake8 score
+Add more unit tests.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/rst/whats_new/Changes in this version.ipynb b/docs/serve/v2.1.24.0/rst/whats_new/Changes in this version.ipynb
new file mode 100644
index 0000000..ff53bfc
--- /dev/null
+++ b/docs/serve/v2.1.24.0/rst/whats_new/Changes in this version.ipynb
@@ -0,0 +1,83 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# What's new in RuleKit version 2.1.24.0?\n",
+ "\n",
+ "\n",
+ "### 1. Revert breaking changes in expert rules induction for regression and survival \n",
+ "The latest version 2.1.21.0 introduced some groundbreaking changes, which you can read more\n",
+ "about them in the latest [release note](https://github.com/adaa-polsl/RuleKit-python/releases/tag/v2.1.21.0).\n",
+ "Now rules and expert conditions can be defined in both the old and new formats, see example below."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2024-11-28T13:38:58.094582Z",
+ "iopub.status.busy": "2024-11-28T13:38:58.093584Z",
+ "iopub.status.idle": "2024-11-28T13:38:58.117835Z",
+ "shell.execute_reply": "2024-11-28T13:38:58.114783Z"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# both variants will work the same\n",
+ "expert_rules = [\n",
+ " (\n",
+ " 'rule-0',\n",
+ " 'IF [[CD34kgx10d6 = (-inf, 10.0)]] AND [[extcGvHD = {0}]] THEN survival_status = {NaN}'\n",
+ " ),\n",
+ " (\n",
+ " 'rule-0',\n",
+ " 'IF [[CD34kgx10d6 = (-inf, 10.0)]] AND [[extcGvHD = {0}]] THEN'\n",
+ " ),\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 2. Upgrade to new version of RuleKit\n",
+ "\n",
+ "In the new version of the Java RuleKit library, many bugs regarding expert induction have been corrected."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Other changes\n",
+ "\n",
+ "* Improve flake8 score\n",
+ "* Add more unit tests."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "tutorials_env",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.10"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/docs/serve/v2.1.24.0/search.html b/docs/serve/v2.1.24.0/search.html
new file mode 100644
index 0000000..4ed231d
--- /dev/null
+++ b/docs/serve/v2.1.24.0/search.html
@@ -0,0 +1,129 @@
+
+
+
+
+
+ Search — rulekit v2.1.24.0 f documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rulekit v2.1.24.0
+
+
+
+
+
+
+
+
+
+
+
+ Please activate JavaScript to enable the search functionality.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/serve/v2.1.24.0/searchindex.js b/docs/serve/v2.1.24.0/searchindex.js
new file mode 100644
index 0000000..4f20c58
--- /dev/null
+++ b/docs/serve/v2.1.24.0/searchindex.js
@@ -0,0 +1 @@
+Search.setIndex({"docnames": ["index", "rst/autodoc", "rst/autodoc/classification", "rst/autodoc/params", "rst/autodoc/regression", "rst/autodoc/rules", "rst/autodoc/stats", "rst/autodoc/survival", "rst/quick_start", "rst/tutorials", "rst/tutorials/classification", "rst/tutorials/expert_rules", "rst/tutorials/regression", "rst/tutorials/survival", "rst/whats_new/Changes in this version"], "filenames": ["index.rst", "rst/autodoc.rst", "rst/autodoc/classification.rst", "rst/autodoc/params.rst", "rst/autodoc/regression.rst", "rst/autodoc/rules.rst", "rst/autodoc/stats.rst", "rst/autodoc/survival.rst", "rst/quick_start.rst", "rst/tutorials.rst", "rst/tutorials/classification.ipynb", "rst/tutorials/expert_rules.ipynb", "rst/tutorials/regression.ipynb", "rst/tutorials/survival.ipynb", "rst/whats_new/Changes in this version.ipynb"], "titles": ["RuleKit", "Code documentation", "Classification", "Parameters", "Regression", "Rules", "Statistics", "Survival", "Quick start", "Tutorials", "Classification", "Expert Rules", "Regression", "Survival analysis", "What\u2019s new in RuleKit version 2.1.24.0?"], "terms": {"thi": [0, 1, 2, 4, 7, 8, 10, 11, 12, 13], "packag": [0, 1, 10, 12, 13], "i": [0, 1, 2, 4, 6, 7, 8, 11, 12, 13], "python": [0, 1], "wrapper": [0, 1, 8], "librari": [0, 8, 14], "versatil": 0, "tool": 0, "rule": [0, 1, 2, 3, 4, 6, 7, 9], "learn": [0, 2, 4, 7, 8], "base": [0, 3, 4, 5], "sequenti": 0, "cover": [0, 2, 4, 5, 6, 7, 10, 12, 13], "induct": [0, 1, 2, 3, 4, 5, 7], "algorithm": [0, 11], "suitabl": 0, "classif": [0, 1, 4, 5, 7, 8, 9], "regress": [0, 1, 5, 9], "surviv": [0, 1, 5, 9], "problem": [0, 2, 4, 7, 10, 11, 12, 13], "aim": 0, "give": 0, "an": [0, 2, 11], "easi": 0, "wai": 0, "integr": [0, 7, 13], "function": [0, 7], "project": 0, "notebook": [0, 10, 11, 12, 13], "all": [0, 2, 5, 7], "model": [0, 2, 3, 4, 7, 8, 11], "ar": [0, 2, 4, 5, 7, 8], "writen": 0, "compat": [0, 2, 4, 7], "scikit": [0, 2, 4, 7, 8], "quick": 0, "start": [0, 1], "what": 0, "new": [0, 2, 4, 7], "tutori": [0, 8, 10, 11, 12, 13], "code": 0, "document": 0, "contain": [1, 2, 3, 4, 5, 6, 7], "class": [1, 2, 3, 4, 5, 6, 7, 11], "initi": [1, 2, 4, 7, 11], "rulekit": [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13], "java": [1, 8, 14], "backend": 1, "main": 1, "us": [1, 2, 3, 4, 5, 7, 8, 10, 13], "It": [1, 8], "jvm": 1, "underhood": 1, "setup": 1, "jar": 1, "sinc": 1, "version": [1, 8, 12], "1": [1, 2, 4, 7, 10, 11, 12, 13], "7": [1, 10, 11, 12, 13], "0": [1, 2, 4, 6, 7, 10, 11, 12, 13], "need": 1, "manual": 1, "you": [1, 3, 8, 10, 11, 12, 13, 14], "mai": [1, 2, 4, 7, 8], "just": [1, 2], "skip": 1, "init": 1, "line": 1, "howev": 1, "certain": [1, 2, 4, 7], "scenario": 1, "when": [1, 2, 7], "want": 1, "custom": 1, "file": 1, "modifi": 1, "vm": 1, "paramet": [1, 2, 4, 5, 7, 8, 10, 12, 13], "can": [1, 2, 3, 4, 7, 8, 10, 12, 13, 14], "equal": [1, 10], "type": [1, 2, 3, 4, 5, 6, 7], "str": [1, 2, 4, 5, 7, 10, 11, 12, 13], "static": 1, "configure_java_logg": 1, "log_file_path": 1, "verbosity_level": 1, "int": [1, 2, 4, 6, 7, 10, 11, 13], "enabl": [1, 2, 4, 7], "debug": 1, "log": 1, "probabl": [1, 2, 7, 13], "don": [1, 8], "t": [1, 2, 4, 5, 7, 8], "method": [1, 2], "unless": 1, "too": 1, "deep": [1, 2, 4, 7], "dive": 1, "process": 1, "your": [1, 8], "re": 1, "some": [1, 2, 14], "issu": 1, "path": 1, "where": [1, 2, 4, 7], "store": 1, "option": [1, 2], "verbos": 1, "level": [1, 5, 6], "minimum": [1, 2, 4, 7], "valu": [1, 2, 3, 4, 5, 6, 7, 10], "maximum": [1, 2, 4, 7], "2": [1, 2, 4, 10, 11, 12, 13], "default": [1, 2, 4, 6, 7], "get_java_logger_config": 1, "_rulekitjavaloggerconfig": 1, "none": [1, 2, 4, 7, 13], "return": [1, 2, 4, 5, 7, 10, 12, 13], "logger": 1, "configur": 1, "initial_heap_s": 1, "max_heap_s": 1, "rulekit_jar_file_path": 1, "load": 1, "have": [1, 8, 14], "call": [1, 8], "befor": 1, "ani": [1, 2, 4, 7, 11], "oper": [1, 2, 3, 4, 7], "heap": 1, "size": [1, 10], "mb": 1, "max": [1, 10, 12, 13], "note": [1, 2, 14], "own": 1, "otherwis": [1, 2], "leav": 1, "offici": 1, "releas": [1, 14], "rais": [1, 2, 4, 7], "except": [1, 11, 13], "If": [1, 2, 4, 7, 8], "fail": 1, "statist": [1, 5, 10, 12, 13], "ruleclassifi": [2, 4, 7, 8, 10, 11], "minsupp_new": [2, 4, 7, 10, 11, 12, 13], "float": [2, 4, 5, 6, 7, 10, 13], "05": [2, 4, 6, 7, 10, 11, 12, 13], "induction_measur": [2, 4, 5, 10, 12], "measur": [2, 3, 4, 5], "correl": [2, 3, 4], "pruning_measur": [2, 4, 5, 10, 12], "voting_measur": [2, 4, 5, 10, 12], "max_grow": [2, 4, 7, 11], "enable_prun": [2, 4, 7], "bool": [2, 4, 5, 7], "true": [2, 4, 7, 8, 10, 11, 12, 13], "ignore_miss": [2, 4, 7, 12, 13], "fals": [2, 4, 5, 6, 7, 10, 11, 12, 13], "max_uncovered_fract": [2, 4, 7], "select_best_candid": [2, 4, 7], "complementary_condit": [2, 4, 7], "control_apriori_precis": 2, "max_rule_count": [2, 4, 7], "approximate_induct": 2, "approximate_bins_count": 2, "100": 2, "5": [2, 4, 7, 10, 11, 12, 13], "number": [2, 4, 5, 6, 7, 12, 13], "fraction": [2, 4, 5, 6, 7], "previous": [2, 4, 7], "uncov": [2, 4, 7], "exampl": [2, 4, 7, 8, 10, 11, 12, 14], "posit": [2, 4, 5, 6, 7, 10], "param": [2, 3, 4, 10, 12], "dure": [2, 3, 4, 5], "union": [2, 3, 4, 5, 7], "prune": [2, 3, 4, 5, 6, 7], "could": [2, 4, 7], "user": [2, 4, 10, 11, 12], "defin": [2, 4, 10, 12, 13, 14], "string": [2, 4, 7], "p": [2, 4, 5, 6], "n": [2, 4, 6, 10], "vote": [2, 3, 4, 5, 10], "non": [2, 4, 7], "neg": [2, 4, 5, 6, 7, 10], "integ": [2, 4, 7], "repres": [2, 4, 5, 7], "condit": [2, 4, 5, 6, 7, 14], "which": [2, 4, 7, 11, 14], "ad": [2, 4, 7], "grow": [2, 4, 5, 6, 7], "phase": [2, 4, 7], "larg": [2, 4, 7], "dataset": [2, 4, 7, 8], "execut": [2, 4, 7], "time": [2, 4, 5, 6, 7, 13], "prohibit": [2, 4, 7], "indic": [2, 4, 5, 7, 13], "limit": [2, 4, 7], "disabl": [2, 4, 7], "boolean": [2, 4, 7], "tell": [2, 4, 7], "whether": [2, 4, 5, 7], "miss": [2, 4, 7], "should": [2, 4, 7, 8], "ignor": [2, 4, 7], "valueof": 2, "given": [2, 4, 7], "attribut": [2, 4, 7, 11, 12, 13], "alwai": [2, 4, 7], "cconsid": 2, "fulfil": [2, 4, 7], "build": [2, 4, 7], "upon": [2, 4, 7], "point": [2, 4, 7], "from": [2, 4, 5, 7, 8, 10, 11, 13], "interv": [2, 4, 7], "remain": [2, 4, 7], "set": [2, 4, 5, 6, 7, 8, 11], "flag": [2, 4, 7], "determin": [2, 4, 7], "best": [2, 4, 7, 10, 12, 13], "candid": [2, 4, 7], "select": [2, 4, 7], "complementari": [2, 4, 7], "form": [2, 4, 7], "nomin": [2, 4, 7], "support": [2, 4, 7, 8], "induc": [2, 4, 5, 6, 7], "verifi": 2, "precis": [2, 3, 5, 6, 10], "higher": 2, "than": 2, "apriori": 2, "investig": 2, "gener": [2, 4, 7], "data": [2, 3, 4, 7, 8, 10, 11, 12, 13], "appli": [2, 4, 7], "singl": [2, 4, 5, 6, 7], "approxim": 2, "heurist": 2, "doe": 2, "check": [2, 8], "possibl": 2, "split": 2, "experiment": 2, "featur": 2, "current": 2, "work": [2, 14], "onli": 2, "result": [2, 4, 7, 10, 12, 13], "chang": [2, 10, 12, 13], "futur": 2, "bin": 2, "evalu": [2, 3, 10], "add_event_listen": [2, 4, 7], "listen": [2, 4, 7], "ruleinductionprogresslisten": [2, 4, 7], "add": [2, 4, 7, 14], "event": [2, 4, 7], "object": [2, 4, 5, 7, 12, 13], "allow": [2, 4, 7, 11], "monitor": [2, 4, 7], "progress": [2, 4, 7], "import": [2, 4, 7, 8, 10, 11, 12, 13], "myeventlisten": [2, 4, 7], "def": [2, 4, 7, 10, 12, 13], "on_new_rul": [2, 4, 7], "self": [2, 4, 7], "print": [2, 4, 5, 7, 8, 10, 11, 12, 13], "do": [2, 4, 7], "someth": [2, 4, 7], "fit": [2, 4, 7, 8, 10, 11, 12, 13], "ndarrai": [2, 3, 4, 7, 10, 12, 13], "datafram": [2, 3, 4, 7, 10, 11, 12], "list": [2, 3, 4, 5, 7, 11], "label": [2, 4, 7, 10, 13], "train": [2, 4, 5, 6, 7, 8, 11], "get_coverage_matrix": [2, 4, 7], "calcul": [2, 4, 7, 13], "coverag": [2, 3, 4, 5, 6, 7], "matrix": [2, 4, 7, 10], "ruleset": [2, 4, 5, 6, 7, 10, 11, 12], "coverage_matrix": [2, 4, 7], "each": [2, 3, 4, 7, 11], "row": [2, 4, 7, 10, 11, 13], "everi": [2, 4, 7], "column": [2, 4, 7, 10, 11, 13], "cell": [2, 4, 7], "mean": [2, 4, 7, 8, 10, 12, 13], "doesn": [2, 4, 7], "np": [2, 4, 7, 10, 12, 13], "get_metadata_rout": [2, 4, 7], "metadata": [2, 4, 7], "rout": [2, 4, 7], "yet": [2, 4, 7], "notimplementederror": [2, 4, 7], "_description_": [2, 4, 7], "get_param": [2, 4, 7], "dict": [2, 4, 5, 7, 10], "Not": [2, 4, 7], "hyperparamet": [2, 4, 7], "dictionari": [2, 4, 5, 7, 10, 12], "predict": [2, 4, 7, 8, 10], "return_metr": [2, 10], "tupl": [2, 4, 7, 10, 11], "classificationpredictionmetr": 2, "perform": [2, 4, 7], "addit": [2, 11], "metric": [2, 6, 8, 13], "instead": [2, 4], "wasn": 2, "first": [2, 4, 7], "element": [2, 4, 7], "being": 2, "second": [2, 4, 5, 6, 7], "one": [2, 4, 7, 10, 12, 13], "predict_proba": 2, "score": [2, 4, 7, 10, 12, 13, 14], "accuraci": [2, 3, 8, 10], "test": [2, 7, 14], "wrt": [2, 4, 7], "set_param": [2, 4, 7], "kwarg": [2, 4, 7], "same": [2, 4, 7, 8, 14], "constructor": [2, 4, 7], "expertruleclassifi": [2, 11], "extend_using_pref": [2, 4, 7, 11], "extend_using_automat": [2, 4, 7, 11], "induce_using_pref": [2, 4, 7, 11], "induce_using_automat": [2, 4, 7, 11], "consider_other_class": 2, "preferred_conditions_per_rul": [2, 4, 7], "2147483647": [2, 4, 7], "preferred_attributes_per_rul": [2, 4, 7], "expert": [2, 4, 7, 9], "knowledg": 2, "consid": [2, 4, 7], "extend": [2, 4, 7], "prefer": [2, 4, 7, 11], "automat": [2, 4, 7], "": [2, 5, 10, 12], "ha": [2, 11], "been": [2, 14], "per": [2, 4, 6, 7, 10], "unlimit": [2, 4, 7], "expert_rul": [2, 4, 7, 11, 14], "expert_preferred_condit": [2, 4, 7, 11], "expert_forbidden_condit": [2, 4, 7, 11], "either": [2, 4, 7], "pass": [2, 4, 7], "name": [2, 4, 7, 12, 13], "multiset": [2, 4, 7], "also": [2, 4, 7], "specifi": [2, 4, 7], "special": [2, 4, 7], "forbidden": [2, 4, 7, 11], "alia": 3, "numpi": [3, 10, 12, 13], "panda": [3, 7, 10, 11, 12, 13], "core": 3, "frame": 3, "constant": 3, "specyf": 3, "enum": 3, "differ": [3, 7], "ream": 3, "more": [3, 8, 14], "about": [3, 5, 7, 14], "its": [3, 8], "implement": [3, 8], "41": [3, 10, 11, 12, 13], "qualiti": [3, 5, 6], "_": 3, "here": [3, 10, 12, 13], "http": [3, 10, 11, 12, 13], "github": 3, "com": [3, 10, 11, 12, 13], "adaa": [3, 10, 11, 12, 13], "polsl": [3, 10, 11, 12, 13], "wiki": 3, "4": [3, 10, 11, 12, 13], "binaryentropi": 3, "c1": 3, "c2": 3, "cfoil": 3, "cn2significnc": 3, "fbayesianconfirm": 3, "fmeasur": 3, "fullcoverag": 3, "georss": 3, "gmeasur": 3, "informationgain": 3, "jmeasur": 3, "kappa": [3, 10], "klosgen": 3, "laplac": 3, "lift": [3, 10], "logicalsuffici": 3, "mestim": 3, "mutualsupport": 3, "novelti": 3, "oddsratio": 3, "onewaysupport": 3, "pawlakdependencyfactor": 3, "q2": 3, "relativerisk": 3, "ripper": 3, "ruleinterest": 3, "rss": 3, "sbayesian": 3, "sensit": [3, 10], "specif": [3, 10], "twowaysupport": 3, "weightedlaplac": [3, 10], "weightedrelativeaccuraci": 3, "yail": 3, "logrank": 3, "ruleregressor": [4, 12], "mean_based_regress": [4, 11, 12], "fast": 4, "median": 4, "target": [4, 8], "coeffici": 4, "r2": [4, 13], "expertruleregressor": [4, 11], "valy": [4, 7], "baserul": 5, "java_object": 5, "get_covering_inform": 5, "inform": 5, "covering_data": 5, "print_stat": 5, "format": [5, 14], "text": [5, 13], "properti": 5, "pvalu": [5, 6, 10, 12, 13], "signific": [5, 6], "stat": [5, 6, 10, 12, 13], "rulestatist": [5, 6], "weight": [5, 6], "weighted_n": 5, "account": [5, 6], "weighted_p": 5, "classificationrul": [5, 10, 11], "decision_class": 5, "decis": 5, "inductionparamet": 5, "regressionrul": [5, 11, 12], "conclusion_valu": 5, "conclus": 5, "calculate_avg_rule_coverag": 5, "count": [5, 10, 12, 13], "averag": [5, 6, 10, 13], "calculate_avg_rule_precis": 5, "calculate_avg_rule_qu": 5, "calculate_conditions_count": 5, "calculate_induced_conditions_count": 5, "calculate_signific": 5, "alpha": 5, "calculate_significance_fdr": 5, "discoveri": [5, 6], "rate": [5, 6], "correct": [5, 6, 14], "two": 5, "field": 5, "assum": [5, 6], "calculate_significance_fw": 5, "familii": [5, 6], "wise": [5, 6], "error": [5, 6, 7, 8, 12], "growing_tim": 5, "is_vot": 5, "pruning_tim": 5, "rulesetstatist": [5, 6], "total_tim": 5, "construct": [5, 6], "survivalrul": [5, 7, 11, 13], "kaplan_meier_estim": [5, 13], "kaplanmeierestim": [5, 7, 13], "kaplan": 5, "meier": 5, "estim": [5, 7, 10, 12], "concslus": 5, "describ": [6, 10, 12, 13], "significance_level": 6, "time_total_": [6, 10, 12, 13], "time_growing_": [6, 10, 12, 13], "time_pruning_": [6, 10, 12, 13], "rules_count": [6, 10, 12, 13], "conditions_per_rul": [6, 10, 12, 13], "induced_conditions_per_rul": [6, 10, 12, 13], "avg_rule_coverag": [6, 10, 12, 13], "avg_rule_precis": [6, 10, 12, 13], "avg_rule_qu": [6, 10, 12, 13], "fdr_pvalu": [6, 10, 12, 13], "fwer_pvalu": [6, 10, 12, 13], "fraction_signific": [6, 10, 12, 13], "fraction_fdr_signific": [6, 10, 12, 13], "fraction_fwer_signific": [6, 10, 12, 13], "survival_time_attr": [7, 11, 13], "padna": 7, "survival_tim": [7, 11, 13], "statu": 7, "omit": 7, "wa": [7, 8], "get_train_set_kaplan_mei": [7, 13], "kaplanmei": 7, "correspond": 7, "brier": [7, 13], "ib": [7, 13], "b": [7, 11], "squar": [7, 12], "between": 7, "summar": [7, 10, 12, 13], "over": 7, "observ": 7, "expertsurvivalrul": [7, 11], "requir": 8, "develop": 8, "kit": 8, "8": [8, 10, 11, 12, 13], "later": 8, "comput": 8, "both": [8, 14], "open": 8, "jdk": 8, "oracl": 8, "quickli": 8, "up": 8, "pip": [8, 10, 13], "11": [8, 10, 11, 12, 13], "jre": 8, "To": [8, 12], "everyth": 8, "correctli": 8, "__version__": 8, "run": 8, "without": 8, "now": [8, 14], "we": 8, "final": 8, "readi": 8, "sklearn": [8, 10, 12, 13], "iri": 8, "load_iri": 8, "x": [8, 10, 11, 13], "y": [8, 10, 11, 13], "classifi": 8, "accuracy_scor": [8, 10], "As": 8, "notic": 8, "easili": 8, "cross": 8, "valid": 8, "hyper": 8, "tune": 8, "etc": 8, "For": 8, "head": [8, 10, 11], "section": 8, "present": [10, 11, 12, 13], "usag": [10, 11, 12, 13], "solv": [10, 12, 13], "seismic": [10, 11], "bump": [10, 11], "access": [10, 13], "topic": [10, 12, 13], "get": [10, 12], "inbuilt": [10, 12], "matplotlib": [10, 13], "pd": [10, 11, 12, 13], "arff": [10, 11, 12, 13], "read_arff": [10, 11, 12, 13], "dataset_url": [10, 13], "raw": [10, 11, 12, 13], "githubusercont": [10, 11, 12, 13], "ref": [10, 11], "master": [10, 11, 12, 13], "df_full": 10, "astyp": [10, 11, 13], "genergi": [10, 11], "gimpul": [10, 11], "goenergi": [10, 11], "goimpul": [10, 11], "nbump": [10, 11], "nbumps2": [10, 11], "nbumps3": [10, 11], "nbumps4": [10, 11], "nbumps5": [10, 11], "nbumps6": 10, "nbumps7": 10, "nbumps89": 10, "senergi": [10, 11], "maxenergi": [10, 11], "584000e": 10, "03": [10, 11], "2584": 10, "000000": [10, 12, 13], "9": [10, 11, 12, 13], "024252e": 10, "04": 10, "538": [10, 11], "579334": 10, "12": [10, 11, 12, 13], "375774": 10, "508901": 10, "859520": 10, "393576": 10, "392802": 10, "067724": 10, "004644": 10, "4975": 10, "270898": 10, "4278": 10, "850619": 10, "065789": 10, "std": [10, 12, 13], "292005e": 10, "562": 10, "652536": 10, "319051": 10, "63": [10, 13], "166556": 10, "364616": 10, "783772": 10, "769710": 10, "279059": 10, "068001": 10, "20450": 10, "833222": 10, "19357": 10, "454882": 10, "247962": 10, "min": [10, 12, 13], "000000e": 10, "02": [10, 12], "96": [10, 11, 12], "25": [10, 11, 12, 13], "166000e": 10, "190": 10, "37": [10, 11, 12, 13], "36": [10, 11, 12], "50": [10, 11, 12, 13], "548500e": 10, "379": 10, "6": [10, 11, 12, 13], "75": [10, 11, 12, 13], "283250e": 10, "669": 10, "38": [10, 11, 12, 13], "30": [10, 11, 12, 13], "250000": 10, "2600": 10, "2000": 10, "595650e": 10, "06": [10, 12, 13], "4518": 10, "1245": 10, "838": 10, "3": [10, 11, 12, 13], "402000": 10, "400000": [10, 12, 13], "pyplot": [10, 13], "plt": [10, 13], "group": 10, "value_count": 10, "e": [10, 11], "index": [10, 12, 13], "fig1": 10, "ax1": 10, "subplot": 10, "pie": 10, "autopct": 10, "1f": 10, "shadow": 10, "startangl": 10, "90": [10, 12, 13], "axi": [10, 11, 12, 13], "show": [10, 11, 13], "math": [10, 12], "drop": [10, 11, 12, 13], "seri": [10, 12, 13], "get_prediction_metr": 10, "y_pred": [10, 12], "y_true": [10, 12], "classification_metr": 10, "confusion_matrix": 10, "tn": 10, "fp": 10, "fn": 10, "tp": 10, "ravel": 10, "npv": 10, "ppv": 10, "mae": 10, "mean_absolute_error": [10, 12], "cohen_kappa_scor": 10, "balanc": 10, "balanced_accuracy_scor": 10, "logist": 10, "loss": 10, "log_loss": 10, "psep": 10, "fall": 10, "out": 10, "youden": 10, "j": 10, "f": [10, 12, 13], "fowlk": 10, "mallow": 10, "fowlkes_mallows_scor": 10, "rules_per_exampl": 10, "conflict": 10, "voting_conflict": 10, "geometr": 10, "sqrt": [10, 12], "from_record": [10, 12, 13], "get_ruleset_stat": [10, 12, 13], "__dict__": [10, 12, 13], "ipython": 10, "displai": [10, 12, 13], "clf": [10, 11], "c2_ruleset": [10, 12], "prediction_metr": 10, "c2_confusion_matrix": 10, "model_stat": 10, "corr_ruleset": [10, 12], "tmp": [10, 12, 13], "corr_confusion_matrix": 10, "concat": [10, 12, 13], "rss_ruleset": [10, 12], "rss_confusion_matrix": 10, "confus": 10, "218550": 10, "036229": 10, "111458": 10, "35": [10, 11, 12, 13], "742857": 10, "22": [10, 11, 12, 13], "142857": 10, "259410": 10, "670793": 10, "322125": 10, "005729": 10, "005879": 10, "010640": 10, "971429": 10, "885714": 10, "471475": 10, "339709": 10, "123223": 10, "21": [10, 11, 12, 13, 14], "51": [10, 11, 12, 13], "666667": 10, "306612": 10, "469157": 10, "201772": 10, "016841": 10, "017345": 10, "026655": 10, "904762": 10, "857143": 10, "514044": 10, "327209": 10, "171176": 10, "14": [10, 11, 12, 13], "714286": [10, 12], "64": [10, 11, 13], "428571": 10, "473795": 10, "484564": 10, "253249": 10, "041892": 10, "044068": 10, "068063": 10, "785714": 10, "932663": 10, "067337": 10, "433613": 10, "709693": 10, "427088": 10, "452941": 10, "966446": 10, "961665": 10, "487342": 10, "407595": 10, "469512": 10, "928703": 10, "81": 10, "93": [10, 11, 12], "77": [10, 11, 12], "2333": 10, "079334": 10, "2146": 10, "661622": 10, "827399": 10, "172601": 10, "246689": 10, "729909": 10, "221157": 10, "617647": 10, "842171": 10, "969018": 10, "216049": 10, "283951": 10, "320122": 10, "823757": 10, "381": 10, "65": [10, 11, 12, 13], "105": 10, "2033": 10, "438854": 10, "1993": 10, "721224": 10, "788313": 10, "211687": 10, "207458": 10, "725394": 10, "629984": 10, "652941": 10, "797846": 10, "970277": 10, "185309": 10, "816694": 10, "288687": 10, "789800": 10, "488": 10, "59": [10, 11, 12, 13], "111": 10, "1926": 10, "633127": 10, "2085": 10, "721766": 10, "23": [10, 11, 12, 13], "IF": [10, 11, 12, 13, 14], "inf": [10, 11, 12, 13, 14], "32": [10, 11, 12, 13], "THEN": [10, 11, 12, 13, 14], "AND": [10, 11, 12, 13, 14], "lt": [10, 11, 12, 13], "84": [10, 11], "13675": 10, "17640": 10, "1625": 10, "3500": 10, "772": 10, "shift": [10, 11], "73": [10, 13], "6150": 10, "1865": 10, "230": 10, "550": [10, 11], "380": 10, "118": 10, "31790": 10, "114": 10, "87": [10, 11, 12], "1342": [10, 11], "233": 10, "28515": 10, "1210": 10, "72": [10, 12, 13], "12550": 10, "514": 10, "1832": 10, "312": [10, 11], "88": [10, 12], "748755": 10, "95": [10, 11, 12], "55000": 10, "3096": 10, "364": 10, "1459": 10, "10150": 10, "2208": 10, "513615": 10, "1005720": 10, "1328": 10, "29": [10, 12, 13], "31": [10, 12], "2109": 10, "350": [10, 11], "36350": 10, "159155": 10, "586025": 10, "1408": 10, "1959": [10, 11], "13": [10, 13], "54950": 10, "750": [10, 11], "38250": 10, "254130": 10, "1133675": 10, "16": [10, 12, 13], "1438": 10, "203": 10, "4300": 10, "131700": 10, "740": 10, "38935": 10, "127440": 10, "14750": 10, "68": [10, 11], "1742": 10, "31100": 10, "211170": 10, "123": 10, "19": [10, 11, 12, 13], "1139": [10, 11], "46": [10, 11, 12], "116": 10, "46580": 10, "1877915": 10, "183": [10, 13], "w": [10, 11], "521": [10, 11], "2344": 10, "34605": 10, "656965": 10, "137": 10, "39": [10, 11, 12, 13], "450": [10, 11], "18870": [10, 11], "160": 10, "62": 10, "1603": 10, "131": [10, 11], "70": [10, 11, 12], "119": 10, "614380": 10, "25000": 10, "2250": 10, "186": [10, 11, 13], "12415": 10, "129940": 10, "121": 10, "793": 10, "150": 10, "1350": 10, "ghazard": [10, 11], "53": [10, 11, 12, 13], "42215": 10, "94300": 10, "133": 10, "813": 10, "74": [10, 11], "11100": 10, "537": [10, 11], "796": [10, 11], "17635": 10, "36470": 10, "18800": 10, "52205": 10, "28": [10, 12], "181": [10, 11], "524": 10, "184": [10, 13], "55": [10, 11, 12, 13], "128": 10, "7265": 10, "60": [10, 11, 12, 13], "31350": 10, "1510": [10, 11], "89": [10, 11, 12], "124": 10, "1252": [10, 11], "1331": [10, 11], "1253": [10, 11], "1500": [10, 11], "36050": [10, 11], "34": [10, 11, 12], "662435": [10, 11], "994": 10, "61250": [10, 11], "712": 10, "2257": 10, "58310": [10, 11], "934630": [10, 11], "40650": [10, 11], "2374": 10, "799855": [10, 11], "650": 10, "71": [10, 11, 12], "58": [10, 12], "34360": [10, 11], "306": 10, "28325": 10, "153": [10, 11], "321": 10, "14295": 10, "36250": 10, "40500": [10, 11], "96260": [10, 11], "1062020": [10, 11], "850": [10, 11], "7500": [10, 11], "1404": 10, "2965": [10, 11], "69": [10, 13], "1789250": 10, "95850": 10, "10495": 10, "126": 10, "78": [10, 11, 12], "250": [10, 11], "43150": 10, "176": [10, 11], "31760": 10, "49585": [10, 11], "362": 10, "771": 10, "27": [10, 11, 12, 13], "20485": 10, "43280": 10, "142": 10, "177": [10, 12], "241": 10, "54": [10, 11, 12, 13], "4905": 10, "seismoacoust": [10, 11], "126350": 10, "2168": 10, "44750": 10, "725": 10, "117": 10, "57680": 10, "34315": 10, "396": [10, 11], "1445": [10, 11], "26200": 10, "78890": 10, "297": 10, "1850": 10, "18585": 10, "25305": 10, "240": [10, 11], "588": 10, "42": [10, 11, 12, 13], "45": [10, 11, 12, 13], "92850": 10, "model_select": [10, 12, 13], "stratifiedkfold": [10, 13], "n_split": [10, 12, 13], "10": [10, 11, 12, 13, 14], "skf": [10, 13], "c2_ruleset_stat": 10, "c2_prediction_metr": 10, "arrai": 10, "train_index": [10, 13], "test_index": [10, 13], "x_train": [10, 12, 13], "x_test": [10, 12, 13], "iloc": [10, 12, 13], "y_train": [10, 12, 13], "y_test": [10, 12, 13], "c": [10, 12], "cezar": [10, 12], "appdata": 10, "local": 10, "temp": 10, "ipykernel_13196": 10, "4002598548": 10, "py": [10, 12], "runtimewarn": 10, "invalid": 10, "encount": 10, "scalar": 10, "divid": 10, "characterist": 10, "292132": 10, "227262": 10, "047455": 10, "200000": [10, 12, 13], "720378": 10, "124536": 10, "239541": 10, "690010": 10, "337021": 10, "014757": 10, "015234": 10, "030014": 10, "909792": 10, "872710": 10, "dtype": [10, 12, 13], "float64": [10, 12, 13], "855063": 10, "144937": 10, "107556": 10, "567020": 10, "224070": 10, "235294": 10, "898747": 10, "945594": 10, "495355": 10, "443788": 10, "101253": 10, "134041": 10, "520255": 10, "145015": 10, "870605": 10, "24": [10, 11, 12, 13], "500000": [10, 12, 13], "216": 10, "900000": [10, 12], "871479": 10, "179": 10, "344832": 10, "gonna": [10, 12, 13], "take": [10, 12, 13], "while": [10, 12, 13], "18": [10, 11, 12, 13], "gridsearchcv": [10, 12, 13], "rang": [10, 12, 13], "15": [10, 12, 13], "measures_choic": [10, 12], "grid": [10, 12, 13], "search": [10, 12, 13], "cv": [10, 12, 13], "grid_search": [10, 12, 13], "param_grid": [10, 12, 13], "balanced_accuraci": 10, "n_job": 10, "grid_result": [10, 12, 13], "bac": 10, "best_score_": [10, 12, 13], "best_params_": [10, 12, 13], "626780": 10, "gt": [10, 12, 13], "train_test_split": [10, 13], "test_siz": [10, 13], "shuffl": [10, 13], "ruleset_stat": [10, 12, 13], "173054": 10, "120460": 10, "029986": 10, "689655": 10, "310345": 10, "491183": 10, "736226": 10, "309334": 10, "019831": 10, "019993": 10, "024284": 10, "931034": 10, "808511": 10, "191489": 10, "170010": 10, "679398": 10, "901976": 10, "533333": 10, "825462": 10, "966346": 10, "158416": 10, "124762": 10, "174538": 10, "358795": 10, "730033": 10, "244275": 10, "809997": 10, "85": [10, 11, 12, 13], "402": 10, "034816": 10, "360": 10, "663511": 10, "guid": 11, "follow": 11, "scheme": 11, "introduc": [11, 14], "guider": 11, "sikora": 11, "et": 11, "al": 11, "2019": 11, "basic": [11, 12, 13], "how": 11, "classification_dataset_url": 11, "df": 11, "forb": 11, "1427": 11, "1653": 11, "1006585": 11, "1752": 11, "2733": 11, "634250": 11, "1655": 11, "386010": 11, "1686": 11, "2892": 11, "2068": 11, "1004565": 11, "2184": 11, "901": 11, "3850": 11, "9600": 11, "8100": 11, "5500": 11, "40": [11, 12, 13], "1150": 11, "695": 11, "48": [11, 12], "10915": 11, "2500": 11, "3950": 11, "75000": 11, "378500": 11, "85450": 11, "5750": 11, "508210": 11, "927": 11, "2489": 11, "318735": 11, "392530": 11, "6750": 11, "3881": 11, "31200": 11, "673155": 11, "10000": 11, "1161025": 11, "45000": 11, "34880": 11, "281": 11, "135": 11, "498": 11, "33010": 11, "106": 11, "54930": 11, "109": 11, "98": [11, 13], "48545": 11, "32795": 11, "16805": 11, "32020": 11, "19670": 11, "40735": 11, "470": 11, "115450": 11, "regression_datset_url": 11, "methan": [11, 12], "mm116_pred": [11, 12], "mm31": [11, 12], "mm116": [11, 12], "as038": [11, 12], "pg072": [11, 12], "ba13": [11, 12], "dmm116": [11, 12], "1076": [11, 12], "49": [11, 12], "13363": 11, "1077": [11, 12], "13364": 11, "13365": 11, "13366": 11, "13367": 11, "13368": [11, 12], "rulekitjavaexcept": [11, 13], "reg": [11, 12], "01": 11, "44": [11, 12, 13], "1075": [11, 12], "20": [11, 12], "43": [11, 12, 13], "61": [11, 12], "56": 11, "82": 11, "survival_dataset_url": 11, "bmt": [11, 13], "survival_statu": [11, 13, 14], "cd34kgx10d6": [11, 13, 14], "extcgvhd": [11, 13, 14], "attr": 11, "ancrecoveri": [11, 13], "26": [11, 12, 13], "srv": [11, 13], "86": 11, "pltrecoveri": [11, 13], "500142": 11, "recipientag": [11, 13], "17": [11, 12, 13], "recipientrh": [11, 13], "relaps": [11, 13], "gendermatch": [11, 13], "donorag": [11, 13], "cd3dcd34": [11, 13], "97": 11, "txpostrelaps": 11, "recipientageint": 11, "94": [11, 13], "rbodymass": [11, 13], "iiiv": [11, 13], "stemcellsourc": [11, 13], "download": 12, "base_dataset_url": 12, "train_dataset_url": 12, "test_dataset_url": 12, "train_df": 12, "test_df": 12, "overview": [12, 13], "shape": [12, 13], "00000": 12, "363960": 12, "775007": 12, "294734": 12, "835600": 12, "308573": 12, "1073": 12, "443372": 12, "000007": 12, "79825": 12, "117105": 12, "269366": 12, "142504": 12, "106681": 12, "461922": 12, "162811": 12, "043566": 12, "28649": 12, "170000": 12, "100000": 12, "1067": 12, "800000": 12, "20000": 12, "260000": 12, "300000": 12, "1070": 12, "50000": 12, "360000": 12, "80000": 12, "450000": 12, "820000": 12, "700000": 12, "600000": [12, 13], "1078": 12, "ntest": 12, "5728": 12, "556652": 12, "006913": 12, "236627": 12, "819239": 12, "538408": 12, "1072": 12, "691690": 12, "000017": 12, "042458": 12, "114682": 12, "167983": 12, "104913": 12, "078865": 12, "498566": 12, "799559": 12, "046849": 12, "171393": 12, "350000": [12, 13], "460000": 12, "1071": 12, "550000": 12, "640000": 12, "980000": [12, 13], "get_regression_metr": 12, "relative_error": 12, "squared_relative_error": 12, "relative_error_leni": 12, "relative_error_strict": 12, "nae_denomin": 12, "avg": 12, "sum": 12, "len": 12, "ab": 12, "corrcoef": 12, "absolute_error": 12, "normalized_absolute_error": 12, "squared_error": 12, "mean_squared_error": 12, "root_mean_squared_error": 12, "root_relative_squared_error": 12, "squared_correl": 12, "power": 12, "del": [12, 13], "_java_object": [12, 13], "c2_reg": 12, "regression_metr": 12, "corr_reg": 12, "rss_reg": 12, "onedr": 12, "pulpit": 12, "emag": 12, "git": 12, "pythonrulekit": 12, "tutorials_env": 12, "lib": 12, "site": 12, "_regress": 12, "492": 12, "futurewarn": 12, "deprec": 12, "remov": 12, "root": 12, "warn": 12, "minimum_cov": [12, 13], "maximum_uncovered_fract": [12, 13], "pruning_en": [12, 13], "max_growing_condit": [12, 13], "670397": 12, "978997": 12, "637769": 12, "272727": 12, "33": [12, 13], "727273": 12, "345683": 12, "874767": 12, "732356": 12, "612636e": 12, "739791": 12, "836199": 12, "871719": 12, "285714": 12, "334990": 12, "862965": 12, "800819": 12, "046280e": 12, "929544": 12, "020750": 12, "894867": 12, "333333": 12, "166667": 12, "417440": 12, "855115": 12, "786208": 12, "242568e": 12, "089929": 12, "114526": 12, "101069": 12, "125935": 12, "382694": 12, "019753": 12, "140547": 12, "167429": 12, "937881": 12, "879620": 12, "088561": 12, "112319": 12, "099635": 12, "125846": 12, "376872": 12, "020912": 12, "144609": 12, "184988": 12, "941044": 12, "885563": 12, "092552": 12, "111375": 12, "102026": 12, "124544": 12, "393860": 12, "020544": 12, "143331": 12, "153866": 12, "945779": 12, "894498": 12, "52": 12, "08": [12, 13], "99": [12, 13], "00": 12, "66": 12, "91": [12, 13], "80": 12, "67": 12, "76": 12, "c2_predict": 12, "c2_regression_metr": 12, "corr_predict": 12, "corr_regression_metr": 12, "rss_predict": 12, "rss_regression_metr": 12, "107227": 12, "100574": 12, "094935": 12, "112747": 12, "739328": 12, "020326": 12, "142569": 12, "126236": 12, "835385": 12, "697868": 12, "105350": 12, "091827": 12, "090950": 12, "109321": 12, "726385": 12, "021890": 12, "147951": 12, "119472": 12, "866898": 12, "751512": 12, "128302": 12, "113411": 12, "111947": 12, "134690": 12, "884639": 12, "027270": 12, "165136": 12, "134849": 12, "866442": 12, "750722": 12, "kfold": 12, "neg_root_mean_squared_error": 12, "rmse": 12, "191976": 12, "best_estimator_": 12, "47": [12, 13], "1074": 12, "nan": [12, 14], "83": 12, "151842": 12, "240354": 12, "883363": 12, "190476": 12, "809524": 12, "116152": 12, "849723": 12, "952381": 12, "111355": 12, "103524": 12, "097884": 12, "114888": 12, "767792": 12, "019642": 12, "140148": 12, "125609": 12, "801204": 12, "641927": 12, "data_df": 13, "recipientgend": 13, "donorage35": 13, "donorabo": 13, "recipientabo": 13, "abomatch": 13, "cd3dkgx10d8": 13, "time_to_agvhd_iii_iv": 13, "830137": 13, "338760": 13, "999": 13, "342466": 13, "078295": 13, "1000000": 13, "163": 13, "394521": 13, "013230": 13, "435": 13, "684932": 13, "481647": 13, "358904": 13, "972255": 13, "2043": 13, "182": 13, "575342": 13, "522750": 13, "385": 13, "895890": 13, "038858": 13, "634": 13, "347945": 13, "635559": 13, "1895": 13, "185": 13, "780822": 13, "077770": 13, "382": 13, "553425": 13, "948135": 13, "1109": 13, "187": 13, "472068": 13, "931551": 13, "891781": 13, "385096": 13, "745714": 13, "801081": 13, "26752": 13, "866310": 13, "90937": 13, "919786": 13, "775408": 13, "042781": 13, "938": 13, "743316": 13, "271826": 13, "305639": 13, "914386": 13, "598716": 13, "859128": 13, "650922": 13, "161747": 13, "200525": 13, "288242": 13, "407688": 13, "418425": 13, "252689": 13, "849": 13, "589495": 13, "646575": 13, "790000": 13, "204132": 13, "040000": 13, "039726": 13, "050000": 13, "786683": 13, "687500": 13, "168": 13, "550685": 13, "720000": 13, "734462": 13, "325000": 13, "676": 13, "117809": 13, "415000": 13, "823565": 13, "785000": 13, "1604": 13, "57": 13, "780000": 13, "560970": 13, "020000": 13, "103": 13, "3364": 13, "771417": 13, "797513": 13, "902853": 13, "308021": 13, "999865": 13, "000135": 13, "000147": 13, "000184": 13, "step": 13, "legend": 13, "titl": 13, "0x289deb3a180": 13, "kaplan_mei": 13, "curv": 13, "enumer": 13, "rule_label": 13, "r": 13, "rule_km": 13, "whole": 13, "train_km": 13, "r1": 13, "hlamismatch": 13, "r3": 13, "266": 13, "r4": 13, "r5": 13, "integrated_brier_scor": 13, "19651358709002972": 13, "random_st": 13, "survival_metr": 13, "append": 13, "799019": 13, "296248": 13, "477474": 13, "581667": 13, "825000": 13, "486613": 13, "995955": 13, "004045": 13, "004061": 13, "004104": 13, "20178456199764142": 13, "scorer": 13, "21437408819868886": 13, "594173": 13, "244234": 13, "312523": 13, "389262": 13, "14054870564224475": 13, "The": 14, "latest": 14, "groundbreak": 14, "read": 14, "them": 14, "old": 14, "see": 14, "below": 14, "variant": 14, "In": 14, "mani": 14, "bug": 14, "regard": 14, "improv": 14, "flake8": 14, "unit": 14}, "objects": {"rulekit.classification": [[2, 0, 1, "", "ExpertRuleClassifier"], [2, 0, 1, "", "RuleClassifier"]], "rulekit.classification.ExpertRuleClassifier": [[2, 1, 1, "", "add_event_listener"], [2, 1, 1, "", "fit"], [2, 1, 1, "", "get_coverage_matrix"], [2, 1, 1, "", "get_metadata_routing"], [2, 1, 1, "", "get_params"], [2, 1, 1, "", "predict"], [2, 1, 1, "", "predict_proba"], [2, 1, 1, "", "score"], [2, 1, 1, "", "set_params"]], "rulekit.classification.RuleClassifier": [[2, 1, 1, "", "add_event_listener"], [2, 1, 1, "", "fit"], [2, 1, 1, "", "get_coverage_matrix"], [2, 1, 1, "", "get_metadata_routing"], [2, 1, 1, "", "get_params"], [2, 1, 1, "", "predict"], [2, 1, 1, "", "predict_proba"], [2, 1, 1, "", "score"], [2, 1, 1, "", "set_params"]], "rulekit": [[1, 2, 0, "-", "main"], [3, 2, 0, "-", "params"], [5, 2, 0, "-", "rules"], [6, 2, 0, "-", "stats"]], "rulekit.main": [[1, 0, 1, "", "RuleKit"]], "rulekit.main.RuleKit": [[1, 1, 1, "", "configure_java_logger"], [1, 1, 1, "", "get_java_logger_config"], [1, 1, 1, "", "init"], [1, 3, 1, "", "version"]], "rulekit.operator": [[3, 4, 1, "", "Data"]], "rulekit.params": [[3, 0, 1, "", "Measures"]], "rulekit.params.Measures": [[3, 3, 1, "", "Accuracy"], [3, 3, 1, "", "BinaryEntropy"], [3, 3, 1, "", "C1"], [3, 3, 1, "", "C2"], [3, 3, 1, "", "CFoil"], [3, 3, 1, "", "CN2Significnce"], [3, 3, 1, "", "Correlation"], [3, 3, 1, "", "Coverage"], [3, 3, 1, "", "FBayesianConfirmation"], [3, 3, 1, "", "FMeasure"], [3, 3, 1, "", "FullCoverage"], [3, 3, 1, "", "GMeasure"], [3, 3, 1, "", "GeoRSS"], [3, 3, 1, "", "InformationGain"], [3, 3, 1, "", "JMeasure"], [3, 3, 1, "", "Kappa"], [3, 3, 1, "", "Klosgen"], [3, 3, 1, "", "Laplace"], [3, 3, 1, "", "Lift"], [3, 3, 1, "", "LogRank"], [3, 3, 1, "", "LogicalSufficiency"], [3, 3, 1, "", "MEstimate"], [3, 3, 1, "", "MutualSupport"], [3, 3, 1, "", "Novelty"], [3, 3, 1, "", "OddsRatio"], [3, 3, 1, "", "OneWaySupport"], [3, 3, 1, "", "PawlakDependencyFactor"], [3, 3, 1, "", "Precision"], [3, 3, 1, "", "Q2"], [3, 3, 1, "", "RSS"], [3, 3, 1, "", "RelativeRisk"], [3, 3, 1, "", "Ripper"], [3, 3, 1, "", "RuleInterest"], [3, 3, 1, "", "SBayesian"], [3, 3, 1, "", "Sensitivity"], [3, 3, 1, "", "Specificity"], [3, 3, 1, "", "TwoWaySupport"], [3, 3, 1, "", "WeightedLaplace"], [3, 3, 1, "", "WeightedRelativeAccuracy"], [3, 3, 1, "", "YAILS"]], "rulekit.regression": [[4, 0, 1, "", "ExpertRuleRegressor"], [4, 0, 1, "", "RuleRegressor"]], "rulekit.regression.ExpertRuleRegressor": [[4, 1, 1, "", "add_event_listener"], [4, 1, 1, "", "fit"], [4, 1, 1, "", "get_coverage_matrix"], [4, 1, 1, "", "get_metadata_routing"], [4, 1, 1, "", "get_params"], [4, 1, 1, "", "predict"], [4, 1, 1, "", "score"], [4, 1, 1, "", "set_params"]], "rulekit.regression.RuleRegressor": [[4, 1, 1, "", "add_event_listener"], [4, 1, 1, "", "fit"], [4, 1, 1, "", "get_coverage_matrix"], [4, 1, 1, "", "get_metadata_routing"], [4, 1, 1, "", "get_params"], [4, 1, 1, "", "predict"], [4, 1, 1, "", "score"], [4, 1, 1, "", "set_params"]], "rulekit.rules": [[5, 0, 1, "", "BaseRule"], [5, 0, 1, "", "ClassificationRule"], [5, 0, 1, "", "InductionParameters"], [5, 0, 1, "", "RegressionRule"], [5, 0, 1, "", "RuleSet"], [5, 0, 1, "", "SurvivalRule"]], "rulekit.rules.BaseRule": [[5, 1, 1, "", "get_covering_information"], [5, 1, 1, "", "print_stats"], [5, 5, 1, "", "pvalue"], [5, 5, 1, "", "stats"], [5, 5, 1, "", "weight"], [5, 5, 1, "", "weighted_N"], [5, 5, 1, "", "weighted_P"], [5, 5, 1, "", "weighted_n"], [5, 5, 1, "", "weighted_p"]], "rulekit.rules.ClassificationRule": [[5, 5, 1, "", "decision_class"]], "rulekit.rules.InductionParameters": [[5, 5, 1, "", "induction_measure"], [5, 5, 1, "", "pruning_measure"], [5, 5, 1, "", "voting_measure"]], "rulekit.rules.RegressionRule": [[5, 5, 1, "", "conclusion_value"]], "rulekit.rules.RuleSet": [[5, 1, 1, "", "calculate_avg_rule_coverage"], [5, 1, 1, "", "calculate_avg_rule_precision"], [5, 1, 1, "", "calculate_avg_rule_quality"], [5, 1, 1, "", "calculate_conditions_count"], [5, 1, 1, "", "calculate_induced_conditions_count"], [5, 1, 1, "", "calculate_significance"], [5, 1, 1, "", "calculate_significance_fdr"], [5, 1, 1, "", "calculate_significance_fwer"], [5, 5, 1, "", "growing_time"], [5, 5, 1, "", "is_voting"], [5, 5, 1, "", "parameters"], [5, 5, 1, "", "pruning_time"], [5, 5, 1, "", "rules"], [5, 5, 1, "", "stats"], [5, 5, 1, "", "total_time"]], "rulekit.rules.SurvivalRule": [[5, 5, 1, "", "kaplan_meier_estimator"]], "rulekit.stats": [[6, 0, 1, "", "RuleSetStatistics"], [6, 0, 1, "", "RuleStatistics"]], "rulekit.stats.RuleSetStatistics": [[6, 3, 1, "", "SIGNIFICANCE_LEVEL"]], "rulekit.stats.RuleStatistics": [[6, 3, 1, "", "N"], [6, 3, 1, "", "P"], [6, 3, 1, "", "n"], [6, 3, 1, "", "p"], [6, 3, 1, "", "pvalue"], [6, 3, 1, "", "weight"]], "rulekit.survival": [[7, 0, 1, "", "ExpertSurvivalRules"], [7, 0, 1, "", "SurvivalRules"]], "rulekit.survival.ExpertSurvivalRules": [[7, 1, 1, "", "add_event_listener"], [7, 1, 1, "", "fit"], [7, 1, 1, "", "get_coverage_matrix"], [7, 1, 1, "", "get_metadata_routing"], [7, 1, 1, "", "get_params"], [7, 1, 1, "", "get_train_set_kaplan_meier"], [7, 1, 1, "", "predict"], [7, 1, 1, "", "score"], [7, 1, 1, "", "set_params"]], "rulekit.survival.SurvivalRules": [[7, 1, 1, "", "add_event_listener"], [7, 1, 1, "", "fit"], [7, 1, 1, "", "get_coverage_matrix"], [7, 1, 1, "", "get_metadata_routing"], [7, 1, 1, "", "get_params"], [7, 1, 1, "", "get_train_set_kaplan_meier"], [7, 1, 1, "", "predict"], [7, 1, 1, "", "score"], [7, 1, 1, "", "set_params"]]}, "objtypes": {"0": "py:class", "1": "py:method", "2": "py:module", "3": "py:attribute", "4": "py:data", "5": "py:property"}, "objnames": {"0": ["py", "class", "Python class"], "1": ["py", "method", "Python method"], "2": ["py", "module", "Python module"], "3": ["py", "attribute", "Python attribute"], "4": ["py", "data", "Python data"], "5": ["py", "property", "Python property"]}, "titleterms": {"rulekit": [0, 14], "tabl": [0, 1, 9], "content": [0, 1, 9], "code": 1, "document": 1, "classif": [2, 10, 11], "paramet": 3, "regress": [4, 11, 12, 14], "rule": [5, 10, 11, 12, 13, 14], "statist": 6, "surviv": [7, 11, 13, 14], "quick": 8, "start": 8, "instal": [8, 10, 13], "packag": 8, "usag": 8, "tutori": 9, "depend": [10, 13], "summari": [10, 12, 13], "dataset": [10, 11, 12, 13], "decis": 10, "class": 10, "distribut": 10, "helper": [10, 12, 13], "function": [10, 12, 13], "calcul": [10, 12], "metric": [10, 12], "induct": [10, 11, 12, 13, 14], "full": [10, 13], "c2": [10, 12], "measur": [10, 12], "gener": [10, 12], "correl": [10, 12], "rss": [10, 12], "stratifi": [10, 13], "k": [10, 13], "fold": [10, 13], "cross": [10, 13], "valid": [10, 12, 13], "hyperparamet": [10, 12, 13], "tune": [10, 12, 13], "build": [10, 13], "model": [10, 12, 13], "split": [10, 13], "train": [10, 12, 13], "test": [10, 12, 13], "80": [10, 13], "20": [10, 13], "expert": [11, 14], "load": 11, "defin": 11, "knowledg": 11, "condit": 11, "file": 12, "evalu": [12, 13], "set": [12, 13], "predict": [12, 13], "us": 12, "select": 12, "from": 12, "analysi": 13, "creat": 13, "ruleset": 13, "characterist": 13, "datafram": 13, "plot": 13, "estim": 13, "first": 13, "five": 13, "exampl": 13, "kaplan": 13, "meier": 13, "": [13, 14], "top": 13, "what": 14, "new": 14, "version": 14, "2": 14, "1": 14, "24": 14, "0": 14, "revert": 14, "break": 14, "chang": 14, "upgrad": 14, "other": 14}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.intersphinx": 1, "nbsphinx": 4, "sphinx": 60}, "alltitles": {"RuleKit": [[0, "rulekit"]], "Table of contents:": [[0, null], [1, null], [9, null]], "Code documentation": [[1, "module-rulekit.main"]], "Classification": [[2, "classification"], [10, "Classification"], [11, "Classification"]], "Parameters": [[3, "parameters"]], "Regression": [[4, "regression"], [11, "Regression"], [12, "Regression"]], "Rules": [[5, "module-rulekit.rules"]], "Statistics": [[6, "module-rulekit.stats"]], "Survival": [[7, "survival"], [11, "Survival"]], "Quick start": [[8, "quick-start"]], "Installation": [[8, "installation"]], "Package usage": [[8, "package-usage"]], "Tutorials": [[9, "tutorials"]], "Install dependencies": [[10, "Install-dependencies"], [13, "Install-dependencies"]], "Summary of the dataset": [[10, "Summary-of-the-dataset"], [12, "Summary-of-the-dataset"], [13, "Summary-of-the-dataset"]], "Decision class distribution": [[10, "Decision-class-distribution"]], "Helper function for calculating metrics": [[10, "Helper-function-for-calculating-metrics"], [12, "Helper-function-for-calculating-metrics"]], "Rule induction on full dataset": [[10, "Rule-induction-on-full-dataset"], [13, "Rule-induction-on-full-dataset"]], "C2 Measure generated rules": [[10, "C2-Measure-generated-rules"], [12, "C2-Measure-generated-rules"]], "Correlation Measure generated rules": [[10, "Correlation-Measure-generated-rules"], [12, "Correlation-Measure-generated-rules"]], "RSS Measure generated rules": [[10, "RSS-Measure-generated-rules"], [12, "RSS-Measure-generated-rules"]], "Stratified K-Folds cross-validation": [[10, "Stratified-K-Folds-cross-validation"], [13, "Stratified-K-Folds-cross-validation"]], "Hyperparameters tuning": [[10, "Hyperparameters-tuning"], [12, "Hyperparameters-tuning"], [13, "Hyperparameters-tuning"]], "Building model with tuned hyperparameters": [[10, "Building-model-with-tuned-hyperparameters"], [13, "Building-model-with-tuned-hyperparameters"]], "Split dataset to train and test (80%/20%).": [[10, "Split-dataset-to-train-and-test-(80%/20%)."]], "Validate model on test dataset": [[10, "Validate-model-on-test-dataset"], [12, "Validate-model-on-test-dataset"], [13, "Validate-model-on-test-dataset"]], "Expert Rules": [[11, "Expert-Rules"]], "Load dataset": [[11, "Load-dataset"], [11, "id1"], [11, "id3"]], "Define expert knowledge": [[11, "Define-expert-knowledge"]], "Rule induction": [[11, "Rule-induction"], [11, "id2"], [11, "id5"]], "Define rules and conditions": [[11, "Define-rules-and-conditions"], [11, "id4"]], "Train file": [[12, "Train-file"]], "Test file": [[12, "Test-file"]], "Rule induction on training dataset": [[12, "Rule-induction-on-training-dataset"]], "Evaluation on a test set": [[12, "Evaluation-on-a-test-set"]], "Prediction using the model selected from the tuning": [[12, "Prediction-using-the-model-selected-from-the-tuning"]], "Survival analysis": [[13, "Survival-analysis"]], "Helper function for creating ruleset characteristics dataframe": [[13, "Helper-function-for-creating-ruleset-characteristics-dataframe"]], "Plot predicted estimators for the first five examples": [[13, "Plot-predicted-estimators-for-the-first-five-examples"]], "Plot rules Kaplan-Meier\u2019s estimators on top of the training dataset estimator": [[13, "Plot-rules-Kaplan-Meier's-estimators-on-top-of-the-training-dataset-estimator"]], "Rules evaluation on full set": [[13, "Rules-evaluation-on-full-set"]], "Split dataset to train and test (80%/20%)": [[13, "Split-dataset-to-train-and-test-(80%/20%)"]], "What\u2019s new in RuleKit version 2.1.24.0?": [[14, "What's-new-in-RuleKit-version-2.1.24.0?"]], "1. Revert breaking changes in expert rules induction for regression and survival": [[14, "1.-Revert-breaking-changes-in-expert-rules-induction-for-regression-and-survival"]], "2. Upgrade to new version of RuleKit": [[14, "2.-Upgrade-to-new-version-of-RuleKit"]], "Other changes": [[14, "Other-changes"]]}, "indexentries": {"rulekit (class in rulekit.main)": [[1, "rulekit.main.RuleKit"]], "configure_java_logger() (rulekit.main.rulekit static method)": [[1, "rulekit.main.RuleKit.configure_java_logger"]], "get_java_logger_config() (rulekit.main.rulekit static method)": [[1, "rulekit.main.RuleKit.get_java_logger_config"]], "init() (rulekit.main.rulekit static method)": [[1, "rulekit.main.RuleKit.init"]], "module": [[1, "module-rulekit.main"], [3, "module-rulekit.params"], [5, "module-rulekit.rules"], [6, "module-rulekit.stats"]], "rulekit.main": [[1, "module-rulekit.main"]], "version (rulekit.main.rulekit attribute)": [[1, "rulekit.main.RuleKit.version"]], "expertruleclassifier (class in rulekit.classification)": [[2, "rulekit.classification.ExpertRuleClassifier"]], "ruleclassifier (class in rulekit.classification)": [[2, "rulekit.classification.RuleClassifier"]], "add_event_listener() (rulekit.classification.expertruleclassifier method)": [[2, "rulekit.classification.ExpertRuleClassifier.add_event_listener"]], "add_event_listener() (rulekit.classification.ruleclassifier method)": [[2, "rulekit.classification.RuleClassifier.add_event_listener"]], "fit() (rulekit.classification.expertruleclassifier method)": [[2, "rulekit.classification.ExpertRuleClassifier.fit"]], "fit() (rulekit.classification.ruleclassifier method)": [[2, "rulekit.classification.RuleClassifier.fit"]], "get_coverage_matrix() (rulekit.classification.expertruleclassifier method)": [[2, "rulekit.classification.ExpertRuleClassifier.get_coverage_matrix"]], "get_coverage_matrix() (rulekit.classification.ruleclassifier method)": [[2, "rulekit.classification.RuleClassifier.get_coverage_matrix"]], "get_metadata_routing() (rulekit.classification.expertruleclassifier method)": [[2, "rulekit.classification.ExpertRuleClassifier.get_metadata_routing"]], "get_metadata_routing() (rulekit.classification.ruleclassifier method)": [[2, "rulekit.classification.RuleClassifier.get_metadata_routing"]], "get_params() (rulekit.classification.expertruleclassifier method)": [[2, "rulekit.classification.ExpertRuleClassifier.get_params"]], "get_params() (rulekit.classification.ruleclassifier method)": [[2, "rulekit.classification.RuleClassifier.get_params"]], "predict() (rulekit.classification.expertruleclassifier method)": [[2, "rulekit.classification.ExpertRuleClassifier.predict"]], "predict() (rulekit.classification.ruleclassifier method)": [[2, "rulekit.classification.RuleClassifier.predict"]], "predict_proba() (rulekit.classification.expertruleclassifier method)": [[2, "rulekit.classification.ExpertRuleClassifier.predict_proba"]], "predict_proba() (rulekit.classification.ruleclassifier method)": [[2, "rulekit.classification.RuleClassifier.predict_proba"]], "score() (rulekit.classification.expertruleclassifier method)": [[2, "rulekit.classification.ExpertRuleClassifier.score"]], "score() (rulekit.classification.ruleclassifier method)": [[2, "rulekit.classification.RuleClassifier.score"]], "set_params() (rulekit.classification.expertruleclassifier method)": [[2, "rulekit.classification.ExpertRuleClassifier.set_params"]], "set_params() (rulekit.classification.ruleclassifier method)": [[2, "rulekit.classification.RuleClassifier.set_params"]], "accuracy (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.Accuracy"]], "binaryentropy (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.BinaryEntropy"]], "c1 (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.C1"]], "c2 (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.C2"]], "cfoil (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.CFoil"]], "cn2significnce (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.CN2Significnce"]], "correlation (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.Correlation"]], "coverage (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.Coverage"]], "fbayesianconfirmation (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.FBayesianConfirmation"]], "fmeasure (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.FMeasure"]], "fullcoverage (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.FullCoverage"]], "gmeasure (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.GMeasure"]], "georss (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.GeoRSS"]], "informationgain (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.InformationGain"]], "jmeasure (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.JMeasure"]], "kappa (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.Kappa"]], "klosgen (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.Klosgen"]], "laplace (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.Laplace"]], "lift (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.Lift"]], "logrank (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.LogRank"]], "logicalsufficiency (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.LogicalSufficiency"]], "mestimate (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.MEstimate"]], "measures (class in rulekit.params)": [[3, "rulekit.params.Measures"]], "mutualsupport (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.MutualSupport"]], "novelty (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.Novelty"]], "oddsratio (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.OddsRatio"]], "onewaysupport (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.OneWaySupport"]], "pawlakdependencyfactor (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.PawlakDependencyFactor"]], "precision (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.Precision"]], "q2 (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.Q2"]], "rss (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.RSS"]], "relativerisk (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.RelativeRisk"]], "ripper (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.Ripper"]], "ruleinterest (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.RuleInterest"]], "sbayesian (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.SBayesian"]], "sensitivity (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.Sensitivity"]], "specificity (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.Specificity"]], "twowaysupport (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.TwoWaySupport"]], "weightedlaplace (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.WeightedLaplace"]], "weightedrelativeaccuracy (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.WeightedRelativeAccuracy"]], "yails (rulekit.params.measures attribute)": [[3, "rulekit.params.Measures.YAILS"]], "rulekit.operator.data (built-in variable)": [[3, "rulekit.operator.Data"]], "rulekit.params": [[3, "module-rulekit.params"]], "expertruleregressor (class in rulekit.regression)": [[4, "rulekit.regression.ExpertRuleRegressor"]], "ruleregressor (class in rulekit.regression)": [[4, "rulekit.regression.RuleRegressor"]], "add_event_listener() (rulekit.regression.expertruleregressor method)": [[4, "rulekit.regression.ExpertRuleRegressor.add_event_listener"]], "add_event_listener() (rulekit.regression.ruleregressor method)": [[4, "rulekit.regression.RuleRegressor.add_event_listener"]], "fit() (rulekit.regression.expertruleregressor method)": [[4, "rulekit.regression.ExpertRuleRegressor.fit"]], "fit() (rulekit.regression.ruleregressor method)": [[4, "rulekit.regression.RuleRegressor.fit"]], "get_coverage_matrix() (rulekit.regression.expertruleregressor method)": [[4, "rulekit.regression.ExpertRuleRegressor.get_coverage_matrix"]], "get_coverage_matrix() (rulekit.regression.ruleregressor method)": [[4, "rulekit.regression.RuleRegressor.get_coverage_matrix"]], "get_metadata_routing() (rulekit.regression.expertruleregressor method)": [[4, "rulekit.regression.ExpertRuleRegressor.get_metadata_routing"]], "get_metadata_routing() (rulekit.regression.ruleregressor method)": [[4, "rulekit.regression.RuleRegressor.get_metadata_routing"]], "get_params() (rulekit.regression.expertruleregressor method)": [[4, "rulekit.regression.ExpertRuleRegressor.get_params"]], "get_params() (rulekit.regression.ruleregressor method)": [[4, "rulekit.regression.RuleRegressor.get_params"]], "predict() (rulekit.regression.expertruleregressor method)": [[4, "rulekit.regression.ExpertRuleRegressor.predict"]], "predict() (rulekit.regression.ruleregressor method)": [[4, "rulekit.regression.RuleRegressor.predict"]], "score() (rulekit.regression.expertruleregressor method)": [[4, "rulekit.regression.ExpertRuleRegressor.score"]], "score() (rulekit.regression.ruleregressor method)": [[4, "rulekit.regression.RuleRegressor.score"]], "set_params() (rulekit.regression.expertruleregressor method)": [[4, "rulekit.regression.ExpertRuleRegressor.set_params"]], "set_params() (rulekit.regression.ruleregressor method)": [[4, "rulekit.regression.RuleRegressor.set_params"]], "baserule (class in rulekit.rules)": [[5, "rulekit.rules.BaseRule"]], "classificationrule (class in rulekit.rules)": [[5, "rulekit.rules.ClassificationRule"]], "inductionparameters (class in rulekit.rules)": [[5, "rulekit.rules.InductionParameters"]], "regressionrule (class in rulekit.rules)": [[5, "rulekit.rules.RegressionRule"]], "ruleset (class in rulekit.rules)": [[5, "rulekit.rules.RuleSet"]], "survivalrule (class in rulekit.rules)": [[5, "rulekit.rules.SurvivalRule"]], "calculate_avg_rule_coverage() (rulekit.rules.ruleset method)": [[5, "rulekit.rules.RuleSet.calculate_avg_rule_coverage"]], "calculate_avg_rule_precision() (rulekit.rules.ruleset method)": [[5, "rulekit.rules.RuleSet.calculate_avg_rule_precision"]], "calculate_avg_rule_quality() (rulekit.rules.ruleset method)": [[5, "rulekit.rules.RuleSet.calculate_avg_rule_quality"]], "calculate_conditions_count() (rulekit.rules.ruleset method)": [[5, "rulekit.rules.RuleSet.calculate_conditions_count"]], "calculate_induced_conditions_count() (rulekit.rules.ruleset method)": [[5, "rulekit.rules.RuleSet.calculate_induced_conditions_count"]], "calculate_significance() (rulekit.rules.ruleset method)": [[5, "rulekit.rules.RuleSet.calculate_significance"]], "calculate_significance_fdr() (rulekit.rules.ruleset method)": [[5, "rulekit.rules.RuleSet.calculate_significance_fdr"]], "calculate_significance_fwer() (rulekit.rules.ruleset method)": [[5, "rulekit.rules.RuleSet.calculate_significance_fwer"]], "conclusion_value (rulekit.rules.regressionrule property)": [[5, "rulekit.rules.RegressionRule.conclusion_value"]], "decision_class (rulekit.rules.classificationrule property)": [[5, "rulekit.rules.ClassificationRule.decision_class"]], "get_covering_information() (rulekit.rules.baserule method)": [[5, "rulekit.rules.BaseRule.get_covering_information"]], "growing_time (rulekit.rules.ruleset property)": [[5, "rulekit.rules.RuleSet.growing_time"]], "induction_measure (rulekit.rules.inductionparameters property)": [[5, "rulekit.rules.InductionParameters.induction_measure"]], "is_voting (rulekit.rules.ruleset property)": [[5, "rulekit.rules.RuleSet.is_voting"]], "kaplan_meier_estimator (rulekit.rules.survivalrule property)": [[5, "rulekit.rules.SurvivalRule.kaplan_meier_estimator"]], "parameters (rulekit.rules.ruleset property)": [[5, "rulekit.rules.RuleSet.parameters"]], "print_stats() (rulekit.rules.baserule method)": [[5, "rulekit.rules.BaseRule.print_stats"]], "pruning_measure (rulekit.rules.inductionparameters property)": [[5, "rulekit.rules.InductionParameters.pruning_measure"]], "pruning_time (rulekit.rules.ruleset property)": [[5, "rulekit.rules.RuleSet.pruning_time"]], "pvalue (rulekit.rules.baserule property)": [[5, "rulekit.rules.BaseRule.pvalue"]], "rulekit.rules": [[5, "module-rulekit.rules"]], "rules (rulekit.rules.ruleset property)": [[5, "rulekit.rules.RuleSet.rules"]], "stats (rulekit.rules.baserule property)": [[5, "rulekit.rules.BaseRule.stats"]], "stats (rulekit.rules.ruleset property)": [[5, "rulekit.rules.RuleSet.stats"]], "total_time (rulekit.rules.ruleset property)": [[5, "rulekit.rules.RuleSet.total_time"]], "voting_measure (rulekit.rules.inductionparameters property)": [[5, "rulekit.rules.InductionParameters.voting_measure"]], "weight (rulekit.rules.baserule property)": [[5, "rulekit.rules.BaseRule.weight"]], "weighted_n (rulekit.rules.baserule property)": [[5, "rulekit.rules.BaseRule.weighted_N"], [5, "rulekit.rules.BaseRule.weighted_n"]], "weighted_p (rulekit.rules.baserule property)": [[5, "rulekit.rules.BaseRule.weighted_P"], [5, "rulekit.rules.BaseRule.weighted_p"]], "n (rulekit.stats.rulestatistics attribute)": [[6, "rulekit.stats.RuleStatistics.N"], [6, "rulekit.stats.RuleStatistics.n"]], "p (rulekit.stats.rulestatistics attribute)": [[6, "rulekit.stats.RuleStatistics.P"], [6, "rulekit.stats.RuleStatistics.p"]], "rulesetstatistics (class in rulekit.stats)": [[6, "rulekit.stats.RuleSetStatistics"]], "rulestatistics (class in rulekit.stats)": [[6, "rulekit.stats.RuleStatistics"]], "significance_level (rulekit.stats.rulesetstatistics attribute)": [[6, "rulekit.stats.RuleSetStatistics.SIGNIFICANCE_LEVEL"]], "pvalue (rulekit.stats.rulestatistics attribute)": [[6, "rulekit.stats.RuleStatistics.pvalue"]], "rulekit.stats": [[6, "module-rulekit.stats"]], "weight (rulekit.stats.rulestatistics attribute)": [[6, "rulekit.stats.RuleStatistics.weight"]], "expertsurvivalrules (class in rulekit.survival)": [[7, "rulekit.survival.ExpertSurvivalRules"]], "survivalrules (class in rulekit.survival)": [[7, "rulekit.survival.SurvivalRules"]], "add_event_listener() (rulekit.survival.expertsurvivalrules method)": [[7, "rulekit.survival.ExpertSurvivalRules.add_event_listener"]], "add_event_listener() (rulekit.survival.survivalrules method)": [[7, "rulekit.survival.SurvivalRules.add_event_listener"]], "fit() (rulekit.survival.expertsurvivalrules method)": [[7, "rulekit.survival.ExpertSurvivalRules.fit"]], "fit() (rulekit.survival.survivalrules method)": [[7, "rulekit.survival.SurvivalRules.fit"]], "get_coverage_matrix() (rulekit.survival.expertsurvivalrules method)": [[7, "rulekit.survival.ExpertSurvivalRules.get_coverage_matrix"]], "get_coverage_matrix() (rulekit.survival.survivalrules method)": [[7, "rulekit.survival.SurvivalRules.get_coverage_matrix"]], "get_metadata_routing() (rulekit.survival.expertsurvivalrules method)": [[7, "rulekit.survival.ExpertSurvivalRules.get_metadata_routing"]], "get_metadata_routing() (rulekit.survival.survivalrules method)": [[7, "rulekit.survival.SurvivalRules.get_metadata_routing"]], "get_params() (rulekit.survival.expertsurvivalrules method)": [[7, "rulekit.survival.ExpertSurvivalRules.get_params"]], "get_params() (rulekit.survival.survivalrules method)": [[7, "rulekit.survival.SurvivalRules.get_params"]], "get_train_set_kaplan_meier() (rulekit.survival.expertsurvivalrules method)": [[7, "rulekit.survival.ExpertSurvivalRules.get_train_set_kaplan_meier"]], "get_train_set_kaplan_meier() (rulekit.survival.survivalrules method)": [[7, "rulekit.survival.SurvivalRules.get_train_set_kaplan_meier"]], "predict() (rulekit.survival.expertsurvivalrules method)": [[7, "rulekit.survival.ExpertSurvivalRules.predict"]], "predict() (rulekit.survival.survivalrules method)": [[7, "rulekit.survival.SurvivalRules.predict"]], "score() (rulekit.survival.expertsurvivalrules method)": [[7, "rulekit.survival.ExpertSurvivalRules.score"]], "score() (rulekit.survival.survivalrules method)": [[7, "rulekit.survival.SurvivalRules.score"]], "set_params() (rulekit.survival.expertsurvivalrules method)": [[7, "rulekit.survival.ExpertSurvivalRules.set_params"]], "set_params() (rulekit.survival.survivalrules method)": [[7, "rulekit.survival.SurvivalRules.set_params"]]}})
\ No newline at end of file
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 9b5a152..555fe10 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -20,6 +20,6 @@ All package models are writen to be compatible with scikit learn library.
:caption: Table of contents:
Quick start <./rst/quick_start.rst>
- Whats new <./rst/whats_new.rst>
+ Whats new <./rst/whats_new/Changes in this version.ipynb>
Tutorials <./rst/tutorials.rst>
Code documentation <./rst/autodoc.rst>
diff --git a/docs/source/rst/whats_new.rst b/docs/source/rst/whats_new.rst
deleted file mode 100644
index 4de56d3..0000000
--- a/docs/source/rst/whats_new.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-
-What's new
-==========
-
-.. toctree::
- :maxdepth: 1
- :caption: Table of contents:
-
- v2.1.18.0 <./whats_new/Changes in this version.ipynb>
\ No newline at end of file
diff --git a/docs/source/rst/whats_new/Changes in this version.ipynb b/docs/source/rst/whats_new/Changes in this version.ipynb
index 73a2c2a..401e665 100644
--- a/docs/source/rst/whats_new/Changes in this version.ipynb
+++ b/docs/source/rst/whats_new/Changes in this version.ipynb
@@ -4,255 +4,13 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "# What's new in RuleKit version 2.1.21.0?\n",
+ "# What's new in RuleKit version 2.1.24.0?\n",
"\n",
"\n",
- "### 1. Ability to use user-defined quality measures during rule induction, pruning, and voting phases.\n",
- "\n",
- "Users can now define custom quality measures function and use them for: growing, pruning and voting. Defining quality measure function is easy and straightforward, see example below.\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "from rulekit.classification import RuleClassifier\n",
- "\n",
- "def my_induction_measure(p: float, n: float, P: float, N: float) -> float:\n",
- " # do anything you want here and return a single float...\n",
- " return (p + n) / (P + N)\n",
- "\n",
- "def my_pruning_measure(p: float, n: float, P: float, N: float) -> float:\n",
- " return p - n\n",
- "\n",
- "def my_voting_measure(p: float, n: float, P: float, N: float) -> float:\n",
- " return (p + 1) / (p + n + 2)\n",
- "\n",
- "python_clf = RuleClassifier(\n",
- " induction_measure=my_induction_measure,\n",
- " pruning_measure=my_pruning_measure,\n",
- " voting_measure=my_voting_measure,\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "This function was available long ago in the original Java library, but there were some technical problems that prevented its implementation in that package. Now, with the release of RuleKit v2, it is finally available.\n",
- "\n",
- "> ⚠️ Using this feature comes at a price. Using the original set of quality measures from `rulekit.params.Measures` provides an optimized and much faster implementation of these quality functions in Java. Using a custom Python function **will certainly slow down the model learning process**. For example, learning rules on the Iris dataset using the FullCoverage measure went from 1.8 seconds to 10.9 seconds after switching to using the Python implementation of the same measure.\n",
- "\n",
- "\n",
- "### 2. Reading arff files from url via HTTP/HTTPS.\n",
- "\n",
- "In the last version of the package, a new function for reading arff files was added. It made it possible to read an arff file by accepting the file path or a file-like object as an argument. As of this version, the function also accepts URLs, giving it the ability to read an arff dataset directly from some servers via HTTP/HTTPS. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "import pandas as pd\n",
- "from rulekit.arff import read_arff\n",
- "\n",
- "df: pd.DataFrame = read_arff(\n",
- " 'https://raw.githubusercontent.com/'\n",
- " 'adaa-polsl/RuleKit/refs/heads/master/data/seismic-bumps/'\n",
- " 'seismic-bumps.arff'\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 3. Improves rules API\n",
- "\n",
- "Access to some basic rule information was often quite cumbersome in earlier versions of this package. For example, there was no easy way to access information about the decision class of a classification rule. \n",
- "\n",
- "In this version, rule classes and rule sets have been refactored and improved. Below is a list of some operations that are now much easier. \n",
- "\n",
- "#### 3.1 For classification rules\n",
- "\n",
- "You can now access rules decision class via `rulekit.rules.ClassificationRule.decision_class` field. Example below:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Decision class of the first rule: 0\n"
- ]
- }
- ],
- "source": [
- "import pandas as pd\n",
- "from rulekit.arff import read_arff\n",
- "from rulekit.classification import RuleClassifier\n",
- "from rulekit.rules import RuleSet, ClassificationRule\n",
- "\n",
- "DATASET_URL: str = (\n",
- " 'https://raw.githubusercontent.com/'\n",
- " 'adaa-polsl/RuleKit/refs/heads/master/data/seismic-bumps/'\n",
- " 'seismic-bumps.arff'\n",
- ")\n",
- "df: pd.DataFrame = read_arff(DATASET_URL)\n",
- "X, y = df.drop('class', axis=1), df['class']\n",
- "\n",
- "clf: RuleClassifier = RuleClassifier()\n",
- "clf.fit(X, y)\n",
- "\n",
- "# RuleSet class became generic now\n",
- "ruleset: RuleSet[ClassificationRule] = clf.model\n",
- "rule: ClassificationRule = ruleset.rules[0]\n",
- "print('Decision class of the first rule: ', rule.decision_class)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### 3.2 For regression rules\n",
- "\n",
- "You can now access rules decision attribute value via `rulekit.rules.RegressionRule.conclusion_value` field. Example below:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Decision value of the first rule: 0.40274932614553977\n"
- ]
- }
- ],
- "source": [
- "import pandas as pd\n",
- "from rulekit.arff import read_arff\n",
- "from rulekit.regression import RuleRegressor\n",
- "from rulekit.rules import RuleSet, RegressionRule\n",
- "\n",
- "DATASET_URL: str = (\n",
- " 'https://raw.githubusercontent.com/'\n",
- " 'adaa-polsl/RuleKit/master/data/methane/'\n",
- " 'methane-train.arff'\n",
- ")\n",
- "df: pd.DataFrame = read_arff(DATASET_URL)\n",
- "X, y = df.drop('MM116_pred', axis=1), df['MM116_pred']\n",
- "\n",
- "reg = RuleRegressor()\n",
- "reg.fit(X, y)\n",
- "\n",
- "ruleset: RuleSet[RegressionRule] = reg.model\n",
- "rule: RegressionRule = ruleset.rules[0]\n",
- "print('Decision value of the first rule: ', rule.conclusion_value)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### 3.3 For survival rules\n",
- "\n",
- "More changes have been made for survival rules. \n",
- "\n",
- "First, there is a new class `rulekit.kaplan_meier.KaplanMeierEstimator`, which represents Kaplan-Meier estimator rules. In the future, prediction arrays for survival problems will probably be moved from dictionary arrays to arrays of such objects, but this would be a breaking change unfortunately \n",
- "\n",
- "In addition, one can now easily access the Kaplan-Meier curve of the entire training dataset using the `rulekit.survival.SurvivalRules.get_train_set_kaplan_meier` method.\n",
- "\n",
- "Such curves can be easily plotted using the charting package of your choice."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 14,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- ""
- ]
- },
- "execution_count": 14,
- "metadata": {},
- "output_type": "execute_result"
- },
- {
- "data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjAAAAGdCAYAAAAMm0nCAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAABAU0lEQVR4nO3deXxU1f3/8fdNyGQhJAEJSYAYkE1QCAKCERWs0QQsFWwVESXgwhcVN6QCioRFTWuRolbBrwv0a7EgFNSfLCpRVBDZBAFZFGSrkgACCRAgITm/P2KGDGSbMJOZybyej8c8nLlz7p1zTyedD+d8zjmWMcYIAADAhwR4ugIAAADOIoABAAA+hwAGAAD4HAIYAADgcwhgAACAzyGAAQAAPocABgAA+BwCGAAA4HPqeLoCVVFUVKRffvlF9erVk2VZnq4OAACoAmOMjh07psaNGysgwLV9Jj4RwPzyyy+Kj4/3dDUAAEA17Nu3T02bNnXpNX0igKlXr56k4gaIiIjwcG0AAEBV5ObmKj4+3v477ko+EcCUDBtFREQQwAAA4GPckf5BEi8AAPA5BDAAAMDnEMAAAACf4xM5MACA8hUWFqqgoMDT1YAfCgwMVJ06dTyyxAkBDAD4sOPHj+u///2vjDGergr8VFhYmOLi4mSz2Wr0c50OYL788kv97W9/07p167R//34tWLBAffv2rfCcZcuWacSIEfr+++8VHx+vsWPHavDgwdWsMgBAKu55+e9//6uwsDBFR0ez0CdqlDFG+fn5OnjwoHbt2qVWrVq5fLG6ijgdwJw4cUKJiYm65557dOutt1ZafteuXbr55ps1bNgwzZo1S5mZmbrvvvsUFxenlJSUalUaACAVFBTIGKPo6GiFhoZ6ujrwQ6GhoQoKCtKePXuUn5+vkJCQGvtspwOYXr16qVevXlUuP336dDVv3lwvvviiJKlt27Zavny5/v73vxPAAIAL0PMCT6rJXheHz3X3B6xcuVLJyckOx1JSUrRy5Up3fzQAAKil3B7AZGVlKSYmxuFYTEyMcnNzdfLkyTLPOX36tHJzcx0eAADvNn78eHXs2NHT1aiWZs2aaerUqZ6uBpzglevAZGRkKDIy0v5gI0cAqL7BgwefN9li3rx5CgkJsQ/v+5Jly5bJsizVr19fp06dcnhvzZo1sizL6WG1NWvWaOjQoa6sJtzM7QFMbGyssrOzHY5lZ2crIiKi3KSzMWPGKCcnx/7Yt2+f6ytmjJR/ovjB9EMAfuTNN9/UwIEDNW3aND3xxBOerk611atXTwsWLHA49tZbb+niiy92+lrR0dEKCwurdl3y8/Orfa6zWPOnmNsDmKSkJGVmZjoc+/TTT5WUlFTuOcHBwfaNG922gWNBnvR84+JHQZ7rrw8AXuiFF17Qww8/rNmzZ2vIkCH241OmTFH79u1Vt25dxcfH68EHH9Tx48ft78+cOVNRUVF6//331apVK4WEhCglJaXCf2CuWbNGN954oxo2bKjIyEj16NFD3377rUMZy7L05ptvql+/fgoLC1OrVq304YcfVule0tLS9Pbbb9tfnzx5UrNnz1ZaWtp5ZZcvX65rr71WoaGhio+P1yOPPKITJ07Y3z93COno0aO67777FB0drYiICP3ud7/Td999Z3+/ZLjszTffVPPmzSucfbNixQr17NlTYWFhql+/vlJSUnTkyJEyP1eSOnbsqPHjxzu00bRp0/SHP/xBdevW1aRJk9S0aVNNmzbN4bz169crICBAe/bsqdI9fPfdd7r++utVr149RUREqHPnzlq7dm259+FtnA5gjh8/rg0bNmjDhg2SiqdJb9iwQXv37pVU3HsyaNAge/lhw4bpp59+0pNPPqlt27bptdde03vvvafHH3/cNXdQTaUXfWIBKAD+YNSoUZo0aZI++ugj9evXz+G9gIAAvfzyy/r+++/1z3/+U5999pmefPJJhzJ5eXl67rnn9H//939asWKFjh49qjvuuKPczzt27JjS0tK0fPlyffPNN2rVqpV69+6tY8eOOZSbMGGCbr/9dm3cuFG9e/fWwIEDdfjw4Urv5+6779ZXX31l//35z3/+o2bNmqlTp04O5Xbu3KnU1FT98Y9/1MaNGzVnzhwtX75cw4cPL/fat912mw4cOKDFixdr3bp16tSpk2644QaHeu3YsUP/+c9/NH/+fPtv4rk2bNigG264Qe3atdPKlSu1fPly9enTR4WFhZXeX2njx49Xv379tGnTJt13330aMGCA3n33XYcys2bNUvfu3ZWQkFClexg4cKCaNm2qNWvWaN26dRo9erSCgoLs17MsSzNnznSqnjXKOOnzzz83ks57pKWlGWOMSUtLMz169DjvnI4dOxqbzWYuueQSM2PGDKc+Mycnx0gyOTk5zla3XCeOHTUmPcKY9Iji5wDgY06ePGm2bNliTp48WWG5tLQ0Y7PZjCSTmZlZpWvPnTvXXHTRRfbXM2bMMJLMN998Yz+2detWI8msWrXKGGNMenq6SUxMLPeahYWFpl69eub//b//Zz8myYwdO9b++vjx40aSWbx4cbnXKfkdOnLkiOnbt6+ZMGGCMcaY66+/3rz00ktmwYIFpvTP27333muGDh3qcI2vvvrKBAQE2NsuISHB/P3vf7e/FxERYU6dOuVwTosWLczrr79uv9egoCBz4MCBcutpjDEDBgww3bt3L/f90p9bIjEx0aSnp9tfSzKPPfaYQ5n169cby7LMnj17jDHFbdukSRMzbdq0Kt9DvXr1zMyZM8utW5s2bcz8+fMrvD9jKv4euuP3u4TT68D07Nmzwh6LsqK1nj17av369c5+VA2iBwZA7dahQwcdOnRI6enp6tq1q8LDwx3eX7p0qTIyMrRt2zbl5ubqzJkzOnXqlPLy8uy5IXXq1NGVV15pP+fSSy9VVFSUtm7dqq5du573mdnZ2Ro7dqyWLVumAwcOqLCwUHl5efYek9J1K1G3bl1FRETowIEDkqTLLrvMPiRy7bXXavHixQ7n3nPPPXr00Ud11113aeXKlZo7d66++uorhzLfffedNm7cqFmzZtmPGWNUVFSkXbt2qW3btueVP378uC666CKH4ydPntTOnTvtrxMSEhQdHX3efZe2YcMG3XbbbRWWqYouXbo4vO7YsaPatm2rd999V6NHj9YXX3yhAwcO2D+rKvcwYsQI3XfffXrnnXeUnJys2267TS1atLCX3bZt2wXX253YC0lSyDu/l4Z9JbEYFIBaqkmTJpo3b56uv/56paamavHixapXr54kaffu3fr973+vBx54QM8995waNGig5cuX695771V+fn61k1vT0tL066+/6qWXXlJCQoKCg4OVlJR0XsJr6WELqXjooqioSJK0aNEie9JqWRM/evXqpaFDh+ree+9Vnz59zvvBlopTH/7nf/5HjzzyyHnvlZXwe/z4ccXFxWnZsmXnvRcVFWV/Xrdu3fNv+hyVrZAcEBBwXqdAWUm6ZX3WwIED7QHMu+++q9TUVPv9V+Uexo8frzvvvFMLFy7U4sWLlZ6ertmzZ583vOit/DeACQrT90UJuixgjwKyNxUn8toq/zICgK9KSEjQF198YQ9ilixZonr16mndunUqKirSiy++aF9V9b333jvv/DNnzmjt2rX23pbt27fr6NGj5/VglFixYoVee+019e7dW5K0b98+HTp0yOk6V6ROnToaNGiQXnjhhfN6Z0p06tRJW7ZsUcuWLav0mZ06dVJWVpbq1KmjZs2aOVXfc3Xo0EGZmZmaMGFCme9HR0dr//799te5ubnatWtXla595513auzYsVq3bp3mzZun6dOnO30PrVu3VuvWrfX4449rwIABmjFjhs8EMF65DkyNsCzdlp/u6VoAQI2Kj4+3D+mkpKQoNzdXLVu2VEFBgV555RX99NNPeueddxx+DEsEBQXp4Ycf1qpVq7Ru3ToNHjxYV111VZnDR5LUqlUrvfPOO9q6datWrVqlgQMHumXPpkmTJungwYPlbk8zatQoff311xo+fLg2bNigH3/8UR988EG5SbzJyclKSkpS37599cknn2j37t36+uuv9fTTTzs9S2fMmDFas2aNHnzwQW3cuFHbtm3TtGnT7IHc7373O73zzjv66quvtGnTJqWlpSkwMLBK127WrJmuvvpq3XvvvSosLNQf/vCHKt/DyZMnNXz4cC1btkx79uzRihUrtGbNGodg9NJLLz1vmro38d8ARo6ZLxXl9QBAbdK0aVMtW7ZMhw4dUkpKipo3b64pU6bor3/9qy6//HLNmjVLGRkZ550XFhamUaNG6c4771T37t0VHh6uOXPmlPs5b731lo4cOaJOnTrp7rvv1iOPPKJGjRq5/H5sNpsaNmxY7uJ1HTp00BdffKEffvhB1157ra644gqNGzdOjRs3LrO8ZVlatGiRrrvuOg0ZMkStW7fWHXfcoT179py3snxlWrdurU8++UTfffedunbtqqSkJH3wwQeqU6d4AGTMmDHq0aOHfv/73+vmm29W3759HfJQKjNw4EB999136tevn0NwWNk9BAYG6tdff9WgQYPUunVr3X777erVq5dDT9H27duVk5Pj1P3WJMv4wC93bm6uIiMjlZOT47I1YYwxuvWlpVpw9E+SpLyRexUWHumSawNATTh16pR27dpV6TokrjBz5kw99thjOnr0qFs/B76nou+hO36/S/htD4xlWfrXvWV3ewIAAO/mtwGMxKQjAAB8lV8HMACAqhk8eDDDR/AqBDC/ycsvJJEXAAAfQQDzm2tf+Fy3TV9J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//Wvf9WsWbM0Y8YMrVixQrm5uXr//fcrrMOqVat07733avjw4dqwYYOuv/56Pfvssw5lKru/+fPnq2nTppo4caL2799vD6pOnTqlzp07a+HChdq8ebOGDh2qu+++W6tXr5ZU3Ns1YMAA3XPPPdq6dauWLVumW2+9Vea3/61mzZqlcePG6bnnntPWrVv1/PPP65lnntE///lPSbJfZ+nSpdq/f7/mz59f4b3WNIaQAKC2KMiTnm/smc9+6hfJVtcll5o4caJuvPFG++sGDRooMTHR/nrSpElasGCBPvzwQw0fPrzc6wwePFgDBgyQJD3//PN6+eWXtXr1aqWmppZZvqCgQNOnT1eLFi0kScOHD9fEiRPt77/yyisaM2aM+vXrJ0n6xz/+oUWLFlV4Ly+99JJSU1P15JNPSpJat26tr7/+WkuWLLGXSUxMrPD+GjRooMDAQNWrV89h2KtJkyYOAdbDDz+sjz/+WO+99566du2q/fv368yZM7r11luVkJAgSWrfvr29fHp6ul588UXdeuutkop7XLZs2aLXX39daWlp9mG5iy66yCuH2+iBKQN7OQKA53Tp0sXh9fHjxzVy5Ei1bdtWUVFRCg8P19atWyvtgenQoYP9ed26dRUREaEDBw6UWz4sLMwevEhSXFycvXxOTo6ys7PVtWtX+/uBgYHq3LlzhXXYunWrunXr5nAsKSnJJfdXWFioSZMmqX379mrQoIHCw8P18ccf289LTEzUDTfcoPbt2+u2227TG2+8oSNHjkiSTpw4oZ07d+ree+9VeHi4/fHss89q586dFX6ut6AHpgx3v7VK/3n0Rvs4IwD4hKCw4p4QT322i9St69iTM3LkSH366aeaPHmyWrZsqdDQUP3pT39Sfn5+xVUKCnJ4bVmWioqKnCpvauBftNW9v7/97W966aWXNHXqVLVv315169bVY489Zj8vMDBQn376qb7++mt98skneuWVV/T0009r1apVCgsr/t/rjTfeOC/ACgwMdM+NuhgBzG9Cg87+Dzbp8EidzF+nsOCgCs4AAC9jWS4bxvEmK1as0ODBg+1DN8ePH9fu3btrtA6RkZGKiYnRmjVrdN1110kq7gH59ttv1bFjx3LPa9u2rVatWuVw7JtvvnF4XZX7s9lsKiwsPO+8W265RXfddZckqaioSD/88IPatWtnL2NZlrp3767u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K/4ufvrpJxMWFmZGjBhhtmzZYl555RUTGBholixZUqP3W5GqtEWPHj3M/fff7/DdyMnJsb9fW9riww8/NAsXLjQ//PCD2b59u3nqqadMUFCQ2bx5szHGf74TxlTeFt70nfDLAKZr167moYcesr8uLCw0jRs3NhkZGR6sleulp6ebxMTEMt87evSoCQoKMnPnzrUf27p1q5FkVq5caYwp/uELCAgwWVlZ9jLTpk0zERER5vTp026tuyud+6NdVFRkYmNjzd/+9jf7saNHj5rg4GDz73//2xhjzJYtW4wks2bNGnuZxYsXG8uyzM8//2yMMea1114z9evXd2iLUaNGmTZt2rj5jqqvvADmlltuKfec2toWxhhz4MABI8l88cUXxhjX/V08+eST5rLLLnP4rP79+5uUlBR331K1ndsWxhT/WD366KPlnlNb28IYY+rXr2/efPNNv/5OlChpC2O86zvhd0NI+fn5WrdunZKTk+3HAgIClJycrJUrV3qwZu7x448/qnHjxrrkkks0cOBA7d27V5K0bt06FRQUOLTDpZdeqosvvtjeDitXrlT79u0VExNjL5OSkqLc3Fx9//33NXsjLrRr1y5lZWU53HtkZKS6devmcO9RUVHq0qWLvUxycrICAgK0atUqe5nrrrtONpvNXiYlJUXbt2/XkSNHauhuXGPZsmVq1KiR2rRpowceeEC//vqr/b3a3BY5OTmSpAYNGkhy3d/FypUrHa5RUsab/z/m3LYoMWvWLDVs2FCXX365xowZo7y8PPt7tbEtCgsLNXv2bJ04cUJJSUl+/Z04ty1KeMt3wic2c3SlQ4cOqbCw0KFxJSkmJkbbtm3zUK3co1u3bpo5c6batGmj/fv3a8KECbr22mu1efNmZWVlyWazKSoqyuGcmJgYZWVlSZKysrLKbKeS93xVSd3LurfS996oUSOH9+vUqaMGDRo4lGnevPl51yh5r379+m6pv6ulpqbq1ltvVfPmzbVz50499dRT6tWrl1auXKnAwMBa2xZFRUV67LHH1L17d11++eWS5LK/i/LK5Obm6uTJkwoNDXXHLVVbWW0hSXfeeacSEhLUuHFjbdy4UaNGjdL27ds1f/58SbWrLTZt2qSkpCSdOnVK4eHhWrBggdq1a6cNGzb43XeivLaQvOs74XcBjD/p1auX/XmHDh3UrVs3JSQk6L333vOqPxZ41h133GF/3r59e3Xo0EEtWrTQsmXLdMMNN3iwZu710EMPafPmzVq+fLmnq+Jx5bXF0KFD7c/bt2+vuLg43XDDDdq5c6datGhR09V0qzZt2mjDhg3KycnRvHnzlJaWpi+++MLT1fKI8tqiXbt2XvWd8LshpIYNGyowMPC8DPLs7GzFxsZ6qFY1IyoqSq1bt9aOHTsUGxur/Px8HT161KFM6XaIjY0ts51K3vNVJXWv6DsQGxurAwcOOLx/5swZHT58uNa3zyWXXKKGDRtqx44dkmpnWwwfPlwfffSRPv/8czVt2tR+3FV/F+WViYiI8Lp/PJTXFmXp1q2bJDl8N2pLW9hsNrVs2VKdO3dWRkaGEhMT9dJLL/nld6K8tiiLJ78TfhfA2Gw2de7cWZmZmfZjRUVFyszMdBjjq42OHz+unTt3Ki4uTp07d1ZQUJBDO2zfvl179+61t0NSUpI2bdrk8OP16aefKiIiwt6d6IuaN2+u2NhYh3vPzc3VqlWrHO796NGjWrdunb3MZ599pqKiIvsfbFJSkr788ksVFBTYy3z66adq06aNVw6ZVNV///tf/frrr4qLi5NUu9rCGKPhw4drwYIF+uyzz84b9nLV30VSUpLDNUrKeNP/x1TWFmXZsGGDJDl8N2pDW5SlqKhIp0+f9qvvRHlK2qIsHv1OOJXyW0vMnj3bBAcHm5kzZ5otW7aYoUOHmqioKIes6drgiSeeMMuWLTO7du0yK1asMMnJyaZhw4bmwIEDxpjiqYEXX3yx+eyzz8zatWtNUlKSSUpKsp9fMh3upptuMhs2bDBLliwx0dHRPjGN+tixY2b9+vVm/fr1RpKZMmWKWb9+vdmzZ48xpngadVRUlPnggw/Mxo0bzS233FLmNOorrrjCrFq1yixfvty0atXKYerw0aNHTUxMjLn77rvN5s2bzezZs01YWJjXTR2uqC2OHTtmRo4caVauXGl27dplli5dajp16mRatWplTp06Zb9GbWmLBx54wERGRpply5Y5TAPNy8uzl3HF30XJNNE///nPZuvWrebVV1/1uimzlbXFjh07zMSJE83atWvNrl27zAcffGAuueQSc91119mvUVvaYvTo0eaLL74wu3btMhs3bjSjR482lmWZTz75xBjjP98JYypuC2/7TvhlAGOMMa+88oq5+OKLjc1mM127djXffPONp6vkcv379zdxcXHGZrOZJk2amP79+5sdO3bY3z958qR58MEHTf369U1YWJjp16+f2b9/v8M1du/ebXr16mVCQ0NNw4YNzRNPPGEKCgpq+lac9vnnnxtJ5z3S0tKMMcVTqZ955hkTExNjgoODzQ033GC2b9/ucI1ff/3VDBgwwISHh5uIiAgzZMgQc+zYMYcy3333nbnmmmtMcHCwadKkifnLX/5SU7dYZRW1RV5enrnppptMdHS0CQoKMgkJCeb+++8/L5ivLW1RVjtIMjNmzLCXcdXfxeeff246duxobDabueSSSxw+wxtU1hZ79+411113nWnQoIEJDg42LVu2NH/+858d1vwwpna0xT333GMSEhKMzWYz0dHR5oYbbrAHL8b4z3fCmIrbwtu+E5YxxjjXZwMAAOBZfpcDAwAAfB8BDAAA8DkEMAAAwOcQwAAAAJ9DAAMAAHwOAQwAAPA5BDAAAMDnEMAAAACfQwADAAB8DgEMAADwOQQwAADA5xDAAAAAn/P/ARyUqwJzYsJCAAAAAElFTkSuQmCC",
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
- "source": [
- "import pandas as pd\n",
- "import matplotlib.pyplot as plt\n",
- "from rulekit.arff import read_arff\n",
- "from rulekit.survival import SurvivalRules\n",
- "from rulekit.rules import RuleSet, SurvivalRule\n",
- "from rulekit.kaplan_meier import KaplanMeierEstimator # this is a new class\n",
- "\n",
- "DATASET_URL: str = (\n",
- " 'https://raw.githubusercontent.com/'\n",
- " 'adaa-polsl/RuleKit/master/data/bmt/'\n",
- " 'bmt.arff'\n",
- ")\n",
- "df: pd.DataFrame = read_arff(DATASET_URL)\n",
- "X, y = df.drop('survival_status', axis=1), df['survival_status']\n",
- "\n",
- "surv = SurvivalRules(survival_time_attr='survival_time')\n",
- "surv.fit(X, y)\n",
- "\n",
- "ruleset: RuleSet[SurvivalRule] = reg.model\n",
- "rule: SurvivalRule = ruleset.rules[0]\n",
- "\n",
- "# you can now easily access Kaplan-Meier estimator of the rules\n",
- "rule_estimator: KaplanMeierEstimator = rule.kaplan_meier_estimator\n",
- "plt.step(\n",
- " rule_estimator.times, \n",
- " rule_estimator.probabilities,\n",
- " label='First rule'\n",
- ")\n",
- "# you can also access training dataset Kaplan-Meier estimator easily\n",
- "train_dataset_estimator: KaplanMeierEstimator = surv.get_train_set_kaplan_meier()\n",
- "plt.step(\n",
- " train_dataset_estimator.times, \n",
- " train_dataset_estimator.probabilities,\n",
- " label='Training dataset'\n",
- ")\n",
- "plt.legend(title='Kaplan-Meier curves:')"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 4. Changes in expert rules induction for regression and survival `❗BREAKING CHANGES`\n",
- "\n",
- "> Note that those changes will likely be reverted on the next version and are caused by a known bug in the original RuleKit library. Fixing it is beyond the scope of this package, which is merely a wrapper for it. \n",
- "\n",
- "Since this version, there has been a change in the way expert rules and conditions for regression and survival problems are communicated. All you have to do is remove conclusion part of those rules (everything after **THEN**).\n",
- "\n",
- "Expert rules before:"
+ "### 1. Revert breaking changes in expert rules induction for regression and survival \n",
+ "The latest version 2.1.21.0 introduced some groundbreaking changes, which you can read more\n",
+ "about them in the latest [release note](https://github.com/adaa-polsl/RuleKit-python/releases/tag/v2.1.21.0).\n",
+ "Now rules and expert conditions can be defined in both the old and new formats, see example below."
]
},
{
@@ -261,23 +19,16 @@
"metadata": {},
"outputs": [],
"source": [
+ "# both variants will work the same\n",
"expert_rules = [\n",
" (\n",
" 'rule-0',\n",
" 'IF [[CD34kgx10d6 = (-inf, 10.0)]] AND [[extcGvHD = {0}]] THEN survival_status = {NaN}'\n",
- " )\n",
- "]\n",
- "\n",
- "expert_preferred_conditions = [\n",
+ " ),\n",
" (\n",
- " 'attr-preferred-0',\n",
- " 'inf: IF [CD34kgx10d6 = Any] THEN survival_status = {NaN}'\n",
- " )\n",
- "]\n",
- "\n",
- "\n",
- "expert_forbidden_conditions = [\n",
- " ('attr-forbidden-0', 'IF [ANCrecovery = Any] THEN survival_status = {NaN}')\n",
+ " 'rule-0',\n",
+ " 'IF [[CD34kgx10d6 = (-inf, 10.0)]] AND [[extcGvHD = {0}]] THEN'\n",
+ " ),\n",
"]"
]
},
@@ -285,33 +36,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "And now:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "expert_rules = [\n",
- " (\n",
- " 'rule-0',\n",
- " 'IF [[CD34kgx10d6 = (-inf, 10.0)]] AND [[extcGvHD = {0}]] THEN'\n",
- " )\n",
- "]\n",
+ "### 2. Upgrade to new version of RuleKit\n",
"\n",
- "expert_preferred_conditions = [\n",
- " (\n",
- " 'attr-preferred-0',\n",
- " 'inf: IF [CD34kgx10d6 = Any] THEN'\n",
- " )\n",
- "]\n",
- "\n",
- "\n",
- "expert_forbidden_conditions = [\n",
- " ('attr-forbidden-0', 'IF [ANCrecovery = Any] THEN')\n",
- "]"
+ "In the new version of the Java RuleKit library, many bugs regarding expert induction have been corrected."
]
},
{
@@ -320,10 +47,8 @@
"source": [
"### Other changes\n",
"\n",
- "* Fix expert rules parsing.\n",
- "* Conditions printed in the order they had been added to the rule.\n",
- "* Fixed bug when using `sklearn.base.clone` function with RuleKit model classes.\n",
- "* Update tutorials in the documentation."
+ "* Improve flake8 score\n",
+ "* Add more unit tests."
]
}
],
diff --git a/rulekit/survival.py b/rulekit/survival.py
index 07b73c6..8f64d67 100644
--- a/rulekit/survival.py
+++ b/rulekit/survival.py
@@ -42,6 +42,7 @@ class _SurvivalModelsParams(BaseModel):
complementary_conditions: Optional[bool] = DEFAULT_PARAMS_VALUE[
"complementary_conditions"
]
+ max_rule_count: int = DEFAULT_PARAMS_VALUE["max_rule_count"]
class _SurvivalExpertModelParams(_SurvivalModelsParams, ExpertModelParams):
diff --git a/tests/test_survival.py b/tests/test_survival.py
index a9c6a4d..bda5f44 100644
--- a/tests/test_survival.py
+++ b/tests/test_survival.py
@@ -185,6 +185,23 @@ def test_getting_training_dataset_kaplan_meier_estimator(self):
"Estimator should contain probabilities for each unique time from the dataset",
)
+ def test_max_rule_count(self):
+ MAX_RULE_COUNT = 3
+ df: pd.DataFrame = read_arff(
+ os.path.join(dir_path, "resources", "data", "bmt-train-0.arff")
+ )
+ X, y = df.drop("survival_status", axis=1), df["survival_status"]
+ clf = survival.SurvivalRules(
+ survival_time_attr="survival_time",
+ max_rule_count=MAX_RULE_COUNT,
+ )
+ clf.fit(X, y)
+ self.assertLessEqual(
+ len(clf.model.rules),
+ MAX_RULE_COUNT,
+ f"Ruleset should contain no more than {MAX_RULE_COUNT} rules according to max_rule_count parameter",
+ )
+
class TestExpertSurvivalRules(unittest.TestCase):