论文辅助笔记:t2vec 数据预处理

news2024/11/6 17:27:00

 1 波尔图数据

curl http://archive.ics.uci.edu/ml/machine-learning-databases/00339/train.csv.zip -o data/porto.csv.zip

这条命令使用 curl 从给定的URL下载一个名为 train.csv.zip 的压缩文件,并将其保存为 data/porto.csv.zip

unzip data/porto.csv.zip

使用 unzip 命令解压 data/porto.csv.zip 这个文件。

mv train.csv data/porto.csv

这条命令将解压后的 train.csv 文件移动(或重命名)到 data 目录下,并将其命名为 porto.csv

cd preprocessing

进入名为 preprocessing 的目录。

julia porto2h5.jl

使用 Julia 语言执行 porto2h5.jl 这个脚本。将 porto.csv 转换为 .h5 格式的命令。

julia preprocess.jl

使用 Julia 语言执行 preprocess.jl 脚本。对数据进行一些预处理的操作。

1.1 porto2h5.jl

using ArgParse
#导入 ArgParse 模块( Julia 中用于解析命令行参数的一个库)

include("utils.jl")
#导入了 utils.jl 文件

args = let s = ArgParseSettings()
    @add_arg_table s begin
        "--datapath"
            arg_type=String
            default="/home/xiucheng/Github/t2vec/data"
    end
    parse_args(s; as_symbols=true)
end
#定义 args:
#`let s = ArgParseSettings() 创建一个新的 ArgParseSettings 对象,这是用于配置命令行参数解析的。
#`@add_arg_table s begin ... end 是一个宏,用于添加参数到 s 中。
#    这里定义了一个名为 --datapath 的参数,它的类型是 String,默认值是 "/home/xiucheng/Github/t2vec/data"。
#parse_args(s; as_symbols=true) 解析命令行参数,并将结果存储在 args 中。




datapath = args[:datapath]
#从 args 中取出 --datapath 参数的值,并将其赋值给 datapath 变量。

porto2h5("$datapath/porto.csv")
#调用 porto2h5 函数,参数是 porto.csv 文件的完整路径。
#这个函数是在 utils.jl 中定义的,它的功能是将 CSV 格式的数据转换为 .h5 格式。

1.2 utils.jl

波尔图数据集:数据集笔记: Porto_UQI-LIUWJ的博客-CSDN博客

using CSV, DataFrames, HDF5
#导入三个模块:CSV、DataFrames、HDF5。
#这些模块分别用于处理CSV文件、数据框操作和HDF5文件操作。


"""
读取原始的波尔图出租车csv数据,将所有trip保存至hdf5文件中
每一个trip都是一个2*n的矩阵,n是trip的长度,每一行是经纬度
"""
function porto2h5(csvfile::String)
    df = CSV.File(csvfile) |> DataFrame
    #使用CSV模块读取CSV文件,然后将其转化为DataFrame对象。

    df = df[df.MISSING_DATA .== false, :]
    #对DataFrame df 进行筛选,去除其中 MISSING_DATA 列值为 true 的行。

    sort!(df, [:TIMESTAMP])
    #对DataFrame df 进行排序,按照 TIMESTAMP 列进行排序。

    println("Processing $(size(df, 1)) trips...")
    ## 打印一个消息,告诉用户正在处理多少条出行记录。

    h5open("../data/porto.h5", "w") do f
        #使用HDF5模块打开(或创建)一个HDF5文件,并以写入模式进行操作。
        #这个文件将保存处理后的数据。

        num, num_incompleted = 0, 0
        '''
        初始化两个变量:
            num 记录成功保存的出行记录数量
            num_incompleted 记录不完整的出行记录数量
        '''

        for trip in df.POLYLINE
            对DataFrame中的 POLYLINE 列进行遍历,每一个元素都是一条出行轨迹。

            try
                trip = Meta.parse(trip) |> eval
            catch e
                num_incompleted += 1
                continue
            end
            '''
            使用 Meta.parse 尝试解析 trip,然后使用 eval 进行求值。
                
            如果解析或求值失败,增加 num_incompleted 的计数并跳过这次循环。
            '''

            tripLength = length(trip)
            tripLength == 0 && continue
            #获取出行轨迹的长度。如果长度为0,则跳过这次循环。
            
            trip = hcat(trip...)
            #使用 hcat 函数将 trip 里的元素水平串联起来。

            num += 1
            #增加成功处理的出行记录的数量。

            f["/trips/$num"] = trip
            #在HDF5文件中保存处理后的出行轨迹。

            f["/timestamps/$num"] = collect(0:tripLength-1) * 15.0
            #在HDF5文件中保存处理后的出行轨迹。

            num % 100_000 == 0 && println("$num")
        end
        attributes(f)["num"] = num
        #在HDF5文件的属性中保存成功处理的出行记录的总数量。

        println("Incompleted trip: $num_incompleted.\nSaved $num trips.")
    end
end

