ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

上海市地铁刷卡数据到OD矩阵

2021-06-05 19:56:53  阅读:238  来源: 互联网

标签:刷卡 stations df OD 矩阵 卡号 time card


上海市地铁刷卡数据到OD矩阵

前言

在这里插入图片描述
上期 ,定义出早高峰和晚高峰时段,接下来就是要分早高峰和晚高峰来做出上海市地铁刷卡人次OD矩阵(origin-destination matrix),因为上海轨道交通具有很好的连通性,所以我们可以利用抽象的矩阵理论来分析。这样整个上海市轨道交通的通勤OD情况就能够通过一个矩阵来表示和研究,矩阵中的元用来刻画各站点的客流来源和去向。

思路

首先要定义出地铁OD矩阵和矩阵中的元,定义
A = ( a i j ) A=(a_{ij}) A=(aij​)
为上海市地铁OD矩阵,矩阵中的元 a i j a_{ij} aij​定义为同一时段从第 j j j个站到第 i i i个站的刷卡人次,比如令 i i i为人民广场站, j j j为富锦路,此时 a i j a_{ij} aij​就表示相同时段内从富锦路进站,从人民广场出站的那波人,令 j j j取不同时值时候,同样也可以知道其他站点到人民广场站的刷卡人次,同理也可以令 i i i为其他站点,这样令 i i i和 j j j取不同的值时,就知道不同站点进出和特定流向情况,现在的问题是如何度量 a i j a_{ij} aij​大小。这里给出集合论方法,令
A = { 卡 号 : j 进 站 的 卡 号 } A=\{卡号: j进站的卡号\} A={卡号:j进站的卡号}
B = { 卡 号 : i 出 站 的 卡 号 } B=\{卡号:i出站的卡号\} B={卡号:i出站的卡号}
因为一个卡号对应一个人,集合 A A A表示从 j j j站进来的那波人次,集合 B B B表示从 i i i站出来的那波人次,如果两拨人次重复的,那么重复的那小波人次就是第 j j j个站到第 i i i个站的刷卡人次 则,此时集合 A A A和集合 B B B的交集 A ∩ B A\cap B A∩B 表示从 j j j 进站的且从 i i i 出站的卡号, 即交集 A ∩ B A\cap B A∩B的势便是 a i j a_{ij} aij​的取值。

结果预览

在这里插入图片描述

代码
# -*- coding: utf-8 -*-
"""
project_name:read_mysql
@author: 帅帅de三叔
Created on Thu Dec 12 15:10:32 2019
"""
import numpy as np #导入数值分析模块
import pandas as pd #导入数据分析模块
from sqlalchemy import create_engine #数据库引擎
connection=create_engine("mysql+pymysql://root:123456@localhost:3306/metro_sh?charset=utf8") #连接数据库
sql=pd.read_sql('zaogaofeng',connection) #读取sql数据库
df=pd.DataFrame(sql) #数据框化
#print(df.head()) #测试表头前5
stations=df['站点'].unique() #所有去重的站点
M=np.zeros(shape=(313,313)) #构造一个313*313零矩阵

for index1,i in enumerate(stations): #行
    for index2,j in enumerate(stations): #列
        card_out_i=df[(df['站点']==i)&(df['费用']!=0)]['卡号'] #第i站出站卡号序列
        card_in_j=df[(df['站点']==j)&(df['费用']==0)]['卡号'] #第j站进站卡号
        print(len(card_out_i),len(card_in_j)) #测试j进站,i出站的卡号
        ai=set(card_out_i) #出站列表集合化
        aj=set(card_in_j)  #进站列表集合化
        aij=ai.intersection(aj) #求交集,即从j进站,i出站的卡号
        print(len(aij)) #交集计数
        count=len(aij) 
        M[index1,index2]=count #赋值               
M=pd.DataFrame(M) #数据框化
M.columns=stations #构造表头
M.index=stations #构造索引
M.to_excel("早高峰OD矩阵.xlsx") #写入excel     
代码解读

整段代码大体过程是先用sqlalchemy模块的create_engine类连接到MySQL数据库,紧接着用 pd.read_sql() 读取库里面的数据表,比如这里的zaogaofeng,数据读出来了,接下来就完全是python操作了,如提取不重复的站点,用 card_out_i=df[(df[‘站点’]==i)&(df[‘费用’]!=0)][‘卡号’] 筛出第 i i i 站出站卡号序列,用 card_in_j=df[(df[‘站点’]==j)&(df[‘费用’]==0)][‘卡号’] 筛出第 j j j 站出站卡号序列,然后用set() 函数集合化,并求交集和交集的势,并把所求的结果赋值给先定义的零矩阵M的第 i i i行第 j j j列元 a i j a_{ij} aij​,最后把重新赋值后的矩阵写入到excel便得到想要得OD矩阵。

改进思路

首先,代码运行太慢了,不管是读取数据库MySQL还是构造OD矩阵中的多两层循环还是集合筛选运算,都很费时;其次是代码写的太散,通用性不强,想打包成函数或者类。下面以晚高峰为例,利用面向对象编程和模块化思想,看看代码是不是简洁些,运行时间多少?

改进代码
# -*- coding: utf-8 -*-
"""
project_name:read_mysql
@author: 帅帅de三叔
Created on Thu Dec 12 15:10:32 2019
"""
import time 
import numpy as np #导入数值分析模块
import pandas as pd #导入数据分析模块
from sqlalchemy import create_engine #数据库引擎
connection=create_engine("mysql+pymysql://root:123456@localhost:3306/metro_sh?charset=utf8") #连接数据库
sql=pd.read_sql('wangaofeng',connection) #读取sql数据库
data=pd.DataFrame(sql) #数据框化
print(data.head()) #测试表头前5

