I am trying to put a FeatureUnion of a PCA, IncrementalPCA and FastICA into a pipeline with a RandomForestClassifier and searching the optimal parameters of the forest with a HalvingGridSearchCV.
Excerpts from the code look like this:
for n_components in range(20,80,10):
# all decomposers use the same parameters
decomposer_pars = {
'n_components':n_components,
'whiten':True,
}
# define the list of decomposers
pipe_preprocessing = [
('pca',PCA(**decomposer_pars)),
('fastica',FastICA(**decomposer_pars)),
('incpca',IncrementalPCA(**decomposer_pars))
]
# define clf
clf = RandomForestClassifier(n_estimators=50,...)
# model
pipe_model = Pipeline(steps=[
('rf', clf)
])
# join to parallel feature union
pipe_preprocessing = FeatureUnion(pipe_preprocessing)
# full pipeline preprocessing + model
pipe = Pipeline(steps=[('preprocessing',pipe_preprocessing),*pipe_model.steps])
# halving gridsearch with crossvalidation
sh = HalvingGridSearchCV(estimator = pipe,
param_grid = {
'rf__min_weight_fraction_leaf' : [0,0.001,0.01,0.1],
'rf__min_samples_split' : [0.001,0.01,0.1],
'rf__max_features' : [3,5],
'rf__min_impurity_decrease' : [0,0.001,0.01],
},
cv = cv, # NOTE: see description below
factor = 2,
scoring = make_scorer(accuracy_score),
resource = 'n_samples',
min_resources = 375,
max_resources = 3000,
aggressive_elimination = False,
refit = False,
return_train_score = False,
n_jobs = n_jobs,
verbose = 0,
error_score='raise')
res = sh.fit(X_train.values,y_train.reindex(X_train.index).values)
Notes:
- The generator cv is custom written an generates training / validation folds of size 2794 / 279, respectively. The generator should result in
n_splits=24folds. - The overall training matrix X_train has a shape (69844, 80).
- The classifier clf is simply an instance of RandomForestClassifier with n_estimators=50.
Execution of this code throws this error:
ValueError: n_components=20 must be between 0 and min(n_samples, n_features)=15 with svd_solver='full'
It's clear that the PCA components need not be larger than either the number of features or the number of samples. What I don't understand is why I get this error. The training fold that I feed in are of shape (2794,80), thus the error above should only occur for n_components>=min(n_samples, n_features)=80. I do not understand why the data is interpreted as having min(n_samples, n_features)=15. When I set n_components<15, the code works.
I don't understand what I am doing wrong here. In my understanding, FeatureUnion applies the three decomposers independently to the input training data, and should (internally) return a part of the feature matrix with shape=(n_components,2794). Thus, the transformed feature matrix would be (3*n_components,2794) and subsequent fitting of the clf should work fine.
- I tried increasing the size of the validation folds (although this does not make sense in theory). Did not change anything.
- Also, I increased the size of the train folds to
9978. Still the same error.
HOWEVER, increasing min_resources in HalvingGridSearchCV to 1000 does resolve the issue and the code runs up to n_components=40. Then, again, the same error.
Obviously, min_resources is limiting n_samples. But, the smallest value possible in my code above is 375, which would still result in folds of shape (375,80), such that the error should not occur for any value of n_components that I scan over.
Thus, min_resources seems to work differently than in my understanding. How does min_resources excatly affect the size of the internal training folds?
Thank you!
EDIT
I manually performed the transformation with the FeatureUnion with all values of n_components, and it works fine. This speaks for the fact that the problem must be caused by min_resources in HalvingGridSearchCV. Still did not find a solution for that.