上一篇文章中,我们介绍了如何用sklearn训练和预测模型,以及缺失值处理,详见[机器学习]sklearn入门指南(1)
分类变量
分类变量(Categorical Variable),也称为定性变量(Qualitative Variable),是指只能取有限个数不同值的变量,这些值通常是互不相容的类别或名称。分类变量可以作为预测模型的重要特征,尤其是在涉及用户属性、产品类别等场景中。
分类变量与数值变量(Quantitative Variable)不同,后者可以在一定范围内取任意值。分类变量的值通常是离散的、无序的,表示的是事物的类型或属性,而不是数量。
在机器学习中,大多数模型只能处理数值型数据,因此需要将分类变量转换为数值型数据,这个过程称为编码(Encoding)或转换(Transformation)
分类变量的分类
- 名义变量(Nominal Variables):
- 这类变量的值没有内在的顺序或排名,各个类别之间是并列关系。
- 例子:性别(男、女)、血型(A、B、AB、O)、国籍(中国、美国、英国)。
- 序数变量(Ordinal Variables):
- 序数变量的值有明确的顺序或等级,但类别之间的差异可能不相等。
- 例子:教育程度(小学、中学、大学)、满意度调查(不满意、一般、满意)。
处理分类变量的方法
1. 丢弃分类变量
如果某些分类变量对分析结果影响不大,可以选择丢弃。
优点:快速且简单
缺点:可能会丢失有用的信息,特别是当分类变量实际上对预测结果有影响时。
方法
`pandas.DataFrame.select_dtypes` 基于列的类型来筛选列,有include和exclude两个参数,表示包括和不包括的类型
`exclude='object'`表示不包括字符串
- 选择字符串类型的数据,必须使用 object ,否则会引发 ValueError 错误
```python
drop_X_train = X_train.select_dtypes(exclude='object')
drop_X_valid = X_valid.select_dtypes(exclude='object')
```
2. 序数编码
序数编码常用于序数变量,这种方法假设类别之间存在一个顺序关系,然后为每个唯一的值分配一个不同的整数。
- 例如:“从不”(0)< “很少”(1)< “大多数日子”(2)< “每天”(3)。
这种假设在某些情况下是合理的,因为类别之间确实存在一个公认的排名。
对于基于树的模型(如决策树和随机森林),序数编码通常能够很好地工作。
优点:能够保留变量的顺序信息。
缺点:如果类别之间实际上没有顺序关系,序数编码可能会引入错误的假设,从而影响模型的性能。
方法
在开始序数编码之前,首先要研究数据集。
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())
#Unique values in 'Condition2' column in training data: ['Norm' 'PosA' 'Feedr' 'PosN' 'Artery' 'RRAe']
#Unique values in 'Condition2' column in validation data: ['Norm' 'RRAn' 'RRNn' 'Artery' 'Feedr' 'PosN']
序数编码器会为训练数据中出现的每个唯一值创建相应的整数值标签。如果验证数据包含的值未出现在训练数据中,则编码器将抛出错误,因为这些值不会被分配整数。
- 验证数据中的“Condition2”列包含值“RRAn”和“RRNn”,但这些值不会出现在训练数据中。如果尝试在 scikit-learn 中使用序数编码器,代码会抛出错误。
因此,要把验证集标签不是训练集标签子集的列删除
然后针对good_label_cols 进行序数编码
# Categorical columns in the training data
object_cols = [col for col in X_train.columns if X_train[col].dtype == "object"]
# Columns that can be safely ordinal encoded
good_label_cols = [col for col in object_cols if
set(X_valid[col]).issubset(set(X_train[col]))]
# Problematic columns that will be dropped from the dataset
bad_label_cols = list(set(object_cols)-set(good_label_cols))
print('Categorical columns that will be ordinal encoded:', good_label_cols)
print('\nCategorical columns that will be dropped from the dataset:', bad_label_cols)
#Categorical columns that will be ordinal encoded: ['MSZoning', 'Street', 'LotShape', 'LandContour', 'Utilities', 'LotConfig', 'LandSlope', 'Neighborhood', 'Condition1', 'BldgType', 'HouseStyle', 'RoofStyle', 'Exterior1st', 'Exterior2nd', 'ExterQual', 'ExterCond', 'Foundation', 'Heating', 'HeatingQC', 'CentralAir', 'KitchenQual', 'PavedDrive', 'SaleType', 'SaleCondition']
#Categorical columns that will be dropped from the dataset: ['Functional', 'RoofMatl', 'Condition2']
label_X_train = X_train.drop(bad_label_cols, axis=1)
label_X_valid = X_valid.drop(bad_label_cols, axis=1)
oe = OrdinalEncoder()
oe.fit(X_train[good_label_cols])
label_X_train[good_label_cols] = pd.DataFrame(oe.transform(X_train[good_label_cols]))
label_X_valid[good_label_cols] = pd.DataFrame(oe.transform(X_valid[good_label_cols]))
3. one-hot独热编码
独热编码通过创建新列来表示原始数据中每个可能值的存在(或不存在)。
- 例如,如果原始数据集中的“颜色”是一个分类变量,包含三个类别:“红色”、“黄色”和“绿色”,那么对应的独热编码将为每个可能的值包含一个列,并且为原始数据集中的每一行包含一个行。在原始值是“红色”的地方,我们在“红色”列中放置一个1;如果原始值是“黄色”,则在“黄色”列中放置一个1,以此类推。
优点:独热编码不假设类别之间存在顺序关系。因此,如果分类数据中没有明确的顺序,独热编码通常会特别有效。
缺点:独热编码不适用于分类变量取值非常多的情况。当分类变量的取值非常多时,独热编码会导致维度灾难(特征空间的维度过高),引起模型训练的困难和过拟合的风险。
方法
要用one-hot 编码,首先要查看列中非重复值的数量,如果数量太多(这里设置为>10),则不适合用one-hot编码
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])
low_cardinality_cols = [col for col in object_cols if X_train[col].nunique() < 10]
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)
#Categorical columns that will be one-hot encoded: ['MSZoning', 'Street', 'LotShape', 'LandContour', 'Utilities', 'LotConfig', 'LandSlope', 'Condition1', 'Condition2', 'BldgType', 'HouseStyle', 'RoofStyle', 'RoofMatl', 'ExterQual', 'ExterCond', 'Foundation', 'Heating', 'HeatingQC', 'CentralAir', 'KitchenQual', 'Functional', 'PavedDrive', 'SaleType', 'SaleCondition']
#Categorical columns that will be dropped from the dataset: ['Exterior2nd', 'Exterior1st', 'Neighborhood']
OH = OneHotEncoder(handle_unknown='ignore', sparse=False)
OH.fit(X_train[low_cardinality_cols])
OH_X_train = pd.DataFrame(OH.transform(X_train[low_cardinality_cols])) # Your code here
OH_X_valid = pd.DataFrame(OH.transform(X_valid[low_cardinality_cols]))# Your code here
OH_X_train.index = X_train.index
OH_X_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 = OH_X_train + num_X_train
OH_X_valid = OH_X_valid + num_X_valid
来自Learn Tutorial Intermediate Machine Learning