2020-03-28 线性时间序列模型

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2020-03-28 线性时间序列模型相关的知识,希望对你有一定的参考价值。

参考技术A

课程采用Ruey S. Tsay的《金融数据分析导论:基于R语言》(Tsay 2013 ) (An Introduction to Analysis of Financial Data with R)作为主要教材之一。

时间序列的线性模型,包括:

股价序列呈现缓慢的、非单调的上升趋势, 局部又有短暂的波动。

可口可乐公司每季度发布的每股盈利数据。 读入:

时间序列图:

序列仍体现出缓慢的、非单调的上升趋势,又有明显的每年的周期变化(称为季节性), 还有短期的波动。

下面用基本R的 plot() 作图并用不同颜色标出不同季节。

现在可以看出,每年一般冬季和春季最低, 夏季最高,秋季介于夏季和冬季之间。

收益率在0上下波动,除了个别时候基本在某个波动范围之内。

用xts包的 plot() 函数作图:

聚焦到2004年的数据:

红色是6月期国债利率, 黑色是3月期国债。 一般6月期高, 但是有些时期3月期超过了6月期,如1980年:

如图标普500月收益率那样的收益率数据基本呈现出在一个水平线(一般是0)上下波动, 且波动范围基本不变。 这样的表现是时间序列“弱平稳序列”的表现。
弱平稳需要一阶矩和二阶矩有限。某些分布是没有有限的二阶矩的,比如柯西分布, 这样的分布就不适用传统的线性时间序列理论。

稍后给出弱平稳的理论定义。

如图2可口可乐季度盈利这样的价格序列则呈现出水平的上下起伏, 如果分成几段平均的话, 各段的平均值差距较大。 这体现出非平稳的特性。
以下为一堆公式推导,具体查看: http://www.math.pku.edu.cn/teachers/lidf/course/fts/ftsnotes/html/_ftsnotes/fts-tslin.html#fig:tslin-intro-sp02

时间序列
自协方差函数
弱平稳序列

图6 是IBM股票月度简单收益率对标普500收益率的散点图。 从图中看出, 两者有明显的正向相关关系。
对于不独立的样本, 比如时间序列样本, 也可以计算相关系数, 其估计合理性需要一些模型假设。

对于联合分布非正态的情况, 有时相关系数不能很好地反映X和Y的正向或者负向的相关。 斯皮尔曼(Spearman)相关系数是计算X的样本的秩(名次)与Y的样本的秩之间的相关系数, 也称为Spearman rank correlation。

另一种常用的非参数相关系数是肯德尔tau(Kendall’s )系数, 反映了一致数对和非一致数对之间的差别。
即两个观测的分量次序一致的概率减去分量次序相反的概率。 一致的概率越大,说明两个的正向相关性越强。

对IBM收益率与标普收益率数据计算这三种相关系数:

自相关函数 (Autocorrelation function, ACF)参见 (何书元 2003 ) P.131 §4.2的例2.1。 原始文献: MAURICE STEVENSON BARTLETT, On the Theoretical Specification and Sampling Properties of Auto-Correlated Time Series, Journal of the Royal Statistical Society (Supplement) 8 (1946), pp. 24-41.

在基本R软件中, acf(x) 可以估计时间序列 x 的自相关函数并对其前面若干项画图。

例:CRSP的第10分位组合的月对数收益率, 1967-1到2009-12。 第10分位组合是NYSE、AMEX、NASDAQ市值最小的10%股票组成的投资组合, 每年都重新调整。

图6: CRSP第10分位组合月对数收益率

用 acf() 作时间序列的自相关函数图:

acf() 的返回值是一个列表,其中 lag 相当于, acf 相当于。 用 plot=FALSE 取消默认的图形输出。

有研究者认为小市值股票倾向于在每年的一月份有正的收益率。
为此,用对的检验来验证。 如果一月份有取正值的倾向, 则相隔12个月的值会有正相关。

计算统计量的值,检验p值:

值小于0.05, 这个检验的结果支持一月份效应的存在性。

