我怎样才能在Python中进行热编码?

avi*_*hen 101 python machine-learning pandas anaconda one-hot-encoding

我有80%分类变量的机器学习分类问题.如果我想使用某种分类器进行分类,我必须使用一个热编码吗?我可以在没有编码的情况下将数据传递给分类器吗?

我正在尝试执行以下功能选择:

  1. 我读了火车文件:

    num_rows_to_read = 10000
    train_small = pd.read_csv("../../dataset/train.csv",   nrows=num_rows_to_read)
    
    Run Code Online (Sandbox Code Playgroud)
  2. 我将分类要素的类型更改为"类别":

    non_categorial_features = ['orig_destination_distance',
                              'srch_adults_cnt',
                              'srch_children_cnt',
                              'srch_rm_cnt',
                              'cnt']
    
    for categorical_feature in list(train_small.columns):
        if categorical_feature not in non_categorial_features:
            train_small[categorical_feature] = train_small[categorical_feature].astype('category')
    
    Run Code Online (Sandbox Code Playgroud)
  3. 我使用一个热编码:

    train_small_with_dummies = pd.get_dummies(train_small, sparse=True)
    
    Run Code Online (Sandbox Code Playgroud)

问题是第3部分经常卡住,虽然我使用的是强机.

因此,在没有热编码的情况下,我无法进行任何特征选择,以确定特征的重要性.

您有什么推荐的吗?

Say*_*ane 134

方法1:您可以在pandas数据帧上使用get_dummies.

例1:

import pandas as pd
s = pd.Series(list('abca'))
pd.get_dummies(s)
Out[]: 
     a    b    c
0  1.0  0.0  0.0
1  0.0  1.0  0.0
2  0.0  0.0  1.0
3  1.0  0.0  0.0
Run Code Online (Sandbox Code Playgroud)

例2:

以下内容将给定列转换为一个热点.使用前缀有多个假人.

import pandas as pd

df = pd.DataFrame({
          'A':['a','b','a'],
          'B':['b','a','c']
        })
df
Out[]: 
   A  B
0  a  b
1  b  a
2  a  c

# Get one hot encoding of columns B
one_hot = pd.get_dummies(df['B'])
# Drop column B as it is now encoded
df = df.drop('B',axis = 1)
# Join the encoded df
df = df.join(one_hot)
df  
Out[]: 
       A  a  b  c
    0  a  0  1  0
    1  b  1  0  0
    2  a  0  0  1
Run Code Online (Sandbox Code Playgroud)

方法2:使用Scikit-learn

给定具有三个特征和四个样本的数据集,我们让编码器找到每个特征的最大值并将数据转换为二进制单热编码.

>>> from sklearn.preprocessing import OneHotEncoder
>>> enc = OneHotEncoder()
>>> enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])   
OneHotEncoder(categorical_features='all', dtype=<class 'numpy.float64'>,
   handle_unknown='error', n_values='auto', sparse=True)
>>> enc.n_values_
array([2, 3, 4])
>>> enc.feature_indices_
array([0, 2, 5, 9], dtype=int32)
>>> enc.transform([[0, 1, 1]]).toarray()
array([[ 1.,  0.,  0.,  1.,  0.,  0.,  1.,  0.,  0.]])
Run Code Online (Sandbox Code Playgroud)

以下是此示例的链接:http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html

  • 使用`get_dummies`设置`drop_first = True`,无需单独删除原始列 (18认同)
  • @ OverflowingTheGlass- drop-first = True不会删除原始列。它将删除分类特征的第一级,以便最终得到k-1列而不是k列,其中k是分类特征的基数。 (7认同)
  • df.join() 在这里不起作用,它会创建更多行...但不知道为什么。 (3认同)
  • df.join() 为我创建更多行,因此我使用 pd.concat([alldata, cat_encoded], axis=1) 将编码列与原始数据集连接起来 (2认同)

Mar*_*oma 25

您可以使用numpy.eye和使用数组元素选择机制:

import numpy as np
nb_classes = 6
data = [[2, 3, 4, 0]]

