【问题标题】:Find points in a column within 5km of a person from lat/lon coordinates in a dataframe从数据框中的纬度/经度坐标查找人 5 公里范围内的列中的点
【发布时间】:2021-11-02 07:31:59
【问题描述】:

我是 Python 的初学者。我有一个数据集,其中包含人们在每个时间段的旅行记录,并且想获得一个新的数据框,该数据集描述了每个人旅行时的选择集。

我正在尝试从纬度/经度坐标中找到一个人 5 公里范围内的所有站点。我有一个数据框,其中包含人员 ID、时间 t 的人员位置坐标、车站坐标。我想获得一个新的数据框,其中包含距离数据集中出现的人 5 公里以内的所有站点(使用 person-id 和 time-t 作为两个单独的索引),以及到所有站点的各自距离为另一列。例如,如果站点 1 出现在周期 1 中,但不在周期 2 中,则它实际上仍然存在,只是不在时间 2 的人们的旅行记录中。这将生成一个数据框,描述每个人的选择集当一个人可以移动时,时间 t(例如,一个人对哪个加油站为她的汽车加油的考虑集),但一个加油站在建成后总是在选择集中可用。 (还要注意,虽然B在时间2没有去任何车站,但她仍然有5和6的选择集,只要B在之前的时间出现过。也就是说,如果一个人出现过,她总是在那里。这就是为什么 B 在时间 2 再次出现。)

import geopy.distance
import pandas as pd
import numpy as np
from scipy.spatial.distance import pdist, squareform

df = pd.DataFrame({        
    'time' : [1,1,2,2],                               
    'personid' : ['A','B','A','C'],      
    'station' : [5,6,7,5],
    'stationLoc' : [(122.286, 114.135),(122.284, 114.131),(122.286, 114.224),(122.286, 114.135)],     
    'personLoc' : [(122.283, 114.127),(122.283, 114.127),(122.286, 114.219),(122.286, 114.224)],                          
    })

我期望得到的是这样的:

df1 = pd.DataFrame({        
    'personid' : ['A','A','A','A','A','B','B','B','B','C'], 
    'time' : [1,1,2,2,2,1,1,2,2,2],                                    
    'stations_within_5km' : [5, 6, 5, 6, 7,  5, 6, 5, 6, 7], 
    'distance' : [Ato5, Ato6, Ato5, Ato6, Ato7,  Bto5, Bto6, Bto5, Bto6, Cto7],                
    })

我曾尝试使用循环,但发现很难实现这一想法以获得标准化的数据格式来运行回归。索尼娅的回答很好,但是当我没有说清楚我的陈述时它被发布了。对此感到抱歉,但仍然很感激。

这是用 Python 编写的。但如果 R​​ 可以更好地工作,R 代码也会受到欢迎。任何想法将不胜感激。

非常感谢!

【问题讨论】:

  • 您提到了“在时间 t 之前 AND 距离该人 5 公里范围内的所有站点”。在那种情况下,您是否在寻找两个距离?像 t 之前的一个和 t 的一个?问题和给出的输出不匹配。输出在哪里显示“t之前的距离”和“t之后的距离”?
  • 嗨,索尼娅。非常感谢您的友好回复。就是我发现前面的描述会给我一个会错过一些值的结果。抱歉之前的描述不正确。关于距离,我的意思是,所有的车站,只要它们出现过,都会被考虑到考虑集中,即使在时间 t 的原始旅行记录中没有显示车站。因此,只要人在同一个地方,在 t 之前和之后不会有两个距离同一个站点。谢谢索尼娅。 ;)
  • 请澄清您的具体问题或提供其他详细信息以准确突出您的需求。正如目前所写的那样,很难准确地说出你在问什么。

标签: python pandas scipy geopy


【解决方案1】:

使用Haversine 距离来计算两个坐标之间的距离。哈弗辛公式如下

def haversine_distance(point1,point2):
    '''
    Takes point1 and point2 and calculates the haversine distance 
    between the two points.
    
    Input Parameters
    ----------------
    point1 and point2 as latitude and longitude coordinates in tuples
    
    For e.g.,
    
    point1_coords = (49.012798, 2.550000)
    point2_coords = (-43.489399, 172.531998)
    
    Output Parameters
    -----------------
    Distance in Km
    
    Notes
    -----
    The Haversine (or great circle) distance is the angular distance 
    between two points on the surface of a sphere.
    
    '''
    lat1,lon1 = point1
    lat2,lon2 = point2

    # φ1, φ2 are the latitude of point 1 and latitude of point 2 (in radians)
    phi1 = math.radians(lat1)
    phi2 = math.radians(lat2)
    # λ1, λ2 are the longitude of point 1 and longitude of point 2 (in radians).
    lambda1 = math.radians(lon1)
    lambda2 = math.radians(lon2)

    delta_phi = phi2-phi1
    delta_lambda = lambda2-lambda1

    # Calculating a
    a = math.sin(delta_phi/2.0)**2 + math.cos(phi1)*math.cos(phi2)*math.sin(delta_lambda/2.0)**2
    
    # Calculating c
    c = 2*math.atan2(math.sqrt(a),math.sqrt(1-a))

    R = 6371  # radius of Earth in kilometers
    
    # Calculating Distance
    d = R*c # d is the distance
    
    return d

然后计算person loc到所有车站位置的距离,如下图:

df['uniq_id'] = df['time'].astype(str) +df['personid'] #Created uniq_id   

def stations_within_5km(uniqid_arr, personloc_arr, stationloc_arr, station_arr):
        distance = {}
        stations_5 = {}
        for i in range(len(personloc_arr)):
            dist = []
            stations_ = []
            for j in range(len(personloc_arr)):
                if haversine_distance(personloc_arr[i],stationloc_arr[j]) <= 5:
                    if station_arr.iloc[j] not in stations_:
                        dist.append(haversine_distance(personloc_arr[i],stationloc_arr[j]))
                        stations_.append(station_arr.iloc[j])
    
            distance[uniqid_arr.iloc[i]] = dist
            stations_5[uniqid_arr.iloc[i]] = stations_
        return distance, stations_5
    
distance, stations_5 = stations_within_5km(df['uniq_id'],df['personLoc'],df['stationLoc'],df['station'])
df['stations_within_5km'] = [stations_5[id_] for id_ in df['uniq_id']]
df['distance'] = [distance[id_] for id_ in df['uniq_id']]

输出:

    time    personid    station stationLoc  personLoc   uniq_id stations_within_5km distance
0   1   A   5   (122.286, 114.135)  (122.283, 114.127)  1A  [5, 6]  [0.580544416674241, 0.26229648732200417]
1   1   B   6   (122.284, 114.131)  (122.283, 114.127)  1B  [5, 6]  [0.580544416674241, 0.26229648732200417]
2   2   A   7   (122.286, 114.224)  (122.286, 114.219)  2A  [5, 7]  [4.98912110882879, 0.2969715135144607]
3   2   C   5   (122.286, 114.135)  (122.286, 114.224)  2C  [7]     [0.0]

计算的字段显示距离人 5 公里范围内的站点(已删除重复项)及其各自的距离。

【讨论】:

  • 你好索尼娅。感谢你的回复。看起来很好。但是,我可以知道如何根据时间和 personid 创建这个 uniq_id 吗?如果数据量增加,我们可能无法手动组合它们。谢谢。
  • 简单地结合 time 和 personid 。 df['uniq_id'] = df['time'].astype(str) +df['personid']
猜你喜欢
  • 2011-04-02
  • 2012-07-15
  • 1970-01-01
  • 2021-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-08
  • 1970-01-01
相关资源
最近更新 更多