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

如何用sklearn.preprocessing.OrdinalEncoder处理多列?解决报错

使用OrdinalEncoder处理多列分类数据的错误解决

问题场景

以下代码尝试用OrdinalEncoder处理多列分类数据时触发错误:

import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OrdinalEncoder

# Define categorical columns and mapping dictionary
categorical_cols = ['color', 'shape', 'size']
mapping = {'red': 0, 'green': 1, 'blue': 2, 'circle': 0, 'square': 1, 'triangle': 2, 'small': 0, 'medium': 1, 'large': 2}
cols = ['color','size']
# Define ColumnTransformer to preprocess categorical columns
preprocessor = ColumnTransformer(
  transformers=[
    ('orlEncdr_with_map', Pipeline(steps=[('orlEnc_with_map', OrdinalEncoder(categories=[list(mapping.keys())], dtype=int))]), cols),
  ])

# Load sample data
data = pd.DataFrame({'color': ['red', 'green', 'blue', 'red'], 'shape': ['circle', 'square', 'triangle', 'triangle'], 'size': ['small', 'medium', 'large', 'medium']})

# Apply preprocessor to data
preprocessed_data = preprocessor.fit_transform(data)

# View preprocessed data
print(preprocessed_data)

错误信息

ValueError                                Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_38148\1089712396.py in <module>
     18 
     19 # Apply preprocessor to data
---> 20 preprocessed_data = preprocessor.fit_transform(data)
     21 
     22 # View preprocessed data

~\Anaconda3\lib\site-packages\sklearn\compose\_column_transformer.py in fit_transform(self, X, y)
    673         self._validate_remainder(X)
    674 
---> 675         result = self._fit_transform(X, y, _fit_transform_one)
    676 
    677         if not result:

~\Anaconda3\lib\site-packages\sklearn\compose\_column_transformer.py in _fit_transform(self, X, y, func, fitted, column_as_strings)
    604         )
    605         try:
