如何找到2个最近的点?

时间:2019-06-21 10:31:20

标签: python math geo

我是python的新手,不知道如何处理此任务: 我需要从点数据框中找到每个点的2个数据框,从轨迹数据框中找到2个最近的点

轨迹数据框:

datetime                 lon_deg              lat_deg
2501    28.03.2018 11:58    13.35994653 48.59990204
2502    28.03.2018 11:58    13.35880586 48.60004335
2503    28.03.2018 11:59    13.35766636 48.600205100000004
2504    28.03.2018 11:59    13.35653218 48.60039648
2505    28.03.2018 12:00    13.35539451 48.60058775
2506    28.03.2018 12:00    13.35426064 48.60079647
2507    28.03.2018 12:01    13.3531299  48.60096096
2508    28.03.2018 12:01    13.352004   48.60099219

点数据框:

datetime    lon_deg                        lat_deg
2018-01-29 08:08:59.000 13.359284659333333  48.600108882
29.01.2018 8:09 13.358371081166666  48.60023545666667
2018-01-29 08:09:19.000 13.358347605833334  48.600238692333335
29.01.2018 8:09 13.358324105166666  48.600241913333335
2018-01-29 08:09:20.000 13.358300611666667  48.600245154666666
29.01.2018 8:09 13.358277134    48.600248416
2018-01-29 08:09:21.000 13.358253648166666  48.60025165216667
2018-01-29 08:09:54.000 13.356701967    48.60046564733333
29.01.2018 8:09 13.356678427    48.6004688765
2018-01-29 08:09:55.000 13.356654635    48.6004718285
29.01.2018 8:09 13.356443313166666  48.600502414833336
2018-01-29 08:10:00.000 13.356419901333334  48.60050610933333
29.01.2018 8:10 13.356396262666667  48.600509612
2018-01-29 08:10:09.000 13.355999669    48.6005754975
29.01.2018 8:10 13.355976287333334  48.600579365
2018-01-29 08:10:10.000 13.355952748166667  48.60058305983333
29.01.2018 8:10 13.355929286666667  48.600586781666664
2018-01-29 08:10:11.000 13.355905869    48.6005904815
29.01.2018 8:10 13.355882745166667  48.60059446966667
2018-01-29 08:10:12.000 13.355859396333333  48.600598258666665
29.01.2018 8:10 13.3558361535   48.600602143
2018-01-29 08:10:13.000 13.355812639    48.600605769
29.01.2018 8:10 13.355789295666666  48.60060949333333
2018-01-29 08:10:14.000 13.355765727833333  48.60061298866667
29.01.2018 8:10 13.355742236833333  48.60061659483333
2018-01-29 08:10:15.000 13.3557187615   48.60062014216667
29.01.2018 8:10 13.355695496166666  48.60062391466667
2018-01-29 08:10:16.000 13.35567225 48.600627667833336
29.01.2018 8:10 13.355649023166666  48.600631406
2018-01-29 08:10:17.000 13.355625505    48.60063494533333
29.01.2018 8:10 13.3556019655   48.60063844983333
2018-01-29 08:10:18.000 13.355578551333334  48.60064199316667
29.01.2018 8:10 13.355461117166668  48.60065928433333
2018-01-29 08:10:21.000 13.355437626833334  48.600662660333334
2018-01-29 08:10:24.000 13.3552968655   48.600682845166666
29.01.2018 8:10 13.3552734295   48.600686212333336
2018-01-29 08:10:25.000 13.355249975    48.600689552333336
2018-01-29 08:10:29.000 13.355062269    48.6007157075
29.01.2018 8:10 13.355038871833333  48.60071868083333
2018-01-29 08:10:30.000 13.355015400166666  48.6007218995
29.01.2018 8:10 13.354991943833333  48.60072502533333
2018-01-29 08:10:31.000 13.354968547333334  48.60072815216667
29.01.2018 8:10 13.353912527    48.60085315883333
2018-01-29 08:10:54.000 13.353889066666667  48.60085595533333
2018-01-29 08:11:00.000 13.353607144333333  48.60088610016667

我将不胜感激!

2 个答案:

答案 0 :(得分:0)

我想这很大程度上取决于您的数据大小。

暴力破解方法类似于:

import numpy as np

points_dataframe = np.random.rand(20,2)
trajecotry_dataframe = np.random.rand(5,2)

print('points_dataframe:')
print(points_dataframe)
print('\n\ntrajecotry_dataframe:')
print(trajecotry_dataframe)
print('\n\n')



for index_points, (x1, y1) in enumerate(points_dataframe):

    distance_list = []

    for index_trajecotry, (x2, y2) in enumerate(trajecotry_dataframe):

        distance_list.append(np.sqrt((x1-x2)**2 + (y1-y2)**2))


    sorted_list = np.sort(distance_list)


    print('+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++')
    print(f'for element {index_points} in the points_dataframe the two closest points are:')
    point0 = np.where(distance_list==sorted_list[0])[0][0]
    print(f'element {point0} from the trajecotry_dataframe')  
    point1 = np.where(distance_list==sorted_list[1])[0][0]
    print(f'element {point1} from the trajecotry_dataframe')  

但是当数据集更大或您不得不更频繁地重复计算时, 也许您应该考虑将数据保存在经过地理编码的数据库中。

答案 1 :(得分:0)

以下是一些用Matlab编写的代码,可能会有所帮助。如果有用,则必须将它们转换为Python。这种方法是蛮力的,而不是最优雅的方法。但是,我尝试包括近似的坐标系转换,这些转换将地球的形状解释为椭球。如果假设地球是一个球体,那么事情就可以简化一点。另外,为了提高精度(尽管很有可能忽略不计),可以通过球体表面(在给定点最接近椭球体的球体)局部近似椭圆体的表面,并使用球体代替欧几里得几何。

