You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.

问题根源与解决方案

核心问题

  1. ColumnTransformer输出格式问题:默认输出numpy数组,而非Pandas DataFrame,导致X.columns.get_indexer(categorical)无法正确匹配列名,传递的离散特征索引完全错误。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 20:25:55