基于皮尔逊相关系数使用selectKBest选15个最优特征及自定义评分函数报错问题
报错原因定位
- 低级传参失误:你用
callable()校验时检测的是函数本身的可调用性,但实际传入SelectKBest的根本不是函数对象,而是函数被执行后的返回值。常见的写法错误是给评分函数加了括号,写成SelectKBest(scoring_function(), k=15);而你编写的scoring_function没有任何return语句,执行后默认返回None,自然会触发“传入None而非可调用对象”的TypeError。 - 原有函数完全不符合sklearn的接口规范,就算修正了传参括号的问题也无法正常工作:
- 遍历逻辑错误:如果传入的x是numpy格式的特征矩阵,原写法
for col in x会按行遍历而非按列遍历,根本无法正确匹配每个特征列的计算 - 无返回值:函数内部循环计算了皮尔逊相关系数,但没有把计算结果收集返回
- 格式不匹配:没有按照
SelectKBest的要求,输出与特征数等长的得分数组、p值数组
- 遍历逻辑错误:如果传入的x是numpy格式的特征矩阵,原写法
正确实现方案
1. 提前准备依赖
import numpy as np from scipy.stats import pearsonr from sklearn.feature_selection import SelectKBest
2. 编写符合接口规范的皮尔逊评分函数
按照sklearn对评分函数的要求:输入为特征矩阵x(形状为(n_samples, n_features))、目标值y(形状为(n_samples,)),输出为两个长度等于特征数的数组,分别存储每个特征的得分、对应的p值。
实现代码:
def pearson_score_func(x, y): n_features = x.shape[1] score_list = [] pval_list = [] for feat_idx in range(n_features): # 提取当前特征列和目标值计算皮尔逊相关系数 corr, p_val = pearsonr(x[:, feat_idx], y) # 取相关系数绝对值作为得分,确保不会漏掉负向强相关的特征 score_list.append(abs(corr)) pval_list.append(p_val) return np.array(score_list), np.array(pval_list)
3. 初始化并运行特征筛选
注意此处传评分函数时不要加括号,直接把函数对象作为参数传入,指定k=15选取排名最高的15个特征:
# 初始化选择器 selector = SelectKBest(score_func=pearson_score_func, k=15) # 拟合数据,转换得到筛选后的特征矩阵 x_filtered = selector.fit_transform(x, y) # (可选)如果原特征是带列名的DataFrame,可通过以下方式拿到被选中的特征名 selected_cols = x.columns[selector.get_support()]
关键注意事项
- 如果业务场景中只需要筛选和目标值正相关最强的特征,就去掉代码里取绝对值的逻辑,直接用原始相关系数作为得分即可
- 皮尔逊相关系数仅能捕捉线性关联,和线性模型的特性适配性高,适合这类场景的特征筛选
- 评分函数内部不要直接按pandas列名遍历特征,因为
SelectKBest经过数据管道处理后传入的是numpy数组,按列索引遍历的写法兼容性更强
内容的提问来源于stack exchange,提问作者zulu
相关产品推荐
相关产品推荐

