ValueError: Found array with dim 3. Estimator expected <= 2 in Scikit-Learn
Flatten 3D tensors into 2D matrices of shape (n_samples, -1) using X.reshape(X.shape[0], -1) before calling .fit().
Root Cause Analysis
This error occurs when Python tries to pass a 3-dimensional array (such as image tensors or time-series sequences of shape (n_samples, height, width)) into a Scikit-Learn transformer or estimator that strictly expects 2D tabular matrices (n_samples, n_features).
1. The 2D Tabular Contract of Scikit-Learn
Standard Scikit-Learn estimators (such as StandardScaler, KMeans, PCA, and RandomForestClassifier) are designed for 2D structured tabular datasets where row indices correspond to individual samples and column indices correspond to features. When check_array(X) detects X.ndim == 3, it immediately raises ValueError: Found array with dim 3. Estimator expected <= 2.
2. Common Sources of 3D Data
This error typically arises when: (1) loading computer vision image batches (e.g. MNIST with shape (60000, 28, 28)); (2) extracting NLP token embeddings with shape (batch_size, seq_len, hidden_dim); or (3) loading multi-channel sensor logs (samples, timesteps, sensors).
3. Flattening Higher-Order Dimensions
Flatten trailing dimensions into a single feature vector using X_2d = X.reshape(X.shape[0], -1). For an array of shape (100, 28, 28), this creates a 2D matrix of shape (100, 784).
4. Reconstructing Shapes After Transformation
If transforming images (such as scaling pixel intensities with StandardScaler), reshape the output back to (n_samples, height, width) with X_scaled.reshape(X.shape) after transformation.
Reproduction Code (MCVE)
import numpy as np
from sklearn.preprocessing import StandardScaler
# 3D tensor representing 10 samples of 4x4 image feature maps
X_3d = np.random.randn(10, 4, 4)
# ValueError: Found array with dim 3. StandardScaler expected <= 2.
scaler = StandardScaler()
scaler.fit(X_3d)
Solution 1: Flatten 3D Array into a 2D Matrix with Reshape
Flatten all dimensions after the sample axis using .reshape(X.shape[0], -1) to create a valid 2D feature matrix.
import numpy as np
from sklearn.preprocessing import StandardScaler
X_3d = np.random.randn(10, 4, 4)
# Flatten from (10, 4, 4) to 2D shape (10, 16)
n_samples = X_3d.shape[0]
X_2d = X_3d.reshape(n_samples, -1)
scaler = StandardScaler()
X_scaled_2d = scaler.fit_transform(X_2d)
print('Scaled 2D shape:', X_scaled_2d.shape)
Solution 2: Use Pipeline FunctionTransformer for Automated Reshaping
Wrap the reshaping operation into a Scikit-Learn FunctionTransformer to automate flattening inside a production Pipeline.
import numpy as np
from sklearn.preprocessing import FunctionTransformer, StandardScaler
from sklearn.pipeline import make_pipeline
from sklearn.cluster import KMeans
X_3d = np.random.randn(20, 8, 8)
def flatten_3d(X):
return X.reshape(X.shape[0], -1)
pipeline = make_pipeline(
FunctionTransformer(flatten_3d),
StandardScaler(),
KMeans(n_clusters=3, random_state=42, n_init='auto')
)
pipeline.fit(X_3d)
print('Pipeline successfully processed 3D tensor input.')
A common mistake is using X.flatten() without arguments, which collapses the entire array into a 1D vector of shape (N * H * W,) rather than preserving the sample dimension (N, H * W). Always specify .reshape(X.shape[0], -1) to preserve sample independence. Contrast Found array with dim 3 with Expected 2D array, got 1D array instead, which occurs when passing a single sample without .reshape(1, -1). For complex sequence processing where temporal relationships must be preserved, use dedicated sequence libraries (like sktime or deep learning models) rather than standard 2D estimators.