引入
上一期我们主要把精力放在了解读进阶模型,以及力所能及的数据处理上。我们学习了如何构造4个不同的特征:
(1)交叉特征: 主要提取流量、上部温度设定、下部温度设定之间的关系;
(2)历史平移特征: 通过历史平移获取上个阶段的信息;
(3)差分特征: 可以帮助获取相邻阶段的增长差异,描述数据的涨减变化情况。在此基础上还可以构建相邻数据比值变化、二阶差分等;
(4)窗口统计特征: 窗口统计可以构建不同的窗口大小,然后基于窗口范围进统计均值、最大值、最小值、中位数、方差的信息,可以反映最近阶段数据的变化情况。
接着着重记录了如何处理异常值,并通过箱线图的方式观察到了前后的效果。
而这一期上分心得我们还是要花点时间在数据的清洗上
如果说之前的异常值处理是所有模型训练之前都需要的投入,那这一期我们需要更加聚焦:
这个模型、这次训练应该做什么数据清洗?
1、时序数据
**时序数据(Time Series Data)**是按时间顺序排列的数据点集合。这意味着数据点之间的顺序是有意义的。在大多数时序数据集中,每一个数据点都与一个时间戳关联,表示该数据点的采集或观测时间。
时序数据的特点:
- 时间依赖性:数据点的值通常取决于其过去的值。例如,今天的股市价格可能受到前几天或前几个月股市趋势的影响。
- 季节性:在固定时间间隔内,数据可能会出现重复的模式或趋势。例如,零售业的销售额可能在节假日时增加。
- 趋势:长时间内的数据可能会显示上升或下降的趋势。
- 噪声:时序数据可能包含随机的、不规律的波动或噪声。
常见的时序数据示例:
- 股票价格:每天的开盘价、收盘价、最高价和最低价。
- 气象数据:每日的气温、湿度、风速等。
- 销售数据:公司每天、每周或每月的销售额。
- 传感器数据:例如,工厂中传感器每分钟记录的温度或压力读数。
- 健康监测:如人的心率或活动量,每秒或每分钟记录一次。
时序数据分析:
对时序数据进行分析可以帮助我们识别和理解数据的模式、趋势和季节性。一些常见的时序数据分析方法包括移动平均、指数平滑和自回归模型。近年来,随着机器学习和深度学习的发展,神经网络模型,特别是LSTM和GRU,也被广泛应用于时序数据的预测和分析。
2、差分特征
在机器学习和时序数据分析中,差分是一种常见的数据预处理方法。差分主要用于移除时序数据的某些趋势或季节性,使数据更接近于一个稳定的或平稳的序列。平稳的时间序列数据在很多模型中是一个关键假设,例如自回归模型(AR)和移动平均模型(MA)。
差分的基本概念:
差分涉及到计算一个时序数据点与其前一个数据点之间的差异。公式表示为:
其中, 是在时刻 的差分值, 是在时刻 的原始值, 是在时刻 的原始值。
差分的应用:
- 移除趋势:时序数据可能显示一个上升或下降的长期趋势。差分可以帮助消除这种趋势,使数据围绕一个恒定的均值波动。
- 移除季节性:如果时序数据具有明显的季节性模式(例如,每年的同一时间发生的模式),可以使用季节性差分来移除它。这涉及到计算数据点与一个季节之前的数据点之间的差异。例如,对于年度季节性,差分可能会计算。
- 稳定性:使数据更平稳是许多时序预测模型的关键假设。差分可以帮助达到这个目标。
在机器学习中的差分特征:
除了上述在时序分析中的应用,差分也可以在机器学习中被用作特征工程的一部分。例如,如果你正在处理传感器数据,并且传感器的读数变化是你感兴趣的信息(而不仅仅是绝对读数),那么差分可能是一个有用的特征。
不得不承认,差分是一种在时序数据分析和机器学习中常用的数据预处理技术,它可以帮助消除数据中的趋势和季节性,以及产生有代表性的特征。
3、差分特征构造注意点
聪明的你看到我分析到这里,已经知道我下一步要干什么了吧?§( ̄▽ ̄)§
是的,既然我们要用到差分,时序数据值得处理一下。需要注意以下要点:
- 缺失值:如果数据中存在缺失值,那么直接计算差分可能导致误导性的结果。在差分之前,通常需要对缺失值进行填充或插值。
- 不规律的时间间隔:如果数据点之间的时间间隔不固定(例如,有的间隔是10分钟,有的是5小时),那么直接差分可能不太适用。在这种情况下,可以考虑重采样数据以获得固定的时间间隔,或者使用其他方法来计算差异,这取决于实际的应用场景和目标。
- 长时间的间隔:如果数据之间的时间间隔非常长(例如,一次数据是今年的,下一次数据是5年后的),直接的差分可能会失去其代表性,因为很多中间的变化都被忽略了。
接下来的数据处理就会聚焦在这些点。
4、时序数据规律性检查
# 加载时间列的值为timedata
time_data = pd.read_csv(train_data_path, usecols=['时间'])
# 转化成时间数据
time_data['时间'] = pd.to_datetime(time_data['时间'])
# 计算时差
time_data['time_diff'] = time_data['时间'].diff()
# 检查时差
gaps = time_data[time_data['time_diff'] > pd.Timedelta(minutes=1)]
gaps
输出
时间 time_diff
2 2022-11-06 09:11:00 0 days 00:02:00
5 2022-11-06 09:15:00 0 days 00:02:00
9 2022-11-06 09:20:00 0 days 00:02:00
12 2022-11-06 09:24:00 0 days 00:02:00
16 2022-11-06 09:29:00 0 days 00:02:00
... ... ...
26651 2023-03-01 03:49:00 0 days 00:05:00
26652 2023-03-01 03:54:00 0 days 00:05:00
26653 2023-03-01 04:00:00 0 days 00:06:00
26654 2023-03-01 04:05:00 0 days 00:05:00
26655 2023-03-01 04:10:00 0 days 00:05:00
[23164 rows x 2 columns]
从结果中我们可以看到,确实存在时序数据的中断和不规律。例如:
- 2022-11-06 09:11:00 之前的数据与之前的时间点相差2分钟。
- 2022-11-06 09:15:00 之前的数据与之前的时间点相差2分钟。
- 以此类推。
5、时序处理
为了解决上面出现的时序不规律的问题,我们通常可以采取以下措施:
- 插值:使用插值技术填充缺失的数据点,以创建一个规律的时间序列。
- 重新采样:将数据重新采样到一个固定的时间间隔(例如,每分钟或每5分钟),然后进行差分。
- 使用不均匀时间差分:计算不均匀时间间隔的差分,这通常需要更复杂的方法。
但是我们既然是数据清洗,就不用考虑最后一个硬莽的方法了。我们用以下步骤来处理:
- 重新采样:将数据重新采样到一个固定的时间间隔。考虑到数据的实际情况,我建议使用1分钟作为重新采样的间隔。
- 插值:对于缺失的数据点,使用线性插值填充。
data = pd.read_csv(train_data_path)
data['时间'] = pd.to_datetime(data['时间'])
data.set_index('时间', inplace=True)
resampled_data = data.resample('1T').interpolate(method='linear')
resampled_data.head()
来看看输出
.......
4890 )
4891 # If we've made a copy once, no need to make another one
4892 copy = False
File ~/.local/lib/python3.8/site-packages/pandas/core/internals/managers.py:670, in BaseBlockManager.reindex_indexer(self, new_axis, indexer, axis, fill_value, allow_dups, copy, consolidate, only_slice)
668 # some axes don't allow reindexing with dups
669 if not allow_dups:
--> 670 self.axes[axis]._validate_can_reindex(indexer)
672 if axis >= self.ndim:
673 raise IndexError("Requested axis not found in manager")
File ~/.local/lib/python3.8/site-packages/pandas/core/indexes/base.py:3785, in Index._validate_can_reindex(self, indexer)
3783 # trying to reindex on an axis with duplicates
3784 if not self._index_as_unique and len(indexer):
-> 3785 raise ValueError("cannot reindex from a duplicate axis")
ValueError: cannot reindex from a duplicate axis
纳尼,报错了。 根据报错信息,我们发现问题是由于“时间”列中存在重复的时间戳,导致无法正常进行重新采样。接下来我们需要先处理重复数据。
5.1. 重复时间戳查找
duplicate_timestamps = data.index[data.index.duplicated(keep=False)]
duplicate_rows = data.loc[duplicate_timestamps]
duplicate_rows
输出看看:
序号 流量1 流量2 流量3 流量4 \
时间
2022-11-14 15:29:00 3711 29.337999 35.037998 27.105000 29.268999
2022-11-14 15:29:00 3712 29.173000 34.832001 27.014999 29.218000
2022-11-14 15:29:00 3711 29.337999 35.037998 27.105000 29.268999
2022-11-14 15:29:00 3712 29.173000 34.832001 27.014999 29.218000
2022-11-14 15:30:00 3713 29.052000 34.832001 26.879999 29.063000
... ... ... ... ... ...
2022-11-16 11:05:00 5605 35.306999 38.946999 39.292999 26.076000
2022-11-16 16:34:00 5859 46.818001 38.911999 39.202000 26.007999
2022-11-16 16:34:00 5860 35.109001 38.722000 39.034000 25.889000
2022-11-16 16:34:00 5859 46.818001 38.911999 39.202000 26.007999
2022-11-16 16:34:00 5860 35.109001 38.722000 39.034000 25.889000
流量5 流量6 流量7 流量8 流量9 ... \
时间 ...
2022-11-14 15:29:00 26.224001 25.868999 26.174999 27.871000 13.061 ...
2022-11-14 15:29:00 26.193001 25.868999 26.242001 27.950001 13.092 ...
2022-11-14 15:29:00 26.224001 25.868999 26.174999 27.871000 13.061 ...
2022-11-14 15:29:00 26.193001 25.868999 26.242001 27.950001 13.092 ...
2022-11-14 15:30:00 25.992001 25.992001 25.893000 27.603001 12.917 ...
... ... ... ... ... ... ...
2022-11-16 11:05:00 28.476999 17.756001 16.461000 15.572000 14.463 ...
2022-11-16 16:34:00 28.445000 17.715000 16.414000 15.551000 14.420 ...
2022-11-16 16:34:00 28.256001 17.607000 16.320000 15.479000 14.350 ...
2022-11-16 16:34:00 28.445000 17.715000 16.414000 15.551000 14.420 ...
2022-11-16 16:34:00 28.256001 17.607000 16.320000 15.479000 14.350 ...
下部温度8 下部温度9 下部温度10 下部温度11 下部温度12 下部温度13 下部温度14 \
时间
2022-11-14 15:29:00 796 797 797 797 796 797 797
2022-11-14 15:29:00 797 797 797 797 797 797 797
2022-11-14 15:29:00 796 797 797 797 796 797 797
2022-11-14 15:29:00 797 797 797 797 797 797 797
2022-11-14 15:30:00 797 797 797 797 797 797 797
... ... ... ... ... ... ... ...
2022-11-16 11:05:00 835 835 835 835 835 835 835
2022-11-16 16:34:00 835 835 835 835 835 835 835
2022-11-16 16:34:00 835 835 835 835 835 835 835
2022-11-16 16:34:00 835 835 835 835 835 835 835
2022-11-16 16:34:00 835 835 835 835 835 835 835
下部温度15 下部温度16 下部温度17
时间
2022-11-14 15:29:00 797 797 724
2022-11-14 15:29:00 797 797 723
2022-11-14 15:29:00 797 797 724
2022-11-14 15:29:00 797 797 723
2022-11-14 15:30:00 797 797 723
... ... ... ...
2022-11-16 11:05:00 835 835 700
2022-11-16 16:34:00 835 835 700
2022-11-16 16:34:00 835 835 700
2022-11-16 16:34:00 835 835 700
2022-11-16 16:34:00 835 835 700
[788 rows x 86 columns]
确实存在重复的时间戳。例如,2022-11-14 15:29:00 这个时间戳在数据中出现了两次。
一通搜索询问,为了处理这些重复的时间戳,一般可以选择以下策略:
- 平均合并:对于同一个时间戳的多行数据,我们可以计算其均值并将其合并为一行。
- 选择一行:只选择其中一行并删除其他重复的行。
- 时间偏移:对重复的时间戳进行微小的时间偏移,使其变得独特。
这里我们采用时间偏移的方式来进行(问就是这个感觉比较高端,想学习一下)
5.2. 时间偏移
接下来我们为重复的时间点进行微小的时间偏移,确保每个时间点都是独特的。
具体操作如下:
- 对于每个重复的时间点,为第二行和后续的行添加1秒的偏移,直到该时间点不再重复。
- 之后,我们再进行上述的重新采样和插值操作。
def offset_duplicates(timestamps):
"""对重复时间点添加一秒偏移"""
seen = {}
new_timestamps = []
for ts in timestamps:
while ts in seen:
seen[ts] += 1
ts += pd.Timedelta(seconds=seen[ts])
seen[ts] = 0
new_timestamps.append(ts)
return new_timestamps
# 调用函数进行时间偏移
data.index = offset_duplicates(data.index)
# 调用之前的重采样、插值函数
resampled_data = data.resample('1T').interpolate(method='linear')
# 预览一下
resampled_data.head()
输出:
序号 流量1 流量2 流量3 流量4 \
2022-11-06 09:08:00 1.0 35.668999 36.146000 25.558001 26.195000
2022-11-06 09:09:00 2.0 35.995998 36.347000 25.382000 26.348000
2022-11-06 09:10:00 2.5 35.667999 36.329000 25.426000 26.220500
2022-11-06 09:11:00 3.0 35.340000 36.311001 25.469999 26.093000
2022-11-06 09:12:00 4.0 35.585999 36.091000 25.250000 26.127001
流量5 流量6 流量7 流量8 流量9 ... \
2022-11-06 09:08:00 25.670000 15.7020 16.690001 15.991 12.8030 ...
2022-11-06 09:09:00 26.131001 15.5230 16.825001 15.871 12.8860 ...
2022-11-06 09:10:00 25.885000 15.5435 16.194500 15.909 12.8705 ...
2022-11-06 09:11:00 25.639000 15.5640 15.564000 15.947 12.8550 ...
2022-11-06 09:12:00 25.670000 15.5750 16.775999 15.936 12.7210 ...
下部温度8 下部温度9 下部温度10 下部温度11 下部温度12 下部温度13 下部温度14 \
2022-11-06 09:08:00 827.0 827.0 827.0 827.0 827.0 827.0 827.0
2022-11-06 09:09:00 827.0 827.0 827.0 827.0 827.0 827.0 827.0
2022-11-06 09:10:00 827.0 827.0 827.0 827.0 827.0 827.0 827.0
2022-11-06 09:11:00 827.0 827.0 827.0 827.0 827.0 827.0 827.0
2022-11-06 09:12:00 827.0 827.0 827.0 827.0 827.0 827.0 827.0
下部温度15 下部温度16 下部温度17
2022-11-06 09:08:00 827.0 827.0 750.0
2022-11-06 09:09:00 827.0 827.0 750.0
2022-11-06 09:10:00 827.0 827.0 750.0
2022-11-06 09:11:00 827.0 827.0 750.0
2022-11-06 09:12:00 827.0 827.0 750.0
[5 rows x 86 columns]
总结
总结一下今天我们数据清洗的成果,我们采取了以下步骤:
- 为重复的时间戳进行了微小的时间偏移,确保每个时间戳都是独特的。
- 对数据进行了重新采样,确保每个时间点间隔为1分钟。
- 使用线性插值填充了缺失的数据点,确保时间序列是连续的。
这样,我们得到了一个规律的、每1分钟一个数据点的时间序列。现在终于可以使用这个处理后的数据进行后续的分析和建模啦,差分的特征可以放心大胆地构造了~