基于k-means聚类算法的城市出租车GPS时空分布特征分析

2023-10-27

目录

前言:

一、研究目的

二、数据源

三、数据预处理

3.1 通用预处理

3.2 删除出租车数据中载客状态瞬间变化的记录

3.3 获取OD数据

3.4 判断每一辆出租车的OD数据中最靠近整点时刻的记录(采用字典形式储存)

3.5 将每一整点时刻出租车的经纬度信息导出成excel文件便于下一步操作

3.6 绘制散点图和GIS分布图查看效果

四、聚类分析

4.1 手工计算(不使用现成的库,使用1点时刻的数据进行测试)

4.2 使用sklearn库进行批量操作

五、数据特征分析

5.1 簇的数量

5.2 簇的分布状况

5.3 簇中的元素数量

5.4 簇的时间分布特征

小结

六、存在的问题

6.1 整点时刻出租车的GPS定位的插值问题

6.2 样本数量问题

6.3 样本时间问题

6.4 (老师点评补充)

七、代码展示

7.1 将数据整理切分成24个时间段

7.2 导入文件绘制散点图

7.3 不同K值选取的对比

7.4 KMeans的计算与可视化

致谢:

参考资料:


前言:

本文的内容是“城市大数据分析与应用”课程作业的部分展示,使用的是KMeans聚类算法

一、研究目的

        通过统计各个时间节点上出租车的GPS定位数据,分析各时间城市内不同地块的交通密集程度,为道路改建、城市公共空间节点处理提供理论支撑。通过统计各个时间节点上出租车的GPS定位数据,分析各时间城市内交通密集、人群密集的区域地块分布。为可能的道路改建、城市公共空间节点处理等提供理论支撑。

二、数据源

数据来源:https://people.cs.rutgers.edu/~dz220/data.html

这里是站内下载好的数据,可供下载https://download.csdn.net/download/qq_41904236/87670733?spm=1001.2014.3001.5503

        该表格中六列数据分别为:出租车的编号、时间、经度、纬度、是否空载(0-空载,1-载客)、实时速度。 

三、数据预处理

预处理目标:获取某一编号的车辆在整点时的经纬度,即获取数据的最终形态为[carID, time, longitude, latitude]

3.1 通用预处理

删除信息与前后数据相同的数据以减少数据量

如:某个体连续n条数据除了时间以外其他信息都相同,则可以只保留首末两条数据

transbigdata.clean_same(data, col=['VehicleNum', 'Time', 'Lng', 'Lat'])

3.2 删除出租车数据中载客状态瞬间变化的记录

transbigdata.clean_taxi_status(data, col=['VehicleNum', 'Time', 'OpenStatus'], timelimit=None)

3.3 获取OD数据

初始数据:

 处理后数据:

选择OD数据作为经纬度获取的基准

3.4 判断每一辆出租车的OD数据中最靠近整点时刻的记录(采用字典形式储存)

注意: 由于初始数据中时间均不是整点时刻,本次研究中是粗略地将最靠近整点时刻的时间点的经纬度作为目标经纬度,如果需要推断整点时刻的经纬度,则需要做插值运算,若采用线性插值,则会出现插值的点坐标不在道路上的情况(实际上这种情况下可以将该插值点投影到最近道路上,这里由于道路信息缺失未加以考虑)。

3.5 将每一整点时刻出租车的经纬度信息导出成excel文件便于下一步操作

3.6 绘制散点图和GIS分布图查看效果

 

四、聚类分析

4.1 手工计算(不使用现成的库,使用1点时刻的数据进行测试)

此处写了一段递归算法,使用KMeans聚类算法的原始定义进行迭代,其基本流程为:根据给定的K值随机选取原数据点作为初始质心(initCenters)——计算每个点到初始质心的距离,按照最近距离来划分簇——根据划分完成的簇计算新的质心(newCenters)——判断新的质心是否与初始质心一致,若一致,测结束递归,完成聚类;若不一致,则将新的质心赋给初始质心再次迭代。

randomNum = np.random.randint(0,len(xx),size=k)
initCenters = []
for i in randomNum:
    initCenters.append(xx[i])
