rulelearn-ripper-interactive 0.2.3__py3-none-any.whl

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.
Files changed (73) hide show
  1. rulelearn_ri/__init__.py +6 -0
  2. rulelearn_ri/algorithms/__init__.py +0 -0
  3. rulelearn_ri/algorithms/r2n/__init__.py +0 -0
  4. rulelearn_ri/algorithms/r2n/base.py +28 -0
  5. rulelearn_ri/algorithms/r2n/functions.py +25 -0
  6. rulelearn_ri/algorithms/r2n/mask.py +58 -0
  7. rulelearn_ri/algorithms/r2n/preprocessing_layers.py +192 -0
  8. rulelearn_ri/algorithms/r2n/r2n_algo.py +287 -0
  9. rulelearn_ri/algorithms/r2n/simple_rulenet.py +75 -0
  10. rulelearn_ri/algorithms/r2n/training.py +34 -0
  11. rulelearn_ri/algorithms/r2n/utilities.py +117 -0
  12. rulelearn_ri/algorithms/rbm/__init__.py +0 -0
  13. rulelearn_ri/algorithms/rbm/boolean_rule_cg.py +65 -0
  14. rulelearn_ri/algorithms/rbm/rbm/BRCG.py +69 -0
  15. rulelearn_ri/algorithms/rbm/rbm/GLRM.py +98 -0
  16. rulelearn_ri/algorithms/rbm/rbm/__init__.py +6 -0
  17. rulelearn_ri/algorithms/rbm/rbm/beam_search.py +302 -0
  18. rulelearn_ri/algorithms/rbm/rbm/boolean_rule_cg.py +245 -0
  19. rulelearn_ri/algorithms/rbm/rbm/features.py +544 -0
  20. rulelearn_ri/algorithms/rbm/rbm/linear_regression.py +393 -0
  21. rulelearn_ri/algorithms/rbm/rbm/logistic_regression.py +447 -0
  22. rulelearn_ri/algorithms/rbm/utils.py +13 -0
  23. rulelearn_ri/algorithms/ripper/__init__.py +10 -0
  24. rulelearn_ri/algorithms/ripper/base.py +81 -0
  25. rulelearn_ri/algorithms/ripper/binding.py +541 -0
  26. rulelearn_ri/algorithms/ripper/mdl.py +97 -0
  27. rulelearn_ri/algorithms/ripper/pruning.py +212 -0
  28. rulelearn_ri/algorithms/ripper/ripper.py +600 -0
  29. rulelearn_ri/algorithms/ripper/ripper_ruleset_generator.py +26 -0
  30. rulelearn_ri/algorithms/ripper/single_rule.py +425 -0
  31. rulelearn_ri/dise.py +64 -0
  32. rulelearn_ri/trxf/__init__.py +0 -0
  33. rulelearn_ri/trxf/classifier/__init__.py +0 -0
  34. rulelearn_ri/trxf/classifier/ruleset_classifier.py +153 -0
  35. rulelearn_ri/trxf/core/__init__.py +5 -0
  36. rulelearn_ri/trxf/core/boolean_evaluator.py +15 -0
  37. rulelearn_ri/trxf/core/conjunction.py +50 -0
  38. rulelearn_ri/trxf/core/dnf_ruleset.py +64 -0
  39. rulelearn_ri/trxf/core/feature.py +155 -0
  40. rulelearn_ri/trxf/core/predicate.py +98 -0
  41. rulelearn_ri/trxf/core/ruleset_generator.py +25 -0
  42. rulelearn_ri/trxf/core/utils.py +40 -0
  43. rulelearn_ri/trxf/metrics.py +98 -0
  44. rulelearn_ri/trxf/pmml_export/__init__.py +4 -0
  45. rulelearn_ri/trxf/pmml_export/__version__.py +1 -0
  46. rulelearn_ri/trxf/pmml_export/models/__init__.py +24 -0
  47. rulelearn_ri/trxf/pmml_export/models/attribute.py +24 -0
  48. rulelearn_ri/trxf/pmml_export/models/characteristics.py +20 -0
  49. rulelearn_ri/trxf/pmml_export/models/data_dictionary.py +53 -0
  50. rulelearn_ri/trxf/pmml_export/models/mining_schema.py +25 -0
  51. rulelearn_ri/trxf/pmml_export/models/pmml_ruleset_model.py +16 -0
  52. rulelearn_ri/trxf/pmml_export/models/predicate.py +42 -0
  53. rulelearn_ri/trxf/pmml_export/models/rule.py +26 -0
  54. rulelearn_ri/trxf/pmml_export/models/ruleset.py +28 -0
  55. rulelearn_ri/trxf/pmml_export/models/ruleset_model.py +16 -0
  56. rulelearn_ri/trxf/pmml_export/models/scorecard.py +35 -0
  57. rulelearn_ri/trxf/pmml_export/pmml_exporter.py +18 -0
  58. rulelearn_ri/trxf/pmml_export/reader/__init__.py +2 -0
  59. rulelearn_ri/trxf/pmml_export/reader/abstract_reader.py +16 -0
  60. rulelearn_ri/trxf/pmml_export/reader/trxf_reader.py +113 -0
  61. rulelearn_ri/trxf/pmml_export/serializer/__init__.py +2 -0
  62. rulelearn_ri/trxf/pmml_export/serializer/abstract_serializer.py +11 -0
  63. rulelearn_ri/trxf/pmml_export/serializer/nyoka_serializer.py +162 -0
  64. rulelearn_ri/trxf/scorecard/__init__.py +3 -0
  65. rulelearn_ri/trxf/scorecard/bins.py +253 -0
  66. rulelearn_ri/trxf/scorecard/partition.py +71 -0
  67. rulelearn_ri/trxf/scorecard/scorecard.py +78 -0
  68. rulelearn_ripper_interactive-0.2.3.dist-info/METADATA +164 -0
  69. rulelearn_ripper_interactive-0.2.3.dist-info/RECORD +73 -0
  70. rulelearn_ripper_interactive-0.2.3.dist-info/WHEEL +5 -0
  71. rulelearn_ripper_interactive-0.2.3.dist-info/licenses/LICENSE +201 -0
  72. rulelearn_ripper_interactive-0.2.3.dist-info/licenses/NOTICE +11 -0
  73. rulelearn_ripper_interactive-0.2.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,541 @@
