人工智能与地理大数据实验--出租车GPS数据—时空大数据Python处理基础(二)

news2024/10/6 12:26:52

环境:Windows 10 专业版 + Python 3.9.1 + Anaconda 2020( 4.8.2)

系列文章:

人工智能与地理大数据实验--出租车GPS数据—时空大数据Python处理基础(一)

人工智能与地理大数据实验--出租车GPS数据—时空大数据Python处理基础(二)


目录

五、源码流程分析

(一)、出租车数据的时间完整性评估

(二)、出租车数据的空间完整性评估

(三)、出租车订单出行特征分析

六、实验结果

(一)、出租车数据的时间完整性评估

(二)、出租车数据的空间完整性评估

(三)、出租车订单出行特征分析


五、源码流程分析

(一)、出租车数据的时间完整性评估

1.时间字段的处理

利用字符串str方法,把Series对象转换为pandas内置的StringMethods对象,并使用StringMethods对象的slice方法截去字符串切片,传入开始与结束位置的索引,提取前两位字符,从而获取小时信息。

# 把Stime列转换为StringMethods对象,进行切片操作,再赋值给Hour列
data['Hour'] = data['Stime'].str.slice(0,2)
data

2.数据量的小时集计

同一小时内产生的GPS数据,Hour字段中会拥有相同的值,可以根据这一字段对数据采用groupby方法进行集计操作,再利用count方法指定VehicleNum列统计每小时的数据量。

# 分组并统计各组数量
Hourcount = data.groupby('Hour')['VehicleNum'].count()
# 更改Series的列名,并通过reset_index将Series变成DataFrame
Hourcount = Hourcount.rename('count').reset_index()
Hourcount

3.数据量时间分布的折线图绘制

通过matplotlib库将数据绘制为简单的折线图与柱状图。

# 1.创建图表
# 导入包
import matplotlib.pyplot as plt
# 创建一个图,图的尺寸为8×4in,dpi为300
fig = plt.figure(1,(8,4),dpi = 300)
# 在图中创建子图
# 111分别表示:创建共一个子图,子图的布局为1行1列
ax = plt.subplot(111)

# 2.在图上画
# 绘制折线图,分别传入节点的x坐标与y坐标,'k-'定义了黑色实线
plt.plot(Hourcount['Hour'],Hourcount['count'],'k-')
# 绘制散点图,分别传入节点的x坐标与y坐标,'k.'定义了黑色散线
plt.plot(Hourcount['Hour'],Hourcount['count'],'k.')
# 绘制柱状图,分别传入节点的x坐标与y坐标
plt.bar(Hourcount['Hour'],Hourcount['count'])

# 3.调整图中元素
# 加y轴标题
plt.ylabel('Data volume')
# 加x轴标题
plt.xlabel('Hour')
# 调整x轴标签
plt.xticks(range(24),range(24))
# 加图标题
plt.title('Hourly data volume')
# 设置y轴范围
plt.ylim(0,30000)
# 显示图
plt.show()

(二)、出租车数据的空间完整性评估

1.出租车GPS数据空间分布栅格图

(1)研究区域栅格生成

用Python代码实现研究范围内栅格,并存储为GeoDataFrame形式。

①研究范围行政区划边界的读取

使用Geopandas读取Shapefile文件

# 导入Geopandas
import geopandas as gpd
# 读取shp格式地理数据文件
sz = gpd.read_file(r'D:\Project\Jupyter_Project\Data\data\sz\sz.shp',encoding = 'utf-8')
# 绘制地理数据文件
sz.plot()

查看读取进来的变量类型及内容

type(sz)

geopandas.geodataframe.GeoDataFrame

sz

②研究范围内栅格的生成

首先定义研究范围与栅格的大小,计算栅格的△lon与△lat。

# 导入math包
import math
# 划定栅格划分范围
lon1 = 113.75194
lon2 = 114.624187
lat1 = 22.447837
lat2 = 22.864748
# 取得左下角经纬度
latStart = min(lat1,lat2)
lonStart = min(lon1,lon2)
# 定义栅格大小,单位为米
accuracy = 500
# 计算栅格的经纬度增加量大小△Lon和△Lat,地球半径取6371004米
deltaLon = accuracy * 360 / (2 * math.pi * 6371004 * math.cos((lat1 + lat2) * math.pi / 360))
deltaLat = accuracy * 360 / (2 * math.pi * 6371004)
deltaLon,deltaLat

(0.004872614089207591, 0.004496605206422906)

然后,定义一个测试GPS点的经纬度,计算其对应的栅格编号与中心点经纬度。

# 定义一个GPS点测试栅格化
testlon = 114
testlat = 22.5
# 计算该GPS点对应的栅格编号
LONCOL = divmod(float(testlon) - (lonStart - deltaLon / 2), deltaLon)[0]
LATCOL = divmod(float(testlat) - (latStart - deltaLat / 2), deltaLat)[0]
# 计算该GPS点对应的栅格中心点经纬度
# 格子编号*格子宽+起始横坐标=格子中心横坐标
HBLON = LONCOL * deltaLon + lonStart
HBLAT = LATCOL * deltaLat + latStart
LONCOL,LATCOL,HBLON,HBLAT

(51.0, 12.0, 114.00044331854959, 22.501796262477075)

接下来计算每个栅格的四个顶点坐标,循环生成栅格,生成整个研究范围的栅格。

