58

我有一组数据框,其中一个列包含一个分类变量。我想将它转换为几个虚拟变量,在这种情况下我通常会使用get_dummies.

发生的情况是get_dummies查看每个数据帧中可用的数据以找出有多少类别,从而创建适当数量的虚拟变量。但是,在我现在正在处理的问题中,我实际上提前知道可能的类别是什么。但是,当单独查看每个数据框时,并非所有类别都一定会出现。

我的问题是:有没有办法将get_dummies类别的名称传递给(或等效函数),这样,对于没有出现在给定数据框中的类别,它只会创建一列 0?

可以做到这一点的东西:

categories = ['a', 'b', 'c']

   cat
1   a
2   b
3   a

变成这样:

  cat_a  cat_b  cat_c
1   1      0      0
2   0      1      0
3   1      0      0
4

10 回答 10

53

TL;博士

pd.get_dummies(cat.astype(pd.CategoricalDtype(categories=categories)))
  • 大熊猫:pd.get_dummies(cat.astype('category', categories=categories))

有没有办法将类别的名称传递给 get_dummies (或等效函数),以便对于未出现在给定数据框中的类别,它只会创建一列 0?

就在这里!Pandas 有一种特殊类型的 Series 仅用于分类数据。该系列的属性之一是可能的类别,其中get_dummies考虑到了。这是一个例子:

In [1]: import pandas as pd

In [2]: possible_categories = list('abc')

In [3]: cat = pd.Series(list('aba'))

In [4]: cat = cat.astype(pd.CategoricalDtype(categories=possible_categories))

In [5]: cat
Out[5]: 
0    a
1    b
2    a
dtype: category
Categories (3, object): [a, b, c]

然后,get_dummies将完全按照您的意愿行事!

In [6]: pd.get_dummies(cat)
Out[6]: 
   a  b  c
0  1  0  0
1  0  1  0
2  1  0  0

还有很多其他方法可以创建分类Seriesor DataFrame,这只是我觉得最方便的一种。您可以在pandas 文档中阅读所有这些内容。

编辑:

我没有遵循确切的版本控制,但是 pandas 如何处理稀疏矩阵存在一个错误,至少在 0.17.0 版本之前是这样。它已被版本 0.18.1(2016 年 5 月发布)更正。

对于 0.17.0 版本,如果您尝试使用sparse=True带有 a 的选项来执行此操作DataFrame,则缺少的虚拟变量的零列将是一列NaN,并且它将被转换为密集的。

看起来 pandas 0.21.0 添加了 a CategoricalDType,并且创建明确包含原始答案中的类别的分类已被弃用,我不太确定何时。

于 2016-05-26T04:53:38.597 回答
36

使用转置和重新索引

import pandas as pd

cats = ['a', 'b', 'c']
df = pd.DataFrame({'cat': ['a', 'b', 'a']})

dummies = pd.get_dummies(df, prefix='', prefix_sep='')
dummies = dummies.T.reindex(cats).T.fillna(0)

print dummies

    a    b    c
0  1.0  0.0  0.0
1  0.0  1.0  0.0
2  1.0  0.0  0.0
于 2016-05-25T02:49:08.253 回答
4

我确实在 pandas github 上问过这个问题。Categorical事实证明,当您将列定义为定义所有可能类别的位置时,很容易绕过它。

df['col'] = pd.Categorical(df['col'], categories=['a', 'b', 'c', 'd'])

get_dummies()将按预期完成其余的工作。

于 2018-07-27T13:33:50.183 回答
4

尝试这个:

In[1]: import pandas as pd
       cats = ["a", "b", "c"]

In[2]: df = pd.DataFrame({"cat": ["a", "b", "a"]})

In[3]: pd.concat((pd.get_dummies(df.cat, columns=cats), pd.DataFrame(columns=cats))).fillna(0)
Out[3]: 
     a    b    c
0  1.0  0.0  0
1  0.0  1.0  0
2  1.0  0.0  0
于 2016-05-25T01:01:59.513 回答
3

我不认为get_dummies它提供了开箱即用的功能,它只允许创建一个column突出NaN值的额外功能。

要自己添加缺失的columns内容,您可以使用pd.concat沿着axis=0垂直“堆叠” DataFrames(虚拟列加上 a DataFrame id)并自动创建任何缺失的列,用于fillna(0)替换缺失值,然后再次.groupby('id')用于分隔各个列DataFrame

于 2016-05-25T00:38:28.657 回答
2

在测试集中添加缺失的类别:

# Get missing columns in the training test
missing_cols = set( train.columns ) - set( test.columns )
# Add a missing column in test set with default value equal to 0
for c in missing_cols:
    test[c] = 0
