Bird
Raised Fist0

Implement Feature Scaling - Standardization, Min-Max, Robust

CODINGbeginnerInterview freq: high
Choose your preparation mode6 modes available
🤖
Implement Feature Scaling - Standardization, Min-Max, Robust
Master feature scaling techniques to prepare data for ML models.
codingbeginnerFreq: highEvaluation Coding
Prerequisites:Feature Scaling - Normalization vs Standardization
📝
Problem Statement

Implement feature scaling methods: Standardization, Min-Max scaling, and Robust scaling. Given a 2D NumPy array X, return the scaled version of X using each method.

Input: 2D NumPy array X of shape (n_samples, n_features). Output: 2D NumPy array of the same shape, scaled according to the specified method.
Input: X = np.array([[1, 2], [3, 4], [5, 6]]), method='standardization' → Output: np.array([[-1.2247, -1.2247], [0, 0], [1.2247, 1.2247]])
🎯
Interview Angles
  • Testing understanding of feature scaling techniques and their differences.
  • Evaluating ability to implement vectorized operations using NumPy.
  • Assessing handling of edge cases like empty arrays or single-element features.
  • Understanding of numerical stability and handling of division by zero.
🔵
Naive Approach

For each feature, compute the necessary statistics (mean, min, max, median, IQR) and apply the scaling formula manually using loops.

Time: O(n_samples * n_features) - Each feature requires a pass over all samples. Space: O(n_samples * n_features) - Output array of the same size as input.
Why Insufficient
O(n_samples * n_features) due to explicit loops over samples and features - inefficient for large datasets.
🐍
Naive Code
Python
import numpy as np

def naive_feature_scaling(X, method='standardization'):
    n_samples, n_features = X.shape
    X_scaled = np.zeros_like(X)
    for j in range(n_features):
        if method == 'standardization':
            mean = np.mean(X[:, j])
            std = np.std(X[:, j])
            for i in range(n_samples):
                X_scaled[i, j] = (X[i, j] - mean) / std
        elif method == 'min-max':
            min_val = np.min(X[:, j])
            max_val = np.max(X[:, j])
            for i in range(n_samples):
                X_scaled[i, j] = (X[i, j] - min_val) / (max_val - min_val)
        elif method == 'robust':
            median = np.median(X[:, j])
            q1 = np.percentile(X[:, j], 25)
            q3 = np.percentile(X[:, j], 75)
            iqr = q3 - q1
            for i in range(n_samples):
                X_scaled[i, j] = (X[i, j] - median) / iqr
    return X_scaled

# Driver example
X = np.array([[1, 2], [3, 4], [5, 6]])
print(naive_feature_scaling(X, method='standardization'))
💡
Key Insight
Use NumPy's vectorized operations to compute statistics and apply scaling in a single pass over the data, eliminating explicit loops.
🐍
Optimized Code
Python
import numpy as np

def optimized_feature_scaling(X, method='standardization'):
    if method == 'standardization':
        mean = np.mean(X, axis=0)
        std = np.std(X, axis=0)
        X_scaled = (X - mean) / std
    elif method == 'min-max':
        min_val = np.min(X, axis=0)
        max_val = np.max(X, axis=0)
        X_scaled = (X - min_val) / (max_val - min_val)
    elif method == 'robust':
        median = np.median(X, axis=0)
        q1 = np.percentile(X, 25, axis=0)
        q3 = np.percentile(X, 75, axis=0)
        iqr = q3 - q1
        X_scaled = (X - median) / iqr
    return X_scaled

# Driver example
X = np.array([[1, 2], [3, 4], [5, 6]])
print(optimized_feature_scaling(X, method='standardization'))
🔍
Line-by-Line
mean = np.mean(X, axis=0)
Compute the mean for each feature across all samples - vectorized operation.
std = np.std(X, axis=0)
Compute the standard deviation for each feature - avoids explicit loops.
X_scaled = (X - mean) / std
Apply standardization formula in a vectorized manner - scales all features at once.
min_val = np.min(X, axis=0)
Compute the minimum value for each feature - necessary for Min-Max scaling.
max_val = np.max(X, axis=0)
Compute the maximum value for each feature - used in Min-Max scaling.
median = np.median(X, axis=0)
Compute the median for each feature - used in Robust scaling.
q1 = np.percentile(X, 25, axis=0)
Compute the 25th percentile (Q1) for each feature - part of IQR calculation.
q3 = np.percentile(X, 75, axis=0)
Compute the 75th percentile (Q3) for each feature - part of IQR calculation.
⚡
Complexity
Time: O(n_samples * n_features) - Vectorized operations over entire dataset. Space: O(n_samples * n_features) - Output array of the same size as input.
[[-1.22474487 -1.22474487]
 [ 0.          0.        ]
 [ 1.22474487  1.22474487]]
