ফাস্ট হাভারসাইন অ্যাপ্রোজেসিমেশন (পাইথন/পান্ডাস)

একটি প্যান্ডাস ডেটাফ্রেমে প্রতিটি সারি 2 পয়েন্টের ল্যাট/এলএনজি সমন্বয় রয়েছে। নীচের পাইথন কোডটি ব্যবহার করে, অনেকগুলি (লক্ষ লক্ষ) সারির জন্য এই 2 পয়েন্টগুলির মধ্যে দূরত্বগুলি গণনা করা খুব বেশি সময় নেয়!

মনে রাখবেন যে 2 পয়েন্ট 50 মাইল ব্যবধানে কম এবং সঠিকতা খুব গুরুত্বপূর্ণ নয়, এটি গণনা দ্রুত করা সম্ভব?

from math import radians, cos, sin, asin, sqrt
def haversine(lon1, lat1, lon2, lat2):
    """
    Calculate the great circle distance between two points 
    on the earth (specified in decimal degrees)
    """
    # convert decimal degrees to radians 
    lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
    # haversine formula 
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    c = 2 * asin(sqrt(a)) 
    km = 6367 * c
    return km


for index, row in df.iterrows():
    df.loc[index, 'distance'] = haversine(row['a_longitude'], row['a_latitude'], row['b_longitude'], row['b_latitude'])
