জিওপান্ডাস: অন্যান্য ডেটাফ্রেমের নিকটতম বিন্দু সন্ধান করুন


20

আমার কাছে 2 টি জিওডাটা ফ্রেম রয়েছে:

import geopandas as gpd
from shapely.geometry import Point
gpd1 = gpd.GeoDataFrame([['John',1,Point(1,1)],['Smith',1,Point(2,2)],['Soap',1,Point(0,2)]],columns=['Name','ID','geometry'])
gpd2 = gpd.GeoDataFrame([['Work',Point(0,1.1)],['Shops',Point(2.5,2)],['Home',Point(1,1.1)]],columns=['Place','geometry'])

এবং আমি জিপিডি 1 তে প্রতিটি সারির জন্য জিপিডি 2-র নিকটতম বিন্দুর নাম জানতে চাই:

desired_output = 

    Name  ID     geometry  Nearest
0   John   1  POINT (1 1)     Home
1  Smith   1  POINT (2 2)    Shops
2   Soap   1  POINT (0 2)     Work

আমি ল্যাম্বদা ফাংশনটি ব্যবহার করে এই কাজটি করার চেষ্টা করছি:

gpd1['Nearest'] = gpd1.apply(lambda row: min_dist(row.geometry,gpd2)['Place'] , axis=1)

সঙ্গে

def min_dist(point, gpd2):

    geoseries = some_function()
    return geoseries

এই পদ্ধতি আমার জন্য কাজ stackoverflow.com/questions/37402046/... লিঙ্ক-এ বর্ণন
জনি Cheesecutter

উত্তর:


16

আপনি সরাসরি শ্যাপলি ফাংশন নিকটতম পয়েন্টগুলি ব্যবহার করতে পারেন (জিওসারিগুলির জ্যামিতিগুলি আকারযুক্ত জ্যামিতিগুলি):

from shapely.ops import nearest_points
# unary union of the gpd2 geomtries 
pts3 = gpd2.geometry.unary_union
def near(point, pts=pts3):
     # find the nearest point and return the corresponding Place value
     nearest = gpd2.geometry == nearest_points(point, pts)[1]
     return gpd2[nearest].Place.get_values()[0]
gpd1['Nearest'] = gpd1.apply(lambda row: near(row.geometry), axis=1)
gpd1
    Name  ID     geometry  Nearest
0   John   1  POINT (1 1)     Home
1  Smith   1  POINT (2 2)    Shops
2   Soap   1  POINT (0 2)     Work

ব্যাখ্যা

for i, row in gpd1.iterrows():
    print nearest_points(row.geometry, pts3)[0], nearest_points(row.geometry, pts3)[1]
 POINT (1 1) POINT (1 1.1)
 POINT (2 2) POINT (2.5 2)
 POINT (0 2) POINT (0 1.1)

কিছু আমার জন্য কাজ করছে না এবং আমি তা বুঝতে পারি না। জ্যামিতি শক্ত হলেও ফাংশনটি একটি খালি জিওসারিজ ফেরত দেয়। উদাহরণস্বরূপ: sample_point = gpd2.geometry.unary_union[400] / sample_point in gpd2.geometry এটি সত্য দেয়। gpd2.geometry == sample_point এটি সমস্ত মিথ্যা বেরিয়ে আসে।
রোব্রোক

উপরে সংযুক্ত: gpd2.geometry.geom_equals(sample_point)কাজ করে।
রোব্রোক

13

আপনার কাছে যদি বড় ডেটাফ্রেম থাকে তবে আমি খুঁজে পেয়েছি যে scipyএর সিকেডিট্রি স্পেসিয়াল ইনডেক্স .queryপদ্ধতিটি নিকটতম প্রতিবেশী অনুসন্ধানগুলির জন্য খুব দ্রুত ফলাফল দেয়। এটি একটি স্থানিক সূচক ব্যবহার করে যেহেতু ডেটাফ্রেম এবং তারপরে সমস্ত দূরত্বের সর্বনিম্ন সন্ধানের চেয়ে লুপিংয়ের চেয়ে দ্রুততার উচ্চতার অর্ডারগুলি। এটি nearest_pointsআরটিরির সাথে শেপলি ব্যবহারের চেয়েও দ্রুত (জিওপ্যান্ডাসের মাধ্যমে উপলভ্য স্থানিক সূচক পদ্ধতি) কারণ সি কেডিটি্রি আপনাকে আপনার সন্ধানকে ভেক্টরাইজ করার অনুমতি দেয় যেখানে অন্য পদ্ধতি না করে।