def generate_od_matrix(df): #自定义构造OD矩阵函数
    stations=list(df['站点'].unique()) #所有去重的站点,object类型转list
    OD_Matrix=np.zeros(shape=(len(stations),len(stations))) #构造一个313*313零矩阵
    for index1,i in enumerate(stations): #行
        for index2,j in enumerate(stations): #列
            print(i,j)
            card_out_i=df[(df['站点']==i)&(df['费用']!=0)]['卡号'] #第i站出站卡号序列
            card_in_j=df[(df['站点']==j)&(df['费用']==0)]['卡号'] #第j站进站卡号
            print(len(card_out_i),len(card_in_j)) #测试j进站,i出站的卡号
            ai=set(card_out_i) #出站列表集合化
            aj=set(card_in_j)  #进站列表集合化
            aij=ai.intersection(aj) #求交集,即从j进站,i出站的卡号
            print(len(aij)) #交集计数
            count=len(aij) #统计j进站,i出站的刷卡人次
            OD_Matrix[index1,index2]=count #赋值
    M=pd.DataFrame(OD_Matrix) #数据框化
    M.columns=stations #构造表头
    M.index=stations #构造索引
    M.to_excel("晚高峰OD矩阵.xlsx") #写入excel  
    
if __name__=="__main__": #起始主函数
    start_time=time.time() #开始时间
    generate_od_matrix(data)
    end_time=time.time() #结束时间
    print("the process lasts:",end_time-start_time) #程序运行总时间   
代码解读

整个程序跑了20989秒,近6个小时,要知道这才是晚高峰80分钟的时间跨度,150万条刷卡记录,如果换成一天的就是900万条,大约35小时,关键怎么在电脑上快速读取这么大数据和处理,这就是接下来要研究的问题了。为此,从新整理了代码,写了两个函数,第一个函数 read_mysql 用来读取MySQL得到一个数据框,第二个函数 generate_od_matrix调用第一个函数的结果来生成OD矩阵,最后主函数用来保存OD矩阵到excel中,本机配置如下
在这里插入图片描述
程序是从周一下午4点左右开跑的,周三早上来上班,发现程序跑完了,甚是欣慰,总共花了137036.9512345791秒,大约是38小时,比计划中的多3小时,这也是可以理解的,其实读数据大约只要30分钟,大部分时间是花在遍历数据并集合化处理上面。

完整代码
# -*- coding: utf-8 -*-
"""
project_name:read_ten_million_rows_data_from_mysql
@author: 帅帅de三叔
Created on Fri Dec 20 13:19:18 2019
"""
import time #导入时间模块
import numpy as np #导入数值分析模块
import pandas as pd #导入数据分析模块
import pymysql #导入数据库连接模块 

def read_mysql(): #定义读取MySQL函数
    rows=[] #用来存放行数据
    db=pymysql.connect(host='localhost',user="root",passwd="123456",database="metro_sh",port=3306,charset='utf8',cursorclass =pymysql.cursors.SSCursor) #连接到本地MySQL数据库
    cursor=db.cursor() #获取游标
    cursor.execute("SELECT * FROM metro20160901") #筛取数据 
    while True:
        row=cursor.fetchone() #一次只取一行
        rows.append(row)
        print("正在读取第%d行"%len(rows))
        print(row)
        if not row:
            break
    cursor.close() #关闭游标
    db.close() #关闭数据库连接
    df=pd.DataFrame(rows)
    return df

def generate_od_matrix(df): #定义生成od矩阵的函数
    df.columns=["卡号","日期","时间","站点","方式","费用","是否有优惠"] #重命名表头
    stations=df['站点'].unique() #所有去重的站点 
    od_matrix=np.zeros(shape=(len(stations),len(stations))) #构造一个313*313零矩阵
    for index1,i in enumerate(stations): #行
        for index2,j in enumerate(stations): #列
            print(index1,index2)
            card_out_i=df[(df['站点']==i)&(df['费用']!=0)]['卡号'] #第i站出站卡号序列
            card_in_j=df[(df['站点']==j)&(df['费用']==0)]['卡号'] #第j站进站卡号
            print(len(card_out_i),len(card_in_j)) #测试j进站,i出站的卡号
            ai=set(card_out_i) #出站列表集合化
            aj=set(card_in_j)  #进站列表集合化
            aij=ai.intersection(aj) #求交集,即从j进站,i出站的卡号
            print(len(aij)) #交集计数
            count=len(aij) 
            od_matrix[index1,index2]=count #赋值               
    od_matrix=pd.DataFrame(od_matrix) #数据框化   
    return od_matrix,stations

if __name__=="__main__":
    start_time=time.time() #开始时间
    M,stations=generate_od_matrix(read_mysql()) #函数嵌套调用读取数据库函数
    M.columns=stations #构造表头
    M.index=stations #构造索引
    M.to_excel("上海市OD矩阵.xlsx") #写入excel  
    end_time=time.time() #开始时间
    print('程序耗时:',end_time-start_time) #测试读取数据时间

如果你不会写代码或直接只想要数据的话可以关注“三行科创”公众号,在对话框留个邮箱和所要数据名称,我发给你。

参考文献

1,https://wenku.baidu.com/view/165abf1d336c1eb91a375d8d.html
2,https://wenku.baidu.com/view/fa71f2107375a417866f8f81.html?sxts=1575956307792
3,https://wenku.baidu.com/view/5710cba20d22590102020740be1e650e52eacf23.html?rec_flag=default&sxts=1575957393812

在这里插入图片描述

标签:刷卡,stations,df,OD,矩阵,卡号,time,card
来源: https://blog.51cto.com/u_15255081/2870568

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有