19
বাহু মন্তব্যের বাইরে আমার পরামর্শ! আমি ভাবছিলাম যে আমি শুধু sqrt ((lat2 - lat1) ^^ 2 + (lon2 - lon1) ^^ 2) কাজ করবো কিনা? সব পয়েন্ট নিউ ইয়র্ক শহরের মধ্যে থাকা।
যোগ লেখক Nyxynyx, উৎস
@ballsdotballs মনে হচ্ছে ইউক্লিডান দূরত্ব আমার জন্য কাজ করবে! কিভাবে sqrt এর ফলাফল হওয়া উচিত ((lat2 - lat1) ^^ 2 + (lon2 - lon1) ^^ 2) মাইলে রূপান্তরিত হবে?
যোগ লেখক Nyxynyx, উৎস
আনুমানিকতা তুলনায় একটি ভাল পদ্ধতি ফাংশনটি প্রোফাইলটি প্রোফাইলটি প্রোফাইলটিকে প্রোফাইলের আকারে রূপান্তরিত করতে হবে, কেন এটি খুব বেশি সময় নেয়, সিটিপিস/সাইথন/নম্ব্ব ব্যবহার করে ফাংশনটি অনুবাদ করতে হয়-এটি একটি সি ফাংশনে যা কোনও অতিরিক্ত ওভারহেড ছাড়াই চালায়। প্রতিটি প্যান্ডাস সিরিজ কলামের কলামের অন্তর্গত তথ্যগুলির numpy array মানগুলি ব্যবহার করার জন্য আপনাকে আপনার কলিং কনভেনশনটি পরিবর্তন করতে হতে পারে এবং আপনি numpy.ctypeslib চেকআউট একটি numpy অ্যারে থেকে একটি ctypes- সামঞ্জস্যপূর্ণ অ্যারে থেকে সহজ রূপান্তর করার জন্য। এটি অনেক কিছু মনে হচ্ছে, তবে এটি সত্যিই পাইথনের সি ফাংশন অ্যাক্সেস করার পক্ষে একটি সহজ উপায়।
যোগ লেখক ely, উৎস
ডেটাফ্রেমের মতো সম্পর্কযুক্ত কাঠামোর মধ্যে সংরক্ষণ করার পরিবর্তে আপনি তথ্য থেকে একটি কে-ডি গাছ নির্মাণের কথা বিবেচনা করতে পারেন। তারপর একটি নির্দিষ্ট বিন্দু প্রতিবেশীদের পেতে সস্তা হবে, এবং সম্ভবত আপনি শুধুমাত্র চাহিদা দূরত্ব গণনা করতে পারে। অ্যাপ্লিকেশন সবসময় প্রতি জোড়া প্রয়োজন হয়? তবুও অন্য বিকল্প পয়েন্টগুলি ক্লাস্টার করতে এবং প্রতিটি ক্লাস্টারের সেন্ট্রয়েড/প্রক্সি হিসাবে অর্থ ব্যবহার করতে পারে। তারপর কোনও দুটো পয়েন্টের মধ্যে দূরত্ব কেবল ক্লাস্টার কেন্দ্রগুলির মধ্যে দূরত্বের দ্বারা আনুমানিক হবে। যদিও এটির মতো কিছু অভিনবতা যদিও বর্বর বাহিনীর চেয়ে সত্যিই ভাল।
যোগ লেখক ely, উৎস
ক্লাস্টারিংয়ের ক্ষেত্রে, আপনি একই ক্লাস্টারের সকল জোড়াগুলির জন্য সত্য দূরত্বগুলি গণনা করতে পারেন (প্রতিটি ক্লাস্টারের জন্য) যাতে সেই পয়েন্টগুলিতে শূন্যের কার্যকর দূরত্ব না থাকে। এটি সহজ সমান্তরালকরণের জন্যও কার্যকর: প্রতিটি প্রক্রিয়াটিকে তথ্যগুলির একটি অনুলিপি প্রদান করুন (অথবা এটি একটি কপি লোড করুন) এবং সূচকগুলির তালিকা সহ এটির জন্য দায়ী। তারপরে সেই প্রক্রিয়াটি অন্যান্য সূচকগুলির বিরুদ্ধে জোড়া সূচকগুলির জোড়ের দূরত্ব গণনা করে এবং তাদের কোথাও লিখে। মাত্র কয়েক লক্ষ সারির সাথে, এটি শালীন হার্ডওয়্যারগুলিতে যুক্তিসঙ্গত হওয়া উচিত।
যোগ লেখক ely, উৎস
হাঁ euclidian approximation ছোট যথেষ্ট দূরত্বের জন্য জরিমানা কাজ করবে। এর জন্য আপনাকে একটি প্রয়োগ করতে হবে না, সরাসরি ডেটাফ্রেমের কলামগুলি সরাসরি ব্যবহার করতে পারেন।
যোগ লেখক reptilicus, উৎস
প্রার্থীদের সংখ্যাগরিষ্ঠতার জন্য গণনা করা এড়ানো সম্ভব। আপনার শুরু বিন্দু থেকে 50 মাইল কম এবং সর্বোচ্চ লম্বা এবং অক্ষাংশ গণনা করুন। তারপর যারা প্রার্থী অধিকাংশ আউট আগাছা যারা মিনিট এবং maxes ব্যবহার করুন।
যোগ লেখক Steven Rumbalski, উৎস
পাইপিতে একটি হেভারসাইন মডিউল রয়েছে যা সি বাস্তবায়িত
যোগ লেখক Steven Rumbalski, উৎস
আপনার ল্যাট 1, লম্বা 1, ল্যাট 1, লং 1 যা একই সারিতে সমস্ত গণনা করা হয়?
যোগ লেখক dustin, উৎস
@ নিক্সনিক্স আপনার প্রশ্নে দেওয়া ফাংশনটি মহান বৃত্তের দূরত্ব দেয়। আপনার মন্তব্য গণনা euclidean দূরত্ব দেয়। কারণ পৃথিবীর ব্যাসার্ধ এত বড়, আপনি একেবারে দূরত্বের জন্য ইউক্লিডিয়ান সংস্করণের সাথে আনুমানিকভাবে অনুমান করতে পারেন।
যোগ লেখক derricw, উৎস

7 উত্তর

এখানে একই ফাংশনের একটি ভেক্টরাইজড numpy সংস্করণ:

import numpy as np

def haversine_np(lon1, lat1, lon2, lat2):
    """
    Calculate the great circle distance between two points
    on the earth (specified in decimal degrees)

    All args must be of equal length.    

    """
    lon1, lat1, lon2, lat2 = map(np.radians, [lon1, lat1, lon2, lat2])

    dlon = lon2 - lon1
    dlat = lat2 - lat1

    a = np.sin(dlat/2.0)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2.0)**2

    c = 2 * np.arcsin(np.sqrt(a))
    km = 6367 * c
    return km

