预测PM2.5--李宏毅机器学习梯度下降作业

初学python和机器学习,此文的写作目的仅仅是日常学习笔记。
code以及详细参考:https://blog.csdn.net/iteapoy/article/details/105431738

原始代码

1. 载入train.csv
import numpy as np
import sys
import pandas as pd

#读入train.csv,繁体字以big5为编码, 用pandas库读取csv文件
data = pd.read_csv('./train.csv', encoding = 'big5')
#显示前20行
data.head(3)

在这里插入图片描述
第1列是日期,第2列是观测站所在地,第3列是观测指标,第4列-第27列是0-23共24小时。

data.shape
Out:
(4320, 27)

数据规格为:4320行(12个月每个月前20天18个观测指标),27列(日期+观测地点+观测指标+24个小时)

2. 预处理

MAC同时打开多个终端快捷键:control+N

终端输入:pip list
查看pandas版本为:0.23.4
更新pandas版本:

  • 第一步:卸载pandas旧版本
    pip3 uninstall pandas

  • 第二步:下载最新版本:https://pypi.org/project/pandas
    说明:由于python默认源是国外的,所以下载可能会出现很慢的情况,这里我建议直接切换镜像源下载

    pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -U pandas
    

    这个命令的意思是指定在https://pypi.tuna.tsinghua.edu.cn/simple网站 下载pandas的包

    解释一下上面的-U 和-i

    -U:安装升级

    -i:指定源

  • 第三步:更新成功后需关闭jupyter后重新打开即可

# 丢弃前两列,需要的是从第三列开始的数值
data = data.iloc[:, 3:]
# 把降雨的NR字符变成数值0
data[data == 'NR'] = 0
# 把dataframe转换成numpy的数组
raw_data = data.to_numpy()
raw_data
3. 特征提取

4320行中,每18行(18个观测指标)是一天的数据,将18行作为一天,4320/18=240天(一年12个月,每个月20天),根据每个月将4320行×24列的数据分成12 组18 行(features) × 480 列(hours) 的数据:
(18行为18个特征值,480列为连续的480个小时:20*24)

month_data = {}
for month in range(12):#12组
    sample = np.empty([18, 480])
    for day in range(20):#20天
        sample[:, day * 24 : (day + 1) * 24] = raw_data[18 * (20 * month + day) : 18 * (20 * month + day + 1), :]
    month_data[month] = sample

分成了12个月,每个月有18行×480列的数据。

对于每个月,每10个小时分成一组,由前9个小时的数据来预测第10个小时的PM2.5,把前9小时的数据放入x,把第10个小时的数据放入y。窗口的大小为10,从第1个小时开始向右滑动,每次滑动1小时。因此,每个月都有471组这样的数据。

把一组18×9的数据平铺成一行向量,然后放入x的一行中,每个月有471组,共有12×471组向量,因此x有12×471行,18×9列。

将预测值放入y中,y有12(月)×471(组)行,1列。

x = np.empty([12 * 471, 18 * 9], dtype = float)
y = np.empty([12 * 471, 1], dtype = float)
for month in range(12):
    for day in range(20):
        for hour in range(24):
            if day == 19 and hour > 14:
                continue
            x[month * 471 + day * 24 + hour, :] = month_data[month][:,day * 24 + hour : day * 24 + hour + 9].reshape(1, -1) #vector dim:18*9 (9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9)
            y[month * 471 + day * 24 + hour, 0] = month_data[month][9, day * 24 + hour + 9] #value
print(x)
print(y)
out:
[[14.  14.  14.  ...  2.   2.   0.5]
 [14.  14.  13.  ...  2.   0.5  0.3]
 [14.  13.  12.  ...  0.5  0.3  0.8]
 ...
 [17.  18.  19.  ...  1.1  1.4  1.3]
 [18.  19.  18.  ...  1.4  1.3  1.6]
 [19.  18.  17.  ...  1.3  1.6  1.8]]
[[30.]
 [41.]
 [44.]
 ...
 [17.]
 [24.]
 [29.]]
