xbe.at

Machine learning / Feature engineering and preprocessing

Feature Scaling for Improved Machine Learning Model Performance

9 min read, 15 sections

Contents
  1. Feature Scaling: Enhancing Model Performance
  2. Why Feature Scaling Matters
  3. Min-Max Scaling
  4. Implementing Min-Max Scaling
  5. Standardization (Z-score Normalization)
  6. Implementing Standardization
  7. Robust Scaling
  8. Impact of Scaling on Model Performance
  9. Scaling for Neural Networks
  10. Handling Mixed Data Types
  11. Real-Life Example: Image Classification
  12. Real-Life Example: Recommendation Systems
  13. Potential Pitfalls and Considerations
  14. Conclusion and Best Practices
  15. Additional Resources

Feature Scaling: Enhancing Model Performance

Feature scaling is a crucial preprocessing step in machine learning that transforms the features of a dataset to a common scale. This process can significantly improve the performance and convergence of many machine learning algorithms, especially those sensitive to the magnitude of input features.

import numpy as np
import matplotlib.pyplot as plt

# Generate sample data
np.random.seed(42)
feature1 = np.random.uniform(0, 100, 100)
feature2 = np.random.uniform(0, 1, 100)

# Plot original data
plt.figure(figsize=(10, 5))
plt.subplot(121)
plt.scatter(feature1, feature2)
plt.title("Original Data")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")

# Plot will show the significant difference in scale between features
plt.show()

Why Feature Scaling Matters

Feature scaling ensures that all features contribute equally to the model's learning process. Without scaling, features with larger magnitudes might dominate the learning process, leading to biased or suboptimal model performance. Scaling is particularly important for algorithms that rely on distances between data points, such as k-nearest neighbors, or those that use gradient descent optimization.

from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# Generate sample data
X = np.column_stack((feature1, feature2))
y = (feature1 + feature2 > 50).astype(int)

# Split data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Train KNN without scaling
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X_train, y_train)
y_pred = knn.predict(X_test)
print(f"Accuracy without scaling: {accuracy_score(y_test, y_pred):.2f}")

# The accuracy might be suboptimal due to the difference in feature scales

Min-Max Scaling

Min-Max scaling, also known as normalization, scales features to a fixed range, typically between 0 and 1. This method preserves zero values and maintains the relative distances between data points.

from sklearn.preprocessing import MinMaxScaler

# Apply Min-Max scaling
scaler = MinMaxScaler()
X_scaled = scaler.fit_transform(X)

# Plot scaled data
plt.figure(figsize=(10, 5))
plt.scatter(X_scaled[:, 0], X_scaled[:, 1])
plt.title("Min-Max Scaled Data")
plt.xlabel("Scaled Feature 1")
plt.ylabel("Scaled Feature 2")
plt.show()

# Both features now range from 0 to 1

Implementing Min-Max Scaling

Let's implement Min-Max scaling from scratch to understand its inner workings. This method scales features to a given range by subtracting the minimum value and dividing by the range of the feature.

def min_max_scale(X, feature_range=(0, 1)):
    X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))
    X_scaled = X_std * (feature_range[1] - feature_range[0]) + feature_range[0]
    return X_scaled

# Apply custom Min-Max scaling
X_custom_scaled = min_max_scale(X)

# Compare with sklearn's implementation
np.allclose(X_scaled, X_custom_scaled)  # Should return True

# The custom implementation produces the same results as sklearn's MinMaxScaler

Standardization (Z-score Normalization)

Standardization scales features to have zero mean and unit variance. This method is less affected by outliers compared to Min-Max scaling and is often preferred when the data follows a Gaussian distribution.

from sklearn.preprocessing import StandardScaler

# Apply standardization
scaler = StandardScaler()
X_standardized = scaler.fit_transform(X)

# Plot standardized data
plt.figure(figsize=(10, 5))
plt.scatter(X_standardized[:, 0], X_standardized[:, 1])
plt.title("Standardized Data")
plt.xlabel("Standardized Feature 1")
plt.ylabel("Standardized Feature 2")
plt.show()

# Features now have mean 0 and standard deviation 1
print(f"Mean: {X_standardized.mean(axis=0)}")
print(f"Standard deviation: {X_standardized.std(axis=0)}")

Implementing Standardization

Let's implement standardization from scratch to understand its computation. This method subtracts the mean and divides by the standard deviation for each feature.

def standardize(X):
    mean = X.mean(axis=0)
    std = X.std(axis=0)
    return (X - mean) / std

# Apply custom standardization
X_custom_standardized = standardize(X)

# Compare with sklearn's implementation
np.allclose(X_standardized, X_custom_standardized)  # Should return True

# The custom implementation produces the same results as sklearn's StandardScaler

Robust Scaling

Robust scaling is less affected by outliers as it uses the median and interquartile range instead of mean and standard deviation. This method is particularly useful when dealing with datasets containing outliers.