ইনপুট মানগুলির সব অ্যারে এবং এটি লক্ষ লক্ষ পয়েন্ট অবিলম্বে করতে সক্ষম হওয়া উচিত। প্রয়োজনীয়তা হ'ল ইনপুটগুলি অ্যানড্রয়েস তবে আপনার প্যান্ডাস টেবিলের কলাম কাজ করবে।

উদাহরণস্বরূপ, এলোমেলোভাবে উত্পন্ন মান সঙ্গে:

>>> import numpy as np
>>> import pandas
>>> lon1, lon2, lat1, lat2 = np.random.randn(4, 1000000)
>>> df = pandas.DataFrame(data={'lon1':lon1,'lon2':lon2,'lat1':lat1,'lat2':lat2})
>>> km = haversine_np(df['lon1'],df['lat1'],df['lon2'],df['lat2'])

তথ্য অ্যারে মাধ্যমে looping পাইথন খুব ধীর। Numpy তথ্যগুলির সম্পূর্ণ অ্যারেগুলিতে কাজ করে এমন ফাংশন সরবরাহ করে যা আপনাকে লুপিং এড়াতে এবং কার্যকরীভাবে কার্য সম্পাদন উন্নত করতে দেয়।

এটি ভেক্টরাইজেশন এর একটি উদাহরণ।

