Written and maintained by CASRAI Editorial Board
Last updated
Short answer: in scikit-learn, a decision tree classifier is the class DecisionTreeClassifier in the sklearn.tree module. You create it, call fit(X, y) on a numeric feature matrix and class labels, then call predict or score. This guide follows the scikit-learn 1.9.1 documentation (read 2026-11-08) and covers the settings that matter for research work: depth limits, cost-complexity pruning, missing values, categorical features and reporting.
Who this is for: researchers and analysts working in Python who need to fit a classification tree, read its rules, control overfitting and report the model reproducibly.
What DecisionTreeClassifier is used for in research
The scikit-learn User Guide describes decision trees as a non-parametric supervised learning method that learns simple if-then decision rules from the data, giving a piecewise-constant prediction. The same page lists the practical reasons researchers use them: they are simple to interpret and visualize, need little data preparation, have a prediction cost logarithmic in the number of training points, handle multi-output problems and are a white-box model whose rules can be read directly.
The same page also lists the limitations you should state in a methods section: trees can overfit and create over-complex trees, small changes in data can produce a very different tree, predictions are not smooth and extrapolate poorly, and the learning algorithm is greedy, so it does not guarantee a globally optimal tree. Trees can also be biased toward dominant classes, so the guide recommends balancing the data set (or using sample weights) before fitting.
The names sklearn decision tree, decision tree sklearn, decision trees sklearn, sklearn decision tree classifier, decision tree classifier sklearn and sklearn DecisionTreeClassifier all refer to this one class. For a numeric outcome the matching class is DecisionTreeRegressor.
Install or access
scikit-learn is free, open-source software installed from the official installation page (scikit-learn installation instructions, read 2026-11-08). The documented routes are:
- pip:
pip install -U scikit-learn - conda:
conda create -n sklearn-env -c conda-forge scikit-learn, thenconda activate sklearn-env - An isolated virtual environment first:
python -m venv sklearn-env, activated withsklearn-envScriptsactivateon Windows orsource sklearn-env/bin/activateon macOS and Linux, then the pip command above.
Record the installed version (import sklearn; print(sklearn.__version__)) in your methods notes, because defaults and features differ between releases.
Step by step: fit, predict and score a decision tree
- Prepare a numeric feature matrix. scikit-learn’s tree implementation does not support categorical variables natively, so encode them numerically (for example one-hot or ordinal encoding) before fitting. Trees use
np.float32internally; sparse input should becsc_matrixfor fitting andcsr_matrixfor prediction. - Split the data. Hold out a test set so the reported score is not computed on training rows. See train-test split in Python.
- Create the classifier with a fixed seed.
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
clf = DecisionTreeClassifier(max_depth=3, random_state=0)
clf.fit(X_train, y_train)
print(clf.predict(X_test[:5]))
print(clf.score(X_test, y_test))
- Predict and score.
predictreturns class labels,predict_probareturns class probabilities andscorereturns mean accuracy on the data you give it. - Cross-validate. The official class page example uses
DecisionTreeClassifier(random_state=0)andcross_val_score(clf, iris.data, iris.target, cv=10)on the iris data. See cross-validation in statistics for the logic of repeated resampling.
The User Guide’s own tips: start with max_depth=3 and increase it, because the number of samples needed to populate the tree roughly doubles for each added level, and try min_samples_leaf=5 as an initial value. Use min_weight_fraction_leaf instead of min_samples_split when you pass sample weights, since min_samples_split ignores them.
Key parameters of DecisionTreeClassifier
All parameters are keyword-only in the 1.9.1 signature. The defaults below are as listed on the official class page.
| Parameter | Default | What it does (per the documentation) |
|---|---|---|
criterion |
'gini' |
Split-quality measure: 'gini', 'entropy' or 'log_loss'. |
splitter |
'best' |
Strategy used to choose the split at each node. |
max_depth |
None |
With None, nodes expand until leaves are pure or contain fewer than min_samples_split samples. |
min_samples_split |
2 |
Minimum samples required to split an internal node. |
min_samples_leaf |
1 |
Minimum samples required at a leaf node. |
min_weight_fraction_leaf |
0.0 |
Minimum weighted fraction of the input sample weights required at a leaf. |
max_features |
None |
Number of features considered when looking for the best split. |
random_state |
None |
Features are randomly permuted at each split even with splitter='best'; set an integer for a deterministic fit. |
max_leaf_nodes |
None |
Grow the tree best-first up to this number of leaves. |
min_impurity_decrease |
0.0 |
A split happens only if it decreases impurity by at least this amount. |
class_weight |
None |
A dictionary, or 'balanced' to weight classes inversely to their frequencies. |
ccp_alpha |
0.0 |
Complexity parameter for Minimal Cost-Complexity Pruning; 0.0 means no pruning. |
monotonic_cst |
None |
Optional monotonicity constraints on features. |
Output and how to read it
Print the rules with export_text
The text rules are usually the clearest thing to put in a supplement:
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier, export_text
iris = load_iris()
decision_tree = DecisionTreeClassifier(random_state=0, max_depth=2)
decision_tree = decision_tree.fit(iris.data, iris.target)
print(export_text(decision_tree, feature_names=iris['feature_names']))
The User Guide shows this output for the iris data:
|--- petal width (cm) <= 0.80
| |--- class: 0
|--- petal width (cm) > 0.80
| |--- petal width (cm) <= 1.75
| | |--- class: 1
| |--- petal width (cm) > 1.75
| | |--- class: 2
Read it top to bottom: each indented line is a split condition, and a line that ends in class: n is a leaf that predicts class n.
Draw the tree
from sklearn import tree then tree.plot_tree(clf) draws the fitted tree with matplotlib. export_graphviz writes a Graphviz file and needs both the Graphviz binaries and the graphviz Python package; it accepts feature_names, class_names, filled, rounded and special_characters.
Other fitted attributes and methods
feature_importances_: array of shape (n_features,), one importance per input feature.classes_,n_classes_,n_features_in_, andfeature_names_in_(defined only when all feature names inXare strings).get_depth()andget_n_leaves(): report the size of the fitted tree.applyanddecision_path: return the leaf reached and the nodes traversed for each sample.
For classification quality beyond accuracy, see the scikit-learn confusion matrix.
Pruning and overfitting
With the default max_depth=None the tree keeps growing until its leaves are pure, which is the usual route to overfitting. The User Guide names three controls: limit depth, raise min_samples_leaf, or prune. Minimal Cost-Complexity Pruning minimizes Rα(T) = R(T) + α|T̃|, where |T̃| is the number of terminal nodes; the weakest link (smallest effective α) is pruned first, and a larger ccp_alpha gives a smaller tree. The documentation attributes the method to Breiman et al., Classification and Regression Trees (1984), chapter 3.
path = clf.cost_complexity_pruning_path(X_train, y_train)
alphas = path.ccp_alphas # candidate ccp_alpha values
impurities = path.impurities
Refit one tree per candidate ccp_alpha and choose the value by cross-validation on the training data, not on the test set.
Missing values and categorical features
Per the User Guide, DecisionTreeClassifier with splitter='best' supports missing values (NaN): at each candidate threshold it tries sending the missing samples all left or all right, and at prediction time a sample follows the direction learned in training; if no missing values were seen during training for a feature, they go to the child with the most samples. The documented example fits X = [nan, -1, nan, 1] (reshaped to one column) with y = [0, 0, 1, 1] and max_depth=1, and predict([[nan]]) returns array([1]).
Categorical features are the opposite case: the implementation does not support them directly, so encode them as numbers before fitting.
Troubleshooting
- Training accuracy is near perfect but test accuracy is low. The tree is overgrown. Set
max_depth, raisemin_samples_leaf, or useccp_alpha. - The tree changes between runs. Features are permuted at random at each split. Set
random_stateto an integer. - An error when fitting columns of text labels. Categorical strings are not supported; encode them numerically first.
- Rare classes are never predicted. Trees favour dominant classes. Balance the data, pass sample weights, or set
class_weight='balanced'. - Poor results with many features and few samples. The User Guide notes this ratio overfits; consider dimensionality reduction (PCA, ICA) or feature selection first.
- Scripts copied from older tutorials fail on imports. Use the import paths shown on the current official pages (
from sklearn.tree import ...). - Trees cannot learn some concepts compactly. The User Guide lists XOR, parity and multiplexer problems as hard for trees.
Reporting checklist for a methods section
- scikit-learn and Python versions.
- Every non-default parameter, plus
random_state. - How categorical variables were encoded and how missing values were handled.
- How the split or cross-validation folds were made, and the metric used.
- Tree size from
get_depth()andget_n_leaves(), and the pruning value if used.
Free alternatives
| Option | What it is | See |
|---|---|---|
DecisionTreeRegressor (scikit-learn) |
The same tree algorithm for a continuous outcome. | User Guide: Decision Trees |
| Random forests in R | An ensemble of many trees, in R rather than Python. | Random forests in R |
| XGBoost | Gradient-boosted trees. | What is XGBoost |
| Logistic regression (scikit-learn) | A linear classifier when a readable coefficient table suits the question better than rules. | scikit-learn logistic regression |
FAQ
How do I use a decision tree in sklearn?
Import DecisionTreeClassifier from sklearn.tree, create it with a random_state, call fit(X_train, y_train) on numeric data, then predict or score on held-out data.
What is the difference between DecisionTreeClassifier and DecisionTreeRegressor?
The classifier predicts class labels; the regressor predicts a continuous value. Both are in sklearn.tree.
Does sklearn’s decision tree handle categorical variables?
No, not natively. Encode categories numerically before fitting.
Does it handle missing values?
Yes, DecisionTreeClassifier with splitter='best' supports NaN, as described above.
How do I stop a decision tree overfitting?
Limit max_depth, raise min_samples_leaf, or prune with ccp_alpha, and check the choice by cross-validation.
Which criterion should I use?
The class accepts 'gini' (default), 'entropy' and 'log_loss'; treat the choice as a tunable setting and compare by cross-validation.
Sources
- scikit-learn documentation, sklearn.tree.DecisionTreeClassifier (version 1.9.1), read 2026-11-08.
- scikit-learn User Guide, Decision Trees, read 2026-11-08.
- scikit-learn, Installing scikit-learn, read 2026-11-08.







