使用Scikit-Learn训练随机森林时出现ValueError错误求助
问题:Sklearn随机森林训练时出现ValueError:无法将字符串转为浮点数
数据文件
car data.csv
我的代码
import pandas as pd from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split car_data = pd.read_csv('car_data.csv') # Create X X = car_data.drop('Buy Rate', axis=1) # Create Y y = car_data['Buy Rate'] clf = RandomForestClassifier() clf.get_params() X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2) clf.fit(X_train, y_train)
执行clf.fit后出现的错误
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) /tmp/ipykernel_51905/2395142735.py in ?() ----> 1 clf.fit(X_train, y_train) ~/Desktop/ml-course/env/lib/python3.10/site-packages/sklearn/base.py in ?(estimator, *args, **kwargs) 1147 skip_parameter_validation=( 1148 prefer_skip_nested_validation or global_skip_validation 1149 ) 1150 ): -> 1151 return fit_method(estimator, *args, **kwargs) ~/Desktop/ml-course/env/lib/python3.10/site-packages/sklearn/ensemble/_forest.py in ?(self, X, y, sample_weight) 344 """ 345 # Validate or convert input data 346 if issparse(y): 347 raise ValueError("sparse multilabel-indicator for y is not supported.") -> 348 X, y = self._validate_data( 349 X, y, multi_output=True, accept_sparse="csc", dtype=DTYPE 350 ) 351 if sample_weight is not None: ~/Desktop/ml-course/env/lib/python3.10/site-packages/sklearn/base.py in ?(self, X, y, reset, validate_separately, cast_to_ndarray, **check_params) 617 if "estimator" not in check_y_params: 618 check_y_params = {**default_check_params, **check_y_params} 619 y = check_array(y, input_name="y", **check_y_params) 620 else: -> 621 X, y = check_X_y(X, y, **check_params) 622 out = X, y 623 624 if not no_val_X and check_params.get("ensure_2d", True): ~/Desktop/ml-course/env/lib/python3.10/site-packages/sklearn/utils/validation.py in ?(X, y, accept_sparse, accept_large_sparse, dtype, order, copy, force_all_finite, ensure_2d, allow_nd, multi_output, ensure_min_samples, ensure_min_features, y_numeric, estimator) 1143 raise ValueError( 1144 f"{estimator_name} requires y to be passed, but the target y is None" 1145 ) 1146 -> 1147 X = check_array( 1148 X, 1149 accept_sparse=accept_sparse, 1150 accept_large_sparse=accept_large_sparse, ~/Desktop/ml-course/env/lib/python3.10/site-packages/sklearn/utils/validation.py in ?(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) 914 ) 915 array = xp.astype(array, dtype, copy=False) 916 else: 917 array = _asarray_with_order(array, order=order, dtype=dtype, xp=xp) -> 918 except ComplexWarning as complex_warning: 919 raise ValueError( 920 "Complex data not supported\n{}\n".format(array) 921 ) from complex_warning ~/Desktop/ml-course/env/lib/python3.10/site-packages/sklearn/utils/_array_api.py in ?(array, dtype, order, copy, xp) 376 # Use NumPy API to support order 377 if copy is True: 378 array = numpy.array(array, order=order, dtype=dtype) 379 else: -> 380 array = numpy.asarray(array, order=order, dtype=dtype) 381 382 # At this point array is a NumPy ndarray. We convert it to an array 383 # container that is consistent with the input's namespace. ~/Desktop/ml-course/env/lib/python3.10/site-packages/pandas/core/generic.py in ?(self, dtype) 2082 def __array__(self, dtype: npt.DTypeLike | None = None) -> np.ndarray: 2083 values = self._values -> 2084 arr = np.asarray(values, dtype=dtype) 2085 if ( 2086 astype_is_view(values.dtype, arr.dtype) 2087 and using_copy_on_write() ValueError: could not convert string to float: 'Hyundai'
解决方案
错误核心是特征数据包含字符串类型的分类特征(如品牌“Hyundai”),而Sklearn随机森林仅支持数值型输入。需对分类特征做编码处理,两种常用方案:
1. 独热编码(适合无顺序的分类特征)
针对无等级关系的分类(如汽车品牌),用OneHotEncoder结合ColumnTransformer构建管道,避免数据泄露:
import pandas as pd from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.preprocessing import OneHotEncoder from sklearn.compose import ColumnTransformer from sklearn.pipeline import Pipeline car_data = pd.read_csv('car_data.csv') X = car_data.drop('Buy Rate', axis=1) y = car_data['Buy Rate'] # 筛选所有字符串类型的特征列 categorical_cols = X.select_dtypes(include=['object']).columns # 构建预处理管道:分类列独热编码,数值列保持原样 preprocessor = ColumnTransformer( transformers=[ ('cat', OneHotEncoder(handle_unknown='ignore'), categorical_cols) ], remainder='passthrough') # 整合预处理与模型的完整管道 model = Pipeline(steps=[ ('preprocessor', preprocessor), ('classifier', RandomForestClassifier()) ]) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2) model.fit(X_train, y_train) # 直接用model.predict(X_test)做预测
2. 序数编码(适合有顺序的分类特征)
若分类特征存在明确等级(如“差/中/好”),可使用OrdinalEncoder替换上面的OneHotEncoder:
from sklearn.preprocessing import OrdinalEncoder preprocessor = ColumnTransformer( transformers=[ ('cat', OrdinalEncoder(), categorical_cols) ], remainder='passthrough')
注意:必须通过管道或先拟合训练集再转换测试集,绝对不能先对全量数据编码再拆分,否则会导致测试集数据泄露。
内容的提问来源于stack exchange,提问作者Gleb
相关产品推荐
相关产品推荐