44
যোগ
আপনি এটি বিভিন্ন আকারের অ্যারে এমনকি এমনকি কাজ করে জানেন;) মাত্রা অভিক্ষেপ মাধ্যমে
যোগ লেখক LetsPlayYahtzee, উৎস
এই জন্য আপনাকে অনেক ধন্যবাদ। ছোট পরামর্শ: ইনপুট ফর্ম্যাটটি স্পষ্ট করতে, র্যান্ডম মানের পরিবর্তে প্রকৃত সমন্বয়গুলির সাথে বাস্তব-বিশ্ব উদাহরণ ব্যবহার যুক্ত করুন।
যোগ লেখক Dennis Golomazov, উৎস
মনে রাখবেন যে এটিও কাজ করে যখন একটি জোড়া আর্গুমেন্ট সিরিজ এবং অন্যটি একটি টিপল হয়: haversine_np (pd.Series ([- 74.00594, -122.41942]), pd.Series ([40.71278 , 37.77493], -87.65005, 41.85003) (নিউ ইয়র্ক, সান ফ্রান্সিসকো) এবং শিকাগো এর মধ্যে দূরত্ব গণনা করে।
যোগ লেখক Dennis Golomazov, উৎস
আরেকটি ছোটখাটো পরামর্শ: আপনি ফাংশন আর্গুমেন্টগুলির আদেশ lat, lon এ বিনিময় করতে চাইতে পারেন। অনেক উত্স অক্ষাংশ প্রথম যায়, যেমন। en.wikipedia.org/wiki/Horizontal_position_representation এ।
যোগ লেখক Dennis Golomazov, উৎস
অ্যারে প্রোগ্রামিং শব্দটির সম্পর্কে জানা ভাল, MATLAB এর সাথে এটি জুড়ে আসেনি।
যোগ লেখক Divakar, উৎস
@ ডেনিসগোলোমাজভ afaik জিআইএস লাইব্রেরি এবং সফটওয়্যার সাধারণত এটি লন, lat হিসাবে অর্ডার। অক্ষাংশ প্রথম প্রধানত একটি Google মানচিত্র পছন্দ বলে মনে হচ্ছে। আমি ব্যক্তিগতভাবে ল্যাট হিসাবে অদ্ভুত এটি চাই, লোন।
যোগ লেখক Leandro Lima, উৎস

প্রকৃতপক্ষে একটি দৃষ্টান্তমূলক উদাহরণের জন্য, আমি numpy সংস্করণটি @ballsdotballs থেকে উত্তরের মধ্যে গ্রহণ করেছি এবং ctypes এর মাধ্যমে কল করার জন্য একটি সহযোগী সি বাস্তবায়ন তৈরি করেছি। যেহেতু numpy এমন একটি অত্যন্ত অপ্টিমাইজেশান টুল, তাই আমার সি কোড কার্যকর হিসাবে সামান্য সম্ভাবনা আছে, কিন্তু এটি কিছুটা বন্ধ হওয়া উচিত। এখানে বড় সুবিধা হল সি ধরনের সাথে একটি উদাহরণ দিয়ে চলার মাধ্যমে, এটি আপনাকে কীভাবে আপনার নিজের ব্যক্তিগত সি ফাংশনগুলিকে পাইথনকে খুব বেশি ওভারহেড ছাড়াই সংযুক্ত করতে পারে তা দেখতে সহায়তা করতে পারে। এটি বিশেষত চমৎকার যখন আপনি কেবল একটি ছোট কম্পিউটেশনের একটি ছোট অংশটিকে পাইথন এর পরিবর্তে কিছু সি উত্সতে ছোট টুকরা লেখার জন্য অপ্টিমাইজ করতে চান। কেবলমাত্র numpy ব্যবহার করে সমস্যাটি বেশিরভাগ সময় সমাধান করবে, কিন্তু সেই ক্ষেত্রেই যখন আপনার সমস্ত numpy দরকার হবে না এবং আপনি সংযোগ যোগ করতে চান না কিছু কোড জুড়ে numpy ডাটা প্রকারের ব্যবহার প্রয়োজন, এটি অন্তর্নির্মিত ctypes লাইব্রেরীতে কীভাবে অবনমিত করা যায় তা জানতে খুব সহজ এবং এটি নিজে করুন।

প্রথমে আসুন আমাদের সি উৎস ফাইল তৈরি করি, যা haversine.c নামে পরিচিত:

#include 
#include 
#include 

int haversine(size_t n, 
              double *lon1, 
              double *lat1, 
              double *lon2, 
              double *lat2,
              double *kms){

    if (   lon1 == NULL 
        || lon2 == NULL 
        || lat1 == NULL 
        || lat2 == NULL
        || kms == NULL){
        return -1;
    }

    double km, dlon, dlat;
    double iter_lon1, iter_lon2, iter_lat1, iter_lat2;

    double km_conversion = 2.0 * 6367.0; 
    double degrees2radians = 3.14159/180.0;

    int i;
    for(i=0; i < n; i++){
        iter_lon1 = lon1[i] * degrees2radians;
        iter_lat1 = lat1[i] * degrees2radians;
        iter_lon2 = lon2[i] * degrees2radians;
        iter_lat2 = lat2[i] * degrees2radians;

        dlon = iter_lon2 - iter_lon1;
        dlat = iter_lat2 - iter_lat1;

        km = pow(sin(dlat/2.0), 2.0) 
           + cos(iter_lat1) * cos(iter_lat2) * pow(sin(dlon/2.0), 2.0);

        kms[i] = km_conversion * asin(sqrt(km));
    }

    return 0;
}

// main function for testing
int main(void) {
    double lat1[2] = {16.8, 27.4};
    double lon1[2] = {8.44, 1.23};
    double lat2[2] = {33.5, 20.07};
    double lon2[2] = {14.88, 3.05};
    double kms[2]  = {0.0, 0.0};
    size_t arr_size = 2;

    int res;
    res = haversine(arr_size, lon1, lat1, lon2, lat2, kms);
    printf("%d\n", res);

    int i;
    for (i=0; i < arr_size; i++){
        printf("%3.3f, ", kms[i]);
    }
    printf("\n");
}

মনে রাখবেন যে আমরা সি কনভেনশনগুলির সাথে রাখতে চেষ্টা করছি। একটি আকারের পরিবর্তনশীলের জন্য size_t ব্যবহার করে উল্লেখযোগ্যভাবে তথ্য আর্গুমেন্টগুলি পাস করে এবং আমাদের হেভারসিন ফাংশনটি প্রত্যাশিত ইনপুটগুলির মধ্যে একটি পরিবর্তন করে কাজ করার জন্য প্রত্যাশিত, যেমন এটি প্রত্যাশিত ডেটা ধারণ করবে প্রস্থান উপর। ফাংশন আসলে একটি পূর্ণসংখ্যা ফেরত দেয়, যা একটি সফল/ব্যর্থ পতাকা যা ফাংশনের অন্যান্য সি-লেভেল ভোক্তাদের দ্বারা ব্যবহার করা যেতে পারে।

পাইথন এর ভিতরে এই ছোট্ট সি-নির্দিষ্ট সমস্যাগুলি পরিচালনা করার জন্য আমাদের একটি উপায় খুঁজে বের করতে হবে।

এর পরে ফাংশনের আমাদের numpy সংস্করণটি কিছু আমদানি এবং কিছু পরীক্ষা ডেটা haversine.py নামক একটি ফাইলে রাখুন:

import time
import ctypes
import numpy as np
from math import radians, cos, sin, asin, sqrt

def haversine(lon1, lat1, lon2, lat2):
    """
    Calculate the great circle distance between two points 
    on the earth (specified in decimal degrees)
    """
    # convert decimal degrees to radians 
    lon1, lat1, lon2, lat2 = map(np.radians, [lon1, lat1, lon2, lat2])
    # haversine formula 
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = (np.sin(dlat/2)**2 
         + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2)**2)
    c = 2 * np.arcsin(np.sqrt(a)) 
    km = 6367 * c
    return km

