在处理一段GPS车辆定位数据时遇见了问题。出租车平均10s采集一条数据,记录了速度、位置和车辆状态等一系列信息(本文仅针对速度字段进行处理)。由于GPS数据的误差和车辆的走走停停,车辆每一次运行中数据记录的条数不固定,且具有时序的信息。本文的目的就是清除脏数据之后提取车辆的每一段连续运行的记录(连续时间记录:前后两条记录时间间隔不超过25秒),并采用三次样条曲线进行数据插值。
样本数据test.csv:
datatime,speed
2019/01/01 16:41:40,0.1
2019/01/01 16:41:50,4.6
2019/01/01 16:42:02,42.3
2019/01/01 16:42:12,61.2
2019/01/01 16:42:22,62.7
2019/01/01 16:42:32,72
2019/01/01 16:42:42,50.6
2019/01/01 16:42:52,34.39
2019/01/01 16:43:02,51.06
2019/01/01 16:43:12,31.34
2019/01/01 16:43:43,56.82
2019/01/01 16:43:52,49.23
2019/01/01 16:44:02,40.63
2019/01/01 16:44:12,50.6
2019/01/01 16:44:22,34.39
2019/01/01 16:44:32,51.06
2019/01/01 16:44:42,31.34
2019/01/01 16:44:52,64.51
2019/01/01 16:45:02,65535
2019/01/01 16:45:12,65535
2019/01/01 16:45:23,69.94
2019/01/01 16:45:32,54
2019/01/01 16:45:42,49.34
2019/01/01 16:45:52,37.7
2019/01/01 16:46:02,14.14
2019/01/01 16:46:12,21.53
2019/01/01 16:46:22,49.34
2019/01/01 16:46:32,37.7
可以看到,20与21行数据明显是错误数据(速度太大,需要去除);测试数据(test.csv)依据时间的连续性可以分为三段(每段数据内部前后两条记录时间差不超过25s,不同段的数据时间差超过25s)。我们需要通过程序得到这三段数据。
数据分析:
可以看到,文件中时间字段有着固定的格式,如果将日期作为str类型进行存储会极大地影响处理效率。对于时间序列的数据而言,pandas提供了一个datatime的对象数组(称为时间戳),可以高效处理格式化时间序列。另外,为了方便时间计算,我们需要使用统一的时间基准,将其转化为unix时间(unix时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒),并将其转化为协调世界时(UTC时间,比北京时间晚8h)。
def test(filename):
data = pd.read_csv(filename)[["datatime","speed"]]
# step1:时间转换
data['datatime'] = pd.to_datetime(data['datatime'], format = "%Y/%m/%d %H:%M:%S")
data['unix_utctime'] = data.apply(
lambda row:row['datatime'].timestamp()-28800, axis=1)
# step2:数据清洗
data = data.drop_duplicates(['unix_utctime'])
data = data[(data['speed']<220)]
# step3:构建划分区间,阈值为25s
data['diff'] = data['unix_utctime'].diff()
data['tag1'] = data['diff'].apply(
lambda x: 1 if x < 25 else 0)
g1 = data.groupby(data['tag1'])
sbin = g1.get_group(0).index.tolist()
sbin.append(int(data.index[-1])+1)
# step4:数据分割,获取分段数据
data['index'] = data.index
data['tag2'] = np.digitize(data['index'], bins = sbin)
g = data.groupby(['tag2'])
# step5:分段数据处理:插值
count = 0
for name,dataset in g:
x = np.array(dataset['unix_utctime'].values)
if x.shape[0] == 1:
continue
yspeed = np.array(dataset['speed'].values)
xnew = np.linspace(int(x[0]), int(x[-1]), int(x[-1]-x[0]+1))
fun_speed= interpolate.interp1d(x, yspeed, kind="cubic")
ynew =fun_speed(xnew)
count = count + 1
pl.plot(xnew, ynew, label = str(count))
pl.legend(loc="lower right")
pl.show()
pd.to_datetime()
函数将格式化了的时间转为datetime数组,然后提取datetime时间的时间戳转为unix时间再转为utc时间。python中时间处理请参考这个链接,超详细(跳转)。data.drop_duplicates()
进行数据去重和筛选出小于220km/h的出租车数据。np.digitize()
函数对index字段按照sbin数组进行分割赋值,记录为tag2本文主要想聊聊时序数据根据数据时间的连续性将数据进行分段的方法。新手记录一些自己写的玩意儿,不至于忘得太快。如果有其他方法,欢迎交流。