我有一个80%类别变量的机器学习分类问题。如果我想使用一些分类器进行分类,我必须使用一个热编码吗?我可以将数据传递给分类器而不进行编码吗?

我试图做以下的特征选择:

I read the train file: num_rows_to_read = 10000 train_small = pd.read_csv("../../dataset/train.csv", nrows=num_rows_to_read) I change the type of the categorical features to 'category': 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') I use one hot encoding: train_small_with_dummies = pd.get_dummies(train_small, sparse=True)

问题是,第三部分经常卡住,尽管我使用的是一个强大的机器。

因此,如果没有一个热编码,我就无法进行任何特征选择,以确定特征的重要性。

你有什么建议吗?


当前回答

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

对于Pandas的基本单热编码,您可以将数据帧传递给get_dummies函数。

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

...和我想要一个热编码的评级列,我这样做:

pd.get_dummies(imdb_movies.Rated)

这将返回一个新的数据框架,其中包含一个列,表示存在的每个评级“级别”,以及一个1或0,指定给定观察值的评级。

通常,我们希望它是原始数据框架的一部分。在本例中,我们使用“列绑定”将新的虚拟编码框架附加到原始框架上。

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

rated_dummies = pd.get_dummies(imdb_movies.Rated)
pd.concat([imdb_movies, rated_dummies], axis=1)

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

简单效用函数

我建议你自己做一个效用函数来快速做到这一点:

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)

用法:

encode_and_bind(imdb_movies, 'Rated')

结果:

另外,根据@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) 

你可以在同一时间编码多个特征,如下所示:

features_to_encode = ['feature_1', 'feature_2', 'feature_3',
                      'feature_4']
for feature in features_to_encode:
    res = encode_and_bind(train_set, feature)

其他回答

它可以而且应该很简单:

class OneHotEncoder:
    def __init__(self,optionKeys):
        length=len(optionKeys)
        self.__dict__={optionKeys[j]:[0 if i!=j else 1 for i in range(length)] for j in range(length)}

用法:

ohe=OneHotEncoder(["A","B","C","D"])
print(ohe.A)
print(ohe.D)

熊猫的热编码非常简单:

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

编辑:

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

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)

一个在numpy中使用矢量化并在pandas中应用的简单示例:

import numpy as np

a = np.array(['male','female','female','male'])

#define function
onehot_function = lambda x: 1.0 if (x=='male') else 0.0

onehot_a = np.vectorize(onehot_function)(a)

print(onehot_a)
# [1., 0., 0., 1.]

# -----------------------------------------

import pandas as pd

s = pd.Series(['male','female','female','male'])
onehot_s = s.apply(onehot_function)

print(onehot_s)
# 0    1.0
# 1    0.0
# 2    0.0
# 3    1.0
# dtype: float64

首先,最简单的热编码方法:使用Sklearn。

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

其次,我不认为使用熊猫进行一个热编码是那么简单(虽然未经证实)

在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

编辑:比较更清楚:

一热编码:将n层转换为n-1列。

Index  Animal         Index  cat  mouse
  1     dog             1     0     0
  2     cat       -->   2     1     0
  3    mouse            3     0     1

你可以看到,如果你的分类特征中有许多不同类型(或级别),这会使你的记忆爆发式增长。记住,这只是一列。

伪代码:

Index  Animal         Index  Animal
  1     dog             1      0   
  2     cat       -->   2      1 
  3    mouse            3      2

转换为数字表示。极大地节省了特征空间,代价是准确性。

您可以将数据传递给catboost分类器而不进行编码。Catboost通过执行单热和目标扩展平均编码来处理分类变量本身。