Ljung和Box(Ljung and Box 1978 )对Box和Pierce(Box and Pierce 1970 )提出了混成统计量(Portmanteau statistic)
检验方法进行了改进

在R软件中, Box.test(x, type="Ljung-Box") 执行Ljung-Box白噪声检验。 Box.test(x, type="Box-Pierce") 执行Box-Pierce混成检验。 用 fitdf= 指定要减去的自由度个数。

检验IBM股票月收益率是否白噪声。
考虑IBM股票从1926-01到2011-09的月度收益率数据, 简单收益率和对数收益率分别考虑。
读入数据:

读入的是简单收益率的月度数据。 作ACF图:

从ACF来看月度简单收益率是白噪声。
作Ljung-Box白噪声检验, 分别取和:

在0.05水平下均不拒绝零假设, 支持IBM月度简单收益率是白噪声的零假设。
从简单收益率计算对数收益率, 并进行LB白噪声检验:

在0.05水平下不拒绝零假设。

Box-Pierce检验和Ljung-Box检验受到取值的影响, 建议采用, 且序列为季度、月度这样的周期序列时, 应取为周期的整数倍。
对CRSP最低10分位的资产组合的月简单收益率作白噪声检验。
此组合的收益率序列的ACF:

针对和作Ljung-Box白噪声检验:

在0.05水平下均拒绝零假设, 认为CRSP最低10分位的投资组合的月度简单收益率不是白噪声。

有效市场假设认为收益率是不可预测的, 也就不会有非零的自相关。 但是,股价的决定方式和指数收益率的计算方式等可能会导致在观测到的收益率序列中有自相关性。 高频金融数据中很常见自相关性。

常见的白噪声检验还有TREVOR S. BREUSCH (1978) 和LESLIE G. GODFREY (1978)提出的拉格朗日乘子法检验(LM检验)。 零假设为白噪声, 对立假设为AR、MA或者ARMA。 参见:

设是独立同分布的二阶矩有限的随机变量, 称为独立同分布白噪声(white noise)。 最常用的白噪声一般假设均值为零。 如果独立同分布, 称为高斯(Gaussian)白噪声或正态白噪声。

白噪声序列的自相关函数为零(除外)。

实际应用中如果样本自相关函数近似为零 (ACF图中都位于控制线之内或基本不超出控制线), 则可认为该序列是白噪声的样本。

如:IBM月度收益率可以认为是白噪声(见例 3.3 ); CRSP最低10分位投资组合月度收益率不是白噪声(见例 3.4 )。

不是所有的弱平稳时间序列都有这样的性质。 非平稳序列更是不需要满足这些性质。

公式就不赘述

如果从时间序列的一条轨道就可以推断出它的所有有限维分布, 就称其为严平稳遍历的。 这里不给出遍历性的严格定义, 仅给出一些严平稳遍历的充分条件。 可以证明, 宽平稳的正态时间序列是严平稳遍历的, 由零均值独立同分布白噪声产生的线性序列是严平稳遍历的。

Tsay, Ruey S. 2013. 金融数据分析导论:基于R语言 . 机械工业出版社.

何书元. 2003. 应用时间序列分析 . 北京大学出版社.

Box, GEP, and D. Pierce. 1970. “Distribution of Residual Autocorelations in Autoregressive-Integrated Moving Average Time Series Models.” J. of American Stat. Assoc. 65: 1509–26.

Ljung, G., and GEP Box. 1978. “On a Measure of Lack of Fit in Time Series Models.” Biometrika 66: 67–72.

参考学习资料: http://www.math.pku.edu.cn/teachers/lidf/course/fts/ftsnotes/html/_ftsnotes/fts-tslin.html#fig:tslin-intro-sp02

机器学习:线性模型学习总结:基于PyTorch的线性模型

基于周志华老师的《机器学习》、上一篇学习笔记以及网络的其他资料,对线性模型的这一部分内容进行一个总结。上接:机器学习:线性模型学习总结(2)

学习时间:2022.04.19~2022.04.20

文章目录

1. 数据预处理

