Панды - вычислить новый столбец на основе относительного значения в других строках - PullRequest
1 голос
/ 08 октября 2019

С данными, как показано ниже

data = """
Class,Location,Long,Lat
A,ABC11,139.6295542,35.61144069
A,ABC20,139.630596,35.61045559
A,ABC03,139.6300307,35.61327781
B,ABC54,139.7787818,35.68847945
B,ABC05,139.7814447,35.6816882
B,ABC06,139.7788191,35.681865
B,ABC24,139.7790396,35.67781697
"""
df = pd.read_csv(StringIO(data))

Каждая строка содержит данные, относящиеся к местоположению. Для каждого местоположения нужно найти расстояние до других местоположений (рядов) следующим образом (упрощено для простоты)

distance = sqrt((Long1-Long2)^2 + (Lat1-Lat2)^2)

, если бы это было сделано за пределами панд, я бы сделал следующее

import math

rows = df.to_dict('records')

# distance of each location w.r.t other locations excluding self
results = {}
for row in rows:
    loc = row['Location']
    results[loc] = {}
    # get a new list excl the curr row
    nrows = [row for row in rows if row['Location'] != loc]
    for nrow in nrows:
        dist = math.sqrt((row["Long"] - nrow["Long"])**2 + (row["Lat"] - nrow["Lat"])**2)
        results[loc][nrow["Location"]] = dist

# find the location with min distance 
fin_results = {}
for k, v in results.items():
    fin_results[k] = {}
    minValKey = min(v, key = v.get)
    fin_results[k]["location"] = minValKey 
    fin_results[k]["dist"] = v[minValKey]

Это даст вывод, подобный приведенному ниже, который для каждого местоположения дает местоположение, которое является самым ближайшим и расстояние до этого местоположения.

{'ABC11': {'location': 'ABC20', 'dist': 0.001433795400325211}, 'ABC20': {'location': 'ABC11', 'dist': 0.001433795400325211}, 'ABC03': {'location': 'ABC11', 'dist': 0.001897909941062068}, 'ABC54': {'location': 'ABC06', 'dist': 0.006614555169662396}, 'ABC05': {'location': 'ABC06', 'dist': 0.002631545857463665}, 'ABC06': {'location': 'ABC05', 'dist': 0.002631545857463665}, 'ABC24': {'location': 'ABC06', 'dist': 0.004054030973106164}}

Хотя это работает функционально, хотел знать, что будет pandasспособ сделать это.

Желаемый вывод

+----------+-------------------+----------------------------+
| location |  nearest_location |  nearest_location_distance |
+----------+-------------------+----------------------------+
| 'ABC11'  | 'ABC20'           | 0.001433795400325211       |
| 'ABC20'  | 'ABC11'           | 0.001433795400325211       |
| 'ABC03'  | 'ABC11'           | 0.001897909941062068       |
| 'ABC54'  | 'ABC06'           | 0.006614555169662396       |
| 'ABC05'  | 'ABC06'           | 0.002631545857463665       |
| 'ABC06'  | 'ABC05'           | 0.002631545857463665       |
| 'ABC24'  | 'ABC06'           | 0.004054030973106164       |
+----------+-------------------+----------------------------+

Ответы [ 4 ]

1 голос
/ 08 октября 2019

Также вы можете использовать df.iterrows :

distance_min=[]
location_min=[]
output_df=df.copy()
for i, col in df.iterrows():
    dist=((col['Long']-df['Long']).pow(2)+(col['Lat']-df['Lat']).pow(2)).pow(1/2)
    location_min.append(df.at[dist[dist>0].idxmin(),'Location'])
    distance_min.append(dist[dist>0].min())

output_df['nearest_location']=location_min
output_df['nearest_location_distance']=distance_min
output_df=output_df.reindex(columns=['Location','nearest_location','nearest_location_distance'])
print(output_df)

 Location  nearest_location  nearest_location_distance
