Open Source Datasets#

Attention

在1.0.0版本发布前,当前文档的内容可能会发生变化。

TrajDL提供了一个公开数据集接口,可以帮助用户管理公开数据集,如Gowalla, porto等。用户可以通过这类接口快速下载原始数据集,TrajDL会构建缓存,提升后续数据集的加载效率。

下面我们会介绍这些公开数据集及其使用方法。

1.  Gowalla数据集#

Gowalla 是一个基于位置的社交网络网站,用户通过签到打卡的方式分享他们的位置。用户的每次签到都会记录其签到的时刻(Timestamp)、地点(Location)和GPS位置(Point),其中每个位置都唯一的位置id。这样,在一段时间内的同一个用户的签到地点就可以构成一段位置序列数据。我们可以通过下面的方式加载原始的Gowalla数据:

from trajdl.datasets.open_source.conf import GowallaDataset

# 加载Gowalla数据集的元信息,打印元信息
gowalla = GowallaDataset()
print(gowalla)

# 以polars DataFrame的类型加载数据
df_gowalla = gowalla.load(return_as="pl")
df_gowalla.head()
GowallaDataset(dataset_name='gowalla', size=105470044, url='https://snap.stanford.edu/data/loc-gowalla_totalCheckins.txt.gz', sha256_original='c1c3e19effba649b6c89aeab3c1f9459fad88cfdc2b460fc70fd54e295d83ea0', mmh3_cache='8a2eb882146b2ab51774b4bf8b1432dc')
load dataset: gowalla
shape: (5, 5)
user_idcheck_in_timelatlngloc_id
strdatetime[μs]f64f64str
"0"2010-10-19 23:55:2730.235909-97.79514"22847"
"0"2010-10-18 22:17:4330.269103-97.749395"420315"
"0"2010-10-17 23:42:0330.255731-97.763386"316637"
"0"2010-10-17 19:26:0530.263418-97.757597"16516"
"0"2010-10-16 18:50:4230.274292-97.740523"5535878"

通过运行上述命令可以看到TrajDL定义的公开数据集的信息,包含数据名、数据大小、下载链接,SHA-256等信息。

return_as参数可以控制load方法返回的数据类型,可以是polars.DataFrame(默认,适合高性能数据处理的场景), pandas.DataFrame(适合于现有科学计算和数据分析工具兼容的场景),pyarrow.Table(适合高效的数据存储、读取和传输的场景)。三者之间可以通过简单的命令进行转换,用户根据自己的需求可自行选择返回的类型。

2.  Porto数据集#

Porto数据集收集了在葡萄牙波尔图市运行的442辆出租车的全年轨迹(2013年7月1日至2014年6月30日)。我们可以通过下面的方式加载原始的Porto数据集:

from trajdl.datasets.open_source.conf import PortoDataset

# 加载Porto数据集元信息并打印
porto = PortoDataset()
print(porto)

# 以polars.DataFrame的形式返回,展示前两行
df_porto = porto.load(return_as="pl")
df_porto.head(2)
PortoDataset(dataset_name='porto', size=534065916, url='http://localhost:7077/taxi%2Bservice%2Btrajectory%2Bprediction%2Bchallenge%2Becml%2Bpkdd%2B2015.zip', sha256_original='a33e2a5e145607ae2bad0db5d21b7548c88b7e0f9db1ce15839f24c4c61f8c76', mmh3_cache='5ef83abb3cf649583f28b80f16e1f4a7')
load dataset: porto
shape: (2, 9)
TRIP_IDCALL_TYPEORIGIN_CALLORIGIN_STANDTAXI_IDTIMESTAMPDAY_TYPEMISSING_DATAPOLYLINE
strstri64i64i64i64strboollist[array[f64, 2]]
"1372636858620000589""C"nullnull200005891372636858"A"false[[-8.618643, 41.141412], [-8.618499, 41.141376], … [-8.630838, 41.154489]]
"1372637303620000596""B"null7200005961372637303"A"false[[-8.639847, 41.159826], [-8.640351, 41.159871], … [-8.66574, 41.170671]]

该原始数据各字段的含义如下:

列名

数据类型

含义

TRIP_ID

String

每次行程的唯一标识

CALL_TYPE

Char

标识此服务的方式,为如下三者之一:
  1. “A”: 该行程从中心调度
  2. “B”: 该行程要求特定站点的出租车
  3. “C”: “其他”

ORIGIN_CALL

Integer

每个电话号码的唯一标识符,该电话号码至少请求过一次服务。如果CALL_TYPE=’A’,则表示行程的客户

ORIGIN_STAND

Integer

出租车站的唯一标识。如果CALL_TYPE=”B”,则表示行程的起点

