算法思维
方程求根
二分法
画图猜f(x)=0的大概范围[a,b]再缩小范围,保证f(a)f(b)<0,在[a,b]上一定有实根。
中点x0=a+(b-a)/2=(a+b)/2 即两端值和的一半。若中点与右端符号相同(如左图),则缩小到[a,x0]。若中点与左端符号相同(如右图),则缩小到[x0,b],依次得到不断减半的区间。
最终区间[an,bn]的长度=(b-a)/2n,称为解方程的二分法。
算法流程:
- 画图得到根初始区间left=1,right=2,f(left)f(right)<0
- 计算中点middle,及中间f(middle)
- 当|f(middle)|>=error时: 如果f(middle)与f(left)的符号相同,则解在[中,右],否则解在[左,中]。相应改变区间。
- 计算中点middle,及f(middle)
- 回到第3步
#例1:求x2-2=0的根,即求2的平方根
def f(x): return x**2-2
left=1;right=2;n=0#n用来统计二分次数
err=1e-6#误差
while True:
n+=1; middle=(left+right)*0.5
if abs(f(middle))<err:
print('f(x)=%.8f x=%.8f n=%d'%(f(middle),middle,n))
break
if f(middle)*f(left)>0: left=middle #中点变为左边界
else: right=middle #中点变为右边界
f(x)=0.00000027 x=1.41421366 n=21
牛顿迭代法
注意,如果初值选取不当,可能越过根(漏掉根),尽量依据绘图,选取根附近的点作为初始点。
算法流程:
- 画图得到根的初始值x
- 求出函数的导数,计算f(x), f’(x) 。
- 当|f(x)|>=err时,重复以下:
x=x-f(x)/f’(x)
计算f(x), f’(x)
#例1:求x2-2=0的根,即求2的平方根
def f(x):
return x ** 2 -2
def df(x):
return x * 2
x=4;err=1e-6;n=0
while True:
if abs(f(x))<err:
print('fx=%.8f x=%.8f n=%d'%(f(x),x,n))
break
x=x-f(x)/df(x) #
n+=1
fx=0.00000000 x=1.41421356 n=5
离散Newton法
离散Newton法,亦称割线法。
(1)画图得到根附近的一对值,x0,x1
(2)计算 f0=f(x0),f1=f(x1)
(3)当|f(x0)|>=err 时:
x=x1-f(x1)*(x1-x0)/(f(x1)-f(x0))
x0=x1
x1=x
f0=f1
f1=f(x1)
#例1:求x2-2=0的根,即求2的平方根
x0=1;x1=2;err=1e-6;n=0
def f(x):
return x**2-2
while True:
if f(x1)-f(x0)==0:
print('False')
break
x=x1-f(x1)/(f(x1)-f(x0))*(x1-x0)
n+=1
if abs(f(x))<err:
print('fx=%.8f x=%.8f n=%d'%(f(x),x,n))
break
x0=x1
x1=x
fx=-0.00000000 x=1.41421356 n=5
函数求最值(梯度下降法)
梯度下降法,一元函数
求函数最值是应用数学最重要的任务之一。
梯度下降法是最早最简单,也是最为常用的最优化方法。大部分的机器学习算法的本质都是先建立初始模型,然后通过最优化方法对目标函数(损失函数)进行优化,从而训练出最好的模型。
梯度下降法(亦称最速下降法)与Newton迭代法的相似之处在于都利用了函数求导。
梯度下降法:找到f’(x)=0的点
然而,在实际问题中,方程f’(x)=0通常不容易求解,特别是当有多个自变量时。梯度下降法不直接求方程f’(x)=0的解,而是通过逐步改变x值进行摸索,从而找出函数的最小值。
为了找到函数的最小值处,只要让函数值朝着梯度方向的反方向(下降)走一小步,再求出此处的梯度方向,继续往梯度方向的反方向走一小步,如此往复,就能找到函数的最小值。
算法流程:
- 随机生成初始x值
- 循环迭代max_iters次
当|f’(x)|<err时,跳出循环
x=x-f’(x)*learning_rate
#例2:求函数y=x2-10x-30 的最小值
import numpy as np
np.random.seed(3)
x=np.random.randn();learning_rate=0.1
err=0.000001;max_iters=10000
def f(x): return x**2-10*x-30
def df(x): return 2*x-10
for i in range(max_iters):
print("第 %d 次迭代:x=%.8f y=%.8f"%(i,x,f(x)))
if abs(df(x)) <err: break
x=x-df(x) * learning_rate#xk+1=xk- η* f’(xk) (迭代公式)
第 0 次迭代:x=1.78862847 y=-44.68709292
第 1 次迭代:x=2.43090278 y=-48.39973947
第 2 次迭代:x=2.94472222 y=-50.77583326
第 3 次迭代:x=3.35577778 y=-52.29653329
第 4 次迭代:x=3.68462222 y=-53.26978130
第 5 次迭代:x=3.94769778 y=-53.89266003
第 6 次迭代:x=4.15815822 y=-54.29130242
第 7 次迭代:x=4.32652658 y=-54.54643355
第 8 次迭代:x=4.46122126 y=-54.70971747
第 9 次迭代:x=4.56897701 y=-54.81421918
第 10 次迭代:x=4.65518161 y=-54.88110028
第 11 次迭代:x=4.72414529 y=-54.92390418
第 12 次迭代:x=4.77931623 y=-54.95129867
第 13 次迭代:x=4.82345298 y=-54.96883115
第 14 次迭代:x=4.85876239 y=-54.98005194
第 15 次迭代:x=4.88700991 y=-54.98723324
第 16 次迭代:x=4.90960793 y=-54.99182927
第 17 次迭代:x=4.92768634 y=-54.99477073
第 18 次迭代:x=4.94214907 y=-54.99665327
第 19 次迭代:x=4.95371926 y=-54.99785809
第 20 次迭代:x=4.96297541 y=-54.99862918
第 21 次迭代:x=4.97038033 y=-54.99912267
第 22 次迭代:x=4.97630426 y=-54.99943851
第 23 次迭代:x=4.98104341 y=-54.99964065
第 24 次迭代:x=4.98483473 y=-54.99977001
第 25 次迭代:x=4.98786778 y=-54.99985281
第 26 次迭代:x=4.99029423 y=-54.99990580
第 27 次迭代:x=4.99223538 y=-54.99993971
第 28 次迭代:x=4.99378830 y=-54.99996141
第 29 次迭代:x=4.99503064 y=-54.99997531
第 30 次迭代:x=4.99602451 y=-54.99998420
第 31 次迭代:x=4.99681961 y=-54.99998989
第 32 次迭代:x=4.99745569 y=-54.99999353
第 33 次迭代:x=4.99796455 y=-54.99999586
第 34 次迭代:x=4.99837164 y=-54.99999735
第 35 次迭代:x=4.99869731 y=-54.99999830
第 36 次迭代:x=4.99895785 y=-54.99999891
第 37 次迭代:x=4.99916628 y=-54.99999930
第 38 次迭代:x=4.99933302 y=-54.99999956
第 39 次迭代:x=4.99946642 y=-54.99999972
第 40 次迭代:x=4.99957314 y=-54.99999982
第 41 次迭代:x=4.99965851 y=-54.99999988
第 42 次迭代:x=4.99972681 y=-54.99999993
第 43 次迭代:x=4.99978145 y=-54.99999995
第 44 次迭代:x=4.99982516 y=-54.99999997
第 45 次迭代:x=4.99986013 y=-54.99999998
第 46 次迭代:x=4.99988810 y=-54.99999999
第 47 次迭代:x=4.99991048 y=-54.99999999
第 48 次迭代:x=4.99992838 y=-54.99999999
第 49 次迭代:x=4.99994271 y=-55.00000000
第 50 次迭代:x=4.99995417 y=-55.00000000
第 51 次迭代:x=4.99996333 y=-55.00000000
第 52 次迭代:x=4.99997067 y=-55.00000000
第 53 次迭代:x=4.99997653 y=-55.00000000
第 54 次迭代:x=4.99998123 y=-55.00000000
第 55 次迭代:x=4.99998498 y=-55.00000000
第 56 次迭代:x=4.99998798 y=-55.00000000
第 57 次迭代:x=4.99999039 y=-55.00000000
第 58 次迭代:x=4.99999231 y=-55.00000000
第 59 次迭代:x=4.99999385 y=-55.00000000
第 60 次迭代:x=4.99999508 y=-55.00000000
第 61 次迭代:x=4.99999606 y=-55.00000000
第 62 次迭代:x=4.99999685 y=-55.00000000
第 63 次迭代:x=4.99999748 y=-55.00000000
第 64 次迭代:x=4.99999798 y=-55.00000000
第 65 次迭代:x=4.99999839 y=-55.00000000
第 66 次迭代:x=4.99999871 y=-55.00000000
第 67 次迭代:x=4.99999897 y=-55.00000000
第 68 次迭代:x=4.99999917 y=-55.00000000
第 69 次迭代:x=4.99999934 y=-55.00000000
第 70 次迭代:x=4.99999947 y=-55.00000000
第 71 次迭代:x=4.99999958 y=-55.00000000
梯度下降法,二元函数
几何含义:
梯度下降法如同人们每走一步都沿着当前最陡的方向下山。
梯度下降法的迭代公式如下:
案例:给定一个二元函数f(x,y)= - exp(x-y)*(x2-2*y2),用梯度下降法求其在x<0,y<0范围上的极小值
- 梯度下降法x、y初值设置。案例描述中要求在x<0,y<0区域内寻找函数最小值,因此初值可以设置为两个负数,本例初值设置:x=-1, y=-1, 也可以尝试设置为其它负数值。
- 梯度下降法学习率的设置。可以先设置为0.1,如果效果不理想再进行微调。
- 梯度下降法循环迭代终止设置。循环的终止方式可以有多种。一种是直接迭代一个较大的循环次数,直到循环自然终止。一种效率更高的方式是判断函数导数值与0值的差异,当差异足够小时(达到一定精度要求时)用break语句跳出循环。还可以根据连续两轮或多轮迭代x值的改变以及y值的改变达到某个微小值以内,认为迭代趋于稳定而跳出循环。或者根据函数值减小的幅度达到某个微小值以内,认为迭代趋于稳定;等等。本例采用第一种和第二种方式的结合:给一个较大的迭代次数10000次(也可以设置得更大);为了提高代码效率,在循环体内判断当前函数的两个偏导数值是否接近0,误差设置为0.000001(根据实际情况设置,该值可调),满足条件就跳出循环。
- 函数和两个偏导函数的函数自定义
- 构造循环结构,利用梯度下降法的x和y值迭代公式进行迭代。输出最终结果。
import numpy as np
x=-1;y=-1
learning_rate=0.1
err=0.000001;max_iters=10000
def f(x,y):
return -np.exp(x-y)*(x**2-2*y**2)
def dx(x,y):
return -(np.exp(x-y)*(2*x)+(x**2-2*y**2)*np.exp(x-y))
def dy(x,y):
return -(np.exp(x-y)*(-4*y)+(x**2-2*y**2)*np.exp(x-y)*(-1))
for t in range(max_iters):
if t%100==0:
print("Iter %d, x=%.8f,y=%.8f,z=%.8f,dx=%.8f,dy=%.8f"%(t,x,y,f(x,y),dx(x,y),dy(x,y)))
if abs(dx(x,y))<err and abs(dy(x,y))<err:
print("Iter %d, x=%.8f,y=%.8f,z=%.8f,dx=%.8f,dy=%.8f"%(t,x,y,f(x,y),dx(x,y),dy(x,y)))
break
x=x-learning_rate*dx(x,y); y=y-learning_rate*dy(x,y) #迭代公式‘
Iter 0, x=-1.00000000,y=-1.00000000,z=1.00000000,dx=3.00000000,dy=-5.00000000
Iter 100, x=-3.09175581,y=-1.37866718,z=-1.03812484,dx=0.07681195,dy=0.04378580
Iter 200, x=-3.58508879,y=-1.71467625,z=-1.07420439,dx=0.03043384,dy=0.01755166
Iter 300, x=-3.79630426,y=-1.85967410,z=-1.08071845,dx=0.01405238,dy=0.00814006
Iter 400, x=-3.89691917,y=-1.92893257,z=-1.08218878,dx=0.00690599,dy=0.00400866
Iter 500, x=-3.94708386,y=-1.96350427,z=-1.08255344,dx=0.00349371,dy=0.00203005
Iter 600, x=-3.97264220,y=-1.98112811,z=-1.08264800,dx=0.00179285,dy=0.00104229
Iter 700, x=-3.98580483,y=-1.99020700,z=-1.08267306,dx=0.00092669,dy=0.00053889
Iter 800, x=-3.99262086,y=-1.99490901,z=-1.08267978,dx=0.00048077,dy=0.00027961
Iter 900, x=-3.99616039,y=-1.99735092,z=-1.08268159,dx=0.00024990,dy=0.00014535
Iter 1000, x=-3.99800112,y=-1.99862089,z=-1.08268208,dx=0.00013003,dy=0.00007563
Iter 1100, x=-3.99895913,y=-1.99928185,z=-1.08268222,dx=0.00006769,dy=0.00003937
Iter 1200, x=-3.99945792,y=-1.99962599,z=-1.08268225,dx=0.00003525,dy=0.00002050
Iter 1300, x=-3.99971766,y=-1.99980520,z=-1.08268226,dx=0.00001836,dy=0.00001068
Iter 1400, x=-3.99985294,y=-1.99989854,z=-1.08268226,dx=0.00000956,dy=0.00000556
Iter 1500, x=-3.99992340,y=-1.99994715,z=-1.08268227,dx=0.00000498,dy=0.00000290
Iter 1600, x=-3.99996010,y=-1.99997247,z=-1.08268227,dx=0.00000259,dy=0.00000151
Iter 1700, x=-3.99997922,y=-1.99998566,z=-1.08268227,dx=0.00000135,dy=0.00000079
Iter 1747, x=-3.99998471,y=-1.99998945,z=-1.08268227,dx=0.00000099,dy=0.00000058
数据拟合
数据拟合(梯度下降法)
测量所得的数据一般都有一定的误差,如何从大量测量所得的数据点中找出数据服从的一般规律性,即找出一个函数来刻画数据点的分布,可以称为数据的函数拟合。拟合好的函数,可以用来对新的测量数据进行预测。
线性拟合
给定呈线性分布的100个点,用梯度下降法求出其隐含的线性函数。已知这100个数据点分布如下图的蓝色小圆点所示,目测服从线性分布,现在请用梯度下降法找出能够较好拟合这100个数据点的未知线性函数y=ax+b(如图中的蓝色线条所示),求出a和b值。
- 梯度下降法a,b初值设置。本例用随机函数为a,b产生一个随机初值。
- 梯度下降法学习率的设置。可以先设置为0.1,如果效果不理想再进行微调。
- 误差计算。为了观察误差是否随着a,b值的调整,逐步在变小,需要对给定的a,b值,计算这100个样本点的平均误差。
- 构造循环结构,利用梯度下降法的迭代公式对a,b进行迭代。输出最终结果。
为了能够更好的理解线性拟合的本质,本例采用模拟数据点,随机生成100个数据点对,这些数据点服从线性分布,真实线性函数是y=3x+15(图中蓝色线), x坐标值为(0,2)的均匀分布,为了模拟测量数据中的测量误差,这里为每个对应的y坐标值增加一个标准正态分布的扰动。
import numpy as np
import matplotlib.pyplot as plt
#生成100个数据点
np.random.seed(3)
X=2*np.random.rand(100)#生成100个随机数,模拟x
Y=15+3*X+np.random.randn(100)#生成100个随机数,模拟y,真实的a=3,b=15
learning_rate=0.1; roundN = 5#对数据点集的轮数
np.random.seed(3); a=np.random.randn()
np.random.seed(4) ;b=np.random.randn()
def errorCompute(a,b):
error=0
for j in range(len(X)):
error+=1/2*(a*X[j]+b-Y[j])**2
return error/len(X)
for i in range(roundN):
for j in range(len(X)):
if j%50==0:
print("round=%d,iter=%d,a=%f,b=%f,E=%f"%(i,j,a,b,errorCompute(a,b)))
gradA=(a*X[j]+b-Y[j])*X[j]; gradB=a*X[j]+b-Y[j] #求偏导的公式
a=a-learning_rate*gradA; b=b-learning_rate*gradB #迭代公式
#下面绘制图形
maxX=max(X); minX=min(X); maxY=max(Y); minY=min(Y)
X_fit=np.arange(minX,maxX,0.01); Y_fit=a*X_fit+b
plt.plot(X,Y,'.')#数据点
plt.plot(X_fit,Y_fit,'r-',label='Gradient Descent')
plt.plot(X_fit,15+3*X_fit,'b-',label='True')
plt.legend()
plt.show()
round=0,iter=0,a=1.788628,b=0.050562,E=129.724642
round=0,iter=50,a=7.157349,b=11.162271,E=2.998449
round=1,iter=0,a=4.984254,b=13.194898,E=1.066988
round=1,iter=50,a=4.116652,b=14.082373,E=0.661608
round=2,iter=0,a=3.513805,b=14.893728,E=0.563870
round=2,iter=50,a=3.253854,b=14.910921,E=0.449889
round=3,iter=0,a=3.096573,b=15.375762,E=0.541890
round=3,iter=50,a=3.009039,b=15.146017,E=0.426155
round=4,iter=0,a=2.978185,b=15.512537,E=0.545377
round=4,iter=50,a=2.939574,b=15.212725,E=0.422347
BP神经网络
数据拟合部分的案例都是预先假设了数据隐含的函数分布的形式,使用梯度下降法求出其参数,但通常我们并不知道数据隐含的分布函数是线性还是多项式或者是其他函数形式,因此上面的应用也是非常有限,神经网络的出现打破了这一僵局。
理论上已证明,具有一个隐含层的三层网络可以逼近任意非线性函数,即一个输入层、一个隐含层、一个输出层可以近似表示任意非线性函数。
BP神经网络是现今多种深度学习网络的基础组成部分,对BP神经网络的了解有助于帮助理解更多更复杂的深度学习网络,BP神经网络正是利用梯度下降法来寻求合适的参数值使得其误差函数最小化。
BP神经网络可以解决回归问题和分类问题。简单来讲,回归问题相当于预测值是连续的数字类型(例如房屋价格预测,股票值预测等等),而分类问题可以看成预测值是离散值类型(例如,物种类别,猫,狗,牛等等)。下面从最简单的三层BP神经网络的回归任务开始阐明BP神经网络结构及其学习原理,其结构图如下:
隐藏层神经元zj值的计算原理是对每个输入x1,….,xI进行加权求和之后加入偏置bj得到(类似于我们构造一元线性函数时采用y=kx+b的方式,这里是扩展为多元线性函数的构造)。
这里权重w上的上标(1)是为了和后面构造输出层神经元值时的w区分开来。每个隐藏层神经元对应I个权重参数w, 共有J个隐藏神经单元,因此共有IJ个参数,将其看成一个J行I列的权重矩阵,另外还有J个偏置b, 所以隐藏层的参数个数共有J(I+1)个,这些参数的初始值可用随机函数获得。
梯度下降法就是对这些参数进行迭代更新的方法,目标是最小化误差函数。
其图示如下:
Sigmoid函数可以使得任何输入值z转换到输出值0~1之间。且其导数值非常方便计算:
σ’ (z)=σ(z)(1-σ(z))
如果为这J*(I+1)+ J+1个参数分别都给一个随机值,对于一个有确定值的输入样本(x1,x2,…,xi,…,xI),可以得到一个预测值y。可以想象,这个预测值y和该样本对应的真实值t之间肯定有差异,这个差异我们称为误差,因此误差函数可以用如下公式表示:
如何调整这J*(I+1)+ J+1个参数值,使得这个误差值E最小,这就是网络学习的目标。换句话说,就是对于所有的输入样本和对应的真实值,让网络学习出J*(I+1)+ J+1个合适的参数值,使得误差最小。这里误差函数公式中包含的样本值(x1,x2,…,xi,…,xI)是已知的,样本对应的真实值t也是已知的,未知的是J*(I+1)+ J+1个参数。因此误差函数值的最小化问题可以转化为利用梯度下降法对这J*(I+1)+ J+1个参数进行迭代的问题,其迭代公式表述如下:
这里最难解决的是各个参数的偏导𝜕𝐸/(𝜕𝑤_𝑘 )的计算,下面对这J*(I+1)+ J+1个参数从后往前分层进行偏导计算推理。
from sklearn.datasets import load_boston
import numpy as np
import matplotlib.pyplot as plt
def sigmoid(x):#激活函数
return 1/(1+np.exp(-x))
def minMaxScaler(X):#数据归一化
X_std=(X-X.min(axis=0))/(X.max(axis=0)-X.min(axis=0))
return X_std
def shuffle(X,y):#数据乱序,并划分训练集和测试集
lenX=len(X)
np.random.seed(10)
random_sort=np.random.permutation(lenX)
trainX=X[random_sort[0:int(0.8*lenX)]]
trainy=y[random_sort[0:int(0.8*lenX)]]
testX=X[random_sort[int(0.8*lenX):]]
testy=y[random_sort[int(0.8*lenX):]]
return trainX,trainy,testX,testy
def forward_propagate(an_input):#信息前向传递
#计算并激活隐藏层
for j in range(hidden_n):
total=0
for i in range(input_n):
total+=an_input[i]*input_hidden_weights[j][i]
total+=input_hidden_bs[j]#加入最后的偏置
hidden_as[j]=sigmoid(total)
#计算并激活输出层
total=0
for j in range(hidden_n):
total+=hidden_as[j]*hidden_output_weights[j]
total+=hidden_output_b
global output_z #由于output_z是标量,需要声明为全局
output_z=total
#误差反向信息传递
def back_propagate(an_input,y_true,learn_rate):
forward_propagate(an_input)#前向信息传递
#计算隐藏层到输出层权重的偏导数及偏置
d_y=output_z-y_true
d_hidden_output_weights=np.zeros(hidden_n)#初始化
for j in range(hidden_n):
d_hidden_output_weights[j]=d_y*hidden_as[j]
d_hidden_output_b=d_y
#更新隐藏层到输出层权重
for j in range(hidden_n):#更新隐藏层到输出层的权重
hidden_output_weights[j]-=learn_rate*d_hidden_output_weights[j]
global hidden_output_b
#更新隐藏层到输出层偏置
hidden_output_b-=learn_rate*d_hidden_output_b
# 计算输入层到隐藏层权重的偏导数
d_hidden_as = np.zeros(hidden_n)
for j in range(hidden_n):
d_hidden_as[j] = d_y * hidden_output_weights[j]
d_hidden_zs = np.zeros(hidden_n)
for j in range(hidden_n):
d_hidden_zs[j] = d_hidden_as[j] * hidden_as[j] * (1 - hidden_as[j])
d_input_hidden_weights = np.zeros((hidden_n, input_n))
d_input_hidden_bs = d_hidden_zs
for j in range(hidden_n):
for i in range(input_n):
d_input_hidden_weights[j][i] = d_hidden_zs[j] * an_input[i]
# 更新输入层到隐藏层权重
for j in range(hidden_n):
for i in range(input_n):
input_hidden_weights[j][i] -= learn_rate * d_input_hidden_weights[j][i]
# 更新输入层到隐藏层的偏置
for j in range(hidden_n):
input_hidden_bs[j] -= learn_rate * d_input_hidden_bs[j]
def computeError(Xdata, Ydata): # 对数据集计算误差,并计算预测结果
error = 0
predictValues = np.zeros(len(Xdata))
for i in range(len(Xdata)):
forward_propagate(Xdata[i])
error += 0.5 * (output_z - Ydata[i]) ** 2
predictValues[i] = output_z
return error / len(Xdata), predictValues
def train(trainX, trainy, iterate=50, learn_rate=0.05): # 训练过程设置
for t in range(iterate): # 训练神经网络
for i in range(len(trainX)):
back_propagate(trainX[i], trainy[i], learn_rate)
if t % 100 == 0: # 输出迭代之后的误差,以便观察误差降低的效果
totalError, preValues = computeError(trainX, trainy)
print('iterate:', t, ' the training error=', totalError)
#初始化
input_n=11#输入层特征数
hidden_n=6#隐藏层神经单元个数
output_n=1#输出单元个数
np.random.seed(10)
input_hidden_weights=np.random.rand(hidden_n,input_n)#输入到隐藏层的权值
np.random.seed(10)
input_hidden_bs=np.random.rand(hidden_n)
np.random.seed(10)
hidden_output_weights=np.random.rand(hidden_n)#隐藏层到输出层的权值
np.random.seed(10)
hidden_output_b=np.random.rand(1)
hidden_as=np.zeros(hidden_n) #隐藏单元激活值
output_z=np.ones(1) #输出单元值
#数据处理
dataset=load_boston()
X=dataset.data[:,[0,2,4,5,6,7,8,9,10,11,12]]
y=dataset.target
X=minMaxScaler(X)
trainX,trainy,testX,testy=shuffle(X,y)
train(trainX,trainy,1000,0.002)#训练
#需要计算测试集的总误差以及测试集预测的结果,以便和真实结果进行画图比对
totalError,predictValues=computeError(testX,testy)
print('test error=',totalError)
#真实值从小到大排列
testy_ascending_index=testy.argsort()
plt.plot(range(len(testX)),testy[testy_ascending_index],'o',label='True value')
plt.plot(range(len(testX)),predictValues[testy_ascending_index],'*',label='predict value')
plt.legend()
plt.show()
iterate: 0 the training error= [45.03945242]
iterate: 100 the training error= [6.18205346]
iterate: 200 the training error= [5.59847866]
iterate: 300 the training error= [5.57628389]
iterate: 400 the training error= [5.5587542]
iterate: 500 the training error= [5.54749627]
iterate: 600 the training error= [5.54091243]
iterate: 700 the training error= [5.53675292]
iterate: 800 the training error= [5.53367205]
iterate: 900 the training error= [5.5305169]
test error= [12.82731241]
数据思维
数据分析
广义的数据分析包括狭义数据分析和数据挖掘
狭义的数据分析是指根据分析目的,采用对比分析、分组分析、交叉分析等分析方法,对收集来的数据进行处理与分析,提取有价值的信息,发挥数据的作用,得到特定统计结果的过程。
数据挖掘则是从大量的、不完全的、有噪声的、模糊的、随机的实际应用数据中,通过应用回归、分类、聚类等技术,挖掘潜在价值的过程。
典型的数据分析的流程:
- 问题定义
- 数据采集
- 数据预处理
- 分析与建模
- 模型评价与优化
- 问题定义:明确分析目标,既本次分析要研究的主要问题和预期的分析目标等。
- 数据采集:从企业数据库中调取相关业务数据、编写网页爬虫或到特定网站下载公开的数据集
- 数据预处理:对原始数据进行清洗、变换和标准化
- 分析与建模:指通过各种统计分析方法以及数据挖掘模型分析数据中有价值的信息,并得出结论的过程
- 模型评价与优化:对已经建立的一个或多个模型,根据其模型的类别,使用对应的指标评价其性能优劣的过程
创建dataframe
第三方库pandas:
导入:import pandas as pd
提供了DataFrame对象。 DataFrame是一 个表格型的数据结构,它含有一组 有序的列。
每列可以是不同的值类型(数值、字符串、布尔值等)。
DataFrame既有行索引也有列索引。
import pandas as pd
#从字典创建dataframe:
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
'year': [2000, 2001, 2002, 2001, 2002],
'pop': [1.5, 1.7, 3.6, 2.4, 2.9]}
df=pd.DataFrame(data)
#指定列的顺序:
df=pd.DataFrame(data, columns=['year', 'state', 'pop'])
#指定行索引
df=pd.DataFrame(data,columns=['year', 'state', 'pop', 'debt'],index=['one', 'two', 'three', 'four', 'five'])
索引
pandas中有三种索引方法:[]、.loc、.iloc
基于行名和列名的索引:.loc
取得其中一行或多行:
df.loc['one']
df.loc['one':'three']
df.loc[['one','three']] #列表索引
取得n行及n列
df.loc['one','year']
df.loc['one':'three','year':'pop']
df.loc[['one','three'],['year','pop']]
基于行索引值和列索引值的索引:.iloc
取得其中一行或多行:
df.iloc[0] #df.loc['one']
df.iloc[0:3] #df.loc['one':'three']
df.iloc[[0,2]] # df.loc[['one’,'three’]] 列表索引
取得n行及n列
df.iloc[0,0] #df.loc['one','year']
df.iloc[0:3,0:3] #df.loc['one':'three','year':'pop']
df.iloc[[0,2],[0,2]] #df.loc[['one','three'],['year','pop']]
Pandas除三种基本索引方法外,还可以使用布尔索引
布尔索引:与前三种索引方式结合使用
筛选符合条件的行:与[]结合使用
df[df.year>2001] #2001年以后
筛选符合条件的行:与.loc结合使用
df.loc[df.year>2001]
df.loc[df.year>2001,'year':'pop’]
筛选符合条件的行:与.iloc结合使用
df.iloc[list(df.year>2001)]
df.iloc[list(df.year>2001),0:2]
基本操作:添加、删除、修改、排序、合并数据集
添加
df=df.append({'year':2003,'state':'Louisiana','pop':1.4},ignore_index=True)#行
df['total']=0 #列
df['total']=df['pop']-df['debt'] #先将debt列值设为1
删除
df.drop(5,inplace=True) #行
df.drop(‘debt’,axis=1,inplace=True) #列
修改
#获取和修改列类型:
df['pop'].dtype
df['pop']=df['pop'].astype(str)
#修改值
df['pop']=df['pop']+3
df.loc[df['year']>=2002,'pop'] +=1
排序
df.sort_values(by=['pop'],ascending=True)
df.sort_values(by=['year','pop'],ascending=False)
合并数据集
df3=pd.concat([df1,df],ignore_index=True) #首先df1=df.copy()
df3=pd.concat([df1,df], axis=1) #轴1方向拼接
文件操作
载入数据:csv、 excel、 txt等
df=pd.read_csv(‘xxxx.csv’,encoding=‘xxx’,sep=‘xxx’,header=None) #sep:分隔符,默认为逗号; header=None没有列标签
df= pd.read_excel(‘xxxx.xlsx’,header=None)#header=None没有列标签
写入数据:csv、 excel、 txt等
df.to_csv(‘xxxx.csv’,sep=‘xxx’,encoding=‘xxx’)
df.to_excel('xxxx.xlsx',index=False) #不写入索引列
第三方库:matplotlib
Matplotlib是一个Python 2D绘图库,可以轻松生成折线图、柱状图、饼图、散点图等
#导入库
import matplotlib.pyplot as plt
#中文问题:
plt.rcParams['font.sans-serif'] = ['SimHei']
# 步骤一(替换sans-serif字体)
plt.rcParams['axes.unicode_minus'] = False
# 步骤二(解决坐标轴负数的负号显示问题)
#折线图
x = [1, 2, 3, 4]
y = [1.2, 2.5, 4.5, 7.3]
plt.plot(x, y) # plot函数作图
plt.savefig('line.png') #保存
plt.show() #看得到图形则不用这条语句
x = [1, 2, 3, 4]
y = [1.2, 2.5, 4.5, 7.3]
plt.plot(x, y, color="r", linestyle="--", marker="*", linewidth=1.0)
plt.show() #看得到图形则不用这条语句
#x轴和y轴标题
plt.ylabel('Y')
plt.xlabel('X')
#图形标题
plt.title('折线图')
#图例
plt.legend(loc='upper left')
#网格
plt.grid()
#注释
plt.text(x,y,'注释')
#导入库
import matplotlib.pyplot as plt
#中文问题:
plt.rcParams['font.sans-serif'] = ['SimHei']
# 步骤一(替换sans-serif字体)
plt.rcParams['axes.unicode_minus'] = False
# 步骤二(解决坐标轴负数的负号显示问题)
#条形图:bar()
x = [0,1,2,3] #季度
y = [1000, 1500, 1300, 1800] #销量
colors=['red','green','cyan','blue']
#plt.bar(x, y,width=0.8,color=colors)
plt.yticks(x,['春', '夏', '秋', '冬'])
#水平条形图:barh()
plt.barh(x, y,height=0.8,color=colors)
#值标签
for i,j in zip(x,y):
plt.text(i,j,j)
plt.show() #看得到图形则不用这条语句
#饼图:pie()
labels = ['娱乐','育儿','饮食','房贷','交通','其它']
sizes = [2,5,12,70,2,9]
explode = (0,0,0,0.1,0,0)
plt.pie(sizes,explode=explode,labels=labels,autopct='%1.1f%%')
plt.title("8月份家庭支出")
plt.show()
分析目标
查看数据基本情况,并完成对数据的基本统计。统计2004年各季度销售量并以条图方式呈现,绘制2003年、2004年销售额曲线对比图,并将2004年不同季度销售额占比以饼图方式呈现。
载入数据
df=pd.read_csv('sales_data_sample9.csv',encoding='gbk')
数据查看
df.info() #查看数据整体情况
print(df.head(3)) #前面n行
print(df.tail(3)) #末尾n行
print(df.shape) #数据集规模
df.dtypes #数据类型
数据预处理
缺失值:
检查是否有缺失值:df.count()
df=df.dropna() #默认丢弃任何含有NaN的行
df=df.dropna(how='all') #只丢弃全为NaN的行
df=df.dropna(how='all',axis=1) #只丢弃全为NaN的列
df=df.fillna(0) #用0填充缺失数据
df['总分'].fillna(df['总分'].mean(),inplace=True) #用列均值填充
变换:
异常值:
探索性分析:
基本统计方法
sum() 求和
max() 最大值 idxmax() 最大值对应索引号
min() 最小值 idxmin() 最小值对应索引号
var() 方差 std() 标准差
median() 中位数 mean() 均值
nlargest(n,列名)该列最大的n个值
describe():计算各列的频率、均值、标准差、级值、四分位数
数值预测
狭义的数据分析:根据分析目的,采用对比分析、分组分析、交叉分析等统计分析方法,对采集来的数据进行处理与分析,从中提取有价值的信息
数据挖掘:从大量的、不完全的、有噪声的、模糊的、随机的实际应用数据中,通过应用回归、分类、聚类等技术,挖掘潜在价值的过程
机器学习
机器学习(Machine Learning)根据已知数据来不断学习和积累经验,然后总结出规律并尝试预测未知数据的属性,是一门综合性非常强的多领域交叉学科,涉及线性代数、概率论、逼近论、凸分析、算法复杂度理论等多门学科
目前机器学习已经有了十分广泛的应用,例如数据挖掘、计算机视觉、自然语言处理、生物特征识别、搜索引擎、医学诊断、检测信用卡欺诈、证券市场分析、DNA序列测序、语音和手写识别、推荐系统、战略游戏和机器人运用等。
机器学习的过程与人类学习过程类似,例如识别图像需要几个步骤:
首先要收集大量样本图像,并标明这些图像的类别(称为样本标签,就像告诉孩子这是一只恐龙),这些样本图像就是数据集。
把样本和标注送给算法学习(称为训练),训练完成之后得到一个模型,这个模型是从这些样本中总结归纳得到的知识。
接下来,可以用这个模型对新的图像进行识别,称为预测。
以下是机器学习中的经典监督学习过程:
机器学习
有监督学习:训练样本包含对应的‘标签’(例如每个样本所属的类别)。训练集需要包括输入和输出,也就是特征和目标,其中目标是由人工标注的‘标签’。通过大量已知的数据不断训练和减少错误来提高认知能力,最后根据积累的经验去预测未知数据的属性。
- 回归
- 分类
无监督学习:训练数据包含一组输入向量而没有相应的目标值。这类算法的目标可能是发现原始数据中相似样本的组合(称作聚类),或者确定数据的分布(称作密度估计),或者把数据从高维空间投影到低维空间(称作降维)以便进行可视化。
- 聚类