根据植物的特征预测其属于哪一种
这个例子是要干什么?
对于里面的各种数据关系,我看好几遍才搞明白。我觉得先理解原理,再去看具体的代码会比较容易一点。
iris的数据集里有三类花(标记为0,1,2),每一类花都有四个特征项(萼片、花瓣的长和宽,标记为0,1,2,3),原始数据中,每一个特征项有多个不同的取值(特征值)。这里要先提一下预处理或者说离散化,目的就是将这些特征值离散为两个值:0和1,方法就是将每一个特征值与该特征项所有值的平均数attribute_mean比较,小于的设为0,大于等于的设为1。
我们知道每一类花在特征项的表现上,应该是有所不同的,例如0类花的花瓣较长,那么对于花瓣长度特征值为1的一朵花F,有较大把握说F属于0类花。也就是说,在这种情况下,我们可以根据花瓣的长度来将每一朵花分类。同样的,如果花的类别与花萼的长、宽;花瓣的宽存在联系,那么也可以用这三个特征项来为每一朵花分类。
既然这四个特征项都可以作为给花分类的指标,而我们只需要一个指标就足够了。所以这就涉及到了用哪一个指标分类更准确的问题,举例来说:对于花瓣长度这一指标,0类花中有40个特征值为0,10个特征值为1;1类花中有25个特征值为0,25个特征值为1;2类花中有10个特征值为0,40个特征值为1,那么,可以认为:花瓣长度特征值为0的,大概率属于0类花,错误数为35,错误率为
25
+
10
40
+
25
+
10
\frac{25+10}{40+25+10}
40+25+1025+10=47%;花瓣长度特征值为1的,大概率属于2类花,错误数为35,错误率为
25
+
10
40
+
25
+
10
\frac{25+10}{40+25+10}
40+25+1025+10=47%。因此,利用花瓣长度进行分类,总的错误数为70。
而对于花瓣宽度这一指标,0类花中有30个特征值为0,20个特征值为1;1类花中有15个特征值为0,35个特征值为1;2类花中有40个特征值为0,10个特征值为1,那么,可以认为:花瓣宽度特征值为0的,大概率属于2类花,错误数为45,错误率为
30
+
15
30
+
15
+
40
\frac{30+15}{30+15+40}
30+15+4030+15=53%;花瓣长度特征值为1的,大概率属于1类花,错误数为30,错误率为
20
+
10
20
+
35
+
10
\frac{20+10}{20+35+10}
20+35+1020+10=46%。因此,利用花瓣长度进行分类,总的错误数为75。
对比以上两个指标,利用花瓣长度作为分类指标的准确度要高于利用花瓣宽度作为分类指标(课本的案例里比较的是总的错误数),类似的,还可以得到用花萼的长、宽作为分类指标时的错误数,把这四个指标的错误数进行比较,可以得到相对来说最准确的分类指标。
至此,train的阶段结束,接下来是利用一部分在train阶段没有用到的花朵数据进行test。这一些花的类型是提前已经确定的,保存在y_test中,但是模型并不知道它们分别属于哪一类。模型需要根据前一阶段选择的指标进行分类,例如用花瓣长度分类:对于花瓣长度特征值为0的,分入0类花;特征值为1的,分入2类花,这样可以得到一个由模型得出这一些花的类型y_predict。通过比较y_test和y_predict的相似性就可以得到这个模型的准确率。
代码实现
#导入数据集并进行预处理
from sklearn.datasets import load_iris
import numpy as np
dataset = load_iris()
X = dataset.data #X是每一朵花的特征值[萼片长,萼片宽,花瓣长,花瓣宽]
y = dataset.target #y记录了每一朵花的类型
attribute_means = X.mean(axis = 0)
X_d = np.array(X >= attribute_means,dtype = 'int')
from collections import defaultdict
from operator import itemgetter
#对于某个特征项的某个特征值,得到最可能的花类及其错误数
#例如,在第一部分中,得到了花瓣长度为0的花,最可能属于0类花,错误数为35
def train_feature_value(X,y_true,feature_index,value):
class_counts = defaultdict(int)
for sample,y in zip(X,y_true): #y为花的类别
if sample[feature_index] == value:#统计每一类花中,符合此特征值的花的个数
class_counts[y] += 1
sorted_class_counts = sorted(class_counts.items(),key = itemgetter(1),reverse = True)
#假设A类花中,符合花瓣长度为1的花数目最多,那么在预测时,花瓣长度为1的花最可能属于A类
most_frequent_class = sorted_class_counts[0][0]
#假设B、C两类花中,符合花瓣长度为1的数目分别为b,c,那么错误数就是b+c(书上讲的比较详细)
error = sum([class_count for class_value,class_count in class_counts.items() if class_value != most_frequent_class])
return most_frequent_class,error
上面是根据某一个特征项的某一个特征值来预测类别,但是每一个特征项都有多个(2个)特征值,所以要遍历每一个特征值(就像根据花瓣长度为0可以有很大把握将花归到0类,还要根据花瓣长度为1将花归到2类)。
def train_on_feature(X,y_true,feature_index):
values = set(X_d[:,feature_index])#得到某个特征项的全部特征值
predictors = {} #predictors的作用就是根据特征值,判断一朵花最可能属于哪一类
errors = []
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
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X_d,y,random_state = 14)
all_predictors = {}
errors = {}
#遍历每一个特征项,求利用该特征项作为分类指标时的错误率以及predictor
for feature_index in range(X_train.shape[1]):
predictor,total_error = train_on_feature(X_train,y_train,feature_index)
all_predictors[feature_index] = predictor
errors[feature_index] = total_error
#选出利用哪个特征项作为分类指标会得到最少的错误数
best_feature,best_error = sorted(errors.items(),key = itemgetter(1))[0]
model = {'variable':best_feature,'predictor':all_predictors[best_feature]}
接下来利用新数据对模型test
def predict(X_test,model):
varible = model['variable']
predictor = model['predictor']
y_predict = np.array([predictor[sample[varible]] for sample in X_test])
return y_predict
y_predict = predict(X_test,model)
accuracy = np.mean(y_test == y_predict) * 100
print('The test accuracy is {:.1f}%'.format(accuracy))
ps:
1、如果理解起来很麻烦,可以尝试将X、y、predictor、all_predictors等打印出来,看一下里面的内容。
2、书上的代码有几处错误,可以直接从网站下载示例代码(第一章,提取码:vszi)。