TAXI_ID

Integer

每个行程出租车司机的唯一标识

TIMESTAMP

Integer

Unix时间戳,以秒为单位,表示该行程的开始时间

DAYTYPE

char

该行程开始时的日期类型,为如下三者之一:
  1. “B”: 该形成在假日或其他特殊日期开始
  2. “C”: 该行程在类型B的前一天开始
  3. “C”: 其他(正常日、工作日、周末)

MISSING_DATE

Boolean

当形成采集到的GPS数据流完整时,该值为FALSE;否则为TRUE

POLYLINE

String

GPS坐标列表字符串(WGS84坐标系),字符串的开头和结尾用”[“和”]”标识

3.  自定义数据集管理#

为了避开部分区域的网络限制,TrajDL支持用户自己下载公开数据集后通过接口加载到TrajDL中。TrajDL提供了3种方法来实现这个需求,下面我们会以Gowalla数据集为例介绍这几种方法。

3.1.  方法1,修改环境变量#

用户可以自行寻找下载速度较快的网站,并获得原始数据集的下载链接,比如https://xxxxxx/datasets/loc-gowalla_totalCheckins.txt.gz。每个公开数据集的url都有一个环境变量可以设置,GowallaDataset的环境变量名是GOWALLA_URL,可以通过下面的命令设置环境变量:

export GOWALLA_URL=https://xxxxxx/datasets/loc-gowalla_totalCheckins.txt.gz

然后再运行TrajDL相关的代码,比如

from trajdl.datasets.open_source.conf import GowallaDataset

ds = GowallaDataset()
ds.load(return_as="pd").head()

TrajDL会读取环境变量并自动设置URL为环境变量里面指定的URL

3.2.  方法2,修改数据集的默认url#

和上面的方法差不多,只不过URL是配置在代码内部。

from trajdl.datasets.open_source.conf import GowallaDataset

gowalla_url = "https://xxxxxx/datasets/loc-gowalla_totalCheckins.txt.gz"

ds = GowallaDataset()
ds.set_url(gowalla_url)
ds.load(return_as="pd").head()

3.3.  方法3,用户自行下载数据集之后通过接口配置#

用户先将数据集下载到任意一个目录,比如datasets/loc-gowalla_totalCheckins.txt.gz,然后通过下面的代码就可以加载数据了。

from trajdl.datasets.open_source.conf import GowallaDataset

original_dataset_path = "datasets/loc-gowalla_totalCheckins.txt.gz"

ds = GowallaDataset()
ds.load(return_as="pd", original_dataset_path=original_dataset_path).head()

目前TrajDL支持的公开数据集的环境变量定义如下:

Dataset

Env

Gowalla

GOWALLA_URL

Porto

PORTO_URL

Note

  1. 推荐用户使用前两种方式,这两种方式适合用户有自己的数据管理系统,比如用户所在实验室或者企业有可以提供HTTP服务的存储工具,用户可以通过URL快速拉取数据集。这种方式在基于Docker的运行环境里面,优势比较明显。

  2. TrajDL的代码里面配置了公开数据集的默认URL和SHA-256的值,用户需要下载相同的数据集才能正常使用上述两种方法完成数据加载。

4.  公开数据集如何转换为LocSeq或Trajectory#

TrajDL的基础数据结构是LocSeqTrajectory,用户在加载了公开数据集后,自己会进行一些数据处理,当数据都被处理好后就可以转换为LocSeqTrajectory了,供后续使用。

4.1.  将Gowalla转换为LocSeq和LocSeqDataset#

# 我们要用Polars的API进行数据处理
import polars as pl

from trajdl.datasets import LocSeq
from trajdl.datasets.open_source.conf import GowallaDataset

df = GowallaDataset().load()
df.head()
load dataset: gowalla
shape: (5, 5)
user_idcheck_in_timelatlngloc_id
strdatetime[μs]f64f64str
"0"2010-10-19 23:55:2730.235909-97.79514"22847"
"0"2010-10-18 22:17:4330.269103-97.749395"420315"
"0"2010-10-17 23:42:0330.255731-97.763386"316637"
"0"2010-10-17 19:26:0530.263418-97.757597"16516"
"0"2010-10-16 18:50:4230.274292-97.740523"5535878"
# 将check_in的时间按天划分,1个用户1天的位置组成1条位置序列
df_locseqs = (
    df
    .with_columns(pl.col("check_in_time").dt.strftime("%Y%m%d").alias("ds"))
    .group_by("user_id", "ds")
    .agg(pl.col("loc_id").sort_by(pl.col("check_in_time")).alias("loc_seq"))
    .select("user_id", "ds", "loc_seq")
)
df_locseqs.head()
shape: (5, 3)
user_iddsloc_seq
strstrlist[str]
"14034""20100915"["1303617"]
"118047""20101016"["709959"]
"68266""20091223"["256119"]
"75887""20100807"["1570584", "81517", "92373"]
"132053""20100901"["1584550"]
# 取其中的前10条序列,构造List[LocSeq]和LocSeqDataset

