2. 线性模型 (一元一次方程)
2.1 线性方程
如下直线方程属于·线性方程:
y
=
k
x
+
b
y = kx + b
y=kx+b
图像可表示为:
2.2 线性拟合
在实际应用中,输入和输出可以用线性模型进行拟合,称之为线性模型或线性问题(如房屋面积与总价、成年人的身高与体重)
如下图所示:
线性拟合就是试图找到一个最优的线性方程,可以最好的匹配当前样本(到所有样本的距离之和最短,误差最小)。若已知样本只有一个自变量
x
x
x与一个因变量
y
y
y,则线性方程可表示为:
y
=
k
x
+
b
y = kx + b
y=kx+b
线性拟合就是根据一组x, y的值,来寻求最佳k,b的值,这个过程也可称为线性回归。
线性回归可以用np.linalg.lstsq(a, b)来计算线性矩阵方程的最小二乘解
2.3 苹果股价案例
用一组散点描述时间序列下的股价:
import pandas as pd
import numpy as np
data = pd.read_csv('aapl.csv', # 导入文件
header=None,
names=['dates','close']) # 日期 & 当日收市股价
print(data)
"""
dates close
0 2011-01-28 336.10
1 2011-01-31 339.32
2 2011-02-01 345.03
3 2011-02-02 344.32
4 2011-02-03 343.44
... ... ...
27 2011-03-09 352.47
28 2011-03-10 346.67
29 2011-03-11 351.99
"""
将dates与close用线画出来
data.plot(x='dates', y='close')
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KLQbhcV9-1597667251227)(line4.png)]
为了方便进行数学运算, 需要把日期改为数字格式, 可以用2011-01-01为0, 计算每个日期距离2011-01-01的天数为日期值
data['delta'] = data['dates'] - pd.to_datetime('2011-01-01')
data['delta'] = data['delta'].dt.days
print(data)
"""
dates close delta
0 2011-01-28 336.10 27
1 2011-01-31 339.32 30
2 2011-02-01 345.03 31
3 2011-02-02 344.32 32
... ... ... ...
"""
我们希望所有点都可以被线性方程 y = k x + b y=kx + b y=kx+b表示,如果把delta和close数据带入方程可得:
"""
k*delta1 + b = clase1
k*delta2 + b = clase2
k*delta3 + b = clase3
...
k*delta29 + b = clase29
"""
这一组方程表示为矩阵相乘格式: (b 可以看作是 1 * b)
[ d e l t a 1 1 d e l t a 2 1 d e l t a 3 1 d e l t a n 1 ] × [ k b ] = [ c l o s e 1 c l o s e 2 c l o s e 3 c l o s e n ] \left[ \begin{array}{ccc} delta{_1} & 1\\ delta{_2} & 1\\ delta{_3} & 1 \\ delta{_n} & 1 \\ \end{array} \right ] \times \left[ \begin{array}{ccc} k\\ b\\ \end{array} \right ] = \left[ \begin{array}{ccc} close{_1}\\ close{_2}\\ close{_3}\\ close{_n}\\ \end{array} \right ] ⎣⎢⎢⎡delta1delta2delta3deltan1111⎦⎥⎥⎤×[kb]=⎣⎢⎢⎡close1close2close3closen⎦⎥⎥⎤
建立一个二维数组和一个一维数组, 用于计算矩阵 (如上所示)
# 制作一个二维数组, 第一列为delta, 第二列全部为1
A = pd.DataFrame({'a':data['delta'], # 第一列为delta
'b': np.ones(len(data))}) # 第二列全部为1, 长度与第一列长度一样
print(A)
"""
a b
0 27 1.0
1 30 1.0
2 31 1.0
.. .. ..
"""
B = data['close']
print(B)
"""
0 336.10
1 339.32
2 345.03
3 344.32
.. ..
"""
每两组方程即可求得一组k与b的值, 单纯进行线性拟合的话, 会得到多个不同的样本
用$np.linalg.lstsq(a, b) $可以通过最小二乘法求出所有结果中拟合误差最小的k与b的值。
x = np.linalg.lstsq(A,B)[0]
print(x) # array([1.75245535e-01, 3.42503209e+02])
# 得到的线性方程为: 0.175*delta + 342.5 = close
利用线型拟合, 计算出基于线性方程的预测close数据 (close_pred)
close_pred = data['delta'] * x[0] +x[1] # 将所有的delta带入到线性方程中得到y_pred
data['close_pred'] = close_pred
print(data)
"""
dates close delta close_pred
0 2011-01-28 336.10 27 347.234839
1 2011-01-31 339.32 30 347.760575
2 2011-02-01 345.03 31 347.935821
3 2011-02-02 344.32 32 348.111066
.. .. .. .. ..
"""
画出股价的趋势线
data.plot(x='dates', y=['close', 'close_pred'])