# 计算每个点和初始中心点的距离
datalen = len(xx)
target = np.full(shape=datalen, fill_value=-1)
def updateCenters(initCenters, counter, limit):
    for i in range(len(xx)):
        dis = []
        for j in range(k):
            dis.append(distance(xx[i],initCenters[j]))
        target[i] = np.argmin(dis)
    newCenters = []
    for i in range(k):
        mean = []
        for j in range(len(xx)):
            if(target[j] == i):
                mean.append(xx[j])
        newCenters.append(np.mean(mean,axis=0))
    if(counter == 0):
        print('未收敛,当前迭代次数为:'+str(limit - counter))
        plt.scatter(x,y,c=target)
        plt.show()
    else:
        if(np.array(newCenters) == initCenters).all():
            print('已收敛,迭代次数为:'+str(limit - counter))
            plt.scatter(x,y,c=target)
            plt.show()
        else:
            counter = counter - 1
            initCenters = np.array(newCenters)
            updateCenters(initCenters, counter, limit)
updateCenters(initCenters,5,5)

(迭代次数为1次,K值根据目测给出5)

(迭代次数为3次,K值根据目测给出5,此时聚类已收敛) 

(*根据测试来看,迭代次数一般不超过10次即可收敛)

4.2 使用sklearn库进行批量操作

在批量操作之前,需要考虑应该使用怎样的K值,在这里需要计算不同K值情况下的误差平方和SSE(Sum of Square Error),用于计算最佳K值。

注:SSE的计算方法:计算每一个K值情况下,各点到其聚类质心的距离的平方和

(p为点,m为各聚类中心) 

下面以1点时刻为例:

这里我们选取K值等于5,由此得到下图:

同时计算各簇质心和聚类数目

 以此类推,计算24个小时的K值情况

由上图可得最佳K值的选择情况以及质心经纬度、聚类数目

 

 然后根据上表选择的K值绘制聚类图

将聚类图叠到深圳市行政地图上可得下图 

(1点的聚类情况) 

聚类运算完毕 

五、数据特征分析

从聚类结果可以看出:

5.1 簇的数量

聚类簇的数量来看,大多数时间段的簇都是5个(部分为7个),因此可以大致推断出深圳人群较为密集的区域有57个,即“核心区域”。

5.2 簇的分布状况

聚类簇的分布状况来看,该57个核心区域分别为:

  ①腾讯滨海大厦周边

  ②车公庙--深圳市政府附近

  ③深圳火车站深圳万象城附近

  ④深圳北站南方科技大学片区

  ⑤深圳东站片区

  ⑥龙城广场(龙岗区中心地带)

  ⑦宝安国际机场片区

5.3 簇中的元素数量

聚类簇中元素的数量来看,

  数量最多的簇对应的地块为深圳火车站深圳万象城附近;数量略次一些的为腾讯滨海大厦周边和车公庙深圳市政府附近。反映出这三个地块是人群最密集、人流量最大的三个片区。

5.4 簇的时间分布特征

聚类的时间分布特征来看,

  1点至7点期间,簇的分布较为分散,可以从SSE分布曲线中看出,SSE值相对较大,说明此时各要素分布较为离散。

  8点至11点期间,簇的分布较为集中。主要集中在南山区腾讯大厦片区、深圳火车站、深圳市政府深圳东站三个区域。

  12点至14点期间,北侧一个簇有向南侧整体偏移的趋势,即龙华区北侧人群向龙华区中心、南侧靠拢的趋势。

  15点至18点期间,簇的分布有从福田区深圳市政府向外扩散的趋势。推测是下班人群从市中心向外流动导致。

  19点至22点期间,簇的分布总体较为平稳均匀。

  23点至24点期间,簇的分布与1点至7点类似,较为分散,仅在深圳站、深圳东站片区较为集中。

小结

总体来看,簇的时间分布在深圳几个火车站周边变动较小,一天24小时都有人群在此处聚集;而南山区、福田区作为主要的工作生活区域,随着时间变化有较为明显的随时间变动的簇的偏移,说明了人群的周期性活动。此外,簇的分布整体呈东西向布局。与城市形状相吻合;簇的变化运动以东西向为主,南北向较少,这也与深圳东西向交通发达,南北向交通较为不变相符。 

六、存在的问题

6.1 整点时刻出租车的GPS定位的插值问题

      如果按照线性插值的方法计算可能会导致定位坐标不在街道上,因此在本研究中采用了最近时刻的位置替代,使数据产生了误差。

6.2 样本数量问题

        本研究中初始数据共有545000条数据,经过筛选和OD处理之后每个整点时刻可用的坐标定位下降到100条左右,在做单独时刻的聚类分析时数据量仍显不足。

6.3 样本时间问题

      本研究中初始数据为20131022日星期二,一方面该数据时间较为久远,对目前的参考价值有限;另一方面,该日期为工作日,需要补充休息日的数据作为进一步分析支撑。

6.4 (老师点评补充)

可以补充其他非一线城市的数据情况分析;

可以补充其他出行方式的GPS数据(公交车、共享单车等);

可以补充分析现在的GPS数据做疫情前后的对比分析。

