unit9 相亲匹配判别
《集体智慧编程》第九单元“高阶分类”主要亮点是相亲人员的匹配判断。是有监督的分析,基于一定量的有结果的试验数据,从中获得规律实现预测。使用高阶分类:核方法与支持向量机(SVM)训练模型并对配对进行判断。
01数据集介绍
假设某网站的相亲记录如下:每一行代表一个配对试验,记录女性和男性的年龄、是否吸烟、是否有孩子、兴趣、住址,以及是否配对成功(0表示失败,1表示成功)。
单提取男女年龄一项,看看相亲市场上年龄的配对情况。散点分布如下图。
横轴为female年龄:年轻的姑娘(<25)和40岁以上男性基本配对失败;
25-40岁的女性在配对上,对象的年龄并没有那么大限制,40岁的女性和20几岁的男性成功配对数也比较多。
40-50岁的女性和25岁以下的男性配对成功的概率较低
02 数据预处理
(1)数值化
将原始数据转换为数值型,可以方便模型的使用。
是否吸烟?是否有孩子:是1;否-1,模糊或确实或不清楚的为0
兴趣爱好:显示男女相同爱好的个数
地址显示男女间地址距离
预处理后数据集变量为:女性年龄,是否吸烟,是否有孩子,男性年龄,是否吸烟,是否有孩子,相同爱好,地址距离。
[39.0, 1, -1, 43.0, -1, 1, 0, 105.66516194012885]
[23.0, -1, -1, 30.0, -1, -1, 0, 1.319127371884788]
[50.0, -1, -1, 49.0, 1, 1, 2, 106.48245828168044]
[46.0, -1, 1, 19.0, -1, -1, 0, 110.56632686422407]
(2)标准化
由于不同变量的数值范围不同,需要做标准化处理,使数据范围在同一水平,便于比较。标准化处理后,每个变量范围在0-1之间,数据集如下所示:
[0.65625, 1.0, 0.0, 0.78125, 0.0, 1.0, 0.0, 0.9556721737702848]
[0.15625, 0.0, 0.0, 0.375, 0.0, 0.0, 0.0, 0.011930642984140028]
[1.0, 0.0, 0.0, 0.96875, 1.0, 1.0, 1.0, 0.9630640838095432]
[0.875, 0.0, 1.0, 0.03125, 0.0, 0.0, 0.0, 1.0]
03 核方法
核方法kernel methods (KMs)是一类模式识别的算法,是解决非线性模式分析问题的一种有效途径。
径向基
def rbf(v1, v2, gamma=10):
dv = [v1[i] - v2[i] for i in range(len(v1))]#点与点间的差
l = veclength(dv)
return math.e ** (-gamma * l)
偏移量
转换空间以后会发生改变。
def getoffset(rows, gamma=10):
l0 = []
l1 = []
#匹配成功的都提出来放在L1中,失败的都放在L0中.
for row in rows:
if row.match == 0:
l0.append(row.data)
else:
l1.append(row.data)
#向量V1、V2偏移量计算
sum0 = sum(sum([rbf(v1, v2, gamma) for v1 in l0]) for v2 in l0)
sum1 = sum(sum([rbf(v1, v2, gamma) for v1 in l1]) for v2 in l1)
return (1.0 / (len(l1) ** 2)) * sum1 - (1.0 / (len(l0) ** 2)) * sum0
ssoffset=getoffset(scaledset)#结果为0.05915809687556309
核方法
模型建立,基于径向量和偏移量,建立决策判断模型。
#输入:point(目标判断点), rows(数据集),offset(偏移量)
def nlclassify(point, rows, offset, gamma=10):
sum0 = 0.0
sum1 = 0.0
count0 = 0
count1 = 0
#配对成功/失败两个数据集径向基计算
for row in rows:
if row.match == 0:
sum0 += rbf(point, row.data, gamma)
count0 += 1
else:
sum1 += rbf(point, row.data, gamma)
count1 += 1
#核方法判断方程
y = (1.0 / count0) * sum0 - (1.0 / count1) * sum1 + offset
if y > 0:
return 0#配对失败
else:
return 1#配对成功
#判断[0.65625, 1.0, 0.0, 0.78125, 0.0, 1.0, 0.0, 0.9556721737702848]
nlclassify(scalef(numericalset[0].data),scaledset,ssoffset)#0;#scalef基于数据集的缩放函数
预测判断
例如有一组数据newrow=[23.0,-1,-1,30.0,-1,-1,0,1.3]。
女性23岁,不吸烟,无小孩;
男性30岁,不吸烟,无小孩;
无共同兴趣爱好,住址相距1.3
核方法判断结果为:配对成功(结果为:1)
nlclassify(scalef(newrow),scaledset,ssoffset)#1
04 SVM支持向量机
代码实现SVM很方便
from sklearn import svm
clf_linear = svm.SVC(kernel='linear').fit(inputs,answers)
clf_rbf = svm.SVC(kernel='rbf').fit(inputs,answers)
clf_sigmoid = svm.SVC(kernel='sigmoid').fit(inputs,answers)
训练号SVM模型以后,实现对未知分类的数据集预判。
a=scalef([23.0,-1,-1,30.0,-1,-1,0,1.3])
newrow=np.array([a])
clf_linear.predict(newrow)#array([0])
05 困难及问题
在对原始数据“地址”做处理计算两地间距离时,yahoo!map一直调试不出来无法获得地址的经纬度。数据集中的地址都是美国地址686 Avenue of the Americas New York NY
,经过多次尝试最后使用geopy包实现。
from geopy.geocoders import Nominatim
def geocodeN(address):
gps=Nominatim()
location=gps.geocode(address)
return location.longitude,location.latitude
geocodeN("220 W 42nd St New York NY")
#(-73.987958, 40.7563095),成功了
但问题是计算每一对距离都很耗时,实际操作中我只计算了20组数据的距离,造成核方法、SVM的训练数据太少,所以以上判断并不考虑准确性。
总之,模型实现其实还好,数据预处理花了很久折腾。