2.3. Model Building#
So far we know how to parametrize:func:.run_cross_validation in terms of the input data (see Data). In this section, we will have a look on how we can parametrize the learning algorithm and the preprocessing steps, also known as the pipeline.
A machine learning pipeline is a process to automate the workflow of a predictive model. It can be thought of as a combination of pipes and filters. At a pipeline’s starting point, the raw data is fed into the first filter. The output of this filter is then fed into the next filter (through a pipe). In supervised Machine Learning, different filters inside the pipeline modify the data, while the last step is a learning algorithm that generates predictions. Before using the pipeline to predict new data, the pipeline has to be trained (fitted) on data. We call this, as scikit-learn does, fitting the pipeline.
Julearn aims to provide a user-friendly way to build and evaluate complex
machine learning pipelines. The run_cross_validation()
function is the
entry point to safely evaluate pipelines by making it easy to specify,
customize and train the pipeline. We first have a look at the most
basic pipeline, only consisting of a machine learning algorithm. Then we will
make the pipeline incrementally more complex.
Pipeline specification in run_cross_validation()
#
One important aspect when building machine learning models is the selection of
a learning algorithm. This can be specified in run_cross_validation()
by setting the model
parameter. This parameter can be any scikit-learn
compatible learning algorithm. However, Julearn provides a built-in list of
Models (Estimators) that can be specified by name (see Name (str)
column in Models (Estimators)). For example, we can simply set
model=="svm"
to use a support vector machine (SVM) [2].
Let’s first specify the data parameters as we learned in Data:
from julearn import run_cross_validation
from seaborn import load_dataset
df = load_dataset("iris")
X = ["sepal_length", "sepal_width", "petal_length", "petal_width"]
y = "species"
X_types = {
"continuous": [
"sepal_length",
"sepal_width",
"petal_length",
"petal_width",
]
}
Now we can run the cross validation with the SVM as learning algorithm:
scores = run_cross_validation(
X=X,
y=y,
data=df,
X_types=X_types,
model="svm",
problem_type="classification",
)
print(scores)
2023-07-19 12:42:38,912 - julearn - INFO - ==== Input Data ====
2023-07-19 12:42:38,912 - julearn - INFO - Using dataframe as input
2023-07-19 12:42:38,912 - julearn - INFO - Features: ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
2023-07-19 12:42:38,913 - julearn - INFO - Target: species
2023-07-19 12:42:38,913 - julearn - INFO - Expanded features: ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
2023-07-19 12:42:38,913 - julearn - INFO - X_types:{'continuous': ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']}
2023-07-19 12:42:38,914 - julearn - INFO - ====================
2023-07-19 12:42:38,914 - julearn - INFO -
2023-07-19 12:42:38,914 - julearn - INFO - Adding step svm that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2023-07-19 12:42:38,914 - julearn - INFO - Step added
2023-07-19 12:42:38,914 - julearn - INFO - = Model Parameters =
2023-07-19 12:42:38,914 - julearn - INFO - ====================
2023-07-19 12:42:38,915 - julearn - INFO -
2023-07-19 12:42:38,915 - julearn - INFO - = Data Information =
2023-07-19 12:42:38,915 - julearn - INFO - Problem type: classification
2023-07-19 12:42:38,915 - julearn - INFO - Number of samples: 150
2023-07-19 12:42:38,915 - julearn - INFO - Number of features: 4
2023-07-19 12:42:38,915 - julearn - INFO - ====================
2023-07-19 12:42:38,915 - julearn - INFO -
2023-07-19 12:42:38,915 - julearn - INFO - Number of classes: 3
2023-07-19 12:42:38,915 - julearn - INFO - Target type: object
2023-07-19 12:42:38,916 - julearn - INFO - Class distributions: species
setosa 50
versicolor 50
virginica 50
Name: count, dtype: int64
2023-07-19 12:42:38,916 - julearn - INFO - Using outer CV scheme KFold(n_splits=5, random_state=None, shuffle=False)
2023-07-19 12:42:38,916 - julearn - INFO - Multi-class classification problem detected #classes = 3.
fit_time score_time ... fold cv_mdsum
0 0.003695 0.002148 ... 0 b10eef89b4192178d482d7a1587a248a
1 0.003433 0.002120 ... 1 b10eef89b4192178d482d7a1587a248a
2 0.003364 0.002065 ... 2 b10eef89b4192178d482d7a1587a248a
3 0.003350 0.002154 ... 3 b10eef89b4192178d482d7a1587a248a
4 0.003359 0.002069 ... 4 b10eef89b4192178d482d7a1587a248a
[5 rows x 8 columns]
You will notice that this code indicates an extra parameter problem_type
.
This is because in machine learning, one can distinguish between regression
problems -when predicting a continuous outcome- and classification problems
-for discrete class label predictions-. Therefore,
run_cross_validation()
additionally needs to know which problem type
we are interested in. The possible values for problem_type
are
classification
and regression
. In the example we are interested in
predicting the species (see y
in Data), i.e. a discrete
class label.
Et voilà, your first machine learning pipeline is ready to go.
Feature preprocessing#
There are cases in which the input data, and in particular the features, should be transformed before passing them to the learning algorithm. One scenario can be that certain learning algorithms need the features in a specific form, for example in standardized form, so that the data resemble a normal distribution. This can be achieved by first z-scoring (or standard scaling) the features (see Scalers).
Importantly in a machine learning workflow, all transformations done to the
data have to be done in a cv-consistent way. That means that
data-transformation steps have to be done on the training data of each
respective cross validation fold and then only apply the parameters of the
transformation to the validation data of the respective fold. One should
never do preprocessing on the entire dataset and then do
cross-validation on the already preprocessed features (or more
generally transformed data) because this leads to leakage of information from
the validation data into the model. This is exactly where
run_cross_validation()
comes in handy, because you can simply add your
wished preprocessing step (Transformers) and it
takes care of doing the respective transformations in a cv-consistent manner.
Let’s have a look at how we can add a z-scoring step to our pipeline:
scores = run_cross_validation(
X=X,
y=y,
data=df,
X_types=X_types,
preprocess="zscore",
model="svm",
problem_type="classification",
)
print(scores)
2023-07-19 12:42:38,956 - julearn - INFO - ==== Input Data ====
2023-07-19 12:42:38,956 - julearn - INFO - Using dataframe as input
2023-07-19 12:42:38,956 - julearn - INFO - Features: ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
2023-07-19 12:42:38,956 - julearn - INFO - Target: species
2023-07-19 12:42:38,956 - julearn - INFO - Expanded features: ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
2023-07-19 12:42:38,956 - julearn - INFO - X_types:{'continuous': ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']}
2023-07-19 12:42:38,957 - julearn - INFO - ====================
2023-07-19 12:42:38,957 - julearn - INFO -
2023-07-19 12:42:38,957 - julearn - INFO - Adding step zscore that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2023-07-19 12:42:38,957 - julearn - INFO - Step added
2023-07-19 12:42:38,957 - julearn - INFO - Adding step svm that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2023-07-19 12:42:38,957 - julearn - INFO - Step added
2023-07-19 12:42:38,958 - julearn - INFO - = Model Parameters =
2023-07-19 12:42:38,958 - julearn - INFO - ====================
2023-07-19 12:42:38,958 - julearn - INFO -
2023-07-19 12:42:38,958 - julearn - INFO - = Data Information =
2023-07-19 12:42:38,958 - julearn - INFO - Problem type: classification
2023-07-19 12:42:38,958 - julearn - INFO - Number of samples: 150
2023-07-19 12:42:38,958 - julearn - INFO - Number of features: 4
2023-07-19 12:42:38,958 - julearn - INFO - ====================
2023-07-19 12:42:38,958 - julearn - INFO -
2023-07-19 12:42:38,958 - julearn - INFO - Number of classes: 3
2023-07-19 12:42:38,959 - julearn - INFO - Target type: object
2023-07-19 12:42:38,959 - julearn - INFO - Class distributions: species
setosa 50
versicolor 50
virginica 50
Name: count, dtype: int64
2023-07-19 12:42:38,959 - julearn - INFO - Using outer CV scheme KFold(n_splits=5, random_state=None, shuffle=False)
2023-07-19 12:42:38,960 - julearn - INFO - Multi-class classification problem detected #classes = 3.
fit_time score_time ... fold cv_mdsum
0 0.005893 0.003160 ... 0 b10eef89b4192178d482d7a1587a248a
1 0.005652 0.003082 ... 1 b10eef89b4192178d482d7a1587a248a
2 0.005568 0.003139 ... 2 b10eef89b4192178d482d7a1587a248a
3 0.005629 0.003097 ... 3 b10eef89b4192178d482d7a1587a248a
4 0.005583 0.003146 ... 4 b10eef89b4192178d482d7a1587a248a
[5 rows x 8 columns]
Note
Learning algorithms (what we specified in the model parameter), are
estimators. Preprocessing steps however, are usually transformers, because
they transform the input data in a certain way. Therefore the parameter
description in the api of run_cross_validation()
,
defines valid input for the preprocess parameter as TransformerLike.
- preprocessstr, TransformerLike or list | None
Transformer to apply to the features. If string, use one of the available transformers. If list, each element can be a string or scikit-learn compatible transformer. If None (default), no transformation is applied.
But what if we want to add more pre-processing steps? For example, in the case that there are many features available, we might want to reduce the dimensionality of the features before passing them to the learning algorithm. A commonly used approach is a principal component analysis (PCA, see Decomposition). If we nevertheless want to keep our previously applied z-scoring, we can simply add the PCA as another preprocessing step as follows:
scores = run_cross_validation(
X=X,
y=y,
data=df,
X_types=X_types,
preprocess=["zscore", "pca"],
model="svm",
problem_type="classification",
)
print(scores)
2023-07-19 12:42:39,016 - julearn - INFO - ==== Input Data ====
2023-07-19 12:42:39,016 - julearn - INFO - Using dataframe as input
2023-07-19 12:42:39,016 - julearn - INFO - Features: ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
2023-07-19 12:42:39,016 - julearn - INFO - Target: species
2023-07-19 12:42:39,016 - julearn - INFO - Expanded features: ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
2023-07-19 12:42:39,016 - julearn - INFO - X_types:{'continuous': ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']}
2023-07-19 12:42:39,017 - julearn - INFO - ====================
2023-07-19 12:42:39,017 - julearn - INFO -
2023-07-19 12:42:39,017 - julearn - INFO - Adding step zscore that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2023-07-19 12:42:39,017 - julearn - INFO - Step added
2023-07-19 12:42:39,017 - julearn - INFO - Adding step pca that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2023-07-19 12:42:39,017 - julearn - INFO - Step added
2023-07-19 12:42:39,017 - julearn - INFO - Adding step svm that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2023-07-19 12:42:39,017 - julearn - INFO - Step added
2023-07-19 12:42:39,018 - julearn - INFO - = Model Parameters =
2023-07-19 12:42:39,018 - julearn - INFO - ====================
2023-07-19 12:42:39,018 - julearn - INFO -
2023-07-19 12:42:39,018 - julearn - INFO - = Data Information =
2023-07-19 12:42:39,018 - julearn - INFO - Problem type: classification
2023-07-19 12:42:39,018 - julearn - INFO - Number of samples: 150
2023-07-19 12:42:39,018 - julearn - INFO - Number of features: 4
2023-07-19 12:42:39,018 - julearn - INFO - ====================
2023-07-19 12:42:39,019 - julearn - INFO -
2023-07-19 12:42:39,019 - julearn - INFO - Number of classes: 3
2023-07-19 12:42:39,019 - julearn - INFO - Target type: object
2023-07-19 12:42:39,019 - julearn - INFO - Class distributions: species
setosa 50
versicolor 50
virginica 50
Name: count, dtype: int64
2023-07-19 12:42:39,020 - julearn - INFO - Using outer CV scheme KFold(n_splits=5, random_state=None, shuffle=False)
2023-07-19 12:42:39,020 - julearn - INFO - Multi-class classification problem detected #classes = 3.
fit_time score_time ... fold cv_mdsum
0 0.007024 0.004145 ... 0 b10eef89b4192178d482d7a1587a248a
1 0.006958 0.004137 ... 1 b10eef89b4192178d482d7a1587a248a
2 0.006924 0.004086 ... 2 b10eef89b4192178d482d7a1587a248a
3 0.006903 0.004061 ... 3 b10eef89b4192178d482d7a1587a248a
4 0.006972 0.004091 ... 4 b10eef89b4192178d482d7a1587a248a
[5 rows x 8 columns]
This is nice, but with more steps added to the pipeline this can become
intransparent. To simplify building complex pipelines, Julearn provides a
PipelineCreator
which helps keeping things neat.
Pipeline specification made easy with the PipelineCreator
#
The PipelineCreator
is a class that helps the user create complex
pipelines with straightforward usage by adding, in order, the desired steps
to the pipeline. Once that the pipeline is specified, the
run_cross_validation()
will detect that it is a pipeline creator and
will automatically create the pipeline and run the cross-validation.
Note
The PipelineCreator
always has to be initialized with the
problem_type
parameter, which can be either classification
or
regression
.
Let’s re-write the previous example, using the PipelineCreator
.
We start by creating an instance of the PipelineCreator
, and
setting the problem_type
parameter to classification
.
from julearn.pipeline import PipelineCreator
creator = PipelineCreator(problem_type="classification")
Then we use the add
method to add every desired step to the pipeline.
Both, the pre-processing steps and the learning algorithm are added in the
same way.
As with the run_cross_validation()
functiona, one can use the names
of the step as indicated in Overview of available Pipeline Steps.
creator.add("zscore")
creator.add("pca")
creator.add("svm")
print(creator)
2023-07-19 12:42:39,088 - julearn - INFO - Adding step zscore that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2023-07-19 12:42:39,088 - julearn - INFO - Step added
2023-07-19 12:42:39,088 - julearn - INFO - Adding step pca that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2023-07-19 12:42:39,088 - julearn - INFO - Step added
2023-07-19 12:42:39,088 - julearn - INFO - Adding step svm that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2023-07-19 12:42:39,088 - julearn - INFO - Step added
PipelineCreator:
Step 0: zscore
estimator: StandardScaler()
apply to: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
needed types: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
tuning params: {}
Step 1: pca
estimator: PCA()
apply to: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
needed types: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
tuning params: {}
Step 2: svm
estimator: SVC()
apply to: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
needed types: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
tuning params: {}
We then pass the creator
to run_cross_validation()
as the
model
parameter. We do not need to (and cannot) specify any other
pipeline specification step (such as preprocess
)
scores = run_cross_validation(
X=X,
y=y,
data=df,
X_types=X_types,
model=creator,
)
print(scores)
2023-07-19 12:42:39,090 - julearn - INFO - ==== Input Data ====
2023-07-19 12:42:39,090 - julearn - INFO - Using dataframe as input
2023-07-19 12:42:39,090 - julearn - INFO - Features: ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
2023-07-19 12:42:39,090 - julearn - INFO - Target: species
2023-07-19 12:42:39,090 - julearn - INFO - Expanded features: ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
2023-07-19 12:42:39,090 - julearn - INFO - X_types:{'continuous': ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']}
2023-07-19 12:42:39,091 - julearn - INFO - ====================
2023-07-19 12:42:39,091 - julearn - INFO -
2023-07-19 12:42:39,091 - julearn - INFO - = Model Parameters =
2023-07-19 12:42:39,092 - julearn - INFO - ====================
2023-07-19 12:42:39,092 - julearn - INFO -
2023-07-19 12:42:39,092 - julearn - INFO - = Data Information =
2023-07-19 12:42:39,092 - julearn - INFO - Problem type: classification
2023-07-19 12:42:39,092 - julearn - INFO - Number of samples: 150
2023-07-19 12:42:39,092 - julearn - INFO - Number of features: 4
2023-07-19 12:42:39,092 - julearn - INFO - ====================
2023-07-19 12:42:39,092 - julearn - INFO -
2023-07-19 12:42:39,092 - julearn - INFO - Number of classes: 3
2023-07-19 12:42:39,092 - julearn - INFO - Target type: object
2023-07-19 12:42:39,093 - julearn - INFO - Class distributions: species
setosa 50
versicolor 50
virginica 50
Name: count, dtype: int64
2023-07-19 12:42:39,093 - julearn - INFO - Using outer CV scheme KFold(n_splits=5, random_state=None, shuffle=False)
2023-07-19 12:42:39,093 - julearn - INFO - Multi-class classification problem detected #classes = 3.
fit_time score_time ... fold cv_mdsum
0 0.007120 0.004096 ... 0 b10eef89b4192178d482d7a1587a248a
1 0.006941 0.004104 ... 1 b10eef89b4192178d482d7a1587a248a
2 0.006925 0.004131 ... 2 b10eef89b4192178d482d7a1587a248a
3 0.006929 0.004101 ... 3 b10eef89b4192178d482d7a1587a248a
4 0.006888 0.004105 ... 4 b10eef89b4192178d482d7a1587a248a
[5 rows x 8 columns]
Awesome! We covered how to create a basic machine learning pipeline and even added multiple feature pre-preprocessing steps.
Let’s jump to the next important aspect in the process of building a machine learning model: Hyperparameters. We here cover the basics of setting hyperparameters. If you want to know more about tuning (or optimizing) hyperparameters, please have a look at Hyperparameter Tuning.
Setting hyperparameters#
If you are new to machine learning, the section heading might confuse you: Parameters, hyperparameters - aren’t we doing machine learning, so shouldn’t the model learn all our parameters? Well, yes and no. Yes, it should learn parameters. However, hyperparameters and parameters are two different things.
A model parameter is a variable that is internal to the learning algorithm and we want to learn or estimate its value from the data, which in turn means that they are not set manually. They are required by the model and are often saved as part of the fitting process. Examples of model parameters are the weights in an artificial neural network, the support vectors in a support vector machine or the coefficients/weights in a linear or logistic regression.
Hyperparameters in turn, are _configuration(s)_ of a learning algorithm,
which cannot be estimated from data, but nevertheless need to be specified to
determine how the model parameters will be learnt. The best value for a
hyperparameter on a given problem is usually not known and therefore has to
be either set manually, based on experience from a previous similar problem,
set by using a heuristic (rule of thumb) or by being _tuned_. Examples are
the learning rate for training a neural network, the C
and sigma
hyperparameters for support vector machines or the number of estimators in a
random forest.
Manually specifying hyperparameters with Julearn is as simple as using the
PipelineCreator
and set the hyperparameter when the step is added.
Let’s say we want to set the with_mean
parameter of the z-score
transformer and compute PCA up to 20% of the variance explained.
This is how the creator would look like:
creator = PipelineCreator(problem_type="classification")
creator.add("zscore", with_mean=True)
creator.add("pca", n_components=0.2)
creator.add("svm")
print(creator)
2023-07-19 12:42:39,161 - julearn - INFO - Adding step zscore that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2023-07-19 12:42:39,161 - julearn - INFO - Setting hyperparameter with_mean = True
2023-07-19 12:42:39,161 - julearn - INFO - Step added
2023-07-19 12:42:39,161 - julearn - INFO - Adding step pca that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2023-07-19 12:42:39,162 - julearn - INFO - Setting hyperparameter n_components = 0.2
2023-07-19 12:42:39,162 - julearn - INFO - Step added
2023-07-19 12:42:39,162 - julearn - INFO - Adding step svm that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2023-07-19 12:42:39,162 - julearn - INFO - Step added
PipelineCreator:
Step 0: zscore
estimator: StandardScaler()
apply to: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
needed types: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
tuning params: {}
Step 1: pca
estimator: PCA(n_components=0.2)
apply to: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
needed types: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
tuning params: {}
Step 2: svm
estimator: SVC()
apply to: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
needed types: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
tuning params: {}
Usable transformers or estimators can be seen under Overview of available Pipeline Steps. The basis for most of these steps are the respective scikit-learn estimators or transformers. To see the valid hyperparameters for a certain transformer or estimator, just follow the respective link in Overview of available Pipeline Steps which will lead you to the scikit-learn documentation where you can read more about them.
In many cases one wants to specify more than one hyperparameter. This can be
done by passing each hyperparameter separated by a comma. For the svm
we
could for example specify the C
and the kernel hyperparameter like this:
creator = PipelineCreator(problem_type="classification")
creator.add("zscore", with_mean=True)
creator.add("pca", n_components=0.2)
creator.add("svm", C=0.9, kernel="linear")
print(creator)
2023-07-19 12:42:39,163 - julearn - INFO - Adding step zscore that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2023-07-19 12:42:39,163 - julearn - INFO - Setting hyperparameter with_mean = True
2023-07-19 12:42:39,163 - julearn - INFO - Step added
2023-07-19 12:42:39,163 - julearn - INFO - Adding step pca that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2023-07-19 12:42:39,163 - julearn - INFO - Setting hyperparameter n_components = 0.2
2023-07-19 12:42:39,164 - julearn - INFO - Step added
2023-07-19 12:42:39,164 - julearn - INFO - Adding step svm that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2023-07-19 12:42:39,164 - julearn - INFO - Setting hyperparameter C = 0.9
2023-07-19 12:42:39,164 - julearn - INFO - Setting hyperparameter kernel = linear
2023-07-19 12:42:39,164 - julearn - INFO - Step added
PipelineCreator:
Step 0: zscore
estimator: StandardScaler()
apply to: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
needed types: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
tuning params: {}
Step 1: pca
estimator: PCA(n_components=0.2)
apply to: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
needed types: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
tuning params: {}
Step 2: svm
estimator: SVC(C=0.9, kernel='linear')
apply to: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
needed types: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
tuning params: {}
Selective preprocessing using feature types#
Under Pipeline specification made easy with the PipelineCreator you might have wondered, how the
PipelineCreator
makes things easier. Beside the straightforward
definition of hyperparameters, the PipelineCreator
also allows to
specify if a certain step must only be applied to certain features types
(see:ref:data_usage on how to define feature types).
In out example, we can now choose to do two PCA steps, one for the petal featuers, and one for the sepal features.
First, we need to define the X_types
so we have both petal and sepal
features:
X_types = {
"sepal": ["sepal_length", "sepal_width"],
"petal": ["petal_length", "petal_width"],
}
Then, we modify the previous creator to add the pca
step to the creator
and specify that it should only be applied to the petal and sepal
features. Since we also want the zscore
applied to all features, we need
to specify this as well, indicating that we want to apply it to both
petal and sepal features:
creator = PipelineCreator(problem_type="classification")
creator.add("zscore", apply_to=["petal", "sepal"], with_mean=True)
creator.add("pca", apply_to="petal", n_components=1)
creator.add("pca", apply_to="sepal", n_components=1)
creator.add("svm")
print(creator)
2023-07-19 12:42:39,165 - julearn - INFO - Adding step zscore that applies to ColumnTypes<types={'sepal', 'petal'}; pattern=(?:__:type:__sepal|__:type:__petal)>
2023-07-19 12:42:39,165 - julearn - INFO - Setting hyperparameter with_mean = True
2023-07-19 12:42:39,166 - julearn - INFO - Step added
2023-07-19 12:42:39,166 - julearn - INFO - Adding step pca that applies to ColumnTypes<types={'petal'}; pattern=(?:__:type:__petal)>
2023-07-19 12:42:39,166 - julearn - INFO - Setting hyperparameter n_components = 1
2023-07-19 12:42:39,166 - julearn - INFO - Step added
2023-07-19 12:42:39,166 - julearn - INFO - Adding step pca_1 that applies to ColumnTypes<types={'sepal'}; pattern=(?:__:type:__sepal)>
2023-07-19 12:42:39,166 - julearn - INFO - Setting hyperparameter n_components = 1
2023-07-19 12:42:39,166 - julearn - INFO - Step added
2023-07-19 12:42:39,166 - julearn - INFO - Adding step svm that applies to ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
2023-07-19 12:42:39,166 - julearn - INFO - Step added
PipelineCreator:
Step 0: zscore
estimator: StandardScaler()
apply to: ColumnTypes<types={'sepal', 'petal'}; pattern=(?:__:type:__sepal|__:type:__petal)>
needed types: ColumnTypes<types={'sepal', 'petal'}; pattern=(?:__:type:__sepal|__:type:__petal)>
tuning params: {}
Step 1: pca
estimator: PCA(n_components=1)
apply to: ColumnTypes<types={'petal'}; pattern=(?:__:type:__petal)>
needed types: ColumnTypes<types={'petal'}; pattern=(?:__:type:__petal)>
tuning params: {}
Step 2: pca_1
estimator: PCA(n_components=1)
apply to: ColumnTypes<types={'sepal'}; pattern=(?:__:type:__sepal)>
needed types: ColumnTypes<types={'sepal'}; pattern=(?:__:type:__sepal)>
tuning params: {}
Step 3: svm
estimator: SVC()
apply to: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
needed types: ColumnTypes<types={'continuous'}; pattern=(?:__:type:__continuous)>
tuning params: {}
We here additionally had specified as a hyperparameter of the _PCA_
that we want to use only the first component. For the svm
we used
the default hyperparameters.
Finally, we again pass the defined X_types
and the creator
to
run_cross_validation()
:
scores = run_cross_validation(
X=X,
y=y,
data=df,
X_types=X_types,
model=creator,
)
print(scores)
2023-07-19 12:42:39,168 - julearn - INFO - ==== Input Data ====
2023-07-19 12:42:39,168 - julearn - INFO - Using dataframe as input
2023-07-19 12:42:39,168 - julearn - INFO - Features: ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
2023-07-19 12:42:39,168 - julearn - INFO - Target: species
2023-07-19 12:42:39,168 - julearn - INFO - Expanded features: ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
2023-07-19 12:42:39,168 - julearn - INFO - X_types:{'sepal': ['sepal_length', 'sepal_width'], 'petal': ['petal_length', 'petal_width']}
2023-07-19 12:42:39,169 - julearn - INFO - ====================
2023-07-19 12:42:39,169 - julearn - INFO -
2023-07-19 12:42:39,170 - julearn - INFO - = Model Parameters =
2023-07-19 12:42:39,170 - julearn - INFO - ====================
2023-07-19 12:42:39,171 - julearn - INFO -
2023-07-19 12:42:39,171 - julearn - INFO - = Data Information =
2023-07-19 12:42:39,171 - julearn - INFO - Problem type: classification
2023-07-19 12:42:39,171 - julearn - INFO - Number of samples: 150
2023-07-19 12:42:39,171 - julearn - INFO - Number of features: 4
2023-07-19 12:42:39,171 - julearn - INFO - ====================
2023-07-19 12:42:39,171 - julearn - INFO -
2023-07-19 12:42:39,171 - julearn - INFO - Number of classes: 3
2023-07-19 12:42:39,171 - julearn - INFO - Target type: object
2023-07-19 12:42:39,172 - julearn - INFO - Class distributions: species
setosa 50
versicolor 50
virginica 50
Name: count, dtype: int64
2023-07-19 12:42:39,172 - julearn - INFO - Using outer CV scheme KFold(n_splits=5, random_state=None, shuffle=False)
2023-07-19 12:42:39,172 - julearn - INFO - Multi-class classification problem detected #classes = 3.
fit_time score_time ... fold cv_mdsum
0 0.021548 0.009156 ... 0 b10eef89b4192178d482d7a1587a248a
1 0.021038 0.009067 ... 1 b10eef89b4192178d482d7a1587a248a
2 0.020724 0.009100 ... 2 b10eef89b4192178d482d7a1587a248a
3 0.020941 0.009109 ... 3 b10eef89b4192178d482d7a1587a248a
4 0.020757 0.009077 ... 4 b10eef89b4192178d482d7a1587a248a
[5 rows x 8 columns]
We covered how to set up basic pipelines, how to use the
PipelineCreator
, how to use the apply_to
parameter of the
PipelineCreator
and covered basics of hyperparameters. Additional,
we saw a basic use-case of target pre-processing. In the next
step we will understand the returns of run_cross_validation()
, i.e.
the model output and the scores of the performed cross-validation.
Total running time of the script: ( 0 minutes 0.435 seconds)