4. 标准化(Normalization)

x = ( x − μ ) / σ x = (x - μ)/σ x=(xμ)/σ

μ是xx的均值,σσ是xx的标准差。通过标准化,可以:将有量纲的表达式,经过变换,化为无量纲的表达式,成为标量使得数据更加符合独立同分布条件

'''
mean() 函数定义: 
numpy.mean(a, axis, dtype, out,keepdims )

mean()函数功能:求取均值 
经常操作的参数为axis,以m * n矩阵举例:

axis 不设置值,对 m*n 个数求均值,返回一个实数
axis = 0:压缩成行,对各列求均值,返回 1* n 矩阵
axis =1 :压缩成列,对各行求均值,返回 m *1 矩阵

np.std()是用来计算标准差
'''
mean_x = np.mean(x, axis = 0) #18 * 9 
std_x = np.std(x, axis = 0) #18 * 9 
for i in range(len(x)): #12 * 471
    for j in range(len(x[0])): #18 * 9 
        if std_x[j] != 0:
            x[i][j] = (x[i][j] - mean_x[j]) / std_x[j]
x

这里每一列是一个观测指标,按列进行标准化。

把训练数据分成训练集train_set和验证集validation,其中train_set用于训练,而validation不会参与训练,仅用于验证。(在baseline中并没有用)

import math
#`Math.floor()` 返回小于或等于一个给定数字的最大整数。
x_train_set = x[: math.floor(len(x) * 0.8), :]
y_train_set = y[: math.floor(len(y) * 0.8), :]
x_validation = x[math.floor(len(x) * 0.8): , :]
y_validation = y[math.floor(len(y) * 0.8): , :]
print(x_train_set)
print(y_train_set)
print(x_validation)
print(y_validation)
print(len(x_train_set))
print(len(y_train_set))
print(len(x_validation))
print(len(y_validation))
[[-1.35825331 -1.35883937 -1.359222   ...  0.26650729  0.2656797
  -1.14082131]
 [-1.35825331 -1.35883937 -1.51819928 ...  0.26650729 -1.13963133
  -1.32832904]
 [-1.35825331 -1.51789368 -1.67717656 ... -1.13923451 -1.32700613
  -0.85955971]
 ...
 [ 0.86929969  0.70886668  0.38952809 ...  1.39110073  0.2656797
  -0.39079039]
 [ 0.71018876  0.39075806  0.07157353 ...  0.26650729 -0.39013211
  -0.39079039]
 [ 0.3919669   0.07264944  0.07157353 ... -0.38950555 -0.39013211
  -0.85955971]]
[[30.]
 [41.]
 [44.]
 ...
 [ 7.]
 [ 5.]
 [14.]]
[[ 0.07374504  0.07264944  0.07157353 ... -0.38950555 -0.85856912
  -0.57829812]
 [ 0.07374504  0.07264944  0.23055081 ... -0.85808615 -0.57750692
   0.54674825]
 [ 0.07374504  0.23170375  0.23055081 ... -0.57693779  0.54674191
  -0.1095288 ]
 ...
 [-0.88092053 -0.72262212 -0.56433559 ... -0.57693779 -0.29644471
  -0.39079039]
 [-0.7218096  -0.56356781 -0.72331287 ... -0.29578943 -0.39013211
  -0.1095288 ]
 [-0.56269867 -0.72262212 -0.88229015 ... -0.38950555 -0.10906991
   0.07797893]]
[[13.]
 [24.]
 [22.]
 ...
 [17.]
 [24.]
 [29.]]
4521
4521
1131
1131
4. 训练
  • Pseudo code
    1. Declare weight vector, initial lr , and # of iteration
    2. For i_th iteration
      1. y’ = the inner product of train_x and weight vector
      2. Loss = y’ - train_y
      3. Gradient = 2*np.dot((train_x)’ , L)
      4. Weight vector -= learning rate * gradient

在这里插入图片描述

Adagrad

在这里插入图片描述