def indices_to_one_hot(data, nb_classes):
    """Convert an iterable of indices to one-hot encoded labels."""
    targets = np.array(data).reshape(-1)
    return np.eye(nb_classes)[targets]
Run Code Online (Sandbox Code Playgroud)

现在的返回值indices_to_one_hot(nb_classes, data)

array([[[ 0.,  0.,  1.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  1.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  1.,  0.],
        [ 1.,  0.,  0.,  0.,  0.,  0.]]])
Run Code Online (Sandbox Code Playgroud)

.reshape(-1)是为了确保您拥有正确的标签格式(您可能也有[[2], [3], [4], [0]]).

  • @AbhilashAwasthi当然可以。但是为什么您希望它能正常工作呢? (2认同)

Wbo*_*boy 20

首先,一个热门编码的最简单方法:使用Sklearn.

http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html

其次,我不认为将pandas用于一个热门编码就是那么简单(虽然未经证实)

在pandas中为python创建虚拟变量

最后,您需要一个热门编码吗?一个热编码会以指数方式增加功能的数量,从而大大增加任何分类器或您将要运行的任何其他内容的运行时间.特别是当每个分类特征具有多个级别时.相反,你可以做虚拟编码.

使用虚拟编码通常效果很好,运行时间和复杂性要低得多.一位聪明的教授曾告诉我,"少即是多".

如果需要,这是我自定义编码功能的代码.

from sklearn.preprocessing import LabelEncoder

#Auto encodes any dataframe column of type category or object.
def dummyEncode(df):
        columnsToEncode = list(df.select_dtypes(include=['category','object']))
        le = LabelEncoder()
        for feature in columnsToEncode:
            try:
                df[feature] = le.fit_transform(df[feature])
            except:
                print('Error encoding '+feature)
        return df
Run Code Online (Sandbox Code Playgroud)

编辑:比较更清晰:

单热编码:将n级转换为n-1列.

Index  Animal         Index  cat  mouse
  1     dog             1     0     0
  2     cat       -->   2     1     0
  3    mouse            3     0     1
Run Code Online (Sandbox Code Playgroud)

如果您的分类功能中有许多不同类型(或级别),您可以看到这将如何破坏您的记忆.请记住,这只是一列.

虚拟编码:

Index  Animal         Index  Animal
  1     dog             1      0   
  2     cat       -->   2      1 
  3    mouse            3      2
Run Code Online (Sandbox Code Playgroud)

