Fork me on GitHub

prophet源码阅读

1.项目简介

1.1.prophet简介

prophet是由facebook开发的一款时间序列预测的工具,他具有以下的优缺点:

  • 优点:
    1.易用性高: Prophet 设计简单,易于上手,无需对时间序列预测领域有深入的专业知识,使得非专业人士也能够快速使用。

    2.灵活性强: Prophet 提供了许多参数和选项,可以根据不同的数据特点和预测需求进行调整,灵活适应各种场景。

    3.自动化处理: Prophet 可以自动处理数据中的缺失值和异常值,自动检测并适应节假日效应,减轻了用户的预处理负担。
    4,可解释性强: Prophet 的预测模型基于可解释性强的分解方式,能够直观地展示出趋势、季节性和假日效应等,便于用户理解和解释预测结果。

  • 缺点:
    1.局限性: Prophet 的预测模型相对简单,无法处理一些复杂的时间序列模式和特征,例如非线性趋势、多重季节性等。

    2.性能问题: 对于大规模的时间序列数据,Prophet 可能会面临性能问题,模型拟合和预测的时间较长,不适用于实时或高频率的预测任务。

    3.不适用于所有场景: 由于其简单的模型结构和特性限制,Prophet 不适用于所有的时间序列预测问题,尤其是一些复杂的、高度非线性的场景。

2.核心代码

2.1.数据处理

  • 数据读取主要是使用pandas库来读取

    1
    2
    3
    import pandas as pd
    pd.read_csv(path)

  • 读取时序数据后,Prophet 在 forecaster.py 中的 _make_future_dataframe 函数中对输入数据进行了处理。

2.2.模型实例化模块

在forecaster.py模块中的Prophet类
实例化只需要调用

1
2
form prophet import Prophet
m = Prophet()

以上两行代码就将prophet对象实例化给了m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def __init__(
self,
growth='linear',
changepoints=None,
n_changepoints=25,
changepoint_range=0.8,
yearly_seasonality='auto',
weekly_seasonality='auto',
daily_seasonality='auto',
holidays=None,
seasonality_mode='additive',
seasonality_prior_scale=10.0,
holidays_prior_scale=10.0,
changepoint_prior_scale=0.05,
mcmc_samples=0,
interval_width=0.80,
uncertainty_samples=1000,
stan_backend=None,
scaling: str = 'absmax',
holidays_mode=None,
):

由上方的Prophet类__init__()参数可以看到由很多可选参数

以下分析一些较为常见的参数设置:

  • growth:默认为linear,可选logistic和flat
  • changepoints:可指定历史数据中哪天为changepoint
  • n_changepoints:设置潜在变化点,默认为25
  • changepoint_rangem:推断历史数据的前多少百分比,默认情况为0.8
  • changepoint_prior_scale:设置趋势的灵活性,如果趋势变化是过拟合(灵活性过高)或拟合欠(灵活性不足),则可以使用输入参数调整稀疏先验的强度。默认情况下,此参数设置为 0.05
  • yearly_seasonlity:默认为‘auto’,表示当历史数据大于一年时自动分析yearly的周期性变化
  • weakly_seasonlity与daily_seasonlity同yearly_seasonlity
  • holidays:属于外部影响因素,为Dataframe形式,可以为python内定的节假日也可以是自己指定的节假日
  • seasonality_mode:表示预测结果是trend+seasonlity还是trend*seasonlity,大部分工业应用为乘法模式,prophet默认为加法模式

Prophet类中一些常用的函数:

  • def add_country_holidays(self, country_name):
    这是prophet中加入内置节假日的函数,使用方法如下:

    1
    2
    3
    4
    m = Prophet(holidays=holidays)
    m.add_country_holidays(country_name='US')
    m.fit(df)
    forecast = m.predict(future
  • def add_seasonality(self, name, period, fourier_order, prior_scale=None,

                      mode=None, condition_name=None):
    

自定义周期函数:
不同与一个月,一周,一年的周期,可以自定义多久时间来分析周期变化

  • def add_regressor(self, name, prior_scale=None, standardize=’auto’,
                    mode=None):  
    
    添加自定义外部影响的函数

2.3.模型训练

prophet训练模型类似于sklearn,forester.py中fit函数进行模型的训练:

m.fit(ds) #训练模型

2.4.模型预测

prophet的预测也相似于sklearn,依靠forester.py中的predic函数

1
2
3
4
5
6
7
8
9
    forecast = m.predict(future)
```



### 2.5.可视化模块
prophet的可视化也很方便包,在Prophet类中有plot、plot_components函数,用于绘制预测结果图和各个组成部分的图:
```commandline
m.plot(forecast)

通过以上代码可以显示出预测结果的可视化,如下所示:

plot

通过以下代码可得预测各部分(趋势和周期性)的可视化:

1
m.plot_compoents(forecast)

compoens

visdom

visdom

在深度学习领域中,数据的可视化是非常重要的一个环节,visdom就是facebook开发专为pytorch定制的一个可视化工具

1.visdom的安装:

输入如下命令:

pip install visdom

Kaggle经典案例1

dogs vs cats

Dogs vs,Cats是一个传统的二分类问题,其训练集包含25000张图片,均放置在同一文件夹下,命名格式为,num>,jpg ,如at,10880.jpg 、
dog.18.jpg ,测试集包含1250张图片,命名为num>jpg ,如10.jpg 。参赛者需根据训练集的图片训练模型,并在测试集上进行预测,输出它是狗的杨
率。最后提交的csv文件如下,第一列是图片的~,第二列是图片为狗的概率。

1.要点梳理

程序主要包含以下功能:

  • 模型定义
  • 数据加载
  • 训练和测试

2.数据加载模块

数据的相关处理主要保存在data/dataset.py中。关于数据加载的相关操作,在上一章中我们已经提到过,其基本原理就是使用Dataset提供数据集的封装,再使用Dataloader实现数据并行加载。Kaggle提供的数据包括训练集和测试集,而我们在实际使用中,还需专门从训练集中取出一部分作为验证集。对于这三类数据集,其相应操作也不太一样,而如果专门写三个Dataset,则稍显复杂和冗余,因此这里通过加一些判断来区分。对于训练集,我们希望做一些数据增强处理,如随机裁剪、随机翻转、加噪声等,而验证集和测试集则不需要。下面看dataset.py的代码:

点击展开/折叠代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import os
from PIL import Image
from torch.utils import data
import numpy as np
from torchvision import transforms as T


class DogCat(data.Dataset):

def __init__(self, root, transforms=None, train=True, test=False):
"""
目标:获取所有图片地址,并根据训练、验证、测试划分数据
"""
self.test = test
imgs = [os.path.join(root, img) for img in os.listdir(root)]

# test1: data/test1/8973.jpg
# train: data/train/cat.10004.jpg
if self.test:
imgs = sorted(imgs, key=lambda x: int(x.split('.')[-2].split('/')[-1])) #lambda表示构造函数,传入的参数是x
else:
imgs = sorted(imgs, key=lambda x: int(x.split('.')[-2]))

imgs_num = len(imgs)

# 划分训练、验证集,验证:训练 = 3:7
if self.test:
self.imgs = imgs
elif train:
self.imgs = imgs[:int(0.7*imgs_num)]
else :
self.imgs = imgs[int(0.7*imgs_num):]

if transforms is None:

# 数据转换操作,测试验证和训练的数据转换有所区别

normalize = T.Normalize(mean = [0.485, 0.456, 0.406],
std = [0.229, 0.224, 0.225])

# 测试集和验证集
if self.test or not train:
self.transforms = T.Compose([
T.Resize(224),
T.CenterCrop(224),
T.ToTensor(),
normalize
])
# 训练集
else :
self.transforms = T.Compose([
T.Resize(256),
T.RandomReSizedCrop(224),
T.RandomHorizontalFlip(), #训练集中需要一点杂质
T.ToTensor(),
normalize
])


def __getitem__(self, index):
"""
返回一张图片的数据
对于测试集,没有label,返回图片id,如1000.jpg返回1000
"""
img_path = self.imgs[index]
if self.test:
label = int(self.imgs[index].split('.')[-2].split('/')[-1])
else:
label = 1 if 'dog' in img_path.split('/')[-1] else 0
data = Image.open(img_path)
data = self.transforms(data)
return data, label

def __len__(self):
"""
返回数据集中所有图片的个数
"""
return len(self.imgs)

3.模型定义模块

模型的定义主要保存在models/目录下,其中BasicModule是对nn.Module的简易封装,提供快速加载和保存模型的接口。

点击展开/折叠代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class BasicModule(t.nn.Module):
"""
封装了nn.Module,主要提供save和load两个方法
"""

def __init__(self):
super(BasicModule,self).__init__()
self.model_name = str(type(self)) # 模型的默认名字

def load(self, path):
"""
可加载指定路径的模型
"""
self.load_state_dict(t.load(path))

def save(self, name=None):
"""
保存模型,默认使用“模型名字+时间”作为文件名,
如AlexNet_0710_23:57:29.pth
"""
if name is None:
prefix = 'checkpoints/' + self.model_name + '_'
name = time.strftime(prefix + '%m%d_%H:%M:%S.pth')
t.save(self.state_dict(), name)
return name

CIFAIR-10分类

入门实战篇

小试牛刀: CIFAR-10分类
下面我们来尝试实现对CIFAR-10数据集的分类,步骤如下:
1.使用torchvision加载并预处理CIFAR-10数据集
2.定义网络
3定义损失函数和优化器
4.训练网络并更新网络参数
5.测试网络

数据预处理部分:

1
2
3
4
5
6
7
8
9
10
import torchvision as tv
import torchvision.transforms as transforms
from torchvision.transforms import ToPILImage
show = ToPILImage() # 可以把Tensor转成Image,方便可视化
```
commandline

# 定义对数据的预处理
<details>
<summary>点击展开/和并代码</summary>

transform = transforms.Compose([
transforms.ToTensor(), # 转为Tensor
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)), # 归一化
])

训练集

trainset = tv.datasets.CIFAR10(
root=’/home/cy/tmp/data/‘,
train=True,
download=True,
transform=transform)

trainloader = t.utils.data.DataLoader(
trainset,
batch_size=4,
shuffle=True,
num_workers=2)

测试集

testset = tv.datasets.CIFAR10(
‘/home/cy/tmp/data/‘,
train=False,
download=True,
transform=transform)

testloader = t.utils.data.DataLoader(
testset,
batch_size=4,
shuffle=False,
num_workers=2)

classes = (‘plane’, ‘car’, ‘bird’, ‘cat’,
‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’)


</details>

数据可视化

数据可视化

例如在jupyter中运行一段这样的代代码:

import numpy as np
import pandas as pd
df1 = pd.DataFrame(data = np.random.randn(1000,4),
              index = pd.date_range(start='27/6/2012',periods=1000),
               columns = list('ABCD'))
df1

运行结果如下:
结果1


线性图:

df1.cumsum().plot()

结果如下:
结果1


柱形图:

利用bar函数:

df1.plot.bar(stacked = True) #stacked参数决定是否堆叠

饼图:表示百分比

利用pie函数:

1
2
3
4
5
df2 = pd.DataFrame(data = np.random.randn(4,2),
columns = ['one','two'],
index = list('ABCD')
)
df2.plot.pie(suplots=True,figsize=(8,8))

运行结果如下:

结果1 --- #### 散点图:用于绘制A与B的关系 利用scatter函数作图:
  • Copyrights © 2022-2024 Yutouegg
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信