2017-12-27 25 views
2

シェイプファイルオブジェクトから作成されたGeoPandas Dataframeがあります。 しかし、証明書の行は同じ名前ですが、非常に異なる場所にあります。名前に基づく分割線

各行に固有の名前が必要です。 したがって、幾何学的に離れていて名前を変更すると、何とか線を分割する必要があります。

すべてのストリートチャンク間の距離を計算し、それらが近くにある場合、それらを再グループ化することができます。

距離の計算は容易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

1つの可能な方法は、各データ点の空間的クラスタリングを使用することです。次のコードでは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") 

DFの各行には、ポイントの数です。クラスタを取得するには、すべてを取得したい:

ids = [] 
coords = [] 

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

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

計算後にクラスターをdfに戻すには、ここにidsが必要です。ここで は(我々はまた、データの正規化は、より良い品質を得るために作る)各点のクラスタを取得されています

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

次の部分は少し厄介ですが、我々は、IDごとに1つだけのクラスターを得ることを確認します。私たちは、各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(。このパラメータを指定して再生することができます - 1つのクラスタにそれらを得るために点間の最大距離であるEPS、あなたが得るlesssクラスターより)と、このデータについては

df["cluster"] = df["id"].map(id_to_cluster) 

、私たちはこの絵のようなものがあります。

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)を取得し、ソースデータフレームに、我々は170行を有し、各行別のLINESTRINGオブジェクトです。各ラインストリングは2次元の点で構成され、点の数はラインストリング間で異なります。だからまず、すべてのポイント(コード内の "coords"リスト)を取得し、各ポイントのクラスターを予測します。 1つのLINESTRINGのポイントで異なるクラスターを表示する可能性はわずかです。この状況を解決するために、各クラスタの数を取得し、最大値をフィルタリングします。

+0

@james、df ["STREET"] = df ["name"] + "_" + df ["cluster"]。まもなく答えに説明を入れてください。 –

+0

@james、iveが投稿を更新しました。また、eps = 1.5のデータをはるかに良く分離しています。 –

+0

@james id_to_cluster = points_clusters [max_inds] .drop_duplicates()。set_index( "id")["cluster"]:この行にdrop_duplicatesにsubset = "id"を追加してください。これは、2つのクラスタの最大数が同じである場合に発生する可能性があります –

関連する問題