机器学习系列之kdtree

目的:最近有个项目,一条公交线路上,有n个站点。现在对每个站点附近的基站,进行聚合。首先,通过爬虫并利用高德API,获取了相应的站点的经纬度信息。然后利用基站维度表(包涵经纬度),计算距离公交站点的所有基站。

步骤一:爬取公交站

爬虫的内容相对简单,本文不在赘述。相关内容,可以自行学习,也可以在评论里探讨。

import requests
import numpy as np
import pandas as pd
from bs4 import BeautifulSoup
import re

url = 'http://guangzhou.8684.cn/x_61c8b4b8'#8684公交网
res = requests.get(url).text
soup = BeautifulSoup(res, 'html.parser')
bus_load = soup.findAll('div',{'class':'bus_site_layer'})

aaa = []
for one in bus_load:
    p = r'<a\shref.*?>(.*?)</a>'
    a = re.findall(p, str(one))
    aaa.append(a)

stations = aaa[0] + aaa[1]
stations = [one + '公交站' for one in stations]

out:'海珠客运站(总站)公交站',
 '海珠客运站公交站',
 '南洲名苑(瑞宝花园)公交站',
 '金碧花园公交站',
 '新滘西路口公交站',
 '石溪(工业大道南)公交站',
 '保利花园(南石头)公交站',
 '纸厂公交站',
 '珠江医院公交站',
 '基建新村公交站',
 '沙园公交站',
 '凤凰新村(宝业路口)公交站',
 '梅园西(地铁凤凰新村站)公交站',
 '革新路口公交站',
 '洪德路公交站',
...

步骤二:获取经纬度

这部分内容主要通过高德API完成,也可以使用其他地图,如百度等,但要注意经纬度的转换。相关的内容,在高德开发文档中介绍比较详细,可以去查阅。或者和我探讨。

#高德API获取经纬度
def getcode(site):
    
    parameters = { 'keywords' : site, 'city': 'guangzhou', 'types': "150700", 'key': 'dec5e22d0cd110eae2c3ed756ac2c24c'}
    
    #base = 'http://restapi.amap.com/v3/geocode/geo'###############高德地图地理编码API####不准确,舍去
    base = 'http://restapi.amap.com/v3/place/text' ##################高德地图搜索API######最后选取
    
    response = requests.get(base, parameters)
    
    info_site = response.json()
    
    return info_site

#解析经纬度
def get_site(info):
    foshan = {}
    foshan['lat'] = info['pois'][0]['location'].split(',')[0]
    foshan['lng'] = info['pois'][0]['location'].split(',')[1]
    
    return  foshan


#主程序,连接爬去公交和高德API
info_cc = []
for one_site in stations:
        tranf = getcode(one_site)
        if tranf['pois']:
            info_cc.append(get_site(tranf))
            
        else:
            print('#####################L  O  S  T########################')
            continue
fs_info = pd.DataFrame(info_cc, columns = ['lat', 'lng'])

out: info_cc:
{'lat': '113.299271', 'lng': '23.064558'},
 {'lat': '113.301216', 'lng': '23.064531'},
 {'lat': '113.293930', 'lng': '23.065277'},
 {'lat': '113.287376', 'lng': '23.067261'},
 {'lat': '113.283188', 'lng': '23.069016'},
 {'lat': '113.277832', 'lng': '23.071381'},
 {'lat': '113.274467', 'lng': '23.073256'},
 {'lat': '113.271523', 'lng': '23.075417'},

步骤三:搜索范围内基站

现在公交路线的站点经纬度,以及整个区域的基站经纬度都有了。下一步,就是要将公交站点附近的基站数据,聚合到一起。采用两种方式,一种是穷举的方式,利用两点经纬度距离计算。另一种是借用KDTree搜索,显然这种方式最好。这中间包涵读取数据库和数据的一些处理工作,没有详细给出,这部分,只是记录下大概的思路。

#由经纬度,计算distance、单位KM
from math import radians, cos, sin, asin, sqrt, fabs
EARTH_RADIUS = 6371 
def hav(theta):  
    s = sin(theta / 2)  
    return s * s  
   
def get_distance_hav(a,b):  
    lat0 = radians(a[1])  
    lat1 = radians(b[1])  
    lng0 = radians(a[0])  
    lng1 = radians(b[0])     
    dlng = fabs(lng0 - lng1)  
    dlat = fabs(lat0 - lat1)  
    h = hav(dlat) + cos(lat0) * cos(lat1) * hav(dlng)  
    distance = 2 * EARTH_RADIUS * asin(sqrt(h))     
    return distance

#测试
#两个公交站距离
a1 = (113.293930,23.065277)
b1 = (113.293930, 23.071381)
get_distance_hav(a1, b1)

out:0.6787338322385186


#数据处理(这部分无需仔细参考,只是处理数据,形成最终的经纬度列表,用于分析)
a_list = np.array(gz_09road[['lat', 'lng']]).tolist()#来自公交站点数据
dataf[['lng', 'lat']] = dataf[['lng', 'lat']].apply(pd.to_numeric)#来自基站经纬度数据
c_list = np.array(dataf[['lng', 'lat']]).tolist()

#方法一:KDTree搜索,距离公交站最近的cgi
from sklearn.neighbors import KDTree
kd = KDTree(c_list)
distance, indice = kd.query(a_list, k = 15, return_distance = True)
print('临近点:', indice)
print('距离:', distance)
#结果只有一部分,仅供参考,请注意过程即可
out:临近点: [[ 9535 23636 23635 11923 23113 23469 23736 22642 23279 23494 10656 12113
   5623 10504  8261]
 [23636 23635 23736 23113 23494 23279 23469 22642  6556   536 18943   496
  12508 12416 12242]
距离: [[0.00069982 0.00161282 0.00161282 0.00176515 0.00186499 0.00186499
  0.00186499 0.00186499 0.00186499 0.00186499 0.00195905 0.00195905
  0.00195905 0.00195905 0.00195905]


#方法二:循环搜索方式,复杂度高
import numpy as np
cluster = {}

_length = []
for one in a_list:
    print(one)
    list_cgi = []
    for two in b_list:
        #print(two)
       
        length = get_distance_hav(one, two[:2])
        _length.append(length)
        if length <= 0.2:#距离定义注意,此处定义不正确
            list_cgi.append(two[2])
            cluster[str(one)] = list_cgi
    

总结:以上内容,就完成了从数据爬取-整理,到通过高德API获取经纬度,再到使用knn中kdtree搜索的过程。具体有不懂地方可以探讨或者查阅相关资料。比较容易。写的不好,多多见谅。谢谢。

以此记录自己选择后的历程,希望再接再厉!工作上的事,都不是事。

猜你喜欢

转载自blog.csdn.net/weixin_41512727/article/details/81081935
今日推荐