转而使用数字表示法.以极高的精度为代价,大大节省了功能空间.

  • "以一点精度为代价." 你怎么能说"有点"?也许在某些情况下,但在其他情况下,准确性可能会受到很大伤害.此解决方案导致将定性特征视为连续特征,这意味着您的模型将无法正确地从数据中学习. (15认同)
  • 正如其他一些评论所指出的那样,该解决方案非常危险。它为分类变量任意分配顺序和距离。这样做会以随机方式降低模型的灵活性。对于基于树的模型,此类编码减少了可能的子集可能性。例如,现在只能获得两个可能的分割[[0 ,,(1,2)]和[(0,1),(2)],而分割[[0,2),(1)]为不可能。当类别数量很高时,损失会更大。 (5认同)
  • 正如Josh所说,在第二个示例中,您最终要告诉模型“ mouse&gt; cat&gt; dog”,但事实并非如此。根据我的经验,`get_dummies`是将分类变量转换为模型友好数据的最直接方法(尽管非常有限) (2认同)

Cyb*_*tic 20

更容易使用Pandas进行基本的单热编码.如果您正在寻找更多选项,可以使用scikit-learn.

对于使用Pandas的基本单热编码,您只需将数据帧传递给get_dummies函数即可.

例如,如果我有一个名为imdb_movies的数据:

在此输入图像描述

...我希望对"额定"列进行单热编码,我只需这样做:

pd.get_dummies(imdb_movies.Rated)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

这将返回一个新的数据框,其中包含存在的每个" 级别 "的列,以及指定给定观察的该评级的存在的1或0.

通常,我们希望这是原始数据帧的一部分.在这种情况下,我们只需使用" 列绑定 "将新的虚拟编码帧附加到原始帧上.

我们可以使用Pandas concat函数进行列绑定:

rated_dummies = pd.get_dummies(imdb_movies.Rated)
pd.concat([imdb_movies, rated_dummies], axis=1)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

我们现在可以对我们的完整数据框进行分析.

简单的实用功能

我建议你自己做一个实用功能来快速做到这一点:

def encode_and_bind(original_dataframe, feature_to_encode):
    dummies = pd.get_dummies(original_dataframe[[feature_to_encode]])
    res = pd.concat([original_dataframe, dummies], axis=1)
    return(res)
Run Code Online (Sandbox Code Playgroud)

用法:

encode_and_bind(imdb_movies, 'Rated')
Run Code Online (Sandbox Code Playgroud)

结果:

在此输入图像描述

另外,根据@pmalbu注释,如果您希望该函数删除原始feature_to_encode,请使用此版本:

def encode_and_bind(original_dataframe, feature_to_encode):
    dummies = pd.get_dummies(original_dataframe[[feature_to_encode]])
    res = pd.concat([original_dataframe, dummies], axis=1)
    res = res.drop([feature_to_encode], axis=1)
    return(res) 
Run Code Online (Sandbox Code Playgroud)

  • 要对多个特征进行编码,最后一行应该是“train_set =encode_and_bind(train_set, feature)”,否则“res”将仅存储原始数据帧上最后一次迭代的编辑 (4认同)
  • 我建议在将一个热端列与原始数据帧连接后删除原始 feature_to_encode。 (2认同)

Qy *_*Zuo 16

使用pandas进行一次热门编码非常简单:

def one_hot(df, cols):
    """
    @param df pandas DataFrame
    @param cols a list of columns to encode 
    @return a DataFrame with one-hot encoding
    """
    for each in cols:
        dummies = pd.get_dummies(df[each], prefix=each, drop_first=False)
        df = pd.concat([df, dummies], axis=1)
    return df
Run Code Online (Sandbox Code Playgroud)

编辑:

使用sklearn的one_hot的另一种方法LabelBinarizer:

from sklearn.preprocessing import LabelBinarizer 
label_binarizer = LabelBinarizer()
label_binarizer.fit(all_your_labels_list) # need to be global or remembered to use it later

def one_hot_encode(x):
    """
    One hot encode a list of sample labels. Return a one-hot encoded vector for each label.
    : x: List of sample Labels
    : return: Numpy array of one-hot encoded labels
    """
    return label_binarizer.transform(x)
Run Code Online (Sandbox Code Playgroud)


Die*_*ter 13

你可以使用numpy.eye函数.

import numpy as np

def one_hot_encode(x, n_classes):
    """
    One hot encode a list of sample labels. Return a one-hot encoded vector for each label.
    : x: List of sample Labels
    : return: Numpy array of one-hot encoded labels
     """
    return np.eye(n_classes)[x]

def main():
    list = [0,1,2,3,4,3,2,1,0]
    n_classes = 5
    one_hot_list = one_hot_encode(list, n_classes)
    print(one_hot_list)

if __name__ == "__main__":
    main()
Run Code Online (Sandbox Code Playgroud)

结果

D:\Desktop>python test.py
[[ 1.  0.  0.  0.  0.]
 [ 0.  1.  0.  0.  0.]
 [ 0.  0.  1.  0.  0.]
 [ 0.  0.  0.  1.  0.]
 [ 0.  0.  0.  0.  1.]
 [ 0.  0.  0.  1.  0.]
 [ 0.  0.  1.  0.  0.]
 [ 0.  1.  0.  0.  0.]
 [ 1.  0.  0.  0.  0.]]
Run Code Online (Sandbox Code Playgroud)

  • 您刚才复制了我的答案吗? (2认同)

Ars*_*ngh 8

pandas 具有内置函数“get_dummies”,以获得该特定列的一种热编码。

one-hot-encoding的一行代码:

df=pd.concat([df,pd.get_dummies(df['column name'],prefix='column name')],axis=1).drop(['column name'],axis=1)
Run Code Online (Sandbox Code Playgroud)