目前一些姻缘网站专门给人介绍对象,也经常有人陷入介绍门中,怎么样来提高准确率降低网站带来的风险呢?其实里面有些推荐算法和匹配算法在里面,今天我们简单介绍其中一种。
大家是否还记得在第一次注册的会员的时候,它会让你填一些年龄、性格、体貌特征选项等等,其实这些都是有用的个人特征数据,网站拿到这些数据之后会根据数据给你匹配最可能适合你的妹子,提高成功率,下面我们就来看一下它是如何给你匹配对象的,里面可能用到了k-近邻算法。
上一篇博文已经介绍过它的原理背景以及实现方式,相信大家已经了解,现在假设把喜欢的妹子归类为三种人:不喜欢的人、魅力一般的人、极具魅力的人,我们都希望找到极具魅力的人,理想的白富美,分类目标是把网站推荐给我们的人自动分到这三类中,该如何分类呢?
当我们有了这样一个业务场景或者想法之后,接下来需要考虑有没有特征项、有多少特征项、有哪些特征权重大对分类结果有帮助等,这些都是我们需要考虑的问题,俗话说“巧妇难为无米之炊”就是这个道理,有米好下锅。假设我们已经收集了三个重要特征
1.每年获得飞行常客里程数
2.玩视频游戏所耗时间百分比
3.每周消费的冰激凌公升数
数据如下:
上图中的第一列、二列、三列分别对应上面三个特征,最右侧为类别标签标示该样本属于哪一类,
收集数据有各种方法,如业务系统平时产生的日志数据、物理设备收集的数据等,或者使用问卷调查或其它方式,只要收集的有用的数据都是可以的。
在有了数据以及确定了哪些特征列之后就需要将保存在DB或者文件里面的数据处理为可以让程序读入的数据了,将数据处理为程序可以理解的格式,这里的程序可以是python也可以是其它处理程序,程序可以处理即可,一般我们会把数据处理抽象出来一个函数,如下代码是激昂上面的数据文件转为python数据对象。
def file2matrix(filename):
'''
从文件加载数据 返回训练集和类别标签
:param filename:数据文件
:return:特征训练集、列表标签
'''
# 打开数据文件
fr = open(filename)
# 获取样本个数
arrayOLines = fr.readlines()
# 获取样本个数
numberOfLines = len(arrayOLines)
# 初始化特征矩阵
returnMat = np.zeros((numberOfLines,3))
# 初始化标签数组
classLabelVector = []
# 样本的索引、序号
index = 0
for line in arrayOLines:
# 每行两边去空格
line = line.strip()
# 以制表符分割每项
listFromLine = line.split('\t')
# 前三列存入特征矩阵中
returnMat[index,:] = listFromLine[0:3]
# 最后一列为类别标签存入列表数组中
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat,classLabelVector
分析数据是为了确保收集的数据可用、有价值,即研究数据可用性、可靠性、准确性等为目的的,而通常为了直观感受数据我们经常以图形化的形式将数据展示出来,如散点图、条形图等下面我们先拿特征数据的第二列和第三列“玩视频游戏所耗时间百分比”和“每周所消耗的冰淇淋公升数”来绘制一幅散点图,先来看看效果如何
从数据集来看,第一列数据明显比其它两列值大很多,为了减少值得差异性带来的误差,需要对大值数据做一下处理,此处
采用均值法,每项的值=(当前值-最小值)/ (最大值-最小值),这样处理过的数据取值范围都在0-1之间,符合我们的预期,自动处理归一化函数如下:
def autoNorm(dataSet):
'''
归一化数值
:param dataSet:待处理数据集
:return:处理后的结果
'''
# 第一列的最小值
minVals = dataSet.min(0)
# 第一列的最大值
maxVals = dataSet.max(0)
# 取值范围
ranges = maxVals - minVals
# 初始化全为0的矩阵
normDataSet = np.zeros(np.shape(dataSet))
# 获取行数
m = dataSet.shape[0]
# 将最小值重复m行 1列输出,相减
normDataSet = dataSet - np.tile(minVals,(m,1))
# 将取值范围重复m行1列输出,相除
normDataSet = normDataSet / np.tile(ranges,(m,1))
# 返回处理后的矩阵、取值范围、最小值
return normDataSet,ranges,minVals
def createScatterGraph(datingDataMat,datingDataLabels):
'''
根据矩阵数据创建散点图
:param datingDataMat: 矩阵
:param datingDataLabels: 类别标签
:return:
'''
# 创建一个区域显示数据
fig = plt.figure()
ax = fig.add_subplot(111)
# 加载2、3列数据
ax.scatter(datingDataMat[:,1],datingDataMat[:,2])
plt.show()
从图中很难以分辨出来样本究竟属于哪一类,这是由于没有把类别标签加入,为了好看我们再把不同类别的样本加上不同的颜色,图下图(图片,加入颜色后)
’
如上图所示,假如类别标签的数据已经很明显看出来是属于哪一类别,三种颜色十分明显,现在效果明显了还存在排列混乱的问题,因为我们的最终目的是为了分类不是展示数据,需要将三种分类明确的分出来,让我们来试试第一列和第二列展示数据。
ax.scatter(datingDataMat[:, 0], datingDataMat[:, 1], 15.0 * np.array(datingDataLabels),
15.0 * np.array(datingDataLabels))
当我们设计的一个学习分类器完成的时候,一个重要事情就是评估算法的好坏,这也决定了该算法能否上线的依据,在java开发中大家都知道有白盒测试、黑盒测试、冒烟测试等,那么在机器学习中是否一样有哪些测试方法呢?最常用的是交叉验证测试法,交叉验证又可以细分为很多种,常用的有三种,这里我们使用第一种简单方法即随机抽取90%数据作为训练集数据 10%作为测试集合数据,代码如下:
def datingClassTest():
'''
测试分类器的效果 错误率大小
:return:
'''
# 调节测试样本集大小参数
hoRatio = 0.10
# 加载样本数据
datingDataMat,datingDataLabels = file2matrix('datingTestSet2.txt')
# 数据归一化处理
normMat,ranges,minVals = autoNorm(datingDataMat)
# 获取样本个数
m = normMat.shape[0]
# 测试集样本个数
numTestVecs = int(m*hoRatio)
# 保存错误的次数
errorCount = 0.0
# 循环错误集
for i in range(numTestVecs):
# 获取分类结果 参数为:待测样本向量、已经样本集、已知分类标签、k值
classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingDataLabels[numTestVecs:m],3)
print "the classifier came back with: %d,the real answer is: %d" % (classifierResult,datingDataLabels[i])
# 统计错误次数
if (classifierResult != datingDataLabels[i]):
errorCount += 1.0
# 计算错误率 错误次数/测试样本个数
print "the total error rate is: %f" % (errorCount/float(numTestVecs))
上面我们的算法已经测试完毕,接下来即可进入使用环节,这个环节我觉得可以提供出来一些页面或者网页供用户使用,用户输入某个人的信息然后返回给用户他是否会喜欢对方,这样对于用户体验、用户效果要好一些,为了方便这里就不绘制界面了,只是来使用下效果如何。
def classifyPerson():
'''
检验约会网站对象预测结果
:return:
'''
# 结果
resultList = ['不喜欢','有点喜欢','很喜欢']
# 输入特征
percentTats = float(raw_input("玩网游所消耗的时间比"))
ffMiles = float(raw_input("每年获得的飞行常客里程数"))
iceCream = float(raw_input("每年消费的冰淇淋公升数"))
# 加载数据
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')
# 归一化处理
normMat,ranges,minVals = autoNorm(datingDataMat)
# 生成特征向量
inArr = np.array([ffMiles,percentTats,iceCream])
# 预测
classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
print "you will probably like this person:",resultList[classifierResult-1]
根据结果来看我还是喜欢旅游多一点、玩网游少一点的妹子
knn优缺点上篇已经总结,这里说说对算法或机器学习的理解,各种机器学习算法层出不穷如何才能学好各种算法呢,这是值得思考的一个问题,我我觉得首先第一步还是要深刻理解这一领域涉及到的各种概念,知道原因了才能有深入的理解,其次是工欲善其事,必先利其器,一些工具函数统计学、数学基础要掌握,知道灵活运用。比如为什么机器学习中都使用矩阵来处理数据?知道原因才能想到如果自己写个算法怎么处理数据,下一篇计划总结一下贝叶斯算法,待续…………
井盖为什么是园的而不是方的谈认知观?
生活中其实处处都能体现出来人们的思想和想法,只要我们细心观察有一颗发现问题的心,牛顿为什么发现苹果?自然界或者人类社会中其实没有什么事情本来就是那样的,不同的认知观会发现不同的问题,如果当你看到井盖时是否会想到为什么是圆的,还是觉得它本来就是那样,两种不同的认知观会有不同的结果。
有了认知观后,其次需要思考园的和方的区别在哪里,从易于使用、制造等多方面思考,就会发现哪种会好一些,生活中也没有标准答案一说,以前的教学给我们灌输的是标准答案,其实在不同条件、不同场景下,我们追求的结果可能是不同的,这就引出来因果学说。