当前位置:   article > 正文

[转]出租车轨迹处理(一):预处理+DBSCAN聚类+gmplot可视化_出租车轨迹聚类结果的可视化

出租车轨迹聚类结果的可视化

1、认识数据

我要处理的是2015年成都市的出租车数据
数据格式及示例为:
出租车ID,纬度,经度,载客状态(1表示载客,0表示无客),时间点
1, 30.4996330000,103.9771760000,1,2014/08/03 06:01:22
1, 30.4936580000,104.0036220000,1,2014/08/03 06:02:22
2, 30.6319760000,104.0384040000,0,2014/08/03 06:01:13
2, 30.6318830000,104.0366790000,1,2014/08/03 06:02:53

  1. import pandas as pd
  2. import numpy as np
  3. import datatime
  4. f=open('D:\动态人口分布实验\交通赛数据_下\\20140816_train.txt')
  5. data=pd.read_csv(f,names=['ID','lat','lon','passager','time'])

2、对数据进行简单预处理

由于我的兴趣只在于出租车的载客位置与卸客位置,于是需要做一个简单的预处理,把载客状态变更(0变1、1变0)的行提取出来。
于是一个简单的做法就是把每一行的“载客状态”,减去上一行或者下一行。所以需要对这一列数据整体进行一个向上或向下平移,生成一个新列,然后做一个两列相减。
然后,要删除掉对后续数据分析无意义的列,减少数据量。
最后,使用pandas强大的索引功能,只选取载客状态变更的数据,进行后续计算。

  1. data['passager_1']=data['passager'].shift(1)
  2. data['change']=data['passager']-data['passager_1']
  3. data=data.drop(['passager_1'],axis=1) #axis=0 为删掉某行; axis=1位删掉某列
  4. data=data.loc[(data['change']==1) |(data['change']==-1)]

3、时间数据的处理
这部分看似简单,但由于基础太差,真心是踩了不少坑。
首先是,要把代表时间的那一列,转换为pandas的datetime类型。
其次,把这一列设置为索引。

  1. data['time']=pd.to_datetime(data['time'])
  2. data=data.set_index('time')
  3. print(data['2014-08-16 09:00:00':'2014-08-16 10:00:00'])

其次为了观察数据的空间分布,保存了一下文件:

data.to_csv('D:\深度学习估算人口\data.csv')

CSV文件可以导入Arcgis中看一下分布。
但是还是想学习一下如何用Python进行可视化。
学习了这两篇博文

1、使用Python加载谷歌地图并可视化
https://blog.csdn.net/qq_38684480/article/details/85123777

2、 Inferring home and work locations using GPS trajectories and DBSCAN
https://yidatao.github.io/2016-12-23/geolife-dbscan/

于是尝试着实现可视化:

  1. import gmplot
  2. data=data.sort_index() #突然发现数据本身的排序并非是严格按照时间,于是还要先进行一个排序
  3. gmap=gmplot.GoogleMapPlotter(data.lat[0],data.lon[0],11)
  4. data1=data.loc[data['ID']==1]
  5. gmap.plot(data1.lat,data1.lon)
  6. gmap.draw('user001_map.html')

4、位置数据的处理
这次数据好的地方在于位置数据都是用经纬度显示,但是有时轨迹数据的位置信息是用Geohash后编码数据表示,因此还需要进行解码。
如之前处理的MOBIKE数据,数据如下:
在这里插入图片描述
可以看出位置两列并非是经纬度。于是需要进行解码。还有一个小知识点是关于数据的切片:pd.iloc

  1. import numpy as np
  2. import pandas as pd
  3. import Geohash as geohash
  4. # 获取出发地的经纬度
  5. def get_eloc_latlon(result):
  6. eloc_latlon = result['geohashed_end_loc'].apply(lambda x: geohash.decode_exactly(x)[:2])
  7. result['eloc_lat'] = eloc_latlon.apply(lambda x: float(x[0]))
  8. result['eloc_lon'] = eloc_latlon.apply(lambda x: float(x[1]))
  9. return result
  10. def get_sloc_latlon(result):
  11. sloc_latlon = result['geohashed_start_loc'].apply(lambda x: geohash.decode_exactly(x)[:2])
  12. result['sloc_lat'] = sloc_latlon.apply(lambda x: float(x[0]))
  13. result['sloc_lon'] = sloc_latlon.apply(lambda x: float(x[1]))
  14. return result
  15. data=pd.DataFrame(pd.read_csv('H:\python program\Mobike-master\\train.csv'))
  16. X = np.array(data[['geohashed_start_loc', 'geohashed_end_loc']])
  17. #print(X[:10,:])
  18. X=get_eloc_latlon(data)
  19. X=get_sloc_latlon(data)
  20. X.to_csv('H:\python program\Mobike-master\\train_lonlat.csv')
  21. Y=pd.read_csv('H:\python program\Mobike-master\\train_lonlat.csv')
  22. YY=Y.iloc[0:10]
  23. print(YY.info())
  24. YY.to_csv('H:\python program\Mobike-master\\train_lonlat10.csv')

