从头学习周志华版的机器学习,同时准备使用Python实现一些相关的方法,以及一些小的项目。因为Python是新手,也准备借这次机会熟悉并掌握,代码方面有一些笨拙,希望慢慢改进、进步。
一般的线性方程
f ( x ) = w 1 x 1 + w 2 x 2 + . . . + w n x n + b f(x)=w_1x_1+w_2x_2+...+w_nx_n+b f(x)=w1x1+w2x2+...+wnxn+b 写成向量形式 ⇒ f ( x ) = w T x + b \Rightarrow f(\bm{x})= \bm{w} ^T\bm{x}+b ⇒f(x)=wTx+b
线性回归
线性回归使用一般的线性方程做回归,即为处理的数据 X \textbf{X} X建立一个合适的线性模型,也就是说需要确定一组合适的 w \bm{w} w和 b b b。值得注意的是将 X \textbf{X} X中的每组数据 x i \bm{x}_i xi替换为 x ^ i = ( x i ; 1 ) \hat{\bm{x}}_i=(\bm{x}_i;1) x^i=(xi;1),则可以将 w \bm{w} w和 b b b用 w ^ = ( w ; b ) \hat{\bm{w}}=(\bm{w};b) w^=(w;b)代替。模型可以替换为 f ( x ^ i ) = w ^ T x i f(\hat{\bm{x}}_i)= \hat{\bm{w} }^T\bm{x}_i f(x^i)=w^Txi。在Python中:
'''线性回归模型'''
def modelLR(x, w):
fx = dot(x, w)
return fx
模型合不合适可以根据 f ( x ) f(x) f(x)和真实的 y y y之间的差距来判断,通常我们使用损失函数衡量它们之间差距。
均方误差是在线性回归问题中常用的损失函数,写成:
L = 1 m ∑ i = 1 m ( f ( x i ) − y ) 2 L=\frac{1}{m}\sum^{m}_{i=1}(f(\bm{x}_i)-y)^2 L=m1i=1∑m(f(xi)−y)2
通常我们认为损失函数越小,模型越合适,也就是说模型的求解转化为了一个最优化问题,在这个问题中目标函数是损失函数,决策变量为 w ^ \hat{\bm{w} } w^。(基于均方误差最小化来进行模型求解的方法称为最小二乘法)
'''损失函数'''
def lossFun(w, x, y):
funError = 0
x = mat(x)
for i in range(0, size(y, 0)):
x1 = x[i, :]
y1 = y[i, 0]
fx = modelLR(x1, w)
funError += (fx - y1)**2
return funError/size(y, 0)
有了优化问题就需要优化方法,回归问题中通常使用梯度下降法,它需要确定两样东西:方向和步长。
我使用的是最速下降法,方向 d k d_k dk为梯度的负方向:
下面是梯度方向的计算
'''计算梯度'''
def calcGrad(h, x, y, w): # 计算梯度
dkCol = size(w, 0)
dk = ones((1, dkCol))
for i in range(0, size(w, 0)):
w1 = w.copy()
w2 = w.copy()
w1[i] = w1[i] - h
w2[i] = w2[i] + h
y1 = lossFun(w1, x, y)
y2 = lossFun(w2, x, y)
dk[0, i] = (y2-y1)/(2*h)
return dk
步长:精确法为:
α k = arg min α ≥ 0 f ( w ^ k + α d k ) \alpha_k=\arg \min\limits_{\alpha\geq0}f(\hat{\bm{w}} _k+\alpha d_k) αk=argα≥0minf(w^k+αdk)
其中: α k \alpha_k αk需要满足:
ϕ ′ ( α ) = d d w ^ k f ( w ^ k + α d k ) ∣ α = α k = ∇ f ( w ^ k + α k d k ) T d k = 0 \phi'(\alpha)=\frac{\rm{d}}{{\rm d}\hat{\bm{w}} _k}f(\hat{\bm{w}} _k+\alpha d_k)|_{\alpha=\alpha_k}=\nabla f(\hat{\bm{w}} _k+\alpha_k d_k)^Td_k=0 ϕ′(α)=dw^kdf(w^k+αdk)∣α=αk=∇f(w^k+αkdk)Tdk=0
'''计算步长'''
def calcStep(dk, x, y, w): # 计算步长
ak = 1
for i in range(0, 20):
newF = lossFun(w+ak*dk, x, y)
oldF = lossFun(w, x, y)
if (newF<oldF):
break
else:
ak = ak/2
return ak
整体的最速下降法为:
'''最速下降法训练'''
def steepest(x, y, w):
epsilon = 1e-5
h = 1e-5
maxIter = 1e3
for i in range(0, int(maxIter)):
grad = calcGrad2(h, x, y, w)
dk = -grad.T
ak = calcStep(dk, x, y, w)
neww = w + ak*dk
if abs(lossFun(neww, x, y)-lossFun(w, x, y)) <= epsilon:
break
w = neww
return w, lossFun(w, x, y)
一个numpy中的 矩阵运算方法帖子
# 载入数据
path = "D:/事项/机器学习学习/week1/"
train = pd.read_csv(path + 'train.csv', engine='python', encoding='gbk')
test = pd.read_csv(path + 'test.csv', engine='python', encoding='gbk')
yt = pd.read_csv(path + 'answer.csv', engine='python', encoding='gbk')
setTrainX = train.values
setTestX = test.values
setTrainX[setTrainX == "NR"] = 0 #替换操作
setTestX[setTestX == "NR"] = 0
此时读取出的文件为panda的DataFrame格式,通过DataFrame.values可以得到ndarray格式的数据。
使用hstack(A, B) 横向结合两个矩阵,需要保证AB矩阵列数相等;vstack(A, B)纵向结合两个矩阵,需要保证AB矩阵行数相等。
因为在这次数据处理中需要循环着结合矩阵,启动时需要有一个矩阵,使用empty(a, b)产生的矩阵并不会被覆盖,所以用了一个很蠢的办法:
tempX = ones((18, 1))
for i in range(0, size(setTrainX, 0) - 18, 18):
tempXX = setTrainX[i:i+18, :]
tempX = hstack((tempX, tempXX))
tempX = tempX[:, 1:]
矩阵形式的ndarray的数据不能使用强制类型转换的方法改变数据类型,它的数据类型可以通过ndarray.dtype查看,直接更改dtype会引起数据的解释错误,即内存中存储的内容不变,仅改变了解释方式。
接着上面的处理,目前的数据的dtype为 “U32” 是字符串类型,不能参与运算,需要改为浮点型,此时需要用到 ndarray.astype(type) 函数。
x = x.astype(float)
值得注意的是,参数float实际上是转换为 “float64” 类型(默认的浮点类型)。
标准化会影响算法的收敛速度。
ss= StandardScaler()
for i in range(0, size(x, 1)):
ss.fit(x[:, i].reshape(-1, 1))
x[:, i] = ss.transform(x[:, i].reshape(-1, 1)).T
注意ndarray格式的数据需要 .reshape(-1, 1) 才能使用 .fit() 函数,原因暂时不知道
ndarray下的向量似乎不能使用类似A[a, b]的调用方法,但是用mat(A)转化为matrix类型就可以使用了。