欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

机器学习入门实战---线性回归之PM2.5

程序员文章站 2022-05-02 16:35:26
...

线性回归之PM2.5

一、实验说明

相关的数据来源可以查看哔哩哔哩李宏毅老师的视频

给定训练集train.csv,测试集test.csv,要求根据前9个小时的空气检测情况预测第10个小时的PM2.5含量

二、训练集介绍

1.CSV文件,包含*丰原地区240天的气象观测资料,取每个月前20天的数据做训练集,每月后10天数据用于测试;
2.每天的监测时间点为0时,1时…到23时,共24个时间节点;
3.每天的检测指标包括CO、NO、PM2.5、PM10等气体浓度,是否降雨、刮风等气象信息,共计18项;

导入相关包

import sys
import pandas as pd
import numpy as np

三、数据预处理

浏览数据可知,数据中存在一定量的空数据NR,且多存在于RAINFALL一项。RAINFALL表示当天对应时间点是否降雨,有降雨值为1,无降雨值为NR,类似于布尔变量。因此将空数据NR全部补为0即可。

data = pd.read_csv('/home/aistudio/data/data27964/train.csv', encoding = 'big5' ) # 读取结果的结构是DataFrame
data
#表示的0~23小时
#表示的

从相关的文件列表中导入相关数据。
机器学习入门实战---线性回归之PM2.5
Pandas里主要数据结构包含DataFrame(二维表),如上打印结果,有行有列。但标准说法行(索引),列(标签)。

# panda里利用iloc选取数据,从0开始。iloc(行,列)
# 当前选取从第三列开始的所有数据
#iloc比较简单,它是基于索引位来选取数据集,0:4就是选取 0,1,2,3这四行,需要注意的是这里是前闭后开集合
data = data.iloc[:, 3:]
data[data=='NR'] = 0
data

机器学习入门实战---线性回归之PM2.5

raw_data = np.array(data) # DataFrame转换成numpy数组
raw_data

array([[‘14’, ‘14’, ‘14’, …, ‘15’, ‘15’, ‘15’],
[‘1.8’, ‘1.8’, ‘1.8’, …, ‘1.8’, ‘1.8’, ‘1.8’],
[‘0.51’, ‘0.41’, ‘0.39’, …, ‘0.35’, ‘0.36’, ‘0.32’],
…,
[‘36’, ‘55’, ‘72’, …, ‘118’, ‘100’, ‘105’],
[‘1.9’, ‘2.4’, ‘1.9’, …, ‘1.5’, ‘2’, ‘2’],
[‘0.7’, ‘0.8’, ‘1.8’, …, ‘1.6’, ‘1.8’, ‘2’]], dtype=object)

print(raw_data.shape) #代表有4320行24列的数据

(4320, 24)

四、特征提取

(1)按月份来处理数据

针对每20天来说,信息维度[18, 480] (18个feature,20*24=480)18个特征
将原始的数据按照每个月来划分,重组成12个 [18,480]

#sample[:, day * 24 :(day+1) * 24]中的“,”前面是":“表明行的内容全部都要,”,"后面的是列的内容,就是按照0-24-48-…这样将24小时的数据提取出来保存
#raw_data的数据是竖着排列的,所以raw_data[18 * (20 * month + day) : 18 * (20 * month + day+1), :]的“,”前面是0-18-36…这样取得
month_data = {}  # key: month  value: data
for month in range(12):
    sample = np.empty([18, 480])  # 创建一个空的【18, 480】数组
    for day in range(20):
        sample[:, day * 24 : (day + 1) * 24] = raw_data[18 * (20 * month + day) : 18 * (20 * month + day + 1), :]
    month_data[month] = sample
#以第一个月为例
print(month_data[0])
print(month_data[0].shape)

[[14. 14. 14. … 14. 13. 13. ]
[ 1.8 1.8 1.8 … 1.8 1.8 1.8 ]
[ 0.51 0.41 0.39 … 0.34 0.41 0.43]

[35. 79. 2.4 … 48. 63. 53. ]
[ 1.4 1.8 1. … 1.1 1.9 1.9 ]
[ 0.5 0.9 0.6 … 1.2 1.2 1.3 ]]
(18, 480)

(2)扩充数据集,获取更好的训练效果

