psyke 0.10.1.dev11__tar.gz → 0.10.4__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.1.dev11/psyke.egg-info → psyke-0.10.4}/PKG-INFO +1 -1
  2. psyke-0.10.4/VERSION +1 -0
  3. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/hypercubic/gridrex/__init__.py +2 -2
  4. psyke-0.10.4/psyke/genetic/fgin/__init__.py +74 -0
  5. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/genetic/gin/__init__.py +32 -23
  6. {psyke-0.10.1.dev11 → psyke-0.10.4/psyke.egg-info}/PKG-INFO +1 -1
  7. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke.egg-info/SOURCES.txt +1 -0
  8. psyke-0.10.1.dev11/VERSION +0 -1
  9. {psyke-0.10.1.dev11 → psyke-0.10.4}/LICENSE +0 -0
  10. {psyke-0.10.1.dev11 → psyke-0.10.4}/MANIFEST.in +0 -0
  11. {psyke-0.10.1.dev11 → psyke-0.10.4}/README.md +0 -0
  12. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/__init__.py +0 -0
  13. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/clustering/__init__.py +0 -0
  14. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/clustering/cream/__init__.py +0 -0
  15. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/clustering/exact/__init__.py +0 -0
  16. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/clustering/utils.py +0 -0
  17. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/__init__.py +0 -0
  18. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/cart/CartPredictor.py +0 -0
  19. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/cart/FairTree.py +0 -0
  20. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/cart/FairTreePredictor.py +0 -0
  21. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/cart/__init__.py +0 -0
  22. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/hypercubic/__init__.py +0 -0
  23. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/hypercubic/cosmik/__init__.py +0 -0
  24. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/hypercubic/creepy/__init__.py +0 -0
  25. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/hypercubic/divine/__init__.py +0 -0
  26. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/hypercubic/ginger/__init__.py +0 -0
  27. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/hypercubic/gridex/__init__.py +0 -0
  28. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/hypercubic/hex/__init__.py +0 -0
  29. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/hypercubic/hypercube.py +0 -0
  30. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/hypercubic/iter/__init__.py +0 -0
  31. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/hypercubic/strategy.py +0 -0
  32. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/hypercubic/utils.py +0 -0
  33. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/real/__init__.py +0 -0
  34. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/real/utils.py +0 -0
  35. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/trepan/__init__.py +0 -0
  36. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/extraction/trepan/utils.py +0 -0
  37. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/genetic/__init__.py +0 -0
  38. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/hypercubepredictor.py +0 -0
  39. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/schema/__init__.py +0 -0
  40. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/tuning/__init__.py +0 -0
  41. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/tuning/crash/__init__.py +0 -0
  42. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/tuning/orchid/__init__.py +0 -0
  43. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/tuning/pedro/__init__.py +0 -0
  44. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/utils/__init__.py +0 -0
  45. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/utils/dataframe.py +0 -0
  46. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/utils/logic.py +0 -0
  47. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/utils/metrics.py +0 -0
  48. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/utils/plot.py +0 -0
  49. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke/utils/sorted.py +0 -0
  50. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke.egg-info/dependency_links.txt +0 -0
  51. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke.egg-info/not-zip-safe +0 -0
  52. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke.egg-info/requires.txt +0 -0
  53. {psyke-0.10.1.dev11 → psyke-0.10.4}/psyke.egg-info/top_level.txt +0 -0
  54. {psyke-0.10.1.dev11 → psyke-0.10.4}/pyproject.toml +0 -0
  55. {psyke-0.10.1.dev11 → psyke-0.10.4}/setup.cfg +0 -0
  56. {psyke-0.10.1.dev11 → psyke-0.10.4}/setup.py +0 -0
  57. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/__init__.py +0 -0
  58. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/clustering/__init__.py +0 -0
  59. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/extraction/__init__.py +0 -0
  60. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/extraction/cart/__init__.py +0 -0
  61. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/extraction/cart/test_cart.py +0 -0
  62. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/extraction/cart/test_simplified_cart.py +0 -0
  63. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/extraction/hypercubic/__init__.py +0 -0
  64. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/extraction/hypercubic/gridex/__init__.py +0 -0
  65. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/extraction/hypercubic/gridex/test_gridex.py +0 -0
  66. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/extraction/hypercubic/iter/__init__.py +0 -0
  67. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/extraction/hypercubic/iter/test_iter.py +0 -0
  68. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/extraction/hypercubic/test_hypercube.py +0 -0
  69. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/extraction/real/__init__.py +0 -0
  70. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/extraction/real/test_real.py +0 -0
  71. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/extraction/real/test_rule.py +0 -0
  72. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/extraction/trepan/__init__.py +0 -0
  73. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/extraction/trepan/test_node.py +0 -0
  74. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/extraction/trepan/test_split.py +0 -0
  75. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/extraction/trepan/test_trepan.py +0 -0
  76. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/utils/__init__.py +0 -0
  77. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/utils/test_prune.py +0 -0
  78. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/utils/test_simplify.py +0 -0
  79. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/psyke/utils/test_simplify_formatter.py +0 -0
  80. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/resources/__init__.py +0 -0
  81. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/resources/datasets/__init__.py +0 -0
  82. {psyke-0.10.1.dev11 → psyke-0.10.4}/test/resources/predictors/__init__.py +0 -0
  83. {psyke-0.10.1.dev11 → psyke-0.10.4}/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.1.dev11
3
+ Version: 0.10.4
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
psyke-0.10.4/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.10.4
@@ -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)
@@ -32,14 +32,15 @@ class GIn:
32
32
  self.toolbox = None
33
33
  self.stats = None
34
34
  self.hof = None
