16 Oct 2019 6029字 21分 次 机器学习
如果这篇博客帮助到你,可以请我喝一杯咖啡~
CC BY 4.0 (除特别声明或转载文章外) 用 Python 访问 Baidu Web 的 API,先用 Baidu Web 的 API 获得数据,然后用 kMeans 算法对地理位置进行聚类,并对聚类得到的簇进行后处理。
实验目的
利用 python 实现 kMeans 算法
实验环境
硬件
所用机器型号为 VAIO Z Flip 2016
- Intel(R) Core(TM) i7-6567U CPU @3.30GHZ 3.31GHz
- 8.00GB RAM
软件
- Windows 10, 64-bit (Build 17763) 10.0.17763
- Visual Studio Code 1.39.2
- Python 2019.10.41019:九月底发布的 VSCode Python 插件支持在编辑器窗口内原生运行 juyter nootbook 了,非常赞!
- Remote - WSL 0.39.9:配合 WSL,在 Windows 上获得 Linux 接近原生环境的体验。
- Windows Subsystem for Linux [Ubuntu 18.04.2 LTS]:WSL 是以软件的形式运行在 Windows 下的 Linux 子系统,是近些年微软推出来的新工具,可以在 Windows 系统上原生运行 Linux。
- Python 3.7.4 64-bit (‘anaconda3’:virtualenv):安装在 WSL 中。
获取地图数据
百度地图提供 API 的网址:http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-placeapi
注册成为开发者
注册登录百度账号之后,点击获取秘钥,弹出注册成为开发者页面。
点击创建应用:注意:IP 白名单中要填入访问方的公网 IP,查看 ip 白名单中的 ip 是否与本机 ip 一致,若不一致则改成本机 ip。
应用类型选择服务端,可以看到下面有需要的 Place API v2 服务。点击确定就可以看到秘钥。
使用 API 获取数据
查看网页,了解 API 的使用格式。API 的格式:
kMean 算法实现
建立辅助函数函数
loadDataSet()
读取文件的数据,函数distEclud()
计算两个向量的欧式距离,函数randCent()
随机生成 k 个随机质心。
kMean 算法实现
函数kMeans()
接受 4 个输入参数,只有数据集及簇的数目是必选参数,而计算距离和创建初始质心的函数都是可选的。
用 kMeans 算法对地图上的点聚类
餐厅是一个城市的重要组成部分,在北京城内有不少餐厅,当今地政府想要建立 4 个餐厅管理服务点,对整个北京中的餐厅进行管理,但是无法确定管理服务点要建在哪里才比较合理?假设现在给出北京地区的一些饭店所在的经纬度,具体分布如下图所示。尝试利用 kMeans 依据饭店的分布,找其各部分的中心位置。
准备数据
饭店的经纬度数据存放在 Restaurant_Data_Beijing.txt 文件中,其中每一行数据的第一列代表地点的纬度(北纬),第二列代表经度(东经)
对地理坐标进行聚类
增加两个函数:函数distSLC()
返回地球表面两点之间的距离,函数clusterPlaces ()
将文本文件中的地点进行聚类并画出结果。
可以与 google map 里面的标记进行对比。不同簇的数据点用不同的形状标记,+号所标注的就是对应簇的质心。可看到地点被大致分成 3 部分。依次修改 k 值为 4、5、6,观察相应的图像输出:
操作习题
先运行下面这段代码获得饭店经纬度数据。
kmeans.py 中的语句「from numpy import* 」用语句「import numpy as np」代替,修改其中对应的代码,使其能够正常执行
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
def loadDataSet(fileName):
dataMat = []
fr = open(fileName)
for line in fr.readlines():
curLine = line.strip().split('\t')
fltLine = list(map(float, curLine))
dataMat.append(fltLine)
return dataMat
def distEclud(vecA, vecB):
return np.sqrt(sum(np.power(vecA - vecB, 2)))
def randCent(dataSet, k):
n = np.shape(dataSet)[1]
centroids = np.mat(np.zeros((k, n)))
for j in range(n):
minJ = min(dataSet[:, j])
rangeJ = float(max(dataSet[:, j]) - minJ)
centroids[:, j] = np.mat(minJ + rangeJ * np.random.rand(k, 1))
return centroids
def distSLC(vecA, vecB):
a = np.sin(vecA[0, 1]*np.pi/180) * np.sin(vecB[0, 1]*np.pi/180)
b = np.cos(vecA[0, 1]*np.pi/180) * np.cos(vecB[0, 1]*np.pi/180) * \
np.cos(np.pi * (vecB[0, 0]-vecA[0, 0]) / 180)
return np.arccos(a + b)*6371.0
def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):
m = np.shape(dataSet)[0]
clusterAssment = np.mat(np.zeros((m, 2)))
centroids = createCent(dataSet, k)
clusterChanged = True
while clusterChanged:
clusterChanged = False
for i in range(m):
minDist = np.inf
minIndex = -1
for j in range(k):
distJI = distMeas(centroids[j, :], dataSet[i, :])
if distJI < minDist:
minDist = distJI
minIndex = j
if clusterAssment[i, 0] != minIndex:
clusterChanged = True
clusterAssment[i, :] = minIndex, minDist**2
for cent in range(k):
ptsInClust = dataSet[np.nonzero(clusterAssment[:, 0].A == cent)[0]]
centroids[cent, :] = np.mean(ptsInClust, axis=0)
return centroids, clusterAssment
def clusterPlaces(numClust=5):
datList = []
for line in open('Restaurant_Data_Beijing.txt').readlines():
lineArr = line.split('\t')
datList.append([float(lineArr[0]), float(lineArr[1])])
datMat = np.mat(datList)
myCentroids, clustAssing = kMeans(datMat, numClust, distMeas=distSLC)
fig = plt.figure()
rect = [0.1, 0.1, 0.8, 0.8]
scatterMarkers = ['s', 'o', '^', '8', 'p',
'd', 'v', 'h', '>', '<']
axprops = dict(xticks=[], yticks=[])
ax0 = fig.add_axes(rect, label='ax0', **axprops)
ax1 = fig.add_axes(rect, label='ax1', frameon=False)
for i in range(numClust):
ptsInCurrCluster = datMat[np.nonzero(clustAssing[:, 0].A == i)[0], :]
markerStyle = scatterMarkers[i % len(scatterMarkers)]
ax1.scatter(ptsInCurrCluster[:, 0].flatten(
).A[0], ptsInCurrCluster[:, 1].flatten().A[0], marker=markerStyle, s=90)
ax1.scatter(myCentroids[:, 0].flatten().A[0],
myCentroids[:, 1].flatten().A[0], marker='+', s=300)
plt.show()
if __name__ == '__main__':
clusterPlaces(6)
对聚类结果可视化(包含样本点和蔟中心,用不同颜色、记号标记)



实验总结
通过本次实验,我大致熟悉了 Baidu Web 的 API 和用 kMeans 算法聚类的一些操作,尤其是使用百度 API,感觉非常实用。