পান্ডায় দুটি জিওডাটাফ্রেমের সাথে নিকটতম দূরত্ব পান


14

এখানে আমার প্রথম জিওডাটফ্রেমটি রয়েছে:

!pip install geopandas
import pandas as pd
import geopandas

city1 = [{'City':"Buenos Aires","Country":"Argentina","Latitude":-34.58,"Longitude":-58.66},
           {'City':"Brasilia","Country":"Brazil","Latitude":-15.78 ,"Longitude":-70.66},
         {'City':"Santiago","Country":"Chile ","Latitude":-33.45 ,"Longitude":-70.66 }]
city2 =  [{'City':"Bogota","Country":"Colombia ","Latitude":4.60 ,"Longitude":-74.08},
           {'City':"Caracas","Country":"Venezuela","Latitude":10.48  ,"Longitude":-66.86}]
city1df = pd.DataFrame(city1)
city2df = pd.DataFrame(city2)
gcity1df = geopandas.GeoDataFrame(
    city1df, geometry=geopandas.points_from_xy(city1df.Longitude, city1df.Latitude))
gcity2df = geopandas.GeoDataFrame(
    city2df, geometry=geopandas.points_from_xy(city2df.Longitude, city2df.Latitude))

City1

           City    Country  Latitude  Longitude                     geometry
0  Buenos Aires  Argentina    -34.58     -58.66  POINT (-58.66000 -34.58000)
1      Brasilia     Brazil    -15.78     -47.91  POINT (-47.91000 -15.78000)
2      Santiago      Chile    -33.45     -70.66  POINT (-70.66000 -33.45000)

এবং আমার দ্বিতীয় জিওডাটাফ্রেমে: সিটি 2:

         City    Country  Latitude  Longitude                     geometry
1        Bogota   Colombia      4.60     -74.08    POINT (-74.08000 4.60000)
2       Caracas  Venezuela     10.48     -66.86   POINT (-66.86000 10.48000)

আমি সিটি 1 থেকে সিটি 2 পর্যন্ত দূরত্বের সাথে নিকটতম শহরটির সাথে তৃতীয় ডেটাফ্রেম চাই:

           City    Country  Latitude  Longitude                     geometry    Nearest    Distance
0  Buenos Aires  Argentina    -34.58     -58.66  POINT (-58.66000 -34.58000)    Bogota    111 Km

জিওডজ্যাঙ্গো এবং ডিক ব্যবহার করে আমার আসল সমাধানটি এখানে দেওয়া হয়েছে (তবে এটি বেশ দীর্ঘ)

from django.contrib.gis.geos import GEOSGeometry
result = []
dict_result = {}
for city01 in city1 :
  dist = 99999999
  pnt = GEOSGeometry('SRID=4326;POINT( '+str(city01["Latitude"])+' '+str(city01['Longitude'])+')')
  for city02 in city2:
    pnt2 = GEOSGeometry('SRID=4326;POINT('+str(city02['Latitude'])+' '+str(city02['Longitude'])+')')
    distance_test = pnt.distance(pnt2) * 100
    if distance_test < dist :
      dist = distance_test
  result.append(dist)
  dict_result[city01['City']] = city02['City']

আমার চেষ্টা এখানে:

from shapely.ops import nearest_points
# unary union of the gpd2 geomtries 
pts3 = gcity2df.geometry.unary_union
def Euclidean_Dist(df1, df2, cols=['x_coord','y_coord']):
    return np.linalg.norm(df1[cols].values - df2[cols].values,
                   axis=1)
def near(point, pts=pts3):
     # find the nearest point and return the corresponding Place value
     nearest = gcity2df.geometry == nearest_points(point, pts)[1]

     return gcity2df[nearest].City
gcity1df['Nearest'] = gcity1df.apply(lambda row: near(row.geometry), axis=1)
gcity1df

এখানে :

    City    Country     Latitude    Longitude   geometry    Nearest
0   Buenos Aires    Argentina   -34.58  -58.66  POINT (-58.66000 -34.58000)     Bogota
1   Brasilia    Brazil  -15.78  -70.66  POINT (-70.66000 -15.78000)     Bogota
2   Santiago    Chile   -33.45  -70.66  POINT (-70.66000 -33.45000)     Bogota

শুভেচ্ছা সহ


