原帖在这里,好久没看到这么清晰的机器学习的教程,所以自己也来试试了,选取的数据是Iris的数据,结果准确率很高,平均在94%左右.如果没有特别声明,一下属性
一般指的是植物的宽度之类的数据,种类
指的是不同种类的植物.
关于朴素贝叶斯
朴素贝叶斯算法是一个直观的方法,使用每个属性归属于某个类的概率来做预测。你可以使用这种监督性学习方法,对一个预测性建模问题进行概率建模。
给定一个类,朴素贝叶斯假设每个属性归属于此类的概率独立于其余所有属性,从而简化了概率的计算。这种强假定产生了一个快速、有效的方法。
给定一个属性值,其属于某个类的概率叫做条件概率。对于一个给定的类值,将每个属性的条件概率相乘,便得到一个数据样本属于某个类的概率。
我们可以通过计算样本归属于每个类的概率,然后选择具有最高概率的类来做预测。
通常,我们使用分类数据来描述朴素贝叶斯,因为这样容易通过比率来描述、计算。一个符合我们目的、比较有用的算法需要支持数值属性,同时假设每一个数值属性服从正态分布(分布在一个钟形曲线上),这又是一个强假设,但是依然能够给出一个健壮的结果。
根据花萼和花瓣的长度和宽度预测它的属性
本文使用的测试问题是”安德森鸢尾花卉”的属性问题,IRIS数据集一共包括150个数据集,分为三类,每类50个数据,每个数据包含四个属性,分别是花萼和花瓣的长度和宽度,最后1条记录是属性值,0,1,2分别代表三种不同的植物
下面是iris数据集的一个样本
1 2 3 4 5
| 5.1,3.5,1.4,0.2,0 4.9,3.0,1.4,0.2,0 4.7,3.2,1.3,0.2,0 4.6,3.1,1.5,0.2,0 5.0,3.6,1.4,0.2,0
|
基本做法和链接的那篇文章一样
朴素贝叶斯算法教程
教程分为如下几步:
1.处理数据:从CSV文件中载入数据,然后划分为训练集和测试集。
2.提取数据特征:提取训练数据集的属性特征,以便我们计算概率并做出预测。
3.单一预测:使用数据集的特征生成单个预测。
4.多重预测:基于给定测试数据集和一个已提取特征的训练数据集生成预测。
5.评估精度:评估对于测试数据集的预测精度作为预测正确率。
6.合并代码:使用所有代码呈现一个完整的、独立的朴素贝叶斯算法的实现。
1.处理数据
1 2 3 4 5 6 7 8 9 10 11
| def load_data(filename, ratio=0.67): data_set = [] train_set = [] fp = open(filename, "r") for line in fp: data_set.append([float(x) for x in line.replace("\n", "").split(',')]) limit = int(len(data_set) * ratio) while len(train_set) < limit: index = random.randrange(len(data_set)) train_set.append(data_set.pop(index)) return data_set, train_set
|
当然也可以在read的时候取随机
1 2 3 4 5 6 7 8 9 10 11 12
| def load_data(filename, ratio=0.67): test_set = [] train_set = [] fp = open(filename, "r") for line in fp: flag = random.randrange(1,101) if flag in range(1, int(ratio * 100) + 1): train_set.append([float(x) for x in line.replace("\n", "").split(',')]) else: test_set.append([float(x) for x in line.replace("\n", "").split(',')]) print len(train_set), len(test_set) return test_set, train_set
|
再按类别生成key-value对应的数据
1 2 3 4 5 6
| def separateByClass(dataset): result = defaultdict(list) for i in range(len(dataset)): classType = int(dataset[i][-1]) result[classType].append(dataset[i][:-1]) return result
|
计算均值还有方差以及概率密度函数
1 2 3 4 5 6 7 8 9 10
| def mean(numbers): return sum(numbers) / float(len(numbers)) def stdev(numbers): return math.sqrt(sum([pow(x - mean(numbers), 2) for x in numbers]) / float(len(numbers) - 1)) def calNumberProbability(mean, std, y): exponent = math.exp(-(math.pow(y - mean, 2)/(2*math.pow(std, 2)))) return (1 / (math.sqrt(2*math.pi) * std)) * exponent
|
训练模型,生成每个属性对应的平均值还有标准差
1 2 3 4 5 6
| def createMeanStdPair(result): summarise = defaultdict(list) for key in result: for type in zip(*result[key]): summarise[key].append([mean(type), stdev(type)]) return summarise
|
预测
准备工作都已经做完了,开始正事了,首先要说明,上面的步骤应该用训练数据去培训,下面用测试数据去生成结果.
1 2 3 4 5 6 7 8 9 10 11
| def labelOfVector(summarise, input_vector): summarise_prob = {} for key in summarise: init_prob = 1 for i in range(len(summarise[key])): mean, std = summarise[key][i] probability = calNumberProbability(mean, std, input_vector[i]) init_prob *= probability summarise_prob[key] = init_prob return sorted(summarise_prob.items(),key=lambda x:x[1])[-1][0]
|
计算精度
1 2 3 4 5 6 7 8 9 10 11
| def main(summarise, test_set): count = 0 sum_vector = 0 for key in test_set: sum_vector += len(test_set[key]) for vector in test_set[key]: label = labelOfVector(summarise, vector) if label == key: count += 1 print "测试数据一共{0}条,正确率为{1}%".format(sum_vector, (count / float(sum_vector)) * 100)
|
运行程序,得到结果
1
| 测试数据一共48条,正确率为95.8333333333%
|
不同种类的植物的区分度很大,且各个属性之间可看作是独立的.
下面我们来看看用现成的scikit-learn
包怎么做.官方文档
测试的问题是“皮马印第安人糖尿病问题”。
这个问题包括768个对于皮马印第安患者的医疗观测细节,记录所描述的瞬时测量取自诸如患者的年纪,怀孕和血液检查的次数。所有患者都是21岁以上(含21岁)的女性,所有属性都是数值型,而且属性的单位各不相同。
每一个记录归属于一个类,这个类指明以测量时间为止,患者是否是在5年之内感染的糖尿病。如果是,则为1,否则为0。
机器学习文献中已经多次研究了这个标准数据集,好的预测精度为70%-76%。下面是pima-indians.data.csv文件中的一个样本,了解一下我们将要使用的数据。
1 2 3 4 5
| 6,148,72,35,0,33.6,0.627,50,1 1,85,66,29,0,26.6,0.351,31,0 8,183,64,0,0,23.3,0.672,32,1 1,89,66,23,94,28.1,0.167,21,0 0,137,40,35,168,43.1,2.288,33,1
|
基本方式和上面类似,我们也用高斯,不知道翻译成什么,直接用Gaussian Naive Bayes代替吧
1.处理数据
这里要注意数据都要处理成array格式的
步骤和上面的类似,先把初始数据处理成train_data
和test_data
.有两点不同需要注意一下.
- 将测量数据和类别数据分开
- 将数据用numpy处理成array格式的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| def load_data(filename, ratio=0.67): test_set = [] train_set = [] train_features = [] test_features = [] fp = open(filename, "r") for line in fp: flag = random.randrange(1,101) if flag in range(1, int(ratio * 100) + 1): train_set.append([float(x) for x in line.replace("\n", "").split(',')[:-1]]) train_features.append(int(line.replace("\n", "").split(',')[-1])) else: test_set.append([float(x) for x in line.replace("\n", "").split(',')[:-1]]) test_features.append(int(line.replace("\n", "").split(',')[-1])) return np.array(test_set), np.array(train_set), np.array(train_features), np.array(test_features)
|
2.建立模型
1 2 3 4 5
| from sklearn.naive_bayes import GaussianNB gnb = GaussianNB() y_pred = gnb.fit(train_set, train_features).predict(test_set) print("split %d rows into train=%d and test=%d rows \nAccuracy: %.2f%%"\ % (len(test_set) + train_set.shape[0], train_set.shape[0], test_set.shape[0], (test_features == y_pred).sum() * 100 / float(test_set.shape[0])))
|
输出结果如下:
1 2
| split 768 rows into train=524 and test=244 rows Accuracy: 79.92%
|
不得不说有scikit-learn
包以后简单了很多, T T.