psyke 0.10.2.dev10__tar.gz → 0.10.4.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of psyke might be problematic. Click here for more details.

Files changed (83) hide show
  1. {psyke-0.10.2.dev10/psyke.egg-info → psyke-0.10.4.dev1}/PKG-INFO +1 -1
  2. psyke-0.10.4.dev1/VERSION +1 -0
  3. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/hypercubic/gridrex/__init__.py +2 -2
  4. psyke-0.10.4.dev1/psyke/genetic/fgin/__init__.py +74 -0
  5. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/genetic/gin/__init__.py +24 -22
  6. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1/psyke.egg-info}/PKG-INFO +1 -1
  7. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke.egg-info/SOURCES.txt +1 -0
  8. psyke-0.10.2.dev10/VERSION +0 -1
  9. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/LICENSE +0 -0
  10. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/MANIFEST.in +0 -0
  11. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/README.md +0 -0
  12. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/__init__.py +0 -0
  13. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/clustering/__init__.py +0 -0
  14. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/clustering/cream/__init__.py +0 -0
  15. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/clustering/exact/__init__.py +0 -0
  16. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/clustering/utils.py +0 -0
  17. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/__init__.py +0 -0
  18. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/cart/CartPredictor.py +0 -0
  19. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/cart/FairTree.py +0 -0
  20. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/cart/FairTreePredictor.py +0 -0
  21. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/cart/__init__.py +0 -0
  22. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/hypercubic/__init__.py +0 -0
  23. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/hypercubic/cosmik/__init__.py +0 -0
  24. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/hypercubic/creepy/__init__.py +0 -0
  25. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/hypercubic/divine/__init__.py +0 -0
  26. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/hypercubic/ginger/__init__.py +0 -0
  27. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/hypercubic/gridex/__init__.py +0 -0
  28. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/hypercubic/hex/__init__.py +0 -0
  29. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/hypercubic/hypercube.py +0 -0
  30. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/hypercubic/iter/__init__.py +0 -0
  31. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/hypercubic/strategy.py +0 -0
  32. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/hypercubic/utils.py +0 -0
  33. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/real/__init__.py +0 -0
  34. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/real/utils.py +0 -0
  35. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/trepan/__init__.py +0 -0
  36. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/extraction/trepan/utils.py +0 -0
  37. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/genetic/__init__.py +0 -0
  38. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/hypercubepredictor.py +0 -0
  39. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/schema/__init__.py +0 -0
  40. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/tuning/__init__.py +0 -0
  41. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/tuning/crash/__init__.py +0 -0
  42. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/tuning/orchid/__init__.py +0 -0
  43. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/tuning/pedro/__init__.py +0 -0
  44. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/utils/__init__.py +0 -0
  45. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/utils/dataframe.py +0 -0
  46. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/utils/logic.py +0 -0
  47. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/utils/metrics.py +0 -0
  48. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/utils/plot.py +0 -0
  49. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke/utils/sorted.py +0 -0
  50. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke.egg-info/dependency_links.txt +0 -0
  51. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke.egg-info/not-zip-safe +0 -0
  52. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke.egg-info/requires.txt +0 -0
  53. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/psyke.egg-info/top_level.txt +0 -0
  54. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/pyproject.toml +0 -0
  55. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/setup.cfg +0 -0
  56. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/setup.py +0 -0
  57. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/__init__.py +0 -0
  58. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/clustering/__init__.py +0 -0
  59. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/extraction/__init__.py +0 -0
  60. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/extraction/cart/__init__.py +0 -0
  61. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/extraction/cart/test_cart.py +0 -0
  62. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/extraction/cart/test_simplified_cart.py +0 -0
  63. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/extraction/hypercubic/__init__.py +0 -0
  64. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/extraction/hypercubic/gridex/__init__.py +0 -0
  65. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/extraction/hypercubic/gridex/test_gridex.py +0 -0
  66. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/extraction/hypercubic/iter/__init__.py +0 -0
  67. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/extraction/hypercubic/iter/test_iter.py +0 -0
  68. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/extraction/hypercubic/test_hypercube.py +0 -0
  69. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/extraction/real/__init__.py +0 -0
  70. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/extraction/real/test_real.py +0 -0
  71. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/extraction/real/test_rule.py +0 -0
  72. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/extraction/trepan/__init__.py +0 -0
  73. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/extraction/trepan/test_node.py +0 -0
  74. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/extraction/trepan/test_split.py +0 -0
  75. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/extraction/trepan/test_trepan.py +0 -0
  76. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/utils/__init__.py +0 -0
  77. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/utils/test_prune.py +0 -0
  78. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/utils/test_simplify.py +0 -0
  79. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/psyke/utils/test_simplify_formatter.py +0 -0
  80. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/resources/__init__.py +0 -0
  81. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/resources/datasets/__init__.py +0 -0
  82. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/resources/predictors/__init__.py +0 -0
  83. {psyke-0.10.2.dev10 → psyke-0.10.4.dev1}/test/resources/tests/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: psyke
