一、KNN算法
位置指纹法中最常用的算法是k最近邻(kNN):选取与当前RSS最邻近的k个指纹的位置估计当前位置,简单直观有效。
基本原理
位置指纹法可以看作是分类或回归问题(特征是RSS向量,标签是位置),监督式机器学习方法可以从数据中训练出一个从特征到标签的映射关系模型。kNN是一种很简单的监督式机器学习算法,可以用来做分类或回归。
对于在线RSS向量,分别计算它与指纹库中各个RSS向量之间的距离(比如欧氏距离),选取最近的k个位置指纹(一个指纹是一个RSS向量与一个位置的对应)。
-
对于knn回归,标签是坐标x和坐标y,可以进行数值计算,使用这k个指纹的位置坐标取平均,得到作为定位结果。
-
对于knn分类,将定位区域划分为1m××1m的网格,每个网格是看作一个类别,用网格标号代替,对k个网格标号计数投票,选择票数做多的网格作为定位结果。
kNN是一种lazy式的学习方法,在上面的过程中不需要使用训练数据进行“学习”,在定位的时候直接在训练数据中搜索就可以。一些工具包中的kNN算法的训练过程中会建立一个kd树(一种数据结构),有利于在线预测时的搜索。
具体实现(python)
回归(RSS向量+坐标):
import numpy as np
import time
start_time = time.time()
## 准备数据
train_data = train_arr3[:,0:(train_arr3.shape[1]-2)]
train_crd = train_arr3[:,(train_arr3.shape[1]-2):train_arr3.shape[1]]
test_data = test_arr3[:,0:(test_arr3.shape[1]-2)]
test_crd = test_arr3[:,(test_arr3.shape[1]-2):test_arr3.shape[1]]
## 2.定义准确度函数
def getAccuracy(pred_crd,test_crd):
return np.mean(np.sqrt(np.sum((pred_crd-test_crd)**2,1)))
## 3.导入KNN模块
from sklearn.neighbors import KNeighborsRegressor
knn = KNeighborsRegressor(4, weights='uniform', metric='euclidean')
%time knn.fit(train_data, train_crd)
%time pred_crd = knn.predict(test_data)
accuracy = getAccuracy(pred_crd, test_crd)
print("accuracy: ", accuracy, "m")
print("--- Run time: %s mins ---" % np.round(((time.time() - start_time)/60),4))
分类(RSS向量+标签):
import numpy as np
import time
start_time = time.time()
## 准备数据
train_data = train_arr3[:,0:(train_arr3.shape[1]-2)]
train_label = train_arr3[:,train_arr3.shape[1]]
test_data = test_arr3[:,0:(test_arr3.shape[1]-2)]
test_label = test_arr3[:,test_arr3.shape[1]]
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(4, weights='uniform', metric='euclidean')
%time knn.fit(train_data, train_label)
%time pred_label = knn.predict(test_data)
sum = 0
for a, y in zip(pred_label, test_label.ravel()):
if a == y:
sum = sum + 1
print ("%s of %s test values correct.\ntest accuracy: %f" % (sum, len(test_label.ravel()), sum / len(test_label.ravel())))
print("test time:",round(time.time() - start_time, 3), "s")
二、WKNN算法(回归)
import pandas as pd
import numpy as np
import operator
##导入原始数据
train_file = pd.read_csv('E:\\wifi定位数据集\\library dataset\\dataset_all\\04\\train_floor3.csv',header=None)
test_file = pd.read_csv('E:\\wifi定位数据集\\library dataset\\dataset_all\\04\\test_floor3.csv',header=None)
train_file.replace(-105,-100,inplace=True) # 缺失值用-100替换
test_file.replace(-105,-100,inplace=True)
train_arr0 = train_file.iloc[:,0:622].values # DataFrame 转换成 array
test_arr0 = test_file.iloc[:,0:622].values
##1.定义计算欧式距离的函数
def euclideanDistance(instance1,instance2,length):
dis0 = 0
for i in range(0,length):
dis0 += (instance1[i]-instance2[i])**2
return dis0**0.5
##2.计算测试点到所有RP距离的函数,并取距离最小的K个
def getNeighbors(trainSet,testPoint,k):
distance = []
length = len(testPoint)-2
for i in range(0,len(trainSet)):
dis1 = euclideanDistance(testPoint,trainSet[i],length)
distance.append((trainSet[i],dis1))
distance.sort(key = operator.itemgetter(1)) ## 对距离按照第二个域排序
neighbors = []
for j in range(0,k):
neighbors.append(distance[j])
return neighbors
##3.计算K个RP坐标的加权平均值
def getResponse(neighbors):
add_weight = 0
crd = 0
for i in range(0,len(neighbors)):
add_weight += 1/neighbors[i][1]
for j in range(0,len(neighbors)):
crd += (neighbors[j][0][97:99]/neighbors[j][1])/add_weight
return crd
##4.定义准确度的函数
def getAccuracy(pred_crd,test_crd):
return np.mean(np.sqrt(np.sum((pred_crd-test_crd)**2,1)))
##5.主函数
train_file = train_arr0[:,0:620]
test_file = test_arr0[:,0:620]
test_crd = test_arr0[:,620:622]
k = 4
pred_crd = []
for i in range(0,len(test_file)):
neighbors = getNeighbors(train_file, test_file[i], k)
crd = getResponse(neighbors)
pred_crd.append(crd)
accuracy = getAccuracy(pred_crd,test_crd)
print("accuracy:" + repr(accuracy) + "m") ## print()内输出的内容格式必须一致
print("--- Run time: %s mins ---" % np.round(((time.time() - start_time)/60),4))
参考:http://www.indoorpress.com/shi-nei-ding-wei-4247.html