হ্যালো এবং স্ট্যাকওভারফ্লোতে আপনাকে স্বাগতম! আপনি মনে করছেন যে স্ট্যাকওভারফ্লো এমন একটি সাইট যেখানে আপনি কোনও সমস্যা পোস্ট করেন এবং বিনিময়ে কিছু কোড পান। এটি বাস্তবে নয়। আপনার প্রশ্নটি সম্ভবত বন্ধ হয়ে যাবে বা খুব শীঘ্রই মুছে ফেলা হবে। ভবিষ্যতে এটি যাতে না ঘটে তার জন্য, দয়া করে ট্যুরটি নিন এবং সহায়তা কেন্দ্রটি দেখুন । বিশেষত, এটিকে আশেপাশের বিষয় হিসাবে কী বিবেচনা করা হয় তা সম্পর্কে নিজেকে ফ্যামিলির করুন
২ro

এছাড়াও, আপনি যখন ডিএফ সম্পর্কে পোস্ট করেন তখন দয়া করে ডিএফ বিষয়বস্তু দিয়ে পাইথন কোডটি পোস্ট করুন, সেই সমস্ত লোকের জন্য যারা আপনাকে নিজের লেখায় সহায়তা করতে চান
আজরো

@azro আমি সমস্যার সমাধান এবং আমার প্রাথমিক ডেটা সম্পাদনা করে যুক্ত করেছি added
user462794

আপনার শহরগুলি কি কেবল দক্ষিণ আমেরিকাতেই রয়েছে? যদি তা না হয় তবে তারা একে অপরের থেকে কত দূরে থাকতে পারে? সিটি 1-এ কতগুলি শহর থাকতে পারে এবং সিটি 2-এ কতগুলি শহর থাকতে পারে? দ্রুততম সমাধানটি খুঁজে পাওয়া কি গুরুত্বপূর্ণ, বা একটি সহজ সমাধান যা যুক্তিসঙ্গত সময়ে চলে? যদি পরবর্তী ঘটনাটি ঘটে তবে যুক্তিসঙ্গত সময়টি কী হবে?
ওয়াল্টার ট্রস

@ ওয়াল্টারট্রস আমার শহর বিশ্বজুড়ে রয়েছে এবং আমি দ্রুততম সমাধানটি অনুসন্ধান করছি। ধন্যবাদ
user462794

উত্তর:


11

