上数据挖掘课的时候,有点好奇为什么数据维数高时最近邻无意义,现在简单验证了一下
数据模拟
假定所有数据的每一维特征都在 [ 0 , 1 ) [0,1) [0,1)内,利用numpy能方便地生成这样的数据:
def generate_data(size, d):
return np.random.random((size,d))
开始验证
距离计算方式采用欧氏距离:
def compute_distance(p1, p2):
return np.sqrt(np.sum(np.square(p1 - p2)))
尝试1
计算数据集中任意两点的最大距离和数据集中样本点之间的平均距离,发现随着维数增加,这两个值也在随之增加。(不是说样本之间的差异性会变小吗?)
但是想一下,就能明白了:
维数为
1
1
1时,最大距离为
1
=
1
\sqrt{1}=1
1=1,维数为
2
2
2时,最大距离为
1
+
1
=
2
\sqrt{1+1}=\sqrt{2}
1+1=2,
n
n
n维的最大距离为
n
\sqrt{n}
n. 尽管样本点不一定能使最大距离能取到,但距离的取值范围发生了变化—它变大了
于是我们可以得出结论距离的绝对大小关系不能反映出问题
尝试2
问题的关键在于这些距离是不是变得相似了,而不是这些距离是不是变小了。Kevin Beyer在论文中写道:当维数趋于极限值时,查询点到数据集中所有点的距离都相等。以此可以想到一个新的验证思路:
随机取一个样本点,计算其他样本点到该点的距离,并计算这些距离的方差
结果又出问题了,好像并没有什么规律
现在思考一个问题:
简单数据集
d
1
=
0.9
,
1.1
d_{1}=0.9,1.1
d1=0.9,1.1,
v
a
r
1
=
0.
1
2
+
0.
1
2
2
var_{1}=\frac{0.1^{2}+0.1^{2}}{2}
var1=20.12+0.12
而
d
2
=
1.85
,
2.15
d_{2}=1.85,2.15
d2=1.85,2.15,
v
a
r
2
=
0.1
5
2
+
0.1
5
2
2
var_{2}=\frac{0.15^{2}+0.15^{2}}{2}
var2=20.152+0.152
显然
v
a
r
1
<
v
a
r
2
var_{1}<var_{2}
var1<var2,但是实际上
d
1
d_{1}
d1中样本与均值的相差百分比是
0.1
1
\frac{0.1}{1}
10.1,
d
2
d_{2}
d2则是
0.15
2
\frac{0.15}{2}
20.15.
也就是说
d
2
d_{2}
d2相差的幅度更小
尝试3
能不能把数据均一化一下呢?以消除数字大小对变化幅度的影响?一个简单的想法是除以最大距离,这样所有数据的范围就能被限定在
[
0
,
1
)
[0,1)
[0,1)内,即:
随机取一个样本点,计算其他样本点到该点的距离,并除以最大距离,计算这个结果的方差
def test_sample(data):
idx = np.random.randint(len(data))
distance = []
max_distance = None
for i in range(len(data)):
if i != idx:
d = compute_distance(data[i], data[idx])
distance.append(d)
if max_distance is None or d > max_distance:
max_distance = d
distance = np.array(distance)
return distance/max_distance
再来看看结果:
然后在不同大小的数据集上测试:
结论
当数据维数从
0
0
0~
10
10
10变化时,查询点到其他样本点的距离以极快的速度变得越来越相似。当数据维数趋近于无穷时,查询点到其他样本点的距离都相等,此时KNN已失去了效果
延伸思考:
计算距离相似度有没有更好的办法?
怎么证明数据维数趋近于无穷时,查询点到数据集中所有点的距离都相等?