适合阅读人群:想初步了解分类变量的处理。
什么叫categorical data分类变量?
分类变量(categorical variable)是说明事物类别的一个名称。 比如“性别”就是一个分类变量,他的值为“男”或“女”;“品牌”也是一个分类变量,值可以是“LV”、”爱马仕”、“Gucci”等; 衣服尺寸也是分类变量:比如,XS、S、M、L。
那这种在建模型的时候,要怎么处理那?
我们先看看,变量有几种类型,然后我们再看看怎么处理分类变量的类型。
生活中的变量:
我们在日常生活中,我们通常归类成2大类变量。
一个是数值类的,比如年龄,身高,交过女朋友数量,通常由阿拉伯数字组成。
第二种分类变量,比如性别,爱好,喜欢的明星,通常是语言文字表示。
统计中变量
但是在统计中,我们却严谨的多。
在统计中,我们分成4大类:
Nominal;Ordinal;Interval;Ratio
来一张图总结一下:
这4种类型和我们生活中理解的类型有什么区别吗?
当然有。
(1) Norminal Data 定类变量:变量的不同取值仅仅代表了不同类的事物,这样的变量叫定类变量。问卷的人口特征中最常使用的问题,而调查被访对象的“性别”,就是 定类变量。对于定类变量,加减乘除等运算是没有实际意义的。
(2) Ordinal Data定序变量:变量的值不仅能够代表事物的分类,还能代表事物按某种特性的排序,这样的变量叫定序变量。问卷的人口特征中最常使用的问题“教育程度“,以及态度量表题目等都是定序变量,定序变量的值之间可以比较大小,或者有强弱顺序,但两个值的差一般没有什么实际意义。
(3)Interval Data 定距变量:变量的值之间可以比较大小,两个值的差有实际意义,这样的变量叫定距变量。有时问卷在调查被访者的“年龄”和“每月平均收入”,都是定距变量。
(4) Ratio Data 定比变量, 有绝对0点,如质量,高度。定比变量与定距变量在市场调查中一般不加以区分,它们的差别在于,定距变量取值为“0”时,不表示“没有”,仅仅是取值为0。定比变量取值为“0”时,则表示“没有”。
这4种类型在machine learning 中,需要区分吗?
当然需要。
由于我们这篇讲categorical data 的处理,那我们讲一下nominal 和 ordinal的区别和实际python code。
一张总结一下:
一、如果我们想处理这类变量,达到下面的效果:
1)用pandas 自带的map:
Sex
map
import pandas as pd
df = pd.read_csv('data/titanic.csv')
df = df.dropna(how = 'any').reset_index(drop = True)
df['Sex_map'] = df['Sex'].map({'male':1,'female':0})
df.head()
2)用Pandas 自带的astype(注:仅适用于该变量只有2个unique value)
Sex
astype int
import pandas as pd
df = pd.read_csv('data/titanic.csv')
df = df.dropna(how = 'any').reset_index(drop = True)
df['Sex_astype'] = pd.Series(df['Sex'] == 'male').astype(int)
df.head()
3)用Sklearn的LabelEncoder
- train dataset
Sex
LabelEncoder
Train dataset
import pandas as pd
df = pd.read_csv('data/titanic.csv')
df = df.dropna(how = 'any').reset_index(drop = True)from sklearn.preprocessing import LabelEncoder
gle = LabelEncoder()
sex_labels = gle.fit_transform(df['Sex'])
df['Sex_labelencoder'] = sex_labels
df.head()
-test dataset
Sex
LabelEncoder
Test dataset
import pandas as pd
df_test = pd.read_csv('data/titanic_test.csv')
df_test = df_test.dropna(how = 'any').reset_index(drop = True)from sklearn.preprocessing import LabelEncoder
sex_labels = gle.transform(df_test['Sex'])
df_test['Sex_labelencoder'] = sex_labels
df_test.head()
二、如果我们想处理这类变量,达到下面的效果:
1)用pandas 自带的 pd.get.dummies()
Sex
get dummies
import pandas as pd
df = pd.read_csv('data/titanic.csv')
df = df.dropna(how = 'any').reset_index(drop = True)import pandas as pd
df = pd.read_csv('data/titanic.csv')
df = df.dropna(how = 'any').reset_index(drop = True)
pd.concat([df,pd.get_dummies(df['Sex'])],axis = 1).head()
注意:这里可以pd.get_dummie(drop= True) 将其中一列移除。
2)用Sklearn自带的 OneHotEncoder()
-Train dataset
Sex
get OneHotEncoder
Train dataset
import pandas as pd
df = pd.read_csv('data/titanic.csv')
df = df.dropna(how = 'any').reset_index(drop = True)from sklearn.preprocessing import OneHotEncoder
ohe = OneHotEncoder()
sex_ohe = ohe.fit_transform(df[['Sex']]).toarray()
sex_ohe_df = pd.DataFrame(sex_ohe, columns= ohe.get_feature_names())
pd.concat([df,sex_ohe_df],axis = 1).head()
-Test dataset
Sex
get OneHotEncoder
Test dataset
import pandas as pd
df_test = pd.read_csv('data/titanic_test.csv')
df_test = df.dropna(how = 'any').reset_index(drop = True)from sklearn.preprocessing import OneHotEncoder
sex_ohe = ohe.transform(df_test[['Sex']]).toarray()
sex_ohe_df = pd.DataFrame(sex_ohe, columns= ohe.get_feature_names())
pd.concat([df_test,sex_ohe_df],axis = 1)
三、下面看看如果变量值比较多的情况:
这种情况,用pandas 的map和astype 显然不合适。
因为写map的时候,比如把所有情况,手动输入{上海:1, 北京:2,深圳:3....}
1)这时候比较可行的是 Sklearn 的LabelEncoder
-Train dataset
Cabin
LabelEncoder
Train dataset
import pandas as pd
df = pd.read_csv('data/titanic.csv')
df = df.dropna(how = 'any').reset_index(drop = True)from sklearn.preprocessing import LabelEncoder
gle = LabelEncoder()
cabin_labels = gle.fit_transform(df['Cabin'])
df['Cabin_labelencoder'] = cabin_labels
df.head()
-Test dataset
Cabin
LabelEncoder
Test
import pandas as pd
df_test = pd.read_csv('data/titanic_test.csv')
df_test = df_test.dropna(how = 'any').reset_index(drop = True)from sklearn.preprocessing import LabelEncoder
cabin_labels = gle.transform(df_test['Cabin'])
df_test['Cabin_labelencoder'] = cabin_labels
df_test.head()
四、如果想这样变化:
1)pandas 自带的pd.get_dummies()
Train dataset
Cabin
get_dummies
Train
import pandas as pd
df = pd.read_csv('data/titanic.csv')
df = df.dropna(how = 'any').reset_index(drop = True)pd.concat([df,pd.get_dummies(df['Cabin'])],axis = 1).head()
- Test dataset
Cabin
get_dummies
Test
import pandas as pd
df_test = pd.read_csv('data/titanic_test.csv')
df_test = df_test.dropna(how = 'any').reset_index(drop = True)pd.concat([df_test,pd.get_dummies(df_test['Cabin'])],axis = 1).head()
我们比较发现,适用dummy的时候,test dataset 并不会把所有的train dataset值都变成column的title,dummy只会显示test dataset里面的值。所以在build model时候,并不适用dummy来处理。
2)Pandas自带的OnehotEncoder
- Train dataset
Cabin
Onehot
Train
import pandas as pd
df = pd.read_csv('data/titanic.csv')
df = df.dropna(how = 'any').reset_index(drop = True)from sklearn.preprocessing import OneHotEncoder
ohe = OneHotEncoder()
cabin_ohe = ohe.fit_transform(df[['Cabin']]).toarray()
cabin_ohe_df = pd.DataFrame(cabin_ohe, columns= ohe.get_feature_names())
pd.concat([df,cabin_ohe_df],axis = 1).head()
- Test Dataset
Cabin
Onehot
Test
import pandas as pd
df_test = pd.read_csv('data/titanic_test.csv')
df_test = df_test.dropna(how = 'any').reset_index(drop = True)from sklearn.preprocessing import OneHotEncoder
ohe = OneHotEncoder()
cabin_ohe = ohe.transform(df_test[['Cabin']]).toarray()
cabin_ohe_df = pd.DataFrame(cabin_ohe, columns= ohe.get_feature_names())
pd.concat([df_test,cabin_ohe_df],axis = 1).head()
我们发现OnehotEncoder 能很好的解决dummy不能达到的要求。
所以,
通常情况下,我们会用OneHot 来处理Nominal 类型, LabelEncoder 来处理Ordinal类型
五、一些特殊处理:
我们想想,如果我有300个城市,如果都用Onehot做,是不是变量太多了?
那怎么解决?
我们可以用bin counting
bin_counting
game = pd.read_csv('data/vgsales.csv')
game[['Name', 'Genre']].head()
game.Genre.unique()
train
from sklearn.feature_extraction import FeatureHasher
fh = FeatureHasher(n_features=6, input_type='string')
hashed_features = fh.fit_transform(game['Genre'])
hashed_features = hashed_features.toarray()
pd.concat([game[['Name', 'Genre']], pd.DataFrame(hashed_features)], axis=1).head()
test
game_test = pd.read_csv('data/vgsales_test.csv')
from sklearn.feature_extraction import FeatureHasher
fh = FeatureHasher(n_features=6, input_type='string')
hashed_features = fh.transform(game_test['Genre'])
hashed_features = hashed_features.toarray()
pd.concat([game_test[['Name', 'Genre']], pd.DataFrame(hashed_features)], axis=1).head()
我们用5个变量代表了原来要用onehot代表的12个变量。
六、我们再想想,如果我有300个城市,还有没有其他的方法可以来描述这300个城市,让他们显得更有意义。
比如,我想预测某个城市的房价,我有几房几厅,是不是在市中心,交通是不是方便,哪个城市;
如果我把城市换成其他更有意义的变量是不是更好?比如:
Target encoding
pip install category_encoders
import pandas as pd
import category_encoders as cedata = pd.DataFrame({'City' : ['Shanghai', 'Beijing', 'Shanghai', 'ShengZheng', 'Shengzheng', 'Beijing', "Beijing"],
'Income' : [70000, 64000, 72000, 59000, 57000, 67000, 62000]})
data
train
encoder = ce.target_encoder.TargetEncoder(cols=['City'])
encoder.fit(data['City'], data['Income'])
data['City_encoder'] = encoder.transform(data['City'])
data
test
data_test = pd.DataFrame({'City' : ['Shanghai', 'Beijing', 'Shanghai', 'Shengzheng']})
data_test['City_encoder'] = encoder.transform(data_test['City'])
data_test
完。