import geopandas as gpd
from shapely.geometry import Polygon
# 定义空的GeoDataFrame表,再往里加栅格
data = gpd.GeoDataFrame()
# 定义空的list,后面循环一次就往里面加东西
LONCOL_list = []
LATCOL_list = []
geometry_list = []
HBLON_list = []
HBLAT_list = []
# 计算行列要生成的栅格数量
# lon方向是lonsum个栅格
lonsnum = int((lon2-lon1) / deltaLon) + 1
# lat方向是latsum个栅格
latsnum = int((lat2-lat1) / deltaLat) + 1
for i in range(lonsnum):
    for j in range(latsnum):
        # 第i列,第j行的栅格中心点坐标
        HBLON = i * deltaLon + lonStart
        HBLAT = j * deltaLat + latStart
        # 用周围的栅格推算三个顶点的位置
        HBLON_1 = (i + 1 ) * deltaLon + lonStart
        HBLAT_1 = (j + 1) * deltaLat + latStart
        # 生成栅格的Polygon形状
        grid_ij = Polygon([
            (HBLON - deltaLon / 2, HBLAT - deltaLat / 2),
            (HBLON_1 - deltaLon / 2, HBLAT - deltaLat / 2),
            (HBLON_1 - deltaLon / 2, HBLAT_1 eltaLat / 2)])
        # 把生成的数据都加入到前面定义的空list里面
        LONCOL_list.append(i)
        LATCOL_list.append(j)
        HBLON_list.append(HBLON)
        HBLAT_list.append(HBLAT)
        geometry_list.append(grid_ij)
# 为GeoPandas文件的每一列赋值为刚刚的list
data['LONCOL'] = LONCOL_list
data['LATCOL'] = LATCOL_list
data['HBLON'] = HBLON_list
data['HBLAT'] = HBLAT_list
data['geometry'] = geometry_list
data

对创建的栅格绘制查看其空间分布。

data.plot(edgecolor = (0,0,0,1),linewidth = 0.2)

利用GeoDataFrame的intersects方法,输入行政区划的Polygon几何图形,将行政区划边界外的栅格剔除。

# 将前面读取的GeoDataFrame用unary_union方法合并为一个Polygon图形作为研究范围
roi = sz.unary_union
# 筛选出研究范围的栅格
grid_sz = data[data.intersects(roi)]
grid_sz.plot(edgecolor = (0,0,0,1),linewidth = 0.2)

将栅格数据保存至本地

grid_sz.to_file(r'D:\Project\Jupyter_Project\Data\data\grid_sz1.josn', driver = 'GeoJSON')

(2)GPS数据的栅格对应与集计

GPS数据以经纬度坐标的形式记录,计算得到每个GPS点对应的栅格编号。然后,再基于栅格标号统计每个栅格内GPS数据量。

import pandas as pd
# 读取数据
data = pd.read_csv('D:/Project/Jupyter_Project/Data/data/TaxiData-Sample.csv',header = None)
data.columns = ['VehicleNum','Stime','Lng','Lat','OpenStatus','Speed']
# 数据对应的栅格经纬度编号
data['LONCOL'] = ((data['Lng'] - (lonStart - deltaLon / 2))/deltaLon).astype('int')
data['LATCOL'] = ((data['Lat'] - (latStart - deltaLat / 2))/deltaLat).astype('int')
# 集计栅格数量
data_distribution = data.groupby(['LONCOL','LATCOL'])['VehicleNum'].count().rename('count').reset_index()
# 剔除不在研究范围内的OD记录
data_distribution = data_distribution[(data_distribution['LONCOL']>=0)&(data_distribution['LATCOL']>=0)&(data_distribution['LONCOL']<=lonsnum)&(data_distribution['LATCOL']<latsnum)]
data_distribution

(3)统计结果与栅格地理信息的连接

前面已经完成了栅格数据量的统计,其中的LONCOL与LATCOL列标识了栅格编号,count则为数据量统计。接下来需要把统计把统计出的结果连接到栅格的空间地理信息grid_sz表上,也就是执行表的连接。

在对DataFrame和GeoDataFrame表连接的时候需要特别注意,merge函数保留传入的第一个对象的数据形式,如果想要让连接后的表格保持GeoDataFrame形式,则必须将地理信息表放在前面。

# 将栅格数据与统计数据进行表连接,在栅格数据上加上数据量
grid_count = pd.merge(grid_sz,data_distribution,on = ['LONCOL','LATCOL'])
grid_count

查看结果的类型

type(grid_count)

geopandas.geodataframe.GeoDataFrame

(4)栅格数据分布的可视化

指定栅格颜色随count列数值变化(即颜色映射),栅格的边界为0时,绘制出的效果即类似像素画。

# 绘制
import matplotlib.pyplot as plt
fig = plt.figure(1,(10,8),dpi = 250)
ax = plt.subplot(111)
# 绘制行政区划的边界
sz.plot(ax = ax, edgecolor = (0,0,0,1), facecolor = (0,0,0,0), linewidths = 0.5)
# 设置colormap与colorbar
import matplotlib as mpl
# 设置99%分位数为colorbar最大值
vmax = grid_count['count'].quantile(0.99)
# 换一种内置颜色
cmapname = 'plasma'
cmap = mpl.cm.get_cmap(cmapname)
# 创建colorbar的纸,命名为cax
cax = plt.axes([0.08, 0.4, 0.02, 0.3])
# 此时因为创建了新的纸,plt移动到了cax这张纸上,设定colorbar的标题
plt.title('count')
# plt移动回ax这张纸上
plt.sca(ax)
# 绘制栅格
grid_count.plot(ax = ax, column = 'count',linewidth = 0,    #指定颜色映射的列
               vmin = 0, vmax = vmax, cmap = cmap,          #设置colorbar与数值范围
               legend = True, cax = cax)                    #显示colorbar色条
