李宏毅机器学习HW1_pm2.5prediction(adagrad/gradient descent/SGD)

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()

输出图像
figure 1

发布了24 篇原创文章 · 获赞 8 · 访问量 2178

猜你喜欢

转载自blog.csdn.net/weixin_44839513/article/details/102495286
今日推荐