HomeWork1 PM2.5 Prediction
课程资料:
https://ntumlta.github.io/2017fall-ml-hw1/
从印象笔记移过来修改的,没编辑太细,猎豹编辑CSDN出现各种错误,太麻烦,反正代码能跑。
id_x是时间点,每一个具体的x,是一个时间点。
怎么抽取训练集?1-9训练,第十个验证,2-10训练,第11个验证?这样每单次训练都要验证一次?不对,这个方法是抽训练集!这一步是数据预处理,就是重叠的抽取样本,9:1来做x和y。前9个id_x是输入,第10个id_x是output。10个数据加起来,才是一个训练数据,而不是单条观测记录。
第一个简陋版本(有理解偏差):
for i in range(0,n-9):#从时刻0到时刻n-9迭代
抽[i:i+8]作为input,抽[i+9]为output
把抽到的数据想好一个格式存起来。
PS:9比1的输入输出,也是自己可选的,不是固定的,考虑到给的官方test就是9:1的预测,所以当然按9:1来设计。
难点:除了天数,还有每天的小时,不是按天预测的,有点复杂了,按小时能不能跨天?可能模型不要这么复杂?(错了,要跨)
数据不跨天的弊端:
模型偏科,就是说从来不预测1点、2点、到9点的数据,只预测10点到24点的数据,这就会产生——用不针对1-9点的模型来预测1-9点,肯定有问题,用模型去预测根本没法见到的数据类型(时间段),会有variance。
不跨天的另一个问题就是大幅缩减了数据量——数据集是12个月,每个月20天,每天24小时,不跨天的话12*20*(24-9)==3600,而跨天是12*(20*24-9)==5652
(补充:后来见过别人的博客,还真有按天取的,现在无法下载数据集,不能进行验证了,因为李宏毅说这个模型本来就是线性的,所以很可能各种错误的方法也能得到正确的结果,这种问题其实是最可怕的,你不对,还误以为自己对了,这样就把重点漏了。这个数据集只是作业,不是真正去预测,真正练手的话,还是用“不完美”的数据集更好)
另外,降雨的数据中有“NR”,这个要自己处理转换一下,用bool?不行,非NR是浮点数,NR是不降雨,NR标0就行了!!!
第二版本:
k=9,k是打算用来预测的前边的input,因为test集提供了9个,所以为了最大化自己的预测,肯定不会去用5个预测!k以test的最大数为准!!
大循环:
按日期的不同,来做分割
中循环:
把所有不同的指标都读一遍,分别加标记以区分
小for循环,i从时刻0到时刻n-9迭代(停止指标,i+9没数据了):
抽i到i+(k-1)作为input,抽i+k为output
把抽到的数据想好一个格式存起来。
第三版本,参考了作业补充ppt
确实需要跨天的,跨月也简单,跳过去从头来就完了(其实预处理数据是单独一步)
跨天的话还面临另一个建模问题,时段问题(其实不跨天也有这问题,所以这不是问题,其实最终是不分时段,都扔进网络自动学)
特征抽取伪代码:
最外层循环-月份i迭代:
每个月i内,每天之间要拼接起来。形成小时序列
第二层循环,按小时i迭代抽取特征:
从j到j+8取出来,作为input存储(train_x.append)这8个组合起来才是1个input,不是8个input,每一个都是向量,所以intpu是矩阵?
j+9作为output,存储(train_y.append)
直到j+10没数据停止
直到月份取光结束
整个train_x,每笔加个bias
实操:参考代码片段,有分月份,只不过分到第二步去做了!!!
建模
0.真正做预测,我肯定考虑要跨天了,但是操作也挺麻烦的,而且他的数据是断的,每个月只有20天(剩下10天可能当测试集了),每个月至少还要做个截断,操作繁琐。
1.特征选择,我肯定先用纯PM2.5了
2.然后可以考虑PM2.5+PM10.
3.然后我会考虑风,因为北京就和风有关
4.可以考虑一下降雨因素
5.然后考虑所有的都用?要不要正则化?
6.每天的不同时段明显不一样,也就是说,半夜那部分的数据,肯定影响你对白天那部分的预测?
既然是机器学习,可能就都考虑进去了,数据足够多,模型足够大,应该所有部分都能正确预测?
PS:应该西风或者西北风好点?
这都不绝对,因为你不知道台湾的污染源分布?
也许受大陆影响,西北风会更脏?
东边的海风也许更干净?
也许因为中部有山,所以东风不好用?
所以这个建模,跟实际地形、外部环境,等等,都有关系。你不了解详细信息,不会建模建的很好。
之前把数据都处理好了,现在是分N批(月份),每批一堆input和一堆output。开始写模型训练。
数据处理转存完,应该可以直接训练了。把建模部分想好的模型的公式列出来,然后用这个公式去训练,然后用训练集输入一遍,然后把test输入,输出,做准确率对比。
第一版:
只算所有PM2.5,
随意初始化weights(多少层?)
模型:y = bias+w1*x1+w2*x2+...+w9*x9(深层?一层?)
训练过程:梯度下降:
η=0.01(先随便吧)
epoch = 1000
for e in epoch:
还是要算出Loss才能进行下边的update的(主要问题就是这个gradient在python怎么表达)
#theta = gradientDescent(X, y, theta, alpha, iterations);#octave代码
#theta = theta - alpha/m * X' *(X*theta - y)#这是octave的,X'好像是逆之类的,而且这里X可能是矩阵,所以应该是通过公式转换了
批量update:
wij=wij-η*gradient#每个wij应该单独有一个gradient吧?
......
第二版:参考答案
(Pseudo code)
1. 宣告weight vector、初始learning rate、# of iteration
2. for i_th iteration :
3. y’ = train_x 和 weight vector 的 內積
4. L = y’ - train_y
5. gra = 2*np.dot( (train_x)’ , L )
6. weight vector -= learning rate * gra
模型公式示意和步骤示意(不过这里的y'没有+b了呢。。。grad+2*x乘以L)
给了参考
# 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)
但是这个也不是分类问题,我应该怎么比结果?取整?不是一个整数就算不准?不是吧?!
但是要的是准确了就该是个比例,而不是其他的
看一下训练过程?那个Loss的计算方法应该可以。
下边是照着参考PPT和代码片段做的
这里逻辑稍微有些墨迹,因为这样比较严谨,不严谨的做法是直接遍历所有数据,但是那样有个弊端,因为每个月丢失了10天,理论上这些数据不是连续的,用1月20日去预测2月1日不是很奇怪?具体影响就不量化了,总之数据不太干净,不严谨。
import csv
import numpy as np
from numpy.linalg import inv
#import sys
import math
#import random
#############################################
#parse data
#initial
data = []
for i in range(18):
data.append([])
n_row = 0
#print("data:",data)
#print("type(data):",type(data))
text = open('train.csv','r',encoding='big5')
row = csv.reader(text,delimiter=",")
print("type(text):",type(text))
print("type(row):",type(row))
for r in row:
#0 cols
if n_row != 0:
for i in range(3,27):
if r[i] != "NR":
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()
print("data[0]:",data[0][:12])
print("data[1]:",data[1][:12])
#divide data
x = []
y = []
const_month = 12
src_data_in_month = int(len(data[0]) / const_month) #480=24*20
data_per_month = src_data_in_month - 9 #471
#per month
for i in range(12):
for j in range(data_per_month):
x.append([])
for t in range(18):
for s in range(9):
x[471*i+j].append(data[t][480*i+j+s])
y.append(data[9][480*i+j+9]) #s=9
print("after append,x[0]:",x[0][:10])
print("len(x):",len(x))
x=np.array(x)
y=np.array(y)
print("len(x):",len(x))
x=np.concatenate((np.ones((x.shape[0],1)),x),axis=1)
print("len(x):",len(x))
w2 = np.matmul(np.matmul(inv(np.matmul(x.transpose(),x)),x.transpose()),y)
################################################
#train
w = np.zeros(len(x[0]))
print("len(x[0]):",len(x[0]))
l_rate=10
repeat=10000
#print("w[0]:",w[0][:10])
#print("w[1]:",w[1][:10])
x_t = x.transpose()
s_gra = np.zeros(len(x[0]))
for i in range(repeat):
hypo = np.dot(x,w)
loss = hypo - y
cost = np.sum(loss**2)/len(x)
cost_a = math.sqrt(cost)
gra = np.dot(x_t,loss)
s_gra += gra**2
ada = np.sqrt(s_gra)
w = w - l_rate * gra/ada
print('iteration:%d | Cost: %f ' %(i,cost_a))
np.save('model.npy',w)
w2 = np.load('model.npy')
#######################################################
#test
test_x = []
n_row = 0
text = open('test.csv',"r")
row = csv.reader(text, delimiter=",")
for r in row:
if n_row % 18 == 0:
test_x.append([])
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)
test_x = np.concatenate((np.ones((test_x.shape[0],1)),test_x),axis=1)
#######################################################3
#test
ans = []
for i in range(len(test_x)):
ans.append(["id_"+str(i)])
a = np.dot(w,test_x[i])
ans[i].append(a)
#############
'''
a = np.dot(w,test_x[i])
a2 = np.dot(w2,test_x[i])
loss = a - a2
cost = np.sum(loss**2)/len(test_x[i])
cost_a = math.sqrt(cost)
print("test Cost:%f"%(cost_a))
'''
########################
filename = "predict.csv"
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()
顺便加入了自己写的和“标准答案”对比的代码,因为这是他们台大的作业,kaggle已经过期,没法直接拿去跑,只能用这个答案对比。为什么能比?这个模型他给的就是线性的,凸函数,可以用close form(翻译是直接公式法?)来找到答案。
import csv
import math
ans = []
n_row = 0
text = open('ans.csv',"r")
row = csv.reader(text,delimiter=",")
print(text)
print(row)
#print("len(row):",len(row))
for r in row:
#print("r[0] is ",r[0])
#print("r[1] is ",r[1])
if r[1] != 'value':
ans.append(round(float(r[1])))
print(ans)
predict = []
n_row = 0
text = open('predict.csv',"r")
row = csv.reader(text,delimiter=",")
for r in row:
#print("r[0] is ",r[0])
#print("r[1] is ",r[1])
if r[1] != 'value':
predict.append(round(float(r[1])))
print(predict)
print(type(predict))
sum = 0
for i in range(len(ans)):
sum += abs(predict[i] - ans[i])
err = sum / len(ans)
#err = abs(predict - ans).sum()/len(ans)
print(err)
方法二:array操作,最后求和平均
#######################################
#implementation 2
predict_ndarray = np.array(predict)
ans_ndarray = np.array(ans)
err_ndarray = predict_ndarray - ans_ndarray
err_ndarray = np.abs(err_ndarray)
sum2 = np.ndarray.sum(err_ndarray)
print(sum2)
err2 = sum2 / len(ans)
print(err2)