机器学习--分类变量编码方法

前言

最近在Medium上看到一篇关于分类变量编码的方法概述,记录一下,主要讲述了除了One-Hot encoding 编码外,根据不同应用场景,也许会有更好的选择。

one-hot 编码(one-hot encoding)类似于虚拟变量(dummy variables),是一种将分类变量转换为几个二进制列的方法。其中 1 代表某个输入属于该类别。
在这里插入图片描述

从机器学习的角度来看,one-hot 编码并不是一种良好的分类变量编码方法。

因为one-hot 编码增加了大量的维度,要枚举该特征下的所有取值情况。例如,如果用一个序列来表示美国的各个州,那么 one-hot 编码会带来 50 多个维度。

one-hot 编码不仅会为数据集增加大量维度,而且实际上并没有太多信息,很多时候 1 散落在众多零之中,即有用的信息零散地分布在大量数据中。这会导致结果异常稀疏,使其难以进行优化,对于神经网络来说尤其如此。

更糟糕的情况是,每个信息稀疏列之间都具有线性关系。这意味着一个变量可以很容易地使用其他变量进行预测,导致高维度中出现并行性和多重共线性的问题。

例如下面这种情况:

在这里插入图片描述

最优数据集由信息具有独立价值的特征组成,但 one-hot 编码创建了一个完全不同的环境。

当然,如果只有三、四个类,那么 one-hot 编码可能不是一个糟糕的选择。但是随着类别的增加,可能还有其他更合适的方案值得探索。Medium 专栏的作者列举了几个方案以供参考。

目标编码

目标编码(Target encoding)是表示分类列的一种非常有效的方法,并且仅占用一个特征空间,也称为均值编码。该列中的每个值都被该类别的平均目标值替代。这可以更直接地表示分类变量和目标变量之间的关系,并且也是一种很受欢迎的技术方法(尤其是在 Kaggle 比赛中)。

在这里插入图片描述

但这种编码方法也有一些缺点。首先,它使模型更难学习均值编码变量和另一个变量之间的关系,仅基于列与目标的关系就在列中绘制相似性。

而最主要的是,这种编码方法对 y 变量非常敏感,这会影响模型提取编码信息的能力。

由于该类别的每个值都被相同的数值替换,因此模型可能会过拟合其见过的编码值(例如将 0.8 与完全不同的值相关联,而不是 0.79),这是把连续尺度上的值视为严重重复的类的结果。

因此,需要仔细监控 y 变量,以防出现异常值。要实现这个目的,就要使用 category_encoders 库。由于目标编码器是一种有监督方法,所以它同时需要 X 和 y 训练集。

from category_encoders import TargetEncoder 
 enc = TargetEncoder(cols=['Name_of_col','Another_name']) 
 training_set = enc.fit_transform(X_train, y_train)

留一法编码

留一法(Leave-one-out)编码试图通过计算平均值(不包括当前行值)来弥补对 y 变量的依赖以及值的多样性。这使异常值的影响趋于平稳,并创建更多样化的编码值。

在这里插入图片描述

由于模型不仅要面对每个编码类的相同值,还要面对一个范围值,因此它可以更好地泛化。

在实现方面,可以使用 category_encoders 库中的 LeaveOneOutEncoder

from category_encoders import LeaveOneOutEncoder
 enc = LeaveOneOutEncoder(cols=['Name_of_col','Another_name'])
 training_set = enc.fit_transform(X_train, y_train)

实现类似效果的另一种策略是将正态分布的噪声添加到编码分数中,其中标准差是可以调整的参数。

贝叶斯目标编码

贝叶斯目标编码(Bayesian Target Encoding)是一种使用目标作为编码方法的数学方法。仅使用均值可能是一种欺骗性度量标准,因此贝叶斯目标编码试图结合目标变量分布的其他统计度量。例如其方差或偏度(称为高阶矩「higher moments」)。

然后通过贝叶斯模型合并这些分布的属性,从而产生一种编码,该编码更清楚类别目标分布的各个方面,但是结果的可解释性比较差

证据权重

证据权重(Weight of Evidence,简称 WoE)是另一种关于分类自变量和因变量之间关系的方案。WoE 源自信用评分领域,曾用于区分用户是违约拖欠还是已经偿还贷款。证据权重的数学定义是优势比的自然对数,即:
ln (% of non events / % of events)

WoE 越高,事件发生的可能性就越大。「Non-events」是不属于某个类的百分比。使用证据权重与因变量建立单调关系,并在逻辑尺度上确保类别,这对于逻辑回归来说很自然。WoE 是另一个衡量指标「Information Value」的关键组成部分。该指标用来衡量特征如何为预测提供信息。

