Machine learning / Classification and clustering
Classification Concepts and Decision Trees
Contents
- Introduction to Classification
- Applications of Classification
- Decision Trees: A Powerful Classification Technique
- Building a Decision Tree
- K-Nearest Neighbors (KNN) Classification
- Handling Imbalanced Datasets
- Feature Selection and Importance
- Cross-Validation: Ensuring Model Reliability
- Hyperparameter Tuning
- Ensemble Methods: Random Forests
- Handling Multi-class Classification
- Real-Life Example: Sentiment Analysis
- Real-Life Example: Image Classification
- Challenges in Classification
- Additional Resources
Introduction to Classification
Classification is a fundamental task in machine learning where we predict the category of an input based on its features. It's widely used in various fields, from medicine to technology.
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
# Load iris dataset
iris = datasets.load_iris()
X, y = iris.data, iris.target
# Split the data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# Create and train a decision tree classifier
clf = DecisionTreeClassifier()
clf.fit(X_train, y_train)
# Make predictions
predictions = clf.predict(X_test)
print(f"Accuracy: {clf.score(X_test, y_test):.2f}")
Applications of Classification
Classification has numerous real-world applications. In healthcare, it's used for disease diagnosis. In environmental science, it helps categorize plant species. Let's explore an example of classifying emails as spam or not spam.
import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
# Sample data
emails = [
("Free gift waiting for you", "spam"),
("Meeting at 3pm today", "not spam"),
("Win a luxury vacation now", "spam"),
("Project report due tomorrow", "not spam")
]
# Prepare the data
X, y = zip(*emails)
df = pd.DataFrame({'email': X, 'label': y})
# Vectorize the text
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(df['email'])
# Train a Naive Bayes classifier
clf = MultinomialNB()
clf.fit(X, df['label'])
# Predict a new email
new_email = ["Claim your prize today"]
X_new = vectorizer.transform(new_email)
prediction = clf.predict(X_new)
print(f"The email '{new_email[0]}' is classified as: {prediction[0]}")
Decision Trees: A Powerful Classification Technique
Decision trees are intuitive and interpretable classification models. They make decisions by splitting data based on feature values, forming a tree-like structure.
from sklearn.tree import DecisionTreeClassifier, plot_tree
import matplotlib.pyplot as plt
# Create and train a decision tree
clf = DecisionTreeClassifier(max_depth=3, random_state=42)
clf.fit(X_train, y_train)
# Visualize the tree
plt.figure(figsize=(20,10))
plot_tree(clf, feature_names=iris.feature_names, class_names=iris.target_names, filled=True)
plt.show()
Building a Decision Tree
Let's walk through the process of building a decision tree using the Iris dataset. We'll use entropy as the criterion for splitting nodes.
from sklearn.tree import DecisionTreeClassifier
# Create a decision tree classifier
clf = DecisionTreeClassifier(criterion='entropy', random_state=42)
# Train the classifier
clf.fit(X_train, y_train)
# Print the importance of each feature
for name, importance in zip(iris.feature_names, clf.feature_importances_):
print(f"{name}: {importance:.4f}")
# Make predictions
y_pred = clf.predict(X_test)
# Print the accuracy
from sklearn.metrics import accuracy_score
print(f"Accuracy: {accuracy_score(y_test, y_pred):.4f}")
K-Nearest Neighbors (KNN) Classification
KNN is another popular classification technique. It classifies data points based on the majority class of their k nearest neighbors.
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
# Create and train a KNN classifier
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X_train, y_train)
# Make predictions
y_pred = knn.predict(X_test)
# Calculate accuracy
accuracy = accuracy_score(y_test, y_pred)
print(f"KNN Accuracy: {accuracy:.4f}")
# Visualize decision boundaries (for 2D data)
import numpy as np
import matplotlib.pyplot as plt
def plot_decision_boundaries(X, y, model, ax=None):
h = .02 # step size in the mesh
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
if ax is None:
ax = plt.gca()
ax.contourf(xx, yy, Z, alpha=0.8, cmap=plt.cm.RdYlBu)
ax.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.RdYlBu, edgecolor='black')
ax.set_xlabel('Feature 1')
ax.set_ylabel('Feature 2')
return ax
# Use only first two features for visualization
X_2d = X[:, :2]
X_train_2d, X_test_2d, y_train, y_test = train_test_split(X_2d, y, test_size=0.3, random_state=42)
knn_2d = KNeighborsClassifier(n_neighbors=3)
knn_2d.fit(X_train_2d, y_train)
plt.figure(figsize=(10, 8))
plot_decision_boundaries(X_2d, y, knn_2d)
plt.title('KNN Decision Boundaries')
plt.show()
Handling Imbalanced Datasets
In real-world scenarios, we often encounter imbalanced datasets where one class significantly outnumbers the others. Let's explore techniques to handle this challenge.
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from imblearn.over_sampling import SMOTE
# Create an imbalanced dataset
X, y = make_classification(n_samples=1000, n_classes=2, weights=[0.9, 0.1], random_state=42)
# Split the data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# Train a classifier on imbalanced data
clf_imbalanced = DecisionTreeClassifier(random_state=42)
clf_imbalanced.fit(X_train, y_train)
# Apply SMOTE to balance the dataset
smote = SMOTE(random_state=42)
X_train_balanced, y_train_balanced = smote.fit_resample(X_train, y_train)
# Train a classifier on balanced data
clf_balanced = DecisionTreeClassifier(random_state=42)
clf_balanced.fit(X_train_balanced, y_train_balanced)
# Compare results
print("Imbalanced Dataset Results:")
print(classification_report(y_test, clf_imbalanced.predict(X_test)))
print("\nBalanced Dataset Results:")
print(classification_report(y_test, clf_balanced.predict(X_test)))
Feature Selection and Importance
Feature selection is crucial for building effective classifiers. Let's explore how to select the most important features using a Random Forest classifier.
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_selection import SelectFromModel
import numpy as np
# Create a random forest classifier
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
# Get feature importances
importances = rf.feature_importances_
indices = np.argsort(importances)[::-1]
# Print feature ranking
print("Feature ranking:")
for f, idx in enumerate(indices):
print(f"{f+1}. Feature {iris.feature_names[idx]}: {importances[idx]:.4f}")
# Select features using SelectFromModel
selector = SelectFromModel(rf, prefit=True)
X_train_selected = selector.transform(X_train)
X_test_selected = selector.transform(X_test)
# Train a new classifier with selected features
clf_selected = DecisionTreeClassifier(random_state=42)
clf_selected.fit(X_train_selected, y_train)
print(f"\nAccuracy with all features: {clf.score(X_test, y_test):.4f}")
print(f"Accuracy with selected features: {clf_selected.score(X_test_selected, y_test):.4f}")
Cross-Validation: Ensuring Model Reliability
Cross-validation is a technique used to assess how well a model generalizes to unseen data. Let's implement k-fold cross-validation.
from sklearn.model_selection import cross_val_score
from sklearn.tree import DecisionTreeClassifier
# Create a decision tree classifier
clf = DecisionTreeClassifier(random_state=42)
# Perform 5-fold cross-validation
scores = cross_val_score(clf, X, y, cv=5)
print("Cross-validation scores:", scores)
print(f"Mean accuracy: {scores.mean():.4f}")
print(f"Standard deviation: {scores.std():.4f}")
# Visualize the cross-validation process
from sklearn.model_selection import KFold
import matplotlib.pyplot as plt
kf = KFold(n_splits=5, shuffle=True, random_state=42)
plt.figure(figsize=(12, 4))
for i, (train_index, val_index) in enumerate(kf.split(X)):
plt.subplot(1, 5, i+1)
plt.scatter(X[train_index, 0], X[train_index, 1], c='blue', alpha=0.6, label='Train')
plt.scatter(X[val_index, 0], X[val_index, 1], c='red', alpha=0.6, label='Validation')
plt.title(f"Fold {i+1}")
plt.legend()
plt.tight_layout()
plt.show()
Hyperparameter Tuning
Optimizing a model's hyperparameters can significantly improve its performance. Let's use GridSearchCV to find the best hyperparameters for a decision tree.
from sklearn.model_selection import GridSearchCV
# Define the parameter grid
param_grid = {
'max_depth': [3, 5, 7, 9],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 4]
}
# Create a decision tree classifier
clf = DecisionTreeClassifier(random_state=42)
# Perform grid search
grid_search = GridSearchCV(clf, param_grid, cv=5, scoring='accuracy')
grid_search.fit(X_train, y_train)
# Print the best parameters and score
print("Best parameters:", grid_search.best_params_)
print(f"Best cross-validation score: {grid_search.best_score_:.4f}")
# Evaluate on the test set
best_clf = grid_search.best_estimator_
test_score = best_clf.score(X_test, y_test)
print(f"Test set accuracy: {test_score:.4f}")
Ensemble Methods: Random Forests
Random Forests are an ensemble of decision trees, often outperforming individual trees. Let's implement a Random Forest classifier.
from sklearn.ensemble import RandomForestClassifier
# Create and train a Random Forest classifier
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
# Make predictions
y_pred = rf.predict(X_test)
# Calculate accuracy
accuracy = accuracy_score(y_test, y_pred)
print(f"Random Forest Accuracy: {accuracy:.4f}")
# Compare feature importances
importances = rf.feature_importances_
for name, importance in zip(iris.feature_names, importances):
print(f"{name}: {importance:.4f}")
# Visualize feature importances
plt.figure(figsize=(10, 6))
plt.bar(iris.feature_names, importances)
plt.title('Feature Importances in Random Forest')
plt.xlabel('Features')
plt.ylabel('Importance')
plt.show()
Handling Multi-class Classification
While we've focused on binary classification, many real-world problems involve multiple classes. Let's explore multi-class classification using the Iris dataset.
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import SVC
from sklearn.preprocessing import label_binarize
from sklearn.metrics import roc_curve, auc
import numpy as np
import matplotlib.pyplot as plt
# Binarize the output
y_bin = label_binarize(y, classes=[0, 1, 2])
n_classes = y_bin.shape[1]
# Split the data
X_train, X_test, y_train, y_test = train_test_split(X, y_bin, test_size=0.3, random_state=42)
# Create and train the multi-class classifier
clf = OneVsRestClassifier(SVC(kernel='linear', probability=True, random_state=42))
clf.fit(X_train, y_train)
# Compute ROC curve and ROC area for each class
y_score = clf.decision_function(X_test)
fpr = dict()
tpr = dict()
roc_auc = dict()
for i in range(n_classes):
fpr[i], tpr[i], _ = roc_curve(y_test[:, i], y_score[:, i])
roc_auc[i] = auc(fpr[i], tpr[i])
# Plot ROC curves
plt.figure(figsize=(10, 8))
colors = ['blue', 'red', 'green']
for i, color in zip(range(n_classes), colors):
plt.plot(fpr[i], tpr[i], color=color, lw=2,
label=f'ROC curve of class {i} (area = {roc_auc[i]:.2f})')
plt.plot([0, 1], [0, 1], 'k--', lw=2)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Multi-class ROC')
plt.legend(loc="lower right")
plt.show()
Real-Life Example: Sentiment Analysis
Let's apply classification to sentiment analysis of product reviews using a bag-of-words model with a Naive Bayes classifier.
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
# Sample dataset
reviews = [
("This product is amazing!", "positive"),
("Worst purchase ever.", "negative"),
("Decent quality for the price.", "neutral"),
("I love it!", "positive"),
("Don't waste your money.", "negative"),
("It's okay, nothing special.", "neutral")
]
# Prepare the data
texts, labels = zip(*reviews)
# Split the data
X_train, X_test, y_train, y_test = train_test_split(texts, labels, test_size=0.3, random_state=42)
# Vectorize the text
vectorizer = CountVectorizer()
X_train_vec = vectorizer.fit_transform(X_train)
X_test_vec = vectorizer.transform(X_test)
# Train the classifier
clf = MultinomialNB()
clf.fit(X_train_vec, y_train)
# Make predictions
y_pred = clf.predict(X_test_vec)
# Print the classification report
print(classification_report(y_test, y_pred))
# Test with a new review
new_review = ["This product exceeded my expectations!"]
new_review_vec = vectorizer.transform(new_review)
prediction = clf.predict(new_review_vec)
print(f"The sentiment of '{new_review[0]}' is predicted as: {prediction[0]}")
Real-Life Example: Image Classification
Image classification is a common application of machine learning. Let's use a simple Convolutional Neural Network (CNN) to classify handwritten digits from the MNIST dataset.
import tensorflow as tf
from tensorflow.keras import layers, models
from tensorflow.keras.datasets import mnist
import matplotlib.pyplot as plt
# Load and preprocess the MNIST dataset
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
train_images = train_images.reshape((60000, 28, 28, 1)).astype('float32') / 255
test_images = test_images.reshape((10000, 28, 28, 1)).astype('float32') / 255
# Build the CNN model
model = models.Sequential([
layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
layers.MaxPooling2D((2, 2)),
layers.Conv2D(64, (3, 3), activation='relu'),
layers.MaxPooling2D((2, 2)),
layers.Conv2D(64, (3, 3), activation='relu'),
layers.Flatten(),
layers.Dense(64, activation='relu'),
layers.Dense(10, activation='softmax')
])
# Compile and train the model
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
history = model.fit(train_images, train_labels, epochs=5, validation_split=0.2)
# Evaluate the model
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
print(f'\nTest accuracy: {test_acc:.4f}')
# Plot training history
plt.plot(history.history['accuracy'], label='accuracy')
plt.plot(history.history['val_accuracy'], label='val_accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
plt.show()
# Make predictions on a few test images
predictions = model.predict(test_images[:5])
for i in range(5):
plt.imshow(test_images[i].reshape(28, 28), cmap='gray')
plt.title(f'Predicted: {predictions[i].argmax()}, Actual: {test_labels[i]}')
plt.show()
Challenges in Classification
Classification faces several challenges, including:
- Overfitting: Models may perform well on training data but poorly on unseen data.
- Class Imbalance: When one class significantly outnumbers others, leading to biased models.
- Feature Selection: Choosing the most relevant features to improve model performance.
- Scalability: Handling large datasets and high-dimensional feature spaces efficiently.
To address these challenges, we can use techniques like:
# Pseudocode for addressing classification challenges
# 1. Overfitting: Use regularization and cross-validation
model = DecisionTreeClassifier(max_depth=3, min_samples_split=5)
scores = cross_val_score(model, X, y, cv=5)
# 2. Class Imbalance: Apply SMOTE (Synthetic Minority Over-sampling Technique)
from imblearn.over_sampling import SMOTE
X_resampled, y_resampled = SMOTE().fit_resample(X, y)
# 3. Feature Selection: Use SelectKBest
from sklearn.feature_selection import SelectKBest, f_classif
selector = SelectKBest(f_classif, k=10)
X_selected = selector.fit_transform(X, y)
# 4. Scalability: Use algorithms that handle large datasets efficiently
from sklearn.naive_bayes import MultinomialNB
model = MultinomialNB()
model.partial_fit(X_batch, y_batch, classes=np.unique(y))
Additional Resources
For further exploration of classification techniques and machine learning:
- scikit-learn Documentation: Comprehensive guide to machine learning in Python. https://scikit-learn.org/stable/documentation.html
- "Introduction to Statistical Learning" by James, Witten, Hastie, and Tibshirani: Excellent resource for understanding statistical learning methods. https://www.statlearning.com/
- Kaggle Competitions: Practice classification on real-world datasets. https://www.kaggle.com/competitions
- ArXiv Machine Learning papers: Latest research in classification and machine learning. https://arxiv.org/list/stat.ML/recent
These resources provide a wealth of information to deepen your understanding of classification techniques and their applications in various domains.