和用Sk-Learn一样,也用来一个专门处理表格数据的函数,不过主要还是使用之前的流程:

    # 数据预处理
    df_x = mango_processing(df_x).astype(float)
    df_y = df_y.astype(float)

    # 划分训练集和测试集
    tr_x, te_x, tr_y, te_y = train_test_split(df_x, df_y, test_size=0.2, random_state=42)

    # 全部转换成张量
    train_tensor_x, test_tensor_x, train_tensor_y, test_tensor_y = map(torch.tensor, (np.array(tr_x), np.array(te_x), np.array(tr_y), np.array(te_y)))

    # 将标签转为long或float格式(根据损失函数定):
    # train_tensor_y = train_tensor_y.squeeze(-1).long()
    # test_tensor_y = test_tensor_y.squeeze(-1).long()
    train_tensor_y = train_tensor_y.squeeze(-1).float()
    test_tensor_y = test_tensor_y.squeeze(-1).float()

    # 返回测试集和训练集
    return train_tensor_x, test_tensor_x, train_tensor_y, test_tensor_y

2. PyTorch线性回归

因为全连接层不加激活函数,就只相当于加权求和,所以就可以当做线性回归:

class LinearModel(nn.Module):
    def __init__(self):
        super(LinearModel, self).__init__()
        self.liner = nn.Linear(14, 1)

    def forward(self, x):
        x = x.to(torch.float32)
        x = self.liner(x)
        x = x.squeeze(-1)  # 线性回归的损失函数MSELoss要求输入维数和目标维数一致,因此做了个降维
        return x

3. PyTorch线性分类

在最后加一个Sigmoid函数实现逻辑回归分类:

class LinearModel(nn.Module):
    def __init__(self):
        super(LinearModel, self).__init__()
        self.liner = torch.nn.Linear(24, 2)

    def forward(self, x):
        x = x.to(torch.float32)
        x = self.liner(x)
        x = torch.sigmoid(x)
        return x

4. 回归评价

这里学习了TorchMetrics这个包,直接用来调用评价回归结果,老样子,还是先写了一个函数:

    # 计算均方误差MSE
    mean_squared_error = torchmetrics.MeanSquaredError()
    mean_squared_error(y_pred, y_true)
    mse = mean_squared_error.compute()
    print('MSE:', mse, end='; ')

    # 计算平均绝对误差MAE
    mean_absolute_error = torchmetrics.MeanAbsoluteError()
    mean_absolute_error(y_pred, y_true)
    mae = mean_absolute_error.compute()
    print('MAE:', mae, end='; ')

    # 计算平均绝对百分比误差MAPE
    mean_absolute_percentage_error = torchmetrics.MeanAbsolutePercentageError()
    mean_absolute_percentage_error(y_pred, y_true)
    mape = mean_absolute_percentage_error.compute()
    print('MAPE:', mape, end='; ')

    # 计算可解释方差EV
    explained_variance = torchmetrics.ExplainedVariance()
    explained_variance(y_pred, y_true)
    ev = explained_variance.compute()
    print('EV:', ev, end='; ')

    # 计算可解释方差EV
    r2_score = torchmetrics.R2Score()
    r2_score(y_pred, y_true)
    r2 = r2_score.compute()
    print('R2-Score:', r2, end='.')

5. 分类评价

同上:

    # 计算准确率Accuracy
    accuracy = torchmetrics.Accuracy()
    accuracy(y_pred, y_true)
    acc = accuracy.compute()
    print('Accuracy:', acc, end='; ')

    # 计算精度precision
    precision = torchmetrics.Precision(average='macro', num_classes=calss_num)  # 需要根据预测的类别数量设定
    precision(y_pred, y_true)
    pre = precision.compute()
    print('Precision:', pre, end='; ')

    # 计算召回率recall
    recall = torchmetrics.Recall(average='macro', num_classes=calss_num)  # 需要根据预测的类别数量设定
    recall(y_pred, y_true)
    rec = recall.compute()
    print('Recall:', rec, end='; ')

    # 计算fl-score
    f1_score = torchmetrics.F1Score(num_classes=calss_num)
    f1_score(y_pred, y_true)
    f1 = f1_score.compute()
    print('F1-Score:', f1, end='; ')

    # 计算AUROC
    auroc = torchmetrics.AUROC(average='macro', num_classes=calss_num)
    auroc(y_pred, y_true)
    auc = auroc.compute()
    print('AUROC:', auc, end='.')
    auroc.reset()