from category_encoders import WOEEncoder 
 enc = WOEEncoder(cols=['Name_of_col','Another_name']) 
 training_set = enc.fit_transform(X_train, y_train)

这些方法都是有监督编码器,或者是考虑目标变量的编码方法,因此在预测任务中通常是更有效的编码器。但是,当需要执行无监督分析时,这些方法并不一定适用。

非线性 PCA

非线性 PCA(Nonlinear PCA)是一种使用分类量化来处理分类变量的主成分分析(PCA)方法。它会找到对类别来说的最佳数值,从而使常规 PCA 的性能(可解释方差)最大化。

### 朴素贝叶斯分类器简介 朴素贝叶斯分类器是一种基于贝叶斯定理的监督学习算法,其核心假设是特征之间相互独立[^2]。尽管这一假设在现实中往往不成立,但该模型仍然表现出良好的性能,在许多实际应用中取得了不错的效果[^3]。 以下是关于如何设计和实现一个简单的朴素贝叶斯分类器实验的具体说明: --- ### 数据集准备 为了验证朴素贝叶斯分类器的有效性,可以选择经典的文本分类数据集(如垃圾邮件检测)或者数值型数据集(如鸢尾花数据集 Iris Dataset)。这里以鸢尾花数据集为例进行演示。 #### 加载数据 可以使用 `scikit-learn` 提供的数据加载工具快速获取鸢尾花数据集: ```python from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split # 加载数据集 data = load_iris() X, y = data.data, data.target # 将数据划分为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) ``` --- ### 构建朴素贝叶斯分类器 利用 Python 中的 `sklearn.naive_bayes` 模块可以直接构建并训练朴素贝叶斯分类器。常见的变体包括高斯分布下的朴素贝叶斯(GaussianNB),适用于连续型变量。 #### 训练模型 以下是一个完整的代码示例: ```python from sklearn.naive_bayes import GaussianNB from sklearn.metrics import accuracy_score, classification_report # 初始化朴素贝叶斯分类器 model = GaussianNB() # 使用训练数据拟合模型 model.fit(X_train, y_train) # 对测试集进行预测 y_pred = model.predict(X_test) # 输出评估指标 print(f"Accuracy: {accuracy_score(y_test, y_pred):.2f}") print("\nClassification Report:") print(classification_report(y_test, y_pred)) ``` 上述代码实现了以下几个功能: 1. **初始化模型**:创建了一个基于高斯分布的朴素贝叶斯分类器实例。 2. **训练阶段**:通过调用 `.fit()` 方法完成模型参数的学习。 3. **预测与评估**:对测试集执行预测操作,并计算准确率以及详细的分类报告。 --- ### 自定义实现朴素贝叶斯分类器 如果希望深入了解内部机制,可以通过手动编写代码来实现朴素贝叶斯的核心逻辑。以下是针对二元分类问题的一个简化版本: #### 手动实现 ```python import numpy as np class NaiveBayesClassifier: def __init__(self): self.class_prior = {} self.feature_likelihoods = {} def fit(self, X, y): n_samples, n_features = X.shape classes = np.unique(y) # 计算先验概率 P(C_k) for c in classes: X_c = X[y == c] self.class_prior[c] = len(X_c) / n_samples # 计算条件概率 P(x_i|C_k),假定各特征服从正态分布 mean = np.mean(X_c, axis=0) var = np.var(X_c, axis=0) self.feature_likelihoods[c] = (mean, var) def predict(self, X): predictions = [] for x in X: posteriors = [] # 遍历每个类别的后验概率 P(C_k|x) for c, prior in self.class_prior.items(): likelihood = np.log(prior) # 基于正态分布的概率密度函数计算似然值 mean, var = self.feature_likelihoods[c] numerator = np.exp(-((x - mean)**2) / (2 * var)) denominator = np.sqrt(2 * np.pi * var) likelihood += np.sum(np.log(numerator / denominator)) posteriors.append(likelihood) # 取最大后验对应的类别作为预测结果 pred_class = np.argmax(posteriors) predictions.append(pred_class) return np.array(predictions) # 测试自定义实现 nb_custom = NaiveBayesClassifier() nb_custom.fit(X_train, y_train) y_pred_custom = nb_custom.predict(X_test) print(f"Custom Accuracy: {accuracy_score(y_test, y_pred_custom):.2f}") ``` 此部分展示了如何从零开始构建朴素贝叶斯分类器,涉及的关键概念包括先验概率 \(P(C_k)\) 和条件概率 \(P(x_i | C_k)\)[^2]。 --- ### 总结 以上提供了两种方式来理解和实践朴素贝叶斯分类器:一种是借助成熟的库(如 scikit-learn)快速搭建模型;另一种则是深入底层原理,自行编码实现基本框架。无论采用哪种方法,都可以加深对该算法的认识及其适用场景的理解。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值