如何在sklearn中编码分类变量?

12 投票
3 回答
23792 浏览
提问于 2025-04-17 16:44

我正在尝试使用UCI库中的汽车评估数据集,我想知道在sklearn中有没有方便的方法来将分类变量转化为二进制形式。一个方法是使用DictVectorizer或LabelBinarizer,但这样我得到了k个不同的特征,而实际上应该只有k-1个,以避免出现多重共线性。 我想我可以自己写一个函数来去掉一列,但这样做的管理工作太麻烦了,有没有简单的方法来进行这样的转换,并得到一个稀疏矩阵作为结果呢?

3 个回答

16

基本的方法是

import numpy as np
import pandas as pd, os
from sklearn.feature_extraction import DictVectorizer

def one_hot_dataframe(data, cols, replace=False):
    vec = DictVectorizer()
    mkdict = lambda row: dict((col, row[col]) for col in cols)
    vecData = pd.DataFrame(vec.fit_transform(data[cols].apply(mkdict, axis=1)).toarray())
    vecData.columns = vec.get_feature_names()
    vecData.index = data.index
    if replace is True:
        data = data.drop(cols, axis=1)
        data = data.join(vecData)
    return (data, vecData, vec)

data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
        'year': [2000, 2001, 2002, 2001, 2002],
        'pop': [1.5, 1.7, 3.6, 2.4, 2.9]}

df = pd.DataFrame(data)

df2, _, _ = one_hot_dataframe(df, ['state'], replace=True)
print df2

下面是如何以稀疏格式来做的

import numpy as np
import pandas as pd, os
import scipy.sparse as sps
import itertools

def one_hot_column(df, cols, vocabs):
    mats = []; df2 = df.drop(cols,axis=1)
    mats.append(sps.lil_matrix(np.array(df2)))
    for i,col in enumerate(cols):
        mat = sps.lil_matrix((len(df), len(vocabs[i])))
        for j,val in enumerate(np.array(df[col])):
            mat[j,vocabs[i][val]] = 1.
        mats.append(mat)

    res = sps.hstack(mats)   
    return res

data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
        'year': ['2000', '2001', '2002', '2001', '2002'],
        'pop': [1.5, 1.7, 3.6, 2.4, 2.9]}

df = pd.DataFrame(data)
print df

vocabs = []
vals = ['Ohio','Nevada']
vocabs.append(dict(itertools.izip(vals,range(len(vals)))))
vals = ['2000','2001','2002']
vocabs.append(dict(itertools.izip(vals,range(len(vals)))))

print vocabs

print one_hot_column(df, ['state','year'], vocabs).todense()
31

如果你的数据是一个 pandas 的数据框(DataFrame),那么你可以直接使用 get_dummies 这个函数。假设你的数据框叫做 df,你想要为变量 'key' 的每个级别创建一个二进制变量(就是0和1的变量)。你只需要这样调用:

pd.get_dummies(df['key'])

然后你可以删除其中一个虚拟变量,这样可以避免多重共线性的问题。希望这对你有帮助……

15

DictVectorizer 是生成分类变量的一种热编码(one-hot encoding)的推荐方法;你可以使用 sparse 参数来创建一个稀疏的 CSR 矩阵,而不是一个密集的 numpy 数组。我通常不太在意多重共线性(就是变量之间的关系),而且我用的那些方法(比如 LinearSVC、SGDClassifier 和基于树的方法)也没有出现什么问题。

如果想要修改 DictVectorizer,使其每个分类特征只保留一列,其实很简单——你只需要在 fit 方法结束时,从 DictVectorizer.vocabulary 中删除一个项就可以了。(欢迎随时提交改进建议!)

撰写回答