5、DBSCAN聚类分析

  1. 聚类

  1. # 也许是由于数据量太大,导致聚类失败,故只选择10辆出租车的数据进行尝试
  2. data1=data.loc[data['ID']<10]
  3. from sklearn.cluster import DBSCAN
  4. from sklearn import metrics
  5. # represent GPS points as (lat, lon)
  6. coords = data1.as_matrix(columns=['lat', 'lon'])
  7. # earth's radius in km
  8. kms_per_radian = 6371.0088
  9. # define epsilon as 0.5 kilometers, converted to radians for use by haversine
  10. epsilon = 0.5 / kms_per_radian
  11. # eps is the max distance that points can be from each other to be considered in a cluster
  12. # min_samples is the minimum cluster size (everything else is classified as noise)
  13. db = DBSCAN(eps=epsilon, min_samples=100, algorithm='ball_tree', metric='haversine').fit(np.radians(coords))
  14. cluster_labels = db.labels_
  15. # get the number of clusters (ignore noisy samples which are given the label -1)
  16. num_clusters = len(set(cluster_labels) - set([-1]))
  17. print ('Clustered ' + str(len(data1)) + ' points to ' + str(num_clusters) + ' clusters')
  18. # turn the clusters in to a pandas series
  19. clusters = pd.Series([coords[cluster_labels == n] for n in range(num_clusters)])
  20. clusters

结果是聚成了4类

  1. Clustered 6304 points to 4 clusters
  2. 0 [[30.694546000000003, 104.064254], [30.694587,...
  3. 1 [[30.642768, 104.041161], [30.642794, 104.0410...
  4. 2 [[30.571728999999998, 103.964786], [30.5734200...
  5. 3 [[30.649578, 104.062095], [30.6518, 104.063633...
  6. dtype: object

2)

  1. from shapely.geometry import MultiPoint
  2. from geopy.distance import great_circle
  3. def get_centermost_point(cluster):
  4. centroid = (MultiPoint(cluster).centroid.x, MultiPoint(cluster).centroid.y)
  5. centermost_point = min(cluster, key=lambda point: great_circle(point, centroid).m)
  6. return tuple(centermost_point)
  7. # get the centroid point for each cluster
  8. centermost_points = clusters.map(get_centermost_point)
  9. lats, lons = zip(*centermost_points)
  10. rep_points = pd.DataFrame({'lon':lons, 'lat':lats})

3) 可视化

  1. import matplotlib.pyplot as plt # 注意,是matplotlib.pyplot,不然没有plt.subplots模块
  2. fig, ax = plt.subplots(figsize=[10, 6])
  3. rs_scatter = ax.scatter(rep_points['lon'][0], rep_points['lat'][0], c='#99cc99', edgecolor='None', alpha=0.7, s=450)
  4. ax.scatter(rep_points['lon'][1], rep_points['lat'][1], c='#99cc99', edgecolor='None', alpha=0.7, s=250)
  5. ax.scatter(rep_points['lon'][2], rep_points['lat'][2], c='#99cc99', edgecolor='None', alpha=0.7, s=250)
  6. ax.scatter(rep_points['lon'][3], rep_points['lat'][3], c='#99cc99', edgecolor='None', alpha=0.7, s=150)
  7. df_scatter = ax.scatter(data1['lon'], data1['lat'], c='k', alpha=0.9, s=3)
  8. ax.set_title('Full GPS trace vs. DBSCAN clusters')
  9. ax.set_xlabel('Longitude')
  10. ax.set_ylabel('Latitude')
  11. ax.legend([df_scatter, rs_scatter], ['GPS points', 'Cluster centers'], loc='upper right')
  12. labels = ['cluster{0}'.format(i) for i in range(1, num_clusters+1)]
  13. for label, x, y in zip(labels, rep_points['lon'], rep_points['lat']):
  14. plt.annotate(
  15. label,
  16. xy = (x, y), xytext = (-25, -30),
  17. textcoords = 'offset points', ha = 'right', va = 'bottom',
  18. bbox = dict(boxstyle = 'round,pad=0.5', fc = 'white', alpha = 0.5),
  19. arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
  20. plt.show()

可视化结果如下:
在这里插入图片描述
之后生成热力图:
使用了gmplot库,生成一个网页,从浏览器打开即可。

  1. import gmplot
  2. gmap = gmplot.GoogleMapPlotter(rep_points['lat'][0], rep_points['lon'][0], 11)
  3. #gmap.plot(data1.lat, data1.lon)
  4. gmap.heatmap(rep_points['lat'][:4], rep_points['lon'][:4], radius=20)
  5. gmap.draw("user_work_home.html")

6、一些其他统计分析
1)按小时统计成都市一天内的上客人数、卸客人数
其中,花费我较多时间的是找到 resample 函数,这真的是一个很有用的功能,具体可以查询《使用python进行数据分析》一书。别的博客还有用时间数据groupby的,可惜我没有实验成功,不知道是否可行。

  1. #首先还是要分别提取出上客数据、卸客数据
  2. PUP=data.loc[data['change']==1]
  3. DOP=data.loc[data['change']==-1]
  4. # 上客人数的可视化
  5. PUP=PUP.resample('H').sum()
  6. M=PUP['change'].plot(title='passagers')
  7. fig=M.get_figure()
  8. fig.set_size_inches(20,9)
  9. # 由于卸客人数数据的change是-1,所以增添一个新列,取【change】的绝对值,然后再汇总、显示
  10. DOP['num']=abs(DOP['change'])
  11. DOP=DOP.resample('H').sum()
  12. N=DOP['num'].plot(title='passagers')
  13. fig=N.get_figure()
  14. fig.set_size_inches(20,9)

在这里插入图片描述
2) 统计一下不同时间段的“净流量”:上客人数—卸客人数

  1. FLOW['flow']=PUP['change']-DOP['num']
  2. FF=FLOW['flow'].plot(title='passagers')
  3. fig=N.get_figure()
  4. fig.set_size_inches(20,9)

在这里插入图片描述


---------------------
作者:菜鸡的自我拯救
来源:CSDN
原文:https://blog.csdn.net/weixin_37659245/article/details/89306413
 

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/代码探险家/article/detail/741922
推荐阅读
相关标签
  

闽ICP备14008679号