SKSurrogate 0.1.0__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.
Files changed (33) hide show
  1. sksurrogate-0.1.0/PKG-INFO +139 -0
  2. sksurrogate-0.1.0/SKSurrogate/DataProcess.py +409 -0
  3. sksurrogate-0.1.0/SKSurrogate/NpyProximation.py +457 -0
  4. sksurrogate-0.1.0/SKSurrogate/__init__.py +110 -0
  5. sksurrogate-0.1.0/SKSurrogate/aml.py +1156 -0
  6. sksurrogate-0.1.0/SKSurrogate/ci.py +93 -0
  7. sksurrogate-0.1.0/SKSurrogate/deployment.py +31 -0
  8. sksurrogate-0.1.0/SKSurrogate/eoa.py +381 -0
  9. sksurrogate-0.1.0/SKSurrogate/execution.py +416 -0
  10. sksurrogate-0.1.0/SKSurrogate/inference.py +224 -0
  11. sksurrogate-0.1.0/SKSurrogate/mltrace.py +2138 -0
  12. sksurrogate-0.1.0/SKSurrogate/modelbundle.py +600 -0
  13. sksurrogate-0.1.0/SKSurrogate/monitoring.py +360 -0
  14. sksurrogate-0.1.0/SKSurrogate/retraining.py +49 -0
  15. sksurrogate-0.1.0/SKSurrogate/sensapprx.py +250 -0
  16. sksurrogate-0.1.0/SKSurrogate/structsearch.py +1411 -0
  17. sksurrogate-0.1.0/SKSurrogate/synthdat.py +503 -0
  18. sksurrogate-0.1.0/SKSurrogate.egg-info/PKG-INFO +139 -0
  19. sksurrogate-0.1.0/SKSurrogate.egg-info/SOURCES.txt +31 -0
  20. sksurrogate-0.1.0/SKSurrogate.egg-info/dependency_links.txt +1 -0
  21. sksurrogate-0.1.0/SKSurrogate.egg-info/entry_points.txt +2 -0
  22. sksurrogate-0.1.0/SKSurrogate.egg-info/requires.txt +13 -0
  23. sksurrogate-0.1.0/SKSurrogate.egg-info/top_level.txt +1 -0
  24. sksurrogate-0.1.0/setup.cfg +4 -0
  25. sksurrogate-0.1.0/setup.py +48 -0
  26. sksurrogate-0.1.0/tests/test_optimized_paths.py +1400 -0
  27. sksurrogate-0.1.0/tests/test_phase1_endpoints.py +323 -0
  28. sksurrogate-0.1.0/tests/test_phase2_endpoints.py +373 -0
  29. sksurrogate-0.1.0/tests/test_phase3_endpoints.py +349 -0
  30. sksurrogate-0.1.0/tests/test_phase4_endpoints.py +436 -0
  31. sksurrogate-0.1.0/tests/test_phase5_endpoints.py +167 -0
  32. sksurrogate-0.1.0/tests/test_phase6_endpoints.py +216 -0
  33. sksurrogate-0.1.0/tests/test_phase7_endpoints.py +133 -0
