用户:四九圣尊查看:16 回复:15 评论:16 创建时间:2018-10-04T12:15:48
之前的聚类问题的数据分布都是这样的:我们使用kmeans可以较好的解决这个问题:
那么当数据一开始是这样的呢:
要求kmeans分出黄色和紫色的类别。这时,稍微想想也知道不可能。kmeans只能处理线性数据。那么这时我们就要将上图变换成线性数据,这时就要用到核函数(kernels)了。
什么是核函数,理解起来比较复杂,这里多引用几个例子:
1.你在你的一生中可能会经历很多变故,可能会变成完全不同的另一个人,但是这个世界上只有一个你,我要怎样才能把不同的“你”分开呢?最直观的方法就是增加“时间”这个维度,虽然这个地球上只有一个你,这个你是不可分割的,但是“昨天在中国的你”和“今天在喵的你”在时间+空间这个维度却是可以被分割的。 (转载来源:csdn)
2.
这张图是不是更加直观?
核函数就是将低维度数据映射到高维度,它有很多种,这里我们采用二阶多项式核:
。这个公式将二位数据投影到三维。证明很简单:
(注意:<x,y>指的是x和y的点积。假设为<[1,2,3],[4,5,6]> = [1*2,2*5,3*6]=[2,10,18]。第二步用到了完全平方公式(x+y)**2 = x**2 + y**2 + 2xy)
用这个核将我们的数据集映射到三维:
现在,黄色和紫色的点是不是就被分开了呢?可以被一条线划分。
代码:(手打好累。。。)
from matplotlib import pyplot as plt
import random
import numpy as np
from sklearn.datasets import make_circles
from mpl_toolkits.mplot3d import Axes3D
fig=plt.figure(1)
x1,y1=make_circles(n_samples=100,factor=0.3,noise=0.1)
plt.subplot(121)
plt.title('make_circles function example')
plt.scatter(x1[:,0],x1[:,1],marker='o',c=y1)
plt.show()
x1 = [x.tolist() for x in x1]
x1_x = []
x1_y = []
x1_z = []
for i in range(len(x1)):
x1[i] = [x1[i][0]**2,(2**0.5)*x1[i][0]*x1[i][1],x1[i][1]**2]
for i in x1:
x1_x.append(i[0])
for i in x1:
x1_y.append(i[1])
for i in x1:
x1_z.append(i[2])
ax = plt.subplot(111, projection='3d')
ax.scatter(x1_x, x1_y, x1_z, c=y1)
plt.show()
然后用传统的kmeans聚类:
for i in range(1000):
y1 = y1.tolist()
for i in range(len(x1)):
if distance(d1[0], d1[1], d1[2], x1[i][0], x1[i][1], x1[i][2]) > distance(d2[0], d2[1], d2[2], x1[i][0], x1[i][1], x1[i][2]):
y1[i] = 1
else:
y1[i] = 0
ra_1x = 0
ra_1y = 0
ra_1z = 0
ra_1a = 0
ra_2x = 0
ra_2y = 0
ra_2z = 0
ra_2a = 0
for i in range(len(x1)):
if y1[i] == 1:
ra_1x += x1[i][0]
ra_1y += x1[i][1]
ra_1z += x1[i][2]
ra_1a += 1
else:
ra_2x += x1[i][0]
ra_2y += x1[i][1]
ra_2z += x1[i][2]
ra_2a += 1
ra_1x = ra_1x/ra_1a
ra_1y = ra_1y / ra_1a
ra_1z = ra_1z / ra_1a
ra_2x = ra_2x / ra_2a
ra_2y = ra_2y / ra_2a
ra_2z = ra_2z / ra_2a
d1 = [ra_1x,ra_1y,ra_1z]
d2 = [ra_2x,ra_2y,ra_2z]
y1 = np.array(y1)
注意,这里的distance换为:
def distance(x,y,z,x1,y1,z1):
one = abs(x-x1) ** 2
two = abs(y-y1) ** 2
three = abs(z-z1) ** 2
return (one+two+three) ** 0.5
三维空间两点距离!
结果:kmeans完全无法正常分类,说明在这个数据集上kmeans算法不太适合这种核函数。可以改用之前我们教的感知机算法。
当然,也可以替换核函数。
不过数据的升维已经将不可解的问题变得可解,希望大家可以运用这种思想处理复杂的数据。
转载一下知乎上的例子:
作者:王赟 Maigo我来举一个核函数把低维空间映射到高维空间的例子。
下面这张图位于第一、二象限内。我们关注红色的门,以及“北京四合院”这几个字下面的紫色的字母。我们把红色的门上的点看成是“+”数据,紫色字母上的点看成是“-”数据,它们的横、纵坐标是两个特征。显然,在这个二维空间内,“+”“-”两类数据不是线性可分的。
<figure>
</figure>
我们现在考虑核函数,即“内积平方”。
这里面是二维空间中的两个点。
这个核函数对应着一个二维空间到三维空间的映射,它的表达式是:
可以验证,
在P这个映射下,原来二维空间中的图在三维空间中的像是这个样子:
<figure><noscript><img src=" https://pic2.zhimg.com/c5a7b1b83b844fc5fff033c9a0d5d601_b.jpg" data-rawwidth="720" data-rawheight="342" class="origin_image zh-lightbox-thumb" width="720" data-original=" https://pic2.zhimg.com/c5a7b1b83b844fc5fff033c9a0d5d601_r.jpg"></noscript>
</figure>
(前后轴为x轴,左右轴为y轴,上下轴为z轴)
注意到绿色的平面可以完美地分割红色和紫色,也就是说,两类数据在三维空间中变成线性可分的了。
而三维中的这个判决边界,再映射回二维空间中是这样的:
<figure><noscript><img src=" https://pic3.zhimg.com/8f4a0d456fd9daf934c373024bf15a32_b.jpg" data-rawwidth="720" data-rawheight="329" class="origin_image zh-lightbox-thumb" width="720" data-original=" https://pic3.zhimg.com/8f4a0d456fd9daf934c373024bf15a32_r.jpg"></noscript>
</figure>
这是一条双曲线,它不是线性的
点赞0
评论
升维后直接用感知机就可以了:(参数多了一个,也就是:x*a1 + y*a2 + z*a3 + b)
a1 = 0
a2 = 0
a3 = 0
b = 0
lr = 0.1
def predict(x,y,z):
return x*a1 + y*a2 + z*a3 + b
for i in range(100):
for i in range(len(x1)):
if predict(x1[i][0],x1[i][1],x1[i][2])>=0 and y1[i] == -1:
a1 = a1 + lr*y1[i]*x1[i][0]
a2 = a2 + lr * y1[i] * x1[i][1]
a3 = a3 + lr * y1[i] * x1[i][2]
b = b+lr*y1[i]
if predict(x1[i][0],x1[i][1],x1[i][2])<0 and y1[i] == 1:
a1 = a1 + lr * y1[i] * x1[i][0]
a2 = a2 + lr * y1[i] * x1[i][1]
a3 = a3 + lr * y1[i] * x1[i][2]
b = b + lr * y1[i]
right = 0
for i in range(len(x1)):
if predict(x1[i][0],x1[i][1],x1[i][2])<0 and y1[i] == -1:
right += 1
if predict(x1[i][0],x1[i][1],x1[i][2])>=0 and y1[i] == 1:
right += 1
print(predict(x1[i][0], x1[i][1], x1[i][2]))
print(right)
点赞1
评论
之前核函数的概念写错了,它跟将数据映射到高维不是一个东西。他是将高维数据在低维计算。也就是说我们的数据分布图最后应该是这样的:
点赞0
评论
`丶丶老※点点工作室※imgsrc="https://static.codemao.cn/emoji/codemao/%E7%BC%96%E7%A8%8B%E7%8C%AB_%E7%BF%BB%E7%99%BD%E7%9C%BC.gif"alt="emotion_编程猫_翻白眼"
点赞0
评论