Normalize Array
Problem Statement
Normalize array data using broadcasting.
Background
Normalization scales data to a standard range. Common methods:
- Min-max: (x - min) / (max - min) → scales to [0, 1]
- Z-score: (x - mean) / std → centers around 0
These operations use broadcasting naturally.
Your Task
Write a function normalize(arr) that normalizes a 2D array column-wise.
Output Format
Return a dictionary with:
- "minmax": Min-max normalized (rounded to 3 decimals)
- "zscore": Z-score normalized (rounded to 3 decimals)
- "col_means": Mean of each column before normalization (rounded to 2 decimals)
- "col_stds": Std of each column before normalization (rounded to 2 decimals)
Example:
[[1, 2], [3, 4], [5, 6]]
Min-max scales each column to [0, 1], z-score centers each column
Column means/stds are computed, then broadcast to normalize
Constraints:
- Normalize along axis=0 (column-wise)
- Use ddof=0 for std calculation
- Round to specified decimal places
More from NumPy Foundations
Broadcasting and Array Normalization in NumPy
Background Knowledge
Broadcasting is a fundamental NumPy mechanism that allows operations between arrays of different shapes. When you perform operations on arrays, NumPy automatically expands smaller arrays to match the shape of larger ones, without actually copying data in memory. This is crucial for efficiency: instead of creating intermediate arrays, NumPy aligns dimensions and applies operations element-wise. For normalization, broadcasting enables you to subtract a 1D array of column means from a 2D array, or divide by standard deviations, all in a single vectorized operation.
Normalization is a preprocessing technique that transforms data to a standard scale. The two methods you'll implement serve different purposes: min-max normalization bounds values to [0, 1], making it useful when you need a fixed range; z-score normalization (standardization) centers data around 0 with unit variance, which is essential for many machine learning algorithms that assume normally distributed inputs. Both methods compute statistics (min, max, mean, std) along specific dimensions—in your case, column-wise—then use broadcasting to apply these statistics uniformly across all rows.
Column-wise operations mean computing statistics independently for each column, then using those statistics to transform the entire column. This is where broadcasting shines: you compute a 1D array of statistics (one value per column) and broadcast it across all rows without explicit loops.
Algorithm/Approach
The general pattern for column-wise normalization is:
- Compute column statistics (mean, std, min, max) along axis 0
- Apply the normalization formula using broadcasting to subtract/divide across all rows
- Round results to the specified precision
- Return structured output as a dictionary
The key insight is that NumPy automatically broadcasts a shape (n_cols,) array across a shape (n_rows, n_cols) array when you perform arithmetic operations.
Step-by-Step Strategy
Step 1: Calculate column statistics
- Use np.mean(arr, axis=0) to get the mean of each column (shape: (n_cols,))
- Use np.std(arr, axis=0) to get the standard deviation of each column
- Use np.min(arr, axis=0) and np.max(arr, axis=0) for min-max normalization
Step 2: Implement min-max normalization
- Apply the formula: (arr - min_vals) / (max_vals - min_vals)
- The subtraction and division automatically broadcast the 1D statistics across all rows
- Handle edge cases: if max equals min for a column, you'll get division by zero (consider adding a small epsilon or handling separately)
Step 3: Implement z-score normalization
- Apply the formula: (arr - mean_vals) / std_vals
- Again, broadcasting handles the shape mismatch automatically
- Watch for columns with zero standard deviation
Step 4: Round and format
- Use np.round() with the appropriate decimal places
- Ensure statistics are rounded to 2 decimals, normalized arrays to 3 decimals
Step 5: Construct the output dictionary
- Organize results with keys matching the required format
- Convert NumPy arrays to lists if needed for JSON compatibility
Common Pitfalls
- Forgetting axis parameter: Using np.mean(arr) computes the global mean, not column-wise means. Always specify axis=0 for column operations.
- Division by zero: If a column has zero variance (all identical values), std will be 0, causing division by zero in z-score normalization. Consider adding a small epsilon (e.g., 1e-8) to the denominator.
- Shape mismatches in broadcasting: Ensure your statistics arrays have shape (n_cols,) not (1, n_cols) or (n_cols, 1). NumPy broadcasts (n_cols,) correctly across (n_rows, n_cols).
- Rounding precision: Apply rounding after normalization, not before, to avoid compounding rounding errors.
- Data type issues: If your input is integer type, division may truncate. Consider converting to float first.
- In-place vs. copy: Operations like arr - mean_vals create new arrays; they don't modify the original. This is usually desired for normalization.
Time & Space Complexity
Time Complexity: O(n×m) where n is the number of rows and m is the number of columns. Computing statistics requires scanning all elements once, and normalization requires one pass through the entire array. Rounding is also linear.
Space Complexity: O(n×m) for the output arrays (normalized versions of the input). The statistics arrays require only O(m) space. NumPy's broadcasting doesn't create intermediate copies of the full array, so you don't pay extra memory for the broadcast operations themselves—only for storing the final results.