内容来源于《Python数据挖掘入门与实践》
OneR算法的思路很简单,它根据已有数据中,具有相同特征值的个体最可能属于哪个类别进行分类。 OneR是One Rule(一条规则)的简写,表示我们特征中分类效果最好的一个用作分类依据。一些分类算法比起OneR要复杂很多,但这个看似不起眼的简单算法,在很多真实数据集上表现得也不凡。
对于OneR算法的介绍,我们使用Python语言和著名的Iris植物分类数据集。
数据集的特征为连续值,而我们即将使用的算法使用类别型特征值,因此我们需要把连续值转变为类别型,这个过程叫作离散化(具体操作下一步会详细介绍)。
经过离散化的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时,类型为1的错误率为SL11;
当sepal length取1时,类型为2的错误率为SL12;
比较SL10、SL11、SL12的大小,取最小值,表明错误率最低。(假设SL10
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类别。
在了解了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