2015-06-09 16 views
5

Tôi đang tìm cách làm tương đương với ArcPy Generate Near Table sử dụng Geopandas/Shapely. Tôi rất mới với Geopandas và Shapely và đã phát triển một phương pháp làm việc, nhưng tôi tự hỏi nếu có một cách hiệu quả hơn để làm điều đó.Tính khoảng cách đến tính năng gần nhất với Geopandas

Tôi có hai tập dữ liệu tập tin điểm - Khối điều tra dân số Centroids và nhà hàng. Tôi đang tìm kiếm, cho mỗi trung tâm Khối điều tra dân số, khoảng cách đến nhà hàng gần nhất của nó. Không có giới hạn nào đối với cùng một nhà hàng là nhà hàng gần nhất cho nhiều nhà hàng.

Lý do điều này trở nên phức tạp hơn một chút đối với tôi là vì việc tính toán theo nguyên tắc, kết hợp dựa trên chỉ mục theo số liệu Geopandas Distance function. Vì vậy, phương pháp chung của tôi là biến tệp Nhà hàng thành tệp đa điểm và sau đó đặt chỉ mục của tệp khối thành tất cả có cùng giá trị. Sau đó, tất cả các khối centroids và các nhà hàng có cùng một giá trị chỉ số.

import pandas as pd 
import geopandas as gpd 
from shapely.geometry import Polygon, Point, MultiPoint 

Bây giờ đọc trong tập tin hình dạng khối trọng tâm và nhà hàng:

Blocks=gpd.read_file(BlockShp) 
Restaurants=gpd.read_file(RestaurantShp) 

Kể từ khi chức năng khoảng cách Geopandas tính toán khoảng cách elementwise, tôi chuyển đổi GeoSeries Restaurant để một GeoSeries MultiPoint:

RestMulti=gpd.GeoSeries(Restaurants.unary_union) 
RestMulti.crs=Restaurants.crs 
RestMulti.reset_index(drop=True) 

Sau đó, tôi thiết lập chỉ mục cho các khối bằng 0 (giá trị tương tự như đa điểm nhà hàng) như một công việc xung quanh để tính toán theo nguyên tố.

Blocks.index=[0]*len(Blocks) 

Cuối cùng, tôi sử dụng chức năng khoảng cách Geopandas để tính khoảng cách đến nhà hàng gần nhất cho mỗi khối centroid.

Blocks['Distance']=Blocks.distance(RestMulti) 

Vui lòng cung cấp bất kỳ đề xuất nào về cách cải thiện điều này. Tôi không bị ràng buộc bởi việc sử dụng Geopandas hay Shapely, nhưng tôi đang tìm cách để tìm hiểu một giải pháp thay thế cho ArcPy.

Cảm ơn sự giúp đỡ!

+0

xác định hàng xóm gần nhất là một nhiệm vụ khá thẳng về phía trước chỉ riêng NumPy. xem phần cuối của bản trình bày này (https://speakerdeck.com/jakevdp/losing-your-loops-fast-numerical-computing-with-numpy-pycon-2015) cho một giải pháp tinh khiết-gumpy được kiểm tra chống lại một hàm scikit-learn . –

+0

Bạn sẽ có thể lặp lại các khối của bạn và sau đó chỉ cần tính toán khoảng cách cho tất cả các nhà hàng cho khối cụ thể đó (sử dụng chức năng geopandas cài sẵn). Chọn mức tối thiểu và bạn đã đặt? Để được trợ giúp thêm, có thể đăng nơi shapefiles nguồn có thể được tìm thấy? – shongololo

Trả lời

6

Nếu tôi hiểu chính xác vấn đề của bạn, Chặn và Nhà hàng có thể có các thứ nguyên rất khác nhau. Vì lý do này, nó có thể là một cách tiếp cận xấu để cố gắng ép buộc vào một định dạng bảng bằng cách tái lập lại.

Tôi sẽ chỉ lặp lại các khối và nhận khoảng cách tối thiểu đến các nhà hàng (giống như @shongololo đã đề xuất).

Tôi sẽ hơi tổng quát hơn một chút (vì tôi đã có mã này viết xuống) và thực hiện một khoảng cách từ điểm này đến điểm khác, nhưng cùng một mã sẽ hoạt động từ điểm đến điểm hoặc từ đa giác sang đa giác. Tôi sẽ bắt đầu với một số GeoDataFrame cho các điểm và tôi sẽ tạo một cột mới có khoảng cách tối thiểu đến các dòng.

%matplotlib inline 
import matplotlib.pyplot as plt 
import shapely.geometry as geom 
import numpy as np 
import pandas as pd 
import geopandas as gpd 

lines = gpd.GeoSeries(
    [geom.LineString(((1.4, 3), (0, 0))), 
     geom.LineString(((1.1, 2.), (0.1, 0.4))), 
     geom.LineString(((-0.1, 3.), (1, 2.)))]) 

# 10 points 
n = 10 
points = gpd.GeoSeries([geom.Point(x, y) for x, y in np.random.uniform(0, 3, (n, 2))]) 

# Put the points in a dataframe, with some other random column 
df_points = gpd.GeoDataFrame(np.array([points, np.random.randn(n)]).T) 
df_points.columns = ['Geometry', 'Property1'] 

points.plot() 
lines.plot() 

enter image description here

Bây giờ có được khoảng cách từ điểm đến đường dây và chỉ tiết kiệm khoảng cách tối thiểu cho mỗi điểm (xem dưới đây để biết một phiên bản với áp dụng)

min_dist = np.empty(n) 
for i, point in enumerate(points): 
    min_dist[i] = np.min([point.distance(line) for line in lines]) 
df_points['min_dist_to_lines'] = min_dist 
df_points.head(3) 

mang đến cho

Geometry          Property1 min_dist_to_lines 
0 POINT (0.2479424516236574 2.944916965334865) 2.621823 0.193293 
1 POINT (1.465768457667432 2.605673714922998)  0.6074484 0.226353 
2 POINT (2.831645235202689 1.125073838462032)  0.657191 1.940127 

---- CHỈNH SỬA ----

(lấy từ một vấn đề github) Sử dụng apply là đẹp hơn và phù hợp hơn với cách bạn muốn làm điều đó trong pandas:

def min_distance(point, lines): 
    return lines.distance(point).min() 

df_points['min_dist_to_lines'] = df_points.geometry.apply(min_distance, df_lines) 
Các vấn đề liên quan