plt.axis('off')
plt.xlim(113.6,114.8)
plt.ylim(22.4,22.9)
plt.show()

2.出租车GPS数据空间分布散点图

在绘制数据的分布情况时,还可以采用更精致的散点图进行绘制。与栅格统计的原理一样,散点也需要集计统计才能进行绘制。

# 经纬度保留三位小数
data2 = data[['Lng','Lat']].round(3).copy()
# 集计每个小范围内的数据量
data2['count'] = 1
data2 = data2.groupby(['Lng','Lat'])['count'].count().reset_index()
# 排序数据,让数据量小的放上面先画,数据量大的放下面后画
data2 = data2.sort_values(by = 'count')
data2

将上面统计的GPS点以散点图的形式绘制,同时给图表加上地图的底图与比例尺指北针。

# 创建图框
import seaborn as sns
import matplotlib as mpl  
import matplotlib.pyplot as plt  
import transbigdata as tbd 
fig = plt.figure(1,(8,8),dpi = 80)      
ax = plt.subplot(111)  
plt.sca(ax)      
# 绘制行政区划的边界
bounds = [113.7, 22.42, 114.3, 22.8]  
sz.plot(ax = ax,edgecolor = (0,0,0,0),facecolor = (0,0,0,0.1),linewidths=0.5)
# 定义colorbar  
pallete_name = "BuPu"  
colors = sns.color_palette(pallete_name, 3)  
colors.reverse()  
cmap = mpl.colors.LinearSegmentedColormap.from_list(pallete_name, colors)  
vmax = data2['count'].quantile(0.99)  
norm = mpl.colors.Normalize(vmin=0, vmax=vmax)  
# 绘制散点图 
plt.scatter(data2['Lng'],data2['Lat'],s = 1,alpha = 1,c = data2['count'],cmap = cmap,norm=norm )  
# 添加比例尺和指北针  
tbd.plotscale(ax,bounds = bounds,textsize = 10,compasssize = 1,accuracy = 2000,rect = [0.06,0.03])  
plt.axis('off')  
plt.xlim(bounds[0],bounds[2])  
plt.ylim(bounds[1],bounds[3])  
# 绘制colorbar    
cax = plt.axes([0.15, 0.33, 0.02, 0.3])  
plt.colorbar(cax=cax)  
plt.title('count')
plt.show()

3.出租车GPS数据空间分布热力图

对数据的空间分布,还可以采用热力图进行绘制。在Matplotlib中绘制热力图则有两种方式,一种是采用等高线图直接对数据的分布进行绘制,另外一种则是用二维核密度绘制。

(1)等高线图plt.contour/plt.contourf

plt.contour(只绘制等高线)与plt.contourf(绘制等高线且在等高线之间填充颜色)是Matplotlib提供的等高线绘制方法,绘制出来的颜色代表的值代表数据量密度具有现实物理意义。

import numpy as np  
# 转换数据透视表,变成矩阵格式
d = data2.pivot(columns = 'Lng',index = 'Lat',values = 'count').fillna(0)  
#取对数,缩小最大最小值之间的差距
z = np.log(d.values)
x = d.columns  
y = d.index  
# 划分层数  
levels = np.linspace(0, z.max(), 25)
import matplotlib as mpl  
import matplotlib.pyplot as plt  
import transbigdata as tbd
fig = plt.figure(1,(8,8),dpi = 80)      
ax = plt.subplot(111)  
plt.sca(ax)  
# 调整整体空白
fig.tight_layout(rect = (0.05,0.1,1,0.9))
# 绘制行政区划的边界
bounds = [113.7, 22.42, 114.3, 22.8]  
sz.plot(ax = ax,edgecolor = (0,0,0,0),facecolor = (0,0,0,0.1),linewidths=0.5)
# 定义colorbar  
import matplotlib
cmap = matplotlib.colors.LinearSegmentedColormap.from_list('cmap', ['#9DCC42','#FFFE03','#F7941D','#E9420E','#FF0000'], 256)
# 绘制等高线图  
plt.contourf(x,y,z, levels=levels, cmap=cmap,origin = 'lower') 
# 添加比例尺和指北针    
tbd.plotscale(ax,bounds = bounds,textsize = 10,compasssize = 1,accuracy = 2000,rect = [0.06,0.03])    
plt.axis('off')  
plt.xlim(bounds[0],bounds[2])  
plt.ylim(bounds[1],bounds[3])    
# 绘制colorbar  
cax = plt.axes([0.13, 0.32, 0.02, 0.3])  
cbar = plt.colorbar(cax=cax)  
# 调整colorbar的显示标记位置
val = [1,10,100,1000,5000]
pos = np.log(np.array(val))
# 在什么位置显示标记
cbar.set_ticks(pos)
# 标记显示什么内容
cbar.set_ticklabels(val)
plt.title('Count')
plt.show()  

(2)空间核密度seaborn-kdeplot

赋予每一个点数据一定的影响范围,利用离散的数据估计连续概率密度,将数据的分布进行平滑处理。经过处理后,估计出来的是抽象的密度值,无法对应现实的物理意义。