可能会有一些错别字或错误,但是也许您可以了解坐标,转换和方法的概念。

使用以下两个功能,您可以转换为:

  1. 到欧几里得坐标的点long_lat0 = [long0, lat0]附近的大地坐标(即经度)是WGS84地球椭球上实际,真实大地坐标的一阶线性近似

  2. 相反,您可以从欧几里得坐标转换回大地纬度

long_lat0 = [long0, lat0]; % a point from dataset 2
long_lat % the n x 2 matrix of points from dataset 1 (or a chunk of it) 

%center of approximate Euclidean coordinate system is point long_lat0 
% with long_lat coordinates and the scaling coefficient 
% a of longitude and b of latitude, 
% which equalizes longitude and latitude distance at point long_lat0, is

function  [x, a, b] = convert_to_local_Eucl(long_lat, long_lat0) 

   % long_lat0 = [long_0, lat_0] is the origin of the local coordinate system 
   % long_lat  = [long_1, lat_1;
   %              long_2, lat_2;
   %              ............
   %              long_n, lat_n]  is an n x 2 array of points in lat and long coordinates 
   %  on the Earth's ellipsoid
   %  x = [x_1, y_1;
   %       x_2, y_2;
   %      ..........
   %       x_n, y_n] 
   % is the n x 2 matrix of Euclidean coordinates with origin the point long_lat0 
   % a is a number, correction factor of longitude coordinate
   % b is a number, correction factor of latitude

   R = 6378137.0 %in meters;
   e_2 = ( R^2 - (6356752.314245)^2 ) / R^2; 
   a = R * (1-e_2) * cosd(long_lat0(2)) / (1 - e_2*sind(long_lat0(2))^(1/2)); % dlong
   b = R * (1-e_2) / (1 - e_2*sind(long_lat0(2))^(3/2); %dlat
   % a and b are correcting/rescaling coefficients 
   % that correct the longitude-latitude coordinates of all points 
   % near point long_lat0 in geodetic coordinates of WGS84.

   x = long_lat .- long_lat0; % subtract the long_lat0 from the coordinates of every point 
   % from the list long_lat, i.e. for each  j = 1...n
   %  x(j, 1) = long_lat(j, 1) - long_lat0(1); 
   %  x(j, 2) = long_lat(j, 2) - long_lat0(2); 

   x = [ a * x(:,1),  b * x(:, 2)]; 
   % multiply the first column of coordinates by the scaling factor a and 
   % multiply the second column of coordinates by the scaling factor b 
   % these coordinates are first order linear Euclidean approximation 
   % of the real geodetic coordinates of WGS84. 
   % Near the point long_lat0 
   % the error is negligible, especially within a couple of kilometers. 
   % The farther you go from that point, the error slowly increases, 
   % but then it doesn't matter since such points are not the closest anyway.    

end

function  long_lat = convert_to_long_lat(x, long_lat0, a, b) 

   % from Euclidean coordinates x = [x(1), x(2)] of a point near long_lat0 go back to 
   % long_lat = [long, lat] coordinates of that points. a and b are the scaling
   % coefficients at point long_lat0

   long_lat = [long_lat0(1) + x(1)/a,  long_lat0(2) + x(2)/b];

end

对于数据集2中的每个点long_lat0 = [long0, lat0],首先从大地纬向经纬度转换为long_lat0处的近似欧几里得坐标 数据集1(第二和第三列)的整个long_lat列表(或大块):

x = convert_2_local_Eucl(long_lat, long_lat0);

然后计算所有2D行向量的大小(即长度) x(j,:) = [x(j,1), x(j,1)] 来自数据集x

magnitudes = norm(x); %you have to either find this function or write one yourself

之后,找到x的索引和元素的最小值:

[j, min] = min(magnitudes);

然后为两对: x1 = x(j,:) and x2 = x(j+1,:) 和  x1 = x(j,:) and x2 = x(j-1,:) 使用下面的函数计算最接近的点:


function [dist, long_lat] = dist_point_to_reference(x1, x2, long_lat0, a, b)
    % calculates the shortest distance dist from the point long_lat0 
    % to the closest point on the segment between x1 and x2 
    % and then obtain the long_lat coordinates of this closest point

   dist = dot(x1, x1) * dot(x2 - x1, x2 - x1) - dot(x1, x2 - x1)^2 ; % dot is dot product 
   dist = sqrt( dist / ( dot(x2 - x1, x2 - x1)^2) );
   % dist is the distance from the point at the origin [0, 0] 
   % to the straight Euclidean interval between
   % the points x1 = [x1(1), x1(2)] and  x2 = [x2(1), x2(2)] 

   if dot(x1, x2 - x1) > 0 % if the height of the triangle is outside, on the side of x1 
      dist = sqrt( dot(x1, x1) );
      long_lat = x1;
   elseif dot(x2, x1 - x2) > 0 % if the height of the triangle is outside, on the side of x2  
      dist = sqrt( dot(x2, x2) );
      long_lat = x1;
   else
      long_lat(1) =  - x2(2) + x1(2); 
      long_lat(2) = x2(1) - x1(1);
      long_lat = long_lat / sqrt(dot(long_lat, long_lat));
      long_lat = - dot(x1, long_lat) * long_lat; % despite the name, these are Eucldean coordinates
   end

   long_lat = convert_to_long_lat(long_lat, a, b); % finally, geodetic coordinates

end