3
- Version: 0.10.2.dev10
3
+ Version: 0.10.4.dev1
4
4
  Summary: Python-based implementation of PSyKE, i.e. a Platform for Symbolic Knowledge Extraction
5
5
  Home-page: https://github.com/psykei/psyke-python
6
6
  Author: Matteo Magnini
@@ -0,0 +1 @@
1
+ 0.10.4.dev1
@@ -5,12 +5,12 @@ from psyke.extraction.hypercubic.gridex import GridEx
5
5
 
6
6
  class GridREx(GridEx):
7
7
  """
8
- Explanator implementing GridREx algorithm.
8
+ Explanator implementing GridREx algorithm, doi:10.24963/kr.2022/57.
9
9
  """
10
10
 
11
11
  def __init__(self, predictor, grid: Grid, min_examples: int, threshold: float, normalization,
12
12
  seed=get_default_random_seed()):
13
13
  super().__init__(predictor, grid, min_examples, threshold, Target.REGRESSION, None, normalization, seed)
14
14
 
15
- def _default_cube(self) -> RegressionCube:
15
+ def _default_cube(self, dimensions=None) -> RegressionCube:
16
16
  return RegressionCube()
@@ -0,0 +1,74 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+
4
+ from psyke import Target
5
+ from psyke.genetic.gin import GIn
6
+
7
+ import skfuzzy as skf
8
+
9
+
10
+ class FGIn(GIn):
11
+
12
+ def __init__(self, train, valid, features, sigmas, slices, min_rules=1, poly=1, alpha=0.5, indpb=0.5, tournsize=3,
13
+ metric='R2', output=Target.REGRESSION, warm=False):
14
+ super().__init__(train, valid, features, sigmas, slices, min_rules, poly, alpha, indpb, tournsize,
15
+ metric, output, warm)
16
+ self.feature_to_idx = {f: i for i, f in enumerate(self.X.columns)}
17
+
18
+ def _evaluate(self, individual=None):
19
+ y_pred, valid_regions = self.__predict(individual or self.best, self.X if self.valid is None else self.valid[0])
20
+ if valid_regions < self.min_rules:
21
+ return -9999,
22
+ return self._score(self.y if self.valid is None else self.valid[1], y_pred),
23
+
24
+ @staticmethod
25
+ def __generate_membership(var, domain, thresholds, shape='tri'):
26
+ th = [var.min()] + [min(max(t, var.min()), var.max()) for t in thresholds] + [var.max()]
27
+
28
+ if shape == 'tri':
29
+ mid = [(x1 + x2) / 2 for x1, x2 in zip(th[:-1], th[1:])]
30
+ return [skf.trapmf(domain, [domain.min()] * 2 + mid[:2])] + \
31
+ [skf.trimf(domain, [x1, x2, x3]) for x1, x2, x3 in zip(mid[:-2], mid[1:-1], mid[2:])] + \
32
+ [skf.trapmf(domain, mid[-2:] + [domain.max()] * 2)]
33
+ if shape == 'trap':
34
+ beg = [None, domain.min()] + [(3 * x1 + x2) / 4 for x1, x2 in zip(th[1:-1], th[2:])] + [domain.max()]
35
+ end = [domain.min()] + [(x1 + 3 * x2) / 4 for x1, x2 in zip(th[:-2], th[1:-1])] + [domain.max()]
36
+ return [skf.trapmf(domain, [end[i - 1], beg[i], end[i], beg[i + 1]]) for i in range(1, len(th))]
37
+ raise ValueError('Supported shape values are only \'tri\' and \'trap\'')
38
+
39
+ @staticmethod
40
+ def __extend_domain(x, q_low=0.05, q_high=0.95, p=0.05, k_sigma=2.0, abs_min_margin=0.0):
41
+ ql, qh = np.quantile(x, [q_low, q_high])
42
+ margin = max(p * (qh - ql), k_sigma * np.std(x), abs_min_margin)
43
+ return np.array([ql - margin, qh + margin])
44
+
45
+ def __get_activations(self, x, functions_domains, valid_masks):
46
+ levels = [np.array([skf.interp_membership(domain, mf, x[index]) for mf in mfs])
47
+ for mfs, domain, index in functions_domains.values()]
48
+ return np.prod(np.meshgrid(*levels, indexing='ij'), axis=0).ravel()[valid_masks]
49
+
50
+ def __fuzzify(self, cuts):
51
+ cuts = dict(zip(self.features, cuts))
52
+ doms = {c: FGIn.__extend_domain(self.X[c]) for c in self.features}
53
+ return {c: (FGIn.__generate_membership(self.X[c], doms[c], cuts[c], 'trap'), doms[c],
54
+ self.feature_to_idx[c]) for c in self.features}
55
+
56
+ def __predict(self, individual=None, to_pred=None):
57
+ cuts = self._get_cuts(individual or self.best)
58
+ masks = np.array([self._region(to_pred, cuts) == r for r in range(np.prod([s + 1 for s in self.slices]))])
59
+ valid_masks = masks.sum(axis=1) >= 3
60
+
61
+ masks = [mask for mask in masks if mask.sum() >= 3]
62
+ functions_domains = self.__fuzzify(cuts)
63
+
64
+ pred = np.array([self._output_estimation(mask, to_pred) for mask in masks]).T
65
+ activations = np.array([self.__get_activations(x, functions_domains, valid_masks) for x in to_pred.values])
66
+
67
+ if self.output == Target.CLASSIFICATION:
68
+ classes, idx = np.unique(pred, return_inverse=True)
69
+ pred = classes[np.argmax(np.vstack([activations[:, idx == i].sum(axis=1) for i, c in enumerate(classes)]),
70
+ axis=0)]
71
+ else:
72
+ pred = (pred * activations).sum(axis=1)
73
+
74
+ return pd.DataFrame(pred, index=to_pred.index), len(masks)
@@ -34,13 +34,13 @@ class GIn:
34
34
  self.hof = None