根据实验要求,需要用连续9个时间点的数据预测第10个时间点的PM2.5。 而每个月采取的是前20天连续的数据,可以扩展成480小时的连续数据;
具体做法,每个月的第一天的0-8时的数据作为训练数据,9时的数据作标签y;9-17的数据作一个data,18时的数据作标签y…以此推,每个月480小时,有480-9= 471个data(因为走到最后只有最后九个小时减去n ),故此时总数据471 * 12 个;而每个data是18*9

x = np.empty([12 * 471, 18 * 9], dtype = float)#这里的x表示一年的为12*471 data 每个data代表了
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
            # reshape将矩阵重整为新的行列数,参数-1代表自动推断,这里去掉了18*9的二维属性,
            # 转而以一维序列代替,一维序列的顺序本身可以隐含其时序信息
            x[month * 471 + day * 24 + hour, :] = month_data[month][:,day * 24 + hour : day * 24 + hour + 9].reshape(1, -1) 
            y[month * 471 + day * 24 + hour, 0] = month_data[month][9, day * 24 + hour + 9] #value
print('x',x)
print(x.shape)
print('y',y)
print(y.shape)

结果:
x [[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]]
(5652, 162)
y [[30.]
[41.]
[44.]

[17.]
[24.]
[29.]]
(5652, 1)

数据的归一化处理

mean_x = np.mean(x, axis = 0) # 求均值, aix=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] # 所有属性归一化,避免使数据的某些特征形成主导作用
x

结果:
array([[-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.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]])

损失函数

采用预测值与标签y之间的平均欧时距离来衡量预测的准确程度
num = 471*12, 乘 1/2 是为了在后续求梯度过程中保证梯度系数为1,方便计算

学习率更新

为了在不影响模型效果的前提下提高学习速度,可以对学习率进行实时更新:即让学习率的值在学习初期较大,之后逐渐减小。这里采用比较经典的adagrad算法来更新学习率。

dim = x.shape[1] + 1 #shape[1]表示的为多少列 shape[0]表示的为多少行
w = np.zeros(shape = (dim, 1 )) #empty创建的数组,数组中的数取决于数组在内存中的位置处的值,为0纯属巧合?[0,0,0,.....0,0,0]163
x = np.concatenate((np.ones((x.shape[0], 1 )), x) , axis = 1).astype(float) #axis=1进行,concatenate (np.ones((x.shape[0], 1 ))[5652 ,1]的全一数组)行拼接 
#使用的是向量的运算
#初始化学习率(163个参数,163个200)和adagrad
learning_rate = np.array([[200]] * dim)
adagrad_sum = np.zeros(shape = (dim, 1 ))
lamuda=100
#没有隐藏层的网络
#增加精确度的方法
#1.增加迭代次数
#2.正则化的使用
for T in range(100001):
    if(T % 5000 == 0 ):
        print("T=",T)
        print("Loss:",(np.sum((x.dot(w) - y)**2)/ x.shape[0] /2)) #最小二乘损失  #问/除以x.shape[0]是什么意思 ?将向量转化成数值
        print('x',(x.dot(w) - y)**2)
    gradient = 2 * np.transpose(x).dot(x.dot(w)-y) #损失的导数x*(yh-h)
    adagrad_sum += gradient ** 2
    w = w - learning_rate * gradient / (np.sqrt(adagrad_sum) + 0.0005)#得到的w

np.save('weight.npy',w)#以二进制的形式将数据进行保存

机器学习入门实战---线性回归之PM2.5

使用模型预测

# 同处理训练集数据一样
testdata = pd.read_csv('/home/aistudio/data/data27964/test.csv', header = None, encoding = 'big5')
test_data = testdata.iloc[:, 2:]
test_data = test_data.copy() # 为防止pandas出错:A value is trying to be set on a copy of a slice from a DataFrame.

test_data[test_data == 'NR'] = 0
test_data = np.array(test_data)
test_data.shape
w = np.load('weight.npy')
 
test_x = np.empty(shape = (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(test_x.shape[0]):        ##Normalization
    for j in range(test_x.shape[1]):
        if not std_x[j] == 0 :
            test_x[i][j] = (test_x[i][j]- mean_x[j]) / std_x[j]
 
test_x = np.concatenate((np.ones(shape = (test_x.shape[0],1)),test_x),axis = 1).astype(float)
test_x.shape

(240, 163)

w.shape

(163, 1)

w = np.load('weight.npy')
ans_y = np.dot(test_x, w)
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)

机器学习入门实战---线性回归之PM2.5

相关标签: 机器学习