scikit-learn kNN回归含列表型特征报错ValueError的解决问询
解决scikit-learn kNN回归中嵌套列表特征的ValueError问题
你遇到的ValueError: setting an array element with a sequence完全是因为scikit-learn的模型(包括KNeighborsRegressor)不支持将嵌套列表作为单个特征值——它要求输入的特征矩阵必须是二维数值数组(或稀疏矩阵),所有元素都是标量类型。你的'list'列每个元素都是一个列表,直接违反了这个输入要求。
下面是分步解决的方案:
1. 将嵌套列表特征展开为多个标量特征
首先需要把每个列表型特征拆分成多个独立的数值列,比如把[1,0,3,5,0,9]拆成list_0到list_5共6个列。用pandas可以轻松实现:
# 展开list列成多个独立特征 expanded_list = paul['list'].apply(pd.Series) expanded_list.columns = [f'list_{i}' for i in expanded_list.columns] # 合并到原数据集,删除原始的list列 paul_processed = pd.concat([paul.drop('list', axis=1), expanded_list], axis=1)
处理后的数据集所有特征都是标量,符合scikit-learn的输入要求。
2. 调整自定义距离函数
原来的距离函数是针对单个特征可能为列表的情况设计的,现在所有特征都是标量,我们需要修改函数,让它能接收整个样本的特征向量,分别计算不同类型特征的距离后求和:
import pandas as pd def my_distance(X, Y, **kwargs): # X和Y是单个样本的一维特征向量 # 提取不同类型的特征(对应处理后的数据集列顺序:cat, metr, list_0~list_5) cat_x, cat_y = X[0], Y[0] metr_x, metr_y = X[1], Y[1] list_x = X[2:] list_y = Y[2:] # 计算原list特征部分的距离:sum(max(xk,yk)) * Para_list sum_max_list = sum(max(xk, yk) for xk, yk in zip(list_x, list_y)) dist_list = sum_max_list * kwargs["Para_list"] # 计算分类特征cat的距离 if cat_x == cat_y and cat_x != -1: dist_cat = 0 elif cat_x == -1 or cat_y == -1 or pd.isna(cat_x) or pd.isna(cat_y): dist_cat = kwargs["Para_minus1"] else: dist_cat = kwargs["Para_nominal"] # 计算数值特征metr的距离 if metr_x == metr_y: dist_metr = 0 elif metr_x == -1 or metr_y == -1 or pd.isna(metr_x) or pd.isna(metr_y): dist_metr = kwargs["Para_minus1"] else: dist_metr = abs(metr_x - metr_y) * kwargs["Para_metrisch"] # 总距离为各部分距离之和 return dist_list + dist_cat + dist_metr
3. 重新训练kNN模型
注意需要用DistanceMetric.get_metric包装自定义函数,并且将数据集转换为numpy数组(避免pandas DataFrame的类型兼容问题):
from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsRegressor from sklearn.metrics import DistanceMetric # 拆分训练测试集 train, test = train_test_split(paul_processed, test_size=0.3) x_train = train.drop('target', axis=1).values y_train = train['target'].values x_test = test.drop('target', axis=1).values y_test = test['target'].values # 包装自定义距离函数 custom_metric = DistanceMetric.get_metric('pyfunc', func=my_distance) # 初始化并训练模型 knn = KNeighborsRegressor( n_neighbors=2, algorithm='ball_tree', metric=custom_metric, metric_params={"Para_list": 2, "Para_minus1": 3, "Para_metrisch": 2, "Para_nominal": 4} ) knn.fit(x_train, y_train) # 预测 y_pred = knn.predict(x_test)
额外注意事项
- 使用
ball_tree算法时,自定义距离函数必须满足对称性(my_distance(X,Y) == my_distance(Y,X))和非负性(距离值≥0),否则算法可能出现异常或结果错误,你的函数目前是符合这些要求的。 - 如果你的列表长度不固定,需要先统一长度(比如补0或NaN)再展开,否则无法转换成规整的特征矩阵。
内容的提问来源于stack exchange,提问作者paule
相关产品推荐
相关产品推荐