35
35
  self.best = None
36
36
 
37
- self.setup(warm)
37
+ self.__setup(warm)
38
38
 
39
- def region(self, X, cuts):
40
- indices = [np.searchsorted(np.array(cut), X[f].to_numpy(), side='right')
39
+ def _region(self, x, cuts):
40
+ indices = [np.searchsorted(np.array(cut), x[f].to_numpy(), side='right')
41
41
  for cut, f in zip(cuts, self.features)]
42
42
 
43
- regions = np.zeros(len(X), dtype=int)
43
+ regions = np.zeros(len(x), dtype=int)
44
44
  multiplier = 1
45
45
  for idx, n in zip(reversed(indices), reversed([len(cut) + 1 for cut in cuts])):
46
46
  regions += idx * multiplier
@@ -48,7 +48,7 @@ class GIn:
48
48
 
49
49
  return regions
50
50
 
51
- def __output_estimation(self, mask, to_pred):
51
+ def _output_estimation(self, mask, to_pred):
52
52
  if self.output == Target.REGRESSION:
53
53
  return LinearRegression().fit(self.poly.fit_transform(self.X)[mask], self.y[mask]).predict(
54
54
  self.poly.fit_transform(to_pred))
@@ -56,9 +56,9 @@ class GIn:
56
56
  return np.mean(self.y[mask])
57
57
  if self.output == Target.CLASSIFICATION:
58
58
  return mode(self.y[mask])
59
- raise TypeError('Supported outputs are Target.{REGRESSION, CONSTANT, CLASSIFICATION}')
59
+ raise ValueError('Supported outputs are Target.{REGRESSION, CONSTANT, CLASSIFICATION}')
60
60
 
61
- def __score(self, true, pred):
61
+ def _score(self, true, pred):
62
62
  if self.metric == 'R2':
63
63
  return r2_score(true, pred)
64
64
  if self.metric == 'MAE':
@@ -69,20 +69,22 @@ class GIn:
69
69
  return f1_score(true, pred, average='weighted')
70
70
  if self.metric == 'ACC':
71
71
  return accuracy_score(true, pred)
72
- raise NameError('Supported metrics are R2, MAE, MSE, F1, ACC')
72
+ raise ValueError('Supported metrics are R2, MAE, MSE, F1, ACC')
73
73
 
74
74
  def predict(self, to_pred):
75
75
  return self.__predict(to_pred=to_pred)[0]
76
76
 
77
- def __predict(self, individual=None, to_pred=None):
78
- individual = individual or self.best
77
+ def _get_cuts(self, individual):
79
78
  boundaries = np.cumsum([0] + list(self.slices))
80
- cuts = [sorted(individual[boundaries[i]:boundaries[i + 1]]) for i in range(len(self.slices))]
79
+ return [sorted(individual[boundaries[i]:boundaries[i + 1]]) for i in range(len(self.slices))]
80
+
81
+ def __predict(self, individual=None, to_pred=None):
82
+ cuts = self._get_cuts(individual or self.best)
81
83
 
82
- regions = self.region(to_pred, cuts)
83
- regionsT = self.region(self.X, cuts)
84
+ regions = self._region(to_pred, cuts)
85
+ regionsT = self._region(self.X, cuts)
84
86
 
85
- y_pred = np.empty(len(to_pred), dtype=f'U{self.y.str.len().max()}') if self.output == Target.CLASSIFICATION \
87
+ pred = np.empty(len(to_pred), dtype=f'U{self.y.str.len().max()}') if self.output == Target.CLASSIFICATION \
86
88
  else np.zeros(len(to_pred))
87
89
  valid_regions = 0
88
90
 
@@ -91,20 +93,20 @@ class GIn:
91
93
  maskT = regionsT == r
92
94
  if min(mask.sum(), maskT.sum()) < 3:
93
95
  if self.output != Target.CLASSIFICATION:
94
- y_pred[mask] = np.mean(self.y)
96
+ pred[mask] = np.mean(self.y)
95
97
  continue
96
- y_pred[mask] = self.__output_estimation(maskT, to_pred[mask])
98
+ pred[mask] = self._output_estimation(maskT, to_pred[mask])
97
99
  valid_regions += 1
98
100
 
99
- return y_pred, valid_regions
101
+ return pred, valid_regions
100
102
 
101
- def evaluate(self, individual=None):
103
+ def _evaluate(self, individual=None):
102
104
  y_pred, valid_regions = self.__predict(individual or self.best, self.X if self.valid is None else self.valid[0])
103
105
  if valid_regions < self.min_rules:
104
106
  return -9999,
105
- return self.__score(self.y if self.valid is None else self.valid[1], y_pred),
107
+ return self._score(self.y if self.valid is None else self.valid[1], y_pred),
106
108
 
107
- def setup(self, warm=False):
109
+ def __setup(self, warm=False):
108
110
  if not warm:
109
111
  creator.create("FitnessMax", base.Fitness, weights=(1.0,))
110
112
  creator.create("Individual", list, fitness=creator.FitnessMax)
@@ -123,7 +125,7 @@ class GIn:
123
125
  self.toolbox.register("mutate", tools.mutGaussian, indpb=self.indpb, mu=0,
124
126
  sigma=sum([[sig] * s for sig, s in zip(self.sigmas, self.slices)], []))
125
127
  self.toolbox.register("select", tools.selTournament, tournsize=self.tournsize)
126
- self.toolbox.register("evaluate", self.evaluate)
128
+ self.toolbox.register("evaluate", self._evaluate)
127
129
 
128
130
  self.stats = tools.Statistics(lambda ind: ind.fitness.values[0])
129
131
  self.stats.register("avg", np.mean)
@@ -139,4 +141,4 @@ class GIn:
139
141
  result, log = algorithms.eaSimple(pop, self.toolbox, cxpb=cxpb, mutpb=mutpb, ngen=n_gen,
140
142
  stats=self.stats, halloffame=self.hof, verbose=False)
141
143
  self.best = tools.selBest(pop, 1)[0]
142
- return self.best, self.evaluate()[0], result, log
144
+ return self.best, self._evaluate()[0], result, log
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: psyke
3
- Version: 0.10.2.dev10
3
+ Version: 0.10.4.dev1
4
4
  Summary: Python-based implementation of PSyKE, i.e. a Platform for Symbolic Knowledge Extraction
5
5
  Home-page: https://github.com/psykei/psyke-python
6
6
  Author: Matteo Magnini
@@ -38,6 +38,7 @@ psyke/extraction/real/utils.py
38
38
  psyke/extraction/trepan/__init__.py
39
39
  psyke/extraction/trepan/utils.py
40
40
  psyke/genetic/__init__.py
41
+ psyke/genetic/fgin/__init__.py
41
42
  psyke/genetic/gin/__init__.py
42
43
  psyke/schema/__init__.py
43
44
  psyke/tuning/__init__.py
@@ -1 +0,0 @@
1
- 0.10.2.dev10
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes