Accessibility analysis of Gauss two-step mobile search method based on road network and GeoPandas

import warnings
warnings.filterwarnings("ignore")
import geopandas as gpd
import pandas as pd
import os
import collections
import heapq
import re
import math
# File path
path=r"C:\Users\Falling flower rain\Desktop\data"
LIST=["\\"+i for i in os.listdir(path)]
KM_Poi=gpd.read_file(path+LIST[5]) # Kunming points of interest
YJBNS_Ent=gpd.read_file(path+LIST[2]) # Emergency shelter entrance data
YJBNS_Polgon=gpd.read_file(path+LIST[3]) # Data of emergency shelter
ZCQ_Roa=gpd.read_file(path+LIST[1]) # Main urban roads
OD=gpd.read_file(path+LIST[0])# OD matrix

Data exploration

KM_Poi.head(2)
FIDOBJECTIDosm_idnametypepopulationQUYU_NAMEgeometry
003474552927Guandu Streettown183624public ferryPOINT (576290.931 2761828.261)
11121483174846Haikou Streettown69019XishanPOINT (561304.355 2742770.016)
YJBNS_Ent.head(2)
FIDOBJECTIDNAMEQUYU_NAMEgeometry
006Chenggong campus of Yunnan University - West GateChenggong POINT (585001.518 2747248.457)
117Chenggong campus of Yunnan University - North GateChenggong POINT (585528.681 2748211.540)
YJBNS_Polgon.head(2)
FIDNAMEShape_LengShape_Areageometry
00Radio and television garden campus of the first primary school in Chenggong New Area, Kunming610.36970019710.134256POLYGON ((11444231.072 2852271.929, 11444275.0...
11Kunming Experimental School Affiliated to Sichuan Normal University (days)966.36613352802.239035POLYGON ((11445552.439 2854525.840, 11445615.3...
ZCQ_Roa.head(2)
FIDFID_roadsosm_idnamereftypeonewaybridgemaxspeedFID_ Kunming...name_1centercentroidchildrenNulevelparentsubFeatureacrouteslengthgeometry
00023412703.0Kunming-Shilin Expresswaymotorway1102...Guandu District000district0201152.168205MULTILINESTRING ((102.73576 25.01994, 102.7363...
11124044953.0Baita Roadsecondary1001...Panlong District000district0101994.046225MULTILINESTRING ((102.72596 25.05293, 102.7260...

2 rows × 21 columns

Data preprocessing

# View coordinate system
KM_Poi.crs # The point of interest is CGCS2000 / 3-degree Gauss Kruger cm 102e
# Its coordinate system code is 4543
<Projected CRS: EPSG:4543>
Name: CGCS2000 / 3-degree Gauss-Kruger CM 102E
Axis Info [cartesian]:
- X[north]: Northing (metre)
- Y[east]: Easting (metre)
Area of Use:
- name: China - between 100°30'E and 103°30'E.
- bounds: (100.5, 21.13, 103.5, 42.69)
Coordinate Operation:
- name: 3-degree Gauss-Kruger CM 102E
- method: Transverse Mercator
Datum: China 2000
- Ellipsoid: CGCS2000
- Prime Meridian: Greenwich
ZCQ_Roa.crs
# The coordinate system of Road needs to be converted into projection coordinates
<Geographic 2D CRS: GEOGCS["CGCS_2000",DATUM["D_2000",SPHEROID["S_2000 ...>
Name: CGCS_2000
Axis Info [ellipsoidal]:
- lon[east]: Longitude (Degree)
- lat[north]: Latitude (Degree)
Area of Use:
- undefined
Datum: D_2000
- Ellipsoid: S_2000
- Prime Meridian: Greenwich
YJBNS_Polgon.crs  # The emergency shelter is WGS84
# Coordinate conversion required
<Projected CRS: EPSG:3857>
Name: WGS 84 / Pseudo-Mercator
Axis Info [cartesian]:
- X[east]: Easting (metre)
- Y[north]: Northing (metre)
Area of Use:
- name: World between 85.06°S and 85.06°N.
- bounds: (-180.0, -85.06, 180.0, 85.06)
Coordinate Operation:
- name: Popular Visualisation Pseudo-Mercator
- method: Popular Visualisation Pseudo Mercator
Datum: World Geodetic System 1984 ensemble
- Ellipsoid: WGS 84
- Prime Meridian: Greenwich
OD.crs
<Projected CRS: EPSG:4543>
Name: CGCS2000 / 3-degree Gauss-Kruger CM 102E
Axis Info [cartesian]:
- X[north]: Northing (metre)
- Y[east]: Easting (metre)
Area of Use:
- name: China - between 100°30'E and 103°30'E.
- bounds: (100.5, 21.13, 103.5, 42.69)
Coordinate Operation:
- name: 3-degree Gauss-Kruger CM 102E
- method: Transverse Mercator
Datum: China 2000
- Ellipsoid: CGCS2000
- Prime Meridian: Greenwich
YJBNS_Ent.crs
<Projected CRS: EPSG:4543>
Name: CGCS2000 / 3-degree Gauss-Kruger CM 102E
Axis Info [cartesian]:
- X[north]: Northing (metre)
- Y[east]: Easting (metre)
Area of Use:
- name: China - between 100°30'E and 103°30'E.
- bounds: (100.5, 21.13, 103.5, 42.69)
Coordinate Operation:
- name: 3-degree Gauss-Kruger CM 102E
- method: Transverse Mercator
Datum: China 2000
- Ellipsoid: CGCS2000
- Prime Meridian: Greenwich

Coordinate system conversion

YJBNS_Polgon=YJBNS_Polgon.to_crs(epsg=4543)
ZCQ_Roa=ZCQ_Roa.to_crs(epsg=4543)
YJBNS_Ent=YJBNS_Ent.to_crs(epsg=4543)

At this time, the work of unifying the coordinate system has been completed

Step 1 Calculation

This step needs to find out all POI s within the search radius of the emergency shelter and calculate the supply-demand ratio

Build buffer

The buffer is used to search for supply points

YJBNS_Polgon_C=YJBNS_Polgon.copy()
# Build buffer example
YJBNS_Polgon_C["geometry"][0].buffer(50)

# We don't need a middle
YJBNS_Polgon_C["geometry"][0].buffer(50).difference(YJBNS_Polgon_C["geometry"][0])

# Check the distribution of emergency shelters
YJBNS_Polgon_C['geometry'].plot()
<matplotlib.axes._subplots.AxesSubplot at 0x1c7f17706d8>

# Set buffer radius
BUFFER=3000
YJBNS_Polgon_C['geometry']=YJBNS_Polgon_C["geometry"].buffer(BUFFER)
YJBNS_Polgon_C['geometry'].plot()
<matplotlib.axes._subplots.AxesSubplot at 0x1c7f178ab00>

Manhattan distance

Compared with European distance measurement, Manhattan distance can better reflect the actual connectivity between urban POI s

OD.head(2)
FIDObjectIDNameOriginIDDestinatioDestinat_1Total_ longgeometry
0012851Guandu Street - century Jinyuan School Affiliated to Yunnan Normal University - East Gate10342211296.528731LINESTRING (576290.931 2761828.261, 575577.741...
1112852Guandu Street - Xingyao campus of Yunda affiliated middle school - North Gate10342021490.718704LINESTRING (576290.931 2761828.261, 577144.590...

For OD cost matrix, we hope to have a settlement for each emergency shelter

In the constructed OD matrix, the Name attribute is divided by street emergency shelter entrance

# Get name list first
Ent_name_list=YJBNS_Ent["NAME"].unique()
Str_name_list=KM_Poi["name"].unique()
S2E=collections.defaultdict(list)# Street entry dictionary
E2S=collections.defaultdict(list) # Street dictionary corresponding to entrance
for i in range(OD.shape[0]):
    # Get and split names
    Name=list(map(lambda x:x.strip(),OD.iloc[i,2].split("-",1)))
    # Record the corresponding value
    dis=OD.iloc[i,6]
    # street
    # The data will be repeatedly read and written three times!!
    # Do not know why?
    heapq.heappush(S2E[Name[0]],(dis,Name[1]))
    heapq.heappush(E2S[Name[1]],(dis,Name[0]))
# At this time, it is found that all records have been recorded
for i in Ent_name_list:
    if i not in E2S.keys():
        print(E2S[i])
        
# Ma Street is a fairy
# He was abandoned because he couldn't find his destination
for j in Str_name_list:
    if j not in S2E.keys():
        print(j)
Ma Jie Street
# The small root heap will weed out the elements
# If you want to keep the element, you can leave a copy
S2E_c=S2E.copy()
E2S_c=E2S.copy()

At this point, we have dealt with the Manhattan distance, and now we can start from the entrance of the shelter to find the settlement with a given threshold

It can also start from the residential area and find the service area with a given threshold

Next, we will get the area information of the shelter

Area of emergency shelter

In this step, we need to obtain the area information of the emergency shelter and correspond it with the entry point

Let's look at the shelter data first

YJBNS_Polgon_C1=YJBNS_Polgon.copy()
YJBNS_Polgon_C1.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x1c7f17a6128>

YJBNS_Polgon_C1.head()
FIDNAMEShape_LengShape_Areageometry
00Radio and television garden campus of the first primary school in Chenggong New Area, Kunming610.36970019710.134256POLYGON ((581419.907 2745109.067, 581460.202 2...
11Kunming Experimental School Affiliated to Sichuan Normal University (days)966.36613352802.239035POLYGON ((582607.927 2747151.992, 582666.062 2...
22Emergency shelter of Yunnan University of traditional Chinese Medicine3778.904004607319.343216POLYGON ((582979.894 2749463.449, 582932.370 2...
33Laoyuhe Wetland Park3832.693417513661.330361POLYGON ((577548.739 2746297.639, 577654.965 2...
44High school attached to Yunshi University1255.955110107052.706438POLYGON ((585882.850 2749957.852, 585741.543 2...

After data exploration, it is found that the NAME attribute column in the data can correspond to the entry NAME, and the Shape_Area is the area obtained by geometric calculation

However, the names between the two tables do not exactly match. We just need to match keywords

# Array to be mapped
E_N=E2S.keys()
P_N=YJBNS_Polgon_C1["NAME"]
Name_Area=[]
for i in P_N:
    for j in E_N:
        if re.search(i,j):
            Name_Area.append([j,(YJBNS_Polgon_C1[YJBNS_Polgon_C1["NAME"]==i]["Shape_Area"]).tolist()[0]])
# Create a query table
Area=dict(Name_Area)

Now we need to design a function to extract the data within a given threshold

def getData(dataset,threshold):
    tem_dataset=dataset.copy()
    if len(tem_dataset)==0:
        # Empty table
        return []
    T=heapq.heappop(tem_dataset)
    ans=[]
    while T[0]<=threshold:
        ans.append(T)
        T=heapq.heappop(tem_dataset)
    return ans 

Population data

The Population data is stored in the Population field of Kunming POI

KM_Poi.head()
FIDOBJECTIDosm_idnametypepopulationQUYU_NAMEgeometry
003474552927Guandu Streettown183624public ferryPOINT (576290.931 2761828.261)
11121483174846Haikou Streettown69019XishanPOINT (561304.355 2742770.016)
2214-1995559001Majinpu Streettown54798ChenggongPOINT (581339.943 2742863.779)
3315-1659466282Ala Streettown87545public ferryPOINT (579586.509 2766116.964)
4522-782694876Shuanglong Streettown11841PanlongPOINT (585541.983 2778974.166)

To view its population data, you only need the following statement

KM_Poi[KM_Poi["name"]=="Guandu Street"]["population"].tolist()[0]
183624
# Encapsulate into function
def getPop(name):
    try:
        return KM_Poi[KM_Poi["name"]==name]["population"].tolist()[0]
    except:
        return -1
    
# But the time complexity is too high
# So I decided to type my watch
Name_Pop={}
for i in range(KM_Poi.shape[0]):
    T=KM_Poi.iloc[i]
    Name_Pop[T['name']]=T['population']

Supply demand ratio calculation

According to the formula:
R j = S j ∑ k ∈ { d k j ≤ d 0 } G ( d k j , d 0 ) D k R_j =\frac{S_j}{\sum_{k\in \{{d_{kj}\le d_0}\}}G(d_{kj},d_0)D_k} Rj​=∑k∈{dkj​≤d0​}​G(dkj​,d0​)Dk​Sj​​
Calculate

# First determine the search radius
# This demo uses the search radius of the given threshold
Threshold=3000
# test
getData(S2E_c["Guandu Street"],Threshold)
[(1296.52873128, 'Century Jinyuan School Affiliated to Yunnan Normal University-East Gate'),
 (1490.71870426, 'Xingyao campus of Yunda affiliated middle school-North Gate'),
 (1600.79115752, 'Yunyao Campus-South Gate'),
 (1708.15483322, 'Xingyao campus of Yunda affiliated middle school-1 Gate No'),
 (1782.80973124, 'Century Jinyuan School Affiliated to Yunnan Normal University-Southwest gate'),
 (1850.44174205, 'Century Jinyuan School Affiliated to Yunnan Normal University-west gate'),
 (1955.38161, 'Century Jinyuan School Affiliated to Yunnan Normal University-Northwest Gate'),
 (2780.42288513, 'New Asia Sports City Sports Center-2 Gate No'),
 (2960.49871649, 'New Asia Sports City Sports Center-1 Gate No')]
# test
getData(E2S_c["Radio and television garden campus of the first primary school in Chenggong New Area, Kunming"],12000)
[(3219.24822336, 'Majinpu Street'),
 (3354.50862843, 'Dayu Street'),
 (5100.55004948, 'Yuhua Street'),
 (8610.87021572, 'Oolong Street'),
 (9965.30536041, 'Longcheng Street'),
 (10175.1377117, 'Luolong Street')]

What we need to deal with now is to accumulate these data according to the formula and determine the Gaussian method first:

def Gauss(dis,dis_D):
    f1=((math.e)**(-0.5))*((dis/dis_D)**2)-math.e*(-0.5)
    f2=1-math.e**(-0.5)
    return f1/f2
# Calculate for each supply point
# Keep copies
YJBNS_Ent_c=YJBNS_Ent.copy()
R_list=[] # Used to store data

for i in range(len(Ent_name_list)):
    # Find each demand point within the search radius
    name=YJBNS_Ent_c.iloc[i,2]
    points=getData(E2S[name],Threshold)
    # Of course, some don't have it at all
    # In this part, we will improve the algorithm later
    # We need to get the population of these points
    ans=0
    for poi in points:
        Name=poi[1]
        dis=poi[0]
        population=Name_Pop[Name]
        ans+=population*Gauss(dis,Threshold)
    # Those that cannot be found need to be handled
    # In fact, our data are not completely one-to-one correspondence
    try:
        R_list.append(Area[name]/ans)
    # At present, for division by zero (there are no points in the search radius of this area)
    # And area mismatch (missing shelter area)
    # Unified zeroing
    except:
        R_list.append(0)
YJBNS_Ent_c['R_val']=R_list
YJBNS_Ent_c.head()
FIDOBJECTIDNAMEQUYU_NAMEgeometryR_val
006Chenggong campus of Yunnan University - West GateChenggong POINT (585001.518 2747248.457)0.0
117Chenggong campus of Yunnan University - North GateChenggong POINT (585528.681 2748211.540)0.0
228Chenggong campus of Yunnan University - East GateChenggong POINT (586966.101 2747785.881)0.0
339Chenggong campus of Yunnan University - South GateChenggong POINT (586146.480 2746968.095)0.0
4410Southwest Associated University Research Institute affiliated school - gate 3Chenggong POINT (587599.978 2748137.044)0.0

Step 2 Calculation

In the previous step, we have obtained the R value

In this step, we will start from the residential area and find all the emergency shelter entrances within the search radius

The specific formula is as follows:

A i = ∑ f ∈ { d i j ≤ d 0 } R j A_i=\sum_{f\in \{{d_{ij}\le d_0}\}}R_j Ai​=f∈{dij​≤d0​}∑​Rj​

KM_Poi_c=KM_Poi.copy()

# In consideration of thread optimization, we still make tables
R_N=dict(zip(YJBNS_Ent_c['NAME'],YJBNS_Ent_c['R_val']))
A_list=[]
for i in range(KM_Poi_c.shape[0]):
    name=KM_Poi_c.iloc[i,3]
    points=getData(S2E[name],Threshold)
    # At this time, only R needs to be calculated_ Sum of Val
    ans=0
    for poi  in points:
        # There is still a problem of mismatch
        try:
            ans+=R_N[poi[1]]
        except:
            ans+=0
    A_list.append(ans)
KM_Poi_c['A_val']=A_list
KM_Poi_c.head()
FIDOBJECTIDosm_idnametypepopulationQUYU_NAMEgeometryA_val
003474552927Guandu Streettown183624public ferryPOINT (576290.931 2761828.261)0.245758
11121483174846Haikou Streettown69019XishanPOINT (561304.355 2742770.016)0.000000
2214-1995559001Majinpu Streettown54798ChenggongPOINT (581339.943 2742863.779)0.000000
3315-1659466282Ala Streettown87545public ferryPOINT (579586.509 2766116.964)0.000000
4522-782694876Shuanglong Streettown11841PanlongPOINT (585541.983 2778974.166)0.000000

Storage and display

KM_Poi_c.to_file(r"C:\Users\Falling flower rain\Documents\Tencent Files\651421775\FileRecv\New folder\Data\Accessibility.shp")
KM_Poi_c.plot()


The results are as follows:

Demo improvements

At present, the improvement directions considered are:

  • Adaptive search radius
  • More reasonable Poisson flow damping
  • More complex human land relationship model
  • Correctness correction of data source

Keywords: Python gis

Added by phpchamps on Fri, 11 Feb 2022 21:58:12 +0200