what/why/how
数据处理——确定模型——算法训练——预测分析
机器学习——线性回归
overfitting 过拟合
regularization 正则化
ridge regression 岭回归
有这么一个库 scikit-learn,让我们判断用哪一个模型
1、KNN
从训练集中找到和新数据最接近的k条记录
根据他们的主要分类来决定新数据的类别
要点:
1.如何判断他们最接近,怎么决定他们的距离(非常决定性能的因素)
2.按照k个里最邻近的那个还是类别最多的那个还是权重加权的?
例子:手写识别:MNIST train.csv
0:label(数字具体是什么)
1-784pixels(灰度值)
方法:余弦定理——判断他们之间的相似度。
两个向量,当两个向量夹角比较小的时候,会比较相似,夹角比较大的时候,不相似。
# -*- coding: utf-8 -*- # CopyRight by heibanke import pandas as pd import numpy as np import time def normalize(x): """ linalg.norm(x), return sum(abs(xi)**2)**0.5 apply_along_axis(func, axis, x), """ #归一化——公式的被除数 norms = np.apply_along_axis(np.linalg.norm, 1, x) + 1.0e-7 return x / np.expand_dims(norms, -1) #作者自己想到的一个归一化的方法 def normalize2(x): """ linalg.norm(x), return sum(abs(xi)**2)**0.5 apply_along_axis(func, axis, x), """ norms = np.apply_along_axis(np.mean, 1, x) + 1.0e-7 return x - np.expand_dims(norms, -1) def nearest_neighbor(norm_func,train_x, train_y, test_x): train_x = norm_func(train_x) test_x = norm_func(test_x) # cosine #test_x就是测试数据,train_x是训练数据,分别相当于j,i corr = np.dot(test_x, np.transpose(train_x)) argmax = np.argmax(corr, axis=1) #然后找一个最大值作为预测值 preds = train_y[argmax] #上边如果采用for循环的形式会更好看一些,但是运行速度会慢一些。 #采用矩阵的形式会快 return preds def validate(preds, test_y): count = len(preds) #对所有正确的进行sum()求和 correct = (preds == test_y).sum() #然后对争取的的总和除以数据总和 return float(correct) / count if __name__=='__main__': TRAIN_NUM = 22 TEST_NUM = 42 # Read data 42000 data = pd.read_csv('train.csv') train_data = data.values[0:TRAIN_NUM,1:] train_label = data.values[0:TRAIN_NUM,0] test_data = data.values[TRAIN_NUM:TEST_NUM,1:] test_label = data.values[TRAIN_NUM:TEST_NUM,0] #这里采用三种方式,一种是公式型的归一化,第二种是减去均值的归一化,第三种没有归一化,直接就是两个向量相关 norm_funcs = [normalize,normalize2,lambda x:x] for norm_f in norm_funcs: t = time.time() preds = nearest_neighbor(norm_f,train_data, train_label, test_data) #acc求出来的就是准确率 acc = validate(preds, test_label) print("%s Validation Accuracy: %f, %.2fs" % (norm_f.__name__,acc, time.time() - t))
我们把TRAIN_NUM = 22
TEST_NUM = 42从2200,4200,;220,420;22,42进行设置处理
可见数据量越大,准确率就会越高。
现在我们用scikit learn的一个库来实现一下。
import pandas as pd from sklearn.decomposition import PCA from sklearn.neighbors import KNeighborsClassifier from sklearn import svm import time if __name__=='__main__': # maximum num is 42000 TRAIN_NUM = 22000 TEST_NUM = 42000 """ train_data: 训练数据 train_label: 训练数据的正确输出 test_data: 测试数据 test_label: 测试数据的正确输出 """ data = pd.read_csv('train.csv') train_data = data.values[0:TRAIN_NUM,1:] train_label = data.values[0:TRAIN_NUM,0] test_data = data.values[TRAIN_NUM:TEST_NUM,1:] test_label = data.values[TRAIN_NUM:TEST_NUM,0] t = time.time() # PCA, principal components analysis # http://blog.jobbole.com/86905/ # http://ufldl.stanford.edu/wiki/index.php/%E4%B8%BB%E6%88%90%E5%88%86%E5%88%86%E6%9E%90 #pca是取协方差的特征值和特征向量,取协方差的一些值作为坐标轴然后去映射 #计算量比较大 #思想:把主要成分作为分析依据,不重要的部分作为噪声去除掉 #如果n_components大于零的整数,则取这么多的特征 #如果是分数,则自动选择,按照比例选择 pca = PCA(n_components=0.8) train_x = pca.fit_transform(train_data) test_x = pca.transform(test_data) #knn regression #knn回归,我们取k为4,可能说做一个加权,详细还是要看源代码 neighbor = KNeighborsClassifier(n_neighbors=4) #fit是对模型一个训练,训练好的模型就可以直接用了 neighbor.fit(train_x, train_label) #预测 preds = neighbor.predict(test_x) #求准确率 acc = float((preds == test_label).sum())/len(test_x) print("KNN Validation Accuracy: %f, %.2fs" % (acc, time.time() - t)) # 22000, 96.7% #svm(Support Vector Machine) regression # 统计学习方法 # PRML t = time.time() #加了一个白话处理,如果不加的话,svm会差一下,目的是让处理后的数据方差都一致 pca = PCA(n_components=0.8,whiten=True) train_x = pca.fit_transform(train_data) test_x = pca.transform(test_data) #初始化,kernel核方法,C是惩罚因子 svc = svm.SVC(kernel='rbf',C=10) svc.fit(train_x, train_label) preds = svc.predict(test_x) acc = float((preds == test_label).sum())/len(test_x) print("SVM Validation Accuracy: %f, %.2fs" % (acc, time.time() - t)) # 22000, 97.8%
距离依据很重要。
二、非监督学习之k-means
1、选择k个点作为初始中心
2、将每个点指派到最近的中心,形成k个簇cluster
3、重新计算每个簇的中心
4、如果簇中心发生明显变化或未达到最大迭代次数,则回到step2
问题:初始点不对的时候,容易收敛到局部最优值
解决办法:
1、选择k个点作为初始中心——canopy,模拟退火,贝叶斯准则
2、将每个点指派到最近的中心,形成k个簇cluster
3、重新计算每个簇的中心
4、如果簇中心发生了明显的变化或未达到最大迭代次数,则回到step2
例子:给你一幅图像,找出其中最主要的三种颜色,并将图片用三种最主要的颜色表示出来
# -*- coding: utf-8 -*- # https://github.com/ZeevG/python-dominant-image-colour # commented by heibanke from PIL import Image import random import numpy class Cluster(object): """ pixels: 主要颜色所依据的像素点 centroid: 主要颜色的RGB值 """ def __init__(self): self.pixels = [] self.centroid = None def addPoint(self, pixel): self.pixels.append(pixel) def setNewCentroid(self): """ 通过pixels均值重新计算主要颜色 """ R = [colour[0] for colour in self.pixels] G = [colour[1] for colour in self.pixels] B = [colour[2] for colour in self.pixels] R = sum(R) / len(R) G = sum(G) / len(G) B = sum(B) / len(B) self.centroid = (R, G, B) self.pixels = [] return self.centroid class Kmeans(object): def __init__(self, k=3, max_iterations=5, min_distance=5.0, size=400): """ k: 主要颜色的分类个数 max_iterations: 最大迭代次数 min_distance: 当新的颜色和老颜色的距离小于该最小距离时,提前终止迭代 size: 用于计算的图像大小 """ self.k = k self.max_iterations = max_iterations self.min_distance = min_distance self.size = (size, size) def run(self, image): self.image = image #生成缩略图,节省运算量 self.image.thumbnail(self.size) self.pixels = numpy.array(image.getdata(), dtype=numpy.uint8) self.clusters = [None]*self.k self.oldClusters = None #在图像中随机选择k个像素作为初始主要颜色 randomPixels = random.sample(self.pixels, self.k) for idx in range(self.k): self.clusters[idx] = Cluster() self.clusters[idx].centroid = randomPixels[idx] iterations = 0 #开始迭代 while self.shouldExit(iterations) is False: self.oldClusters = [cluster.centroid for cluster in self.clusters] print iterations #对pixel和self.clusters中的主要颜色分别计算距离,将pixel加入到离它最近的主要颜色所在的cluster中 for pixel in self.pixels: self.assignClusters(pixel) #对每个cluster中的pixels,重新计算新的主要颜色 for cluster in self.clusters: cluster.setNewCentroid() iterations += 1 return [cluster.centroid for cluster in self.clusters] def assignClusters(self, pixel): shortest = float('Inf') for cluster in self.clusters: distance = self.calcDistance(cluster.centroid, pixel) if distance < shortest: shortest = distance nearest = cluster nearest.addPoint(pixel) def calcDistance(self, a, b): result = numpy.sqrt(sum((a - b) ** 2)) return result def shouldExit(self, iterations): if self.oldClusters is None: return False #计算新的中心和老的中心之间的距离 for idx in range(self.k): dist = self.calcDistance( numpy.array(self.clusters[idx].centroid), numpy.array(self.oldClusters[idx]) ) if dist < self.min_distance: return True if iterations <= self.max_iterations: return False return True # The remaining methods are used for debugging def showImage(self): """ 显示原始图像 """ self.image.show() def showCentroidColours(self): """ 显示主要颜色 """ for cluster in self.clusters: image = Image.new("RGB", (200, 200), cluster.centroid) image.show() def showClustering(self): """ 将原始图像的像素完全替换为主要颜色后的效果 """ localPixels = [None] * len(self.image.getdata()) for idx, pixel in enumerate(self.pixels): shortest = float('Inf') for cluster in self.clusters: distance = self.calcDistance( cluster.centroid, pixel ) if distance < shortest: shortest = distance nearest = cluster localPixels[idx] = nearest.centroid w, h = self.image.size localPixels = numpy.asarray(localPixels)\ .astype('uint8')\ .reshape((h, w, 3)) colourMap = Image.fromarray(localPixels) return colourMap if __name__=="__main__": from PIL import Image import os k_image=Kmeans(k=3) #默认参数 path = './pics/' fp = open('file_color.txt','w') for filename in os.listdir(path): print path+filename try: color = k_image.run(Image.open(path+filename)) #把图像用三种主要颜色显示出来 w_image = k_image.showClustering() w_image.save(path+'mean_'+filename,'jpeg') fp.write('The color of '+filename+' is '+str(color)+'\n') except: print "This file format is not support" fp.close()
处理前的图片:
处理后的图片: