李宏毅机器学习作业HW1

本作业主要参考秋沐霖https://www.cnblogs.com/HL-space/p/10676637.html

自己代码的做的更改
1、考虑前5小时的PM2.5对第6小时的影响,有可能考虑太久以前的对当前的影响可能几乎为0.
2、考虑比较近的前2小时影响比较大,用2次项
3、随机抽样:样本打乱然后再取前90%样本数据作为训练集,取后10%样本数据作为验证集合。
4、画出了loss和No.of parameters updates的图,用来查看loss随着更新的次数的变化情况。

# 调整训练的数据集
# 这个是作者的改进版本,是用每5个小时为一组数据,然后前两个小时的平方(PM2.5可能跟前两个小时的相关性比较大),前5个小时到前3个小时使用一次方
# 来自: https://www.cnblogs.com/HL-space/p/10676637.html
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import random

# 数据预处理
def dataProcess(df):
    x_list, y_list = [], []
    # df替换指定元素,将空数据填充为0
    df = df.replace(['NR'], [0.0])
    # astype() 转换array中元素数据类型
    array = np.array(df).astype(float)
    # 将数据集拆分为多个数据帧
    for i in range(0, 4320, 18):
        for j in range(24-5):  # 数据的调整, 用前5个小时预测第6个小时的数据,因为时间越早的数据可能跟后面的数据没有什么相关性
            mat = array[i:i+18, j:j+5]  # (18, 5)
            label = array[i+5, j+5]  # 第6行是PM2.5  (1,)
            x_list.append(mat)
            y_list.append(label)  # (240*19)
    # x = np.array(x_list)  # 这样一共就有(240*19)
    # y = np.array(y_list)

    '''
    # 将每行数据都scale到0到1的范围内,有利于梯度下降,但经尝试发现效果并不好
    for i in range(18):
        if(np.max(x[:, i, :]) != 0):
            x[: , i, :] /= np.max(x[:, i, :])
    '''
    # print(x_list.shape)  # (4560=240*19, 18, 5)  240天,每一天分成19组数据,每组数据18个特征,5个小时
    # print(y_list.shape)  # (4560,)
    print(len(y_list))
    return x_list, y_list, array


# 更新参数,训练模型
def train(x_train, y_train, epoch):
    bias = 0  # 偏置值初始化
    weights = np.ones(5)  # 权重初始化
    learning_rate = 1  # 初始学习率
    reg_rate = 0.001  # 正则项系数
    bg2_sum = 0  # 用于存放偏置值的梯度平方和
    wg2_sum = np.zeros(5)  # 用于存放权重的梯度平方和
    loss_list = []

    # print(x_train[1, 9, 0:3])
    # print(x_train[1, 9, 3:])
    # print(np.concatenate((x_train[1, 9, 0:3], x_train[1, 9, 3:]**2), axis=0))

    for i in range(epoch):
        b_g = 0
        w_g = np.zeros(5)
        # 在所有数据上计算Loss_label的梯度
        # 这边是考虑到前两个小时的影响可能会更大,所以前两个小时使用平方项
        for j in range(len(y_train)):
            b_g += (y_train[j] - weights.dot(
                np.concatenate((x_train[j, 9, 0:3], x_train[j, 9, 3:]**2), axis=0)) - bias) * (-1)
            for k in range(5):
                if k < 3:
                    w_g[k] += (y_train[j] - weights.dot(
                        np.concatenate((x_train[j, 9, 0:3], x_train[j, 9, 3:]**2), axis=0)) - bias) * (-x_train[j, 9, k])
                else:
                    w_g[k] += (y_train[j] - weights.dot(
                        np.concatenate((x_train[j, 9, 0:3], x_train[j, 9, 3:] ** 2), axis=0)) - bias) * (-2*x_train[j, 9, k])
        # 如果考虑更多的特征呢?
        # 求平均
        b_g /= len(y_train)
        w_g /= len(y_train)
        #  加上Loss_regularization在w上的梯度
        for m in range(5):
            w_g[m] += reg_rate * weights[m]

        # adagrad
        bg2_sum += b_g**2
        wg2_sum += w_g**2
        # 更新权重和偏置
        bias -= learning_rate / np.sqrt(bg2_sum) * b_g
        weights -= learning_rate / np.sqrt(wg2_sum) * w_g

        # 每训练200轮,输出一次在训练集上的损失
        if i%20 == 0:
            loss = 0
            for j in range(len(y_train)):
                loss += (y_train[j] - weights.dot(x_train[j, 9, :]) - bias)**2
            print('after {} epochs, the loss on train data is:'.format(i), loss/len(y_train))
            loss_list.append(loss/len(y_train))
    show_loss(loss_list)
    return weights, bias


# 验证模型效果
def validate(x_val, y_val, weights, bias):
    loss = 0
    for i in range(len(y_val)):
        loss += (y_val[i] - weights.dot(x_val[i, 9, :]) - bias)**2
    return loss / len(y_val)


# loss随着迭代次数的增加的变化
def show_loss(loss_list):
    fig = plt.figure()
    ax1 = fig.add_subplot(1,1,1)
    plt.plot(range(len(loss_list)), loss_list, 'r')
    ax1.set_title("gradient descent loss")
    ax1.set_xlabel("No. of parameters updates")
    ax1.set_ylabel("Loss")
    plt.show()

def main():
    # 从csv中读取有用的信息
    # 由于大家获取数据集的渠道不同,所以数据集的编码格式可能不同
    # 若读取失败,可在参数栏中加入encoding = 'gb18030'
    df = pd.read_csv('train.csv', usecols=range(3,27))
    x, y, _ = dataProcess(df)
    #划分训练集与验证集

    # 下面这一段代码非常重要
    # 随机抽取90%作为训练集, 10%作为测试集
    # 获得数据集长度
    data_length = len(y)
    print(data_length)
    # 定义数据集每个数据的序号,根据序号读取数据
    index_list = list(range(data_length))
    # 随机打乱训练数据的索引序号
    random.shuffle(index_list)
    x_list = []
    y_list = []
    for i in index_list:
        x_list.append(x[i])
        y_list.append(y[i])
    x_train, y_train = np.array(x_list[0: 4104]), np.array(y_list[0: 4104])
    x_val, y_val = np.array(x_list[4104:]), np.array(y_list[4104:])
    # x_train, y_train = x[0:3200], y[0:3200]
    # x_val, y_val = x[3200:3600], y[3200:3600]
    epoch = 2000 # 训练轮数
    # 开始训练
    w, b = train(x_train, y_train, epoch)
    # 在验证集上看效果
    loss = validate(x_val, y_val, w, b)
    print('The loss on val data is:', loss)

if __name__ == '__main__':
    main()

结果分析:
1、loss还是挺大的,可能就是一开始的模型设置有问题,只考虑到PM2.5这个特征,应该可以多考虑其它几个比较重要的特征。
2、梯度下降很慢,可能因为使用adagrad的原因。可以考虑使用其它方法的梯度下降。
3、训练结果再拿到测试集上取跑一跑,看看loss的情况,这时候的loss情况是最接近真实一个外部没有见过的数据传入模型,预测结果情况的、

李宏毅机器学习作业HW1_第1张图片

你可能感兴趣的:(深度学习)