এখানে একটি সহায়ক ফাংশন যা gpd2প্রতি বিন্দু থেকে নিকটতম প্রতিবেশীর দূরত্ব এবং 'নাম' ফিরিয়ে দেবে gpd1। এটি ধরে নিয়েছে যে উভয় জিডিএফ-এর একটি geometryকলাম রয়েছে (পয়েন্টগুলির)।

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

from scipy.spatial import cKDTree
from shapely.geometry import Point

gpd1 = gpd.GeoDataFrame([['John', 1, Point(1, 1)], ['Smith', 1, Point(2, 2)],
                         ['Soap', 1, Point(0, 2)]],
                        columns=['Name', 'ID', 'geometry'])
gpd2 = gpd.GeoDataFrame([['Work', Point(0, 1.1)], ['Shops', Point(2.5, 2)],
                         ['Home', Point(1, 1.1)]],
                        columns=['Place', 'geometry'])

def ckdnearest(gdA, gdB):
    nA = np.array(list(zip(gdA.geometry.x, gdA.geometry.y)) )
    nB = np.array(list(zip(gdB.geometry.x, gdB.geometry.y)) )
    btree = cKDTree(nB)
    dist, idx = btree.query(nA, k=1)
    gdf = pd.concat(
        [gdA, gdB.loc[idx, gdB.columns != 'geometry'].reset_index(),
         pd.Series(dist, name='dist')], axis=1)
    return gdf

ckdnearest(gpd1, gpd2)

এবং যদি আপনি একটি লাইনস্ট্রিংয়ের নিকটতম বিন্দুটি সন্ধান করতে চান তবে এখানে একটি পূর্ণ কাজের উদাহরণ রয়েছে:

import itertools
from operator import itemgetter

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

from scipy.spatial import cKDTree
from shapely.geometry import Point, LineString

gpd1 = gpd.GeoDataFrame([['John', 1, Point(1, 1)],
                         ['Smith', 1, Point(2, 2)],
                         ['Soap', 1, Point(0, 2)]],
                        columns=['Name', 'ID', 'geometry'])
gpd2 = gpd.GeoDataFrame([['Work', LineString([Point(100, 0), Point(100, 1)])],
                         ['Shops', LineString([Point(101, 0), Point(101, 1), Point(102, 3)])],
                         ['Home',  LineString([Point(101, 0), Point(102, 1)])]],
                        columns=['Place', 'geometry'])


def ckdnearest(gdfA, gdfB, gdfB_cols=['Place']):
    A = np.concatenate(
        [np.array(geom.coords) for geom in gdfA.geometry.to_list()])
    B = [np.array(geom.coords) for geom in gdfB.geometry.to_list()]
    B_ix = tuple(itertools.chain.from_iterable(
        [itertools.repeat(i, x) for i, x in enumerate(list(map(len, B)))]))
    B = np.concatenate(B)
    ckd_tree = cKDTree(B)
    dist, idx = ckd_tree.query(A, k=1)
    idx = itemgetter(*idx)(B_ix)
    gdf = pd.concat(
        [gdfA, gdfB.loc[idx, gdfB_cols].reset_index(drop=True),
         pd.Series(dist, name='dist')], axis=1)
    return gdf

c = ckdnearest(gpd1, gpd2)

এই পদ্ধতিটি ব্যবহার করে লাইনেও সবচেয়ে কাছের পয়েন্টটি দেওয়া সম্ভব? উদাহরণস্বরূপ নিকটতম রাস্তায় জিপিএসের অবস্থান স্ন্যাপ করতে।
হাইপারকনট

এই উত্তর আশ্চর্যজনক! তবে নিকটবর্তী পয়েন্টের লাইনের কোডটি আমার জন্য একটি বাগ তৈরি করে। মনে হচ্ছে প্রতিটি পয়েন্টের জন্য নিকটতম লাইন থেকে সঠিক দূরত্ব ফিরে এসেছে, তবে যে রেখাটি আইডি ফিরে এসেছে তা ভুল। আমি মনে করি এটি আইডিএক্স গণনা, তবে আমি পাইথনের কাছে বেশ নতুন, তাই আমি এটির চারপাশে আমার মাথা গুটিয়ে রাখতে পারি না।
শেকডক