七、代码展示

7.1 将数据整理切分成24个时间段

from time import time
from sklearn.metrics import accuracy_score
import transbigdata as tbd
import pandas as pd
import geopandas as gpd
import math
import xlwt

data = pd.read_csv('TaxiData-Sample.csv',header=None)
data.columns = ['VehicleNum','time','slon','slat','OpenStatus','Speed']

oddata = tbd.taxigps_to_od(data,col = ['VehicleNum','time','slon','slat','OpenStatus'])
#print(oddata)

solvedTable = {}
match = []
matchAll = []
counter = 0
init_num = 22396
init_time = 0
absTemp = []
for i in range(5815):
    if(oddata.iloc[i]['VehicleNum'] == init_num):
        # counter = counter + 1
        # 找距离该时间点最近的整数时间点
        hour = oddata.iloc[i]['stime'][0]+oddata.iloc[i]['stime'][1]
        minute = oddata.iloc[i]['stime'][3]+oddata.iloc[i]['stime'][4]
        second = oddata.iloc[i]['stime'][6]+oddata.iloc[i]['stime'][7]
        time = round(int(hour) + int(minute) / 60 + int(second) / 600,2) #将时间转换成小数表示
        adj_time = round(time,0) # 四舍五入取整

        if(adj_time == init_time):
            difference = abs(round(adj_time - time,2)) # 求差值            
            absTemp.append(difference)
        else:
            if(len(absTemp) == 1):
                new_log = oddata.iloc[i-1]['slon']
                new_lat = oddata.iloc[i-1]['slat']
                match.append(init_time)
                match.append(new_log)
                match.append(new_lat)
            elif(len(absTemp) > 1):
                absDup = absTemp
                absTemp.sort()
                for j in range(len(absTemp)):
                    if(absDup[j] == absTemp[0]):
                        new_log = oddata.iloc[i+j+1-len(absTemp)]['slon']
                        new_lat = oddata.iloc[i+j+1-len(absTemp)]['slat']
                        match.append(init_time)
                        match.append(new_log)
                        match.append(new_lat)
            absTemp = []
            init_time =  adj_time
            difference = abs(round(adj_time - time,2)) # 求差值            
            absTemp.append(difference)
            matchAll.append(match)
            match = []

    else:
        #match.append(counter)
        solvedTable[str(init_num)] = matchAll
        matchAll = []
        counter = 1
        init_num = oddata.iloc[i]['VehicleNum']

#print(solvedTable)
datalist = []
interval = 16
for i,j in solvedTable.items():
    for k in j:
        if(k[0] == interval):
            datalist.append([int(i), k[1], k[2]])
book = xlwt.Workbook(encoding='utf-8',style_compression=0)
sheet = book.add_sheet('Taxi_' + str(interval),cell_overwrite_ok=True)
col = ('carID','longitude','latitude')
for i in range(0,3):
        sheet.write(0,i,col[i])
#datalist = [[0,0,0],[1,1,1]]
for i in range(0,len(datalist)):
        data = datalist[i]
        for j in range(0,3):
            sheet.write(i+1,j,data[j])
savepath = 'E:/Urban/Taxi_' + str(interval) + '.xls'
book.save(savepath)


7.2 导入文件绘制散点图

import matplotlib.pyplot as plt
import pandas as pd
import xlrd

#读入文件
file_path = "visual/Taxi_24.xls"
df = pd.read_excel(file_path, header=None)

#print(df)
#定义 x  y变量
x = []
y = []

#定义颜色变量
color = ['c', 'b', 'g', 'r', 'm', 'y', 'k', 'w']

#用for循环将文件中的值赋值给x,y
for i in range(1,len(df[0])):
    x.append(df[1][i])
    y.append(df[2][i])

#画图
plt.scatter(x, y, c=color[1], edgecolors='r')
plt.show()

7.3 不同K值选取的对比

import matplotlib.pyplot as plt
from prometheus_client import Metric
from pyrsistent import l
from sklearn import preprocessing
from sklearn import cluster
from sklearn.datasets._samples_generator import make_blobs
from sklearn.cluster import KMeans, linkage_tree
from sklearn.metrics import calinski_harabasz_score
import pandas as pd
import time
import numpy as np
from scipy.cluster.hierarchy import dendrogram, linkage
from sklearn.cluster import AgglomerativeClustering

def calSSE(data,target,k):
    sse = 0
    clusterI = []
    for i in range(k):        
        for j in range(len(target)):
            if(target[j] == i):
                clusterI.append(data[j])

        m = np.mean(clusterI, axis = 0)
        for p in clusterI:
            sse += np.sum(np.square(p-m))
        
        clusterI = []
   
    return sse

