2024/5/5周报

本文介绍了一种结合ARIMA模型与K-means聚类的水质预测方法,通过聚类分析增强对随机特征数据的预测。ARIMA模型利用历史信息,而聚类分析识别影响因素,结果显示ARIMA结合聚类模型在预测精度上有显著提升。

摘要

本周阅读的文献中提出了一种基于趋势分量和随机增量特征的ARIMA模型与K-means聚类模型相结合的水质预测方法,将ARIMA模型与聚类模型相结合,可以弥补单一ARIMA模型的不足。通过聚类分析发现可能存在的影响因素,提高对于具有随机特征的数据预测精度。文献中用到的两种机器学习方法,一是AR模型和MA模型结合的ARIMA模型,能够利用数据本身的历史信息来预测未来,二是K-means聚类分析方法,能够把相似的数据样本分到一组(簇)。最后实现ARIME的代码以及对上周自注意力机智的位置编码内容进行补充学习。

Abstract

In the literature read this week, a water quality prediction method combining ARIMA model with K-means clustering model based on trend components and random incremental features is proposed. Combining ARIMA model with clustering model can make up for the deficiency of single ARIMA model. Through cluster analysis, the possible influencing factors are found, and the prediction accuracy of data with random characteristics is improved. Two machine learning methods used in literature, one is ARIMA model combining AR model and MA model, which can use historical information of data itself to predict the future, and the other is K-means clustering analysis method, which can divide similar data samples into a group (cluster). Finally, the code of ARIME is realized and the position coding content of last week’s self-attention wit is supplemented.

文献阅读

题目

Application of Time Serial Model in Water Quality Predicting

现有问题

ARIMA模型是一种经典的时间序列预测方法,能较好地反映时间序列数据的线性特征。然而,单一的ARIMA模型难以全面有效地处理河流水质的非线性变化,对具有趋势特征的数据有较好的预测效果,但对具有随机特征的数据预测效果较差。

创新点

将ARIMA模型与K-means聚类分析相结合,提出了一种基于趋势分量和随机增量特征的ARIMA模型与聚类相结合的水质预测方法。采用k均值聚类方法分析监测水域降水与TP指数的关系,计算降水对水质变化的随机增量特征,结合趋势分量特征和随机增量特征,计算水质预测结果。

ARIMA(自回归差分移动平均模型)

ARIMA模型,是一种将AR和MA模型结合起来的模型,用于处理更复杂的时间序列问题。

AR(自回归模型)

自回归模型AR,就是使用一个变量的过去值来预测其未来值的模型。自回归模型假设过去的值与未来的值之间存在线性关系。假设你能通过给过去的值加权求和来预测未来的值,这些权重就是模型的参数。

在这里插入图片描述

如果我们要预测时间t+1的值,我们可以使用到时间t为止的所有真实值;但是如果我们要预测时间t+2的值,我们就没有时间t+1的真实值,所以我们必须使用我们在时间t+1的预测值。这个过程将持续下去,因此,越往未来预测,我们依赖的预测值就越多。这也就是为什么时间序列预测中的误差会随着时间的推移而累积。

AR模型与多元线性回归模型在形式上非常相似,但应用的数据类型和各自对数据的假设有很大差别,AR模型自变量之间有严格的时间顺序,而多元线性回归模型则没有。

MA(移动平均模型)

它描述的是当前时间点的数据与过去噪声的关系。白噪声是一种特殊的时间序列模型,每个时间点的数据都是独立且服从相同分布的,且具有常数的均值和方差。
在这里插入图片描述

AR(自回归)模型和MA(移动平均)模型虽然在形式上看起来很相似,但是他们的关键区别在于他们对过去信息的处理方式。

对于AR模型来说,当前值是过去值的函数,是在使用过去的"实际"观察值来预测现在的值。对MA模型来说,当前值是过去噪声(或称之为误差或冲击)的函数。这里的“白噪声”实际上是模型无法解释的随机部分,是未能被模型捕获的信息。MA模型是在试图用过去的"错误"或"冲击"来预测现在的值。

AR模型是使用过去的实际值进行预测,而MA模型是使用过去的预测误差进行预测。举个例子:影响明日会不会下雨的真正因素并不是“今天”或“昨天”这些时间概念本身,而是风、云、日照等更加客观和科学的因素(这些其实就是MA模型认为的“偶然因素”)。

ARIMA模型

ARIMA模型的基本思想是利用数据本身的历史信息来预测未来。一个时间点上的标签值既受过去一段时间内的标签值影响,也受过去一段时间内的偶然事件的影响。这就是说,标签值是围绕着时间的大趋势而波动的,其中趋势是受历史标签影响构成的,波动是受一段时间内的偶然事件影响构成的,且大趋势本身不一定是稳定的。其中:
1)AR部分用于处理时间序列的自回归部分,它考虑了过去若干时期的观测值对当前值的影响。
2)I(差分)部分用于使非平稳时间序列达到平稳,消除了时间序列中的趋势和季节性因素。
在这里插入图片描述

3)MA部分用于处理时间序列的移动平均部分,它考虑了过去的预测误差对当前值的影响。

K-means聚类分析

k-means算法又名k均值算法,是基于划分的聚类,K-means算法中的k表示的是聚类为k个簇,means代表取每一个聚类中数据值的均值作为该簇的中心,或者称为质心,即用每一个的类的质心对该簇进行描述。K 均值聚类是一种分区方法,它将数据中的观测值视为具有位置和相互间距离的对象。它将对象划分为 K 个互斥簇,使每个簇中的对象尽可能彼此靠近,并尽可能远离其他簇中的对象。每个簇的特性由其质心或中心点决定。聚类中使用的距离通常不代表空间距离。

K-Means聚类算法思路

①随机选择k个聚类中心

②计算所有点到k个聚类中心的距离

③选择样本中每个点到每个聚类中心距离的最小值,并将其归类

④重新计算聚类中心,将聚类中心移动至每对于簇的均值点

⑤重复“归类-移动”(以上②③④步骤),直至聚类中心不再移动

研究实验

数据集

数据通过水质监测平台获取某流域2019年1月1日至2020年12月31日的水质数据。共有16876行数据,主要有水温、pH、溶解氧、电导率、浊度、高锰酸盐指数、氨氮、总氮、总氮9项指标。其中,高锰酸盐指标、氨氮、总磷、总氮每4 h采集一次,其他5项指标每小时采集一次。

以某流域水质监测数据为样本,选取水质总磷(TP)指数作为预测对象。

评价指标

检验模型预测精度的常用指标有MAE、MSE和MAPE。其中MAE为绝对误差的平均值,能较好地反映预测误差值的实际情况。MSE即均方误差,是指参数预测值与实际值之差的平方的期望值。MSE评估数据的波动。MSE越小,模型的预测精度越高。MAPE是平均绝对百分比误差。MAPE值越小,模型的预测精度越高。

实验目的

对比ARIM单一模型与ARIMA结合聚类的预测精度,证实ARIMA结合聚类其预测精度高于单一ARIMA模型,说明ARIMA结合聚类可以更好预测具有随机特征的数据。

实验设置

1.首先对样本数据进行清洗、平稳性分析和白噪声分析;
2.其次,根据贝叶斯信息准则(BIC)原理选择合适的参数,利用ARIMA方法获得趋势分量特征,进行水质预测;
3.再次,采用k均值聚类方法分析监测水域降水与TP指数的关系,计算降水对水质变化的随机增量特征。
4.最后,结合趋势分量特征和随机增量特征,计算水质预测结果,比较ARIMA模型与ARIMA结合聚类模型两种方法的预测结果。

实验结果

通过对2020年TP数据进行聚类分析,可以看出TP数据大部分时间分布在0.02 ~ 0.065之间,但也有少量数据分布在这个范围之外。因此可以确定还有其他因素影响着TP指标数据的走势,分析监测水域附近降雨对TP指数的影响,通过相关分析可以确定降雨量增量与TP增量之间存在很强的相关性。
在这里插入图片描述

