MovingPandas解析(附有环境文件和配置细节)


前言

本文主要内容是对GitHub上的移动数据分析库 – MovingPandas 源代码进行解读,解释各部分函数功能的使用以及算法。


一、Movingpandas是什么?

MovingPandas 是在 pandas 的基础上,尤其是在 DataFrame 上,针对移动数据进行优化的数据操作分析库。
作者引入了 GeoPandas 的内容。同时在GeoPandas的基础上,加入了 trajectory 这一数据结构。基于 trajectory 作为基本单元,实现一系列轨迹数据的处理和分析。

1. MovingPandas结构

  • geometry_utils
  • overlay
  • trajectory
  • trajectory_aggregator
  • trajectory_collection
  • trajectory_generalizer
  • trajectory_plotter

上述结构中,trajectory 是基本单元,代表某一 agent 的轨迹数据。
trajectory中包括了以 DF 结构保存的数据,以及相关的属性和操作函数。
trajectory_aggregator 聚合:提取显著点、聚类、流向计算
trajectory_collection 是 trajectory 的集合。整合了所有trajectory的计算操作
trajectory_generalizer 提供了大量数据预处理操作。包括最短间距、最大间距、时间间距。D-P算法等。
trajectory_plotter 则基于 pandas 和 hvplot 提供了轨迹出图的功能。

2.文档

官方文档在这里
文档包括了一些基本的轨迹预处理和生成分析的案例以及api文档。

二、范例

在这里插入图片描述
在这里插入图片描述

2.使用

使用pd自带的数据读取即可,基于自身数据量的考量还可以使用类似chunk的方式逐步读取数据。

reader = pd.read_csv('F:/ship/apr.csv',
                    encoding= 'gb2312',iterator = True,chunksize = 100000)

为轨迹添加时间索引字段

df['t'] = pd.to_datetime(
	df['Receivedtime(UTC+8)'],
	format='%Y-%m-%d %H:%M:%S'
)
df = df.set_index('t')

利用shapely库将经纬度坐标转为点要素,设置地理要素字段,生成GeoDataFrame,设置坐标系,这边默认WGS84

geom = [Point(xy) for xy in zip(df.Lon_d,df.Lat_d)]
df = gpd.GeoDataFrame(df,geometry = geom)
df.crs = 'epsg:4326'

利用 trajectory_collection 生成轨迹集对象

traj_collection = mpd.TrajectoryCollection(df, 'MMSI',MIN_LENGTH)
print("Finished creating {} trajectories".format(len(traj_collection)))

随后针对轨迹集的操作和制图可以参考官方的示例,实例使用 binder 给出。不需要安装对应环境就可以跑实例代码了。

函数和算法解析

轨迹分段 split_by_observation_gap

def split_by_observation_gap(self, gap):
    """
    Split the trajectory into subtrajectories whenever there is a gap in the observations.

    Parameters
    ----------
    gap : datetime.timedelta
        Time gap threshold

    Returns
    -------
    list
        List of trajectories
    """
    result = []
    temp_df = self.df.copy()
    temp_df['t'] = temp_df.index
    temp_df['gap'] = temp_df['t'].diff() > gap
    temp_df['gap'] = temp_df['gap'].apply(lambda x: 1 if x else 0).cumsum()
    dfs = [group[1] for group in temp_df.groupby(temp_df['gap'])]
    for i, df in enumerate(dfs):
        df = df.drop(columns=['t', 'gap'])
        if len(df) > 1:
            result.append(Trajectory(df, '{}_{}'.format(self.id, i)))
    return result

首先生成 gap 字段,通过使用 diff() 函数计算本行记录与上一行记录中的时间字段 ‘t’ 之间的差距。如果差距大于设定的阈值 gap 则记录下数据。比方说阈值为 10 ,生成数据如下:

true   => 1  => 1
true   => 1  => 2
true   => 1  => 3
false   => 0  => 3
false   => 0  => 3
false  => 0  => 3
true   => 1  => 4
随后使用 lambda 句式设计算法,将所有 true、false 转换成数值类型 0,1 ,随后将当前行的数据变成,第一行到当前行数据的总和,得到新的行

对新行进行分组groupby,得到的结果就是利用阈值进行分段的结果。

数据稀松 MinDistanceGeneralizer