if __name__ == "__main__":
    lat1 = 50.0 * np.random.rand(1000000)
    lon1 = 50.0 * np.random.rand(1000000)
    lat2 = 50.0 * np.random.rand(1000000)
    lon2 = 50.0 * np.random.rand(1000000)

    t0 = time.time()
    r1 = haversine(lon1, lat1, lon2, lat2)
    t1 = time.time()
    print t1-t0, r1

আমি 0 এবং 50 এর মধ্যে এলোমেলোভাবে নির্বাচিত লেট এবং লোন (ডিগ্রিতে) করতে বেছে নিলাম, তবে এই ব্যাখ্যাটির জন্য এটি অনেক বেশি গুরুত্বপূর্ণ নয়।

আমাদের যা করতে হবে তা হল আমাদের সি মডিউলকে এমনভাবে কম্পাইল করা যাতে এটি প্যাথন দ্বারা গতিশীলভাবে লোড করা যায়। আমি একটি লিনাক্স সিস্টেম ব্যবহার করছি (আপনি Google এ খুব সহজে অন্যান্য সিস্টেমের জন্য উদাহরণ খুঁজে পেতে পারেন), তাই আমার লক্ষ্য haversine.c কে একটি ভাগ করা বস্তুর মধ্যে কম্পাইল করা, যেমন:

gcc -shared -o haversine.so -fPIC haversine.c -lm

আমরা একটি এক্সিকিউটেবলের সাথে কম্পাইল করতে এবং সি প্রোগ্রামের প্রধান ফাংশন প্রদর্শন দেখতে এটি চালাতে পারি:

> gcc haversine.c -o haversine -lm
> ./haversine
0
1964.322, 835.278, 

এখন আমরা শেয়ারকৃত বস্তু haversine.so সংকলন করেছি, আমরা পাইথন এ লোড করতে ctypes ব্যবহার করতে পারি এবং আমাদের এটি করার জন্য ফাইলটির পাথ সরবরাহ করতে হবে:

lib_path = "/path/to/haversine.so" # Obviously use your real path here.
haversine_lib = ctypes.CDLL(lib_path)

এখন haversine_lib.haversine একটি পাইথন ফাংশনের মতোই অনেক বেশি কাজ করে, কেবলমাত্র ইনপুট এবং আউটপুটগুলি সঠিকভাবে ব্যাখ্যা করা হয়েছে কিনা তা নিশ্চিত করার জন্য আমাদের কিছু ম্যানুয়াল টাইপ মার্শালিং করতে হবে।

numpy actually provides some nice tools for this and the one I'll use here is numpy.ctypeslib. We're going to build a pointer type that will allow us to pass around numpy.ndarrays to these ctypes-loaded functions as through they were pointers. Here's the code:

arr_1d_double = np.ctypeslib.ndpointer(dtype=np.double, 
                                       ndim=1, 
                                       flags='CONTIGUOUS')

