simml 0.1.0__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.

Potentially problematic release.


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

@@ -0,0 +1,3 @@
1
+ from.models import GaussianProcessModelConfig,LinearModelConfig,NeuralNetworkModelConfig
2
+ from.trainer import CVResult,SurrogateTrainer
3
+ __all__=['SurrogateTrainer','CVResult','LinearModelConfig','GaussianProcessModelConfig','NeuralNetworkModelConfig']
@@ -0,0 +1,9 @@
1
+ from __future__ import annotations
2
+ _C='neural_network'
3
+ _B='gaussian_process'
4
+ _A='linear'
5
+ from typing import Literal
6
+ from pydantic import BaseModel
7
+ class LinearModelConfig(BaseModel):type:Literal[_A]=_A
8
+ class GaussianProcessModelConfig(BaseModel):type:Literal[_B]=_B;n_restarts_optimizer:int=5;normalize_y:bool=True;random_seed:int=42
9
+ class NeuralNetworkModelConfig(BaseModel):type:Literal[_C]=_C;hidden_layer_sizes:list[int]=[64,64];activation:str='relu';solver:str='adam';max_iter:int=2000;early_stopping:bool=True;random_seed:int=42
@@ -0,0 +1,55 @@
1
+ from __future__ import annotations
2
+ _B='target_names'
3
+ _A='pipeline'
4
+ import warnings
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+ from typing import Any
8
+ import joblib,numpy as np,pandas as pd
9
+ from sklearn.base import clone
10
+ from sklearn.gaussian_process import GaussianProcessRegressor
11
+ from sklearn.metrics import mean_absolute_error,r2_score
12
+ from sklearn.model_selection import KFold,LeaveOneOut,cross_val_predict
13
+ from sklearn.multioutput import MultiOutputRegressor
14
+ from sklearn.pipeline import Pipeline
15
+ from sklearn.preprocessing import StandardScaler
16
+ from.models import GaussianProcessModelConfig
17
+ from.trainer import CVResult,build_pipeline,estimator_from_config
18
+ def build_multi_pipeline(estimator):
19
+ A=estimator
20
+ if isinstance(A,GaussianProcessRegressor):B=MultiOutputRegressor(clone(A),n_jobs=-1)
21
+ else:B=clone(A)
22
+ return Pipeline([('scaler',StandardScaler()),('model',B)])
23
+ @dataclass
24
+ class MultiCVResult:
25
+ model_name:str;target_results:dict[str,CVResult]
26
+ @property
27
+ def mean_q2(self):A=[A.q2 for A in self.target_results.values()if not np.isnan(A.q2)];return float(np.mean(A))if A else float('nan')
28
+ @property
29
+ def mean_r2(self):return float(np.mean([A.r2 for A in self.target_results.values()]))
30
+ def summary(B):
31
+ C=[f"\n ┌─ {B.model_name} (multi-output) [Q² moyen={B.mean_q2:+.4f} R² moyen={B.mean_r2:+.4f}]"]
32
+ for(D,A)in B.target_results.items():E='-'*int(max(0,A.q2)*20);C.append(f" │ {D:<26} R²={A.r2:+.4f} Q²={A.q2:+.4f} RMSE={A.rmse:.3f} LOOCV={A.loocv_rmse:.3f} {E}")
33
+ C.append(f" └{'─'*62}");return'\n'.join(C)
34
+ @dataclass
35
+ class MultiOutputSurrogateTrainer:
36
+ feature_names:list[str];target_names:list[str];model_configs:list[Any];n_folds:int=5;random_seed:int=42;models_dir:Path=Path('models_saved_multi')
37
+ def _estimators(A):return[estimator_from_config(A)for A in A.model_configs]
38
+ @staticmethod
39
+ def _press(y,y_loo):A=y-y_loo;B=float(np.sum(A**2));C=float(np.sum((y-np.mean(y))**2));D=1.-B/C if C>0 else float('nan');E=float(np.sqrt(np.mean(A**2)));return B,D,E
40
+ def run(A,csv_path):
41
+ J='ignore';I=True;E=pd.read_csv(csv_path).dropna(subset=A.target_names);F=E[A.feature_names].values;B=E[A.target_names].values;S=KFold(n_splits=A.n_folds,shuffle=I,random_state=A.random_seed);T=LeaveOneOut();print(f" Dataset : {len(E)} lignes │ {len(A.feature_names)} features │ {len(A.target_names)} cibles (multi-output)");K=[]
42
+ for(C,L)in A._estimators():
43
+ print(f"\n ══ {C} (multi-output) ══");M=build_multi_pipeline(L)
44
+ with warnings.catch_warnings():warnings.simplefilter(J);U=cross_val_predict(M,F,B,cv=S)
45
+ with warnings.catch_warnings():warnings.simplefilter(J);V=cross_val_predict(M,F,B,cv=T)
46
+ N={}
47
+ for(G,O)in enumerate(A.target_names):D,H,W=B[:,G],U[:,G],V[:,G];X,Y,Z=A._press(D,W);N[O]=CVResult(model_name=C,target_name=O,r2=r2_score(D,H),mae=mean_absolute_error(D,H),rmse=float(np.sqrt(np.mean((D-H)**2))),press=X,q2=Y,loocv_rmse=Z)
48
+ P=MultiCVResult(model_name=C,target_results=N);K.append(P);print(P.summary());Q=build_multi_pipeline(L)
49
+ with warnings.catch_warnings():warnings.simplefilter(J);Q.fit(F,B)
50
+ A.models_dir.mkdir(parents=I,exist_ok=I);a=C.replace(' ','_').replace('(','').replace(')','');R=A.models_dir/f"{a}_multi.joblib";joblib.dump({_A:Q,_B:A.target_names},R);print(f" Sauvegardé : {R}")
51
+ return K
52
+ @staticmethod
53
+ def print_best(results):A='═';print(f"\n{A*80}");print(' MEILLEUR MODÈLE MULTI-OUTPUT (Q² moyen)');print(f"{A*80}");B=max(results,key=lambda r:r.mean_q2);print(B.summary());print(f"{A*80}")
54
+ @staticmethod
55
+ def load(path):A=joblib.load(path);return A[_A],A[_B]
@@ -0,0 +1,50 @@
1
+ from __future__ import annotations
2
+ import warnings
3
+ from dataclasses import dataclass
4
+ from pathlib import Path
5
+ from typing import Any
6
+ import joblib,numpy as np,pandas as pd
7
+ from sklearn.base import clone
8
+ from sklearn.gaussian_process import GaussianProcessRegressor
9
+ from sklearn.gaussian_process.kernels import RBF,ConstantKernel,WhiteKernel
10
+ from sklearn.linear_model import LinearRegression
11
+ from sklearn.metrics import mean_absolute_error,r2_score
12
+ from sklearn.model_selection import KFold,LeaveOneOut,cross_val_predict
13
+ from sklearn.neural_network import MLPRegressor
14
+ from sklearn.pipeline import Pipeline
15
+ from sklearn.preprocessing import StandardScaler
16
+ from.models import GaussianProcessModelConfig,LinearModelConfig,NeuralNetworkModelConfig
17
+ def build_pipeline(estimator):return Pipeline([('scaler',StandardScaler()),('model',clone(estimator))])
18
+ def estimator_from_config(cfg):
19
+ A=cfg
20
+ if isinstance(A,LinearModelConfig):return'Regression Lineaire',LinearRegression()
21
+ if isinstance(A,GaussianProcessModelConfig):return'Gaussian Process',GaussianProcessRegressor(kernel=ConstantKernel(1.)*RBF(1.)+WhiteKernel(.001),n_restarts_optimizer=A.n_restarts_optimizer,normalize_y=A.normalize_y,random_state=A.random_seed)
22
+ if isinstance(A,NeuralNetworkModelConfig):return'Neural Network (MLP)',MLPRegressor(hidden_layer_sizes=tuple(A.hidden_layer_sizes),activation=A.activation,solver=A.solver,max_iter=A.max_iter,early_stopping=A.early_stopping,random_state=A.random_seed)
23
+ raise ValueError(f"Config modèle non reconnue : {type(A)}")
24
+ @dataclass
25
+ class CVResult:
26
+ model_name:str;target_name:str;r2:float;mae:float;rmse:float;press:float;q2:float;loocv_rmse:float
27
+ def line(A):B='-'*int(max(0,A.q2)*20);return f" {A.model_name:<28} │ {A.target_name:<26} │ R²={A.r2:+.4f} Q²={A.q2:+.4f} MAE={A.mae:.3f} RMSE={A.rmse:.3f} LOOCV={A.loocv_rmse:.3f} PRESS={A.press:.3f} {B}"
28
+ @dataclass
29
+ class SurrogateTrainer:
30
+ feature_names:list[str];target_names:list[str];model_configs:list[Any];n_folds:int=5;random_seed:int=42;models_dir:Path=Path('models_saved')
31
+ def _estimators(A):return[estimator_from_config(A)for A in A.model_configs]
32
+ @staticmethod
33
+ def _compute_press(y_true,y_pred):A=y_true;B=A-y_pred;C=float(np.sum(B**2));D=float(np.sum((A-np.mean(A))**2));E=1.-C/D if D>0 else np.nan;F=float(np.sqrt(np.mean(B**2)));return C,E,F
34
+ def run(A,csv_path):
35
+ H='ignore';G=True;D=pd.read_csv(csv_path).dropna(subset=A.target_names);E=D[A.feature_names].values;P=KFold(n_splits=A.n_folds,shuffle=G,random_state=A.random_seed);Q=LeaveOneOut();R=A._estimators();I=[];print(f" Dataset : {len(D)} lignes │ {len(A.feature_names)} features │ {len(A.target_names)} cibles")
36
+ for C in A.target_names:
37
+ B=D[C].values;print(f"\n ── {C} ──")
38
+ for(J,K)in R:
39
+ L=build_pipeline(K)
40
+ with warnings.catch_warnings():warnings.simplefilter(H);F=cross_val_predict(L,E,B,cv=P)
41
+ with warnings.catch_warnings():warnings.simplefilter(H);S=cross_val_predict(L,E,B,cv=Q)
42
+ T,U,V=A._compute_press(y_true=B,y_pred=S);M=CVResult(model_name=J,target_name=C,r2=r2_score(B,F),mae=mean_absolute_error(B,F),rmse=float(np.sqrt(np.mean((B-F)**2))),press=T,q2=U,loocv_rmse=V);I.append(M);print(M.line());N=build_pipeline(K)
43
+ with warnings.catch_warnings():warnings.simplefilter(H);N.fit(E,B)
44
+ O=A.models_dir/C;O.mkdir(parents=G,exist_ok=G);W=J.replace(' ','_').replace('(','').replace(')','');joblib.dump(N,O/f"{W}.joblib")
45
+ return I
46
+ @staticmethod
47
+ def print_best(results,target_names):
48
+ A='═';print(f"\n{A*100}");print(' MEILLEUR MODÈLE PAR CIBLE (Q²)');print(f"{A*100}")
49
+ for B in target_names:C=max((A for A in results if A.target_name==B),key=lambda r:r.q2);print(C.line())
50
+ print(f"{A*100}")
@@ -0,0 +1,22 @@
1
+ Metadata-Version: 2.4
2
+ Name: simml
3
+ Version: 0.1.0
4
+ Summary: A framework for scientific simulation surrogate models.
5
+ Author-email: PinkSalmon <dev@pinksalmon.cloud>
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: Programming Language :: Python :: 3.11
8
+ Classifier: Programming Language :: Python :: 3.12
9
+ Classifier: Programming Language :: Python :: 3.13
10
+ Requires-Python: >=3.11
11
+ Requires-Dist: joblib
12
+ Requires-Dist: pandas
13
+ Requires-Dist: pydantic
14
+ Requires-Dist: scikit-learn
15
+ Provides-Extra: dev
16
+ Requires-Dist: mypy>=1.0; extra == 'dev'
17
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
18
+ Requires-Dist: pytest>=7.0; extra == 'dev'
19
+ Requires-Dist: ruff>=0.4; extra == 'dev'
20
+ Provides-Extra: docs
21
+ Requires-Dist: mkdocstrings-python; extra == 'docs'
22
+ Requires-Dist: zensical; extra == 'docs'
@@ -0,0 +1,7 @@
1
+ simml/surrogate/__init__.py,sha256=estmhsSPMzyGsAjK8jLQQ0dcScgjxJvTorQueOys7dU,250
2
+ simml/surrogate/models.py,sha256=MfiMRLjt8bHpaZSk6lNSzLkg4M9eGP4YLEQhv4VlhKo,534
3
+ simml/surrogate/multi_trainer.py,sha256=QUwc-7WwFZFPUfWwrnPxvNlF513G6BCdoc8hfSmflfA,3589
4
+ simml/surrogate/trainer.py,sha256=gU6v1xy8OTmoBiUqNiDThzaDyGT_5vsXewGwcySvbvo,3701
5
+ simml-0.1.0.dist-info/METADATA,sha256=biedC7J0cPFLmPFcLx1lESltvIBUalBOI67uhZSpOgs,789
6
+ simml-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
7
+ simml-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any