for v in range(25):
    #读入文件
    file_path = "visual/Taxi_"+str(v)+".xls"
    df = pd.read_excel(file_path, header=None)
    x = []
    y = []
    for i in range(1,len(df[0])):
        x.append(df[1][i])
        y.append(df[2][i])

    xx = []
    # k = 5
    for i in range(len(x)):
        xx.append([x[i],y[i]])
    #mod = KMeans(n_clusters=k,random_state=9)
    #y_pre = mod.fit_predict(xx)

    #print(calSSE(xx,y_pre,k))
    arr = []
    for k in range(1,20):
        kms = KMeans(n_clusters=k)
        y_pre = kms.fit_predict(xx)
        arr.append(calSSE(xx,y_pre,k))

    plt.plot(arr)
    plt.show()

7.4 KMeans的计算与可视化

import matplotlib.pyplot as plt
from prometheus_client import Metric
from pyrsistent import l
from sklearn import preprocessing
from sklearn.datasets._samples_generator import make_blobs
from sklearn.cluster import KMeans, linkage_tree
from sklearn.metrics import calinski_harabasz_score
import pandas as pd
import time
import numpy
from scipy.cluster.hierarchy import dendrogram, linkage
from sklearn.cluster import AgglomerativeClustering

file_path = "visual/Taxi_22.xls"
df = pd.read_excel(file_path, header=None)
x = []
y = []
for i in range(1,len(df[0])):
    x.append(df[1][i])
    y.append(df[2][i])

xx = []
mod = KMeans(n_clusters=7,random_state=9)
for i in range(len(x)):
    xx.append([x[i],y[i]])
y_pre = mod.fit_predict(xx)
plt.figure(figsize=(20,8),dpi=80)
plt.scatter(x,y,c=y_pre)
plt.show()

r1 = pd.Series(mod.labels_).value_counts()
r2 = pd.DataFrame(mod.cluster_centers_)
r = pd.concat([r2, r1], axis = 1)
r.columns = ['质心经度','质心纬度','聚类数目']
print(r)

致谢:

感谢王老师一学期的付出,在线上上课的情况下克服重重困难为我们带来精彩的课程内容!

参考资料:

[1] 【数学建模】聚类分析——python实现_Fonsi-的博客-CSDN博客_聚类分析python

[2] python数据分析:聚类分析(cluster analysis)_泛泛之素的博客-CSDN博客_python聚类分析

[3] python 聚类_10种Python聚类算法完整操作示例(建议收藏)_ASS-ASH的博客-CSDN博客_python 聚类

[4] 数据挖掘复习笔记之聚类&关联 - 知乎 

[5] 聚类分析_哔哩哔哩_bilibili

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于k-means聚类算法的城市出租车GPS时空分布特征分析 的相关文章

