Python数据挖掘-OneR算法简介

OneR算法

内容来源于《Python数据挖掘入门与实践》

在末尾有源代码,但需要使用Jupyter notebook,大家可以去我的另一篇文章找安装教程。http://blog.csdn.net/xinan_zxy/article/details/78935571
文中的涉及到的错误率概念,大家可以去我的另一篇文章了解。http://blog.csdn.net/xinan_zxy/article/details/78994611

OneR算法的思路很简单,它根据已有数据中,具有相同特征值的个体最可能属于哪个类别进行分类。 OneR是One Rule(一条规则)的简写,表示我们特征中分类效果最好的一个用作分类依据。一些分类算法比起OneR要复杂很多,但这个看似不起眼的简单算法,在很多真实数据集上表现得也不凡。

1.思路解析

对于OneR算法的介绍,我们使用Python语言和著名的Iris植物分类数据集。

关于Iris植物分类数据集的介绍,大家可以上查看这里https://baike.baidu.com/item/IRIS/4061453?fr=aladdin

数据集的特征为连续值,而我们即将使用的算法使用类别型特征值,因此我们需要把连续值转变为类别型,这个过程叫作离散化(具体操作下一步会详细介绍)。
经过离散化的Iris数据集如下

sepal length sepal width petal length petal width class
0 1 0 0 0
0 0 0 0 0
0 1 0 0 0
1 0 1 1 2
1 1 1 1 2
1 0 1 1 2

经过离散化的Iris数据集每个特征值为0或1,而类别class为0或1或2。