和上图不同处: 下面Loss的代码用到的是 Root Mean Square Error

因为存在常数项b,所以维度(dim)需要多加一列;eps项是极小值,避免adagrad的分母为0.

每一个维度(dim)会对应到各自的gradient和权重w,通过一次次的迭代(iter_time)学习。最终,将训练得到的模型(权重w)存储为.npy格式的文件。

dim = 18 * 9 + 1
w = np.zeros([dim, 1])
'''
numpy提供了numpy.concatenate((a1,a2,...), axis=0)函数。能够一次完成多个数组的拼接。其中a1,a2,...是数组类型的参数
>>> a=np.array([[1,2,3],[4,5,6]])
>>> b=np.array([[11,21,31],[7,8,9]])
>>> np.concatenate((a,b),axis=0)
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [11, 21, 31],
       [ 7,  8,  9]])

>>> np.concatenate((a,b),axis=1)  #axis=1表示对应行的数组进行拼接
array([[ 1,  2,  3, 11, 21, 31],
       [ 4,  5,  6,  7,  8,  9]])
'''
x = np.concatenate((np.ones([12 * 471, 1]), x), axis = 1).astype(float)
learning_rate = 100
iter_time = 1000
'''
用法:zeros(shape, dtype=float, order='C')
返回:返回来一个给定形状和类型的用0填充的数组;
参数:shape:形状
dtype:数据类型,可选参数,默认numpy.float64
order:可选参数,c代表与c语言类似,行优先;F代表列优先
'''
adagrad = np.zeros([dim, 1])
eps = 0.0000000001
for t in range(iter_time):
    loss = np.sqrt(np.sum(np.power(np.dot(x, w) - y, 2))/471/12)#rmse
    if(t%100==0):
        print(str(t) + ":" + str(loss))
    #Numpy中dot()函数主要功能有两个:**向量点积和矩阵乘法**。
    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)
w


5.测试
# 读入测试数据test.csv
testdata = pd.read_csv('./test.csv', header = None, encoding = 'big5')
# 丢弃前两列,需要的是从第3列开始的数据
test_data = testdata.iloc[:, 2:]
# 把降雨为NR字符变成数字0
test_data[test_data == 'NR'] = 0
# 将dataframe变成numpy数组
test_data = test_data.to_numpy()
# 将test数据也变成 240 个维度为 18 * 9 + 1 的数据。
test_x = np.empty([240, 18*9], dtype = float)
for i in range(240):
    test_x[i, :] = test_data[18 * i: 18* (i + 1), :].reshape(1, -1)
for i in range(len(test_x)):
    for j in range(len(test_x[0])):
        if std_x[j] != 0:
            test_x[i][j] = (test_x[i][j] - mean_x[j]) / std_x[j]
test_x = np.concatenate((np.ones([240, 1]), test_x), axis = 1).astype(float)
test_x


out:
array([[ 1.        , -1.19914238, -1.35883937, ...,  0.73508789,
         0.73411671,  0.54674825],
       [ 1.        , -1.67647517, -1.67694799, ...,  0.36022341,
         0.82780412, -0.20328266],
       [ 1.        , -2.18563014, -1.67694799, ...,  0.82880401,
         0.0783049 , -0.29703653],
       ...,
       [ 1.        , -1.67647517, -1.8360023 , ...,  0.07907505,
        -0.10906991, -1.04706744],
       [ 1.        , -1.35825331, -1.51789368, ..., -0.10835719,
         0.35936711,  0.07797893],
       [ 1.        , -1.8355861 , -1.8360023 , ..., -1.04551839,
        -1.13963133, -1.14082131]])

载入模型即可对test数据进行预测,得到预测值ans_y。

w = np.load('weight.npy')
ans_y = np.dot(test_x, w)
ans_y
5. 将预测值保存到csv文件
import 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)

以上,baseline已完成,需要在baseline的基础上优化模型。优化模型这一部分就不在这里赘述了,我会另开一篇博客,记录我优化模型的几个过程。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值