时间序列和异常检测
时间序列建模有助于我们根据过去的属性预测未来
7.1go语言中表示时序数据
gonum、gota包中都有时序数据表示方式
读数据并将数据制作成时序图
import (
"image/color"
"log"
"os"
"gonum.org/v1/plot/vg"
"gonum.org/v1/plot"
"gonum.org/v1/plot/plotter"
"github.com/kniren/gota/dataframe"
)
func main() {
airFlie, err := os.Open("D:/gocode/AirPassengers.csv")
if err != nil {
log.Fatal(err)
}
defer airFlie.Close()
// 创建数据帧
airData := dataframe.ReadCSV(airFlie)
// fmt.Println(airData)
// 将时间序列绘图
yVals := airData.Col("value").Float()
pts := make(plotter.XYs, airData.Nrow())
// 填充数据点
for i, floatVal := range airData.Col("time").Float() {
pts[i].X = floatVal
pts[i].Y = yVals[i]
}
p, err := plot.New()
if err != nil {
log.Fatal(err)
}
p.X.Label.Text = "time"
p.Y.Label.Text = "passengers"
p.Add(plotter.NewGrid())
// 将时间序列填入
l, err := plotter.NewLine(pts)
if err != nil {
log.Fatal(err)
}
l.LineStyle.Width = vg.Points(1)
l.LineStyle.Color = color.RGBA{B: 255, A: 255}
p.Add(l)
// Save()的第一个参数是长,第二参数是高
if err := p.Save(10*vg.Inch, 4*vg.Inch, "passengers.png"); err != nil {
log.Fatal(err)
}
}
7.2理解时间序列的术语
时间、日期、时间戳
观察、测量、信号、随机变量
季节性:随着季节的变化而变化
趋势:随着时间的变化而呈现的一种形态
平稳的:随着时间的变化,不变或者没有较大的变化
时间段:时间学列中连续观测点之间的时间量
自归模型:试图通过同一过程的一个或多个延迟或滞后版本对时间序列过程建模。
移动平均模型:试图根据不完全预测项的当前或过去的值对时间序列进行建模
7.3与时间序列有关的相关统计
7.3.1自相关
自相关是衡量信号与其本身的延迟版本之间相关型的变量 使用自相关函数定量
import (
"fmt"
"log"
"math"
"os"
"gonum.org/v1/plot/plotter"
"gonum.org/v1/plot/plotutil"
"gonum.org/v1/plot/vg"
"gonum.org/v1/plot"
"github.com/kniren/gota/dataframe"
"gonum.org/v1/gonum/stat"
)
//计算延迟自相关的函数
func acf(x []float64, lag int) float64 {
xAdj := x[lag:len(x)]
xLag := x[0 : len(x)-lag]
var numrator float64
var denomiator float64
xBar := stat.Mean(x, nil)
for idx, xval := range xAdj {
numrator += ((xval - xBar) * (xLag[idx] - xBar))
}
for _, xval := range x {
denomiator += math.Pow(xval-xBar, 2)
}
return numrator / denomiator
}
func main() {
airFlie, err := os.Open("D:/gocode/AirPassengers.csv")
if err != nil {
log.Fatal(err)
}
defer airFlie.Close()
// 创建数据帧
airData := dataframe.ReadCSV(airFlie)
passengers := airData.Col("value").Float()
fmt.Println("自相关是:")
for i := 1; i < 11; i++ {
adjusted := passengers[i:len(passengers)]
lag := passengers[0 : len(passengers)-i]
ac := stat.Correlation(adjusted, lag, nil)
fmt.Printf("Lag %d period :%0.2f\n", i, ac)
}
// 成图显示
p, err := plot.New()
if err != nil {
log.Fatal(err)
}
p.Title.Text = "passengers "
p.X.Label.Text = "Lag"
p.Y.Label.Text = "ACF"
p.Y.Max = 0
p.Y.Max = 1
w := vg.Points(3)
numLags := 20
pts := make(plotter.Values, numLags)
for i := 1; i < numLags; i++ {
pts[i-1] = acf(passengers, i)
}
bars, err := plotter.NewBarChart(pts, w)
if err != nil {
log.Fatal(err)
}
bars.LineStyle.Width = vg.Length(0)
bars.Color = plotutil.Color(1)
p.Add(bars)
if err := p.Save(8*vg.Inch, 4*vg.Inch, "acf.png"); err != nil {
log.Fatal(err)
}
}
7.3.2偏自相关
测量一个 序列在减去任何中间延迟的自相关后,在特定的延迟步长的相关性。可以将其视为移除中间关联后的剩余自相关。
如果偏自相关在第一次延迟后消失,就使用基于自身的单延迟,若没有消失就要使用时间序列的多个延时版本。
偏自相关就是为了消除了其他延迟产生的影响
import (
"fmt"
"log"
"os"
"strconv"
"github.com/kniren/gota/dataframe"
"github.com/sajari/regression"
"gonum.org/v1/plot"
"gonum.org/v1/plot/plotter"
"gonum.org/v1/plot/plotutil"
"gonum.org/v1/plot/vg"
)
// 偏相关函数
func pacf(x []float64, lag int) float64 {
var r regression.Regression
r.SetObserved("x")
for i := 0; i < lag; i++ {
r.SetVar(i, "x"+strconv.Itoa(i))
}
xAdj := x[lag:len(x)]
for i, xVal := range xAdj {
lagVariables := make([]float64, lag)
for idx := 1; idx <= lag; idx++ {
lagVariables[idx-1] = x[lag+i-idx]
}
r.Train(regression.DataPoint(xVal, lagVariables))
}
r.Run()
return r.Coeff(lag)
}
func main() {
airFlie, err := os.Open("D:/gocode/AirPassengers.csv")
if err != nil {
log.Fatal(err)
}
defer airFlie.Close()
// 创建数据帧
airData := dataframe.ReadCSV(airFlie)
passengers := airData.Col("value").Float()
fmt.Println("偏自相关:")
for i := 1; i < 11; i++ {
pac := pacf(passengers, i)
fmt.Printf("Lag %d period :%0.2f\n", i, pac)
}
// 成图显示
p, err := plot.New()
if err != nil {
log.Fatal(err)
}
p.Title.Text = "passengers "
p.X.Label.Text = "Lag"
p.Y.Label.Text = "PACF"
p.Y.Max = 0
p.Y.Max = 1
w := vg.Points(3)
numLags := 20
pts := make(plotter.Values, numLags)
for i := 1; i < numLags; i++ {
pts[i-1] = pacf(passengers, i)
}
bars, err := plotter.NewBarChart(pts, w)
if err != nil {
log.Fatal(err)
}
bars.LineStyle.Width = vg.Length(0)
bars.Color = plotutil.Color(1)
p.Add(bars)
if err := p.Save(8*vg.Inch, 4*vg.Inch, "pacf.png"); err != nil {
log.Fatal(err)
}
}
7.4预测的自回归模型
用来预测时间序列的第一类模型称为自回归模型
7.4.2自回归模型假设和陷阱
平稳性:自回归模型假定时间序列是平稳的
遍历性:时间序列的统计特征不应随着时间变化或漂移
7.4.3自回归模型实例
利用差分(后一项减前一项)保持时间序列的平稳
import (
"encoding/csv"
"image/color"
"log"
"math"
"os"
"strconv"
"gonum.org/v1/plot/vg"
"gonum.org/v1/plot"
"github.com/kniren/gota/dataframe"
"gonum.org/v1/plot/plotter"
)
func main() {
airFlie, err := os.Open("D:/gocode/AirPassengers.csv")
if err != nil {
log.Fatal(err)
}
defer airFlie.Close()
// 创建数据帧
airData := dataframe.ReadCSV(airFlie)
passengers := airData.Col("value").Float()
timeVals := airData.Col("time").Float()
pts := make(plotter.XYs, airData.Nrow()-1)
var difference [][]string
difference = append(difference, []string{"time", "differenceVal"})
for i := 1; i < len(passengers); i++ {
pts[i-1].X = timeVals[i]
pts[i-1].Y = passengers[i] - passengers[i-1] //差分
// 使用消减
difference = append(difference, []string{
strconv.FormatFloat(timeVals[i], 'f', -1, 64),
strconv.FormatFloat(math.Log(passengers[i]-passengers[i-1]), 'f', -1, 64),
})
}
p, err := plot.New()
if err != nil {
log.Fatal(err)
}
p.X.Label.Text = "time"
p.Y.Label.Text = "differenceVals"
p.Add(plotter.NewGrid())
l, err := plotter.NewLine(pts)
if err != nil {
log.Fatal(err)
}
l.LineStyle.Width = vg.Points(1)
l.LineStyle.Color = color.RGBA{B: 255, A: 255}
p.Add(l)
if err := p.Save(10*vg.Inch, 4*vg.Inch, "diff.png"); err != nil {
log.Fatal(err)
}
//保存数据
f, err := os.Create("diff_serices.csv")
if err != nil {
log.Fatal(err)
}
defer f.Close()
w := csv.NewWriter(f)
w.WriteAll(difference)
if err := w.Error(); err != nil {
log.Fatal(err)
}
}
自回归移动平均模型