class MinDistanceGeneralizer(TrajectoryGeneralizer):
    """
    Generalizes based on distance.

    This generalization ensures that consecutive locations are at least a certain distance apart.

    tolerance : float
        Desired minimum distance between consecutive points

    Examples
    --------

    >>> mpd.MinDistanceGeneralizer(traj).generalize(tolerance=1.0)
    """

    def _generalize_traj(self, traj, tolerance):
        temp_df = traj.df.copy()
        prev_pt = temp_df.iloc[0][traj.get_geom_column_name()]
        keep_rows = [0]
        i = 0

        for index, row in temp_df.iterrows():
            pt = row[traj.get_geom_column_name()]
            if traj.is_latlon:
                dist = measure_distance_spherical(pt, prev_pt)
            else:
                dist = measure_distance_euclidean(pt, prev_pt)
            if dist >= tolerance:
                keep_rows.append(i)
                prev_pt = pt
            i += 1

        keep_rows.append(len(traj.df)-1)
        new_df = traj.df.iloc[keep_rows]
        new_traj = Trajectory(new_df, traj.id)
        return new_traj

写了很长的函数,但其实算法很简单,就是计算每个点与上一个点之间的距离,然后一点一点距离叠加,知道超过阈值,将超过阈值时的那个点作为新点,再进行叠加。最后把所有新点都提取出来就成了稀松过后的点了。

轨迹显著点提取

就不放源码了。
输入设置好的参数。设置最大距离,最小距离。最短时间间隔,最小角度等多个阈值。
将满足所有阈值的点最为显著点提取出来。
首先判断第二点与第一点的距离,如果距离大于最大距离阈值则加入显著点,
否则进入第二步,判断后续的轨迹点中,是否有小于最短距离的,
如果有进入第三步,判断该点与后一点之间距离是否超过最短时间阈值。如果是的话加入显著点,
如果不是的话进入第四步,计算与后一点之间的角度距离是否超过最小角度阈值。如果是的话加入显著点。不是的话就进入下一点

ps(其实我觉得这个叫离群点还合适一些)

轨迹点聚类

聚类算法,作者参考了论文
算法如下:

  • 设置 cellsize 将工作空间进行矩形网格划分。
  • 遍历所有点,从点 A 开始,
  • 如果 A点 附近(九宫格)存在聚类中心点 Ci,计算是否小于最大距离,默认是1×10^8 或最短距离,默认是 cellsize × 200 。遍历 8 个九宫格里的所有聚类中心点 ,如果存在的话就计算该点与 A 的距离,判断出距离最近的点 Ci ,并加入这个聚类
  • 如果不存在,则该点成为初始聚类中心点 。
  • 将所有聚类中心点中的所有点清楚,只保留所有聚类中心,重新再对所有点聚类,寻找对应的聚类中心。ps:我当时没想明白为什么要把所有点都删了,还特地去问了作者

流flow

遍历所有的轨迹,逐个轨迹点找该点最近的格网 cell 。将每条轨迹的所有点找到的最近 cell 加入到序列 (Sequence),每两个 cell 形成一个 flow ,flow的权重就是两个 cell 之间的 Sequence 条数。
在这里插入图片描述

配置过程

要是在海外就容易的多了,使用默认的软件源,再加一个conda-forge 就完事了。但是国内的话,就可能遇见网速慢甚至无法访问的问题。期间还遇到了 pip 过程中的 SSL 连接问题。

软件源

由于软件的依赖包比较多,需要同时使用到 conda 和 pip 两个安装工具。

conda

我这边 conda 使用的软件源经过测试之后比较合适的是 清华 的。

show_channel_urls: true
channel_alias: http://mirrors.tuna.tsinghua.edu.cn/anaconda
default_channels:
  - http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
  - http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free
  - http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r
  - http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/pro
  - http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/msys2
custom_channels:
  conda-forge: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
  msys2: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
  bioconda: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
  menpo: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
  pytorch: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
  simpleitk: http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
ssl_verify: true
channels:

  - conda-forge
channel_priority: flexible

将这个软件源的内容放在 C:/用户/用户名/.condarc 中即可。
也可以使用 conda config --set 的方法

pip

pip 中,经过测试,使用豆瓣和清华的都没办法完整安装,缺少依赖包,最后采用了阿里云的源

  1. 在 C:\Users\用户名\AppData\Roaming\ 这个目录下新建 pip 文件夹(如果没有的话)
  2. 在 pip 文件夹下新建文件 pip.ini
    并添加以下文字
[global]

timeout = 6000

index-url =http://mirrors.aliyun.com/pypi/simple/ 

trusted-host =mirrors.aliyun.com
  1. 其中的 trusted-host 是为了解决 pip 过程中出现的 ssl 信任问题,如果不需要可以不加。附带 SSL 的正确解决方式(我这是临时的)

创建环境

环境文件 environment.yaml

environment.yaml(金山文档)
https://kdocs.cn/l/svvKLcHJIDZP


这个是项目开发者提供的环境文件,会比较干净,但是我没测试过这个软件源能不能下全。


环境创建

得到环境文件之后
在 anaconda prompt 中,输入以下命令

conda env create -f environment.yaml 

将会创建一个名为 TrajEnv 的 python 环境。

启用环境:conda activate TrajEnv

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值