ColumnTransformer预处理后mutual_info_regression报错问题求助
房屋售价回归模型预处理与互信息计算报错问题
我正在开发一个预测房屋售价的回归模型,已将数据拆分为特征集X和目标变量y。为预处理数据,我创建了两个Pipeline:
- 数值变量:缺失值填充(常数0)+ 标准化
- 分类变量:缺失值填充(常数'None')+ TargetEncoder编码
直接用Pipeline转换DataFrame一切正常,但用ColumnTransformer整合两个Pipeline后,生成的数据集出现异常。将该数据集传入自定义的mutual_info_regression函数时,抛出错误:ValueError: Found array with 0 sample(s) (shape=(0, 1)) while a minimum of 1 is required。
注意:不指定离散变量时函数可正常运行,且用其他方式预处理的DataFrame也能正常指定离散变量。我需要确保mutual_info_regression能正确识别离散特征,以获得可靠的互信息结果。
问题代码(ColumnTransformer版本)
# 数值变量预处理Pipeline:缺失值填充+标准化 numerical_processes = Pipeline(steps = [('imputer', SimpleImputer(strategy = 'constant', fill_value = 0)), ('scaler', StandardScaler())]) # 分类变量预处理Pipeline:缺失值填充+TargetEncoder编码 categorical_processes = Pipeline(steps = [('imputer', SimpleImputer(strategy = 'constant', fill_value = 'None')), ('encoder', ce.TargetEncoder())]) # 整合两个Pipeline的预处理器 Preprocessor = ColumnTransformer( transformers = [('num', numerical_processes, numerical), ('categorical', categorical_processes, categorical)])
可行的预处理代码(非ColumnTransformer版本)
X_df = X.copy() X_df[numerical] = numerical_processes.fit_transform(X[numerical]) X_df[categorical] = categorical_processes.fit_transform(X[categorical], y) X_df.head()
互信息计算代码及报错
自定义MI函数
from sklearn.feature_selection import mutual_info_regression def MI(X, y, categorical): mi_scores = mutual_info_regression(X, y, discrete_features = X.columns.get_indexer(categorical), random_state = 4) mi_scores = pd.Series(mi_scores, name = 'Mutual Info', index = X.columns) mi_scores = mi_scores.sort_values(ascending = False) return mi_scores print(MI(X_pp, y, categorical))
报错信息
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[21], line 1 ----> 1 print(MI(X_pp, y, categorical)) 2 #Mutual_Information.head() Cell In[18], line 4, in MI(X, y, categorical) 3 def MI(X, y, categorical): ----> 4 mi_scores = mutual_info_regression(X, y, discrete_features = X.columns.get_indexer(categorical), 5 random_state = 4) 6 mi_scores = pd.Series(mi_scores, name = 'Mutual Info', index = X.columns) 7 mi_scores = mi_scores.sort_values(ascending = False) File /opt/conda/lib/python3.10/site-packages/sklearn/feature_selection/_mutual_info.py:388, in mutual_info_regression(X, y, discrete_features, n_neighbors, copy, random_state) 312 def mutual_info_regression( 313 X, y, *, discrete_features="auto", n_neighbors=3, copy=True, random_state=None 314 ): 315 """Estimate mutual information for a continuous target variable. 316 317 Mutual information (MI) [1]_ between two random variables is a non-negative (...) 386 of a Random Vector", Probl. Peredachi Inf., 23:2 (1987), 9-16 387 """ --> 388 return _estimate_mi(X, y, discrete_features, False, n_neighbors, copy, random_state) File /opt/conda/lib/python3.10/site-packages/sklearn/feature_selection/_mutual_info.py:304, in _estimate_mi(X, y, discrete_features, discrete_target, n_neighbors, copy, random_state) 297 y = scale(y, with_mean=False) 298 y += ( 299 1e-10 300 * np.maximum(1, np.mean(np.abs(y))) 301 * rng.standard_normal(size=n_samples) 302 ) --> 304 mi = [ 305 _compute_mi(x, y, discrete_feature, discrete_target, n_neighbors) 306 for x, discrete_feature in zip(_iterate_columns(X), discrete_mask) 307 ] 309 return np.array(mi) File /opt/conda/lib/python3.10/site-packages/sklearn/feature_selection/_mutual_info.py:305, in <listcomp>(.0) 297 y = scale(y, with_mean=False) 298 y += ( 299 1e-10 300 * np.maximum(1, np.mean(np.abs(y))) 301 * rng.standard_normal(size=n_samples) 302 ) 304 mi = [ --> 305 _compute_mi(x, y, discrete_feature, discrete_target, n_neighbors) 306 for x, discrete_feature in zip(_iterate_columns(X), discrete_mask) 307 ] 309 return np.array(mi) File /opt/conda/lib/python3.10/site-packages/sklearn/feature_selection/_mutual_info.py:161, in _compute_mi(x, y, x_discrete, y_discrete, n_neighbors) 159 return mutual_info_score(x, y) 160 elif x_discrete and not y_discrete: --> 161 return _compute_mi_cd(y, x, n_neighbors) 162 elif not x_discrete and y_discrete: 163 return _compute_mi_cd(x, y, n_neighbors) File /opt/conda/lib/python3.10/site-packages/sklearn/feature_selection/_mutual_info.py:138, in _compute_mi_cd(c, d, n_neighbors) 135 c = c[mask] 136 radius = radius[mask] --> 138 kd = KDTree(c) 139 m_all = kd.query_radius(c, radius, count_only=True, return_distance=False) 140 m_all = np.array(m_all) File sklearn/neighbors/_binary_tree.pxi:833, in sklearn.neighbors._kd_tree.BinaryTree.__init__() File /opt/conda/lib/python3.10/site-packages/sklearn/utils/validation.py:931, in check_array(array, accept_sparse, accept_large_sparse, dtype, order, copy, force_all_finite, ensure_2d, allow_nd, ensure_min_samples, ensure_min_features, estimator, input_name) 929 n_samples = _num_samples(array) 930 if n_samples < ensure_min_samples: --> 931 raise ValueError( 932 "Found array with %d sample(s) (shape=%s) while a" 933 " minimum of %d is required%s." 934 % (n_samples, array.shape, ensure_min_samples, context) 935 ) 937 if ensure_min_features > 0 and array.ndim == 2: 938 n_features = array.shape[1] ValueError: Found array with 0 sample(s) (shape=(0, 1)) while a minimum of 1 is required.
问题根源与解决方案
核心问题
- ColumnTransformer输出格式问题:默认输出numpy数组,而非Pandas DataFrame,导致
X.columns.get_indexer(categorical)无法正确匹配列名,传递的离散特征索引完全错误。 - TargetEncoder未获取y:
ColumnTransformer.fit()默认不会将目标变量y传递给需要监督信息的转换器(如TargetEncoder),导致编码后的特征可能出现无效值。
修复步骤
1. 调整ColumnTransformer配置,保留列名并传递y
# 修改ColumnTransformer,关闭自动前缀,保留原始列名 Preprocessor = ColumnTransformer( transformers = [('num', numerical_processes, numerical), ('categorical', categorical_processes, categorical)], verbose_feature_names_out=False # 禁用特征名前缀,保持和原数据一致 ) # 拟合转换时传入y,供TargetEncoder使用 X_pp = Preprocessor.fit_transform(X, y) # 将numpy数组转回DataFrame,恢复列名 X_pp = pd.DataFrame(X_pp, columns=Preprocessor.get_feature_names_out())
2. 修正离散特征的标记方式
用布尔数组替代索引列表,避免列名不匹配问题:
def MI(X, y, categorical): # 创建布尔掩码:标记哪些列是离散特征 discrete_mask = X.columns.isin(categorical) mi_scores = mutual_info_regression(X, y, discrete_features=discrete_mask, random_state=4) mi_scores = pd.Series(mi_scores, name='Mutual Info', index=X.columns) mi_scores = mi_scores.sort_values(ascending=False) return mi_scores print(MI(X_pp, y, categorical))
3. 额外验证
- 检查
X_pp.shape是否和原始X一致 - 查看分类变量的编码结果,确保没有出现全相同的值(这会导致有效样本数为0)
内容的提问来源于stack exchange,提问作者jdbanfill
相关产品推荐
相关产品推荐