1.2.1 补充说明(Mata.parse)

  • Meta.parse 是Julia中的一个函数,它可以将一个字符串解析为Julia的表达式。
    • 在上述代码中,假设 trip 原始的值是一个表示列表或数组的字符串,例如:"[(2.0, 3.0), (4.0, 5.0)]",那么使用 Meta.parse 可以将其转换为Julia中的一个真正的列表或数组。
    • 一旦你有了一个Julia表达式,你想要执行它。这就是 eval 函数的作用。
      • eval 取一个表达式作为输入,并执行它,返回执行的结果。
      • 不使用 eval,你得到的是一个描述表达式结构的 Expr 对象,而不是表达式的实际执行结果
    • 还是以上面的"[(2.0, 3.0), (4.0, 5.0)]"为例:
      • 不使用eval的话:输出类型就是Expr 表达式
        • str = "[(2.0, 3.0), (4.0, 5.0)]"
          expr = Meta.parse(str)
          println(expr)
          println(typeof(expr))
          '''
          [(2.0, 3.0), (4.0, 5.0)]
          Expr
          '''
      • 使用eval的话:输出类型就是float数组
        •    
          str = "[(2.0, 3.0), (4.0, 5.0)]"
          expr = Meta.parse(str) |> eval
          println(expr)
          println(typeof(expr))
          '''
          [(2.0, 3.0), (4.0, 5.0)]
          Vector{Tuple{Float64, Float64}}
          '''

1.2.2 hcat(trip...)补充说明

  • 在Julia中,...(也称为"splatting"操作符)用于将数组或集合的元素展开为单独的参数
    • trip 是一个包含多个元组的数组,如 [(a1, b1), (a2, b2), ...],使用 trip... 会展开这些元组,效果等同于列出它们:(a1, b1), (a2, b2), ...
  • hcat 是Julia中的一个函数,用于水平地串联数组。它将多个数组(或元组)作为输入,并将它们并排放置,形成一个新的二维数组。
trip = [(2.0, 3.0), (4.0, 5.0), (6.0, 7.0)]
result = hcat(trip...)
result
''
1×3 Matrix{Tuple{Float64, Float64}}:
 (2.0, 3.0)  (4.0, 5.0)  (6.0, 7.0)
