【问题标题】:Calculating distance and velocity between time ordered coordinates计算时间有序坐标之间的距离和速度
【发布时间】:2018-07-03 22:41:18
【问题描述】:

我有一个 csv,其中包含在给定时间 (timestamp) 由id 字段表示的给定用户的位置 (longitude)。我需要为每个用户计算一个点和连续点之间的距离和速度。例如,对于 ID 1,我需要找到点 1 和点 2、点 2 和点 3、点 3 和点 4 之间的距离和速度,等等。鉴于我正在使用地球上的坐标,我了解 Haversine 度量将用于距离计算,但是,鉴于我的问题的时间和用户顺序方面,我不确定如何迭代我的文件。鉴于此,使用python,我如何遍历我的文件以按用户和时间对事件进行排序,然后计算每个事件之间的距离和速度?

理想情况下,输出将是第二个 csv,类似于:ID#, start_time, start_location, end_time, end_location, distance, velocity

下面的示例数据:

ID,timestamp,latitude,longitude
3,6/9/2017 22:20,38.7953326,77.0088833  
1,5/5/2017 13:10,38.8890106,77.0500613
2,2/10/2017 16:23,40.7482494,73.9841913
1,5/5/2017 12:35,38.9206015,77.2223287
3,6/10/2017 10:00,42.3662109,71.0209426
1,5/5/2017 20:00,38.8974155,77.0368333
2,2/10/2017 7:30,38.8514261,77.0422981
3,6/9/2017 10:20,38.9173461,77.2225527
2,2/10/2017 19:51,40.7828687,73.9675438
3,6/10/2017 6:42,38.9542676,77.4496951
1,5/5/2017 16:35,38.8728748,77.0077629
2,2/10/2017 10:00,40.7769311,73.8761546

