iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 3
3
AI & Data

30天精通GIS資料分析-使用Python系列 第 3

Day03 從Pandas到Geopandas的幾種方法

  • 分享至 

  • xImage
  •  

Geopandas可以讀取各GIS格式進行空間運算,然而實際上我們可能拿到的資料不見得是GIS的格式

雖然不是GIS格式,但它有可能是有坐標資訊的資料

這樣的資料可能會是一個csv或Excel,資料中含有經緯度或xy
對於這樣的資料,我們可以把它先轉為GeopandasGeoDataFrame
以方便空間的運算

大綱

  • 用Pandas讀取csv或Excel
  • DataFrame轉為Geodataframe
  • Geocoding

用Pandas讀取csv或Excel

為了今天的範例,請先下載[新北市路燈資料]的csv檔,解壓縮後將之命名為Light.csv

拿到資料的第一步先使用Pandas讀取這個csv為DataFrame

import pandas as pd 
df=pd.read_csv('data/Light/Light.csv',encoding='utf-8')

ps.如果沒有pandas請先安裝

conda install pandas

首先,瀏覽一下這份資料
可以看到這份資料具有TWD97X, TWD97Y坐標欄位,
很明顯的,我們可以把它轉為點資料
接下來,我們試著把X,Y轉換成GeoDataFrame

DataFrame轉為Geodataframe

前一天提到GeoDataFrame包含geometry的屬性,
因此,要產生GeoDataFrame,需要產生geometry
這時候需要用shapely套件中的geometry
我們使用之中的Point類型,並把TWD97X, TWD97Y包進去,命名為geom

from shapely.geometry import Point
import geopandas as gpd
geom = [Point(xy) for xy in zip(df.TWD97X, df.TWD97Y)]

有了geom,我們可以用來產生GeoDataFrame
其中,需要指定crs,也就是坐標系統
由於TWD97X, TWD97Y的坐標是TWD97,為epsg:3826

[Day10] 坐標系統及WebGIS常用的坐標轉換

crs = {'init': 'epsg:3826'}
gdf = gpd.GeoDataFrame(df, crs=crs, geometry=geom)
gdf

就這樣,透過幾個步驟,我們成功把csv轉成了GeoDataFrame,
然後我們就可以做GeoDataFrame能做的事

例如我們可以把它會在圖上:
將永和區的資料畫圖來,並以address為color code繪圖,

gdf[gdf['district']=='永和區'].plot(column='address')

Geocoding

像是今天的資料集[新北市路燈資料]是一份具有XY的點資料,
如果今天資料中沒有XY,我們還是可以透過一些Geocoding方法取得坐標
在去年的文章[Day 9] 自己產製資料-地址定位part2中,
提到可以使用TGOS來進行門牌地址的Geocoding。

然而TGOS一般的服務必須先將資料匯出,今天為了一次性的完成資料加工,
Geocoding會以TomTom Developer Portal Geocode提供的服務為例(個人經驗,這個服務的Geocoding會有較好的成果)

首先,必須要取得一個api key,每個key每天都有一些免費的request數量,
取得api key請自行前往該服務申請User account | TomTom Developer Portal

假設已經順利取得api的key,我們就以新北市各圖書館地址電話表為範例來做Geocoding,

一樣,下載csv格式,
先以Pandas讀取csv

import pandas as pd 
df=pd.read_csv('data/Library/Library.csv',encoding='utf-8')
df

接著我們寫一個函式取名為rest處理Geocoding,
api呼叫的方法及回應的格式直接參考TomTom Developer Portal Geocode的說明

以下程式碼範例中,YOUR_KEY必須填入你的api key!

import requests,json
def rest(address):

    url = 'https://api.tomtom.com/search/2/geocode/{}.json?&key=YOUR_KEY&countrySet=TWN&language=zh-TW&limit=1'.format(
        address)
    response = requests.get(url)
    data = response.text
    js = json.loads(str(data))
    return js['results'][0]['position']

ps. requests需要安裝,

conda install requests

然後,我們使用rest函式,透過其傳回來的x,y產生點資料的geometry(命名為geom)

# 這邊使用df.head()測試避免一天request太多
geom=[Point(rest(row.address)) for idx, row in df.head().iterrows()]

有了geom就可以產生GeoDataFrame了,
要注意的是,這邊的坐標是WGS84,也就是epsg:4326

crs = {'init': 'epsg:4326'}
gdf = gpd.GeoDataFrame(df.head(), crs=crs, geometry=geom)
gdf

看看成果吧

GeoDataFrame也可以輸出成GIS格式,匯出在其他平台檢視與處理,包含常用的shp或是geojson

gdf.to_file(driver = 'ESRI Shapefile', filename = 'output/Light.shp')

今天的相關測試可以參考GitHub

本文同步發表於個人部落格


上一篇
Day02 Geopandas初探
下一篇
Day04 幾何資料基本運算
系列文
30天精通GIS資料分析-使用Python30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
osmunt
iT邦新手 4 級 ‧ 2021-10-15 15:10:58

大大您好,我在跟著大大文章練習的時候

import requests,json
def rest(address):

    url = 'https://api.tomtom.com/search/2/geocode/{}.json?&key=YOUR_KEY&countrySet=TWN&language=zh-TW&limit=1'.format(
        address)
    response = requests.get(url)
    data = response.text
    js = json.loads(str(data))
    return js['results'][0]['position']
    
# 這邊使用df.head()測試避免一天request太多
geom=[Point(rest(row.address)) for idx, row in df.head().iterrows()]

這段出現了error:0
於是去查看了一下,發現是Point出錯
因為rest回傳的資料好像不符合Point所需要的
所以我將程式碼改成這樣

import requests,json
def rest(address):

    url = 'https://api.tomtom.com/search/2/geocode/{}.json?&key=YOUR_KEY&countrySet=TWN&language=zh-TW&limit=1'.format(
        address)
    response = requests.get(url)
    data = response.text
    js = json.loads(str(data))
    # 改成以下這段
    dic_lat = js['results'][0]['position']['lat']
    dic_lon = js['results'][0]['position']['lon']
    dic_tuple = (dic_lon,dic_lat)
    return dic_tuple

後面就可以了
可能是小弟本身哪裡有做錯,
也有可能是資料、版本有更新,
所導致這個問題出來
小弟目前是新手,哪裡有做不好的,還請大大多多指教

我要留言

立即登入留言