# Ensure the order of column in the test set is in the same order than in train set
test = test[train.columns]

请注意,此代码还删除了从测试数据集中的类别产生的列,但在训练数据集中不存在

于 2017-07-28T05:07:56.500 回答
2

正如其他人所建议的 - 将您的分类特征转换为“类别”数据类型应该使用“ get_dummies ”解决看不见的标签问题。

# Your Data frame(df)
from sklearn.model_selection import train_test_split
X = df.loc[:,df.columns !='label']
Y = df.loc[:,df.columns =='label']

# Split the data into 70% training and 30% test
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.3) 

# Convert Categorical Columns in your data frame to type 'category'
for col in df.select_dtypes(include=[np.object]).columns:
    X_train[col] = X_train[col].astype('category', categories = df[col].unique())
    X_test[col] = X_test[col].astype('category', categories = df[col].unique())

# Now, use get_dummies on training, test data and we will get same set of columns
X_train = pd.get_dummies(X_train,columns = ["Categorical_Columns"])
X_test = pd.get_dummies(X_test,columns = ["Categorical_Columns"])
于 2018-12-27T18:42:03.470 回答
2

越短越好:

import pandas as pd

cats = pd.Index(['a', 'b', 'c'])
df = pd.DataFrame({'cat': ['a', 'b', 'a']})

pd.get_dummies(df, prefix='', prefix_sep='').reindex(columns = cats, fill_value=0)

结果:

    a   b   c
0   1   0   0
1   0   1   0
2   1   0   0

笔记:

  • cats需要是熊猫索引
  • prefix=''并且prefix_sep=''需要设置才能使用您首先定义的猫类别。否则,get_dummies转换为:cats_acats_b) cats_c。对我来说这更好,因为它是明确的。
  • 使用 fill_value=0 转换NaNfrom 列c。或者,您可以fillna(0)在句末使用。(我不知道哪个更快)。

这是一个更短的版本(更改了索引值):

import pandas as pd

cats = pd.Index(['cat_a', 'cat_b', 'cat_c'])
df = pd.DataFrame({'cat': ['a', 'b', 'a']})

pd.get_dummies(df).reindex(columns = cats, fill_value=0)

结果:

    cat_a   cat_b   cat_c
0   1         0     0
1   0         1     0
2   1         0     0

奖金轨道!

我想你有这些类别,因为你以前使用训练数据做了一个虚拟/一个热门。您可以保存原始编码(.columns),然后在生产期间应用:

cats = pd.Index(['cat_a', 'cat_b', 'cat_c']) # it might come from the original onehot encoding (df_ohe.columns)

import pickle

with open('cats.pickle', 'wb') as handle:
    pickle.dump(cats, handle, protocol=pickle.HIGHEST_PROTOCOL)


with open('cats.pickle', 'rb') as handle:
    saved_cats = pickle.load(handle)



df = pd.DataFrame({'cat': ['a', 'b', 'a']})

pd.get_dummies(df).reindex(columns = saved_cats, fill_value=0)

结果:

    cat_a   cat_b   cat_c
0   1         0     0
1   0         1     0
2   1         0     0
于 2020-06-13T22:27:37.070 回答
1

如果您知道您的类别,您可以pd.get_dummies()按照您的建议先申请,然后添加缺少的类别列。

这将创建缺少的示例cat_c

import pandas as pd

categories = ['a', 'b', 'c']
df = pd.DataFrame(list('aba'), columns=['cat'])
df = pd.get_dummies(df)

print(df)

   cat_a  cat_b
0      1      0
1      0      1
2      1      0

现在只需使用联合操作添加缺少的类别列(如此处建议)。

possible_categories = ['cat_' + cat for cat in categories]

df = df.reindex(df.columns.union(possible_categories, sort=False), axis=1, fill_value=0)

print(df)

   cat_a  cat_b  cat_c
0      1      0      0
1      0      1      0
2      1      0      0

于 2020-12-01T11:59:32.627 回答
0

我最近希望解决同样的问题,但使用多列数据框和两个数据集(用于机器学习任务的训练集和测试集)。测试数据帧与训练数据帧具有相同的分类列,但其中一些列缺少训练数据帧中存在的类别。

我不想为每一列手动定义所有可能的类别。相反,我将训练和测试数据帧合并为一个,称为 get_dummies,然后将其拆分回两个。

# train_cat, test_cat are dataframes instantiated elsewhere

train_test_cat = pd.concat([train_cat, test_cat]
tran_test_cat = pd.get_dummies(train_test_cat, axis=0))

train_cat = train_test_cat.iloc[:train_cat.shape[0], :]
test_cat = train_test_cat.iloc[train_cat.shape[0]:, :]
于 2020-06-23T16:16:41.107 回答