使用决策树时遇ValueError:数组元素赋值为序列,求解决方案
解决决策树训练时的"ValueError: setting an array element with a sequence"错误
我一眼就看出问题出在你处理info.venue的方式上——当你用OneHotEncoder处理后直接把结果塞回DataFrame的单列时,就埋下了报错的隐患。下面给你拆解原因和解决办法:
问题根源
你这段代码里的操作逻辑有明显问题:
df['info.venue']=labelencoder.fit_transform(df['info.venue']) df['info.venue']=onehotencoder.fit_transform(df[['info.venue']])
- LabelEncoder把字符串转成整数后,
df['info.venue']是一列普通整数; - 但OneHotEncoder处理这个单列后,返回的是形状为(n_samples, n_categories)的稀疏矩阵(比如你的venue有11个不同取值,就会生成11列);
- 你试图把这个多列的稀疏矩阵塞进DataFrame的一个单列里,这本身就不合理。当你把
info.venue和其他普通数值列组合成X时,X里同时存在稀疏矩阵和普通数组,决策树模型的fit()方法无法处理这种混合类型,于是抛出"setting an array element with a sequence"错误。
解决方案
推荐两种简单可行的处理方式,选一种就行:
方法1:用pd.get_dummies()简化独热编码(最推荐)
Pandas的get_dummies()可以直接把字符串类型的类别特征转成独热编码列,不用手动做LabelEncoder,代码更简洁:
import pandas as pd from sklearn.preprocessing import LabelEncoder from sklearn.model_selection import train_test_split # 注意:sklearn.cross_validation已废弃 from sklearn.tree import DecisionTreeClassifier # 处理二分类/少类别特征 labelencoder = LabelEncoder() df['info.toss.decision'] = labelencoder.fit_transform(df['info.toss.decision']) df['info.toss.winner'] = labelencoder.fit_transform(df['info.toss.winner']) df['info.outcome.winner'] = labelencoder.fit_transform(df['info.outcome.winner']) # 对venue生成独热编码列,前缀为info.venue venue_dummies = pd.get_dummies(df['info.venue'], prefix='info.venue') # 合并独热列到原数据,删除原venue列 df = pd.concat([df, venue_dummies], axis=1) df.drop('info.venue', axis=1, inplace=True) # 构建特征矩阵(要包含所有独热列) X_cols = ['info.toss.decision', 'info.toss.winner'] + list(venue_dummies.columns) X = df[X_cols] Y = df['info.outcome.winner'] # 划分数据集+训练模型 X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.25, random_state=0) classifier = DecisionTreeClassifier(criterion='gini', random_state=0) classifier.fit(X_train, y_train)
方法2:用OneHotEncoder并正确处理输出格式
如果坚持用scikit-learn的OneHotEncoder,需要把稀疏矩阵转为普通数组,再拆成多列加入DataFrame:
from sklearn.preprocessing import LabelEncoder, OneHotEncoder import pandas as pd from sklearn.model_selection import train_test_split from sklearn.tree import DecisionTreeClassifier labelencoder = LabelEncoder() df['info.toss.decision'] = labelencoder.fit_transform(df['info.toss.decision']) df['info.toss.winner'] = labelencoder.fit_transform(df['info.toss.winner']) df['info.outcome.winner'] = labelencoder.fit_transform(df['info.outcome.winner']) # 先给venue做整数编码 df['info.venue_encoded'] = labelencoder.fit_transform(df['info.venue']) # 用OneHotEncoder生成普通数组(设置sparse_output=False) onehotencoder = OneHotEncoder(sparse_output=False) venue_onehot = onehotencoder.fit_transform(df[['info.venue_encoded']]) # 把独热数组转成DataFrame,列名用原始venue名称 venue_cats = labelencoder.inverse_transform(onehotencoder.categories_[0]) venue_columns = [f'info.venue_{cat}' for cat in venue_cats] venue_df = pd.DataFrame(venue_onehot, columns=venue_columns, index=df.index) # 合并到原数据,删除中间列 df = pd.concat([df, venue_df], axis=1) df.drop(['info.venue', 'info.venue_encoded'], axis=1, inplace=True) # 构建特征矩阵并训练 X_cols = ['info.toss.decision', 'info.toss.winner'] + venue_columns X = df[X_cols] Y = df['info.outcome.winner'] X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.25, random_state=0) classifier = DecisionTreeClassifier(criterion='gini', random_state=0) classifier.fit(X_train, y_train)
额外注意事项
- 别再用
sklearn.cross_validation了,这个模块早就被废弃,现在用sklearn.model_selection里的工具; - 如果你的数据集超大,想保留稀疏矩阵节省内存,可以用
scipy.sparse.hstack合并特征:
此时X是稀疏矩阵,决策树模型也能正常处理。from scipy.sparse import hstack other_features = df[['info.toss.decision','info.toss.winner']].values X = hstack([venue_onehot, other_features])
内容的提问来源于stack exchange,提问作者Mayur Mahajan
相关产品推荐
相关产品推荐

