Как найти 2 ближайших пункта? - PullRequest
0 голосов
/ 21 июня 2019

Я новичок в 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 голосов
/ 23 июня 2019

Вот некоторые фрагменты кода, написанные на 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

Для каждой точки long_lat0 = [long0, lat0] из набора данных 2 начните с преобразования изгеодезический long-lat для аппроксимации евклидовых координат в long_lat0 весь (или часть) long_lat список набора данных 1 секунда и третий столбец:

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
0 голосов
/ 21 июня 2019

Я полагаю, что это сильно зависит от размера ваших данных.

Подход методом грубой силы будет выглядеть примерно так:

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')  

Но когда набор данных больше или вы должны повторитьПри более частых вычислениях, возможно, вам стоит подумать о сохранении ваших данных в геокодированной базе данных.

...