# 导入绘图包
import matplotlib as mpl
import matplotlib.pyplot as plt
import transbigdata as tbd
import seaborn as sns
import numpy as np
fig = plt.figure(1,(10,10),dpi = 60)    
ax = plt.subplot(111)
plt.sca(ax)
# 调整整体空白
fig.tight_layout(rect = (0.05,0.1,1,0.9))
# 绘制行政区划的边界
bounds = [113.7, 22.42, 114.3, 22.8]  
sz.plot(ax = ax,edgecolor = (0,0,0,0),facecolor = (0,0,0,0.1),linewidths=0.5)
# colorbar的数据
cmap = mpl.colors.LinearSegmentedColormap.from_list('cmap', ['#9DCC42','#FFFE03','#F7941D','#E9420E','#FF0000'], 256)
# 设定位置
plt.axis('off')
plt.xlim(bounds[0],bounds[2])
plt.ylim(bounds[1],bounds[3])
# 定义colorbar位置
cax = plt.axes([0.13, 0.32, 0.02, 0.3])
# 绘制二维核密度图
sns.kdeplot('Lng','Lat',                     #指定x与y坐标所在的列
            data = data2[data2['count']>10], #传入数据,筛选去除太小的值
            weights = 'count',               #设定权重所在字段
            alpha = 0.8,                     #透明度
            gridsize = 120,                  #绘图精细度,越高越慢
            bw = 0.03,                    #高斯核大小(经纬度),越小越精细
            cmap = cmap,                     #定义colormap
            ax = ax,                         #指定绘图位置
            shade = True,                    #等高线间是否填充颜色
            shade_lowest = False,            #最底层不显示颜色
            cbar = True,                     #显示colorbar
            cbar_ax = cax                    #指定colorbar位置
           )
plt.show()

(三)、出租车订单出行特征分析

1.出租车订单出行特征提取

(1)出行OD提取的代码实现

提取出行的开始和结束信息。

# 导入pandas包,并赋值给变量pd
import pandas as pd
# 读取GPS数据文件
data = pd.read_csv('D:/Project/Jupyter_Project/Data/data/TaxiData-clean.csv')
# 构建StatusChange列
data['StatusChange'] = data['OpenStatus'] - data['OpenStatus'].shift()
# 筛选出行开始和结束信息  
oddata = data[((data['StatusChange'] == -1)|
               (data['StatusChange'] == 1))&
               (data['VehicleNum'].shift() == data['VehicleNum'])]
# 删去无用的列
oddata = oddata.drop(['OpenStatus','Speed'],axis = 1)
oddata

数据处理成oddata的形式,虽然能够从数据中找到订单的OD,但是每个订单有两条数据,这行数据能同时包含订单的OD信息、订单开始和结束信息,利用shfit函数处理连续数据,但要注意使用shift后要保证数据属于同一辆出租车。

# 首先给oddata更改列名  
oddata.columns = ['VehicleNum', 'Stime', 'SLng', 'SLat', 'StatusChange']  
# 把一个订单的两行数据整理成一行  
oddata['Etime'] = oddata['Stime'].shift(-1)  
oddata['ELng'] = oddata['SLng'].shift(-1)  
oddata['ELat'] = oddata['SLat'].shift(-1)  
# 筛选正确的订单OD数据:StatusChange == 1;shift后的数据属于同一个出租车  
oddata = oddata[(oddata['StatusChange'] == 1)&  
                  (oddata['VehicleNum'] == oddata['VehicleNum'].shift(-1))]  
# 去掉StatusChange列
oddata = oddata.drop('StatusChange',axis = 1)  
oddata

(2)出行订单数量的时间分布

统计oddata数据表,得到出行订单数量的时间分布。

# 统计每小时订单数
oddata['Hour'] = oddata.apply(lambda r:r['Stime'][:2],axis = 1).astype(int) 
Hourcount_od = oddata.groupby('Hour')['VehicleNum'].count()
Hourcount_od = Hourcount_od.rename('count').reset_index()
# 绘制折线图
import matplotlib.pyplot as plt
fig = plt.figure(1,(8,4),dpi = 300)
ax = plt.subplot(111)
plt.plot(Hourcount_od['Hour'],Hourcount_od['count'],'k-')
plt.plot(Hourcount_od['Hour'],Hourcount_od['count'],'k.')
plt.bar(Hourcount_od['Hour'],Hourcount_od['count'])
plt.ylabel('Trips')
plt.xlabel('Hour')
plt.xticks(range(24),range(24))
plt.title('Hourly trip count')
plt.ylim(0,350)
plt.show()

2.出租车出行订单持续时间的统计

(1)订单持续时间的统计

①标准化时间

标准化时间以0点为初始时间,将某一时刻转换为相对初始时间的时间差。

# 1.标准化时间
# 订单开始时间标准化
oddata['Stime_st'] = oddata['Stime'].apply(lambda r: int(r.split(':')[0]))*3600+oddata['Stime'].apply(lambda r: int(r.split(':')[1]))*60+oddata['Stime'].apply(lambda r: int(r.split(':')[2]))
# 订单结束时间标准化
oddata['Etime_st'] = oddata['Etime'].apply(lambda r: int(r.split(':')[0]))*3600+oddata['Etime'].apply(lambda r: int(r.split(':')[1]))*60+oddata['Etime'].apply(lambda r: int(r.split(':')[2]))    
# 计算时间差
oddata['duration'] = (oddata['Etime_st'] - oddata['Stime_st'])
oddata

②时间格式转换