6. 完整过程

6.1 线性回归预测

数据来源:New York City Taxi Fare Prediction | Kaggle

# 读取数据集,做好预处理
df = pd.read_csv('train.csv')
df.pickup_datetime = pd.to_datetime(df.pickup_datetime).dt.tz_localize(None)
df['hour'] = df['pickup_datetime'].apply(lambda x: x.strftime('%H')).astype(int)
df['minute'] = df['pickup_datetime'].apply(lambda x: x.strftime('%M')).astype(int)
df['second'] = df['pickup_datetime'].apply(lambda x: x.strftime('%S')).astype(int)
df['date'] = df['pickup_datetime'].apply(lambda x: x.strftime('%Y%m%d')).astype(int)
print(df.info())

target = df.fare_amount
data = df.drop(['fare_amount', 'key', 'pickup_datetime'], axis=1)
# 划分训练集,转换成张量
tr_tx, te_tx, tr_ty, te_ty = data_to_tensor(data, target)


# ---------------------------------------定义网络---------------------------------------
class LinearModel(nn.Module):
    def __init__(self):
        super(LinearModel, self).__init__()
        self.liner = nn.Linear(14, 1)

    def forward(self, x):
        x = x.to(torch.float32)
        x = self.liner(x)
        x = x.squeeze(-1)  # 线性回归的损失函数MSELoss要求输入维数和目标维数一致,因此做了个降维
        return x


# --------------------------准备训练(除超参数外,可复用)--------------------------

# 设置随机数种子,保证结果可复现
seed = 42
torch.manual_seed(seed)  # 设置CPU

# 实例化模型
model = LinearModel()

# 适应设备(CPU or GPU)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)

# 存入DataLoader
ds = TensorDataset(tr_tx, tr_ty)
dl = DataLoader(ds, batch_size=128, shuffle=True)

# 学习率
lr = 1e-5
# 设定迭代次数
epoch = 100
# 设定每隔多少次显示一次评价指标
show_step = 10
# 选用优化器
optimizer = optim.Adam(model.parameters(), lr=lr, weight_decay=0.01)
# 设置损失函数Loss
criterion = nn.MSELoss()


# ----------------------------------模型训练(可复用)----------------------------------
for epoch in range(epoch+1):
    for x, y in dl:
        pred = model(x)  # 正向传播
        loss = criterion(pred, y)  # 计算损失函数
        optimizer.zero_grad()  # 优化器的梯度清零
        loss.backward()  # 反向传播
        optimizer.step()  # 参数更新
    if epoch % show_step == 0:  # 控制输出间隔
        with torch.no_grad():
            print('epoch: ', epoch)
            tr_pred = model(tr_tx)  # 得到训练集的预测结果
            te_pred = model(te_tx)  # 得到测试集的预测结果
            all_regress_evaluation(tr_pred, tr_ty, te_pred, te_ty)


# -------------------------------输出验证集结果(基本可复用)-------------------------------
df_v = pd.read_csv('test.csv')  # 读取验证集数据
df_v.pickup_datetime = pd.to_datetime(df_v.pickup_datetime).dt.tz_localize(None)
df_v['hour'] = df_v['pickup_datetime'].apply(lambda x: x.strftime('%H')).astype(int)
df_v['minute'] = df_v['pickup_datetime'].apply(lambda x: x.strftime('%M')).astype(int)
df_v['second'] = df_v['pickup_datetime'].apply(lambda x: x.strftime('%S')).astype(int)
df_v['date'] = df_v['pickup_datetime'].apply(lambda x: x.strftime('%Y%m%d')).astype(int)
va_x = df_v.drop(['key', 'pickup_datetime'], axis=1)  # 弃列(少一个预测列)
va_x = mango_processing(va_x).astype(float)  # 数据预处理
va_tx = torch.tensor(np.array(va_x))  # 转换成张量
va_pred = model(va_tx)  # 预测
va_id = df_v['key']  # 读取索引列
va_out = pd.DataFrame('key': va_id, 'fare_amount': va_pred.detach().numpy())  # 构建输出数据的DataFrame
va_out['fare_amount'] = va_out['fare_amount'].apply(lambda x: round(x, 2))  # 数字保留两位小数
va_out.to_csv('Valid Prediction.csv', index=False)  # 输出到CSV,并取消索引列