下面两图分别为单一ARIMA模型的预测结果和ARIMA结合聚类的预测结果。可以看出来TP指数预测值与这一时期实际数据的变化趋势较为接近,说明ARIMA模型结合聚类模型的预测效果更准确。
在这里插入图片描述在这里插入图片描述

从评价指标也可以看出,利用ARIMA模型预测TP指数,其预测精度不高。这是因为ARIMA模型只提取了水质变化的趋势分量特征,而不能提取随机变化特征。与ARIMA水质预测方法相比,ARIMA结合聚类的方法具有更高的精度,其平均绝对误差(MAE)、均方误差(MSE)和平均绝对百分比误差(MAPE)分别降低了44.6%、56.8%和45.8%。
在这里插入图片描述

深度学习

ARIMA模型python实现

使用ARIMA 模型对非平稳时间序列进行建模操作,差分运算具有强大的确定性的信息提取能力, 许多非平稳的序列差分后显示出平稳序列的性质, 这是称这个非平稳序列为差分平稳序列。 对差分平稳序列可以还是要ARMA 模型进行拟合, ARIMA 模型的实质就是差分预算与 ARMA 模型的结合。

#导入数据
import pandas as pd
filename = r'D:\datasets\arima_data.xls'
data = pd.read_excel(filename, index_col = u'日期')
 
#画出时序图
import matplotlib.pyplot as plt     
plt.rcParams['font.sans-serif'] = ['SimHei']    #定义使其正常显示中文字体黑体
plt.rcParams['axes.unicode_minus'] = False      #用来正常显示表示负号
data.plot()
plt.show()
#画出自相关性图
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
plot_acf(data)
plt.show()
 
#平稳性检测
from statsmodels.tsa.stattools import adfuller
print('原始序列的检验结果为:',adfuller(data[u'销量']))
#原始序列的检验结果为: (1.8137710150945268, 0.9983759421514264, 10, 26, {'1%': -3.7112123008648155,'10%': -2.6300945562130176, '5%': -2.981246804733728}, 299.46989866024177)
#返回值依次为:adf, pvalue p值, usedlag, nobs, critical values临界值 , icbest, regresults, resstore 
#adf 分别大于3中不同检验水*的3个临界值,单位检测统计量对应的p 值显著大于 0.05 , 说明序列可以判定为 非平稳序列
#通过AIC确定ARIMA参数,打印原始数据和差分后数据的自相关系数图和偏自相关系数图
D_data = data.diff().dropna()
D_data.columns = [u'销量差分']
 
D_data.plot()   #画出差分后的时序图
plt.show()
 
plot_acf(D_data)    #画出自相关图
plt.show()
plot_pacf(D_data)   #画出偏相关图
plt.show()
print(u'差分序列的ADF 检验结果为: ', adfuller(D_data[u'销量差分']))   #平稳性检验
#差分序列的ADF 检验结果为:  (-3.1560562366723537, 0.022673435440048798, 0, 35, {'1%': -3.6327426647230316, '10%': -2.6130173469387756, '5%': -2.9485102040816327}, 287.5909090780334)
#一阶差分后的序列的时序图在均值附近比较平稳的波动, 自相关性有很强的短期相关性, 单位根检验 p值小于 0.05 ,所以说一阶差分后的序列是平稳序列
#对一阶差分后的序列做白噪声检验
from statsmodels.stats.diagnostic import acorr_ljungbox
print(u'差分序列的白噪声检验结果:',acorr_ljungbox(D_data, lags= 1)) #返回统计量和 p 值
# 差分序列的白噪声检验结果: (array([11.30402222]), array([0.00077339])) p值为第二项, 远小于 0.05
 
#对模型进行定阶
from statsmodels.tsa.arima_model import ARIMA 
 
pmax = int(len(D_data) / 10)    #一般阶数不超过 length /10
qmax = int(len(D_data) / 10)
bic_matrix = []
for p in range(pmax +1):
    temp= []
    for q in range(qmax+1):
        try:
            temp.append(ARIMA(data, (p, 1, q)).fit().bic)
        except:
            temp.append(None)
        bic_matrix.append(temp)
 
bic_matrix = pd.DataFrame(bic_matrix)   #将其转换成Dataframe 数据结构
p,q = bic_matrix.stack().idxmin()   #先使用stack 展开, 然后使用 idxmin 找出最小值的位置
print(u'BIC 最小的p值 和 q 值:%s,%s' %(p,q))  #  BIC 最小的p值和q 值:0,1
#在确保三个基本假设都满足后,即可开始建模,其中ARIMA的三个参数(p,d,q)选用步骤3和5的最优结果
#所以根据得到的q、p可以建立ARIMA 模型,ARIMA(0,1,1)
model = ARIMA(data, (p,1,q)).fit()
model.summary2()        #生成一份模型报告
#forecast()中填入预测期数,开始预测
model.forecast(5)   #为未来5天进行预测,返回预测结果、标准误差和置信区间

Positional Encoding(位置编码)

对于Self-attention结果而言,它可以一次性的将所有的字都当做输入。但是NLP的输入是有特点的,其特点是输入的文本要按照一定的顺序才可以。因为,文本的顺序是带有一部分语义关系的,同一个词在句子中的不同位置可能就代表了不一样的语义。比如下面两句话,不同的语序就有不同的语义。
1.我喜欢吃洋葱
2.洋葱喜欢吃我
在这里插入图片描述
注意力机制没有考虑序列之间的先后关系,即上下文。那如果在序列中随意变换词与词之间的位置,得到的结果肯定是一样的,所以我们需要对每个词加入位置信息。在self-attention这个layer中少了一个position information(位置信息),那么把这个位置信息插入到self-attention中去就需要用到positional encoding这个技术,为每个位置设定一个专属的位置向量,然后将这个位置向量加到上,现在的位置就是已知的了。
在这里插入图片描述

位置编码是需要在最开始输入的时候就进行处理的,最开始的词都被编码成向量如x1,x2,x3,同样要根据位置编码对应的位置向量t1,t2,t3,将x1与t1对应做一个向量加法后生成新的x1,其他编码以此类推,新的向量就包含了位置信息。

位置信息也是通过Embedding进行表示,对于位置编码来说有两种方式可以得到,而Transformer中使用的是后者。

  1. 通过Embedding进行训练
  2. 通过公式计算

相对位置编码的特点,关注一个token与另一个token距离的相对位置(距离差几个token),使用相对位置的方法,可以清晰的知道单词之间的距离远近的关系。
在这里插入图片描述
相对位置表示方法:
在这里插入图片描述

总结

ARIMA模型是一种有效分析时间序列变化趋势的统计模型,它可以用来分析各种有时间序列性质的问题。它具有较高的分析效率和准确性,通过仔细查看和识别噪声,可以得出准确的结论。因此,ARIMA模型是一种优秀的数据分析方法,在很多领域都有广泛的应用。