'''

1.3 preporcess.jl

1.3.1 一些定义和命令行参数

using JSON
using DataStructures
using NearestNeighbors
using Serialization, ArgParse
'''
导入了五个模块/库:
`JSON(处理JSON数据)
`DataStructures(提供数据结构)
`NearestNeighbors(最近邻搜索)
`Serialization(序列化和反序列化对象)
`ArgParse(命令行参数解析)
'''


include("SpatialRegionTools.jl")

args = let s = ArgParseSettings()
    @add_arg_table s begin
        "--datapath"
            arg_type=String
            default="/home/xiucheng/Github/t2vec/data"
    end
    parse_args(s; as_symbols=true)
end
'''
使用 ArgParse 库定义并解析命令行参数。
定义了一个命令行参数 --datapath,其类型为字符串,并为其提供了默认值。
'''

datapath = args[:datapath]
#从解析的命令行参数中提取 datapath 参数的值,并赋值给变量 datapath

1.3.2  hyper-parameters.json相关的内容


param  = JSON.parsefile("../hyper-parameters.json")
'''
使用 JSON.parsefile 函数读取一个名为 "hyper-parameters.json" 的JSON文件,并将内容解析为Julia的数据结构。
'''


regionps = param["region"]
cityname = regionps["cityname"]
cellsize = regionps["cellsize"]
#从解析的JSON数据中提取关于空间区域的参数,包括城市名称和单元格大小。

if !isfile("$datapath/$cityname.h5")
    println("Please provide the correct hdf5 file $datapath/$cityname.h5")
    exit(1)
end
#检查是否存在一个名为 cityname.h5 的HDF5文件。如果文件不存在,打印错误信息并退出程序。


1.3.2 SpatialRegion 对象

region = SpatialRegion(cityname,
                       regionps["minlon"], regionps["minlat"],
                       regionps["maxlon"], regionps["maxlat"],
                       cellsize, cellsize,
                       regionps["minfreq"], # minfreq
                       40_000, # maxvocab_size
                       10, # k
                       4) # vocab_start
#使用提取的参数创建一个 SpatialRegion 对象(一个自定义的数据结构,在"SpatialRegionTools.jl" 文件中定义。


println("Building spatial region with:
        cityname=$(region.name),
        minlon=$(region.minlon),
        minlat=$(region.minlat),
        maxlon=$(region.maxlon),
        maxlat=$(region.maxlat),
        xstep=$(region.xstep),
        ystep=$(region.ystep),
        minfreq=$(region.minfreq)")
#打印关于创建的 SpatialRegion 对象的详细信息。

paramfile = "$datapath/$(region.name)-param-cell$(Int(cellsize))"
if isfile(paramfile)
    println("Reading parameter file from $paramfile")
    region = deserialize(paramfile)
else
    println("Creating paramter file $paramfile")
    num_out_region = makeVocab!(region, "$datapath/$cityname.h5")
    serialize(paramfile, region)
end
'''
检查参数文件是否已经存在:
如果存在,则从该文件中读取 SpatialRegion 对象的数据。
如果不存在,则创建新的参数文件,并使用 makeVocab! 函数(在 "SpatialRegionTools.jl" 中定义)来填充它,并将 SpatialRegion 对象序列化到文件中。
'''

println("Vocabulary size $(region.vocab_size) with cell size $cellsize (meters)")
#打印空间区域的词汇大小和单元格大小信息。

println("Creating training and validation datasets...")
createTrainVal(region, "$datapath/$cityname.h5", datapath, downsamplingDistort, 1_000_000, 10_000)
#打印消息并使用 createTrainVal 函数(在 "SpatialRegionTools.jl" 中定义)创建训练和验证数据集。

saveKNearestVocabs(region, datapath)
#使用 saveKNearestVocabs 函数(在 "SpatialRegionTools.jl" 中定义)保存最近的词汇信息。

 1.4 SpatialRegionTools.jl

1.4.1 导入库和SpatialRegion结构体

#module SpatialRegionTools

using StatsBase:rle
using HDF5
using DataStructures
using NearestNeighbors
using Statistics, Printf
include("utils.jl")
'''
导入库和模块:

从StatsBase库导入rle函数。
导入HDF5库,用于处理HDF5格式的数据。
导入DataStructures库,提供各种数据结构。
导入NearestNeighbors库,用于最近邻搜索。
导入Statistics和Printf模块。
包含外部文件"utils.jl"。
'''



#export SpatialRegion, makeVocab!, gps2vocab, saveKNearestVocabs,
#       trip2seq, seq2trip, createTrainVal
#列出了此模块中定义的功能和数据结构,这些功能和数据结构可以在外部使用

const UNK = 3


"""
example:
SpatialRegion的使用示例。

region = SpatialRegion("porto",
                       -8.735152, 40.953673,
                       -8.156309, 41.307945,
                       cellsize, cellsize,
                       50, # minfreq
                       50_000, # maxvocab_size
                       5, # k
                       4) # vocab_start
"""


mutable struct SpatialRegion
#声明一个可变的结构体(即其字段的值可以在创建后被更改)名为SpatialRegion。
    
    name::String #区域的名称,例如城市名。

    minlon::Float64
    minlat::Float64
    maxlon::Float64
    maxlat::Float64
    '''
    定义了一个边界框(bounding box),通过其最小和最大的经度和纬度来描述。
    这个边界框表示空间区域的地理范围。
    '''
    

    minx::Float64
    miny::Float64
    maxx::Float64
    maxy::Float64
    #边界框在某种度量空间(如米)上的表示。它表示经纬度转换为米后的坐标。


    xstep::Float64
    ystep::Float64
    #在x和y方向上的单元格大小或步长


    numx::Int
    numy::Int
    #在x和y方向上的单元格数量


    minfreq::Int
    #最小频率,某个单元格中的轨迹数量达到多少时才被认为是"热门"的
   
    maxvocab_size::Int #词汇表的最大大小
    
    k::Int
    
    cellcount #描述每个单元格被击中(即有多少轨迹通过)的次数

    hotcell::Vector{Int} #表示被标记为"热门"的单元格的列表或索引

    hotcell_kdtree #与"热门"单元格相关的k-d树结构,用于高效的空间搜索

    hotcell2vocab::Dict{Int, Int} #一个字典,将"热门"单元格映射到词汇表ID

    vocab2hotcell::Dict{Int, Int} #一个字典,将词汇表ID映射回其对应的"热门"单元格

    vocab_start::Int #词汇表开始的索引或ID

    vocab_size::Int #词汇表的大小

    built::Bool

    #构造函数
    function SpatialRegion(name::String,
                           minlon::Float64,
                           minlat::Float64,
                           maxlon::Float64,
                           maxlat::Float64,
                           xstep::Float64,
                           ystep::Float64,
                           minfreq::Int,
                           maxvocab_size::Int,
                           k::Int,
                           vocab_start::Int)
        minx, miny = lonlat2meters(minlon, minlat)
        maxx, maxy = lonlat2meters(maxlon, maxlat)
        numx = round(maxx - minx, digits=6) / xstep
        numx = convert(Int, ceil(numx))
        numy = round(maxy - miny, digits=6) / ystep
        numy = convert(Int, ceil(numy))
        new(name,
            minlon, minlat, maxlon, maxlat,
            minx, miny, maxx, maxy,
            xstep, ystep,
            numx, numy, minfreq, maxvocab_size, k,
            Accumulator{Int, Int}(),
            Int[],
            Any,
            Dict(),
            Dict(),
            vocab_start,
            vocab_start,
            false)
    end
end

1.4.2 cell id和Web Mercator坐标之间的转换

"""
将给定的Web Mercator坐标(x, y)转换为一个单元格ID
"""
function coord2cell(region::SpatialRegion, x::Float64, y::Float64)
    xoffset = round(x - region.minx, digits=6) / region.xstep
    yoffset = round(y - region.miny, digits=6) / region.ystep
    #计算x/y坐标相对于区域的最小x/y坐标的偏移量(以单元格数计)

    xoffset = convert(Int, floor(xoffset))
    yoffset = convert(Int, floor(yoffset))
    #将x/y的偏移量向下取整,以得到x/y在哪个单元格内

    yoffset * region.numx + xoffset
    #由于每行有region.numx个单元格,所以yoffset乘以region.numx得到前面所有行的单元格总数。
    #然后再加上xoffset就得到了该坐标所在单元格的ID
end
"""
将一个单元格ID转换为对应的Web Mercator坐标(x, y)
"""
function cell2coord(region::SpatialRegion, cell::Int)
    yoffset = div(cell, region.numx)
    #将单元格ID除以每行的单元格数量。结果yoffset表示这个ID对应的单元格在第几行

    xoffset = mod(cell, region.numx)
    #计算单元格ID除以每行的单元格数量的余数。结果xoffset表示这个ID对应的单元格在这一行的第几列

    y = region.miny + (yoffset + 0.5) * region.ystep
    x = region.minx + (xoffset + 0.5) * region.xstep
    '''
    计算单元格中心的y坐标。
        首先,从区域的最小y坐标开始,并加上yoffset乘以单元格的高度(即region.ystep),这样我们就得到了该单元格的上边缘的y坐标。
        然后,再加上半个单元格的高度,即(0.5 * region.ystep)
        这样就得到了该单元格中心的y坐标
    '''
    x, y
end

1.4.3 cell id 和经纬度之间的转换 

'''
将给定的GPS坐标(经度lon和纬度lat)转换为一个单元格ID
'''
function gps2cell(region::SpatialRegion, lon::Float64, lat::Float64)
    x, y = lonlat2meters(lon, lat)
    #将经度和纬度转换为Web Mercator坐标系中的x和y坐标
    
    coord2cell(region, x, y)
    #调用之前定义的coord2cell函数,将Web Mercator坐标转换为对应的单元格ID。
end

'''
将给定的单元格ID转换回其对应的GPS坐标(经度和纬度)
'''
function cell2gps(region::SpatialRegion, cell::Int)
    x, y = cell2coord(region, cell)
    #将单元格ID转换为Web Mercator坐标系中的x和y坐标

    meters2lonlat(x, y)
    #将Web Mercator坐标转换回经度和纬度
end

 1.4.4 SpatialRegion 内的相对偏移量

'''
根据提供的GPS坐标(经度lon和纬度lat)计算其在SpatialRegion区域内的相对偏移量
'''
function gps2offset(region::SpatialRegion, lon::Float64, lat::Float64)
    x, y = lonlat2meters(lon, lat)
    #将GPS坐标转换为Web Mercator坐标系下的x和y坐标

    xoffset = round(x - region.minx, digits=6) / region.xstep
    yoffset = round(y - region.miny, digits=6) / region.ystep
    #计算x/y坐标的相对偏移量

    xoffset, yoffset
end

 1.4.5 inregion 点/轨迹 是否在指定region中

'''
检查给定的经度lon和纬度lat是否在SpatialRegion区域内
'''
function inregion(region::SpatialRegion, lon::Float64, lat::Float64)
    lon >= region.minlon && lon < region.maxlon &&
    lat >= region.minlat && lat < region.maxlat
    '''
    检查经度和纬度是否位于region定义的边界之内。
        如果都在范围内,函数返回true
        否则返回false
    '''
end
'''
接受一个类型为Matrix{Float64}的trip参数,其中每列都是一个经度/纬度对
'''
function inregion(region::SpatialRegion, trip::Matrix{Float64})
    for i = 1:size(trip, 2)
        inregion(region, trip[:, i]...) || return false
    end
    true
    '''
    循环检查trip矩阵中的每一个经纬度对是否都在region区域内。
        如果所有的点都在范围内,函数返回true
        否则一旦发现某个点不在范围内就立即返回false
    '''
end

1.4.6 MakeVocab! 为热点单元格创建词汇表

"""
该函数从hdf5文件中读取轨迹,统计每个单元格中的点数,并为最常出现的单元格建立一个词汇表
"""
function makeVocab!(region::SpatialRegion, trjfile::String)
    region.cellcount = Accumulator{Int, Int}()
    #为region初始化一个累加器,用于统计每个单元格中的点数

    num_out_region = 0
    #初始化一个变量来计数不在区域内的点

    h5open(trjfile, "r") do f
        #打开hdf5文件进行读取。

        num = read(attributes(f)["num"])
        #读取hdf5文件中的属性“num”,表示有多少轨迹。

        for i = 1:num
            trip = read(f["/trips/$i"])
            #遍历每个轨迹,并读取其数据

            for p = 1:size(trip, 2)
                lon, lat = trip[:, p]
                #对于每个轨迹,遍历其所有的点。

                if !inregion(region, lon, lat)
                    num_out_region += 1
                    #如果点不在region内,则增加计数。
                else
                    cell = gps2cell(region, lon, lat)
                    push!(region.cellcount, cell)
                    #否则,将该点转换为一个单元格,并在cellcount累加器中增加该单元格的计数
                end
            end

            i % 100_000 == 0 && println("Processed $i trips")
            #每处理100,000个轨迹,打印一个消息
            
        end
    end
    
    max_num_hotcells = min(region.maxvocab_size, length(region.cellcount))
    #确定热点单元格的最大数量。

    topcellcount = sort(collect(region.cellcount), by=last, rev=true)[1:max_num_hotcells]
    #对单元格按其计数排序,并选择前max_num_hotcells个。

    println("Cell count at max_num_hotcells:$(max_num_hotcells) is $(last(topcellcount[end]))")
    
    region.hotcell = filter(p -> last(p) >= region.minfreq, topcellcount) .|> first
    #筛选那些计数大于或等于minfreq的热点单元格。

    region.hotcell2vocab = Dict([(cell, i-1+region.vocab_start)
        for (i, cell) in enumerate(region.hotcell)])
    #为每个热点单元格构建一个到词汇ID的映射。

    
    region.vocab2hotcell = Dict(last(p) => first(p) for p in region.hotcell2vocab)
    #构建从词汇ID到热点单元格的反向映射。

    region.vocab_size = region.vocab_start + length(region.hotcell)
    #更新词汇的大小。

    coord = hcat(map(x->collect(cell2coord(region, x)), region.hotcell)...)
    #为热点单元格获取其坐标。

    region.hotcell_kdtree = KDTree(coord)
    #使用这些坐标构建一个KDTree,便于后续的搜索。

    region.built = true
    #标记region已构建。

    num_out_region
end
  •  push!(region.cellcount, cell) 这行代码中的 push! 是Julia中的一个函数,它用于将一个元素添加到集合的末尾。
    • 在这里,它正在将cell值添加到region.cellcount中。
  • 通常情况下,push!函数是用于数组的。
    • 然而,在这个上下文中,region.cellcount是一个Accumulator对象
    • Accumulator是一个特殊的数据结构,通常用于计数,其中键是要计数的项,值是相应的计数。
  • 所以,push!(region.cellcount, cell) 这行代码在做以下事情:

     
    • 检查cell是否已经作为键存在于region.cellcount中。
      • 如果cell已存在,那么其对应的计数值会增加1。
      • 如果cell不存在,那么它将被添加到Accumulator中,并且其计数被设置为1。

 1.4.7 找到最近的热点单元格

'''
从给定的单元格cell中找到k个最近的热点单元格
'''
function knearestHotcells(region::SpatialRegion, cell::Int, k::Int)
    @assert region.built == true "Build index for region first"
    #首先确保region的索引已经被构建。如果没有,函数会抛出一个错误。

    coord = cell2coord(region, cell) |> collect
    #将给定的单元格转换为其对应的坐标

    idxs, dists = knn(region.hotcell_kdtree, coord, k)
    #使用KDTree进行k最近邻搜索来找到k个最近的热点单元格的索引和到给定单元格的距离。

    region.hotcell[idxs], dists
    #返回找到的热点单元格和它们到给定单元格的距离。
end

'''
找到给定单元格cell的最近的热点单元格
'''
function nearestHotcell(region::SpatialRegion, cell::Int)
    @assert region.built == true "Build index for region first"
    #首先确保region的索引已经被构建

    hotcell, _ = knearestHotcells(region, cell, 1)
    #使用knearestHotcells函数找到单一最近的热点单元格。

    hotcell[1]
    #返回找到的热点单元格
end

1.4.8 为每个词汇找到k个最近的词汇和相应的距离

"""
为每个词汇找到k个最近的词汇和相应的距离,并将它们保存到一个hdf5文件中
"""
function saveKNearestVocabs(region::SpatialRegion, datapath::String)
    V = zeros(Int, region.k, region.vocab_size)
    D = zeros(Float64, region.k, region.vocab_size)
    '''
    定义两个矩阵V和D。
    V矩阵存储每个词汇的k个最近词汇的索引,而D矩阵存储与这些词汇的相应距离。
    '''


    for vocab in 0:region.vocab_start-1
        V[:, vocab+1] .= vocab
        D[:, vocab+1] .= 0.0
    end
    #使用一个for循环初始化矩阵V和D的前几列(从0到region.vocab_start-1)。
    #在这些列中,每个词汇的最近词汇被认为是它自己,距离是0

    for vocab in region.vocab_start:region.vocab_size-1
        cell = region.vocab2hotcell[vocab]
        kcells, dists = knearestHotcells(region, cell, region.k)
        kvocabs = map(x->region.hotcell2vocab[x], kcells)
        V[:, vocab+1] .= kvocabs
        D[:, vocab+1] .= dists
    end
    '''
    对于region.vocab_start到region.vocab_size-1的每一个词汇,使用knearestHotcells函数找到其最近的单元格和距离。
    然后将这些单元格转换为相应的词汇,并将结果存储在V和D中。
    '''

    cellsize = Int(region.xstep)
    file = joinpath(datapath, region.name * "-vocab-dist-cell$(cellsize).h5")
    #定义文件名。文件名是根据region.name、单元格的大小(region.xstep)和"-vocab-dist-cell"构建的。
    
    h5open(file, "w") do f
        f["V"], f["D"] = V, D
    #使用h5open函数将V和D矩阵保存到hdf5文件中。

    end
    println("Saved cell distance into $file")
    nothing
    '''
    打印一条消息,说明距离已经被保存到文件中。

    函数返回nothing,表示这个函数不返回任何值。
    '''
end

 1.4.9 cell2vocab 单元格转换到词汇ID

function cell2vocab(region::SpatialRegion, cell::Int)
    @assert region.built == true "Build index for region first"
    if haskey(region.hotcell2vocab, cell)
        return region.hotcell2vocab[cell]
    else
        hotcell = nearestHotcell(region, cell)
        return region.hotcell2vocab[hotcell]
    end
    '''
    如果单元格是热门单元格,则直接从hotcell2vocab字典中返回其词汇ID。
    
    如果不是热门单元格,则使用nearestHotcell函数找到其最近的热门单元格,并返回该热门单元格的词汇ID。
    '''
end

 1.4.10 gps2vocab gps坐标转换到词汇ID

function gps2vocab(region::SpatialRegion, lon::Float64, lat::Float64)
    inregion(region, lon, lat) || return UNK
    #首先,检查GPS坐标是否在区域内。如果不在,就返回UNK

    cell2vocab(region, gps2cell(region, lon, lat))
    #如果GPS坐标在区域内,就使用cell2vocab函数和gps2cell函数将GPS坐标转换为单元格ID,然后将单元格ID转换为词汇ID
end

1.4.11 trip2seq seq2trip  trip和词汇序列互转

'''
将一个trip(一系列GPS坐标)转换为一个词汇序列
'''
function trip2seq(region::SpatialRegion, trip::Matrix{Float64})
    seq = Int[]
    for i in 1:size(trip, 2)
        lon, lat = trip[:, i]
        push!(seq, gps2vocab(region, lon, lat))
    end
    #对于trip中的每个GPS点,使用gps2vocab函数将其转换为一个词汇ID,并将这些ID添加到seq数组中
    
    seq |> rle |> first
    #使用rle函数(对序列进行运行长度编码)处理seq,并返回结果中的第一个元素
end
'''
此函数接受一个整数向量seq,其中每个整数是一个词汇ID,并将其转换回相应的GPS坐标轨迹。
'''
function seq2trip(region::SpatialRegion, seq::Vector{Int})
    trip = zeros(Float64, 2, length(seq))
    for i = 1:length(seq)
        cell = get(region.vocab2hotcell, seq[i], -1)
        cell == -1 && error("i=$i is out of vocabulary")
        lon, lat = cell2gps(region, cell)
        #对于每个词汇ID,它首先查找与之关联的单元格ID(从vocab2hotcell),然后使用cell2gps转换为GPS坐标

        trip[:, i] = [lon, lat]
    end
    trip
    #结果是一个二维矩阵,其中每列是一个GPS点的坐标
end

1.4.12 tripmeta, seqmeta 计算元数据

'''
从一个给定的轨迹中计算元数据,特别是轨迹的中心点坐标
'''
function tripmeta(region::SpatialRegion, trip::Matrix{Float64})
    mins, maxs = minimum(trip, dims=2), maximum(trip, dims=2)
    #计算轨迹中所有点的最小和最大坐标

    centroids = mins + (maxs - mins) / 2
    #计算并返回这些坐标范围的中点

    gps2offset(region, centroids...)
    #使用gps2offset将中心点转换为与区域关联的偏移量
end
'''
接受一个词汇序列并返回该序列对应的轨迹的中心点坐标
'''
function seqmeta(region::SpatialRegion, seq::Vector{Int})
    trip = seq2trip(region, seq)
    #使用seq2trip将词汇序列转换为一个GPS坐标轨迹

    tripmeta(region, trip)
    #使用tripmeta计算并返回轨迹的中心点坐标
end

1 .4.13

function createTrainVal(region::SpatialRegion,
                        trjfile::String,
                        datapath::String,
                        injectnoise::Function,
                        ntrain::Int,
                        nval::Int;
                        nsplit=5,
                        min_length=20,
                        max_length=100)
    seq2str(seq) = join(map(string, seq), " ") * "\n"
    #定义一个seq2str的局部函数,将序列转化为一个由空格分隔的字符串

    h5open(trjfile, "r") do f
        #使用h5open打开h5格式的轨迹文件



        trainsrc = open("$datapath/train.src", "w")
        traintrg = open("$datapath/train.trg", "w")
        trainmta = open("$datapath/train.mta", "w")

        validsrc = open("$datapath/val.src", "w")
        validtrg = open("$datapath/val.trg", "w")
        validmta = open("$datapath/val.mta", "w")
        #为训练和验证数据集创建文件,包括源数据、目标数据和元数据文件



        for i = 1:ntrain+nval
             # 遍历h5文件中的轨迹

            trip = f["/trips/$i"] |> read
            # 从h5文件中读取单个轨迹

            min_length <= size(trip, 2) <= max_length || continue
            #检查轨迹长度是否在指定的范围内


            trg = trip2seq(region, trip) |> seq2str
            #将轨迹转化为目标序列并格式化

            meta = tripmeta(region, trip)
            mta = @sprintf "%.2f %.2f\n" meta[1] meta[2]
            # 计算轨迹的元数据并格式化

            noisetrips = injectnoise(trip, nsplit)
            # 使用injectnoise函数在原始轨迹上生成噪声轨迹

            srcio, trgio, mtaio = i <= ntrain ? (trainsrc, traintrg, trainmta) : (validsrc, validtrg, validmta)
            ## 根据当前轨迹的索引,确定是训练数据还是验证数据

            for noisetrip in noisetrips
                # 对于每个噪声轨迹

                src = trip2seq(region, noisetrip) |> seq2str
                ## 转化噪声轨迹为源序列并格式化

                write(srcio, src)
                write(trgio, trg)
                write(mtaio, mta)
                ## 将源序列、目标序列和元数据写入相应的文件
            end
            i % 100_000 == 0 && println("Scaned $i trips...")
            #i >= 8_000 && break
        end
        close(trainsrc), close(traintrg), close(trainmta), close(validsrc), close(validtrg), close(validmta)
    end
    nothing
end

 1.4.13 保存/加载空间区域

'''
将一个空间区域的参数保存到文件
'''
function saveregion(region::SpatialRegion, paramfile::String)
    save(paramfile,
          # JLD cannot handle Accumulator correctly
          #"cellcount", region.cellcount.map,
          "hotcell", region.hotcell,
          "hotcell2vocab", region.hotcell2vocab,
          "vocab2hotcell", region.vocab2hotcell,
          "hotcell_kdtree", region.hotcell_kdtree,
          "vocab_size", region.vocab_size)
    nothing
end


'''
从文件中加载一个空间区域的参数,并更新给定的空间区域对象
'''
function loadregion!(region::SpatialRegion, paramfile::String)
    jldopen(paramfile, "r") do f
        #region.cellcount = read(f, "cellcount")
        region.hotcell = read(f, "hotcell")
        region.hotcell2vocab = read(f, "hotcell2vocab")
        region.vocab2hotcell = read(f, "vocab2hotcell")
        region.hotcell_kdtree = read(f, "hotcell_kdtree")
        region.vocab_size = read(f, "vocab_size")
        region.built = true
    end
    nothing
end

2 其他城市

要处理一个新城市的数据,你需要按照特定的格式提供一个 hdf5 输入文件,并设置适当的超参数

  • 提供 hdf5 输入
    • 为目标城市提供一个名为 t2vec/data/cityname.h5 的 hdf5 文件,其中 cityname 是你要处理的城市的名称
    • hdf5 输入的格式
      • attributes(f)["num"]:存储的是轨迹的总数。
      • f["/trips/i"]:存储的是第 i 条轨迹的 GPS 数据,它是一个 2xn 的矩阵。第一行是经度序列,第二行是纬度序列。
      • f["/timestamps/i"]:存储的是第 i 条轨迹的时间戳序列,它是一个 n 维的向量。
  • 设置超参数
    • t2vec/hyper-parameters.json 文件中,需要为目标城市设置适当的超参数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1115199.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python实现矩阵转置

使用列表推导式实现矩阵转置 matrix [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] print([[row[i] for row in matrix]for i in range(4)])使用内置函数来实现矩阵转置 matrix [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] print(list(map(list, zip(*matrix))))使用…

softplc windows 安装测试

下载 .NET 6.0 (Linux、macOS 和 Windows) 安装后 在这里 The command could not be loaded, possibly because: * You intended to execute a .NET application: The application restore does not exist. * You intended to execute a .NET SDK command: No…

如何利用IP定位技术进行反欺诈?

网络欺诈风险是指在互联网和数字领域中&#xff0c;存在各种类型的欺诈活动&#xff0c;旨在欺骗个人、组织或系统以获得非法获益。以下是一些常见的网络欺诈风险类型&#xff1a; 身份盗用&#xff1a;这是一种欺诈行为&#xff0c;涉及盗取他人的个人身份信息&#xff0c;如姓…

基于Java的汽车维修预约管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

电度表和电能表是一样的吗?

电度表和电能表都是用于测量电能的仪表&#xff0c;但它们之间存在一些区别。接下来&#xff0c;小编来为大家介绍下电度表和电能表的区别有哪些吧&#xff0c;一起来看下&#xff01; 电度表是传统的机械式电能表&#xff0c;它通过测量电流和电压的乘积来计算电能&#xff0c…

数字化营销系统的重点功能?利用数字化营销系统为企业降本增效?

如今&#xff0c;越来越多的企业开始关注数字化营销&#xff0c;并利用数字化手段推动新的营销方式、模式和策划。数字化营销的重要性不言而喻&#xff0c;下面我们来了解一下数字化营销的优势有哪些&#xff1f; 1. 数字化营销可以更大程度地为用户提供足够的信息。 通过商品…

【数据结构初阶】九、排序的讲解和实现(直接插入 \ 希尔 \ 直接选择 \ 堆 \ 冒泡 -- C语言)

相关代码gitee自取&#xff1a; C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 【数据结构初阶】八、非线性表里的二叉树&#xff08;二叉树的实现 -- C语言链式结构&#xff09;-CSDN博客 排序 排序的概念 所谓排序&#xff0c;就是使一串记录&#xff0c;按照…

[人工智能-综述-12]:第九届全球软件大会(南京)有感 -1-程序员通过大模型增强自身软件研发效率的同时,也在砸自己的饭碗

目录 前言&#xff1a; 一、什么是软件工程 1.1 什么软件工程 1.2 影响软件开发效能的三大因素 1.3 AI大模型是如何提升软件工程全过程效率的 二、AI大模型如何提升软件项目管理效率 2.1 概述 2.2 案例或工具 三、AI大模型如何提升软件开发工具的效率 3.1 概述 3.2 …

python使用grpc

proto 首先编写proto&#xff0c;也可以根据对象生成proto syntax "proto3";package text;service TextSender{rpc Send(Text) returns (SendResponse);rpc Resend(Text) returns (SendResponse); }message Text{string text 1; }message SendResponse{bool suce…

kali linux

一、Kali Linux文件系统 二、终端窗口基础 清除命令行 新建终端 TAB自动补全 关闭终端窗口 重启/关闭 最近使用的命令 <>重定向 tmux终端窗口 开始tmux Tmux快捷键 三、管理用户和组 用户命令 Kali Linux操作系统安全命令 密码设置 切换用户 查看当前用户…

为什么MySQL使用B+树索引,而不使用其他作为索引呢?

索引介绍 索引是一种用于快速查询和检索数据的数据结构&#xff0c;其本质可以看成一种排序号的数据结构。 索引的作用相当于书的目录。打个比方&#xff1a;在查字典的时候&#xff0c;如果没有目录&#xff0c;那我们就只能一页一页地去查&#xff0c;速度很慢。如果有目录…

怎么把图片转换成ico图标文件?

环境&#xff1a; Win10 专业版 问题描述&#xff1a; 怎么把图片转换成ico图标文件 解决方案&#xff1a; 要将图片转换为 ico 图标文件&#xff0c;可以使用以下几种方法&#xff1a; 方法 1&#xff1a;使用在线转换器 1.访问在线 ico 转换器&#xff0c;例如&#xf…

others-AppLovin广告接入

title: others-AppLovin广告接入 categories: Others tags: [广告, AppLovin] date: 2023-10-20 10:07:01 comments: false mathjax: true toc: true others-AppLovin广告接入 前篇 官方 - https://www.applovin.com/ Android sdk - https://github.com/AppLovin/AppLovin-MAX…

03-Android App logger策略

背景 经常会为log定位而烦恼。比如&#xff1a;同一个类&#xff0c;一样的log输出&#xff0c;无法定位到Log输出的行。 方案 1.java StackTraceElement 通过java StackTraceElement获取类名&#xff0c;以及log输出行 2. 具体实现 NonNullprivate static String getSour…

基于金枪鱼群优化的BP神经网络(分类应用) - 附代码

基于金枪鱼群优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于金枪鱼群优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.金枪鱼群优化BP神经网络3.1 BP神经网络参数设置3.2 金枪鱼群算法应用 4.测试结果…

FreeRTOS入门教程(互斥锁的概念和函数使用)

文章目录 前言一、互斥锁的概念二、互斥锁相关函数三、使用互斥锁完成同步四、FreeRTOS中互斥锁存在的问题五、优先级反转和优先级继承六、死锁七、递归锁总结 前言 本篇文章带大家学习什么是互斥锁&#xff0c;并且学习一下互斥锁中一些函数的使用方法。 一、互斥锁的概念 …

修改java项目启动后在jps展示的名称

文章目录 问题在服务器上启动jar包的时候,通过jps查看java进程只展示个 jar解决,指定jar包的全路径jps查看maven打包修改jar名称 问题在服务器上启动jar包的时候,通过jps查看java进程只展示个 jar 解决,指定jar包的全路径 java -jar /root/test/aaa.jarjps查看 494976 aaa.ja…

OpenCV实现物体尺寸的测量

一 &#xff0c;项目分析 物体尺寸测量的思路是找一个确定尺寸的物体作为参照物&#xff0c;根据已知的计算未知物体尺寸。 如下图所示&#xff0c;绿色的板子尺寸为220*300&#xff08;单位&#xff1a;毫米&#xff09;&#xff0c;通过程序计算白色纸片的长度。 主要是通过…

DatenLord前沿技术分享 No.38

达坦科技专注于打造新一代开源跨云存储平台DatenLord&#xff0c;通过软硬件深度融合的方式打通云云壁垒&#xff0c;致力于解决多云架构、多数据中心场景下异构存储、数据统一管理需求等问题&#xff0c;以满足不同行业客户对海量数据跨云、跨数据中心高性能访问的需求。在本周…