6.2 逻辑回归分类

数据来源:Spaceship Titanic | Kaggle

# 读取数据集,做好预处理
df = pd.read_csv('train.csv')
target = df.Transported
data = df.drop(['PassengerId', 'Transported', 'Name', 'Cabin'], axis=1)
# 划分训练集,转换成张量
tr_tx, te_tx, tr_ty, te_ty = data_to_tensor(data, target)


# ------------------------------------------定义网络------------------------------------------
class LinearModel(nn.Module):
    def __init__(self):
        super(LinearModel, self).__init__()
        self.liner = torch.nn.Linear(24, 2)

    def forward(self, x):
        x = x.to(torch.float32)
        x = self.liner(x)
        x = torch.sigmoid(x)
        return x


# --------------------------准备训练(除超参数外,可完全复用)--------------------------

# 设置随机数种子,保证结果可复现
seed = 42
torch.manual_seed(seed)  # 设置CPU

# 实例化模型
model = LinearModel()

# 适应设备(CPU or GPU)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)

# 存入DataLoader
ds = TensorDataset(tr_tx, tr_ty)
dl = DataLoader(ds, batch_size=256, shuffle=True)

# 学习率
lr = 1e-3
# 设定迭代次数
epoch = 70
# 设定每隔多少次显示一次评价指标
show_step = 10
# 选用优化器
optimizer = optim.Adam(model.parameters(), lr=lr, weight_decay=0.01)
# 设置损失函数Loss
criterion = nn.CrossEntropyLoss()


# ----------------------------------模型训练(可完全复用)----------------------------------
for epoch in range(epoch+1):
    for x, y in dl:
        pred = model(x)  # 正向传播
        loss = criterion(pred, y)  # 计算损失函数
        optimizer.zero_grad()  # 优化器的梯度清零
        loss.backward()  # 反向传播
        optimizer.step()  # 参数更新
    if epoch % show_step == 0:  # 控制输出间隔
        with torch.no_grad():
            print('epoch: ', epoch)
            tr_pred = model(tr_tx)  # 得到训练集的预测结果
            te_pred = model(te_tx)  # 得到测试集的预测结果
            all_classify_evaluation(tr_pred, tr_ty, te_pred, te_ty, 2)


# 输出曲线
tr_pred = model(tr_tx)
torch_plot_curve(tr_pred, tr_ty)


# -------------------------------输出验证集结果(基本可复用)-------------------------------
df_v = pd.read_csv('test.csv')  # 读取验证集数据
va_x = df_v.drop(['PassengerId', 'Name', 'Cabin'], axis=1)  # 弃列(少一个预测列)
va_x = mango_processing(va_x).astype(float)  # 数据预处理
va_tx = torch.tensor(np.array(va_x))  # 转换成张量
va_pred = model(va_tx)  # 预测
_, va_y = torch.max(va_pred.data, 1)  # 分类数据,需要选取概率最大项的索引填充到第1列
va_id = df_v['PassengerId']  # 读取索引列
va_out = pd.DataFrame('PassengerId': va_id, 'Transported': va_y)  # 构建输出数据的DataFrame
va_out['Transported'] = va_out['Transported'].astype(bool)  # 分类数据,标签转换
va_out.to_csv('Valid Prediction.csv', index=False)  # 输出到CSV,并取消索引列

以上是关于2020-03-28 线性时间序列模型的主要内容,如果未能解决你的问题,请参考以下文章

[GPT] 序列模型分类及其模型方案选择

线性模型

线性模型

2020-03-28用未来着眼当下

2020-03-28 微服务网关Zuul

时间序列预测多元线性回归模型