0    ABC11            ABC20                   0.001434
1    ABC20            ABC11                   0.001434
2    ABC03            ABC11                   0.001898
3    ABC54            ABC06                   0.006615
4    ABC05            ABC06                   0.002632
5    ABC06            ABC05                   0.002632
6    ABC24            ABC06                   0.004054
1 голос
/ 08 октября 2019

Вы можете использовать scipy distance_matrix, что на самом деле то, что @rafaelc закодировало:

from scipy.spatial import distance_matrix

dist_mat = distance_matrix(df[['Long','Lat']],df[['Long','Lat']])

# assign distance matrix with appropriate name
dist_mat = pd.DataFrame(dist_mat, 
                        index=df.Location, 
                        columns=df.Location)

# convert the data frame to dict
(dist_mat.where(dist_mat>0)
     .agg(('idxmin', 'min'))
     .to_dict()
)

Вывод:

{'ABC11': {'idxmin': 'ABC20', 'min': 0.001433795400325211},
 'ABC20': {'idxmin': 'ABC11', 'min': 0.001433795400325211},
 'ABC03': {'idxmin': 'ABC11', 'min': 0.001897909941062068},
 'ABC54': {'idxmin': 'ABC06', 'min': 0.006614555169662396},
 'ABC05': {'idxmin': 'ABC06', 'min': 0.002631545857463665},
 'ABC06': {'idxmin': 'ABC05', 'min': 0.002631545857463665},
 'ABC24': {'idxmin': 'ABC06', 'min': 0.004054030973106164}}    ​

Если вы хотите только кадр данных:

(dist_mat.where(dist_mat>0)
     .agg(('idxmin', 'min'))
     .T
)

Выход:

      idxmin         min
ABC11  ABC20   0.0014338
ABC20  ABC11   0.0014338
ABC03  ABC11  0.00189791
ABC54  ABC06  0.00661456
ABC05  ABC06  0.00263155
ABC06  ABC05  0.00263155
ABC24  ABC06  0.00405403
1 голос
/ 08 октября 2019

Вы можете использовать numpy широковещание

long_ = df.Long.to_numpy()
lat   = df.Lat.to_numpy() 

distances = np.sqrt((long_ - long_[:, None]) ** 2 + (lat - lat[:,None]) **2)

dist_df = pd.DataFrame(distances, index=df.Location, columns=df.Location)

Location     ABC11     ABC20     ABC03     ABC54     ABC05     ABC06     ABC24

ABC11     0.000000  0.001434  0.001898  0.167940  0.167348  0.165044  0.163559
ABC20     0.001434  0.000000  0.002878  0.167472  0.166822  0.164528  0.163012
ABC03     0.001898  0.002878  0.000000  0.166680  0.166151  0.163836  0.162385
ABC54     0.167940  0.167472  0.166680  0.000000  0.007295  0.006615  0.010666
ABC05     0.167348  0.166822  0.166151  0.007295  0.000000  0.002632  0.004558
ABC06     0.165044  0.164528  0.163836  0.006615  0.002632  0.000000  0.004054
ABC24     0.163559  0.163012  0.162385  0.010666  0.004558  0.004054  0.000000

m = dist_df[dist_df>0]
pd.concat([m.idxmin(1).rename('nearest_location'),
           m.min(1).rename('nearest_location_distance'), ],1)

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

        nearest_location  nearest_location_distance
Location                                            
ABC11               ABC20                   0.001434
ABC20               ABC11                   0.001434
ABC03               ABC11                   0.001898
ABC54               ABC06                   0.006615
ABC05               ABC06                   0.002632
ABC06               ABC05                   0.002632
ABC24               ABC06                   0.004054

Здесь будет найдено расстояние от одного ряда до всех других. Вот как я истолковал вопрос, не уверенный, является ли ваша цель.

0 голосов
/ 08 октября 2019

Поскольку ansev предлагает то же решение, немного более законченное

import pandas as pd 
from io import StringIO

df = pd.read_csv(StringIO(data))
df['result']= (df['Lat'].diff(-1).pow(2)+df['Long'].diff(-1).pow(2)).pow(1/2)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...