我有一个包含分类因子的模型。我使用pandas.get_dummies
将其编码为独热编码。
然而,该分类因子有许多不常见的级别。如果我使用pandas.get_dummies
重新编码新数据,新的列可能会“失效”,因为新的级别不会出现在新数据中。
我在考虑这样做:
dummies_df = pd.get_dummies(list_of_all_possible_levels)
dummies_df[:] = 0
dummies_df.drop(dummies_df.index[1:], inplace=True)
# 如果有10个级别,这将成为一个10x10的DataFrame。我只需要
# 一个“空”行并删除第一行之后的所有行。
# 假设DataFrame看起来像这样:
df['categorical_factor', 'numeric_factor', 'other_numeric_factor']
# 我想做一些事情来标记特征的列为1
# 并将单行dummies_df附加到df的每一行
for cat in df.categorical_factor:
dummies_df[cat] = 1
df['numeric_factor', 'other_numeric_factor'] + dummies_df
我只是在想是否应该这样遍历行,还是有更好的“笛卡尔积”类型的答案。如果这是R语言,我会使用cbind(df, dummies_df)
,因为R知道如何循环使用dummies_df
的值。
或者也许我应该在新数据上使用pandas.get_dummies
,并像这样将缺失的级别作为新列加入:
new_dat['missing_level_1'] = [0 for _ in new_dat.index]
new_dat['missing_level_2'] = [0 for _ in new_dat.index]
编辑:样本数据
levels=['level_1', 'level_2', 'level_3']
A = [0,1,2]
B = [3,4,5]
df = pd.DataFrame({'levels': levels, 'A': A, 'B': B})
df = df.drop('levels', axis=1).join(pd.get_dummies(df.levels))
new_levels=['level_1', 'level_2', 'level_2']
new_A = [5,6,7]
new_B = [8,9,7]
new_df = pd.DataFrame({'levels': new_levels, 'A': new_A, 'B': new_B})
new_df = new_df.drop('levels', axis=1).join(pd.get_dummies(new_df.levels))
df
现在是
+---------+---+---+---------+---------+---------+
| (index) | A | B | level_1 | level_2 | level_3 |
+---------+---+---+---------+---------+---------+
| 0 | 0 | 3 | 1 | 0 | 0 |
| 1 | 1 | 4 | 0 | 1 | 0 |
| 2 | 2 | 5 | 0 | 0 | 1 |
+---------+---+---+---------+---------+---------+
而new_df
现在是
+---------+---+---+---------+---------+
| (index) | A | B | level_1 | level_2 |
+---------+---+---+---------+---------+
| 0 | 5 | 8 | 1 | 0 |
| 1 | 6 | 9 | 0 | 1 |
| 2 | 7 | 7 | 0 | 1 |
+---------+---+---+---------+---------+
(它缺少level_3
列。)
我希望new_df
变成
+---------+---+---+---------+---------+---------+
| (index) | A | B | level_1 | level_2 | level_3 |
+---------+---+---+---------+---------+---------+
| 0 | 5 | 8 | 1 | 0 | 0 |
| 1 | 6 | 9 | 0 | 1 | 0 |
| 2 | 7 | 7 | 0 | 1 | 0 |
+---------+---+---+---------+---------+---------+
回答:
最稳定的解决方案是reindex
虚拟变量的DataFrame。
当你编码第一个(原型)DataFrame时,你会记住虚拟列的列表:
# 初始编码
levels=['level_1', 'level_2', 'level_3']
df_original = pd.DataFrame({'levels': levels, 'A': [0,1,2], 'B': [3,4,5]})
dummies = pd.get_dummies(df_original.levels)
df = df_original.drop('levels', axis=1).join(dummies)
# 记住级别及其顺序
dummy_columns = list(dummies.columns)
之后,你强制你的新虚拟DataFrame具有相同的列:
# 编码另一个DataFrame
new_levels=['level_1', 'level_2', 'level_2']
new_df_original = pd.DataFrame({'levels': new_levels, 'A': [5,6,7], 'B': [8,9,7]})
# 这是我使用记住的信息的地方
new_dummies = pd.get_dummies(new_df_original.levels). \
reindex(columns=dummy_columns).fillna(0).astype(int)
new_df = new_df_original.drop('levels', axis=1).join(new_dummies)
print(new_df)
这将给出你想要的结果:
A B level_1 level_2 level_3
0 5 8 1 0 0
1 6 9 0 1 0
2 7 7 0 1 0