1

এটি নির্ধারণ:

def min_dist(point, gpd2):
    gpd2['Dist'] = gpd2.apply(lambda row:  point.distance(row.geometry),axis=1)
    geoseries = gpd2.iloc[gpd2['Dist'].argmin()]
    return geoseries

অবশ্যই কিছু সমালোচনা স্বাগত। আমি জিপিডি 1 এর প্রতিটি সারির জন্য জিপিডি 2 ['জেলা'] পুনরায় গণনার ভক্ত নই ...


1

জিনের উত্তর আমার পক্ষে কার্যকর হয়নি। অবশেষে আমি আবিষ্কার করেছি যে gpd2.geometry.unary_union এমন একটি জ্যামিতির ফলস্বরূপ যা আমার প্রায় 150.000 পয়েন্টের প্রায় 30.000 ধারণ করে। অন্য যে কেউ একই সমস্যা নিয়ে চলছে, আমি কীভাবে এটি সমাধান করেছি তা এখানে:

    from shapely.ops import nearest_points
    from shapely.geometry import MultiPoint

    gpd2_pts_list = gpd2.geometry.tolist()
    gpd2_pts = MultiPoint(gpd2_pts_list)
    def nearest(point, gpd2_pts, gpd2=gpd2, geom_col='geometry', src_col='Place'):
         # find the nearest point
         nearest_point = nearest_points(point, gpd2_pts)[1]
         # return the corresponding value of the src_col of the nearest point
         value = gpd2[gpd2[geom_col] == nearest_point][src_col].get_values()[0]
         return value

    gpd1['Nearest'] = gpd1.apply(lambda x: nearest(x.geometry, gpd2_pts), axis=1)

0

@ জেহউউ-দুর্দান্ত উত্তরটি ব্যবহার করার সময় যার যার নিজস্ব ডেটাতে ত্রুটিযুক্ত ত্রুটি রয়েছে , আমার সমস্যাটি হ'ল আমার সূচিগুলি সারিবদ্ধ হয়নি। জিডিএফএ এবং জিডিএফবি এর সূচি পুনরায় সেট করা আমার সমস্যাগুলি সমাধান করেছে, সম্ভবত এটি আপনাকে শেক্সডকেও সহায়তা করতে পারে ।

import itertools
from operator import itemgetter

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

from scipy.spatial import cKDTree
from shapely.geometry import Point, LineString

gpd1 = gpd.GeoDataFrame([['John', 1, Point(1, 1)],
                         ['Smith', 1, Point(2, 2)],
                         ['Soap', 1, Point(0, 2)]],
                        columns=['Name', 'ID', 'geometry'])
gpd2 = gpd.GeoDataFrame([['Work', LineString([Point(100, 0), Point(100, 1)])],
                         ['Shops', LineString([Point(101, 0), Point(101, 1), Point(102, 3)])],
                         ['Home',  LineString([Point(101, 0), Point(102, 1)])]],
                        columns=['Place', 'geometry'])


def ckdnearest(gdfA, gdfB, gdfB_cols=['Place']):
    # resetting the index of gdfA and gdfB here.
    gdfA = gdfA.reset_index(drop=True)
    gdfB = gdfB.reset_index(drop=True)
    A = np.concatenate(
        [np.array(geom.coords) for geom in gdfA.geometry.to_list()])
    B = [np.array(geom.coords) for geom in gdfB.geometry.to_list()]
    B_ix = tuple(itertools.chain.from_iterable(
        [itertools.repeat(i, x) for i, x in enumerate(list(map(len, B)))]))
    B = np.concatenate(B)
    ckd_tree = cKDTree(B)
    dist, idx = ckd_tree.query(A, k=1)
    idx = itemgetter(*idx)(B_ix)
    gdf = pd.concat(
        [gdfA, gdfB.loc[idx, gdfB_cols].reset_index(drop=True),
         pd.Series(dist, name='dist')], axis=1)
    return gdf

c = ckdnearest(gpd1, gpd2)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.