记录来自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)
从上可看出,LabelEncoder
和OrdinalEncoder
都可以将字符转成数字,两者的差别在于前者的输入为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转载请注明出处