from trajdl.datasets import LocSeq, LocSeqDataset

# 遍历dataframe的前10行,将其转换为LocSeq,entity_id设定为用户id
locseqs = []
for user_id, _, loc_seq in df_locseqs.head(10).iter_rows():
    locseqs.append(LocSeq(seq=loc_seq, entity_id=user_id))
locseqs
[LocSeq(size=1, entity_id='14034', loc_seq='1303617'),
 LocSeq(size=1, entity_id='118047', loc_seq='709959'),
 LocSeq(size=1, entity_id='68266', loc_seq='256119'),
 LocSeq(size=3, entity_id='75887', loc_seq='1570584', '81517', '92373'),
 LocSeq(size=1, entity_id='132053', loc_seq='1584550'),
 LocSeq(size=2, entity_id='160632', loc_seq='91412', '213891'),
 LocSeq(size=1, entity_id='27786', loc_seq='12473'),
 LocSeq(size=2, entity_id='36606', loc_seq='67600', '2336788'),
 LocSeq(size=1, entity_id='107522', loc_seq='726970'),
 LocSeq(size=2, entity_id='154445', loc_seq='705559', '597957')]

然后将其转换为LocSeqDataset

ds = LocSeqDataset.init_from_loc_seqs(locseqs)
ds
LocSeqDataset(size=10)
ds.schema()
seq: large_list<item: large_string>
  child 0, item: large_string
entity_id: large_string
ts_seq: large_list<item: int64>
  child 0, item: int64
ts_delta: large_list<item: float>
  child 0, item: float
dis_delta: large_list<item: float>
  child 0, item: float
start_ts: int64
ds.seq
<pyarrow.lib.ChunkedArray object at 0x7fdc29513520>
[
  [
    [
      "1303617"
    ],
    [
      "709959"
    ],
    ...
    [
      "726970"
    ],
    [
      "705559",
      "597957"
    ]
  ]
]

4.2.  将Porto转换为Trajectory和TrajectoryDataset#

TrajectoryDataset同理通过上述方法构建,我们以Porto数据集为例。

from trajdl.datasets.open_source.conf import PortoDataset

df = PortoDataset().load()
df.head(2)
load dataset: porto
shape: (2, 9)
TRIP_IDCALL_TYPEORIGIN_CALLORIGIN_STANDTAXI_IDTIMESTAMPDAY_TYPEMISSING_DATAPOLYLINE
strstri64i64i64i64strboollist[array[f64, 2]]
"1372636858620000589""C"nullnull200005891372636858"A"false[[-8.618643, 41.141412], [-8.618499, 41.141376], … [-8.630838, 41.154489]]
"1372637303620000596""B"null7200005961372637303"A"false[[-8.639847, 41.159826], [-8.640351, 41.159871], … [-8.66574, 41.170671]]
from trajdl.datasets import Trajectory, TrajectoryDataset
trajs = []
for polyline in df.head(10)["POLYLINE"]:
    trajs.append(Trajectory(seq=polyline.to_numpy()))
trajs
[Trajectory(entity_id=None, length=23),
 Trajectory(entity_id=None, length=19),
 Trajectory(entity_id=None, length=65),
 Trajectory(entity_id=None, length=43),
 Trajectory(entity_id=None, length=29),
 Trajectory(entity_id=None, length=26),
 Trajectory(entity_id=None, length=36),
 Trajectory(entity_id=None, length=34),
 Trajectory(entity_id=None, length=38),
 Trajectory(entity_id=None, length=19)]
ds = TrajectoryDataset.init_from_trajectories(trajs)
ds
TrajectoryDataset(size=10)
ds.schema()
seq: large_list<item: fixed_size_list<item: double>[2]>
  child 0, item: fixed_size_list<item: double>[2]
      child 0, item: double
entity_id: large_string
ts_seq: large_list<item: int64>
  child 0, item: int64
ts_delta: large_list<item: float>
  child 0, item: float
dis_delta: large_list<item: float>
  child 0, item: float
start_ts: int64

Tip

本文介绍了TrajDL里面管理的公开数据集,以及如何将公开数据集转换成BaseSeqBaseArrowDataset。用户在使用自己的数据集的时候也可以通过BaseSeq实现BaseArrowDataset的轻松构建。