haversine_lib.haversine.restype = ctypes.c_int
haversine_lib.haversine.argtypes = [ctypes.c_size_t,
                                    arr_1d_double, 
                                    arr_1d_double,
                                    arr_1d_double,
                                    arr_1d_double,
                                    arr_1d_double] 

লক্ষ্য করুন যে আমরা haversine_lib.haversine ফাংশন প্রক্সি বলতে চাই তার প্রকারের অনুসারে আমাদের আর্গুমেন্টগুলি ব্যাখ্যা করতে।

এখন, এটি পরীক্ষা করার জন্য পাইথন থেকে ঠিক আছে একটি আকার পরিবর্তনশীল, এবং একটি অ্যারে যা ফলাফল তথ্য ধারণ করতে (যেমন সি কোডের মতো) পরিবর্তন করা হবে, তাহলে আমরা কল করতে পারি এটা:

size = len(lat1)
output = np.empty(size, dtype=np.double)
print "====="
print output
t2 = time.time()
res = haversine_lib.haversine(size, lon1, lat1, lon2, lat2, output)
t3 = time.time()
print t3 - t2, res
print type(output), output

__ প্রধান __ haversine.py ব্লক এটিকে একত্রিত করে, পুরো ফাইলটি এখন এই রকম দেখাচ্ছে:

import time
import ctypes
import numpy as np
from math import radians, cos, sin, asin, sqrt

def haversine(lon1, lat1, lon2, lat2):
    """
    Calculate the great circle distance between two points 
    on the earth (specified in decimal degrees)
    """
    # convert decimal degrees to radians 
    lon1, lat1, lon2, lat2 = map(np.radians, [lon1, lat1, lon2, lat2])
    # haversine formula 
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = (np.sin(dlat/2)**2 
         + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2)**2)
    c = 2 * np.arcsin(np.sqrt(a)) 
    km = 6367 * c
    return km

if __name__ == "__main__":
    lat1 = 50.0 * np.random.rand(1000000)
    lon1 = 50.0 * np.random.rand(1000000)
    lat2 = 50.0 * np.random.rand(1000000)
    lon2 = 50.0 * np.random.rand(1000000)

    t0 = time.time()
    r1 = haversine(lon1, lat1, lon2, lat2)
    t1 = time.time()
    print t1-t0, r1

    lib_path = "/home/ely/programming/python/numpy_ctypes/haversine.so"
    haversine_lib = ctypes.CDLL(lib_path)
    arr_1d_double = np.ctypeslib.ndpointer(dtype=np.double, 
                                           ndim=1, 
                                           flags='CONTIGUOUS')

    haversine_lib.haversine.restype = ctypes.c_int
    haversine_lib.haversine.argtypes = [ctypes.c_size_t,
                                        arr_1d_double, 
                                        arr_1d_double,
                                        arr_1d_double,
                                        arr_1d_double,
                                        arr_1d_double]

    size = len(lat1)
    output = np.empty(size, dtype=np.double)
    print "====="
    print output
    t2 = time.time()
    res = haversine_lib.haversine(size, lon1, lat1, lon2, lat2, output)
    t3 = time.time()
    print t3 - t2, res
    print type(output), output

এটি চালানোর জন্য, যা Python এবং ctypes সংস্করণগুলি পৃথকভাবে চালাবে এবং কিছু ফলাফল মুদ্রণ করবে, আমরা তা করতে পারি

python haversine.py

যা প্রদর্শন করে:

0.111340045929 [  231.53695005  3042.84915093   169.5158946  ...,  1359.2656769
  2686.87895954  3728.54788207]
=====
[  6.92017600e-310   2.97780954e-316   2.97780954e-316 ...,
   3.20676686e-001   1.31978329e-001   5.15819721e-001]
0.148446083069 0
 [  231.53675618  3042.84723579   169.51575588 ...,  1359.26453029
  2686.87709456  3728.54493339]