@@ -0,0 +1,139 @@
1
+ Metadata-Version: 2.4
2
+ Name: SKSurrogate
3
+ Version: 0.1.0
4
+ Summary: A python package that implements or wraps a few machine learning tools Scikit-Learn style.
5
+ Home-page: https://github.com/mghasemi/sksurrogate.git
6
+ Author: Mehdi Ghasemi
7
+ Author-email: mehdi.ghasemi@gmail.com
8
+ License: MIT License
9
+ Keywords: Auto Machine Learning,AutoML,Optimization,Surrogate Optimization,Numerical,Machine Learning,Regression,Random Search
10
+ Requires-Dist: numpy
11
+ Requires-Dist: scipy
12
+ Requires-Dist: pandas
13
+ Requires-Dist: matplotlib
14
+ Requires-Dist: scikit-learn
15
+ Requires-Dist: SALib
16
+ Requires-Dist: imbalanced-learn
17
+ Requires-Dist: joblib
18
+ Requires-Dist: eli5
19
+ Requires-Dist: skrebate
20
+ Requires-Dist: tqdm
21
+ Requires-Dist: peewee
22
+ Requires-Dist: category_encoders
23
+ Dynamic: author
24
+ Dynamic: author-email
25
+ Dynamic: description
26
+ Dynamic: home-page
27
+ Dynamic: keywords
28
+ Dynamic: license
29
+ Dynamic: requires-dist
30
+ Dynamic: summary
31
+
32
+ |Quality| |Doc| |Licence|
33
+
34
+ |Logo|
35
+
36
+ SKSurrogate
37
+ ==================
38
+ ``SKSurrogate`` is a suite of tools which implements surrogate optimization for expensive
39
+ functions based on ``scikit-learn``. The main purpose of ``SKSurrogate`` is to facilitate
40
+ hyperparameter optimization for machine learning models and optimized pipeline design (AutoML).
41
+
42
+ The version of the surrogate optimization implemented here heavily relies on regressors.
43
+ A custom regressor based on Hilbert Space techniques is implemented, but all ``scikit-learn``
44
+ regressors are accepted for optimization.
45
+
46
+ Finding an optimized pipeline -based on a given list of transformers and estimators is
47
+ a time-consuming task. A version of evolutionary optimization has been implemented to reduce
48
+ its time in lieu of global optimality.
49
+
50
+ ``SKSurrogate`` is positioned as a scientific/research library: the numerical methods are
51
+ validated against benchmarks, but the API surface evolves with ongoing research work.
52
+
53
+ Installation
54
+ ------------
55
+ From PyPI::
56
+
57
+ pip install sksurrogate
58
+
59
+ or from source (development)::
60
+
61
+ pip install git+https://github.com/mghasemi/sksurrogate.git
62
+
63
+ Data identity and schema validation
64
+ -----------------------------------
65
+ ``SKSurrogate`` now records a deterministic dataset fingerprint and a JSON-serializable schema
66
+ for each tracked dataset. Each call to ``mltrack.RegisterData(...)`` stores dataset metadata,
67
+ including the target column, row count, column names, dtypes, nullability, and categorical values.
68
+ This allows a run to be identified and later compared against a different dataset or a refreshed
69
+ training sample.
70
+
71
+ The tracker also exposes ``validate_data(...)`` and ``validate_prediction_data(...)`` to compare
72
+ incoming data against the stored schema before training or inference. By default the checks are
73
+ strict: missing columns, reordered columns, dtype mismatches, and unknown categorical values fail
74
+ with actionable errors. For compatibility workflows, these checks can be relaxed explicitly with
75
+ ``missing_columns='ignore'`` or ``unknown_categories='ignore'``.
76
+
77
+ The intended workflow is:
78
+
79
+ 1. Register the training dataset with ``mltrack.RegisterData(frame, target)``.
80
+ 2. Validate training data before fitting with ``tracker.validate_data(frame, target=...)``.
81
+ 3. Validate prediction inputs with ``tracker.validate_prediction_data(frame)`` before calling
82
+ ``predict`` on a model or pipeline.
83
+ 4. Use the stored ``dataset_fingerprint`` and ``dataset_schema`` metadata for reproducibility,
84
+ drift checks, and auditability.
85
+
86
+ Dependencies
87
+ ----------------
88
+ ``SKSurrogate`` heavily depends on `NumPy <http://www.numpy.org/>`_,
89
+ `scipy <https://www.scipy.org/>`_, and `scikit-learn <https://scikit-learn.org/stable/>`_,
90
+ for its main functionalities. Other dependencies include `pandas <https://pandas.pydata.org/>`_,
91
+ `matplotlib <https://matplotlib.org/>`_, `SALib <https://github.com/SALib/SALib>`_,
92
+ `peewee <https://github.com/coleifer/peewee>`_, and
93
+ `tqdm <https://github.com/tqdm/tqdm>`_.
94
+
95
+ Documentation
96
+ ----------------
97
+ The documentation is produced by `Sphinx <http://www.sphinx-doc.org/en/stable/>`_ and is intended to cover code usage
98
+ as well as a bit of theory to explain each method briefly.
99
+ For more details refer to the documentation at `sksurrogate.rtfd.io <http://sksurrogate.readthedocs.io/>`_.
100
+ The optional web UI and control-plane API are documented in the
101
+ `Web UI and Control-Plane API guide <https://sksurrogate.readthedocs.io/en/latest/controlplane.html>`_.
102
+ The `step-by-step UI manual <https://sksurrogate.readthedocs.io/en/latest/ui-manual.html>`_
103
+ includes screenshots and example CSV files.
104
+
105
+ License
106
+ ================
107
+ This code is distributed under `MIT license <https://en.wikipedia.org/wiki/MIT_License>`_:
108
+
109
+ MIT License
110
+ ----------------
111
+
112
+ Copyright (c) 2019 Mehdi Ghasemi
113
+
114
+ Permission is hereby granted, free of charge, to any person obtaining a copy
115
+ of this software and associated documentation files (the "Software"), to deal
116
+ in the Software without restriction, including without limitation the rights
117
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
118
+ copies of the Software, and to permit persons to whom the Software is
119
+ furnished to do so, subject to the following conditions:
120
+
121
+ The above copyright notice and this permission notice shall be included in all
122
+ copies or substantial portions of the Software.
123
+
124
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
125
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
126
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
127
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
128
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
129
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
130
+ SOFTWARE.
131
+
132
+ .. |Logo| image:: ./docs/images/funnel.png
133
+ .. |Quality| image:: https://api.codacy.com/project/badge/Grade/9a4d3e663cb04128a06d47efc85f23da
134
+ :target: https://www.codacy.com/app/mghasemi/sksurrogate?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=mghasemi/sksurrogate&amp;utm_campaign=Badge_Grade
135
+ .. |Doc| image:: https://readthedocs.org/projects/sksurrogate/badge/?version=latest
136
+ :target: https://sksurrogate.readthedocs.io/en/latest/?badge=latest
137
+ :alt: Documentation Status
138
+ .. |Licence| image:: https://img.shields.io/badge/license-MIT-blue.svg
139
+ :target: https://github.com/mghasemi/sksurrogate/blob/master/License.txt
@@ -0,0 +1,409 @@
1
+ """
2
+ DataProcess: A DataFrame preprocessing module for ML
3
+ ===========================================================
4
+
5
+ The module is designed to do some preprocessing task on a given DataFrame.
6
+ Currently, the module detects types of columns data e.g., numerical (integer, float), categorical, boolean, ordinal,
7
+ datetime, and labels. To impose a text column, the type of the column should be declared before passing the DataFrame.
8
+ This can be done by a simple code such as `df.astype({'txt_column':pandas.StringDtype()})`
9
+
10
+ The module performs ordinal encoding, one hot encoding, date range to float transformation, label encoding, and
11
+ missing data imputation.
12
+
13
+ To Do
14
+ ----------
15
+ Processing of Image data.
16
+
17
+ Code
18
+ ----------
19
+ """
20
+ import numpy as np
21
+
22
+ import numpy
23
+ import pandas
24
+ import pandas as pd
25
+ from copy import copy
26
+ import re
27
+ from sklearn.base import BaseEstimator, TransformerMixin
28
+ from sklearn.pipeline import Pipeline
29
+ from sklearn.experimental import enable_iterative_imputer
30
+ from sklearn.impute import IterativeImputer
31
+ from sklearn.feature_extraction.text import TfidfVectorizer
32
+
33
+
34
+ class DateTime2Num(TransformerMixin, BaseEstimator):
35
+ """
36
+ Converts a date range data to numeric (float) between `lower` and `upper`.
37
+
38
+ :param cols: default: `None`; column names for transformation.
39
+ :param unit: default: 'day`; the time unit.
40
+ :param lower: default: `0.0`; the lower bound of the transformation range.
41
+ :param upper: default: `2.0`; the upper bound of the transformation range.
42
+ """
43
+
44
+ def __init__(self, cols=None, unit='day', lower=0., upper=2.):
45
+ if unit not in ['day', 'hour', 'minute', 'second']:
46
+ raise ValueError("`unit` must be either 'day', 'hour', 'minute', or 'second'.")
47
+ self.cols = cols
48
+ self.unit = unit
49
+ self.lower = lower
50
+ self.upper = upper
51
+ self.coefs = dict()
52
+ self.scale = 1.
53
+ self.scale = numpy.timedelta64(1, 's')
54
+ if self.unit == 'minute':
55
+ self.scale = 60.
56
+ self.scale = numpy.timedelta64(1, 'm')
57
+ elif self.unit == 'hour':
58
+ self.scale = 60 * 60.
59
+ self.scale = numpy.timedelta64(1, 'h')
60
+ elif self.unit == 'day':
61
+ self.scale = 60 * 60 * 24.
62
+ self.scale = numpy.timedelta64(1, 'D')
63
+
64
+ def fit(self, X):
65
+ """
66
+ Fits and calculates the transformation parameters for date range transformation.
67
+
68
+ :param X: Input data
69
+ :return: `self`
70
+ """
71
+ if self.cols is None:
72
+ return self
73
+ n_length = self.upper - self.lower
74
+ for clmn in self.cols:
75
+ t_vec = X[clmn].dropna().values
76
+ min_date, max_date = t_vec.min(), t_vec.max()
77
+ # t_length = (max_date - min_date).seconds / self.scale
78
+ t_length = (max_date - min_date) / self.scale
79
+ trans_coef = n_length / t_length
80
+ intercept = self.lower
81
+ self.coefs[clmn] = (trans_coef, intercept, min_date)
82
+ return self
83
+
84
+ def transform(self, X):
85
+ """
86
+ Apply the calculated parameters to transform the datetime columns.
87
+
88
+ :param X: the input data
89
+ :return: transformed data
90
+ """
91
+ if self.cols is None:
92
+ return X
93
+ TX = X
94
+ for clmn in self.cols:
95
+ vect = numpy.array(
96
+ [self.coefs[clmn][1] + self.coefs[clmn][0] * (_ - self.coefs[clmn][2]) / self.scale for _ in
97
+ TX[clmn].values])
98
+ TX[clmn] = vect
99
+ return TX
100
+
101
+ def fit_transform(self, X, y=None, **fit_params):
102
+ """
103
+ Fits and transforms the input data.
104
+
105
+ :param X: input data;
106
+ :param y: target field; not required, but included to comply with scikit-learn's signature
107
+ :param fit_params: included to comply with scikit-learn's signature
108
+ :return: transformed DataFrame
109
+ """
110
+ self.fit(X)
111
+ return self.transform(X)
112
+
113
+
114
+ class DataPreprocess(object):
115
+ """
116
+ This class performs a few reprocessing task on the input DataFrame to provide a ML ready dataset.
117
+
118
+ :param df: the input raw DataFrame
119
+ :param bin_threshold: float between 0. and 1.; when the proportion of unique values to the total number of entities
120
+ falls below this number fo two valued columns, the type is deduced to be binary
121
+ :param cat_threshold: when the proportion of unique values to the total number of entities
122
+ falls below this number fo discrete columns, the type is deduced to be categorical or ordinal
123
+ :param force_threshold: boolean, indicate whether to force the deduction based on the provided thresholds or not
124
+ :param imputer: the imputer object; default `IterativeImputer` for missing values imputation
125
+ :param force_impute: boolean; default `True` to indicate the desire for missing value imputation
126
+ """
127
+
128
+ def __init__(self, df, bin_threshold=.1, cat_threshold=.1, force_threshold=False, imputer=None, force_impute=True,
129
+ text_processor=None):
130
+ self.df = copy(df)
131
+ self.bin_threshold = bin_threshold
132
+ self.cat_threshold = cat_threshold
133
+ self.force_threshold = force_threshold
134
+ self.columns = list(df.columns)
135
+ self.values = dict()
136
+ self.uniques = dict()
137
+ self.types = dict()
138
+ self.transforms = dict()
139
+ self.mapping = dict()
140
+ self.deduced_types = dict(float64=[], int64=[], datetime64=[], other=[], text=[],
141
+ binary=[], categorical=[], label=[], obsolete=[])
142
+ self.pivot_types = dict()
143
+ self.processed_frame = dict()
144
+ self.transformed_df = None
145
+ self.steps = []
146
+ for clmn in self.columns:
147
+ self.values[clmn] = self.df[clmn].dropna().values
148
+ self.uniques[clmn] = self.df[clmn].dropna().unique()
149
+ self.types[clmn] = self.df[clmn].dtypes.name
150
+ self.types_deduced = False
151
+ self.encoded = False
152
+ self.force_impute = force_impute
153
+ if imputer is None:
154
+ self.imputer = IterativeImputer()
155
+ else:
156
+ self.imputer = imputer
157
+ if text_processor is None:
158
+ self.txt_prcsr = TfidfVectorizer(sublinear_tf=True, max_features=1600, min_df=5, norm='l2',
159
+ ngram_range=(1, 3), stop_words='english')
160
+ else:
161
+ self.txt_prcsr = text_processor
162
+
163
+ @staticmethod
164
+ def numeric(val, typ='float64'):
165
+ trans_val = re.sub(r"[^\d\.]", "", str(val))
166
+ if typ == 'float64':
167
+ return float(trans_val)
168
+ elif typ == 'int64':
169
+ return int(trans_val)
170
+
171
+ def is_float(self, clmn):
172
+ """
173
+ Determines if the type of the data for the column `clmn` is float or not
174
+
175
+ :param clmn: the name of the column
176
+ :return: boolean
177
+ """
178
+ if self.types[clmn] == 'float64':
179
+ return True
180
+ return False
181
+
182
+ def is_int(self, clmn):
183
+ """
184
+ Determines if the type of the data for the column `clmn` is integer or not
185
+
186
+ :param clmn: the name of the column
187
+ :return: boolean
188
+ """
189
+ if self.types[clmn] == 'int64':
190
+ return True
191
+ return False
192
+
193
+ def is_object(self, clmn):
194
+ """
195
+ Determines if the type of the data for the column `clmn` is object (e.g., string, blob, etc.) or not
196
+
197
+ :param clmn: the name of the column
198
+ :return: boolean
199
+ """
200
+ if self.types[clmn] == 'object':
201
+ return True
202
+ return False
203
+
204
+ def is_datetime(self, clmn):
205
+ """
206
+ Determines if the type of the data for the column `clmn` is datetime or not
207
+
208
+ :param clmn: the name of the column
209
+ :return: boolean
210
+ """
211
+ if 'datetime64' in self.types[clmn]:
212
+ return True
213
+ return False
214
+
215
+ def is_text(self, clmn):
216
+ """
217
+ Determine if the type of the data for the column `clmn` is string/text or not. A string column is of type
218
+ `pandas.StringDtype()`.
219
+
220
+ :param clmn: the name of the column
221
+ :return: boolean
222
+ """
223
+ if 'string' in self.types[clmn]:
224
+ self.df[clmn].fillna("", inplace=True)
225
+ return True
226
+ return False
227
+
228
+ def is_obsolete(self, clmn):
229
+ """
230
+ Determines if the column is worth to be included in the analysis or not
231
+
232
+ :param clmn: the name of the column
233
+ :return: boolean; `True` if includes more than 1 value, `False` otherwise
234
+ """
235
+ if len(self.uniques[clmn]) < 2:
236
+ return True
237
+ return False
238
+
239
+ def is_bin(self, clmn):
240
+ """
241
+ Determines if the type of the data for the column `clmn` is binary or not
242
+
243
+ :param clmn: the name of the column
244
+ :return: boolean
245
+ """
246
+ ratio = len(self.uniques[clmn]) / len(self.values[clmn])
247
+ if self.force_threshold and (len(self.uniques[clmn]) == 2) and (ratio <= self.bin_threshold):
248
+ return True
249
+ if not self.force_threshold and (len(self.uniques[clmn]) == 2):
250
+ return True
251
+ return False
252
+
253
+ def is_categorical(self, clmn):
254
+ """
255
+ Determines if the type of the data for the column `clmn` is categorical or not
256
+
257
+ :param clmn: the name of the column
258
+ :return: boolean
259
+ """
260
+ ratio = len(self.uniques[clmn]) / len(self.values[clmn])
261
+ if self.force_threshold and (ratio <= self.cat_threshold):
262
+ return True
263
+ elif (ratio <= self.cat_threshold) and (self.types[clmn] == 'object'):
264
+ return True
265
+ else:
266
+ return False
267
+
268
+ def is_label(self, clmn):
269
+ """
270
+ Determines if the type of the data for the column `clmn` is label or not
271
+
272
+ :param clmn: the name of the column
273
+ :return: boolean
274
+ """
275
+ if (self.types[clmn] == 'object') and not self.is_categorical(clmn):
276
+ return True
277
+ return False
278
+
279
+ def set_type(self, clmn, typ):
280
+ if typ not in self.deduced_types:
281
+ raise "Unknown type."
282
+ self.deduced_types[typ].append(clmn)
283
+ self.pivot_types[clmn] = typ
284
+
285
+ def deduce_types(self):
286
+ """
287
+ Deduces the type of all columns.
288
+
289
+ :return: `None`
290
+ """
291
+ for clmn in self.columns:
292
+ if clmn in self.pivot_types:
293
+ continue
294
+ if self.is_label(clmn):
295
+ self.deduced_types['label'].append(clmn)
296
+ self.pivot_types[clmn] = 'label'
297
+ elif self.is_text(clmn):
298
+ self.deduced_types['text'].append(clmn)
299
+ self.pivot_types[clmn] = 'text'
300
+ elif self.is_bin(clmn):
301
+ self.deduced_types['binary'].append(clmn)
302
+ self.pivot_types[clmn] = 'binary'
303
+ elif self.is_categorical(clmn):
304
+ self.deduced_types['categorical'].append(clmn)
305
+ self.pivot_types[clmn] = 'categorical'
306
+ elif self.is_datetime(clmn):
307
+ self.deduced_types['datetime64'].append(clmn)
308
+ self.pivot_types[clmn] = 'datetime64'
309
+ elif self.is_object(clmn):
310
+ self.deduced_types['other'].append(clmn)
311
+ self.pivot_types[clmn] = 'other'
312
+ elif self.is_int(clmn):
313
+ self.deduced_types['int64'].append(clmn)
314
+ self.pivot_types[clmn] = 'int64'
315
+ elif self.is_float(clmn):
316
+ self.deduced_types['float64'].append(clmn)
317
+ self.pivot_types[clmn] = 'float64'
318
+ elif self.is_obsolete(clmn):
319
+ self.deduced_types['obsolete'].append(clmn)
320
+ self.pivot_types[clmn] = 'obsolete'
321
+ self.types_deduced = True
322
+
323
+ def transform_label_bin(self, clmn):
324
+ """
325
+ Transforms the determined label and binary columns.
326
+
327
+ :param clmn: the column's name
328
+ :return: `None`
329
+ """
330
+ lbls = numpy.sort(self.uniques[clmn])
331
+ self.transforms[clmn] = {_: lbls[_] for _ in range(lbls.shape[0])}
332
+ self.mapping[clmn] = {lbls[_]: _ for _ in range(lbls.shape[0])}
333
+
334
+ def encode(self):
335
+ """
336
+ Transforms the whole input DataFrame based on the deduced types and does missing data imputation if desired.
337
+ The resulted DataFrame will be stored in `transformed_df`
338
+
339
+ :return: Transformed and encoded dataframe
340
+ """
341
+ if not self.types_deduced:
342
+ self.deduce_types()
343
+ self.steps = []
344
+ txt_clmn_df = None
345
+ org_df = copy(self.df)
346
+ for clmn in self.deduced_types['int64']:
347
+ values = org_df[clmn].astype(str).str.replace(r"[^\d\.]", "", regex=True)
348
+ org_df[clmn] = pandas.to_numeric(values, errors='coerce')
349
+ for clmn in self.deduced_types['float64']:
350
+ values = org_df[clmn].astype(str).str.replace(r"[^\d\.]", "", regex=True)
351
+ org_df[clmn] = pandas.to_numeric(values, errors='coerce')
352
+ if self.deduced_types['text']:
353
+ txt_clmn_df = self.df[self.deduced_types['text']]
354
+ org_df.drop(self.deduced_types['text'], axis=1, inplace=True)
355
+ ordinal_columns = self.deduced_types['binary'] + self.deduced_types['label']
356
+ for clmn in ordinal_columns:
357
+ self.transform_label_bin(clmn)
358
+
359
+ working_df = org_df.copy()
360
+ for clmn in ordinal_columns:
361
+ working_df[clmn] = working_df[clmn].map(self.mapping[clmn]).astype(float)
362
+
363
+ for clmn in self.deduced_types['categorical']:
364
+ dummy = pandas.get_dummies(
365
+ working_df[clmn].astype(object).fillna("__MISSING__"),
366
+ prefix=str(clmn),
367
+ prefix_sep="_",
368
+ dummy_na=False,
369
+ )
370
+ working_df = pandas.concat([working_df.drop(columns=[clmn]), dummy], axis=1)
371
+
372
+ for clmn in self.deduced_types['datetime64']:
373
+ working_df[clmn] = pandas.to_datetime(working_df[clmn], errors='coerce')
374
+ working_df[clmn] = (
375
+ (working_df[clmn] - pandas.Timestamp("1970-01-01"))
376
+ .dt.total_seconds()
377
+ .astype(float)
378
+ )
379
+
380
+ dtn = DateTime2Num(cols=self.deduced_types['datetime64'])
381
+ self.steps.append(('Date2Num', dtn))
382
+ self.steps.append(('Impute', self.imputer))
383
+ trans = Pipeline(self.steps)
384
+
385
+ # Keep the numeric matrix consistent with the original API while avoiding the deprecated category_encoders path.
386
+ encoded_frame = pandas.DataFrame(
387
+ trans.fit_transform(working_df),
388
+ columns=working_df.columns,
389
+ )
390
+ self.transformed_df = encoded_frame.copy()
391
+
392
+ rounded_columns = set(ordinal_columns).union(self.deduced_types['categorical'])
393
+ for clmn in self.transformed_df.columns.intersection(rounded_columns):
394
+ rounded = pandas.to_numeric(self.transformed_df[clmn], errors='coerce').round(0)
395
+ if self.force_impute:
396
+ self.transformed_df[clmn] = rounded.astype(int)
397
+ else:
398
+ self.transformed_df[clmn] = rounded.astype(float)
399
+
400
+ for clmn in self.deduced_types['text']:
401
+ txt_array = txt_clmn_df[clmn].values
402
+ processed_txt = self.txt_prcsr.fit_transform(txt_array)
403
+ length = processed_txt.shape[1]
404
+ clmn_names = ["%s_%d" % (clmn, _) for _ in range(length)]
405
+ self.transformed_df = pandas.concat(
406
+ [self.transformed_df, pandas.DataFrame(processed_txt.toarray(), columns=clmn_names)], axis=1)
407
+
408
+ self.encoded = True
409
+ return self.transformed_df