李宏毅2020机器学习深度学习(1) 线性回归 笔记+作业

1. 相关知识

1.1 普通的梯度下降法

在这里插入图片描述
普通方法可能出现的问题
在这里插入图片描述
学习率太小(蓝色的线),下降慢,迭代次数多
学习率太大(绿色的线),下降快,但是太快容易在极优值附近振荡
学习率特别大(黄色的线),直接越过了极优值
改进的想法:随着迭代次数增加,让学习率变小。
初始迭代时,使用较大的学习率加速下降,迭代几次后,减小学习率防止振荡和越过。

1.2 Adagrad算法

在这里插入图片描述
每个参数的学习率都把它除上之前微分的均方根,σt是每个参数的所有偏微分的均方根
在这里插入图片描述
公式化简
在这里插入图片描述
求偏导细节参考第5节

# adagrad更新梯度
# 因为常数项的存在,所以dim需要多加一栏
# eps项是避免adagrad的分母为0而加的极小数值
# 每一个dim都会对应到各自的gradient, weight(w)
# 通过一次次的iteration学习
def adagrad(x, dim, num):
    w = np.zeros([dim, 1])
    x = np.concatenate((np.ones([num, 1]), x), axis = 1).astype(float)
    learning_rate = 100
    iter_time = 10000
    adagrad = np.zeros([dim, 1])
    eps = 0.0000000001
    for t in range(iter_time):
        loss = (np.sum(np.power(np.dot(x, w) - y, 2)) )/ num # mse
        if(t%100==0):
            print(str(t) + ":" + str(loss))
        gradient = 2 * np.dot(x.transpose(), np.dot(x, w) - y) #大小为dim*1
        adagrad += gradient ** 2
        w = w - learning_rate * gradient / np.sqrt(adagrad + eps)
    np.save('weight.npy', w)

2. 作业描述

根据某地一年内18项空气质量有关的检测指标,在24小时的变化数据,使用线性回归预测PM2.5(也是指标之一)的变化。
数据如图所示
在这里插入图片描述
训练集:每个月前20天的完整数据
测试集:从剩下的资料中(10 * 12天)中抽出240 * 10小时的数据作为测试
每条数据中,前9小时的观测数据作为feature,共9 * 18 = 162个参数,第10小时的PM2.5作为answer

3. 数据预处理

指标RF对应当天是否降雨,有降雨则为1,无降雨值为NR
考虑降雨对PM2.5有显著影响,将NR全部修改为0
去除无用数据,将pandas数据帧转换为numpy的二维数组
然后抽取训练数据
参考答案这里有些小错误

# 数据预处理
def dataProcess(data):
    # 第一步,数据预处理
    # 去除前3列的无用数据
    data = data.iloc[1:, 3:]
    # 将未降雨的值"NR"修改为0
    data[data == 'NR'] = 0
    raw_data = data.to_numpy()
    return raw_data

4. 建立模型

线性模型
在这里插入图片描述
损失函数为MSE
在这里插入图片描述

5. 损失函数求导

为了便于用numpy写代码
将常数项也看作系数矩阵的一部分
在这里插入图片描述
求偏导公式
在这里插入图片描述

6. 完整代码

# -*- coding: utf-8 -*-

import sys
import pandas as pd
import numpy as np
import csv


# 数据预处理
def dataProcess(data):
    # 第一步,数据预处理
    # 去除前3列的无用数据
    data = data.iloc[1:, 3:]
    # 将未降雨的值"NR"修改为0
    data[data == 'NR'] = 0
    raw_data = data.to_numpy()
    return raw_data

# 标准化
def normalize(x):
    mean_x = np.mean(x, axis = 0) 
    std_x = np.std(x, axis = 0) 
    for i in range(len(x)): 
        for j in range(len(x[0])): 
            if std_x[j] != 0:
                x[i][j] = (x[i][j] - mean_x[j]) / std_x[j]
    return x

# adagrad更新梯度
# 因为常数项的存在,所以dim需要多加一栏
# eps项是避免adagrad的分母为0而加的极小数值
# 每一个dim都会对应到各自的gradient, weight(w)
# 通过一次次的iteration学习
def adagrad(x, dim, num):
    w = np.zeros([dim, 1])
    x = np.concatenate((np.ones([num, 1]), x), axis = 1).astype(float)
    learning_rate = 100
    iter_time = 10000
    adagrad = np.zeros([dim, 1])
    eps = 0.0000000001
    for t in range(iter_time):
        loss = (np.sum(np.power(np.dot(x, w) - y, 2)) )/ num # mse
        if(t%100==0):
            print(str(t) + ":" + str(loss))
        gradient = 2 * np.dot(x.transpose(), np.dot(x, w) - y) #dim*1
        adagrad += gradient ** 2
        w = w - learning_rate * gradient / np.sqrt(adagrad + eps)
    np.save('weight.npy', w)
    return w # 只是方便在内存中查看结果

# 18个feature中的第10个为要预测的PM2.5
# 將原始 4320 * 18 的資料重組成 18 (features) * 4320 (hours) 的資料。
# 12个月,每个月20天 12 * 20 * 18 =  4320
if __name__ == '__main__':
    data = pd.read_csv('train.csv', header = None, encoding = 'big5')
    raw_data = dataProcess(data)
    # 每九小时形成一条训练data
    # 考虑PM2.5每日会有周期性的变化规律,比如工厂不会昼夜不停等
    #(答案思路非常清奇,用0-8预测9,然后1-9预测10,会充分利用一个月数据中的480小时,得到471个训练数据)
    # 选择用0 - 8点的数据来预测上午9点的PM2.5 
    # 权重项有18*9 = 162项
    raw_data = raw_data[:,0:10]
    x = np.empty([12 * 20, 18 * 9], dtype = float)
    y = np.empty([12 * 20, 1], dtype = float)
    for day in range(240):
        y[day,0] = raw_data[18*day+9,9]
    for day in range(240):
        x[day,:] = raw_data[18*day:18*(day+1),0:9].reshape(1, -1)
    x = normalize(x) # 训练数据标准化
    dim = 18 * 9 + 1 # 加上截距项
    num = 240        # 训练数据共12 * 20 = 240条
    w = adagrad(x, dim, num)
    # 用训练出来的w,计算y
    data_test = pd.read_csv('test.csv', header = None, encoding = 'big5')
    data_test = data_test.iloc[:, 2:]
    data_test[data_test == 'NR'] = 0
    data_test = data_test.to_numpy()
    test_x = np.empty([240, 18*9], dtype = float)
    for i in range(240):
        test_x[i, :] = data_test[18 * i: 18* (i + 1), :].reshape(1, -1)
    test_x = np.concatenate((np.ones([240, 1]), test_x), axis = 1).astype(float)
    # 测试数据要和训练数据作相同的标准化
    test_x = normalize(test_x) 
    ans_y = np.dot(test_x, w)
    # 把预测结果存入csv
    with open('submit.csv', mode='w', newline='') as submit_file:
        csv_writer = csv.writer(submit_file)
        header = ['id', 'value']
        print(header)
        csv_writer.writerow(header)
        for i in range(240):
            row = ['id_' + str(i), ans_y[i][0]]
            csv_writer.writerow(row)
            print(row)      
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页