প্রত্যাশিত হিসাবে, numpy সংস্করণটি আরও দ্রুত (1 মিলিয়ন দৈর্ঘ্যের সাথে ভেক্টরগুলির 0.11 সেকেন্ড) কিন্তু আমাদের দ্রুত এবং নোংরা ctypes সংস্করণটি কোনও স্লুপ নয়: একটি শ্রদ্ধাশীল 0.148 সেকেন্ড একই তথ্য।

আসুন পাইথন-এ একটি সাদাসিধা for-loop সমাধানের সাথে এটির তুলনা করি:

from math import radians, cos, sin, asin, sqrt

def slow_haversine(lon1, lat1, lon2, lat2):
    n = len(lon1)
    kms = np.empty(n, dtype=np.double)
    for i in range(n):
       lon1_v, lat1_v, lon2_v, lat2_v = map(
           radians, 
           [lon1[i], lat1[i], lon2[i], lat2[i]]
       )

       dlon = lon2_v - lon1_v 
       dlat = lat2_v - lat1_v 
       a = (sin(dlat/2)**2 
            + cos(lat1_v) * cos(lat2_v) * sin(dlon/2)**2)
       c = 2 * asin(sqrt(a)) 
       kms[i] = 6367 * c
    return kms

যখন আমি এটি একই পাইথন ফাইলে অন্যদের হিসাবে এবং একই মিলিয়ন-এলিমেন্ট ডেটাতে সময় দিয়ে রাখি, তখন আমি আমার মেশিনে প্রায় 2.65 সেকেন্ডের সময়টি নিয়মিত দেখি।

তাই দ্রুত ctypes এ স্যুইচ করে আমরা 18 এর একটি ফ্যাক্টর দ্বারা গতি উন্নত করি। অনেকগুলি হিসাব যা বেয়ার, সংস্পর্শী ডেটাতে অ্যাক্সেস থেকে উপকৃত হতে পারে, তারপরেও আপনি এটির তুলনায় অনেক বেশি লাভ দেখতে পান।

শুধু সুপার স্পষ্ট হতে, আমি এই কোডটিকে numpy ব্যবহার করার চেয়ে ভাল বিকল্প হিসাবে সমর্থন করছি না। এটি এমন সমস্যা যা numpy সমাধান করার জন্য তৈরি হয়েছিল এবং তাই আপনার নিজের ctypes কোডটি হোমব্রিউইং করলেও এটি (ক) numpy আপনার অ্যাপ্লিকেশনে ডাটা প্রকার এবং (খ) আপনার কোডটি numpy সমতুল্যতে মানচিত্রের একটি সহজ উপায় বিদ্যমান রয়েছে, এটি খুব কার্যকর নয়।

তবে এটি যেভাবে আপনি সি-তে কিছু লিখতে পছন্দ করেন তার জন্য এটি কীভাবে করা যায় তা এখনও জানা খুবই সহায়ক, তবুও এটি পাইথনে কল করুন, অথবা এমন পরিস্থিতিতে যেখানে numpy এর উপর নির্ভরতা বাস্তব নয় (একটি এমবেডেড সিস্টেমে যেখানে numpy ইনস্টল করা যাবে না, উদাহরণস্বরূপ)।

11
যোগ

যদি বিজ্ঞানের ব্যবহার শিখতে দেওয়া হয় তবে আমি নিম্নলিখিত সুযোগটি দেব:

from sklearn.neighbors import DistanceMetric
dist = DistanceMetric.get_metric('haversine')

# example data
lat1, lon1 = 36.4256345, -5.1510261
lat2, lon2 = 40.4165, -3.7026
lon1, lat1, lon2, lat2 = map(np.radians, [lon1, lat1, lon2, lat2])

X = [[lat1, lon1],
     [lat2, lon2]]
kms = 6367
print(kms * dist.pairwise(X))
7
যোগ

যদি বিজ্ঞানের ব্যবহার শিখতে দেওয়া হয় তবে আমি নিম্নলিখিত সুযোগটি দেব:

from sklearn.neighbors import DistanceMetric
dist = DistanceMetric.get_metric('haversine')

# example data
lat1, lon1 = 36.4256345, -5.1510261
lat2, lon2 = 40.4165, -3.7026
lon1, lat1, lon2, lat2 = map(np.radians, [lon1, lat1, lon2, lat2])

