pythonmachine-learningscikit-learntpot

TPOT: classification fails on multi-class data


I cannot get TPot (v. 0.9.2, Python 2.7) working on multiclass data (although I could not find anything in the documentation of TPot saying it does only binary classification).

An example provided below. It runs until 9% and then drops dead with the error:

RuntimeError: There was an error in the TPOT optimization process. 
This could be because the data was not formatted properly, or because
data for a regression problem was provided to the TPOTClassifier 
object. Please make sure you passed the data to TPOT correctly.

But change n_classes to 2 and it is running okay.

from sklearn.metrics import f1_score, make_scorer
from sklearn.datasets import make_classification
from tpot import TPOTClassifier

scorer = make_scorer(f1_score)
X, y = make_classification(n_samples=200, n_features=100,
                           n_informative=20, n_redundant=10,
                           n_classes=3, random_state=42)
tpot = TPOTClassifier(generations=10, population_size=20, verbosity=20, scoring=scorer)
tpot.fit(X, y)

Solution

  • Indeed, TPOT is supposed to work with multiclass data, too - the example in the docs is with the MNIST dataset (10 classes).

    The error is related to the f1_score; keeping your code with n_classes=3, and asking for

    tpot = TPOTClassifier(generations=10, population_size=20, verbosity=2)
    

    (i.e. using the default scoring='accuracy') works OK:

    Warning: xgboost.XGBClassifier is not available and will not be used by TPOT.
    
    Generation 1 - Current best internal CV score: 0.7447422496202984                                                                                
    Generation 2 - Current best internal CV score: 0.7447422496202984                                                                                  
    Generation 3 - Current best internal CV score: 0.7454927186634503                                                                                   
    Generation 4 - Current best internal CV score: 0.7454927186634503             
    Generation 5 - Current best internal CV score: 0.7706334316090413
    Generation 6 - Current best internal CV score: 0.7706334316090413
    Generation 7 - Current best internal CV score: 0.7706334316090413
    Generation 8 - Current best internal CV score: 0.7706334316090413
    Generation 9 - Current best internal CV score: 0.7757616367372464
    Generation 10 - Current best internal CV score: 0.7808898418654516
    
    Best pipeline: 
    
    LogisticRegression(KNeighborsClassifier(DecisionTreeClassifier(input_matrix, criterion=entropy, max_depth=3, min_samples_leaf=15, min_samples_split=12), n_neighbors=6, p=2, weights=uniform), C=0.01, dual=False, penalty=l2)
    
    TPOTClassifier(config_dict={'sklearn.linear_model.LogisticRegression': {'penalty': ['l1', 'l2'], 'C': [0.0001, 0.001, 0.01, 0.1, 0.5, 1.0, 5.0, 10.0, 15.0, 20.0, 25.0], 'dual': [True, False]}, 'sklearn.decomposition.PCA': {'iterated_power': range(1, 11), 'svd_solver': ['randomized']}, 'sklearn.feature_selection.Se...ocessing.PolynomialFeatures': {'degree': [2], 'interaction_only': [False], 'include_bias': [False]}},
            crossover_rate=0.1, cv=5, disable_update_check=False,
            early_stop=None, generations=10, max_eval_time_mins=5,
            max_time_mins=None, memory=None, mutation_rate=0.9, n_jobs=1,
            offspring_size=20, periodic_checkpoint_folder=None,
            population_size=20, random_state=None, scoring=None, subsample=1.0,
            verbosity=2, warm_start=False)
    

    Asking for the F1 score with the usage suggested in the docs, i.e.:

    tpot = TPOTClassifier(generations=10, population_size=20, verbosity=2, scoring='f1')
    

    produces again the error you report, probably because the default argument in f1_score is average='binary', which indeed does not make sense for multi-class problems, and the simple f1 is only for binary problems (docs).

    Using explicitly some other variation of F1 score in scoring, e.g. f1_macro, f1_micro, or f1_weighted works OK (not shown).