将Stime和Etime转换为时间格式后进行差值计算。

# 2.时间格式转换
oddata['duration'] = pd.to_datetime(oddata['Etime']) - pd.to_datetime(oddata['Stime'])    
# 将时间差转换为秒
oddata['duration'] = oddata['duration'].apply(lambda r: r.seconds)
oddata

(2)订单持续时间的箱形图绘制

Matplotlib中箱型图的绘制有两种方法:Matplotlib的boxplot函数和seaborn库的boxplot。

首先用Matplotlib的boxplot函数进行绘制。

# 订单持续时间箱型图的绘制:plt.boxplot
import matplotlib.pyplot as plt
fig = plt.figure(1,(6,4),dpi = 250)
ax = plt.subplot(111)  
plt.sca(ax)  
# 整理箱型图的数据,循环遍历每个小时,将列数据放入datas变量中
datas = []
for hour in range(24):
    datas.append(oddata[oddata['Hour']==hour]['duration']/60)
# 绘制箱型图  
plt.boxplot(datas)  
# 更改x轴ticks的文字,传入两个参数,第一个为位置,第二个为标注文字
plt.xticks(range(1,25),range(24))
plt.ylabel('Order time(minutes)')
plt.xlabel('Order start time')
plt.ylim(0,60)
plt.show()

用seaborn库中的boxplot函数绘制。

# 订单持续时间箱型图的绘制:sns.boxplot
import matplotlib.pyplot as plt  
import seaborn as sns
fig = plt.figure(1,(6,4),dpi = 250)
ax = plt.subplot(111)
plt.sca(ax)
# 只需要一行,指定传入的数据,x轴y轴分别是哪个维度
sns.boxplot(x="Hour", y=oddata["duration"]/60, data=oddata,ax = ax)
plt.ylabel('Order time(minutes)')
plt.xlabel('Order start time')
plt.ylim(0,60)
plt.show()

3.出租车出行订单的栅格OD可视化

(1)出行订单数据的栅格对应

将出行订单OD数据与栅格对应

# 计算起点对应的栅格经纬度编号
oddata['SLONCOL'] = ((oddata['SLng'] - (lonStart - deltaLon / 2))/deltaLon).astype('int')
oddata['SLATCOL'] = ((oddata['SLat'] - (latStart - deltaLat / 2))/deltaLat).astype('int')   
# 计算终点对应的栅格经纬度编号
oddata['ELONCOL'] = ((oddata['ELng'] - (lonStart - deltaLon / 2))/deltaLon).astype('int')
oddata['ELATCOL'] = ((oddata['ELat'] - (latStart - deltaLat / 2))/deltaLat).astype('int')
# 剔除起终点在一个栅格内的记录
oddata = oddata[-((oddata['SLONCOL']==oddata['ELONCOL'])&
                  (oddata['SLATCOL']==oddata['ELATCOL']))]
# 剔除不在研究范围内的OD记录
oddata = oddata[(oddata['SLONCOL']>=0)&(oddata['SLATCOL']>=0)&
                (oddata['ELONCOL']>=0)&(oddata['ELATCOL']>=0)&
                (oddata['SLONCOL']<=lonsnum)&
                (oddata['SLATCOL']<=latsnum)&
                (oddata['ELONCOL']<=lonsnum)&
                (oddata['ELATCOL']<=latsnum)]   
# 列数比较多,转置方便查看
oddata.iloc[:5].T

(2)栅格OD集计与起终点坐标计算

通过groupby函数以起终点栅格编号列为依据集计订单数量,并计算起终点对应栅格中心点经纬度坐标。

#对以起终点栅格编号列为依据集计订单数量
OD = oddata.groupby(['SLONCOL','SLATCOL','ELONCOL','ELATCOL'])['VehicleNum'].count().rename('count').reset_index()
#起点栅格中心点经纬度
OD['SHBLON'] = OD['SLONCOL'] * deltaLon + (lonStart - deltaLon / 2)
OD['SHBLAT'] = OD['SLATCOL'] * deltaLat + (latStart - deltaLat / 2)
#终点栅格中心点经纬度    
OD['EHBLON'] = OD['ELONCOL'] * deltaLon + (lonStart - deltaLon / 2)
OD['EHBLAT'] = OD['ELATCOL'] * deltaLat + (latStart - deltaLat / 2)
#排序,将count值大的OD排在最下  
OD = OD.sort_values(by = 'count')
OD

(3)对上面统计的出行OD进行可视化绘制,可以用Matplotlib的折线绘制和GeoPandas的LineString绘制方法。

①Matplotlib的折线

#绘制OD
import matplotlib.pyplot as plt
fig = plt.figure(1,(10,8),dpi = 250)
ax  = plt.subplot(111)
plt.sca(ax)

#绘制地图底图,设置两者均在ax上绘制
grid_sz.plot(ax =ax,edgecolor = (0,0,0,0.8),facecolor = (0,0,0,0),linewidths=0.2)
sz.plot(ax = ax,edgecolor = (0,0,0,1),facecolor = (0,0,0,0),linewidths=0.5)

#设置colormap的数据
import matplotlib
vmax = OD['count'].max()
#设定一个标准化的工具,设定OD的colormap最大最小值,他的作用是norm(count)就会将count标准化到0-1的范围内
norm = matplotlib.colors.Normalize(vmin=0,vmax=vmax)
#设定colormap的颜色
cmapname = 'autumn_r'
#cmap是一个获取颜色的工具,cmap(a)会返回颜色,其中a是0-1之间的值
cmap = matplotlib.cm.get_cmap(cmapname)

