Kaggle学习笔记——Categorical Variables


kaggle课程连接 https://www.kaggle.com/learn/intermediate-machine-learning.

简介

本次练习介绍三种处理数据中的分类变量(即类型为object的变量)的方法。
方法一、删除分类变量

  • 处理分类变量的最简单方法是从数据集中删除它们。仅当列中没有有用的信息时,此方法才能很好地工作。

方法二、标签编码

  • 标签编码将每个唯一值分配给不同的整数。
    此方法假定以下类别的排序:“从不”(0)<“很少”(1)<“大多数日子”(2)<“每天”(3)。在本示例中,这种假设是有意义的,因为对类别的排名无可争议。并非所有类别变量的值都具有明确的顺序,但是我们将其称为序数变量。
  • 对于基于树的模型(例如决策树和随机森林),可以期望标签编码可以与序数变量一起很好地工作。

方法三、一键编码

  • 一键编码会创建新列,以指示原始数据中每个可能值的存在(或不存在)。
    为了理解这一点,我们将通过一个示例进行研究。
  • 在原始数据集中,“颜色”是具有三个类别的类别变量:“红色”,“黄色”和“绿色”。对应的一键编码在原始数据集中包含一列用于每个可能的值,并且在每一行中包含一行。无论原始值为“红色”,我们都会在“红色”列中输入1;如果原始值为“ Yellow”,则在“ Yellow”列中输入1,依此类推。与标签编码相反,OneHotEncoder不假定类别的顺序。因此,如果分类数据中没有明确的顺序(例如,“红色”既不大于也不小于“黄色”),则可以期望这种方法特别有效。
  • 我们将没有内在排名的分类变量称为名义变量。如果分类变量具有大量值(即具有15个以上不同值的变量),则一键编码通常效果不佳。对于此数据集,带有文本的列表示类别变量。

数据准备

import pandas as pd
#train_test_split用于划分数据集
from sklearn.model_selection import train_test_split
#RandomForestRegressor随机森林
from sklearn.ensemble import RandomForestRegressor
#mean_absolute_error试错函数
from sklearn.metrics import mean_absolute_error
#LabelEncoder实现标签编码
from sklearn.preprocessing import LabelEncoder

# 读取数据
X = pd.read_csv('.../train.csv', index_col='Id')
X_test = pd.read_csv('.../test.csv', index_col='Id')

# 过滤标签列的缺失值的所有行,从数据集中分离标签出来
##dropna 过滤空值,axis=0表示过滤行;subset 表示丢弃的指定列;inplace=True 表示在原有的数据上改变。
X.dropna(axis=0, subset=['SalePrice'], inplace=True)
y = X.SalePrice
X.drop(['SalePrice'], axis=1, inplace=True)

#删除X和X_test的缺失列
cols_with_missing = [col for col in X.columns if X[col].isnull().any()]
X.drop(cols_with_missing, axis=1, inplace=True)
X_test.drop(cols_with_missing, axis=1, inplace=True)

#从数据集中划分训练集和测试集
X_train, X_valid, y_train, y_valid = train_test_split(X, y,train_size=0.8, test_size=0.2, random_state=0)

# 训练以及错误检验函数
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)

步骤1:删除包含分类数据的列

#-------------------------------方法1:删除包含分类数据的列-----------------
#训练集和测试集需保持同步删除
drop_X_train = X_train.select_dtypes(exclude=['object'])
print(drop_X_train)
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))

MAE from Approach 1 (Drop categorical variables):
17837.82570776256

步骤2:标签编码

# 查看“'Condition2'”列。在训练和验证集中打印唯一的条目。
print("Unique values in 'Condition2' column in training data:", X_train['Condition2'].unique())
print("\nUnique values in 'Condition2' column in validation data:", X_valid['Condition2'].unique())

在进行标签编码时,虽然在训练数据中对每个唯一值创建一个对应的整数值标签。但是如果在测试集上出现训练集中从未出现的类,则相应的编码功能将会出现错误。处理方法有:
(1)编写一个自定义标签编码器来处理新类别。
(2)删除有问题的类别列。
下面的代码单元,将有问题的列保存到Python列表 bad_label_cols中。将可以安全地进行标签编码的列存储在good_label_cols中。

# 获得所有分类列object_cols
object_cols = [col for col in X_train.columns if X_train[col].dtype == "object"]

# 可以安全地进行标签编码的列(good_label_cols)=训练集train和验证集valid的中类字段相同的列,此处不考率测试集test的情况。
good_label_cols = [col for col in object_cols if
                   set(X_train[col]) == set(X_valid[col])]

# 将有问题的列将从数据集中删除:bad_label_cols为object_cols与good_label_cols的差集
bad_label_cols = list(set(object_cols) - set(good_label_cols))

print('Categorical columns that will be label encoded:', good_label_cols)
print('\nCategorical columns that will be dropped from the dataset:', bad_label_cols)

# 将预处理的DataFrames分别设置为`label_X_train`和`label_X_valid`。
# 从数据集中删除“ bad_label_cols”中的类别列。

# Drop categorical columns that will not be encoded 删除坏的列
label_X_train = X_train.drop(bad_label_cols, axis=1)
label_X_valid = X_valid.drop(bad_label_cols, axis=1)

标签编码——LabelEncoder
LabelEncoder是用来对分类型特征值进行编码,即对不连续的数值或文本进行编码。其中包含以下常用方法:
fit(y) :fit可看做一本空字典,y可看作要塞到字典中的词。
fit_transform(y):相当于先进行fit再进行transform,即把y塞到字典中去以后再进行transform得到索引值。
inverse_transform(y):根据索引值y获得原始数据。
transform(y) :将y转变成索引值。

