在对分类特征进行处理时,我们经常会把这类特征转成独热编码(onehot)
在sklearn中有OneHotEncoder,但是使用比较麻烦,万幸是pandas有对应的get_dummies
pandas.
get_dummies
(data, prefix=None, prefix_sep='_', dummy_na=False, columns=None, sparse=False, drop_first=False, dtype=None)[source]Convert categorical variable into dummy/indicator variables
使用get_dummies可以参考pandas文档,这里不做赘述
这里讲讲我在ML项目中使用独热编码遇到的一些坑和解决办法。
问题:拆分训练集和测试集之后各自dummy,因为有些特征可能只在两个set各自出现,于是会导致两个集的特征不一致
我参考了这篇的解决办法
第一种办法
合并进行dummy,pd.concat(( train, test ))
, get_dummies()
,之后再拆分train test set
第二种办法
对测试集的特征进行处理,如果存在 在训练集出现但在测试集中没有出现的特征值,就补充该dummy列且填充0,如果出现在测试集出现但在训练集没出现的特征值,那么就删除。
这种办法实际上就是以训练集特征值为准,少补多删
#columns是训练集经过dummy的feature名,d是测试集经过dummy之后的数据集
#这个函数增加缺少的dummy列
def add_missing_dummy_columns( d, columns ):
missing_cols = set( columns ) - set( d.columns )
for c in missing_cols:
d[c] = 0
def fix_columns( d, columns ):
#增加缺少的dummy列
add_missing_dummy_columns( d, columns )
# make sure we have all the columns we need
assert( set( columns ) - set( d.columns ) == set())
extra_cols = set( d.columns ) - set( columns )
if extra_cols:
print "extra columns:", extra_cols
d = d[ columns ]
return d
因为我的某些特征值有上千个,这样dummy就会多了上千个的特征,经过训练集和测试集特征一致化后,在xgb运行时会报如下错ValueError: feature_names mismatch
ValueError: feature_names mismatch
但实际上特征名应该是match的,我在google上搜到了这篇stackoverflow,发现问题差不多,xbgoost的GitHub 上也有这个issue
这个bug实际上很蠢。。就是应该传numpy的矩阵格式,所以使用dataframe.values转换一下即可
贴一下我自己的dummy特征一致化过程代码:
主要流程:
1 训练集和测试集分别dummy
2 把训练集多的特征值feature加到测试集上
3 把测试集多的特征值feature删掉
4 测试两个features集是否一致
#deel with dummy features
X_train = pd.get_dummies(X_train,columns=['xkkh','zy','xy','constellation','course_type','zzmm','instituteType','xb'])
X_test = pd.get_dummies(X_test,columns=['xkkh','zy','xy','constellation','course_type','zzmm','instituteType','xb'])
#X_test = X_test[X_train.columns]
miss_columns = set(X_train.columns) - set(X_test.columns)
#add missing dummy columns
for col in miss_columns:
X_test[col] = 0
adu_columns = set(X_test.columns) - set(X_train.columns)
#delete adundant columns:
X_test.drop(list(adu_columns),axis=1,inplace=True)
print("after deeling with dummy columns,trainset and testset keep same:",set(X_train.columns)-set(X_test.columns) == set([]))