oikan 0.0.3.6__py3-none-any.whl → 0.0.3.8__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.
- oikan/model.py +81 -30
- {oikan-0.0.3.6.dist-info → oikan-0.0.3.8.dist-info}/METADATA +1 -1
- oikan-0.0.3.8.dist-info/RECORD +10 -0
- oikan-0.0.3.6.dist-info/RECORD +0 -10
- {oikan-0.0.3.6.dist-info → oikan-0.0.3.8.dist-info}/WHEEL +0 -0
- {oikan-0.0.3.6.dist-info → oikan-0.0.3.8.dist-info}/licenses/LICENSE +0 -0
- {oikan-0.0.3.6.dist-info → oikan-0.0.3.8.dist-info}/top_level.txt +0 -0
oikan/model.py
CHANGED
@@ -12,6 +12,7 @@ from sklearn.model_selection import train_test_split
|
|
12
12
|
from sklearn.metrics import r2_score, accuracy_score
|
13
13
|
from .exceptions import *
|
14
14
|
import sys
|
15
|
+
from tqdm import tqdm
|
15
16
|
|
16
17
|
class OIKAN(ABC):
|
17
18
|
"""
|
@@ -319,11 +320,15 @@ class OIKAN(ABC):
|
|
319
320
|
|
320
321
|
def _generate_augmented_data(self, X):
|
321
322
|
"""Generates augmented data by adding Gaussian noise."""
|
323
|
+
if self.augmentation_factor == 1:
|
324
|
+
return np.array([]).reshape(0, X.shape[1])
|
325
|
+
|
322
326
|
X_aug = []
|
323
|
-
for _ in range(self.augmentation_factor):
|
327
|
+
for _ in range(self.augmentation_factor - 1):
|
324
328
|
noise = np.random.normal(0, self.sigma, X.shape)
|
325
329
|
X_perturbed = X + noise
|
326
330
|
X_aug.append(X_perturbed)
|
331
|
+
|
327
332
|
return np.vstack(X_aug)
|
328
333
|
|
329
334
|
def _perform_symbolic_regression(self, X, y):
|
@@ -349,14 +354,23 @@ class OIKAN(ABC):
|
|
349
354
|
if np.any(np.isinf(X)) or np.any(np.isinf(y)):
|
350
355
|
raise NumericalInstabilityError("Input data contains infinite values")
|
351
356
|
|
352
|
-
|
357
|
+
if self.verbose:
|
358
|
+
print("\nStage 1: Coarse Model Fitting")
|
359
|
+
|
353
360
|
coarse_degree = 2 # Fixed low degree for coarse model
|
354
361
|
poly_coarse = PolynomialFeatures(degree=coarse_degree, include_bias=True)
|
362
|
+
|
363
|
+
if self.verbose:
|
364
|
+
print("Generating polynomial features...")
|
355
365
|
X_poly_coarse = poly_coarse.fit_transform(X)
|
366
|
+
|
367
|
+
if self.verbose:
|
368
|
+
print("Fitting coarse elastic net model...")
|
356
369
|
model_coarse = ElasticNet(alpha=self.alpha, fit_intercept=False)
|
357
370
|
model_coarse.fit(X_poly_coarse, y)
|
358
371
|
|
359
|
-
|
372
|
+
if self.verbose:
|
373
|
+
print("Computing feature importances...")
|
360
374
|
basis_functions_coarse = poly_coarse.get_feature_names_out()
|
361
375
|
if len(y.shape) == 1 or y.shape[1] == 1:
|
362
376
|
coef_coarse = model_coarse.coef_.flatten()
|
@@ -364,7 +378,7 @@ class OIKAN(ABC):
|
|
364
378
|
coef_coarse = np.sum(np.abs(model_coarse.coef_), axis=0)
|
365
379
|
|
366
380
|
importances = np.zeros(X.shape[1])
|
367
|
-
for i, func in enumerate(basis_functions_coarse):
|
381
|
+
for i, func in enumerate(tqdm(basis_functions_coarse, disable=not self.verbose, desc="Analyzing features")):
|
368
382
|
features_involved = get_features_involved(func)
|
369
383
|
for idx in features_involved:
|
370
384
|
importances[idx] += np.abs(coef_coarse[i])
|
@@ -375,11 +389,13 @@ class OIKAN(ABC):
|
|
375
389
|
# Select top K features
|
376
390
|
top_k_indices = np.argsort(importances)[::-1][:self.top_k]
|
377
391
|
|
378
|
-
|
379
|
-
|
392
|
+
if self.verbose:
|
393
|
+
print(f"\nStage 2: Refined Model with top {self.top_k} features")
|
394
|
+
print("Generating additional non-linear features...")
|
395
|
+
|
380
396
|
additional_features = []
|
381
397
|
additional_names = []
|
382
|
-
for i in top_k_indices:
|
398
|
+
for i in tqdm(top_k_indices, disable=not self.verbose, desc="Generating features"):
|
383
399
|
# Higher-degree polynomial
|
384
400
|
additional_features.append(X[:, i]**3)
|
385
401
|
additional_names.append(f'x{i}^3')
|
@@ -391,15 +407,18 @@ class OIKAN(ABC):
|
|
391
407
|
additional_features.append(np.sin(X[:, i]))
|
392
408
|
additional_names.append(f'sin_x{i}')
|
393
409
|
|
394
|
-
|
410
|
+
if self.verbose:
|
411
|
+
print("Combining features and fitting final model...")
|
395
412
|
X_additional = np.column_stack(additional_features)
|
396
413
|
X_refined = np.hstack([X_poly_coarse, X_additional])
|
397
414
|
basis_functions_refined = list(basis_functions_coarse) + additional_names
|
398
415
|
|
399
|
-
# Fit refined model
|
400
416
|
model_refined = ElasticNet(alpha=self.alpha, fit_intercept=False)
|
401
417
|
model_refined.fit(X_refined, y)
|
402
418
|
|
419
|
+
if self.verbose:
|
420
|
+
print("Building final symbolic model...")
|
421
|
+
|
403
422
|
# Store symbolic model
|
404
423
|
if len(y.shape) == 1 or y.shape[1] == 1:
|
405
424
|
# Regression
|
@@ -414,7 +433,7 @@ class OIKAN(ABC):
|
|
414
433
|
# Classification
|
415
434
|
coefficients_list = []
|
416
435
|
selected_indices = set()
|
417
|
-
for c in range(y.shape[1]):
|
436
|
+
for c in tqdm(range(y.shape[1]), disable=not self.verbose, desc="Processing classes"):
|
418
437
|
coef = model_refined.coef_[c]
|
419
438
|
indices = np.where(np.abs(coef) > 1e-6)[0]
|
420
439
|
selected_indices.update(indices)
|
@@ -445,16 +464,32 @@ class OIKANRegressor(OIKAN):
|
|
445
464
|
"""
|
446
465
|
X = np.asarray(X)
|
447
466
|
y = np.asarray(y).reshape(-1, 1)
|
448
|
-
|
449
|
-
if self.
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
467
|
+
|
468
|
+
if self.augmentation_factor > 1:
|
469
|
+
self._train_neural_net(X, y, output_size=1, loss_fn=nn.MSELoss())
|
470
|
+
|
471
|
+
if self.verbose:
|
472
|
+
print(f"Original data: features shape: {X.shape} | target shape: {y.shape} | size: {X.nbytes / (1024 * 1024):.2f} MB")
|
473
|
+
|
474
|
+
X_aug = self._generate_augmented_data(X)
|
475
|
+
|
476
|
+
self.neural_net.eval()
|
477
|
+
with torch.no_grad():
|
478
|
+
y_aug = self.neural_net(torch.tensor(X_aug, dtype=torch.float32)).detach().numpy()
|
479
|
+
|
480
|
+
if self.verbose:
|
481
|
+
print(f"Augmented data: features shape: {X_aug.shape} | target shape: {y_aug.shape} | size: {X_aug.nbytes / (1024 * 1024):.2f} MB")
|
482
|
+
|
483
|
+
X_combined = np.vstack([X, X_aug])
|
484
|
+
y_combined = np.vstack([y, y_aug])
|
485
|
+
else:
|
486
|
+
if self.verbose:
|
487
|
+
print("Skipping neural network training (augmentation_factor=1)")
|
488
|
+
print(f"Data: features shape: {X.shape} | target shape: {y.shape} | size: {X.nbytes / (1024 * 1024):.2f} MB")
|
489
|
+
X_combined = X
|
490
|
+
y_combined = y
|
491
|
+
|
492
|
+
self._perform_symbolic_regression(X_combined, y_combined)
|
458
493
|
if self.verbose:
|
459
494
|
print("OIKANRegressor model training completed successfully!")
|
460
495
|
|
@@ -499,16 +534,32 @@ class OIKANClassifier(OIKAN):
|
|
499
534
|
self.classes_ = le.classes_
|
500
535
|
n_classes = len(self.classes_)
|
501
536
|
y_onehot = nn.functional.one_hot(torch.tensor(y_encoded), num_classes=n_classes).float()
|
502
|
-
|
503
|
-
if self.
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
537
|
+
|
538
|
+
if self.augmentation_factor > 1:
|
539
|
+
self._train_neural_net(X, y_onehot, output_size=n_classes, loss_fn=nn.CrossEntropyLoss())
|
540
|
+
|
541
|
+
if self.verbose:
|
542
|
+
print(f"Original data: features shape: {X.shape} | target shape: {y.shape} | size: {X.nbytes / (1024 * 1024):.2f} MB")
|
543
|
+
|
544
|
+
X_aug = self._generate_augmented_data(X)
|
545
|
+
|
546
|
+
self.neural_net.eval()
|
547
|
+
with torch.no_grad():
|
548
|
+
logits_aug = self.neural_net(torch.tensor(X_aug, dtype=torch.float32)).detach().numpy()
|
549
|
+
|
550
|
+
if self.verbose:
|
551
|
+
print(f"Augmented data: features shape: {X_aug.shape} | target shape: {logits_aug.shape} | size: {X_aug.nbytes / (1024 * 1024):.2f} MB")
|
552
|
+
|
553
|
+
X_combined = np.vstack([X, X_aug])
|
554
|
+
y_combined = np.vstack([y_onehot.numpy(), logits_aug])
|
555
|
+
else:
|
556
|
+
if self.verbose:
|
557
|
+
print("Skipping neural network training (augmentation_factor=1)")
|
558
|
+
print(f"Data: features shape: {X.shape} | target shape: {y.shape} | size: {X.nbytes / (1024 * 1024):.2f} MB")
|
559
|
+
X_combined = X
|
560
|
+
y_combined = y_onehot.numpy()
|
561
|
+
|
562
|
+
self._perform_symbolic_regression(X_combined, y_combined)
|
512
563
|
if self.verbose:
|
513
564
|
print("OIKANClassifier model training completed successfully!")
|
514
565
|
|
@@ -0,0 +1,10 @@
|
|
1
|
+
oikan/__init__.py,sha256=zEzhm1GYLT4vNaIQ4CgZcNpUk3uo8SWnoaHYtHW_XSQ,628
|
2
|
+
oikan/exceptions.py,sha256=GhHWqy2Q5LVBcteTy4ngnqxr7FOoLNyD8dNt1kfRXyw,901
|
3
|
+
oikan/model.py,sha256=K-cBAUvfw3B8wxWjNSUC1CadU1iVUb8erapUpD9KzKw,25822
|
4
|
+
oikan/neural.py,sha256=PZjaffSuABuCNxu-7PinU1GR6ji0Y6xRgSQ3n5HRDxI,1572
|
5
|
+
oikan/utils.py,sha256=7UCm9obO-8Q2zhetdAkukMDOZvGSBWUL_dSF04XqM7k,8808
|
6
|
+
oikan-0.0.3.8.dist-info/licenses/LICENSE,sha256=75ASVmU-XIpN-M4LbVmJ_ibgbzbvRLVti8FhnR0BTf8,1096
|
7
|
+
oikan-0.0.3.8.dist-info/METADATA,sha256=jmDvzPj-d_JH4yAZiBf45-mjItUVRepX1Xv2cMqqAkA,12749
|
8
|
+
oikan-0.0.3.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
9
|
+
oikan-0.0.3.8.dist-info/top_level.txt,sha256=XwnwKwTJddZwIvtrUsAz-l-58BJRj6HjAGWrfYi_3QY,6
|
10
|
+
oikan-0.0.3.8.dist-info/RECORD,,
|
oikan-0.0.3.6.dist-info/RECORD
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
oikan/__init__.py,sha256=zEzhm1GYLT4vNaIQ4CgZcNpUk3uo8SWnoaHYtHW_XSQ,628
|
2
|
-
oikan/exceptions.py,sha256=GhHWqy2Q5LVBcteTy4ngnqxr7FOoLNyD8dNt1kfRXyw,901
|
3
|
-
oikan/model.py,sha256=vnn5THWhndj5-P2Vsa78CErsT24LVmjMd8CnWeW09Kg,23663
|
4
|
-
oikan/neural.py,sha256=PZjaffSuABuCNxu-7PinU1GR6ji0Y6xRgSQ3n5HRDxI,1572
|
5
|
-
oikan/utils.py,sha256=7UCm9obO-8Q2zhetdAkukMDOZvGSBWUL_dSF04XqM7k,8808
|
6
|
-
oikan-0.0.3.6.dist-info/licenses/LICENSE,sha256=75ASVmU-XIpN-M4LbVmJ_ibgbzbvRLVti8FhnR0BTf8,1096
|
7
|
-
oikan-0.0.3.6.dist-info/METADATA,sha256=P-07jTsmYsaANnQOjh_mzmjLk1Q9rqN665CBp_FKYjU,12749
|
8
|
-
oikan-0.0.3.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
9
|
-
oikan-0.0.3.6.dist-info/top_level.txt,sha256=XwnwKwTJddZwIvtrUsAz-l-58BJRj6HjAGWrfYi_3QY,6
|
10
|
-
oikan-0.0.3.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|