2017-12-27 4 views
2

셰이프 파일 개체에서 생성 된 GeoPandas Dataframe이 있습니다. 그러나 certian 라인은 같은 이름이지만 매우 다른 장소에 있습니다.이름을 기준으로 한 분할 선

각 줄마다 고유 한 이름을 지정하고 싶습니다. 따라서 기하학적으로 구별되고 이름을 바꾸면 어떻게 든 선을 분할해야합니다.

모든 거리 청크 사이의 거리를 계산하고 인접한 경우 다시 그룹화하려고 시도 할 수 있습니다.

의 거리의 계산을 용이 Geopandas에서 수행 될 수있다 : 라인 Distance Between Linestring Geopandas

세트 시도 :

from shapely.geometry import Point, LineString 
import geopandas as gpd 


line1 = LineString([ 
    Point(0, 0), 
    Point(0, 1), 
    Point(1, 1), 
    Point(1, 2), 
    Point(3, 3), 
    Point(5, 6), 
]) 

line2 = LineString([ 
    Point(5, 3), 
    Point(5, 5), 
    Point(9, 5), 
    Point(10, 7), 
    Point(11, 8), 
    Point(12, 12), 
]) 

line3 = LineString([ 
    Point(9, 10), 
    Point(10, 14), 
    Point(11, 12), 
    Point(12, 15), 
]) 

df = gpd.GeoDataFrame(
    data={'name': ['A', 'A', 'A']}, 
    geometry=[line1, line2, line3] 
) 
+0

좌표에 대한 sklearn의 dbscan 클러스터링은 옵션입니다. http://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html. 데이터 사용 예제 : http://scikit-learn.org/stable/auto_examples/cluster/plot_dbscan.html#sphx-glr-auto-examples-cluster-plot-dbscan-py –

+0

필요한 모든 파일을 공유하십시오. shp 파일 만 데이터를로드하기에 충분하지 않습니다. 세부 정보 : https://gis.stackexchange.com/questions/262505/python-cant-read-shapefile/262509 –

+0

네, 이제 데이터를로드하는 것이 좋습니다. 불량 클러스터링 접근법. –

답변

2

하나의 가능한 방법은 각각의 데이터 포인트의 공간 클러스터링을 사용하는 것이다. 다음 코드는 DBSCAN을 사용하지만 다른 유형이 더 적합 할 수 있습니다. http://scikit-learn.org/stable/modules/clustering.html

from matplotlib import pyplot as plt 
from sklearn.cluster import DBSCAN 
from sklearn.preprocessing import StandardScaler 

import numpy as np 
import pandas as pd 
import geopandas as gpd 

df = gpd.GeoDataFrame.from_file("stackex_dataset.shp") 

안양의 각 라인이 포인트의 숫자입니다 : 여기에 작동 방법의 개요이다. 우리는 클러스터를 얻기 위해 그들 모두를 얻으려면 :

ids = [] 
coords = [] 

for row in df.itertuples(): 
    geom = np.asarray(row.geometry) 

    coords.extend(geom) 
    ids.extend([row.id] * geom.shape[0]) 

우리는 계산 한 후 df 명령으로 다시 클러스터를 얻기 위해 여기에 ID를해야합니다. 여기 각 포인트에 대한 클러스터를 획득한다 (우리는 또한 더 나은 품질을 얻을 수있는 데이터 정상화하기) :

clust = DBSCAN(eps=0.5) 
clusters = clust.fit_predict(StandardScaler().fit_transform(coords)) 

다음 부분은 좀 지저분입니다하지만 우리는 우리가 ID 당 하나 개의 클러스터를 얻을 수 있는지 확인하려면. 각 이드에 대해 가장 빈번한 포인트 클러스터를 선택합니다.

points_clusters = pd.DataFrame({"id":ids, "cluster":clusters}) 
points_clusters["count"] = points_clusters.groupby(["id", "cluster"])["id"].transform('size') 

max_inds = points_clusters.groupby(["id", "cluster"])['count'].transform(max) == points_clusters['count'] 
id_to_cluster = points_clusters[max_inds].drop_duplicates(subset ="id").set_index("id")["cluster"] 

그런 다음이 번호의 도움으로 거리를 열거 할 수 있도록 클러스터 번호를 다시 데이터 프레임으로 가져옵니다.

DBSCAN 및 EPS = 0.5이 데이터를 들면
df["cluster"] = df["id"].map(id_to_cluster) 

은 (이 매개 변수를 사용하여 재생할 수 있습니다 - 하나 개의 클러스터에서 그들을 얻을 수있는 점 사이의 최대 거리 인 더 EPS 당신이 얻을의 lesss가 클러스터를.) 우리는이 그림의 종류가 있습니다

plt.scatter(np.array(coords)[:, 0], np.array(coords)[:, 1], c=clusters, cmap="autumn") 
plt.show() 

enter image description here

그리고 별도 거리의 수 8 개의 위치 :

print(len(df["cluster"].drop_duplicates())) 
,

낮은 eps를 만들면 코드의 지저분한 부분에 대해

enter image description here

: clust = DBSCAN (EPS는 = 0.15) 우리는 더 나은 데이터를 분리 클러스터 (이 시점에서 12)를 얻을 소스 DataFrame 우리가 170 ​​개 행이 각 행 별도의 LINESTRING 개체입니다. 각 라인 스팅은 2d 포인트로 구성되며, 포인트 수는 라인 스 트링간에 다릅니다. 먼저 모든 점 (코드의 "coords"목록)을 얻고 각 점의 클러스터를 예측합니다. 하나의 LINESTRING 포인트에서 다른 클러스터를 제공 할 가능성은 거의 없습니다.이 상황을 해결하기 위해 각 클러스터를 계산 한 다음 최대 값을 필터링합니다.

+0

거리 이름을 얻으려면 @james, df [ "STREET"] = df [ "name"] + "_"+ df [ "cluster"]. 곧 대답을 설명해주십시오. –

+0

@james, ive 님이 포스트를 업데이트했습니다. 또한 eps = 1.5 데이터를 훨씬 잘 분리합니다. –

+0

@james drop_duplicates에 다음 줄에 subset = "id"를 추가하십시오 : id_to_cluster = points_clusters [max_inds] .drop_duplicates(). set_index ("id") [ "cluster"]. 최대 2 개의 클러스터가있을 때 발생할 수 있습니다. –

관련 문제