35
+ self.best = None
35
36
 
36
- self.setup(warm)
37
+ self.__setup(warm)
37
38
 
38
- def region(self, X, cuts):
39
- 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')
40
41
  for cut, f in zip(cuts, self.features)]
41
42
 
42
- regions = np.zeros(len(X), dtype=int)
43
+ regions = np.zeros(len(x), dtype=int)
43
44
  multiplier = 1
44
45
  for idx, n in zip(reversed(indices), reversed([len(cut) + 1 for cut in cuts])):
45
46
  regions += idx * multiplier
@@ -47,7 +48,7 @@ class GIn:
47
48
 
48
49
  return regions
49
50
 
50
- def __output_estimation(self, mask, to_pred):
51
+ def _output_estimation(self, mask, to_pred):
51
52
  if self.output == Target.REGRESSION:
52
53
  return LinearRegression().fit(self.poly.fit_transform(self.X)[mask], self.y[mask]).predict(
53
54
  self.poly.fit_transform(to_pred))
@@ -55,9 +56,9 @@ class GIn:
55
56
  return np.mean(self.y[mask])
56
57
  if self.output == Target.CLASSIFICATION:
57
58
  return mode(self.y[mask])
58
- raise TypeError('Supported outputs are Target.{REGRESSION, CONSTANT, CLASSIFICATION}')
59
+ raise ValueError('Supported outputs are Target.{REGRESSION, CONSTANT, CLASSIFICATION}')
59
60
 
60
- def __score(self, true, pred):
61
+ def _score(self, true, pred):
61
62
  if self.metric == 'R2':
62
63
  return r2_score(true, pred)
63
64
  if self.metric == 'MAE':
@@ -68,18 +69,23 @@ class GIn:
68
69
  return f1_score(true, pred, average='weighted')
69
70
  if self.metric == 'ACC':
70
71
  return accuracy_score(true, pred)
71
- raise NameError('Supported metrics are R2, MAE, MSE, F1, ACC')
72
+ raise ValueError('Supported metrics are R2, MAE, MSE, F1, ACC')
72
73
 
73
- def evaluate(self, individual):
74
- to_pred, true = self.valid or (self.X, self.y)
74
+ def predict(self, to_pred):
75
+ return self.__predict(to_pred=to_pred)[0]
76
+
77
+ def _get_cuts(self, individual):
75
78
  boundaries = np.cumsum([0] + list(self.slices))
76
- 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)
77
83
 
78
- regions = self.region(to_pred, cuts)
79
- regionsT = self.region(self.X, cuts)
84
+ regions = self._region(to_pred, cuts)
85
+ regionsT = self._region(self.X, cuts)
80
86
 
81
- y_pred = np.empty(len(to_pred), dtype=f'U{self.y.str.len().max()}') if self.output == Target.CLASSIFICATION \
82
- else np.zeros_like(self.y)
87
+ pred = np.empty(len(to_pred), dtype=f'U{self.y.str.len().max()}') if self.output == Target.CLASSIFICATION \
88
+ else np.zeros(len(to_pred))
83
89
  valid_regions = 0
84
90
 
85
91
  for r in range(np.prod([s + 1 for s in self.slices])):
@@ -87,17 +93,20 @@ class GIn:
87
93
  maskT = regionsT == r
88
94
  if min(mask.sum(), maskT.sum()) < 3:
89
95
  if self.output != Target.CLASSIFICATION:
90
- y_pred[mask] = np.mean(self.y)
96
+ pred[mask] = np.mean(self.y)
91
97
  continue
92
- y_pred[mask] = self.__output_estimation(maskT, to_pred[mask])
98
+ pred[mask] = self._output_estimation(maskT, to_pred[mask])
93
99
  valid_regions += 1
94
100
 
101
+ return pred, valid_regions
102
+
103
+ def _evaluate(self, individual=None):
104
+ y_pred, valid_regions = self.__predict(individual or self.best, self.X if self.valid is None else self.valid[0])
95
105
  if valid_regions < self.min_rules:
96
106
  return -9999,
107
+ return self._score(self.y if self.valid is None else self.valid[1], y_pred),
97
108
 
98
- return self.__score(true, y_pred),
99
-
100
- def setup(self, warm=False):
109
+ def __setup(self, warm=False):
101
110
  if not warm:
102
111
  creator.create("FitnessMax", base.Fitness, weights=(1.0,))
103
112
  creator.create("Individual", list, fitness=creator.FitnessMax)
@@ -116,7 +125,7 @@ class GIn:
116
125
  self.toolbox.register("mutate", tools.mutGaussian, indpb=self.indpb, mu=0,
117
126
  sigma=sum([[sig] * s for sig, s in zip(self.sigmas, self.slices)], []))
118
127
  self.toolbox.register("select", tools.selTournament, tournsize=self.tournsize)
119
- self.toolbox.register("evaluate", self.evaluate)
128
+ self.toolbox.register("evaluate", self._evaluate)
120
129
 
121
130
  self.stats = tools.Statistics(lambda ind: ind.fitness.values[0])
122
131
  self.stats.register("avg", np.mean)
@@ -131,5 +140,5 @@ class GIn:
131
140
  pop = self.toolbox.population(n=n_pop)
132
141
  result, log = algorithms.eaSimple(pop, self.toolbox, cxpb=cxpb, mutpb=mutpb, ngen=n_gen,
133
142
  stats=self.stats, halloffame=self.hof, verbose=False)
134
- best = tools.selBest(pop, 1)[0]
135
- return best, self.evaluate(best)[0], result, log
143
+ self.best = tools.selBest(pop, 1)[0]
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.1.dev11
3
+ Version: 0.10.4
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.1.dev11
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes