OneRClassifier: 一规则 (OneR) 分类方法

One Rule (OneR) 分类方法的实现。

from mlxtend.classifier import OneRClassifier

概述

"OneR" 代表 One Rule (由 Robert Holte [1] 提出),它是一种经典的监督学习算法。请注意,该算法的预测性能并非突出;因此,它更推荐用于教学目的以及在实际应用中作为性能的下限基准。

"OneRule" 这个名称可能有点误导,因为它技术上是关于“一个特征”,而不是“一个规则”。也就是说,OneR 返回一个特征,为此特征定义了一个或多个决策规则。本质上,作为一个简单的分类器,它只找到一个特征(以及该特征的一个或多个特征值)来对数据实例进行分类。

基本过程如下

  • 对于数据集中的所有特征(列)中的每个特征
    • 对于给定特征的每个特征值
      1. 获取具有该特征值的训练样本。
      2. 获取与上一步中确定的训练样本相对应的类别标签(及类别标签计数)。
      3. 将频率(计数)最高的类别标签视为多数类。
      4. 将错误数量记录为具有给定特征值但不是多数类的训练样本数量。
    • 通过汇总该特征所有可能特征值的错误来计算该特征的错误。
  • 返回最佳特征,最佳特征被定义为错误最低的特征。

请注意,OneR 算法假定特征值是分类的(或离散化的)。在 Interpretable Machine Learning 在线章节“4.5.1 Learn Rules from a Single Feature (OneR)” (https://christophm.github.io/interpretable-ml-book/rules.html, [2]) 中可以找到很好的解释和 OneR 分类器。

参考文献

[1] Holte, Robert C. "Very simple classification rules perform well on most commonly used datasets." Machine learning 11.1 (1993): 63-90.

[2] Interpretable Machine Learning (2018) by Christoph Molnar: https://christophm.github.io/interpretable-ml-book/rules.html

示例 1 -- 在离散化鸢尾花数据集上演示 OneR

如上文概述所述,OneR 算法要求特征是分类的或离散化的。MLxtend 中的 OneRClassifier 实现不会修改数据集中的特征,确保特征是分类的是用户的责任。

在下面的示例中,我们将离散化鸢尾花数据集。特别地,我们将数据集转换为四分位数。换句话说,每个特征值都被替换为一个分类值。对于萼片宽度(鸢尾花数据集的第一列),这将是

  • (0, 5.1] => 0
  • (5.1, 5.8] => 1
  • (5.8, 6.4] => 2
  • (6,4, 7.9] => 3

以下是原始鸢尾花数据的前 15 行(花朵)

from mlxtend.data import iris_data


X, y = iris_data()
X[:15]
array([[5.1, 3.5, 1.4, 0.2],
       [4.9, 3. , 1.4, 0.2],
       [4.7, 3.2, 1.3, 0.2],
       [4.6, 3.1, 1.5, 0.2],
       [5. , 3.6, 1.4, 0.2],
       [5.4, 3.9, 1.7, 0.4],
       [4.6, 3.4, 1.4, 0.3],
       [5. , 3.4, 1.5, 0.2],
       [4.4, 2.9, 1.4, 0.2],
       [4.9, 3.1, 1.5, 0.1],
       [5.4, 3.7, 1.5, 0.2],
       [4.8, 3.4, 1.6, 0.2],
       [4.8, 3. , 1.4, 0.1],
       [4.3, 3. , 1.1, 0.1],
       [5.8, 4. , 1.2, 0.2]])

以下是离散化后的数据集。每个特征被划分为 4 个四分位数。

import numpy as np


def get_feature_quartiles(X):
    X_discretized = X.copy()
    for col in range(X.shape[1]):
        for q, class_label in zip([1.0, 0.75, 0.5, 0.25], [3, 2, 1, 0]):
            threshold = np.quantile(X[:, col], q=q)
            X_discretized[X[:, col] <= threshold, col] = class_label
    return X_discretized.astype(np.int)

Xd = get_feature_quartiles(X)
Xd[:15]
array([[0, 3, 0, 0],
       [0, 1, 0, 0],
       [0, 2, 0, 0],
       [0, 2, 0, 0],
       [0, 3, 0, 0],
       [1, 3, 1, 1],
       [0, 3, 0, 0],
       [0, 3, 0, 0],
       [0, 1, 0, 0],
       [0, 2, 0, 0],
       [1, 3, 0, 0],
       [0, 3, 0, 0],
       [0, 1, 0, 0],
       [0, 1, 0, 0],
       [1, 3, 0, 0]])

给定一个带有分类特征的数据集,我们可以像使用 scikit-learn 的分类估计器一样使用 OneR 分类器。首先,我们将数据集划分为训练数据和测试数据

from sklearn.model_selection import train_test_split


Xd_train, Xd_test, y_train, y_test = train_test_split(Xd, y, random_state=0, stratify=y)

接下来,我们可以使用 fit 方法在训练集上训练一个 OneRClassifier 模型

from mlxtend.classifier import OneRClassifier
oner = OneRClassifier()

oner.fit(Xd_train, y_train);

模型拟合后,可以通过 feature_idx_ 属性访问所选特征的列索引

oner.feature_idx_
2

模型拟合后,还有一个 prediction_dict_ 可用。它列出了所选特征的总错误(即在 feature_idx_ 下列出的特征)。它还提供了分类规则

oner.prediction_dict_
{'total error': 16, 'rules (value: class)': {0: 0, 1: 1, 2: 1, 3: 2}}

例如,'rules (value: class)': {0: 0, 1: 1, 2: 1, 3: 2} 意味着所选特征(花瓣长度)有 3 条规则: - 如果值为 0,则分类为 0 (Iris-setosa) - 如果值为 1,则分类为 1 (Iris-versicolor) - 如果值为 2,则分类为 1 (Iris-versicolor) - 如果值为 3,则分类为 2 (Iris-virginica)

模型拟合后,我们可以使用 oner 对象进行预测

oner.predict(Xd_train)
array([1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 2, 2, 1,
       0, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 0, 0, 1, 2, 1, 1, 2, 2, 1, 0, 1,
       1, 1, 2, 0, 1, 2, 1, 2, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 2, 0, 1, 1,
       0, 1, 2, 1, 2, 0, 1, 2, 1, 1, 2, 0, 1, 0, 0, 1, 1, 2, 0, 0, 0, 1,
       0, 1, 2, 2, 2, 0, 1, 0, 2, 0, 1, 1, 1, 1, 0, 2, 2, 0, 1, 1, 0, 2,
       1, 2])
y_pred = oner.predict(Xd_train)
train_acc = np.mean(y_pred == y_train)  
print(f'Training accuracy {train_acc*100:.2f}%')
Training accuracy 85.71%
y_pred = oner.predict(Xd_test)
test_acc = np.mean(y_pred == y_test)  
print(f'Test accuracy {test_acc*100:.2f}%')
Test accuracy 84.21%

除了手动计算预测准确率(如上所示),我们还可以使用 score 方法

test_acc = oner.score(Xd_test, y_test)
print(f'Test accuracy {test_acc*100:.2f}%')
Test accuracy 84.21%

API

OneRClassifier(resolve_ties='first')

OneR (一规则) 分类器。

参数

  • resolve_ties : str (默认值: 'first')

    当两个或多个特征具有相同的错误时,如何解决平局的选项。选项包括 - 'first' (默认值): 选择列表中的第一个特征,即列索引较低的特征。 - 'chi-squared': 对每个特征与目标进行卡方检验,并选择 p 值最低的特征。

属性

  • self.classes_labels_ : array-like, shape = [n_labels]

    包含训练集中找到的唯一类别标签的数组。

  • self.feature_idx_ : int

    基于训练集中列的规则特征的索引。

  • self.p_value_ : float

    给定特征的 p 值。仅在使用 fit 方法且 OneR 属性 resolve_ties = 'chi-squared' 被设置后可用。

  • self.prediction_dict_ : dict

    包含特征 (self.feature_idx_) 规则和总错误信息的字典。例如,{'total error': 37, 'rules (value: class)': {0: 0, 1: 2}} 意味着总错误为 37,规则是“如果特征值 == 0 则分类为 0”和“如果特征值 == 1 则分类为 2”。(否则分类为类别 1。)

    有关用法示例,请参阅 https://mlxtend.cn/mlxtend/user_guide/classifier/OneRClassifier/

方法


fit(X, y)

从训练数据中学习规则。

参数

  • X : {array-like, sparse matrix}, shape = [n_samples, n_features]

    训练向量,其中 n_samples 是样本数,n_features 是特征数。

  • y : array-like, shape = [n_samples]

    目标值。

返回

  • self : object

get_params(deep=True)

获取此估计器的参数。

参数

  • deep : bool, default=True

    如果为 True,将返回此估计器及其包含的作为估计器的子对象的参数。

返回

  • params : mapping of string to any

    参数名称映射到其值。


predict(X)

预测 X 的类别标签。

参数

  • X : {array-like, sparse matrix}, shape = [n_samples, n_features]

    训练向量,其中 n_samples 是样本数,n_features 是特征数。

返回

  • maj : array-like, shape = [n_samples]

    预测的类别标签。


score(X, y, sample_weight=None)

返回给定测试数据和标签的平均准确率。

在多标签分类中,这是子集准确率,这是一个严格的指标,因为它要求每个样本的每个标签集都被正确预测。

参数

  • X : array-like of shape (n_samples, n_features)

    测试样本。

  • y : array-like of shape (n_samples,) or (n_samples, n_outputs)

    X 的真实标签。

  • sample_weight : array-like of shape (n_samples,), default=None

    样本权重。

返回

  • score : float

    self.predict(X) 相对于 y 的平均准确率。


set_params(params)

设置此估计器的参数。

该方法适用于简单估计器和嵌套对象(例如管道)。后者的参数形式为 <component>__<parameter>,以便可以更新嵌套对象的每个组件。

参数

  • **params : dict

    估计器参数。

返回

  • self : object

    估计器实例。

ython