0%

Categorical Feature Encoding

记录来自Kaggle的一次playground competition(Categorical Feature Encoding Challenge);备注,Kaggle比赛分类以下几种类型,摘抄自知乎回答

  • Getting Started(面向初学者),非常适合入门级的参赛者用来练手,但没有奖牌或奖金,只能看到自己的排名
  • Playground(面向初学者),项目难度比Getting Started稍难,主要是一些趣味性的比赛,看创意而不是解决具体的研究问题,奖励可能是奖金、荣誉,不能获得奖牌
  • Featured(面向竞赛者),是Kaggle上主要的竞赛类型,为解决商业问题而设立的比赛,奖金高竞争激烈,有金银铜牌奖励,对参赛选手的能力有一定的要求
  • Research(面向竞赛者),致力于解决科研界学术界的前沿问题,偏向于实验性质,较难;竞争没那么激烈,通常也有奖金和金银铜牌,但有的比赛只给荣誉奖励,或者是提供参加顶会的机会
  • Recruitment(面向求职者),赞助商为招聘数据科学家而设立的比赛,奖励就是赞助商提供的工作机会
  • Annual,不是严格意义上的比赛,每年两次,一次是美国大学篮球锦标赛期间的三月机器学习比赛,一次是圣诞节期间的圣诞主题优化比赛
  • Limited participation,通常是私人赛或邀请赛,例如只有master级别及以上才能参加的Master's Competition

个人Notebook地址如下:Encoding for category in my learning


通过此次competition,我才接触到多种分类变量的encoding方法,并不局限于常用的one-hot-encoding

Binary data

对于Binary data,即常见的只有两个分类值的变量,如1/0;比如简单的将bin_4列的Y/N变成1/0,则:

X = pd.DataFrame({'col' : ['Y', 'N', 'Y', 'N']})
X.col = X.col.apply(lambda x: 1 if x == "Y" else 0)

Ordinal data

对于Ordinal data,即有序变量,如low/median/high;比如将ord_1列中的值转为数值型,则用replace替换下即可:

df = pd.DataFrame({'col' : ['low', 'median', 'low', 'high']})
df.col.replace(to_replace = ['low', 'median','high'],
                         value = [0, 1, 2], inplace = True)

还可以利用LabelEncoder()将其转换成连续的数值型变量,即是对不连续的数字或者文本进行编号,如:

from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
le.fit_transform(['a', 'c', 'b', 'd', 'a', 'b'])
>> array([0, 2, 1, 3, 0, 1], dtype=int64)

还有一种常用的方法是使用OrdinalEncoder(),将分类变量编码为整数,如:

from sklearn.preprocessing import OrdinalEncoder
oe = OrdinalEncoder(categories='auto')
X = [['Male', 1], ['Female', 3], ['Female', 2]]
oe.fit_transform(X)

从上可看出,LabelEncoderOrdinalEncoder都可以将字符转成数字,两者的差别在于前者的输入为1维数据,后者的输入则可以为多维数据

Nominal data

对于Nominal data,即无序变量,如颜色red/green/blue等等,常见的一般用one-hot-encoding,对应numpy则是OneHotEncoder方法,对应pandas则是get_dummies

个人比较喜欢用get_dummies,因为使用方便。。。

df = pd.DataFrame({'A': ['a', 'b', 'a'], 'B': ['b', 'a', 'c'], 'C': [1, 2, 3]})
pd.get_dummies(df)
>>   C  A_a  A_b  B_a  B_b  B_c
  0  1    1    0    0    1    0
  1  2    0    1    1    0    0
  2  3    1    0    0    0    1

默认是只对object或者category类型的列进行encoding,除非通过columns参数指定了一些数值型的列

pd.get_dummies(df, columns=['A', 'B', 'C'])

还可以通过sparse参数将其转化为SparseArray(稀疏数组),以减少计算内存,并且转化为Compressed Sparse Row format,如:

dummies = pd.get_dummies(data, columns=columns, sparse=True)
X = dummies.sparse.to_coo().tocsr()
X = X.astype("float32")

也可以通过drop_first参数将K个dummies减少为k-1个

有时还会遇到训练集和测试集中的某列分类数据不一致,也就是说有些features可能只在两个数据集中各自出现,于是会导致两个数据集的特征不一致

这时比较常用的解决办法则是通过pd.concat将两个数据集的行合并一起,然后再拆分开,如:

data = pd.concat([X_train, X_test])
dummies = pd.get_dummies(data, columns=data.columns, sparse=True)
X_train = dummies.iloc[:X_train.shape[0], :]
X_test = dummies.iloc[X_train.shape[0]:, :]

Other encoding

除了上述encoding方法外,还有对于high-cardinality features,可以用:

  • feature_extraction模块的FeatureHasher,即将字符串特征的序列转换为scipy.sparse矩阵
  • category_encoders模块的LeaveOneOutEncoder,即用Bayesian方法来Encoding(具体的不是太理解),

注:category_encoders模块封装了多种encoder例子,具体可以看Category Encoders Examples,作者做了整理,如:

import category_encoders as ce
  • Classic Encoders
    • sklearn.preprocessing.LabelEncoder()
    • Ordinal,ce.OrdinalEncoder
    • One-Hot,ce.OneHotEncoder
    • Binary,ce.BinaryEncoder
    • BaseN,ce.BaseNEncoder
    • Hashing, ce.HashingEncoder
  • Contrast Encoders
    • Helmert,ce.HelmertEncoder
    • Sum,ce.SumEncoder
    • Backward Difference,ce.BackwardDifferenceEncoder
    • Polynomial,ce.PolynomialEncoder
  • Bayesian Encoders
    • Target,ce.TargetEncoder
    • LeaveOneOut,ce.LeaveOneOutEncoder
    • WeightOfEvidence,ce.WeightOfEvidenceEncoder

以上方法众多,以后得再琢磨琢磨下。。。

本文出自于http://www.bioinfo-scrounger.com转载请注明出处