X = [[lat1, lon1],
     [lat2, lon2]]
kms = 6367
print(kms * dist.pairwise(X))
7
যোগ

এই উত্তরগুলির কিছুটি পৃথিবীর ব্যাসার্ধ "গোলাকার"। যদি আপনি অন্য দূরত্ব ক্যালকুলেটরগুলির (যেমন geopy ) বিরুদ্ধে এটি পরীক্ষা করেন তবে এই ফাংশন বন্ধ হয়ে যাবে।

যদি আপনি মাইলের মধ্যে উত্তর চান তবে নীচের রূপান্তর ধ্রুবকের জন্য আপনি R = 3959.87433 স্যুইচ করতে পারেন।

আপনি যদি কিলোমিটার চান তবে R = 6372.8 ব্যবহার করুন।

lon1 = -103.548851
lat1 = 32.0004311
lon2 = -103.6041946
lat2 = 33.374939


def haversine(lat1, lon1, lat2, lon2):

      R = 3959.87433 # this is in miles.  For Earth radius in kilometers use 6372.8 km

      dLat = radians(lat2 - lat1)
      dLon = radians(lon2 - lon1)
      lat1 = radians(lat1)
      lat2 = radians(lat2)

      a = sin(dLat/2)**2 + cos(lat1)*cos(lat2)*sin(dLon/2)**2
      c = 2*asin(sqrt(a))

      return R * c

print(haversine(lat1, lon1, lat2, lon2))
0
যোগ

এই উত্তরগুলির কিছুটি পৃথিবীর ব্যাসার্ধ "গোলাকার"। যদি আপনি অন্য দূরত্ব ক্যালকুলেটরগুলির (যেমন geopy ) বিরুদ্ধে এটি পরীক্ষা করেন তবে এই ফাংশন বন্ধ হয়ে যাবে।

যদি আপনি মাইলের মধ্যে উত্তর চান তবে নীচের রূপান্তর ধ্রুবকের জন্য আপনি R = 3959.87433 স্যুইচ করতে পারেন।

আপনি যদি কিলোমিটার চান তবে R = 6372.8 ব্যবহার করুন।

lon1 = -103.548851
lat1 = 32.0004311
lon2 = -103.6041946
lat2 = 33.374939


def haversine(lat1, lon1, lat2, lon2):

      R = 3959.87433 # this is in miles.  For Earth radius in kilometers use 6372.8 km

      dLat = radians(lat2 - lat1)
      dLon = radians(lon2 - lon1)
      lat1 = radians(lat1)
      lat2 = radians(lat2)

      a = sin(dLat/2)**2 + cos(lat1)*cos(lat2)*sin(dLon/2)**2
      c = 2*asin(sqrt(a))

      return R * c

print(haversine(lat1, lon1, lat2, lon2))
0
যোগ

এই উত্তরগুলির কিছুটি পৃথিবীর ব্যাসার্ধ "গোলাকার"। যদি আপনি অন্য দূরত্ব ক্যালকুলেটরগুলির (যেমন geopy ) বিরুদ্ধে এটি পরীক্ষা করেন তবে এই ফাংশন বন্ধ হয়ে যাবে।

যদি আপনি মাইলের মধ্যে উত্তর চান তবে নীচের রূপান্তর ধ্রুবকের জন্য আপনি R = 3959.87433 স্যুইচ করতে পারেন।

আপনি যদি কিলোমিটার চান তবে R = 6372.8 ব্যবহার করুন।

lon1 = -103.548851
lat1 = 32.0004311
lon2 = -103.6041946
lat2 = 33.374939


def haversine(lat1, lon1, lat2, lon2):

      R = 3959.87433 # this is in miles.  For Earth radius in kilometers use 6372.8 km

      dLat = radians(lat2 - lat1)
      dLon = radians(lon2 - lon1)
      lat1 = radians(lat1)
      lat2 = radians(lat2)

      a = sin(dLat/2)**2 + cos(lat1)*cos(lat2)*sin(dLon/2)**2
      c = 2*asin(sqrt(a))

      return R * c

print(haversine(lat1, lon1, lat2, lon2))
0
যোগ