from sklearn.preprocessing import RobustScaler

# Apply robust scaling
scaler = RobustScaler()
X_robust = scaler.fit_transform(X)

# Plot robustly scaled data
plt.figure(figsize=(10, 5))
plt.scatter(X_robust[:, 0], X_robust[:, 1])
plt.title("Robustly Scaled Data")
plt.xlabel("Robustly Scaled Feature 1")
plt.ylabel("Robustly Scaled Feature 2")
plt.show()

# Features are scaled based on the median and interquartile range

Impact of Scaling on Model Performance

Let's compare the performance of a K-Nearest Neighbors classifier with and without feature scaling to demonstrate the impact of scaling on model performance.

from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import cross_val_score

# Function to evaluate model performance
def evaluate_model(X, y, scaler=None):
    if scaler:
        X = scaler.fit_transform(X)
    knn = KNeighborsClassifier(n_neighbors=3)
    scores = cross_val_score(knn, X, y, cv=5)
    return scores.mean()

# Evaluate without scaling
score_unscaled = evaluate_model(X, y)

# Evaluate with different scaling methods
score_minmax = evaluate_model(X, y, MinMaxScaler())
score_standard = evaluate_model(X, y, StandardScaler())
score_robust = evaluate_model(X, y, RobustScaler())

print(f"Unscaled: {score_unscaled:.3f}")
print(f"Min-Max Scaled: {score_minmax:.3f}")
print(f"Standardized: {score_standard:.3f}")
print(f"Robustly Scaled: {score_robust:.3f}")

# Results show improved performance with scaling

Scaling for Neural Networks

Neural networks often benefit from feature scaling as it helps in faster convergence during training. Let's compare the training of a simple neural network with and without feature scaling.

from sklearn.neural_network import MLPClassifier
from sklearn.model_selection import train_test_split

# Split the data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Train without scaling
mlp_unscaled = MLPClassifier(hidden_layer_sizes=(10,), max_iter=1000, random_state=42)
mlp_unscaled.fit(X_train, y_train)

# Train with scaling
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
mlp_scaled = MLPClassifier(hidden_layer_sizes=(10,), max_iter=1000, random_state=42)
mlp_scaled.fit(X_train_scaled, y_train)

print(f"Unscaled accuracy: {mlp_unscaled.score(X_test, y_test):.3f}")
print(f"Scaled accuracy: {mlp_scaled.score(X_test_scaled, y_test):.3f}")
print(f"Unscaled iterations: {mlp_unscaled.n_iter_}")
print(f"Scaled iterations: {mlp_scaled.n_iter_}")

# Scaling typically leads to faster convergence and potentially better performance

Handling Mixed Data Types

In real-world scenarios, datasets often contain a mix of numerical and categorical features. Let's explore how to handle such mixed data types when applying feature scaling.

import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder

# Create a sample dataset with mixed types
data = pd.DataFrame({
    'age': np.random.randint(18, 80, 100),
    'income': np.random.randint(20000, 200000, 100),
    'gender': np.random.choice(['M', 'F'], 100),
    'education': np.random.choice(['HS', 'BS', 'MS', 'PhD'], 100)
})

# Define the preprocessing steps
numeric_features = ['age', 'income']
categorical_features = ['gender', 'education']

preprocessor = ColumnTransformer(
    transformers=[
        ('num', StandardScaler(), numeric_features),
        ('cat', OneHotEncoder(drop='first'), categorical_features)
    ])

# Fit and transform the data
X_preprocessed = preprocessor.fit_transform(data)

print("Preprocessed data shape:", X_preprocessed.shape)
# The shape reflects scaled numeric features and one-hot encoded categorical features

Real-Life Example: Image Classification

In image classification tasks, feature scaling is crucial for normalizing pixel values. Let's demonstrate this using a simple example with the MNIST dataset.

from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC

# Load the digits dataset
digits = load_digits()
X, y = digits.data, digits.target

# Split the data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Train SVM without scaling
svm_unscaled = SVC(random_state=42)
svm_unscaled.fit(X_train, y_train)
print(f"Unscaled accuracy: {svm_unscaled.score(X_test, y_test):.3f}")

# Apply scaling
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# Train SVM with scaling
svm_scaled = SVC(random_state=42)
svm_scaled.fit(X_train_scaled, y_train)
print(f"Scaled accuracy: {svm_scaled.score(X_test_scaled, y_test):.3f}")

# Scaling typically improves the performance of SVMs in image classification tasks

Real-Life Example: Recommendation Systems

In recommendation systems, feature scaling can help normalize user-item interaction data. Let's simulate a simple movie rating system to demonstrate this concept.

import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics.pairwise import cosine_similarity

# Simulate user-movie rating data
users = ['User1', 'User2', 'User3', 'User4']
movies = ['Movie1', 'Movie2', 'Movie3', 'Movie4', 'Movie5']
ratings = np.random.randint(1, 6, size=(len(users), len(movies)))
df = pd.DataFrame(ratings, index=users, columns=movies)