label_encoder = LabelEncoder()
for col in set(good_label_cols):
    
    #将标签转换为归一化的编码:对于每一列,将每个唯一值随机分配给一个不同的整数。通过此种方法可以提高模型的预期性。
    label_X_train[col] = label_encoder.fit_transform(X_train[col])
    label_X_valid[col] = label_encoder.transform(X_valid[col])
print("label_X_train:",label_X_train)
print("MAE from Approach 2 (Label Encoding):")
print(score_dataset(label_X_train, label_X_valid, y_train, y_valid))

MAE from Approach 2 (Label Encoding):
17575.291883561644

拟合标签编码器并返回编码的标签函数:transform()和fit_transform()的运行结果是一样的,只不过fit_transform()是先拟合数据,再标准化。
【注】transform函数可以替换为fit_transform函数,但fit_transform函数不能替换为transform函数
le.transform(["apple", "apple", "banana"])

array([1, 1, 2]…)

综上,编码分类数据比从数据集中删除列产生更好的结果。

步骤3:统计基数

将分类变量的唯一条目数称为该分类变量的“基数”。 例如,变量’Street’具有基数2。
获取每列具有分类数据的唯一条目的数量,这一步就类似excel中统计各个列的取值类别的数量

object_nunique = list(map(lambda col: X_train[col].nunique(), object_cols))
d = dict(zip(object_cols, object_nunique))

# 按列按升序打印唯一条目数
sorted(d.items(), key=lambda x: x[1])
print(d)

步骤4:一键编码

OneHotEncoder编码
有一些特征并不是以连续值的形式给出。这种特征可以采用整数的形式进行编码,如: [“male”, “from US”, “uses Internet Explorer”] 可表示成 [0, 1, 3] ,
[“female”, “from Asia”, “uses Chrome”] 可表示成[1, 2, 1]。
但是,这些整数形式的编码表示不能直接作为某些机器学习算法输入,因为有些机器学习算法是需要连续型的输入数据,同一列数据之间数值的大小可代表差异程度。
一个解决办法就是采用OneHotEncoder,这种表示方式将每一个分类特征变量的m个可能的取值转变成m个二值特征,即对于每一条数据这m个值中仅有一个特征值为1,其他的都为0。

# 将`low_cardinality_cols`设置为包含将被一键编码的列的Python列表。此处仅对基数小于10的列创建单次编码
low_cardinality_cols = [col for col in object_cols if X_train[col].nunique() < 10]
# high_cardinality_cols包含将要从数据集中删除的分类列的列表
high_cardinality_cols = list(set(object_cols)-set(low_cardinality_cols))

print('Categorical columns that will be one-hot encoded:', low_cardinality_cols)
print('\nCategorical columns that will be dropped from the dataset:', high_cardinality_cols)
#-------------------onehotencoder------------------
from sklearn.preprocessing import OneHotEncoder

#OneHotEncoder参数说明
#ignore表示当validation data中出现training data中没出现的值时,忽略。
#sparse=False保证返回一个numpy array
OH_encoder = OneHotEncoder(handle_unknown='ignore', sparse=False)
#print("OH_encoder:",OH_encoder)
OH_cols_train = pd.DataFrame(OH_encoder.fit_transform(X_train[low_cardinality_cols]))
OH_cols_valid = pd.DataFrame(OH_encoder.transform(X_valid[low_cardinality_cols]))
print("oh_cols_train:",OH_cols_train)
#1168*122  注意此处的原数字部分都被统一写成了0

oh_cols_train:
0 1 2 3 4 5 6 … 115 116 117 118 119 120 121
0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 … 0.0 0.0 0.0 0.0 0.0 0.0 1.0
1 0.0 0.0 0.0 1.0 0.0 0.0 1.0 … 1.0 0.0 0.0 0.0 0.0 1.0 0.0
2 0.0 0.0 0.0 1.0 0.0 0.0 1.0 … 1.0 0.0 0.0 0.0 0.0 1.0 0.0
3 0.0 0.0 0.0 1.0 0.0 0.0 1.0 … 1.0 0.0 0.0 0.0 0.0 1.0 0.0

#编码index;
OH_cols_train.index = X_train.index
OH_cols_valid.index = X_valid.index
#print("oh_cols_train.index:",OH_cols_train.index)
#删除分类列,将被替换为一键编码
num_X_train = X_train.drop(object_cols, axis=1)
num_X_valid = X_valid.drop(object_cols, axis=1)
print("num_X_train:",num_X_train)
#1168*33

num_X_train:
MSSubClass LotArea OverallQual … MiscVal MoSold YrSold
Id …
619 20 11694 9 … 0 7 2007
871 20 6600 5 … 0 8 2009
93 30 13360 5 … 0 8 2009
818 20 13265 8 … 0 7 2008

#合并数据集num_X_train和OH_cols_train
#pd.concat参数说明
#	objs为需要连接的对象,eg [df1, df2];
#	axis = 0, 表示在水平方向(row)进行连接 axis = 1, 表示在垂直方向(column)进行连接
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("OH_X_train:",OH_X_train)
print("MAE from Approach 3 (One-Hot Encoding):")
print(score_dataset(OH_X_train, OH_X_valid, y_train, y_valid))v

MAE from Approach 3 (One-Hot Encoding):
17525.345719178084

over.
新手上路,欢迎批评指正!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值