প্রথমত, আমি ক্রস জোড় দ্বারা দুটি ডেটা ফ্রেম একত্রিত করি। এবং তারপরে, আমি mapপাইথন ব্যবহার করে দুটি পয়েন্টের মধ্যে দূরত্ব পেয়েছি । আমি ব্যবহার map, কারণ অধিকাংশ সময় এটা অনেক দ্রুত চেয়ে apply, itertuples, iterrowsইত্যাদি (রেফারেন্স: https://stackoverflow.com/a/52674448/8205554 )

শেষ অবধি, আমি ডেটা ফ্রেম অনুসারে গ্রুপ করি এবং দূরত্বের সর্বনিম্ন মান নিয়ে আসি।

এখানে গ্রন্থাগার রয়েছে,

import pandas as pd
import geopandas
import geopy.distance
from math import radians, cos, sin, asin, sqrt

এখানে ব্যবহৃত ফাংশন,

def dist1(p1, p2):
    lon1, lat1, lon2, lat2 = map(radians, [p1.x, p1.y, p2.x, p2.y])

    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    c = 2 * asin(sqrt(a)) 

    return c * 6373

def dist2(p1, p2):
    lon1, lat1, lon2, lat2 = map(radians, [p1[0], p1[1], p2[0], p2[1]])

    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    c = 2 * asin(sqrt(a)) 

    return c * 6373

def dist3(p1, p2):
    x = p1.y, p1.x
    y = p2.y, p2.x

    return geopy.distance.geodesic(x, y).km

def dist4(p1, p2):
    x = p1[1], p1[0]
    y = p2[1], p2[0]

    return geopy.distance.geodesic(x, y).km

এবং তথ্য,

city1 = [
  {
    'City': 'Buenos Aires',
    'Country': 'Argentina',
    'Latitude': -34.58,
    'Longitude': -58.66
  },
  {
    'City': 'Brasilia',
    'Country': 'Brazil',
    'Latitude': -15.78,
    'Longitude': -70.66
  },
  {
    'City': 'Santiago',
    'Country': 'Chile ',
    'Latitude': -33.45,
    'Longitude': -70.66
  }
]

city2 = [
  {
    'City': 'Bogota',
    'Country': 'Colombia ',
    'Latitude': 4.6,
    'Longitude': -74.08
  },
  {
    'City': 'Caracas',
    'Country': 'Venezuela',
    'Latitude': 10.48,
    'Longitude': -66.86
  }
]


city1df = pd.DataFrame(city1)
city2df = pd.DataFrame(city2)

geopandasডেটা ফ্রেমের সাথে ক্রস জয়েন ,

gcity1df = geopandas.GeoDataFrame(
    city1df, 
    geometry=geopandas.points_from_xy(city1df.Longitude, city1df.Latitude)
)
gcity2df = geopandas.GeoDataFrame(
    city2df, 
    geometry=geopandas.points_from_xy(city2df.Longitude, city2df.Latitude)
)

# cross join geopandas
gcity1df['key'] = 1
gcity2df['key'] = 1
merged = gcity1df.merge(gcity2df, on='key')

mathফাংশন এবং geopandas,

# 6.64 ms ± 588 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit

# find distance
merged['dist'] = list(map(dist1, merged['geometry_x'], merged['geometry_y']))

mapping = {
    'City_x': 'City',
    'Country_x': 'Country',
    'Latitude_x': 'Latitude',
    'Longitude_x': 'Longitude',
    'geometry_x': 'geometry',
    'City_y': 'Nearest',
    'dist': 'Distance'
}

nearest = merged.loc[merged.groupby(['City_x', 'Country_x'])['dist'].idxmin()]
nearest.rename(columns=mapping)[list(mapping.values())]

           City    Country  Latitude  Longitude                     geometry  \
2      Brasilia     Brazil    -15.78     -70.66  POINT (-70.66000 -15.78000)   
0  Buenos Aires  Argentina    -34.58     -58.66  POINT (-58.66000 -34.58000)   
4      Santiago     Chile     -33.45     -70.66  POINT (-70.66000 -33.45000)   

  Nearest     Distance  
2  Bogota  2297.922808  
0  Bogota  4648.004515  
4  Bogota  4247.586882 

geopyএবং geopandas,

# 9.99 ms ± 764 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit

# find distance
merged['dist'] = list(map(dist3, merged['geometry_x'], merged['geometry_y']))

mapping = {
    'City_x': 'City',
    'Country_x': 'Country',
    'Latitude_x': 'Latitude',
    'Longitude_x': 'Longitude',
    'geometry_x': 'geometry',
    'City_y': 'Nearest',
    'dist': 'Distance'
}

nearest = merged.loc[merged.groupby(['City_x', 'Country_x'])['dist'].idxmin()]
nearest.rename(columns=mapping)[list(mapping.values())]

           City    Country  Latitude  Longitude                     geometry  \
2      Brasilia     Brazil    -15.78     -70.66  POINT (-70.66000 -15.78000)   
0  Buenos Aires  Argentina    -34.58     -58.66  POINT (-58.66000 -34.58000)   
4      Santiago     Chile     -33.45     -70.66  POINT (-70.66000 -33.45000)   

  Nearest     Distance  
2  Bogota  2285.239605  
0  Bogota  4628.641817  
4  Bogota  4226.710978 

আপনি যদি এর pandasপরিবর্তে ব্যবহার করতে চান geopandas,

# cross join pandas
city1df['key'] = 1
city2df['key'] = 1
merged = city1df.merge(city2df, on='key')

সঙ্গে mathফাংশন,

# 8.65 ms ± 2.21 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit

# find distance
merged['dist'] = list(
    map(
        dist2, 
        merged[['Longitude_x', 'Latitude_x']].values, 
        merged[['Longitude_y', 'Latitude_y']].values
    )
)

mapping = {
    'City_x': 'City',
    'Country_x': 'Country',
    'Latitude_x': 'Latitude',
    'Longitude_x': 'Longitude',
    'City_y': 'Nearest',
    'dist': 'Distance'
}

nearest = merged.loc[merged.groupby(['City_x', 'Country_x'])['dist'].idxmin()]
nearest.rename(columns=mapping)[list(mapping.values())]

           City    Country  Latitude  Longitude Nearest     Distance
2      Brasilia     Brazil    -15.78     -70.66  Bogota  2297.922808
0  Buenos Aires  Argentina    -34.58     -58.66  Bogota  4648.004515
4      Santiago     Chile     -33.45     -70.66  Bogota  4247.586882

সাথে geopy,

# 9.8 ms ± 807 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit

# find distance
merged['dist'] = list(
    map(
        dist4, 
        merged[['Longitude_x', 'Latitude_x']].values, 
        merged[['Longitude_y', 'Latitude_y']].values
    )
)

mapping = {
    'City_x': 'City',
    'Country_x': 'Country',
    'Latitude_x': 'Latitude',
    'Longitude_x': 'Longitude',
    'City_y': 'Nearest',
    'dist': 'Distance'
}

nearest = merged.loc[merged.groupby(['City_x', 'Country_x'])['dist'].idxmin()]
nearest.rename(columns=mapping)[list(mapping.values())]

           City    Country  Latitude  Longitude Nearest     Distance
2      Brasilia     Brazil    -15.78     -70.66  Bogota  2285.239605
0  Buenos Aires  Argentina    -34.58     -58.66  Bogota  4628.641817
4      Santiago     Chile     -33.45     -70.66  Bogota  4226.710978

এই দূরত্বগুলি একটি আনুমানিক সূত্র দিয়ে গণনা করা হয় যা আর্থস ফ্ল্যাটিংয়ের জন্য অ্যাকাউন্ট করে না। geopy.distance.distance()একই 3 টি দূরত্ব ব্যবহার করে (বৃত্তাকার) 2285, 4629এবং 4227কিমি।
ওয়াল্টার ট্রস

আমি এই মানগুলি লিঙ্কটি দিয়ে দেখছি: দূরত্ব .৩/ ৩৩.৪5,-- ০.6/ / .6. ,,- 74.0.০৮ দোষ কি?
ই জেইটিনসি

আমি আরও বিশ্বাস করি এই বিষয়টি বাদে geopy, একটি ওয়েবসাইট হিসাবে আমি আরও বেশি বিশ্বাস করি edwilliams.org/gccalc.htm , যা এর সাথে একমতgeopy । এনওএএ-এর ওয়েবসাইট, nhc.noaa.gov/gccalc.shtml , এটি পূর্বের উপর ভিত্তি করে তৈরি হয়েছে তবে এর পরে বিভিন্ন ফলাফল পাওয়া যায়। এটি সম্ভবত পূর্ববর্তী একটি পুরানো সংস্করণ উপর ভিত্তি করে।
ওয়াল্টার ট্রস

5

আমি মনে করি যে ও (ম · এন) এর চেয়ে ভাল সময় জটিলতার সাথে সমাধান খুঁজে পাওয়া বেশ কঠিন , যেখানে এম এবং এন এর আকার এবং । দূরত্বের তুলনা (একমাত্র O (m · n) অপারেশনটিকে সহজ রাখার জন্য এবং ন্যম্পি এবং পান্ডার দ্বারা সরবরাহিত ভেক্টরাইজড অপারেশনের সুবিধা গ্রহণ করা, গতি কোনও যুক্তিসঙ্গত ইনপুট আকারের জন্য সমস্যা হওয়া উচিত নয়।city1city2

ধারণাটি হ'ল, একটি গোলকের মধ্যে দূরত্বের তুলনা করতে, আপনি 3 ডি-র মধ্যে পয়েন্টগুলির মধ্যে দূরত্বগুলি তুলনা করতে পারেন। নিকটতম শহরটি গোলকের পাশ দিয়ে যাওয়ার সবচেয়ে কাছের শহরটিও । তদুপরি, আপনি সাধারণত দূরত্ব গণনা করতে বর্গাকার শিকড় নেন তবে আপনার যদি কেবল তাদের তুলনা করা দরকার তবে আপনি বর্গমূলগুলি এড়াতে পারবেন।

from geopy.distance import distance as dist
import numpy as np
import pandas as pd

def find_closest(lat1, lng1, lat2, lng2):
    def x_y_z_of_lat_lng_on_unit_sphere(lat, lng):
        rad_lat, rad_lng = np.radians(lat), np.radians(lng)
        sin_lat, sin_lng = np.sin(rad_lat), np.sin(rad_lng)
        cos_lat, cos_lng = np.cos(rad_lat), np.cos(rad_lng)
        return cos_lat * cos_lng, cos_lat * sin_lng, sin_lat
    x1, y1, z1 = x_y_z_of_lat_lng_on_unit_sphere(lat1, lng1)
    x2, y2, z2 = x_y_z_of_lat_lng_on_unit_sphere(lat2, lng2)
    return pd.Series(map(lambda x, y, z:
                         ((x2-x)**2 + (y2-y)**2 + (z2-z)**2).idxmin(),
                         x1, y1, z1))

city1 = [{"City":"Tokyo",    "Ctry":"JP", "Latitude": 35.68972, "Longitude": 139.69222},
         {"City":"Pretoria", "Ctry":"ZA", "Latitude":-25.71667, "Longitude": 28.28333},
         {"City":"London",   "Ctry":"GB", "Latitude": 51.50722, "Longitude": -0.12574}]
city2 = [{"City":"Seattle",  "Ctry":"US", "Latitude": 47.60972, "Longitude":-122.33306},
         {"City":"Auckland", "Ctry":"NZ", "Latitude":-36.84446, "Longitude": 174.76364}]
city1df = pd.DataFrame(city1)
city2df = pd.DataFrame(city2)

closest = find_closest(city1df.Latitude, city1df.Longitude, city2df.Latitude, city2df.Longitude)

resultdf = city1df.join(city2df, on=closest, rsuffix='2')
km = pd.Series(map(lambda latlng1, latlng2: round(dist(latlng1, latlng2).km),
                   resultdf[['Latitude',  'Longitude' ]].to_numpy(),
                   resultdf[['Latitude2', 'Longitude2']].to_numpy()))
resultdf['Distance'] = km
print(resultdf.to_string())
#        City Ctry  Latitude  Longitude     City2 Ctry2  Latitude2  Longitude2  Distance
# 0     Tokyo   JP  35.68972  139.69222   Seattle    US   47.60972  -122.33306      7715
# 1  Pretoria   ZA -25.71667   28.28333  Auckland    NZ  -36.84446   174.76364     12245
# 2    London   GB  51.50722   -0.12574   Seattle    US   47.60972  -122.33306      7723

দ্রষ্টব্য এবং দ্রাঘিমাংশকে ব্যবহার করে কার্টেসিয়ান স্থানাঙ্ক হিসাবে ব্যবহার করা কোনও সমাধান ভুল, কারণ মেরুদের (সমান দ্রাঘিমাংশের রেখাগুলি) মেরুগুলির দিকে অগ্রসর হওয়া একে অপরের কাছাকাছি পৌঁছায়।


3

এই সমাধানটি সম্ভবত আপনার সমস্যা সমাধানের দ্রুততম উপায় নয় তবে আমি বিশ্বাস করি এটি কৌশলটি কার্যকর করবে।

#New dataframe is basicly a copy of first but with more columns
gcity3df = gcity1df.copy()
gcity3df["Nearest"] = None
gcity3df["Distance"] = None

#For each city (row in gcity3df) we will calculate the nearest city from gcity2df and 
fill the Nones with results

for index, row in gcity3df.iterrows():
    #Setting neareast and distance to None, 
    #we will be filling those variables with results

    nearest = None
    distance = None
    for df2index, df2row in gcity2df.iterrows():
        d = row.geometry.distance(df2row.geometry)
        #If df2index city is closer than previous ones, replace nearest with it
        if distance is None or d < distance:
            distance = d
            nearest = df2row.City 
    #In the end we appends the closest city to gdf
    gcity3df.at[index, "Nearest"] = nearest
    gcity3df.at[index, "Distance"] = distance

আপনার যদি ডিগ্রি না দিয়ে মিটারে কাজ করার দরকার হয় তবে আপনি সর্বদা আপনার স্তরটিকে পুনরায় প্রজেক্ট করতে পারেন (এটি ওয়াল্টার যে শব্দটি বোঝাচ্ছেন সেটিও মুছে ফেলবে)। gcity3df = gcity3df.to_crs({'init': 'epsg:XXXX'})আপনার বিশ্বের অঞ্চলে ব্যবহার করা হচ্ছে এমন সিআরএক্সএক্সএক্সজিএসএক্স XXXX এর মাধ্যমে আপনি এটি করতে পারেন by

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