#遍历绘制OD
for i in range(len(OD)):
    r = OD.iloc[i]
    count = r['count']
    linewidth = 1.5*(count/OD['count'].max())

plt.plot([r['SHBLON'],r['EHBLON']],[r['SHBLAT'],r['EHBLAT']],linewidth = linewidth,color = cmap(norm(count)))

#隐藏坐标轴
plt.axis('off')
plt.show()

②GeoPandas的LineString方法

from shapely.geometry import LineString
# 遍历生成OD的LineString对象,并赋值给geometry列
OD['geometry'] = OD.apply(lambda r:LineString([[r['SHBLON'],r['SHBLAT']],[r['EHBLON'],r['EHBLAT']]]),axis = 1)
# 转换为GeoDataFrame
OD = gpd.GeoDataFrame(OD)
# 绘制看看是否能够识别图形信息
OD.plot()

生成GeoDataFrame后,用plot函数绘制,并指定颜色映射的列,即可绘制OD。

# 绘制
# 创建图框
import matplotlib.pyplot as plt
fig = plt.figure(1,(10,8),dpi = 250)
ax = plt.subplot(111)
# 绘制栅格与行政区划边界
grid_sz.plot(ax = ax,edgecolor = (0,0,0,0.8),facecolor = (0,0,0,0),linewidths=0.2)
sz.plot(ax = ax,edgecolor = (0,0,0,1),facecolor = (0,0,0,0),linewidths=0.5)
# 设置colormap的数据
import matplotlib as mpl
vmax = OD['count'].max()
cmapname = 'autumn_r'
cmap = mpl.cm.get_cmap(cmapname)
# 创建colorbar的纸,命名为cax
cax = plt.axes([0.08, 0.4, 0.02, 0.3])
plt.title('count')
plt.sca(ax)
# 绘制OD
OD.plot(ax = ax,column = 'count',                       #指定在ax上绘制,并指定颜色映射的列
        linewidth = 1.5*(OD['count']/OD['count'].max()),#指定线宽
        cmap = cmap,vmin = 0,vmax = vmax,               #设置OD的颜色
        legend=True,cax = cax)                          #设置绘制色标
# 隐藏边框,并设定显示范围
plt.axis('off')
plt.xlim(113.6,114.8)
plt.ylim(22.4,22.9)
# 显示图
plt.show()

4.出租车出行的OD期望线绘制

(1)栅格匹配至行政规划

在栅格匹配至行政规划时,首先提取栅格的中心点,将栅格地理信息由矢量面转变为点。再使用GeoPandas的sjoin函数进行空间对象的空间连接,其用法与Pandas的merge表连接非常相似。

# 读取行政区划的矢量图形
sz = gpd.GeoDataFrame.from_file(r'D:\Project\Jupyter_Project\Data\data\sz\sz.shp',encoding = 'utf8')
# 读取栅格数据
grid_sz = gpd.GeoDataFrame.from_file('D:\Project\Jupyter_Project\Data\data\grid_sz.json')
# 提取栅格中心点,创建一个新变量
grid_centroid = grid_sz.copy()
# 提取栅格中心点,赋值给grid_centriod的geometry
grid_centroid['geometry'] = grid_centroid.centroid
# 栅格匹配到行政区划:gpd.sjoin
grid_centroid = gpd.sjoin(grid_centroid,sz)
grid_centroid

(2)数据匹配到行政区划

将栅格信息与OD进行表连接,获得出行起终点所在的行政区划信息。

# 保留有用的字段  
grid_centroid = grid_centroid[['LONCOL','LATCOL','qh']]
# 改变grid_centroid字段名,使其与OD数据起点栅格编号列能够匹配
grid_centroid.columns = ['SLONCOL','SLATCOL','Sqh']
OD = pd.merge(OD,grid_centroid,on = ['SLONCOL','SLATCOL'] )
# 改变grid_centroid字段名,使其与OD数据终点栅格编号列能够匹配
grid_centroid.columns = ['ELONCOL','ELATCOL','Eqh']
OD = pd.merge(OD,grid_centroid,on = ['ELONCOL','ELATCOL'] )
# 集计OD量
qhod  = OD.groupby(['Sqh','Eqh'])['count'].sum().reset_index()
# 去除起终点在同个行政区划的数据
qhod = qhod[qhod['Sqh'] != qhod['Eqh']] 
qhod.head(5)

(3)行政区划间OD期望线绘制

将行政区划的中心点坐标与行政区划OD出行量进行表连接,将起终点经纬度对应至OD期望线上,转换为GeoDataFrame并为每一条OD生成LineString线型,使其成为地理信息数据。

# 匹配起点行政区划的中心点经纬度
tmp = sz[['centroid_x','centroid_y','qh']]
tmp.columns = ['S_x','S_y','Sqh']
qhod = pd.merge(qhod,tmp,on = 'Sqh')
# 匹配终点行政区划的中心点经纬度
tmp.columns = ['E_x','E_y','Eqh']
qhod = pd.merge(qhod,tmp,on = 'Eqh')
# 为OD期望线生成GeoDataFrame
qhod = gpd.GeoDataFrame(qhod)
qhod['geometry'] = qhod.apply(lambda r:LineString([[r['S_x'],r['S_y']],[r['E_x'],r['E_y']]]),axis = 1)
qhod.plot()

接下来对OD期望线进行可视化