---> 606             return Parallel(n_jobs=self.n_jobs)(
    607                 delayed(func)(
    608                     transformer=clone(trans) if not fitted else trans,

~\Anaconda3\lib\site-packages\joblib\parallel.py in __call__(self, iterable)
   1046             # remaining jobs.
   1047             self._iterating = False
-> 1048             if self.dispatch_one_batch(iterator):
   1049                 self._iterating = self._original_iterator is not None
   1050 

~\Anaconda3\lib\site-packages\joblib\parallel.py in dispatch_one_batch(self, iterator)
    862                 return False
    863             else:
-> 864                 self._dispatch(tasks)
    865                 return True
    866 

~\Anaconda3\lib\site-packages\joblib\parallel.py in _dispatch(self, batch)
    780         with self._lock:
    781             job_idx = len(self._jobs)
-> 782             job = self._backend.apply_async(batch, callback=cb)
    783             # A job can complete so quickly than its callback is
    784             # called before we get here, causing self._jobs to

~\Anaconda3\lib\site-packages\joblib\_parallel_backends.py in apply_async(self, func, callback)
    206     def apply_async(self, func, callback=None):
    207         """Schedule a func to be run"""
-> 208         result = ImmediateResult(func)
    209         if callback:
    210             callback(result)

~\Anaconda3\lib\site-packages\joblib\_parallel_backends.py in __init__(self, batch)
    570         # Don't delay the application, to avoid keeping the input
    571         # arguments in memory
-> 572         self.results = batch()
    573 
    574     def get(self):

~\Anaconda3\lib\site-packages\joblib\parallel.py in __call__(self)
    261         # change the default number of processes to -1
    262         with parallel_backend(self._backend, n_jobs=self._n_jobs):
-> 263             return [func(*args, **kwargs)
    264                     for func, args, kwargs in self.items]
    265 

~\Anaconda3\lib\site-packages\joblib\parallel.py in <listcomp>(.0)
    261         # change the default number of processes to -1
    262         with parallel_backend(self._backend, n_jobs=self._n_jobs):
-> 263             return [func(*args, **kwargs)
    264                     for func, args, kwargs in self.items]
    265 

~\Anaconda3\lib\site-packages\sklearn\utils\fixes.py in __call__(self, *args, **kwargs)
    214     def __call__(self, *args, **kwargs):
    215         with config_context(**self.config):
-> 216             return self.function(*args, **kwargs)
    217 
    218 

~\Anaconda3\lib\site-packages\sklearn\pipeline.py in _fit_transform_one(transformer, X, y, weight, message_clsname, message, **fit_params)
    891     with _print_elapsed_time(message_clsname, message):
    892         if hasattr(transformer, "fit_transform"):
-> 893             res = transformer.fit_transform(X, y, **fit_params)
    894         else:
    895             res = transformer.fit(X, y, **fit_params).transform(X)

~\Anaconda3\lib\site-packages\sklearn\pipeline.py in fit_transform(self, X, y, **fit_params)
    432             fit_params_last_step = fit_params_steps[self.steps[-1][0]]
    433             if hasattr(last_step, "fit_transform"):
-> 434                 return last_step.fit_transform(Xt, y, **fit_params_last_step)
    435             else:
    436                 return last_step.fit(Xt, y, **fit_params_last_step).transform(Xt)

~\Anaconda3\lib\site-packages\sklearn\base.py in fit_transform(self, X, y, **fit_params)
    850         if y is None:
    851             # fit method of arity 1 (unsupervised transformation)
-> 852             return self.fit(X, **fit_params).transform(X)
    853         else:
    854             # fit method of arity 2 (supervised transformation)

~\Anaconda3\lib\site-packages\sklearn\preprocessing\_encoders.py in fit(self, X, y)
    884 
    885         # `_fit` will only raise an error when `self.handle_unknown="error"`
-> 886         self._fit(X, handle_unknown=self.handle_unknown, force_all_finite="allow-nan")
    887 
    888         if self.handle_unknown == "use_encoded_value":

~\Anaconda3\lib\site-packages\sklearn\preprocessing\_encoders.py in _fit(self, X, handle_unknown, force_all_finite)
     82         if self.categories != "auto":
     83             if len(self.categories) != n_features:
-> 84                 raise ValueError(
     85                     "Shape mismatch: if categories is an array,"
     86                     " it has to be of shape (n_features,)."

ValueError: Shape mismatch: if categories is an array, it has to be of shape (n_features,).

当把cols = ['size']改为单列时代码可正常运行,请问如何修改代码才能用OrdinalEncoder处理多列数据?


解决方案

错误原因

报错核心是OrdinalEncoder的categories参数格式不匹配:处理N列数据时,categories必须是包含N个列表的数组,每个列表对应一列的分类取值顺序。原代码中categories=[list(mapping.keys())]只传入一个列表,而要处理['color','size']两列,因此触发形状不匹配错误。同时原代码的mapping把不同列的分类混在一起,逻辑上也不合理——color列取值为红/绿/蓝,size列是小/中/大,两者分类集合完全不同,应分开定义。

修改后的代码

import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OrdinalEncoder

# 为每一列单独定义分类顺序
category_mappings = {
    'color': ['red', 'green', 'blue'],
    'size': ['small', 'medium', 'large']
}
cols = ['color', 'size']

# 提取对应列的分类列表,顺序与cols一致
categories_list = [category_mappings[col] for col in cols]

# 定义预处理流程
preprocessor = ColumnTransformer(
    transformers=[
        ('ordinal_encoder', OrdinalEncoder(categories=categories_list, dtype=int), cols),
    ])

# 加载数据
data = pd.DataFrame({
    'color': ['red', 'green', 'blue', 'red'],
    'shape': ['circle', 'square', 'triangle', 'triangle'],
    'size': ['small', 'medium', 'large', 'medium']
})

# 执行预处理
preprocessed_data = preprocessor.fit_transform(data)
print(preprocessed_data)

代码说明

  1. 拆分分类映射:为每一列单独定义分类取值顺序,避免不同列分类混淆。
  2. 匹配categories格式:根据待处理列的顺序,生成对应长度的分类列表categories_list,确保其长度与待处理列数一致。
  3. 简化流程:仅需OrdinalEncoder一步处理时,无需嵌套Pipeline,直接在ColumnTransformer中使用即可。

运行结果

输出结果为:

[[0. 0.]
 [1. 1.]
 [2. 2.]
 [0. 1.]]

对应color列红(0)/绿(1)/蓝(2)和size列小(0)/中(1)/大(2)的编码结果。


内容的提问来源于stack exchange,提问作者parvij

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 12:27:04