bindissueWeek(event) { this.shopData.thisWeekRepairShopIssue.issueWeek = event.detail.value; this.$apply(); console.log('本周出单向输入--------', this.shopData.thisWeekRepairShopIssue.issueWeek); } 调用这个方法 报异常 Cannot set property 'issueWeek' of null 我的data是 shopData: { // 修理厂信息 id: null, // 修理厂id reception: null, // 前台方向 monopolycode: null, // 修理厂推荐送修码 boss: null, // 老板名称 workers: null, //工人数量 policy: null, // 政策 feedback: null, // 线团反馈信息 periodWeek: null, // 根据本周出单信息 开始日期与结束日期 拼接出的 字段 thisWeekRepairShopIssue: { // 本周出单信息 startDate: null, //开始日期 endDate: null, //结束日期 remark: null, //备注日期 id: null, // 本周id issueWeek: null, //本周出单 shareWeek: null //本周份额 }, thisMouthWeekRepairShopBusiness: { // 当月目标保费信息 nextMouthPremium: null, // 次月保费目标 nextMouthAudit: null, // 次月审核状态 premium: null, // 保费目标 premiumOnyear: null, // 同比净保费 progress: null, // 目标达成进度 progressMonth: null, // 当月续保进度 progressNextmonth: null, // 次月续保进度 dingbaoYear: null, // 当年定保比 dingbaoOnyear: null, // 同比定保比 dingbaoRing: null, // 环比定保比 audit: null // 当月审核状态 }, thisMouthPatrols: [ // 巡店情况 { clockDate: null, // 打开时间 talk: null, // 谈判信息 feedback: null, // 线团反馈信息 deviceFlag: null, // 设备信息采集是否正常 1-是 0-否 } ], thisMouthImage: { // 画像信息 imageName: null, // 画像名称 dingbaoMonth: null, // 当前定报比 dingbaoDiff: null, // 定保比差异 dingsunDiff: null, // 定损车辆台次差异 imgNameBgStyle: null, // 样式 } } 注意我用的wpy开发的小程序 这个异常是为什么
最新发布
08-27
<think>我们正在处理一个在小程序开发中出现的错误:`TypeError: Cannot set property 'issueWeek' of null`。这个错误通常发生在尝试给一个`null`对象的属性赋值时。下面我们将逐步分析问题原因并提供解决方案。 ### 错误原因分析 1. **对象未初始化**:在`wpy`框架中,你尝试给`this.data`中的一个属性(例如`issueWeek`)赋值,但该属性所属的对象为`null`。 2. **异步数据问题**:可能在数据还未准备好(例如从接口获取数据)时就尝试设置属性。 3. **生命周期问题**:在组件的生命周期中,可能在某些钩子函数(如`onLoad`)中尝试设置属性,但此时数据对象还未创建。 ### 解决方案 #### 1. 检查数据初始化 在组件的`data`中确保所有对象都被正确初始化,避免出现`null`。 ```javascript data = { // 确保这里不是null,而是一个空对象或具有默认值的对象 form: { issueWeek: '' // 初始化为空字符串或其他默认值 } } ``` #### 2. 检查赋值操作 在设置属性之前,确保目标对象存在。例如: ```javascript // 错误示例:如果this.data.form为null,则会报错 this.data.form.issueWeek = '2024年第25周'; // 正确做法:使用setData方法,并确保对象已经初始化 this.setData({ 'form.issueWeek': '2024年第25周' }); ``` #### 3. 检查异步操作 如果赋值依赖于异步操作(如网络请求),确保在回调函数中检查数据是否已经初始化。 ```javascript // 假设这是一个异步操作 wx.request({ url: 'your_api_url', success: (res) => { // 在设置之前,确保form对象已经存在 if (this.data.form) { this.setData({ 'form.issueWeek': res.data.issueWeek }); } else { // 如果form为null,则先初始化form this.setData({ form: { issueWeek: res.data.issueWeek // 其他字段... } }); } } }); ``` #### 4. 使用`setData`的正确姿势 在小程序中,修改数据必须使用`this.setData`方法,直接赋值不会触发视图更新,且容易引发错误。 #### 5. 检查生命周期 确保在合适的生命周期中操作数据。例如,在`onLoad`中初始化数据,在`onReady`中处理与界面相关的操作。 ```javascript onLoad() { // 初始化数据 this.setData({ form: { issueWeek: '' // 初始值 } }); } ``` ### 完整示例 假设我们有一个表单对象`form`,其中包含`issueWeek`属性。以下是一个完整的组件示例: ```javascript import wepy from 'wepy'; export default class MyComponent extends wepy.component { data = { form: { // 初始化form对象,避免为null issueWeek: '' } } methods = { bindissueWeek(e) { // 使用setData更新数据 this.setData({ 'form.issueWeek': e.detail.value }); } } onLoad() { // 如果需要从服务器获取数据 this.getDataFromServer(); } getDataFromServer() { // 模拟异步请求 setTimeout(() => { // 确保form对象存在(已经初始化) if (this.data.form) { this.setData({ 'form.issueWeek': '2024年第25周' }); } else { // 如果form未初始化,则初始化 this.setData({ form: { issueWeek: '2024年第25周' } }); } }, 1000); } } ``` ### 常见错误场景 1. **未初始化对象**:在`data`中定义了一个对象,但初始值为`null`,然后在方法中直接给这个对象的属性赋值。 2. **异步回调中未判空**:在异步回调中直接给对象的属性赋值,但此时对象可能还未初始化(比如在请求返回之前,用户已经离开了页面,导致组件部分数据被销毁)。 ### 相关问题 1. 在wpy小程序中如何正确初始化数据对象? 2. 如何避免在异步操作中因为组件卸载导致的赋值错误? 3. 小程序中`setData`的使用有哪些注意事项?</think>### 问题分析:`TypeError: Cannot set property 'issueWeek' of null` 在wpy小程序开发中出现该错误,核心原因是**尝试给一个值为`null`的对象设置属性**。具体表现为: ```javascript // 错误示例:试图给null对象设置issueWeek属性 null.issueWeek = "2024年第25周"; ``` 常见触发场景: 1. **数据初始化缺失**:在`data`中未初始化`form`对象,直接尝试设置`form.issueWeek`[^1] 2. **异步回调问题**:网络请求返回时组件已卸载,`this.data.form`变为`null` 3. **生命周期冲突**:在`onLoad`完成前访问组件数据 4. **变量作用域问题**:方法内`this`指向错误(常见于未使用箭头函数) --- ### 完整解决方案 #### 1. 确保数据正确初始化(关键步骤) 在组件的`data`中预定义`form`对象: ```javascript data = { form: { // 必须初始化对象 issueWeek: "" // 预定义属性 } } ``` #### 2. 使用安全的属性设置方式 修改`bindissueWeek`方法,避免直接操作`null`: ```javascript methods = { bindissueWeek(e) { // 安全写法:检查对象是否存在 if (!this.data.form) { this.setData({ form: {} }) // 动态创建对象 } // 正确设置数据 this.setData({ 'form.issueWeek': e.detail.value // 使用setData更新 }); // 替代方案:使用扩展运算符保持对象引用 this.setData({ form: { ...this.data.form, issueWeek: e.detail.value } }); } } ``` #### 3. 处理异步操作的生命周期 对于网络请求等异步操作: ```javascript onLoad() { // 示例:请求数据前初始化对象 this.setData({ form: {} }); // 使用箭头函数保持this指向 wx.request({ success: (res) => { // 检查组件是否仍挂载 if (this && this.data) { this.setData({ 'form.issueWeek': res.data.week }) } } }) } ``` #### 4. 使用wpy的响应式系统 利用wpy的`twoWay`绑定减少手动操作: ```wxml <!-- template.wxml --> <input value="{{ form.issueWeek }}" bindinput="bindissueWeek" /> ``` ```javascript // 启用双向绑定 events = { 'form.issueWeek': (newVal) => { console.log('自动更新:', newVal) } } ``` --- ### 错误排查流程图 ```mermaid graph TD A[出现 Cannot set property issueWeek of null] --> B{检查 data 初始化} B -->|form 未定义| C[在 data 中添加 form: {}] B -->|已初始化| D{检查异步操作} D -->|请求回调中出错| E[添加组件卸载判断] D -->|非异步操作| F{检查 this 指向} F -->|普通函数| G[改用箭头函数] F -->|作用域污染| H[检查变量命名冲突] E --> I[在 onUnload 中标记卸载] ``` --- ### 预防措施 1. **启用严格模式**:在文件顶部添加 `'use strict'` 提前捕获未定义变量 2. **类型安全检查**: ```javascript // 安全设置属性函数 function safeSet(obj, prop, value) { if (obj === null || obj === undefined) { return false; } obj[prop] = value; return true; } // 调用示例 safeSet(this.data.form, 'issueWeek', '2024W25'); ``` 3. **使用TypeScript**:添加类型定义避免空值 ```typescript interface FormData { issueWeek?: string; // 可选属性 } data = { form: {} as FormData // 类型断言 } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值