现在,我们需要计算数据集中每个特征的每个特征值,与类别class的关系。详细如下:
当sepal length取0时,类型为0的错误率为SL00;
当sepal length取0时,类型为1的错误率为SL01;
当sepal length取0时,类型为2的错误率为SL02;
比较SL00、SL01、SL02的大小,取最小值,表明错误率最低。(假设SL00 当sepal length取1时,类型为0的错误率为SL10;
当sepal length取1时,类型为1的错误率为SL11;
当sepal length取1时,类型为2的错误率为SL12;
比较SL10、SL11、SL12的大小,取最小值,表明错误率最低。(假设SL10 则对于sepal length特征值来说,与类别class的关系如下:

sepal length ->class 错误率
0->0 SL00
1->0 SL10

通过sepal length对新的数据进行分类的总错误率是SL00+SL10;
同理,可以得到其他三个特征值如下:

sepal width ->class 错误率
0->0 SW00
1->0 SW10

通过sepal width对新的数据进行分类的总错误率是SW00+SW10;

petal length ->class 错误率
0->0 PL00
1->0 PL10

通过sepal width对新的数据进行分类的总错误率是PL00+PL10;

petal width ->class 错误率
0->0 PW00
1->0 PW10

通过sepal width对新的数据进行分类的总错误率是PW00+PW10;

到了这一步,我们可以知道四个特征值总错误率SL00+SL10、SW00+SW10、PL00+PL10、PW00+PW10,接着比较四个错误率,取最低。(假设SL00+SL10 得到最低的总错误率之后,说明相对应的分类规则最有用,即利用这条规则对新的数据进行分类。
例如:新数据中sepal length的特征值为0,则是0类别;为1,则是0类别。

2.Python代码实现

在了解了OneR算法的设计思想之后,我们使用Python来实现。
Python的scikit-learn库内置了该数据集,可直接导入

from sklearn.datasets import load_iris
dataset = load_iris()
X = dataset.data
y = dataset.target

用print(dataset.DESCR)命令查看数据集,大概了解一下,包括特征的说明。
接着,我们把数据集离散化,最简单的离散化算法,莫过于确定一个阈值,将低于该阈值的特征值置为0,高于阈值的置为1。我们把某项特征的阈值设定为该特征所有特征值的均值。每个特征的均值计算方法如下。

attribute_means = X.mean(axis=0)

我们得到了一个长度为4的数组,这正好是特征的数量。数组的第一项是第一个特征的均值,以此类推。接下来,用该方法将数据集打散,把连续的特征值转换为类别型。

X_d = np.array(X >= attribute_means, dtype='int')

由此,可以得到我们思路解析中的数据集。
接着,创建一个函数,根据待预测数据的某项特征值预测类别,并给出错误率。在这之前需要导入前面用过的defaultdict和itemgetter模块。

from collections import defaultdict
from operator import itemgetter

下面创建函数声明,参数分别是数据集、类别数组、选好的特征索引值、特征值。

#训练特征值
def train_feature_value(X, y_true, feature_index, value):
    #参数分别是数据集、class类别数组、选好的特征索引值(0,1,2,3)、特征值(0,1)
    class_counts = defaultdict(int)
    #这个循环表示指定特征index和特征值,得到该特征值对应的class的数量
    for sample, y in zip(X, y_true):
        if sample[feature_index] == value:
            class_counts[y] += 1
    #对上面循环得到的数组降序排列,取数量最大的那个,表示指定特征index和特征值,特征值最可能与某class相关。如上面所说的SL00,SL01,SL02
    sorted_class_counts = sorted(class_counts.items(),key=itemgetter(1), reverse=True)
    most_frequent_class = sorted_class_counts[0][0]
    #计算错误率,并返回最可能的关系。
    incorrect_predictions = [class_count for class_value,class_count in class_counts.items() if class_value != most_frequent_class]
    error = sum(incorrect_predictions)
    return most_frequent_class, error

接着,我们再创建另一个函数,用于训练特征项

#训练特征项
def train_on_feature(X, y_true, feature_index):
    #得到指定特征index的所有值,由于已经离散化,所以values为{0,1}
    values = set(X[:,feature_index])
    predictors = {}
    errors = []
    #循环得到指定特征值index与类别class的关系,和总错误率,如上述的SL00+SL10。并返回预测数组和总错误率
    for current_value in values:
        most_frequent_class, error = train_feature_value(X,y_true, feature_index, current_value)
        predictors[current_value] = most_frequent_class
        errors.append(error)
    total_error = sum(errors)
    return predictors, total_error

功能部分已经实现,现在需要对其进行测试。
首先需要把数据集划分成训练集和测试集,scikit-learn库提供了一个将数据集切分为训练集和测试集的函数。

from sklearn.cross_validation import train_test_split
Xd_train, Xd_test, y_train, y_test = train_test_split(X_d, y, random_state=14)

接下来,计算所有特征值的目标类别(预测器)。记得只使用训练集。遍历数据集中的每个特征,使用我们先前定义的函数train_on_feature()训练预测器,计算错误率。

all_predictors = {}
errors = {}
#循环全部的特征项,得到相关的关系和总错误率,并排列得到最佳的规则即OneR
for feature_index in range(Xd_train.shape[1]):
    predictors, total_error = train_on_feature(Xd_train,y_train,feature_index)
    all_predictors[feature_index] = predictors
    errors[feature_index] = total_error
best_feature, best_error = sorted(errors.items(), key=itemgetter(1))[0]

接着,我们创建model模型。

model = {'feature': best_feature,'predictor': all_predictors[best_feature]}

model模型是一个字典结构,包含两个元素:用于分类的特征和预测器。有了模型后,就可以根据特征值对没有见过的数据进行分类。示例如下:

variable = model['feature']
predictor = model['predictor']
prediction = predictor[int(sample[variable])]

接着我们编写预测函数:

def predict(X_test, model):
    feature = model['feature'] 
    predictor = model['predictor']
    y_predicted = [predictor[int(sample[feature])] for sample in X_test]
    return y_predicted

我们用上面这个函数预测测试集中每条数据的类别,并得到正确率为65.8%

y_predicted = predict(Xd_test, model)
accuracy = np.mean(y_predicted == y_test) * 100
print("The test accuracy is {:.1f}%".format(accuracy))

代码的GitHub地址:https://github.com/20132100247/PythonOneR.git

你可能感兴趣的:(数据挖掘)