# 绘制
# 创建图框  
import matplotlib.pyplot as plt  
fig = plt.figure(1,(10,8),dpi = 250)      
ax = plt.subplot(111)  
# 绘制行政区划边界  
sz.plot(ax = ax,edgecolor = (0,0,0,0),facecolor = (0,0,0,0.2),linewidths=0.5)
# 设置colormap的数据  
import matplotlib as mpl  
vmax = qhod['count'].max()  
cmapname = 'autumn_r'  
cmap = mpl.cm.get_cmap(cmapname)  
# 创建colorbar
cax = plt.axes([0.08, 0.4, 0.02, 0.3])  
plt.title('count')  
plt.sca(ax)  
# 绘制OD  
qhod.plot(ax = ax,column = 'count', #指定在ax上绘制,并指定颜色映射的列
        linewidth = 5*(qhod['count']/qhod['count'].max()),#指定线宽
        cmap = cmap,vmin = 0,vmax = vmax    #设置OD的颜色
        legend=True,cax = cax)           #设置绘制色标
# 隐藏边框,并设定显示范围
plt.axis('off')
plt.xlim(113.6,114.8)
plt.ylim(22.4,22.9)
# 显示图
plt.show()

六、实验结果

(一)、出租车数据的时间完整性评估

图1.小时数据量折线图

从数据量的时变折线图可以看出,数据在小时分布上并没有明显的数据缺失情况。

(二)、出租车数据的空间完整性评估

图2.GPS数据的空间分布(栅格集计)

图3.出租车GPS数据的空间分布散点图

图4.数据分布的等高线图

图5.数据分布的空间二维核密度分布图

从图2-图5来看,数据集中分布于中心城区,郊区存在大片空白没数据的地方,这部分地方没有出租车需求。郊区有数据的地方则明显呈现线性分布,与道路的分布较为吻合。

(三)、出租车订单出行特征分析

图6.订单数量的小时分布

从订单的开始时间统计可以看出,出租车订单并没有在某个时间段存在明显缺失。在夜间时段,订单数量会有一个明显的低谷,这也与实际的需求相符。从数据量与订单量的时间分布上看,出租车数据在时间分布上是较为完整的。

图7.plt.boxplot绘制的分组箱型图

图8.sns.boxplot绘制的分组箱型图

经过前面的数据处理,成功地计算出了出租车出行订单的持续时间,并用箱型图展示了不同时间段订单持续时间的分布情况。从中可以看出,出租车的订单持续时间在一日之中的不同时间内存在一定差异,在早晚高峰时间,订单的持续时间明显更长,因为高峰时间城市道路更加拥挤,出行所需的时间当然就更长了。

图9.OD绘制结果

图10.OD期望线绘制

从出行订单OD数据的空间分布上看,数据的出行订单集中分布于城市的核心区域,也与真实的需求相符合。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1638101.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

接收区块链的CCF会议--APSEC 2024 截止7.13 附录用率

会议名称&#xff1a;APSEC&#xff08;Asia-Pacific Software Engineering Conference&#xff09; CCF等级&#xff1a;CCF C类学术会议 类别&#xff1a;软件工程/系统软件/程序设计语言 录用率&#xff1a;2023年&#xff0c;90 submissions were recommended for accep…

【MATLAB画图】如何绘制图像坐标系

首先我们需要图像坐标轴的原点在左上角&#xff1a; set(gca,ydir,reverse,xaxislocation,top); 然后我们需要坐标轴上加上箭头 quiver(0, 0, 0, 520); % 在(x1, y1)处绘制一个箭头&#xff0c;其方向和长度由(dx, dy)确定 quiver(0, 0, 700, 0); % 在(x1, y1)处绘制一个箭头…

缓存分享(1)——Guava Cache原理及最佳实践

Guava Cache原理及最佳实践 1. Guava Cache是什么1.1 简介1.2 核心功能1.3 适用场景 2. Guava Cache的使用2.1 创建LoadingCache缓存2.2 创建CallableCache缓存 缓存的种类有很多&#xff0c;需要根据不同的应用场景来选择不同的cache&#xff0c;比如分布式缓存如redis、memca…

帕金森患者应该怎么注意生活方式?

在面对帕金森病的挑战时&#xff0c;科学合理地改善日常生活方式&#xff0c;不仅能帮助患者更好地管理病情&#xff0c;还能提升生活质量。今天&#xff0c;让我们一起探索如何通过简单的日常调整&#xff0c;为患有帕金森病的朋友们带来积极的变化。 饮食调整&#xff1a;营养…

MATLAB 函数

MATLAB 函数 函数是一起执行任务的一组语句。在MATLAB中&#xff0c;函数是在单独的文件中定义的。文件名和函数名应该相同。 函数在其自己的工作空间&#xff08;也称为本地工作空间&#xff09;中对变量进行操作&#xff0c;与在MATLAB命令提示符下访问的工作空间&#xff0…

优化|贝叶斯优化系列(一):基础算法原理

贝叶斯优化是一种处理黑盒函数优化问题的重要方法。它通过构建一个目标函数的代理模型&#xff0c;并且利用贝叶斯机器学习方法如高斯过程回归来评估代理模型的不确定性。基于代理模型&#xff0c;通过一个采样函数来决定在哪里进行采样。本推文简单描述了贝叶斯优化方法的框架…

【1小时掌握速通深度学习面试1】卷积神经网络-上

