'''
本程序简单预测PM2.5的走向,每个月只取了20天的测量数据。
共有18中污染源,即将 18种污染源的数据和对应的PM2.5的数据 进行训练
再根据训练结果来预测新的数据下PM2.5的值
'''
# import library #
import csv
import numpy as np
from numpy.linalg import inv
import random
import math
import sys
# read data #
data = []
# 每一个维度存储一种污染物的数据,一共有18种污染物
for i in range(18):
data.append([]) # []表示这十八个输入中,每一个输入都是一个列表
n_row = 0 # 初始从第0行开始
# 打开数据文件,文件big5编码为繁体字
text = open('D:/PythonCodes/CNN/train.csv', 'r', encoding='big5')
# 读取名称为text的Excel文件,返回文件行的累加信息,类型为_csv.reader
row = csv.reader(text , delimiter=",")
# r中保存了当前行的所有信息,r是一个列表,每次循环到这就更换到下一行
for r in row:
# 第0行没有数据信息
if n_row != 0:
# 每一列只有第3-27格有值(一天内24小时的数值)
for i in range(3,27):
if r[i] != "NR":
# data[]中一共可以存放18个列表,每一个列表存放某一种污染物的所有数值
data[(n_row-1)%18].append(float(r[i]))
else:
data[(n_row-1)%18].append(float(0))
n_row = n_row+1
text.close()
'''
file = open('D:/PythonCodes/CNN/testdata.csv','w', encoding = 'utf-8')
for i in range(len(data)):
s = str(data[i]).replace('[','').replace(']','')#去除[],这两行按数据不同,可以选择
s = s + '\n' #去除单引号,逗号,每行末尾追加换行符
file.write(s)
file.close()
print("保存文件成功")
'''
# Parse Data to (x,y) #
x = []
y = []
# 一共有12个月,每个月20天
for i in range(12):
# 一共有480个小时,连续取10个小时一组的数据,可取471组(最后9个数据舍去)
for j in range(471):
x.append([]) # 在x中加入列表存储数据
# 污染物的种类一共有18种
for t in range(18):
# 取每种污染物前9小时的数据,在第10小时存放PM2.5的值
for s in range(9):
x[471*i+j].append(data[t][480*i+j+s] )
y.append(data[9][480*i+j+9]) # PM2.5的数据存放在第10行
# 每个按行排列
x = np.array(x)
y = np.array(y)
# add square term
# x = np.concatenate((x,x**2), axis=1) 将数据量翻倍,新的数据为x^2
# add bias
# 5652行1列的ones,每一行1后面直接连接x的每行列表
# 此处多的一列存储的是bias,值为1
x = np.concatenate((np.ones((x.shape[0],1)),x), axis=1)
#print(x.shape) # (5652, 163)
#init weight & other hyperparams#
w = np.zeros(len(x[0])) # shap: (163,) 0: 163 __len__: 1 size: 163
l_rate = 10 # 学习率,用于更新w
repeat = 10000 # 迭代次数
#check your ans with close form solution#
# use close form to check whether ur gradient descent is good
# however, this cannot be used in hw1.sh
# w = np.matmul(np.matmul(inv(np.matmul(x.transpose(),x)),x.transpose()),y)
'''模型是Y = b + w * x'''
#start training#
# 将x矩阵进行转置,此时第一行全是1
# shape: (5652,) 0: 5652 len: 1 size: 5652
x_t = x.transpose()
s_gra = np.zeros(len(x[0])) # 163行的0
for i in range(repeat):
hypo = np.dot(x,w) # 做矩阵乘法,(5652, 163)*(163, 1) shape = (5652, 1),预测值
loss = hypo - y # 预测数值 - 真实数值
cost = np.sum(loss**2) / len(x) # L(f) = (y - f)^2 求和再求平局值
cost_a = math.sqrt(cost) # 开方
# 梯度下降
gra = np.dot(x_t,loss) # (163, 5652) * (5652, 1) shape: (163, 1) dL
s_gra += gra**2
ada = np.sqrt(s_gra) # 均方根
w = w - l_rate * (gra/ada) # 更新后的w
print ('iteration: %d | Cost: %f ' % ( i,cost_a))
# save model
np.save('model.npy',w)
# read model
w = np.load('model.npy')
test_x = []
n_row = 0
text = open('D:/PythonCodes/CNN/test.csv' ,"r")
row = csv.reader(text , delimiter= ",")
for r in row:
if n_row %18 == 0:
test_x.append([]) # 灭没有18个数据就生成新的列表
for i in range(2,11):
test_x[n_row//18].append(float(r[i]) ) # // 表示向下取整
else :
for i in range(2,11):
if r[i] !="NR":
test_x[n_row//18].append(float(r[i]))
else:
test_x[n_row//18].append(0)
n_row = n_row+1
text.close()
test_x = np.array(test_x)
# add square term
# test_x = np.concatenate((test_x,test_x**2), axis=1)
# add bias
test_x = np.concatenate((np.ones((test_x.shape[0],1)),test_x), axis=1) # 把test里面的数据连接到ones后面
ans = []
for i in range(len(test_x)):
ans.append(["id_"+str(i)])
a = np.dot(w,test_x[i]) # 用已经训练的w来生成预测值,并存入ans
ans[i].append(a)
filename = "predict.csv" # 最后把结果写入predict的文件中
text = open(filename, "w+")
s = csv.writer(text,delimiter=',',lineterminator='\n')
s.writerow(["id","value"])
for i in range(len(ans)):
s.writerow(ans[i])
text.close()