Pandas sklearn one-hot 编码数据帧或 numpy?

Posted

技术标签:

【中文标题】Pandas sklearn one-hot 编码数据帧或 numpy?【英文标题】:Pandas sklearn one-hot encoding dataframe or numpy? 【发布时间】:2017-02-16 20:20:36 【问题描述】:

在某些列不需要编码的情况下,如何将 pandas 数据帧转换为 sklearn one-hot-encoded(数据帧/numpy 数组)?

mydf = pd.DataFrame('Target':[0,1,0,0,1, 1,1],
                   'GroupFoo':[1,1,2,2,3,1,2],
                    'GroupBar':[2,1,1,0,3,1,2],
                    'GroupBar2':[2,1,1,0,3,1,2],
                    'SomeOtherShouldBeUnaffected':[2,1,1,0,3,1,2])
columnsToEncode = ['GroupFoo', 'GroupBar']

是一个已经标签编码的数据帧,我只想编码columnsToEncode标记的列吗?

我的问题是我不确定pd.Dataframenumpy 数组表示是否更好,以及如何将编码部分与另一个重新合并。

到目前为止我的尝试:

myEncoder = OneHotEncoder(sparse=False, handle_unknown='ignore')
myEncoder.fit(X_train)
df = pd.concat([
         df[~columnsToEncode], # select all other / numeric
        # select category to one-hot encode
         pd.Dataframe(encoder.transform(X_train[columnsToEncode]))#.toarray() # not sure what this is for
        ], axis=1).reindex_axis(X_train.columns, axis=1)

注意:我知道Pandas: Get Dummies / http://pandas.pydata.org/pandas-docs/stable/generated/pandas.get_dummies.html 但在我需要每次折叠都进行这种编码的训练/测试拆分中效果不佳。

【问题讨论】:

我并不完全清楚为什么 pre-one.hot 编码在使用训练/测试拆分时会出现问题(因为两组可能都需要这种编码;所以在拆分之前就这样做)。如果真的需要它,它可能可以使用 scikit-learn 的管道(在传递给分类器/回归器之前自动调用预处理)。另外:您始终可以使用 df.as_matrix() 来提取 numpy-array。 我明天必须尝试功能联合。关键是我需要每折叠执行一个特定的预处理步骤。 【参考方案1】:

这个库提供了几个分类编码器,使 sklearn / numpy 可以很好地与 pandas https://github.com/wdm0006/categorical_encoding

但是,它们还不支持“处理未知类别”

现在我会使用

myEncoder = OneHotEncoder(sparse=False, handle_unknown='ignore')
myEncoder.fit(df[columnsToEncode])

pd.concat([df.drop(columnsToEncode, 1),
          pd.DataFrame(myEncoder.transform(df[columnsToEncode]))], axis=1).reindex()

因为它支持未知数据集。现在,我会坚持使用 half-pandas half-numpy,因为 pandas 标签很好。对于数字列。

【讨论】:

在执行 myEncoder.fit(df["sales"]) 时,我收到错误为 ValueError: Expected 2D array, got 1D array instead: array=['ab' 'vg' 'ab' 'iu' 'ab' 'vg' 'iu']。如果您的数据具有单个特征,则使用 array.reshape(-1, 1) 重塑您的数据,如果它包含单个样本,则使用 array.reshape(1, -1)。【参考方案2】:

我相信对初始答案的更新会更好,以便执行虚拟编码 导入日志

import pandas as pd
from sklearn.base import TransformerMixin

log = logging.getLogger(__name__)


class CategoricalDummyCoder(TransformerMixin):
    """Identifies categorical columns by dtype of object and dummy codes them. Optionally a pandas.DataFrame
    can be returned where categories are of pandas.Category dtype and not binarized for better coding strategies
    than dummy coding."""

    def __init__(self, only_categoricals=False):
        self.categorical_variables = []
        self.categories_per_column = 
        self.only_categoricals = only_categoricals

    def fit(self, X, y):
        self.categorical_variables = list(X.select_dtypes(include=['object']).columns)
        logging.debug(f'identified the following categorical variables: self.categorical_variables')

        for col in self.categorical_variables:
            self.categories_per_column[col] = X[col].astype('category').cat.categories
        logging.debug('fitted categories')
        return self

    def transform(self, X):
        for col in self.categorical_variables:
            logging.debug(f'transforming cat col: col')
            X[col] = pd.Categorical(X[col], categories=self.categories_per_column[col])
            if self.only_categoricals:
                X[col] = X[col].cat.codes
        if not self.only_categoricals:
            return pd.get_dummies(X, sparse=True)
        else:
            return X

【讨论】:

【参考方案3】:

对于 One Hot Encoding,我建议使用 ColumnTransformer 和 OneHotEncoder 而不是 get_dummies。这是因为 OneHotEncoder 返回一个对象,该对象可用于使用您在训练数据上使用的相同映射对看不见的样本进行编码。

以下代码对 columns_to_encode 变量中提供的所有列进行编码:

import pandas as pd
import numpy as np

df = pd.DataFrame('cat_1': ['A1', 'B1', 'C1'], 'num_1': [100, 200, 300], 
                   'cat_2': ['A2', 'B2', 'C2'], 'cat_3': ['A3', 'B3', 'C3'],
                   'label': [1, 0, 0])

X = df.iloc[:, :-1].values
y = df.iloc[:, -1].values

from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
columns_to_encode = [0, 2, 3] # Change here
ct = ColumnTransformer(transformers=[('encoder', OneHotEncoder(), columns_to_encode)], remainder='passthrough')
X = np.array(ct.fit_transform(X))

X:

array([[1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 100],
       [0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 200],
       [0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 300]], dtype=object)

为避免multicollinearity due to the dummy variable trap,我还建议删除您编码的每一列返回的列之一。以下代码对 columns_to_encode 变量中提供的所有列进行编码 AND 它删除了每个热编码列的最后一列:

import pandas as pd
import numpy as np

def sum_prev (l_in):
    l_out = []
    l_out.append(l_in[0])
    for i in range(len(l_in)-1):
        l_out.append(l_out[i] + l_in[i+1])
    return [e - 1 for e in l_out]

df = pd.DataFrame('cat_1': ['A1', 'B1', 'C1'], 'num_1': [100, 200, 300], 
                   'cat_2': ['A2', 'B2', 'C2'], 'cat_3': ['A3', 'B3', 'C3'],
                   'label': [1, 0, 0])

X = df.iloc[:, :-1].values
y = df.iloc[:, -1].values

from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
columns_to_encode = [0, 2, 3] # Change here
ct = ColumnTransformer(transformers=[('encoder', OneHotEncoder(), columns_to_encode)], remainder='passthrough')

columns_to_encode = [df.iloc[:, del_idx].nunique() for del_idx in columns_to_encode]
columns_to_encode = sum_prev(columns_to_encode)
X = np.array(ct.fit_transform(X))
X = np.delete(X, columns_to_encode, 1)

X:

array([[1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 100],
       [0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 200],
       [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 300]], dtype=object)

【讨论】:

以上是关于Pandas sklearn one-hot 编码数据帧或 numpy?的主要内容,如果未能解决你的问题,请参考以下文章

将 pandas 稀疏数据帧转换为稀疏 numpy 矩阵以供 sklearn 使用?

使用单热编码处理sklearn中的分类变量

独热编码(one-hot)是什么?什么数据类型需要进行独热编码?pandas如何进行独热编码(one-hot)?

如何用pandas将某列one-hot编码后,修改原dataframe

使用 pandas 和 scikit-learn 对多维数组进行 one-hot 编码

Pandas实战教程 | 实现one-hot编码