随机推荐

  • 数据标准详细概述-2022

    1 数据标准的是什么 在实际的工作生产中 我们一般会参照国家标准 地方标准 行业标准等来进行具体的活动 来确保我们生成过程符合监管要求 便于上下游协同等 于是我们会见到如下的标准指导文件 同样 数据标准也会以文件的形式存在 在除了国标 行标
  • qq人脸更换_QQ安全中心现在怎么替换人脸设置或删除人脸?

    以下内容收集自网络 题主可以参考一下 1 我们从手机中打开QQ安全中心 如果还不是最新版本的话 请先升级到最新版本 2 在QQ安全中心首页 点击最下方的 工具 按钮 3 在 工具 页面 点击打开 实验室 这个图标 4 在打开的界面 点击打开
  • 四阶魔方玩法总结V1.0

    四阶魔方玩法总结V1 0 1 引言 今写此文 我主要是为了方便自己再次玩其魔方的时候 可以快速的想起 避免又从头学起 毕竟自己学会的 理解的 写出来的东西 再次玩魔方的时候 仅仅是回顾和追忆的过程 不存在学习 理解和消化的过程 避免再次浪费
  • 12.大数据之Hive性能优化

    hive性能调优 1 HADOOP计算框架特性 数据量大不是问题 数据倾斜是个问题 jobs数比较多的作业运行效率相对比较低 比如即使有几百行的表 如果多次关联多次汇总 产生十几个jobs 耗时很长 原因是map reduce作业初始化的时
  • 二叉树类型的常考选择题知识储备(二叉树的性质)

    1 若规定 根节点的层数为 1 则 一个非空二叉树的 第 i 层 上最多有 2i 1 i gt 0 个结点 2 若规定只有根节点的二叉树的深度为1 则 深度为 K 的二叉树的 最大结点数是 2k 1 k gt 0 3 对于任意一个二叉树 如
  • Angular管道操作符(

    一 模板表达式操作符 模板表达式语言使用了JavaScript 语法的子集 并补充了几个用于特定场景的特殊操作符 管道操作符 安全导航操作符 二 管道操作符 在绑定之前 表达式的结果可能需要一些转换 例如 可能希望吧数字显示成金额 强制文本
  • 【Web3】Mnemonic Word Create Wallet

    目录 Create Mnemonic Word 介绍 一 根据 Mnemonic Word 生成密钥对 keypair 二 通过 keypair 获取 Wallet 地址 和 private key 代码 Create Mnemonic W
  • bash: ./make.sh: /bin/sh^M: 解释器错误: 没有那个文件或目录

    原因 在Linux运行 sh文件时报上述错误 原因是因为该文件在windows系统上打开过 关闭后其中的空格符号和Linux的不同 导致这个报错 可以通过sed命令与正则的配合将文件中的空格符号替换成linux的空格 解决方法 sed i
  • 实验6

    一 MPEG 1 Audio LayerII编码器原理 1 多相滤波器组 将PCM样本变换到32个子带的频域信号 如果输入的采样频率为48kHz 那么子带的频率宽度为48 2 32 0 75Hz 缺点 1 等带宽的滤波器组与人类听觉系统的临
  • MSCOCO数据标注详解(超详细)

    博主大大 风吴痕 对MSCOCO的讲解 超级详细而且有代码举例 转发收藏 后面方便自己查看 https blog csdn net wc781708249 article details 79603522
  • SQLite 3.7.13的加密解密

    原文链接 http lancelot blog 51cto com 393579 940805 http lancelot blog 51cto com 393579 940808 http lancelot blog 51cto com
  • stata移动平均插值法mipolate命令

    stata移动平均插值法mipolate命令 xtset id year by id mipolate x3 year gen x3 1 idw 4 idw表示取移动平均的项数 结果
  • Springboot框架通过@Scheduled实现定时任务

    一 开启定时任务方法 Scheduled定时任务是Spring boot自身提供的功能 所以不需要引入Maven依赖包 在项目入口main方法上加注解 EnableScheduling 开启定时任务 二 不同定时方式的解析 1 fixedD
  • rom查找表matlab,用matlab生成查找表输出coe文件给xilinx的Mem_IPCore使用

    这是一个coe文件的例子 Sample initialization file for a 32 bit wide by 16 deep RAM 这是注释说明性文字 memory initialization radix 16 2 10 1
  • 三、高级数据结构和算法:树的遍历

    3 树的遍历 树的遍历 是指依照一定的规律不反复地访问树中的每个节点 遍历是将非线性的树状结构按一定规律转化为线性结构 3 1 多叉树遍历 多叉树遍历分为深度优先遍历和广度优先遍历两类 3 1 1 深度优先遍历 Depth First Se
  • 基础算法题——整除光棍(Java大数)

    整除光棍 这里所谓的 光棍 并不是指单身汪啦 说的是全部由1组成的数字 比如1 11 111 1111等 传说任何一个光棍都能被一个不以5结尾的奇数整除 比如 111111就可以被13整除 现在 你的程序要读入一个整数x 这个整数一定是奇数
  • Java Date类,DateFormat类,Calendar类用法。

    1 Date类 java util Date 表示日期和时间的类 类Date表示特定的瞬间 精确到毫秒 毫秒 千分之一秒 1000毫秒 1秒 毫秒值的作用 可以对时间和日期进行计算 例如 可以对时间和日期进行计算 2088 01 03到20
  • Nginx自动化部署脚本(在线离线均适用)

    bin bash Author Wang Dajiang Date 2023 01 18 FileName install nginx sh csdn https blog csdn net sinat 41836475 type blog
  • .net mysql 特殊字符转义字符_MySQL 特殊字符转义问题

    模糊查询时 很多特殊字符都是有特定意义的 比如 等 这些在模糊查询中都是通配符 如果用户在前端的输入是没有限制的 那么 一旦输入相关特殊字符 就会获得错误的查询结果 出于需求的细致要求 这个问题是需要解决的 在网上找了很多资料 发现能够完全
  • 基于k-means聚类算法的城市出租车GPS时空分布特征分析

    目录 前言 一 研究目的 二 数据源 三 数据预处理 3 1 通用预处理 3 2 删除出租车数据中载客状态瞬间变化的记录 3 3 获取OD数据 3 4 判断每一辆出租车的OD数据中最靠近整点时刻的记录 采用字典形式储存 3 5 将每一整点时