Python Pandas实现不规则时间序列数据的分钟级分组与补齐
本文介绍如何使用Python的Pandas和Numpy库,将不规则采样的时间序列数据按分钟进行分组。通过将秒级时间戳转换为分钟并分组,提取每组数据长度,利用最大长度构建统一宽度的DataFrame,最后通过ffill方法向前填充缺失值,实现数据对齐与补齐。
数据处理需求与数据源概述
首先明确处理需求:需要将数据按分钟为单位进行分组,并将每一分钟内的多条数据合并为一行输出。由于不同时间段内的数据采样数量不一致,最终输出的数据列数需以包含数据最多的那一分钟组为准,其余数据量不足的组,其缺失部分需使用各自组的最后一个有效数据进行填充补足。
接下来介绍数据源情况。在预处理阶段,已剔除无关列,仅保留核心的数据列(data)和时间戳列(time)。其中,时间戳以秒为单位记录,原始数据总共包含407454行记录。
data time
0 6522.50 1.530668e+09
1 6522.66 1.530668e+09
2 6523.79 1.530668e+09
3 6523.79 1.530668e+09
4 6524.82 1.530668e+09
5 6524.35 1.530668e+09
6 6523.66 1.530668e+09
7 6522.64 1.530668e+09
8 6523.25 1.530668e+09
9 6523.88 1.530668e+09
10 6525.30 1.530668e+09
11 6525.70 1.530668e+09
... ... ...
407443 6310.69 1.531302e+09
407444 6310.55 1.531302e+09
407445 6310.42 1.531302e+09
407446 6310.40 1.531302e+09
407447 6314.03 1.531302e+09
407448 6314.04 1.531302e+09
407449 6312.84 1.531302e+09
407450 6312.57 1.531302e+09
407451 6312.56 1.531302e+09
407452 6314.04 1.531302e+09
407453 6314.04 1.531302e+09
[407454 rows x 2 columns]
Pandas分组与数据对齐实现
开始执行数据处理逻辑,首先定义一个处理函数,该函数接收一个DataFrame对象以及时间列的名称作为输入参数。
def getdata_time(dataframe,name):
dataframe[name] = dataframe[name]/60 #将时间转换为分钟
dataframe[name] = dataframe[name].astype('int64')
datalen = dataframe.groupby(name).count().max() #获取数据最大长度
timeframe = dataframe.groupby(name).count().reset_index()#为了获取时间将分组后时间转换为DataFrame
timeseries = timeframe['time']
array = [] #建立一个空数组以便存值
for time, group in dataframe.groupby(name):
tmparray = numpy.array(group['data']) #将series转换为数组并添加到总数组中
array.append(tmparray)
notimedata = pandas.DataFrame(array)
notimedata = notimedata.fillna(method='ffill',axis = 1,limit=datalen[0]) #将缺失值补全
notimedata[datalen[0]+1] = timeseries #把时间添加到最后一列
return notimedata
对函数内部逻辑进行逐行解析。第一步是按分钟维度进行数据分组,因此需要将秒计的时间戳除以60转换为分钟值。随后将其转换为int类型,这主要是为了便于观察和调试(关于类型转换是否会导致数据精度丢失从而影响最终结果,目前尚不确定,如有相关经验者欢迎指正)。
变量datalen用于存储每分钟数据中的最大长度,作为后续对齐的标准。DataFrame.groupby.count()方法用于统计每组数据的行数,而非统计分组的总数量。若需获取分组后的索引信息,需调用下一行的reset_index方法。之所以不在groupby后直接调用reset_index,是因为groupby产生的结果并非标准的DataFrame;而经过count()(或任何能生成与每组index一一对应结果的聚合操作)处理后,结果便转化为包含index列和计数结果的DataFrame。直接对groupby对象调用reset_index会引发报错,具体错误信息如下:
AttributeError: Cannot access callable attribute 'reset_index' of 'DataFrameGroupBy' objects, try using the 'apply' method
在应用count操作后调用reset_index,可查看分组统计结果。数据显示,原始数据共被划分为10397个组。
time data
0 25511135 33
1 25511136 18
2 25511137 25
3 25511138 42
4 25511139 36
5 25511140 7
6 25511141 61
7 25511142 45
8 25511143 46
9 25511144 19
10 25511145 21
... ... ...
10387 25521697 3
10388 25521698 9
10389 25521699 16
10390 25521700 13
10391 25521701 4
10392 25521702 34
10393 25521703 124
10394 25521704 302
10395 25521705 86
10396 25521706 52
[10397 rows x 2 columns]
提取出的timeseries变量将在后续数据整合阶段使用。现在开始执行逐组数据提取:首先初始化一个空数组用于存储数据,接着利用for循环遍历每一组的信息。其中,time变量代表分组的索引(即分钟时间),group变量代表该分组内的所有数据。从group['data']中提取数据并追加至之前创建的空数组中。循环结束后,将数组转换为DataFrame。需要注意的是,该DataFrame中包含大量缺失值,因为其列数是根据数据量最大的那一组确定的。转换后的数据结构如下:
0 1 2 3 ... 1143 1144 1145 1146
0 6522.50 6522.66 6523.79 6523.79 ... NaN NaN NaN NaN
1 6523.95 6524.90 6525.00 6524.35 ... NaN NaN NaN NaN
2 6520.87 6520.00 6520.45 6520.46 ... NaN NaN NaN NaN
3 6516.34 6516.26 6516.21 6516.21 ... NaN NaN NaN NaN
4 6513.28 6514.00 6514.00 6514.00 ... NaN NaN NaN NaN
5 6511.98 6511.98 6511.99 6513.00 ... NaN NaN NaN NaN
6 6511.00 6511.00 6511.00 6511.00 ... NaN NaN NaN NaN
7 6511.70 6511.78 6511.99 6511.99 ... NaN NaN NaN NaN
8 6509.51 6510.00 6510.80 6510.80 ... NaN NaN NaN NaN
9 6511.36 6510.00 6510.00 6510.00 ... NaN NaN NaN NaN
10 6507.00 6507.00 6507.00 6507.00 ... NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ...
10386 6333.77 6331.31 6331.30 6333.19 ... NaN NaN NaN NaN
10387 6331.68 6331.30 6331.68 NaN ... NaN NaN NaN NaN
10388 6331.30 6331.30 6331.00 6331.00 ... NaN NaN NaN NaN
10389 6330.93 6330.92 6330.92 6330.93 ... NaN NaN NaN NaN
10390 6330.83 6330.83 6330.90 6330.80 ... NaN NaN NaN NaN
10391 6327.57 6326.00 6326.00 6325.74 ... NaN NaN NaN NaN
10392 6327.57 6329.70 6328.85 6328.85 ... NaN NaN NaN NaN
10393 6323.54 6323.15 6323.15 6322.77 ... NaN NaN NaN NaN
10394 6311.00 6310.83 6310.83 6310.50 ... NaN NaN NaN NaN
10395 6311.45 6311.32 6310.01 6310.01 ... NaN NaN NaN NaN
10396 6310.46 6310.46 6310.56 6311.61 ... NaN NaN NaN NaN
[10397 rows x 1147 columns]
从输出结果可见,行数等于分组的总个数(10397行),而列数等于数据量最大的那一组的长度(共1147列)。
随后,通过调用fillna方法对缺失值进行填充。参数method='ffill'表示使用缺失值前一个有效数据进行向前填充,axis = 1指定按行方向操作(即横向填充),limit参数限制最大填充的长度。最后,将之前提取的timeseries添加到DataFrame的最后一列,从而得到符合需求最终格式的结果。
0 1 2 ... 1145 1146 1148
0 6522.50 6522.66 6523.79 ... 6522.14 6522.14 25511135
1 6523.95 6524.90 6525.00 ... 6520.00 6520.00 25511136
2 6520.87 6520.00 6520.45 ... 6517.00 6517.00 25511137
3 6516.34 6516.26 6516.21 ... 6514.00 6514.00 25511138
4 6513.28 6514.00 6514.00 ... 6511.97 6511.97 25511139
5 6511.98 6511.98 6511.99 ... 6511.00 6511.00 25511140
6 6511.00 6511.00 6511.00 ... 6510.90 6510.90 25511141
7 6511.70 6511.78 6511.99 ... 6512.09 6512.09 25511142
8 6509.51 6510.00 6510.80 ... 6512.09 6512.09 25511143
9 6511.36 6510.00 6510.00 ... 6507.04 6507.04 25511144
10 6507.00 6507.00 6507.00 ... 6508.57 6508.57 25511145
11 6507.16 6507.74 6507.74 ... 6506.35 6506.35 25511146
... ... ... ... ... ... ... ...
10388 6331.30 6331.30 6331.00 ... 6331.00 6331.00 25521698
10389 6330.93 6330.92 6330.92 ... 6330.99 6330.99 25521699
10390 6330.83 6330.83 6330.90 ... 6327.58 6327.58 25521700
10391 6327.57 6326.00 6326.00 ... 6325.74 6325.74 25521701
10392 6327.57 6329.70 6328.85 ... 6325.00 6325.00 25521702
10393 6323.54 6323.15 6323.15 ... 6311.00 6311.00 25521703
10394 6311.00 6310.83 6310.83 ... 6315.00 6315.00 25521704
10395 6311.45 6311.32 6310.01 ... 6310.00 6310.00 25521705
10396 6310.46 6310.46 6310.56 ... 6314.04 6314.04 25521706
[10397 rows x 1148 columns]
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









