decision-tree-template
Q: Which CSV or Excel file should I use for this decision tree analysis?
A: Read these files:
- https://raw.githubusercontent.com/pplonski/datasets-for-start/master/breast_cancer_wisconsin/data.csv
I’ll load the CSV and show a quick preview.
</>Load cancer dataset
import pandas as pd
url = "https://raw.githubusercontent.com/pplonski/datasets-for-start/master/breast_cancer_wisconsin/data.csv"
df = pd.read_csv(url)
print(f"Shape: {df.shape}")
columns = df.columns.tolist()
print(f"Columns ({len(columns)}):", columns if len(columns) <= 100 else columns[:100] + ["..."])
df.head()Shape: (569, 32) Columns (32): ['id', 'diagnosis', 'radius_mean', 'texture_mean', 'perimeter_mean', 'area_mean', 'smoothness_mean', 'compactness_mean', 'concavity_mean', 'concave points_mean', 'symmetry_mean', 'fractal_dimension_mean', 'radius_se', 'texture_se', 'perimeter_se', 'area_se', 'smoothness_se', 'compactness_se', 'concavity_se', 'concave points_se', 'symmetry_se', 'fractal_dimension_se', 'radius_worst', 'texture_worst', 'perimeter_worst', 'area_worst', 'smoothness_worst', 'compactness_worst', 'concavity_worst', 'concave points_worst', 'symmetry_worst', 'fractal_dimension_worst']
| id | diagnosis | radius_mean | texture_mean | perimeter_mean | area_mean | smoothness_mean | compactness_mean | concavity_mean | concave points_mean | ... | radius_worst | texture_worst | perimeter_worst | area_worst | smoothness_worst | compactness_worst | concavity_worst | concave points_worst | symmetry_worst | fractal_dimension_worst | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 842302 | M | 17.99 | 10.38 | 122.80 | 1001.0 | 0.11840 | 0.27760 | 0.3001 | 0.14710 | ... | 25.38 | 17.33 | 184.60 | 2019.0 | 0.1622 | 0.6656 | 0.7119 | 0.2654 | 0.4601 | 0.11890 |
| 1 | 842517 | M | 20.57 | 17.77 | 132.90 | 1326.0 | 0.08474 | 0.07864 | 0.0869 | 0.07017 | ... | 24.99 | 23.41 | 158.80 | 1956.0 | 0.1238 | 0.1866 | 0.2416 | 0.1860 | 0.2750 | 0.08902 |
| 2 | 84300903 | M | 19.69 | 21.25 | 130.00 | 1203.0 | 0.10960 | 0.15990 | 0.1974 | 0.12790 | ... | 23.57 | 25.53 | 152.50 | 1709.0 | 0.1444 | 0.4245 | 0.4504 | 0.2430 | 0.3613 | 0.08758 |
| 3 | 84348301 | M | 11.42 | 20.38 | 77.58 | 386.1 | 0.14250 | 0.28390 | 0.2414 | 0.10520 | ... | 14.91 | 26.50 | 98.87 | 567.7 | 0.2098 | 0.8663 | 0.6869 | 0.2575 | 0.6638 | 0.17300 |
| 4 | 84358402 | M | 20.29 | 14.34 | 135.10 | 1297.0 | 0.10030 | 0.13280 | 0.1980 | 0.10430 | ... | 22.54 | 16.67 | 152.20 | 1575.0 | 0.1374 | 0.2050 | 0.4000 | 0.1625 | 0.2364 | 0.07678 |
5 rows × 32 columns
The provided source is a CSV URL, but its schema has not been verified in the available notebook output. This checks the headers and a small sample to confirm it is suitable for decision-tree modeling.
</>Preview dataset columns
sample = pd.read_csv(url, nrows=3)
print("Columns:", sample.columns.tolist())
sampleColumns: ['id', 'diagnosis', 'radius_mean', 'texture_mean', 'perimeter_mean', 'area_mean', 'smoothness_mean', 'compactness_mean', 'concavity_mean', 'concave points_mean', 'symmetry_mean', 'fractal_dimension_mean', 'radius_se', 'texture_se', 'perimeter_se', 'area_se', 'smoothness_se', 'compactness_se', 'concavity_se', 'concave points_se', 'symmetry_se', 'fractal_dimension_se', 'radius_worst', 'texture_worst', 'perimeter_worst', 'area_worst', 'smoothness_worst', 'compactness_worst', 'concavity_worst', 'concave points_worst', 'symmetry_worst', 'fractal_dimension_worst']
| id | diagnosis | radius_mean | texture_mean | perimeter_mean | area_mean | smoothness_mean | compactness_mean | concavity_mean | concave points_mean | ... | radius_worst | texture_worst | perimeter_worst | area_worst | smoothness_worst | compactness_worst | concavity_worst | concave points_worst | symmetry_worst | fractal_dimension_worst | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 842302 | M | 17.99 | 10.38 | 122.8 | 1001 | 0.11840 | 0.27760 | 0.3001 | 0.14710 | ... | 25.38 | 17.33 | 184.6 | 2019 | 0.1622 | 0.6656 | 0.7119 | 0.2654 | 0.4601 | 0.11890 |
| 1 | 842517 | M | 20.57 | 17.77 | 132.9 | 1326 | 0.08474 | 0.07864 | 0.0869 | 0.07017 | ... | 24.99 | 23.41 | 158.8 | 1956 | 0.1238 | 0.1866 | 0.2416 | 0.1860 | 0.2750 | 0.08902 |
| 2 | 84300903 | M | 19.69 | 21.25 | 130.0 | 1203 | 0.10960 | 0.15990 | 0.1974 | 0.12790 | ... | 23.57 | 25.53 | 152.5 | 1709 | 0.1444 | 0.4245 | 0.4504 | 0.2430 | 0.3613 | 0.08758 |
3 rows × 32 columns
Use the provided breast-cancer CSV:
https://raw.githubusercontent.com/pplonski/datasets-for-start/master/breast_cancer_wisconsin/data.csv
It contains 569 records, a categorical diagnosis field (M or B) suitable as the decision-tree classification target, and 30 numeric measurement features. Exclude id from the predictors because it is an identifier rather than a meaningful clinical feature.
Train a scikit-learn decision tree from the loaded dataset.
The task is classification: diagnosis contains the malignant (M) and benign (B) labels. I will exclude id because it is an identifier, retain the 30 numeric measurements, and use a depth-3 tree.
Q: How should the decision tree be trained?
A: Use a train/test split and evaluate the model on held-out data
I’ll use a stratified 80/20 split, exclude id, impute any missing feature values using training-set medians, and fit a depth-3 classifier. The saved variables support later tree visualization.
</>Train decision tree classifier
from sklearn.model_selection import train_test_split
from sklearn.impute import SimpleImputer
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
target_col = "diagnosis"
feature_cols = [col for col in df.columns if col not in ["id", target_col]]
X = df[feature_cols]
y = df[target_col]
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.20, random_state=42, stratify=y
)
imputer = SimpleImputer(strategy="median")
X_train_imputed = imputer.fit_transform(X_train)
X_test_imputed = imputer.transform(X_test)
model = DecisionTreeClassifier(max_depth=3, random_state=42)
model.fit(X_train_imputed, y_train)
y_pred = model.predict(X_test_imputed)
test_accuracy = accuracy_score(y_test, y_pred)
target_names = model.classes_.tolist()
print(f"Training records: {len(X_train)} | Test records: {len(X_test)}")
print(f"Features used: {len(feature_cols)} (excluded: id)")
print(f"Test accuracy: {test_accuracy:.3f}")
print("\nClassification report:")
print(classification_report(y_test, y_pred, target_names=target_names))
confusion_matrix(y_test, y_pred, labels=target_names)Training records: 455 | Test records: 114
Features used: 30 (excluded: id)
Test accuracy: 0.904
Classification report:
precision recall f1-score support
B 0.89 0.97 0.93 72
M 0.94 0.79 0.86 42
accuracy 0.90 114
macro avg 0.91 0.88 0.89 114
weighted avg 0.91 0.90 0.90 114array([[70, 2],
[ 9, 33]])The depth-3 decision tree was trained using a stratified 80/20 train/test split:
- Training set: 455 records
- Held-out test set: 114 records
- Features: 30 numeric diagnostic measurements
- Excluded:
id, because it is an identifier rather than a clinical measurement - Missing values: median imputation was fit on training data and applied to test data
- Test accuracy: 90.4%
Performance by diagnosis:
- Benign (
B): 97% recall — 70 of 72 benign cases were correctly classified. - Malignant (
M): 79% recall — 33 of 42 malignant cases were correctly classified.
The confusion matrix shows 2 benign cases incorrectly predicted as malignant and 9 malignant cases incorrectly predicted as benign. The latter is the more consequential error type in this medical context, so the model is reasonably accurate overall but misses some malignant cases.
Visualize the trained decision tree with supertree.
</>Show super tree
try:
from supertree import SuperTree
except ImportError:
%pip install -q supertree
from supertree import SuperTree
super_tree = SuperTree(model, X, y, feature_cols, target_names)
super_tree.show_tree()<IPython.core.display.HTML object>
The SuperTree visualization is displayed for the trained depth-3 classifier. It represents the model fit on the 455-record training partition, using the 30 diagnostic measurements and excluding the identifier column.
Read the tree from the root downward: each node tests one measurement against a threshold, branching toward increasingly benign (B) or malignant (M) classifications. Because the tree is limited to three levels, it is intentionally interpretable: predictions rely on only a small sequence of feature thresholds rather than all 30 measurements.
On the held-out 114-record test set, this visualized model achieved 90.4% accuracy. It correctly identified 70 of 72 benign cases and 33 of 42 malignant cases; the tree’s main limitation is its 9 false-negative malignant predictions.
i want to open the tree diagram in the browser
Thinking
Exploring SuperTree functions
I need to give the code for using SuperTree effectively. It seems like SuperTree(...).save_html("tree.html") could be the right call, so I’ll check the API documentation for that. I remember that it transforms sklearn trees into an interactive format. The show_tree() method might open a browser, and I should ensure to avoid any assumptions about unknown methods. My goal is to provide direct access to the output. I’ll also think about remote notebooks and linking files properly.
Save the interactive SuperTree diagram as an HTML file and open it in a new browser tab.
</>Save and open decision tree
from pathlib import Path
from IPython.display import HTML, display
import webbrowser
tree_file = Path("decision_tree_supertree.html").resolve()
super_tree.save_html(str(tree_file))
display(HTML(f'<a href="file://{tree_file}" target="_blank">Open the interactive decision tree in a new browser tab</a>'))
webbrowser.open_new_tab(tree_file.as_uri())HTML saved to /Users/ckuruwit/decision_tree_supertree.html
True
The interactive SuperTree diagram was saved as decision_tree_supertree.html at:
/Users/ckuruwit/decision_tree_supertree.html
The notebook also returned True when requesting a new browser tab, indicating the browser-open command was successfully sent.
what is worst suffix in the var names??
_worst means the largest (worst-case) value of that measurement across the sampled cell nuclei for a patient.
For example:
radius_worst: largest cell-nucleus radius observedtexture_worst: highest texture variation observedarea_worst: largest cell-nucleus area observedconcavity_worst: greatest boundary concavity observed
In this breast-cancer dataset, each core measurement commonly has three summaries:
_mean: average value_se: standard error, representing variation/uncertainty_worst: mean of the three largest values observed for that measurement
“Worst” is a dataset-specific clinical label: it does not always mean “bad” in isolation, but larger worst-case measurements can help distinguish malignant (M) from benign (B) tumors.