【问题标题】:Pandas sklearn one-hot encoding dataframe or numpy?Pandas sklearn one-hot 编码数据帧或 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。
  • 我明天必须尝试功能联合。关键是我需要每折叠执行一个特定的预处理步骤。

标签: python pandas numpy scikit-learn dummy-variable


【解决方案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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-11
      • 1970-01-01
      • 2021-11-02
      • 1970-01-01
      • 2021-02-23
      • 2017-11-06
      • 2016-11-15
      • 2023-01-16
      相关资源
      最近更新 更多