以前在处理gis数据的时候,都是直接导入本地shp素材、本地geojson素材,本地topojson素材,自从接触postgis数据之后,深感使用规范的存储系统来统一管理gis数据的好处,特别是数据量大了之后,优势便更加明显,你可以选择将很多需要做空间计算的步骤转移到Postgis数据库内进行计算,要知道Postgis提供的空间计算能力与R和Python这种应用导向的工具相比,优势要大得多。

在批量导入素材之前,我们可以先看下R语言目前提供的各种导入接口在I/O性能上相比有何异同。

#install.packages("geojsonio")

#devtools::install_github("ropensci/geojsonio")

library("geojsonio")

library("rgdal")

library("sf")

library("maptools")

使用maptools包中的readShapePoly函数进行导入(已快被遗弃了,推荐使用sf和rgdal包)

system.time(china_map

用户 系统 流逝 0.23 0.00 0.23

Warning message:

use rgdal::readOGR or sf::st_read

china_map@data

ggplot2::fortify(china_map)

geojsonio包导入:

system.time(geojson1

"D:/R/rstudy/CHN_adm/bou2_4p.shp",

method = "local",

parse = TRUE,

what = "sp",

encoding="utf-8",

use_iconv=TRUE

))

用户 系统 流逝 0.69 0.03 0.71

使用rgdal包:

system.time(map_data

"D:/R/rstudy/CHN_adm/bou2_4p.shp",

encoding="utf-8",

use_iconv=TRUE

))

OGR data source with driver: ESRI Shapefile

Source: "D:\R\rstudy\CHN_adm\bou2_4p.shp",

layer: "bou2_4p"with 925 features

It has 7 fields

Integer64 fields read as strings: BOU2_4M_ BOU2_4M_ID

用户 系统 流逝 0.66 0.09 0.75

使用sf包导入:

system.time(nepal_shp

"D:/R/rstudy/CHN_adm/bou2_4p.shp",

options = "ENCODING=gbk" ))

用户 系统 流逝 0.05 0.00 0.05

可以看到在同一个shp文件单项导入的情况下,纯粹从时间上来看:

sf > maptools > rgdal > geojsonio

这里值得一提的是,geojsonio包是封装的rgdal服务,性能上自然略逊rgdal一筹,以上四个包中,除sf包是基于simple features标准的模型之外,其他基本都是基于sp模型的。sf模型的性能由此可见一斑。

当然,以上sf包、rgdal包和sf包都是兼容性很好地包,可以支持非常广泛的数据源,以下分别是在json标准下的两种素材上进行测试。

geojson

system.time(geojson

"D:/R/mapdata/State/china.geojson",

method = "local",

parse = TRUE,

encoding="utf-8",

use_iconv=TRUE,

what = "sp" ))

用户 系统 流逝 0.80 0.02 0.81

system.time(map_data

"D:/R/mapdata/State/china.geojson",

encoding="utf-8",

use_iconv=TRUE,

stringsAsFactors = FALSE

))

OGR data source with driver: GeoJSON

Source: "D:\R\mapdata\State\china.geojson", layer: "china"with 34 features

It has 2 fields

用户 系统 流逝 0.77 0.00 0.76

system.time(nepal_shp

"D:/R/mapdata/State/china.geojson" ))

用户 系统 流逝 0.03 0.00 0.03

topojson

system.time(map_data

"D:/R/mapdata/china.topojson",

use_iconv=TRUE,

encoding = "utf-8",

stringsAsFactors = FALSE

))

OGR data source with driver: GeoJSON

Source: "D:\R\mapdata\china.topojson", layer: "china"with 34 features

It has 2 fields

用户 系统 流逝 0.52 0.01 0.59

system.time(geojson

"D:/R/mapdata/china.topojson",

encoding="utf-8",

use_iconv=TRUE

))

OGR data source with driver: GeoJSON

Source: "D:\R\mapdata\china.topojson", layer: "china"with 34 features

It has 2 fields

用户 系统 流逝 0.59 0.00 0.59

system.time(nepal_shp

"D:/R/mapdata/china.topojson" ))

用户 系统 流逝 0.02 0.00 0.01

是不是看完这个性能大比拼之后大吃一惊,为sf包的超强IO能力所折服,sf包是一个非常强大的包,实现了基于simple features的所有特性,如果你了解一点儿Postgis的话,你会发现作者把大部分空间运算的函数名称设计的和Postgis中的函数一模一样,这就意味着你无论是只了解过sf包函数,或者只了解过Postgis函数,都可以低成本的迁移到两一个平台,因为同名函数往往功能一致。

如果你要想将sf包导入的数据模型转换为普通的数据框模式,仅仅只需使用其提供的as(sf,’Spatial’)函数一次转化即可,当然sf有自己的ggplot2通道函数geom_sf(),这意味着你不必多此一举。(当然对于sf不甚熟悉,习惯于使用geom_polygon来实现地理信息可视化的小伙伴儿,可以采取这种办法,但是仍然要推荐大家学习sf包,因为它代表着未来)。

R语言-gis数据批量入库:

#定义读写函数:

task

#此处为写入本地gis数据(可以是任意格式,可以使用任意一种导入工具) map_data

file_name

#此处是写入数据库的函数,可以使用sf包、rgdal包以及RPostgreSQL包提供的写出函数。 writeOGR(obj = map_data ,dsn = conn,driver = "PostgreSQL",layer=file_name,encoding="gbk",overwrite_layer = TRUE)

}

#此处使用l_ply函数创建批量执行任务

Project_io

setwd(path)

input_list = list.files(path)

conn

}

#启动任务

Project_io("D:/R/mapdata/Province")

Python-gis数据批量入库:

import geopandas as gpd

import pandas as pd

from sqlalchemy import create_engine

from geoalchemy2 import Geometry,WKTElement

import numpy as np

import os

import re

import json

def dict_to_json(data):

for i in data:

if isinstance (data[i].tolist()[0],dict):

data[i] = data[i].map(lambda x:json.dumps(x))

return data

#数据写入函数:

def write_gis(path):

map_data = gpd.GeoDataFrame.from_file(path)

map_data = dict_to_json(map_data)

map_data['geometry'] = map_data['geometry'].apply(lambda x: WKTElement(x.wkt,4326))

map_data.drop(['center','parent'], axis = 1, inplace=True)

map_data.to_sql(

name = re.split('\\.',path)[0],

con = engine,

if_exists= 'replace',

dtype = {'geometry':Geometry(geometry_type ='POLYGON',srid = 4326)}

)

return None

#创建批量任务

def to_do(file_path,username,password,dbname):

os.chdir(file_path)

link = "postgresql://{0}:{1}@localhost:5432/{2}".format(username,password,dbname)

engine = create_engine(link,encoding = 'utf-8')

file_list = os.listdir()

map(lambda x: write_gis(x),file_list)

return None

#执行任务计划

if __name__ == '__main__':

file_path = 'D:/R/mapdata/Province'

username = 'postgres'

password = *****

dbname = 'mytest'

to_do(file_path,username,password,dbname)

print('DODE')

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