【问题讨论】:

    标签: python gps distance haversine


    【解决方案1】:

    看来你可以使用pandas 的魔力。

    读取数据

    使用 read_csv() 函数从 csv 文件创建 pandas dataframe 很容易:

    import pandas as pd
    df = pd.read_csv(filename)
    

    根据您的示例数据,这将创建以下dataframe

        ID        timestamp   latitude  longitude
    0    3   6/9/2017 22:20  38.795333  77.008883
    1    1   5/5/2017 13:10  38.889011  77.050061
    2    2  2/10/2017 16:23  40.748249  73.984191
    3    1   5/5/2017 12:35  38.920602  77.222329
    4    3  6/10/2017 10:00  42.366211  71.020943
    5    1   5/5/2017 20:00  38.897416  77.036833
    6    2   2/10/2017 7:30  38.851426  77.042298
    7    3   6/9/2017 10:20  38.917346  77.222553
    8    2  2/10/2017 19:51  40.782869  73.967544
    9    3   6/10/2017 6:42  38.954268  77.449695
    10   1   5/5/2017 16:35  38.872875  77.007763
    11   2  2/10/2017 10:00  40.776931  73.876155
    

    转换时间戳列

    Pandas(和一般的 Python)具有广泛的日期和时间操作库。但首先,您需要通过将时间戳列(字符串)转换为日期时间对象来准备数据。我假设您的数据在 format "MM/DD/YYYY" 中(因为您没有指定)。

    df['timestamp'] = pd.to_datetime(df['timestamp'], format='%m/%d/%Y %H:%M')
    

    辅助函数

    您将不得不定义一些函数来计算距离和速度。 Haversine距离函数改编自this answer

    from math import sin, cos, sqrt, atan2, radians
    
    def getDistanceFromLatLonInKm(lat1,lon1,lat2,lon2):
        R = 6371 # Radius of the earth in km
        dLat = radians(lat2-lat1)
        dLon = radians(lon2-lon1)
        rLat1 = radians(lat1)
        rLat2 = radians(lat2)
        a = sin(dLat/2) * sin(dLat/2) + cos(rLat1) * cos(rLat2) * sin(dLon/2) * sin(dLon/2) 
        c = 2 * atan2(sqrt(a), sqrt(1-a))
        d = R * c # Distance in km
        return d
    
    def calc_velocity(dist_km, time_start, time_end):
        """Return 0 if time_start == time_end, avoid dividing by 0"""
        return dist_km / (time_end - time_start).seconds if time_end > time_start else 0
    

    制作一些中间变量

    我们想要计算每一行的Haversine 函数,但我们需要第一行中每个组的一些信息。幸运的是,pandas 使用 sort_values()groupby()transform() 让这一切变得简单。

    以下代码创建了 3 个新列,每个 ID 的初始纬度、经度和时间各一列。

    # First sort by ID and timestamp:
    df = df.sort_values(by=['ID', 'timestamp'])
    
    # Group the sorted dataframe by ID, and grab the initial value for lat, lon, and time.
    df['lat0'] = df.groupby('ID')['latitude'].transform(lambda x: x.iat[0])
    df['lon0'] = df.groupby('ID')['longitude'].transform(lambda x: x.iat[0])
    df['t0'] = df.groupby('ID')['timestamp'].transform(lambda x: x.iat[0])
    

    应用函数

    # create a new column for distance
    df['dist_km'] = df.apply(
        lambda row: getDistanceFromLatLonInKm(
            lat1=row['latitude'],
            lon1=row['longitude'],
            lat2=row['lat0'],
            lon2=row['lon0']
        ),
        axis=1
    )
    
    # create a new column for velocity
    df['velocity_kmps'] = df.apply(
        lambda row: calc_velocity(
            dist_km=row['dist_km'],
            time_start=row['t0'],
            time_end=row['timestamp']
        ),
        axis=1
    )
    

    结果

    >>> print(df[['ID', 'timestamp', 'latitude', 'longitude', 'dist_km', 'velocity_kmps']])
    
        ID           timestamp   latitude  longitude     dist_km  velocity_kmps
    3    1 2017-05-05 12:35:00  38.920602  77.222329    0.000000       0.000000
    1    1 2017-05-05 13:10:00  38.889011  77.050061   15.314742       0.007293
    10   1 2017-05-05 16:35:00  38.872875  77.007763   19.312148       0.001341
    5    1 2017-05-05 20:00:00  38.897416  77.036833   16.255868       0.000609
    6    2 2017-02-10 07:30:00  38.851426  77.042298    0.000000       0.000000
    11   2 2017-02-10 10:00:00  40.776931  73.876155  344.880549       0.038320
    2    2 2017-02-10 16:23:00  40.748249  73.984191  335.727502       0.010498
    8    2 2017-02-10 19:51:00  40.782869  73.967544  339.206320       0.007629
    7    3 2017-06-09 10:20:00  38.917346  77.222553    0.000000       0.000000
    0    3 2017-06-09 22:20:00  38.795333  77.008883   22.942974       0.000531
    9    3 2017-06-10 06:42:00  38.954268  77.449695   20.070609       0.000274
    4    3 2017-06-10 10:00:00  42.366211  71.020943  648.450485       0.007611
    

    从这里开始,我将让您弄清楚如何获取每个 ID 的最后一个条目。

    【讨论】:

    • 这看起来应该可以解决问题。几个快速的问题。首先,是当前点和初始点(最早出现的时间)之间的距离,还是前一个点的距离?其次,可以通过将dist_km / (time_end - time_start).second更改为.hour来将kmps更改为kmph?
    • 对于您的第一个问题,它是从初始点开始的。第二个问题:我认为是这样,但您应该查看文档。你自己做一些编码/调试不会有什么坏处。
    • 好的,主要的问题/问题是不仅要找到当前点和初始点之间的距离和速度,还要找到当前点和前一个(或下一个)点之间的距离和速度,这样我就可以找到点 1/2、点 2/3、点 3/4 等之间的距离和速度。您知道如何实现吗?
    • SO 不是免费的代码编写服务。我已经给了你很多开始。我相信您可以进行研究并从这里获取。没有其他用户愿意回应你(也许我也不应该)。玩这个,看看你能走多远。如果您遇到问题,请尝试发布一个新的特定问题。祝你好运。相关:How much research effort is expected of Stack Overflow users?
    • 我不是要求免费编写代码,所以你不必如此居高临下,保罗。我只是在寻求帮助。我了解我的问题,以及我想如何尝试解决它,但是在代码中实现它是我遇到问题的地方,因为我不是最精通的程序员。我了解您提供的解决方案,并为此感谢您。
    猜你喜欢
    • 2011-09-16
    • 2021-09-08
    • 2021-04-05
    • 1970-01-01
    • 1970-01-01
    • 2020-06-02
    • 1970-01-01
    • 2022-01-08
    • 1970-01-01
    相关资源
    最近更新 更多