目录 1.简述卷积的基本操作&#xff0c;并分析其与全连接层的区别 2.在卷积神经网络中&#xff0c;如何计算各层的感受野大小?卷积层的输出尺寸、参数量和计算量。 3.简述分组卷积及其应用场景 4.简述空洞卷积的设计思路 5.简述转置卷积的主要思想以及应用场景 1.简述卷积…

8. Django 表单与模型

8. 表单与模型 表单是搜集用户数据信息的各种表单元素的集合, 其作用是实现网页上的数据交互, 比如用户在网站输入数据信息, 然后提交到网站服务器端进行处理(如数据录入和用户登录注册等).网页表单是Web开发的一项基本功能, Django的表单功能由Form类实现, 主要分为两种: dj…

vue3项目引入VueQuill富文本编辑器(成功)及 quill-image-uploader 图像模块(未成功)

tip&#xff1a;重点解释都写在代码注释里了&#xff0c;方便理解&#xff0c;所以看起来比较密集 富文本基本使用 项目文件夹路径安装依赖 npm install vueup/vue-quilllatest --save 全局注册&#xff1a;main.js // main.js// 自己项目的一些配置&#xff08;只放了主要…

IoTDB 入门教程 问题篇①——内存不足导致datanode服务无法启动

文章目录 一、前文二、发现问题三、分析问题四、继续分析五、解决问题 一、前文 IoTDB入门教程——导读 二、发现问题 执行启动命令&#xff0c;但是datanode服务却无法启动&#xff0c;查询不到6667端口 bash sbin/start-standalone.sh 进而导致数据库连接也同样失败 [rooti…

开箱子咸鱼之王H5游戏源码_内购修复优化_附带APK完美运营无bug最终版__GM总运营后台_附带安卓版本

内容目录 一、详细介绍二、效果展示2.效果图展示 三、学习资料下载 一、详细介绍 1.包括原生打包APK&#xff0c;资源全部APK本地化&#xff0c;基本上不跑服务器宽带 2.优化后端&#xff0c;基本上不再一直跑内存&#xff0c;不炸服响应快&#xff01; 3.优化前端&#xff0c…

Linux开发板 FTP 服务器移植与搭建

VSFTPD&#xff08;Very Secure FTP Daemon&#xff09;是一个安全、稳定且快速的FTP服务器软件&#xff0c;广泛用于Unix和Linux操作系统。它以其轻量级、高效和易于配置而受到赞誉。VSFTPD不仅支持标准的FTP命令和操作&#xff0c;还提供了额外的安全特性&#xff0c;如匿名F…

会声会影2024中文旗舰版最新网盘安装包下载

会声会影2024是一款功能强大的视频编辑软件&#xff0c;它凭借直观易用的界面、全面的编辑工具以及丰富的特效库&#xff0c;吸引了广泛的用户群体。无论是视频编辑初学者还是专业人士&#xff0c;都能在这款软件中找到满足自己创作需求的功能。 一、软件概述 会声会影2024继承…

【c++】模板编程解密:C++中的特化、实例化和分离编译

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本篇文章我们来学习模版的进阶部分 目录 1.非类型模版参数按需实例化 2.模版的特化函数模版特化函数模版的特化类模版全特化偏特化 3.分离编译模版分离编译 1.非类…

Android(Java)项目支持Kotlin语言开发

Android&#xff08;Java&#xff09;项目通过相关Kotlin设置后&#xff0c;允许同时使用Java语言和Kotlin语言进行开发代码的。 示例环境&#xff1a; Android Studio Giraffe | 2022.3.1 Patch 3 Java 8 Kotlin 1.9.20 设置Kotlin选项&#xff1a; 第一步&#xff1a;在项…

ASP.NET淘宝店主交易管理系统的设计与实现

摘 要 淘宝店主交易管理系统主要采用了ASPACCESS的B/S设计模式&#xff0c;通过网络之间的数据交换来实现客户、商品、交易的管理和对客户、商品、交易统计工作&#xff0c;从而提高淘宝店主在管理网店过程中的工作效率和质量。 系统分为基本资料模块&#xff0c;统计资料模…

基于ssm+vue+Mysql的药源购物网站

开发语言&#xff1a;Java框架&#xff1a;ssmJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;Maven3.…

知识图谱与知识表示:人工智能的基石

知识图谱与知识表示&#xff1a;人工智能的基石 一、知识图谱&#xff1a;连接数据的桥梁1.1 知识图谱的构成1.2 知识图谱的应用 二、知识表示&#xff1a;AI的推理基础2.1 知识表示的定义2.2 知识表示的形式 三、从符号表示到向量表示3.1 符号表示与向量表示3.2 向量表示的优势…

virtualbox kafka nat + host-only集群 + windows 外网 多网卡

virtualbox kafka nat + host-only集群 + windows 映射访问 kafka集群搭建背景kafka集群搭建 背景 使用virtualbox搭建kafka集群,涉及到不同网络策略的取舍 首先 桥接 网络虽说 啥都可以,但是涉及到过多ip的时候,而且还不能保证使用的ip不被占用,所以个人选择kafka虚拟机…

带宽的理解-笔记

带宽的理解 带宽(频带宽度)&#xff1a;是指电磁波最高频率和最低频率的差值&#xff0c;这一段频率被称为带宽。 举例说明 人耳能听到的频率范围是20赫兹到2万赫兹。换句话说&#xff0c;人而只对20赫兹至2万赫兹的声音频率有反应&#xff0c;超出或低于这一频率范围的声音我…