🔲
Edge Cases
Empty array
Returns an empty array without error.
mean = np.mean(X, axis=0) - Handles empty input gracefully.
Single element
Returns zero for standardization, zero for min-max, NaN for robust due to division by zero.
std = np.std(X, axis=0) - Handles single element by returning zero.
All same class
Standardization and Min-Max return zero, Robust returns NaN due to zero IQR.
iqr = q3 - q1 - Handles zero IQR by returning NaN.
⚠️
Common Mistakes
Symptom: Code runs slowly on large datasets.
Symptom: Incorrectly scaled features or runtime errors.
Symptom: NaN values in the output for features with zero IQR.
Symptom: Incorrect scaling results due to wrong method application.

Practice

(1/5)
1.
import numpy as np

# Forward pass for a single neuron
inputs = np.array([1.0, 2.0, 3.0])
weights = np.array([0.2, 0.8, -0.5])
bias = 2.0

output = np.dot(inputs, weights) + bias
print(output)
easy
A. 2.8
B. 2.0
C. 3.0
D. 2.3

Solution

  1. Step 1: Calculate dot product

    np.dot(inputs, weights) = 1.0*0.2 + 2.0*0.8 + 3.0*(-0.5) = 0.2 + 1.6 - 1.5 = 0.3
  2. Step 2: Add bias

    0.3 + 2.0 = 2.3
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Dot product then add bias [OK]
Hint: Dot product then add bias [OK]
Common Mistakes:
2. What is the time complexity of the following non-max suppression implementation?
def non_max_suppression(boxes, scores, iou_threshold):
    indices = np.argsort(scores)[::-1]
    keep = []
    while len(indices) > 0:
        current = indices[0]
        keep.append(current)
        indices = indices[1:]
        indices = [i for i in indices if iou(boxes[current], boxes[i]) < iou_threshold]
    return keep
easy
A. O(n^3)
B. O(n^2)
C. O(n)
D. O(n log n)

Solution

  1. Step 1: Analyze the loop structure

    The outer loop runs n times, and the inner loop (IoU calculation) also runs n times in the worst case.
  2. Step 2: Determine complexity

    Each IoU calculation is O(1), making the overall complexity O(n^2).
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Nested loops suggest O(n^2) [OK]
Hint: Nested loops suggest O(n^2) [OK]
Common Mistakes:
3. What is the time complexity of training a Random Forest with bagging and feature sampling, assuming each tree is trained on a subset of m features from n samples?
easy
A. O(n * m * log(m))
B. O(n^2 * m)
C. O(n * m^2)
D. O(n * m * log(n))

Solution

  1. Step 1: Analyze Tree Training Complexity

    Each decision tree in a Random Forest is trained on a subset of features and samples.
  2. Step 2: Determine Complexity

    Training a decision tree typically involves sorting, leading to O(n * m * log(n)) complexity.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Tree training involves sorting [OK]
Hint: Tree training involves sorting [OK]
Common Mistakes:
4. In a multi-class classification problem, how should you modify the confusion matrix implementation to handle more than two classes?
medium
A. Use a 2x2 matrix and sum over classes.
B. Use a 3D matrix to capture all interactions.
C. Use separate matrices for each class.
D. Use a matrix of size (n_classes, n_classes).

Solution

  1. Step 1: Understand multi-class needs

    Each class needs its own row and column in the matrix.
  2. Step 2: Choose correct matrix size

    A (n_classes, n_classes) matrix captures all class interactions.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Multi-class needs (n_classes, n_classes) matrix. [OK]
Hint: Multi-class needs (n_classes, n_classes) matrix. [OK]
Common Mistakes:
5. How can you optimize the memory usage of a NumPy-based backpropagation implementation for a large neural network?
hard
A. Use in-place operations to reduce memory overhead.
B. Use Python lists instead of NumPy arrays.
C. Store all intermediate results for debugging.
D. Increase the batch size to reduce iterations.

Solution

  1. Step 1: Identify memory bottlenecks

    Intermediate results can consume significant memory.
  2. Step 2: Optimize memory usage

    In-place operations reduce memory overhead by modifying data directly.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    In-place operations save memory [OK]
Hint: In-place operations save memory [OK]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard