python学习09之分类变量

  本次学习,我们将了解什么是分类变量以及处理这类数据的三种方法。

  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())

    接下来,我们获得训练数据中所有分类变量的列表。

       我们通过检查每个列的数据类型(或dtype)来做到这一点。
      对象dtype表示列中有文本(理论上它还可以有其他内容,但这对我们的目的并不重要)。  
      对于这个数据集,带有文本的列表示分类变量。
#获取分类变量列表
s = (X_train.dtypes == 'object')
object_cols = list(s[s].index)

print("Categorical variables:")
print(object_cols)

  4、定义功能来度量每种方法的质量

     我们定义了一个函数score_dataset()来比较处理分类变量的三种不同方法。该函数报告随机森林模型的平均绝对误差(MAE)。一般来说,我们希望MAE尽可能低!
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)的性能最差,但具体情况有所不同。

本次学习到此结束!!!!!

原文地址:https://www.cnblogs.com/fb1704011013/p/11196714.html