import csv
import matplotlib.pyplot as plt
import numpy as np
# 1.读取train.csv
# 共18种污染物,构建列表,按照污染物种类分别存储:[[存储每天的24小时的AMB_TEMP数据(每天一行(row)数据,共240天(行),240*24个值)],
# [存储每天的24小时的CH4数据(每天一行(row)数据,共240天(行))],[],...[]],
# 即:
# 0 1 … … 5759
# AMB_TEMP 1月第一天0时 1月第一天1时 … … 12月第20天23时
# CH4 1月第一天0时 1月第一天1时 … … 12月第20天23时
# CO 1月第一天0时 1月第一天1时 … … 12月第20天23时
# … … … … … …
# WS_HR 1月第一天0时 1月第一天1时 … … 12月第20天23时
data = []
for i in range(18):
data.append([])
with open(r'C:\Users\hp\Desktop\李宏毅\NTU_ML2017_Hung-yi-Lee_HW-master\HW1\data\train.csv', 'r',
encoding='big5') as my_file:
# encoding='big5'繁体中文码,简体中文码:GB2312;西欧字符:UTF-8;不注明将无法读取
rows = csv.reader(my_file, delimiter=',') # 读取csv文件,以逗号隔开
row_read = 0 # 从第一行开始读取(第0行是表头)
for row in rows:
# 读取第4列~27列数据(column[3]~column[26])
if row_read != 0: # 表头不读
for column in range(3, 27):
if (row[column] == 'NR'):
data[(row_read - 1) % 18].append(float(0)) # 保证不同日期的同一种污染物在同一个列表中
else:
data[(row_read - 1) % 18].append(float(row[column]))
row_read += 1
# 根据前面连续9个小时的数据,估计第10个小时的数据
# 由于每个月只有20天的数据,因此每个月的最后一天的最后9个小时将不能构成连续的10个小时,而其他时间均连续,因此可利用的数据有
# (24*20-9=471)个小时
# 利用trainX存储连续的九个小时,trainY存储第十个小时
trainX = []
trainY = []
for month in range(12):
for hour in range(471):
trainX.append([])
for row in range(18):
for column in range(9):
# 一个月有478hour可以利用,trainX[0]:0-8列共9个小时内,18种污染物的值,trainX[1]:1-9列内18种污染物的值,trainX[2]:
# 2-10列内18种污染物的值......trainX[470]:470-478列内(479小时)18种污染物的值,train[471]:2月第一天0-8h内18种污染物的值(跳过上个月第480h)
# ......以此类推
trainX[month * 471 + hour].append(data[row][month * 480 + hour + column])
trainY.append(
data[9][month * 480 + 9 + hour])
# data[9][x]即为PM2.5那一行的数据;从第9列开始(第十个小时)依次读取:9,10,11,...479(第480小时)
# 将矩阵转化为numpy数组(方便运算)
trainX = np.array(trainX)
trainY = np.array(trainY)
# 读取test.CSV,
testX = []
with open(r'C:\Users\hp\Desktop\李宏毅\NTU_ML2017_Hung-yi-Lee_HW-master\HW1\data\test.csv', 'r') as my_file:
rows = csv.reader(my_file, delimiter=',')
row_read = 0
for row in rows:
if (row_read % 18 == 0):
# row_read=0,第一行,row_read=18第19行
# 每读完18行(row_read=18,36...)添加一个数组
testX.append([])
for i in range(2, 11): # 读取第2-10列
testX[row_read // 18].append(float(row[i])) # //地板除,向下取商,1//18=0,2//18=0......18//18=1,19//18=1
else:
for i in range(2, 11):
if (row[i] == 'NR'): # 读到是否下雨按照0(no rain)处理
testX[row_read // 18].append(float(0))
else:
testX[row_read // 18].append(float(row[i]))
# testX[0]:id_0(某一天)9个小时内 18种污染物值;testX[1]:id_1 9小时内 18种污染物的值......直到testX[239]
row_read += 1 # 读取下一行
# testX:
# 0 1 … … 162
# # # # 0 id_0 AMB_TEMP 0时浓度 id_0 AMB_TEMP 1时浓度 … … id_0 WS_HR 8时浓度
# # # # 1 id_1 AMB_TEMP 0时浓度 id_1 AMB_TEMP 1时浓度 … … id_1 WS_HR 8时浓度
# # # # 2 id_2 AMB_TEMP 0时浓度 id_2 AMB_TEMP 1时浓度 … … id_2 WS_HR 8时浓度
# # # # … … … … … …
# # # # 239 id_239 AMB_TEMP 0时浓度 id_239 AMB_TEMP 1时浓度 … … id_239 WS_HR 8时浓度
testX = np.array(testX)
# print(testX.reshape(240,162)) testX为240*162矩阵
# 读取ans.csv,用来对比预测结果
with open(r'C:\Users\hp\Desktop\李宏毅\NTU_ML2017_Hung-yi-Lee_HW-master\HW1\data\ans.csv') as my_file:
ans = csv.reader(my_file, delimiter=',')
y = []
row_read = 0
for i in ans:
if row_read != 0:
y.append(i[1]) # 跳过表头
row_read += 1
# print(y) ['33', '60', '16',...]注意此处的为字符串,需转化为数字,可以用y.append(float(i[1]))
y = np.array(list(map(float, y))) # list(map(float,y))——转化为数字列表;再转化为numpy数组
# print(y) [ 33. 60. 16....]
# 转化为列表
y = y.tolist()
# print(y) [33.0, 60.0, 16.0, 33.0, 5.0, 41.0,...]
# 训练模型
#1adagrad
def adagrad(trainX, trainY, w,iteration, lr):
loss_process = []
sum_grad = np.zeros(len(trainX[0])) # 长度为162的零数组[0,0,0,0,...]
for i in range(iteration):
hypo = np.dot(trainX, w) # trainX*W,假设PM2.5与18种污染物呈线性关系:y=w*x ,即 hypo=trainX*w
loss = hypo - trainY # loss
cost = np.sum(loss ** 2) / len(trainX) # len(trainX)=5652(行数) COST是一个数字,不是矩阵
# sum(loss**2)用于求出loss每一项的平方再相加:........np.sum(mat1**2),mat1=[1,2,3]——1+4+9=14
loss_process.append(cost) # 计算出的cost存入loss_process
grad = np.dot(trainX.transpose(), loss) # trainX.transpose():转置矩阵,trainX的转置*loss计算梯度
# adagrad
sum_grad = s_grad + grad ** 2 # 梯度平方求和(矩阵)
ada = np.sqrt(sum_grad) # 矩阵
w = w - lr * grad / ada
print('iteration:%d|Cost:%f' % (i + 1, cost)) # 打印迭代次数、cost值
return w, loss_process
# 2.SGD(随机梯度下降)
# def SGD(trainX,trainY,w,iteration,lr):
# list_cost=[]
# for i in range(iteration):
# hypo=np.dot(trainX,w)
# loss=hypo-trainY
# cost=np.sum(abs(loss))/len(trainX)
# list_cost.append(cost)
#
# rand=np.random.randint(0,len(trainX))#返回一个随机数
# grad=trainX[rand]*loss[rand]/len(trainX)#随机梯度
# w=w-lr*grad
# return w,list_cost
# w1,loss_process=SGD(trainX,trainY,w,1000,1)
# 3.gradient descent
# def grad(trainX,trainY,w,lr,iteration):
#
# cost_process=[]
# for i in range(iteration):
#
# hypo=np.dot(trainX,w)
# loss=hypo-trainY
# grad=np.dot(trainX.T,loss)
# cost=np.sum(loss**2)/len(trainX)
# cost_process.append(cost)
# w=w-lr*grad
# return w,cost_process
# w1,cost_process=grad(trainX,trainY,w,1,1000)
# 调用函数,分析结果
testX = np.concatenate((np.ones((testX.shape[0], 1)), testX), axis=1)
# testX.shape[0]:240,将ones(240*1)与testX(240*162)在axis=1(行)上拼接 (axis=0在列进行拼接)
# 得到240*163的矩阵:
# testX
# [[ 1. 15. 14. ... 2.5 2.5 2.3]
# [ 1. 12. 12. ... 2.1 2.6 1.5]
# [ 1. 8.8 12. ... 2.6 1.8 1.4]
# ...
# [ 1. 12. 11. ... 1.8 1.6 0.6]
# [ 1. 14. 13. ... 1.6 2.1 1.8]
# [ 1. 11. 11. ... 0.6 0.5 0.5]]
trainX = np.concatenate((np.ones((trainX.shape[0], 1)), trainX), axis=1)
# ones:5652*1, trainX:5652*162
# print(trainX) 5652*163矩阵
# trainX
# [[ 1. 14. 14. ... 2. 2. 0.5]
# [ 1. 14. 14. ... 2. 0.5 0.3]
# [ 1. 14. 13. ... 0.5 0.3 0.8]
# ...
# [ 1. 17. 18. ... 1.1 1.4 1.3]
# [ 1. 18. 19. ... 1.4 1.3 1.6]
# [ 1. 19. 18. ... 1.3 1.6 1.8]]
w = np.zeros(len(trainX[0]))
# w为长度为162的零数组
# print(w)
# [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0....... 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
# print(np.shape(np.dot(trainX,w)))
# (5652,)
w1, loss_list1 = ada(trainX, trainY, w, 1000, 1)
# 保存为csv文件,并返回predictY
def test(testX, w, restore_location):
predictY = []
ans = []
for i in range(len(testX)): # len(testX)=240
ans.append([])
ans[i].append('id_' + str(i)) # 存储预测值及其编号[['id_0', 23.696998304887256], ['id_1', 63.00759564013169],...]
# print(ans)
# ['id_0', 'id_1', 'id_2', 'id_3', 'id_4', 'id_5',...'id_238', 'id_239']
predicty = np.dot(testX[i], w) # 向量相乘:数字
predictY.append(predicty) # 存储预测值[23.696998304887256, 63.00759564013169, 24.96169628067876,...]
ans[i].append(predicty)
text = open(restore_location, 'w+') # w+可读写模式打开存储预测结果
my_writer = csv.writer(text, delimiter=',', lineterminator='\n') # lineterminator='\n':默认写入一行数据时会自动空行,此处是为了去掉空行
my_writer.writerow(['id', 'value']) # 写入表头
for i in range(len(ans)):
my_writer.writerow(ans[i]) # 将ans列表(预测结果)写入
text.close()
return predictY # 返回预测数值列表
predictY1 = test(testX, w1, 'predict_4.csv')
# 画图分析
plt.figure(figsize=(13, 7)) # 指定图片长和宽,单位:英寸
plt.plot(np.arange(0, 240, 1), predictY1, 'r', label='predict pm2.5(ada)') # 预测结果:x轴范围,分刻度,曲线颜色,曲线标签
plt.plot(np.arange(0, 240, 1), y, 'b', label='ans pm2.5') # 真值
plt.legend() # 显示标签
plt.show()
输出图像