李宏毅机器学习作业1-使用线性回归预测PM2.5

题目

  给定台湾丰原地区一年(12个月)的PM2.5及各项污染指标的数据,抽取每个月前二十天数据组成训练集train.csv,取每月后十天的数据组成测试集test.csv,其中每10小时的数据为一组,前九小时作为输入,要求根据输入预测第十小时的输出。
  由于编码不同,我怒改了一波表头并改了文件编码,这不影响结果。
在这里插入图片描述

图1 train.csv中的数据

正文

数据预处理
  观察train.csv文件发现,对应RAINFALL一项有很多缺失值,用NR表示。分析得出,RAINFALL应该是一个 [ 0   1 ] [0\ 1] [0 1]之间的浮点数,表示下雨还是不下,那么NR很有可能代表的是0,这里先将NR都表示为0.0.

数据存储
  由于题目要求是根据前九个小时预测第十个小时的PM2.5值,因此在一天的24小时中,都可以以 9 + 1 9+1 9+1为滑动窗口采集数据,则一天可采集15组数据,总共可采集 12 × 20 × ( 24 − 9 ) = 3600 12\times 20\times (24-9)=3600 12×20×(249)=3600组数据;
  数据集是否可以扩大呢?想象一下,前面说到每个月采取前20天数据作为已知,而这前20天又都是连续的,因此可以以20天为1组,将每20天的小时数据首尾相连,这样通过滑动窗口获得的数据数量为 12 × ( 20 × 24 − 9 ) = 5652 12\times (20\times 24-9)=5652 12×(20×249)=5652组。

回归模型
  采用多元线性回归模型,其目标为: arg ⁡ min ⁡ w , b 1  n  ∑ i = 1 n ( y ^ i − x i T ⋅ w − b ) 2 \arg \min _{w, b} \frac{1}{ \text { n }}\sum_{i=1}^{n}\left(\hat{y}^{i}-\boldsymbol x^{i T} \cdot\boldsymbol w-b\right)^{2} argminw,b n 1i=1n(y^ixiTwb)2
其中 x \boldsymbol x x w \boldsymbol w w均为向量,且均属于 R 9 × 1 R^{9\times 1} R9×1.

梯度下降法求解
  经调参发现,学习率为0.00001,迭代次数为1000次时结果尚佳,训练集平均损失为:4.473245434194629,测试集平均损失为:4.97302969793434。
  另外,本模型采用adagrad进行了优化。

线性代数方法求标准解(基于上面的模型,只考虑PM2.5)
  计算得出训练集平均损失为:4.443108788904938

代码

# -*- coding:utf-8 -*-
import numpy as np
import pandas as pd


def data_processing(df):
    df = df.replace('NR', 0.0)
    temp = np.array(df).astype(float)

    # 每隔18取一次PM2.5,分成12月(组),每组480小时
    temp = temp[9:len(temp):18]
    new = []
    for i in range(0, len(temp), 20):
        t = []
        for j in range(i, i+20):
            t.extend(temp[j].tolist())
        new.append(t)

    # 下面取训练集
    x_data, y_data = [], []
    for i in range(len(new)):
        for j in range(9, len(new[0])):
            x_data.append(new[i][j-9:j])
            y_data.append(new[i][j])

    return x_data, y_data


def linear_algbra(x_data, y_data):
    y = np.array(y_data).T
    x = np.array(x_data)
    x = np.insert(x, 0, len(x)*[1], axis=1)
    # print(x)
    temp = np.matrix(x.T.dot(x))
    weight = temp.I.dot(x.T).dot(y)
    return weight, list(x)


def count_loss(standard, x_data, y_data):
    sum = 0.0
    for i in range(len(y_data)):
        x = np.array(x_data[i])
        st = np.array(standard)
        sum += np.abs(y_data[i] - x.dot(st.T))
    sum /= len(y_data)
    print('average loss: ', float(sum))


def gradient_descent(x_data, y_data):
    # 初始化
    lr = 1
    epoch = 1000
    weight = np.zeros(9)
    bias = 0
    b_sum, w_sum = 0.0, 0.0
    # 梯度下降
    for e in range(epoch):
        tw = np.zeros(9)
        tb = 0.0
        for i in range(len(y_data)):
            tb -= 2.0*(y_data[i]-bias-weight.T.dot(x_data[i]))
            tw -= 2.0*(y_data[i]-bias-weight.T.dot(x_data[i]))*np.array(x_data[i])
        # 下面不加的话会上溢
        tw /= len(y_data)
        tb /= len(y_data)
        # anagrad
        b_sum += tb**2
        w_sum += tw.dot(tw.T)
        bias -= lr/np.sqrt(b_sum)*tb
        weight -= lr/np.sqrt(w_sum)*tw

    return np.insert(weight, 0, [bias])


def test(standard):
    ans = pd.read_csv('ans.csv', usecols=[1])
    y_test = ans.astype(float)
    df = pd.read_csv('test.csv', usecols=[1])
    res = []
    df = df.replace('NR', 0.0)
    x_test = df.astype(float)
    x_test = x_test[8::18]
    t = np.copy(x_test)
    x_test = np.insert(t, 0, len(t)*[1], axis=1)
    sum = 0.0
    for i in range(len(x_test)):
        temp = standard.T.dot(x_test[i])
        sum += abs(np.array(y_test)[i] - temp)
        res.append(temp)
    sum /= len(x_test)
    return res, sum


if __name__ == '__main__':
    df = pd.read_csv('train.csv', usecols=np.arange(3, 27).tolist())  # usecols控制读取的列,这里不读前三列
    x_data, y_data = data_processing(df)
    standard, x1 = linear_algbra(x_data, y_data)  # 计算标准的weight
    gd = gradient_descent(x_data, y_data)         # 使用梯度下降计算出的权重
    print('linear algobra', end=' ')
    count_loss(standard, x1, y_data)              # 4.443108788904938
    print('gradient descent', end=' ')
    count_loss(gd, x1, y_data)                    # 5.057686349538455
    res, los = test(gd)
    print('loss in test.csv: ', los)


结果

在这里插入图片描述

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值