本次学习,我们将了解什么是分类变量以及处理这类数据的三种方法。
1、介绍
分类变量只接受有限数量的值。
考虑一项调查,询问你多久吃一次早餐,并提供四个选项:“从不”、“很少”、“大多数日子”或“每天”。
在本例中,数据是分类的,因为响应属于一组固定的类别。如果人们对他们所拥有的汽车品牌进行调查,他们的回答可以分为“本田”、“丰田”和“福特”。
在本例中,数据也是分类的。如果我们试图在没有预先处理这些变量的情况下将这些变量插入Python中的大多数机器学习模型中,那么我们将会得到一个错误。
2、三种方法的使用
1)、删除分类变量
处理分类变量最简单的方法是从数据集中删除它们。这种方法只有在列中不包含有用信息的情况下才能很好地工作。
2)、标签的编码
标签编码将每个惟一值分配给不同的整数。
这种方法假设类别的顺序为:“Never”(0)<“rare”(1)<“Most days”(2)<“Every day”(3)。
在本例中,这个假设是有意义的,因为对类别有一个无可争议的排名。
并不是所有的分类变量在值中都有一个明确的顺序,但是我们将那些有顺序的变量称为有序变量。
对于基于树的模型(如决策树和随机森林),可以期望标签编码能够很好地处理有序变量。
3)、独热编码
独热编码创建新列,指示原始数据中每个可能值的存在(或不存在)。
为了理解这一点,我们将通过一个例子:
在原始数据集中,“颜色”是一个类别变量,有三个类别:“红色”、“黄色”和“绿色”。
对应的独热编码包含每个可能值的一列,以及原始数据集中每行的一行。当原值为“红色”时,我们在“红色”列中加1;如果原值为“黄色”,我们在“黄色”列中加1,依此类推。
与标签编码不同,一个热编码不假定类别的顺序。
因此,如果分类数据中没有明确的顺序(例如,“红色”既不大于也不小于“黄色”),您可以期望这种方法特别有效。
我们把没有内在排序的分类变量称为名义变量。
如果类别变量具有大量值(即,通常不会将其用于超过15个不同值的变量),则一个热编码通常无法很好地执行。
3、举例说明
和上一次的学习一样,我们将使用墨尔本住房的数据集
import pandas as pd from sklearn.model_selection import train_test_split #读取数据 data = pd.read_csv('E:/data_handle/melb_data.csv') #从预测器中分离目标 y =data.Price X = data.drop(['Price'],axis=1) #将数据划分为训练和验证子集 X_train_full, X_valid_full, y_train, y_valid = train_test_split(X, y, train_size=0.8,test_size=0.2,random_state=0) #删除有缺少值得列 cols_with_missing = [col for col in X_train_full.columns if X_train_full[col].isnull().any()] X_train_full.drop(cols_with_missing, axis=1, inplace=True) X_valid_full.drop(cols_with_missing, axis=1, inplace=True) #“基数”是指列中唯一的数目 #选择技术相对较低的分类列(方便但随意) low_cardinality_cols = [cname for cname in X_train_full.columns if X_train_full[cname].dtype == 'object'] #选择数字列 numerical_cols = [cname for cname in X_train_full.columns if X_train_full[cname].dtype in ['int64', 'float64']] #仅仅保留所选列 my_cols = low_cardinality_cols + numerical_cols X_train = X_train_full[my_cols].copy() X_valid = X_valid_full[my_cols].copy() #打印前五行数据 print(X_train.head())
接下来,我们获得训练数据中所有分类变量的列表。
#获取分类变量列表 s = (X_train.dtypes == 'object') object_cols = list(s[s].index) print("Categorical variables:") print(object_cols)
4、定义功能来度量每种方法的质量
def score_dataset(X_train, X_valid, y_train, y_valid): model = RandomForestRegressor(n_estimators=100, random_state=0) model.fit(X_train,y_train) preds = model.predict(X_valid) return mean_absolute_error(y_valid,preds)
5、三种方法的MAE得分
1)、第一种方法
#方法一求取MAE的值 drop_X_train = X_train.select_dtypes(exclude=['object']) drop_X_valid = X_valid.select_dtypes(exclude=['object']) print("MAE from Approach 1 (Drop categorical variables):") print(score_dataset(drop_X_train, drop_X_valid, y_train, y_valid))
2)、第二种方法
#复制以避免更改原始数据 label_X_train = X_train.copy() label_X_valid = X_valid.copy() #将标签编码器应用于每一列与分类数据 label_encoder = LabelEncoder() for col in object_cols: label_X_train[col] = label_encoder.fit_transform(X_train[col]) label_X_valid[col] = label_encoder.transform(X_valid[col]) print("MAE from Approach 2 (Label Encoding):") print(score_dataset(label_X_train, label_X_valid, y_train, y_valid))
在上面的代码单元格中,对于每一列,我们将每个惟一的值随机分配给一个不同的整数。
这是一种比提供自定义标签更简单的常见方法;然而,如果我们为所有有序变量提供更好的信息标签,我们可以期望额外的性能提升。
但是第二种方法我出现了bug,暂时还未解决,解决ing
3)、第三种方法
独热编码:
我们使用来自scikit-learn的OneHotEncoder类来获得一次热编码。
有许多参数可用于自定义其行为。
当验证数据包含训练数据中没有表示的类时,我们设置handle_unknown='ignore'以避免错误,而设置sparse=False确保以numpy数组(而不是稀疏矩阵)的形式返回编码的列。
要使用编码器,我们只提供我们希望进行单热编码的分类列。
例如,为了编码训练数据,我们提供X_train[object_cols]。(下面代码单元格中的object_cols是包含分类数据的列名列表,因此X_train[object_cols]包含训练集中的所有分类数据。)
#方法三求取MAE的值 #对每个列应用独热编码器,其中包含分类数据 OH_encoder = OneHotEncoder(handle_unknown='ignore', sparse=False) OH_cols_train = pd.DataFrame(OH_encoder.fit_transform(X_train[object_cols])) OH_cols_valid = pd.DataFrame(OH_encoder.transform(X_valid[object_cols])) #独热编码删除索引;并放回原处 OH_cols_train.index = X_train.index OH_cols_valid.index = X_valid.index #删除分类列(将替换为独热编码) num_X_train = X_train.drop(object_cols, axis=1) num_X_valid = X_valid.drop(object_cols, axis=1) #向数值特性添加独热编码列 OH_X_train = pd.concat([num_X_train, OH_cols_train], axis=1) OH_X_valid = pd.concat([num_X_valid, OH_cols_valid], axis=1) print("MAE from Approach 3 (One-Hot Encoding):") print(score_dataset(OH_X_train, OH_X_valid, y_train, y_valid))
5、总结
哪种方法最好?
在本例中,删除分类列(方法1)的性能最差,因为它有最高的MAE得分。
至于另外两种方法,由于返回的MAE分数非常接近,因此其中一种方法对另一种方法似乎没有任何有意义的好处。
通常,独热编码(方法3)的性能最好,而删除分类列(方法1)的性能最差,但具体情况有所不同。
本次学习到此结束!!!!!