# Calculate user similarity without scaling
similarity_unscaled = cosine_similarity(df)

# Apply Min-Max scaling
scaler = MinMaxScaler()
df_scaled = pd.DataFrame(scaler.fit_transform(df), index=df.index, columns=df.columns)

# Calculate user similarity with scaling
similarity_scaled = cosine_similarity(df_scaled)

print("Unscaled similarity matrix:")
print(similarity_unscaled)
print("\nScaled similarity matrix:")
print(similarity_scaled)

# Scaling can affect the similarity scores, potentially leading to different recommendations

Potential Pitfalls and Considerations

While feature scaling is generally beneficial, there are scenarios where it might not be necessary or could potentially be harmful. Understanding these cases is crucial for effective application of scaling techniques.

import numpy as np
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score

# Generate sample data
np.random.seed(42)
X = np.random.randn(1000, 2)
y = (X[:, 0] + X[:, 1] > 0).astype(int)

# Evaluate decision tree performance without scaling
dt = DecisionTreeClassifier(random_state=42)
scores_unscaled = cross_val_score(dt, X, y, cv=5)

# Apply scaling
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# Evaluate decision tree performance with scaling
scores_scaled = cross_val_score(dt, X_scaled, y, cv=5)

print(f"Unscaled accuracy: {scores_unscaled.mean():.3f} +/- {scores_unscaled.std():.3f}")
print(f"Scaled accuracy: {scores_scaled.mean():.3f} +/- {scores_scaled.std():.3f}")

# Decision trees are typically invariant to feature scaling
# The results should be similar for both scaled and unscaled data

Conclusion and Best Practices

Feature scaling is a powerful technique for improving model performance, but it should be applied thoughtfully. Here are some key takeaways and best practices:

  1. Always scale features for distance-based algorithms and neural networks.
  2. Apply scaling after splitting your data into training and test sets to prevent data leakage.
  3. Choose the appropriate scaling method based on your data characteristics and the algorithm you're using.
  4. Be cautious when applying scaling to tree-based models, as they are generally invariant to monotonic transformations.
  5. Remember to apply the same scaling to new data during prediction.
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression

# Generate sample data
X, y = np.random.randn(1000, 5), np.random.randint(0, 2, 1000)

# Split the data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Create a pipeline with scaling and model
pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('model', LogisticRegression())
])

# Fit the pipeline
pipeline.fit(X_train, y_train)

# Evaluate the model
print(f"Model accuracy: {pipeline.score(X_test, y_test):.3f}")

# The pipeline ensures that scaling is applied consistently to both training and test data

Additional Resources

For those interested in diving deeper into feature scaling and preprocessing techniques, here are some valuable resources:

  1. "A Comparative Study of Efficient Initialization Methods for the K-Means Clustering Algorithm" by Celebi et al. (2013) ArXiv: https://arxiv.org/abs/1209.1960
  2. "Feature Scaling in Support Vector Data Description" by Xiao et al. (2014) ArXiv: https://arxiv.org/abs/1412.4572
  3. "Understanding the Difficulty of Training Deep Feedforward Neural Networks" by Glorot and Bengio (2010) ArXiv: https://arxiv.org/abs/1003.4406

These papers provide in-depth analyses of feature scaling's impact on various machine learning algorithms and offer insights into best practices for data preprocessing.

For practical implementations and tutorials, the scikit-learn documentation on preprocessing techniques is an excellent resource: https://scikit-learn.org/stable/modules/preprocessing.html

Remember that while these resources offer valuable insights, the effectiveness of feature scaling can vary depending on your specific dataset and chosen algorithm. Always validate the impact of scaling through cross-validation and testing on your particular problem.

More in Feature engineering and preprocessing

  1. Feature Scaling Methods in Machine Learning7 min

    Feature scaling is a crucial preprocessing step in machine learning that transforms numerical features to a similar scale, improving model performance and...

  2. Feature Engineering Techniques for Data Science8 min

    Feature engineering is the process of transforming raw data into meaningful features that enhance machine learning model performance. It involves selecting...

  3. Feature selection preprocessing8 min

    Feature selection is a crucial preprocessing step in machine learning. It involves choosing the most relevant features from a dataset to improve model...

  4. Feature Engineering for Machine Learning using python4 min

    Feature engineering is the process of transforming raw data into features that better represent the underlying problem to the predictive models, resulting in...

  5. Feature Selection Using Information Gain and Mutual Information in Python7 min

    Feature selection is a crucial step in machine learning that helps identify the most relevant features for a given task. Information Gain and Mutual...

  6. Feature Engineering for Machine Learning in Python11 min

    Feature engineering is a crucial process in machine learning that involves transforming raw data into meaningful features that can improve model performance....