1
+ import numpy as np
2
+ import numba as nb
3
+
4
+
5
+ LE = 0
6
+ GE = 1
7
+ EQ = 2
8
+
9
+
10
+ # # jitclass is not optimized for interpreter yet
11
+ # @nb.jitclass(
12
+ # [
13
+ # ('name', nb.int64),
14
+ # ('op', nb.uint8),
15
+ # ('num_val', nb.double),
16
+ # ('nom_val', nb.int64)
17
+ # ]
18
+ # )
19
+ class Literal(object):
20
+ """
21
+ A literal is an atomic formula (atom). In rule induction, the negation of an atom needs
22
+ to be explicitly added. For example, ‘credit score >= 200’ and ‘credit score < 200’ (to solve
23
+ some issues related to float number, the complement of >= is sometimes written as <=) need to
24
+ be added at the same time
25
+
26
+ name : int64_t
27
+ Feature name for literal (encoded)
28
+ op : uint8_t
29
+ Operator for literal (encoded)
30
+ num_val : double
31
+ Numerical feature value for literal (encoded)
32
+ nom_val : int64_t
33
+ Nominal feature value for literal
34
+ """
35
+
36
+ def __init__(
37
+ self,
38
+ name,
39
+ op,
40
+ num_val,
41
+ nom_val
42
+ ):
43
+ self.name = name
44
+ self.op = op
45
+ self.num_val = num_val
46
+ self.nom_val = nom_val
47
+
48
+ def __repr__(self):
49
+ return '_'.join([
50
+ str(self.name),
51
+ str(self.op),
52
+ str(self.num_val),
53
+ str(self.nom_val)])
54
+
55
+ def __str__(self):
56
+ return self.__repr__()
57
+
58
+
59
+ def _filter_contradicted_instances(pos, neg):
60
+ """
61
+ Delete common instances in pos and neg
62
+
63
+ Parameters
64
+ ----------
65
+ pos: const double[::1, :]
66
+ neg: const double[::1, :]
67
+
68
+ Returns
69
+ -------
70
+ const double[::1, :]
71
+ New neg
72
+ """
73
+ feature_shape = np.shape(neg)[1]
74
+ pos_set = set(map(tuple, pos))
75
+ neg_set = set(map(tuple, neg))
76
+ filtered_neg_set = neg_set.difference(pos_set)
77
+ return neg if len(filtered_neg_set) == len(neg_set) else np.array(list(map(list, filtered_neg_set))).reshape(-1, feature_shape)
78
+
79
+
80
+ @nb.njit(
81
+ 'double(int64, int64, int64, int64)',
82
+ nogil=True,
83
+ cache=True,
84
+ error_model='numpy'
85
+ )
86
+ def _gain(
87
+ p0,
88
+ p1,
89
+ n0,
90
+ n1
91
+ ):
92
+ """
93
+ Calculation of p-foil gain for IREP*
94
+
95
+ Parameters
96
+ ----------
97
+ p0 : int64
98
+ Total positive instances
99
+ p1 : int64
100
+ Positive instances in the next iteration
101
+ n0 : int64
102
+ Total negative instances
103
+ n1 : int64
104
+ Negative instances in the next iteration
105
+
106
+ Returns
107
+ -------
108
+ double
109
+ The p-foil gian
110
+ """
111
+ if p1 == 0:
112
+ return 0
113
+ else:
114
+ return p1 * (np.log2(p1 / (p1 + float(n1))) - np.log2(p0 / (p0 + float(n0))))
115
+
116
+
117
+ @nb.njit(
118
+ [
119
+ 'int64(double[::1, :], int64, uint8, double, int64)',
120
+ 'int64(double[:, ::1], int64, uint8, double, int64)'
121
+ ],
122
+ nogil=True,
123
+ cache=True,
124
+ error_model='numpy'
125
+ )
126
+ def _count_bound_literal(
127
+ data,
128
+ name,
129
+ op,
130
+ num_val,
131
+ nom_val,
132
+ ):
133
+ """
134
+ Count the number of instances that are covered by the literal
135
+
136
+ Parameters
137
+ ----------
138
+ data : const double[::1, :]
139
+ Input instances
140
+ name : int64_t
141
+ Feature name for literal
142
+ op : uint8_t
143
+ Operator for literal
144
+ num_val : double
145
+ Numerical feature value for literal
146
+ nom_val : int64_t
147
+ Nominal feature value for literal
148
+
149
+ Returns
150
+ -------
151
+ uint64_t
152
+ The number of instances which are covered by the literal
153
+ """
154
+ result_count = 0
155
+ if op == LE:
156
+ for i in range(len(data)):
157
+ result_count += data[i, name] <= num_val
158
+ elif op == GE:
159
+ for i in range(len(data)):
160
+ result_count += data[i, name] >= num_val
161
+ elif op == EQ:
162
+ for i in range(len(data)):
163
+ result_count += int(data[i, name]) == nom_val
164
+ else:
165
+ raise RuntimeError('Unknown operator')
166
+ return result_count
167
+
168
+
169
+ @nb.njit(
170
+ [
171
+ 'int64(double[::1, :], double[::1, :], int64[::1], uint8[::1], double[::1], int64[::1])',
172
+ 'int64(double[::1, :], double[:, ::1], int64[::1], uint8[::1], double[::1], int64[::1])',
173
+ 'int64(double[:, ::1], double[::1, :], int64[::1], uint8[::1], double[::1], int64[::1])',
174
+ 'int64(double[:, ::1], double[:, ::1], int64[::1], uint8[::1], double[::1], int64[::1])',
175
+ ],
176
+ nogil=True,
177
+ parallel=True,
178
+ error_model='numpy'
179
+ )
180
+ def _find_best_literal(
181
+ pos,
182
+ neg,
183
+ name_vec,
184
+ op_vec,
185
+ num_val_vec,
186
+ nom_val_vec
187
+ ):
188
+ """
189
+ Find the best literal for OpenMP based IREP*
190
+
191
+ Parameters
192
+ ----------
193
+ pos : const double[::1, :]
194
+ Positive instances
195
+ neg : const double[::1, :]
196
+ Negative instances
197
+ name_vec : const int64_t[::1]
198
+ Feature names for literals
199
+ op_vec : const uint8_t[::1]
200
+ Operators for literals
201
+ num_val_vec : const double[::1]
202
+ Numerical feature values for literals
203
+ nom_val_vec : const int64_t[::1]
204
+ Nominal feature values for literals
205
+
206
+ Returns
207
+ -------
208
+ uint64_t
209
+ The index of the best literal
210
+ """
211
+ p = len(pos)
212
+ n = len(neg)
213
+ gain_list = np.empty(len(name_vec), dtype=np.float64)
214
+
215
+ for i in nb.prange(len(name_vec)):
216
+
217
+ name = name_vec[i]
218
+ op = op_vec[i]
219
+ num_val = num_val_vec[i]
220
+ nom_val = nom_val_vec[i]
221
+
222
+ gain_list[i] = _gain(
223
+ p,
224
+ _count_bound_literal(pos, name, op, num_val, nom_val),
225
+ n,
226
+ _count_bound_literal(neg, name, op, num_val, nom_val)
227
+ )
228
+
229
+ return np.argmax(gain_list)
230
+
231
+
232
+ @nb.njit(
233
+ [
234
+ 'boolean[::1](double[::1, :], int64, uint8, double, int64)',
235
+ 'boolean[::1](double[:, ::1], int64, uint8, double, int64)',
236
+ ],
237
+ nogil=True,
238
+ cache=True,
239
+ error_model='numpy'
240
+ )
241
+ def bind_literal_index(
242
+ data,
243
+ name,
244
+ op,
245
+ num_val,
246
+ nom_val,
247
+ ):
248
+ """
249
+ Find instances that are covered by the literal
250
+
251
+ Parameters
252
+ ----------
253
+ data : const double[::1, :]
254
+ Input instances
255
+ name : int64_t
256
+ Feature name for literal
257
+ op : uint8_t
258
+ Operator for literal
259
+ num_val : double
260
+ Numerical feature value for literal
261
+ nom_val : int64_t
262
+ Nominal feature value for literal
263
+
264
+ Returns
265
+ -------
266
+ uint64_t
267
+ Instances which are covered by the literal
268
+ """
269
+ result = np.empty(len(data), dtype=np.bool_)
270
+ if op == LE:
271
+ for i in range(len(data)):
272
+ result[i] = data[i, name] <= num_val
273
+ elif op == GE:
274
+ for i in range(len(data)):
275
+ result[i] = data[i, name] >= num_val
276
+ elif op == EQ:
277
+ for i in range(len(data)):
278
+ result[i] = int(data[i, name]) == nom_val
279
+ else:
280
+ raise RuntimeError('Unknown operator')
281
+ return result
282
+
283
+
284
+ @nb.njit(
285
+ [
286
+ 'double[:,::1](double[::1, :], int64, uint8, double, int64)',
287
+ 'double[:,::1](double[:, ::1], int64, uint8, double, int64)'
288
+ ],
289
+ nogil=True,
290
+ cache=True,
291
+ error_model='numpy'
292
+ )
293
+ def _bind_literal(
294
+ data,
295
+ name,
296
+ op,
297
+ num_val,
298
+ nom_val,
299
+ ):
300
+ """
301
+ Find instances that are covered by the literal
302
+
303
+ Parameters
304
+ ----------
305
+ data : const double[::1, :]
306
+ Input instances
307
+ name : int64_t
308
+ Feature name for literal
309
+ op : uint8_t
310
+ Operator for literal
311
+ num_val : double
312
+ Numerical feature value for literal
313
+ nom_val : int64_t
314
+ Nominal feature value for literal
315
+
316
+ Returns
317
+ -------
318
+ ndarray
319
+ Instances that are covered by the literal
320
+ """
321
+ return data[bind_literal_index(data, name, op, num_val, nom_val)]
322
+
323
+
324
+ def _bind_rule_index(
325
+ data,
326
+ rule
327
+ ):
328
+ """
329
+ Find instances that are covered by the rule
330
+
331
+ Parameters
332
+ ----------
333
+ data : const double[::1, :]
334
+ Input instances
335
+ rule : list
336
+ Input rule
337
+
338
+ Returns
339
+ -------
340
+ ndarray
341
+ Boolean index array for instances that are covered by the rule
342
+ """
343
+ index = np.full(len(data), True)
344
+ for literal in rule:
345
+ index = index & bind_literal_index(data, literal.name, literal.op, literal.num_val, literal.nom_val)
346
+ return index
347
+
348
+
349
+ def __unbound_rule_index(
350
+ data,
351
+ rule,
352
+ ):
353
+ """
354
+ Find instances that are not covered by the rule
355
+
356
+ Parameters
357
+ ----------
358
+ data : const double[::1, :]
359
+ Input instances
360
+ rule : list
361
+ Input rule
362
+
363
+ Returns
364
+ -------
365
+ ndarray
366
+ Boolean index array for instances that are not covered by the rule
367
+ """
368
+ return ~_bind_rule_index(data, rule)
369
+
370
+
371
+ def unbound_rule_list_index(
372
+ data,
373
+ rules
374
+ ):
375
+ """
376
+ Find instances that are not covered by the rule list
377
+
378
+ Parameters
379
+ ----------
380
+ data : const double[::1, :]
381
+ Input instances
382
+ rules : list
383
+ Input rule list
384
+
385
+ Returns
386
+ -------
387
+ ndarray
388
+ Boolean index array for instances that are not covered by the rule list
389
+ """
390
+ index = np.full(len(data), True)
391
+ for rule in rules:
392
+ index = index & __unbound_rule_index(data, rule)
393
+ return index
394
+
395
+
396
+ def _bind_rule(
397
+ data,
398
+ rule
399
+ ):
400
+ """
401
+ Find instances that are covered by the rule
402
+
403
+ Parameters
404
+ ----------
405
+ data : const double[::1, :]
406
+ Input instances
407
+ rule : list
408
+ Input rule
409
+
410
+ Returns
411
+ -------
412
+ ndarray
413
+ Instances that are covered by the rule
414
+ """
415
+ return data[_bind_rule_index(data, rule)]
416
+
417
+
418
+ def _unbound(
419
+ data,
420
+ rule
421
+ ):
422
+ """
423
+ Find instances that are not covered by the rule
424
+
425
+ Parameters
426
+ ----------
427
+ data : const double[::1, :]
428
+ Input instances
429
+ rule : list
430
+ Input rule
431
+
432
+ Returns
433
+ -------
434
+ ndarray
435
+ Instances that are not covered by the rule
436
+ """
437
+ return data[__unbound_rule_index(data, rule)]
438
+
439
+
440
+ def _unbound_rule_list(
441
+ data,
442
+ rules
443
+ ):
444
+ """
445
+ Find instances that are not covered by the rule list
446
+
447
+ Parameters
448
+ ----------
449
+ data : const double[::1, :]
450
+ Input instances
451
+ rules : list
452
+ Input rule list
453
+
454
+ Returns
455
+ -------
456
+ ndarray
457
+ Instances that are not covered by the rule list
458
+ """
459
+ return data[unbound_rule_list_index(data, rules)]
460
+
461
+
462
+ def _rule_predict(
463
+ data,
464
+ rule
465
+ ):
466
+ """
467
+ Make a decision using input data and rule
468
+
469
+ Parameters
470
+ ----------
471
+ data : const double[::1, :]
472
+ Input instances
473
+ rule : list
474
+ Input rule
475
+
476
+ Returns
477
+ -------
478
+ ndarray
479
+ Predictions
480
+ """
481
+ if len(rule) == 0:
482
+ return np.full(len(data), False)
483
+ else:
484
+ return _bind_rule_index(data, rule)
485
+
486
+
487
+ def _rule_list_predict(
488
+ data,
489
+ rules
490
+ ):
491
+ """
492
+ Make a decision based on input data and rule list
493
+
494
+ Parameters
495
+ ----------
496
+ data : const double[::1, :]
497
+ Input instances
498
+ rules : list
499
+ Input rule list
500
+
501
+ Returns
502
+ -------
503
+ ndarray
504
+ Predictions
505
+ """
506
+ if len(rules) == 0:
507
+ return np.full(len(data), False)
508
+ else:
509
+ return ~unbound_rule_list_index(data, rules)
510
+
511
+
512
+ def append_literal(
513
+ rule,
514
+ literal
515
+ ):
516
+ """
517
+ Append a literal to a rule. It will delete unnecessary literals in that rule after append
518
+
519
+ Parameters
520
+ ----------
521
+ rule : list
522
+ Target rule
523
+ literal : Literal
524
+ New literal
525
+ """
526
+ # nominal variable will not be added twice
527
+ if literal.op != EQ:
528
+ # start from the last condition
529
+ for i in range(len(rule) - 1, -1, -1):
530
+ # delete redundant conditions
531
+ if rule[i].name == literal.name:
532
+ if rule[i].op == literal.op:
533
+ if literal.op == LE:
534
+ if literal.num_val < rule[i].num_val:
535
+ del rule[i]
536
+ else:
537
+ if literal.num_val > rule[i].num_val:
538
+ del rule[i]
539
+ # add condition to the rule
540
+ rule.append(literal)
541
+
@@ -0,0 +1,97 @@
1
+ import numba as nb
2
+ import numpy as np
3
+
4
+ from rulelearn_ri.algorithms.ripper.binding import _rule_list_predict
5
+
6
+
7
+ @nb.njit(
8
+ 'double(int64, int64)',
9
+ nogil=True,
10
+ cache=True,
11
+ error_model='numpy'
12
+ )
13
+ def __theorem_length(
14
+ k,
15
+ n
16
+ ):
17
+ """
18
+ Calculate the MDL for a rule
19
+
20
+ Parameters
21
+ ----------
22
+ k: uint64_t
23
+ Literal count for theorem
24
+ n : uint64_t
25
+ Total literal count
26
+
27
+ Returns
28
+ -------
29
+ double
30
+ The MDL for a rule
31
+ """
32
+ if k == 0:
33
+ return 0.0
34
+ p = k / float(n)
35
+ return np.log2(k) + k * np.log2(1 / p) + (n - k) * np.log2(1 / (1 - p))
36
+
37
+
38
+ @nb.njit(
39
+ 'double(int64, int64)',
40
+ nogil=True,
41
+ cache=True,
42
+ error_model='numpy'
43
+ )
44
+ def __msg_length_uniform(
45
+ e,
46
+ d
47
+ ):
48
+ """
49
+ Calculate the MDL a data set
50
+
51
+ Parameters
52
+ ----------
53
+ e: uint64_t
54
+ Error count
55
+ d : uint64_t
56
+ Total number of instances
57
+
58
+ Returns
59
+ -------
60
+ double
61
+ The MDL for data set
62
+ """
63
+ if e == 0 or e == d:
64
+ return np.log2(d + 1)
65
+ return np.log2(d + 1) + e * (-np.log2(e / float(d))) + (d - e) * (-np.log2(1 - (e / float(d))))
66
+
67
+
68
+ def _mdl(
69
+ pos,
70
+ neg,
71
+ rule_list,
72
+ n
73
+ ):
74
+ """
75
+ Calculate the MDL for a rule list and the training data from which the rule list is learned
76
+
77
+ Parameters
78
+ ----------
79
+ pos : const double[::1, :]
80
+ Positive instances of training data
81
+ neg : const double[::1, :]
82
+ Negative instances of training data
83
+ rule_list : list
84
+ Learned rule list
85
+ n : uint64_t
86
+ Total literal count
87
+
88
+ Returns
89
+ -------
90
+ double
91
+ The MDL for the rule list and the training data from which the rule list is learned
92
+ """
93
+ e = np.count_nonzero(_rule_list_predict(neg, rule_list)) + \
94
+ len(pos) - np.count_nonzero(_rule_list_predict(pos, rule_list))
95
+
96
+ return 0.5 * np.sum([__theorem_length(len(rule), n) for rule in rule_list]) + \
97
+ __msg_length_uniform(e, len(pos) + len(neg))