Python与量化投资
从基础到实战
第三章 Python 进阶
3.1 NumPy 的使用
NumPy 是高性能科学计算和数据分析的基础包。
import numpy as np
一旦在代码中看到np,就是使用了NumPy。
- 多维数组 ndarray
一个快速、灵活的大数据容器。
一维数组
data=[1,2,3,4]
arr=np.array(data)
arr
array([1, 2, 3, 4])
多维数组
data1=[data,data]
arr1=np.array(data1)
arr1
array([[1, 2, 3, 4],
[1, 2, 3, 4]])
其他函数也可以快速创建数组
np.zeros((3,3))
array([[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 0., 0.]])
np.ones((3,3))
array([[ 1., 1., 1.],
[ 1., 1., 1.],
[ 1., 1., 1.]])
np.arange(1,10,2)
array([1, 3, 5, 7, 9])
np.linspace(1,10,4) # 创建一个等差数列
array([ 1., 4., 7., 10.])
- ndarray 的数据类型
dtype 代表ndarray 中元素的数据类型。
arr2=np.array([1,2,3,4])
arr2.dtype
dtype('int32')
arr3=np.array([1.1,2,3,4])
arr3.dtype
dtype('float64')
arr4=np.array(['量','化','分','析'])
arr4.dtype
dtype('<U1')
不同的数据类型之间也能互相转换
float_arr2=arr2.astype(np.float64)
float_arr2
array([ 1., 2., 3., 4.])
int_arr3=arr3.astype(np.int32)
int_arr3
array([1, 2, 3, 4])
u_arr3=arr3.astype(np.unicode_)
u_arr3
array(['1.1', '2.0', '3.0', '4.0'],
dtype='<U32')
- 数组索引、切片和赋值
arr4=np.array([[1,2,3],[4,5,6],[7,8,9]])
arr4
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
arr4[1] #索引
array([4, 5, 6])
arr4[:2] # 切片
array([[1, 2, 3],
[4, 5, 6]])
arr4[:2,:2] # 切片
array([[1, 2],
[4, 5]])
arr4[:2, :2] = 10 # 赋值
arr4
array([[10, 10, 3],
[10, 10, 6],
[ 7, 8, 9]]
arr4.copy()[:2, :2] = 5 # 赋值
arr4
array([[10, 10, 3],
[10, 10, 6],
[ 7, 8, 9]])
- 基本的数组运算
代码向量化
arr5 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
arr5
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
arr5 + arr5
array([[ 1, 4, 9],
[16, 25, 36],
[49, 64, 81]])
arr5 * arr5
array([[ 1, 4, 9],
[16, 25, 36],
[49, 64, 81]])
arr5 * 2
array([[ 2, 4, 6],
[ 8, 10, 12],
[14, 16, 18]])
arr5 ** 0.5
array([[ 1. , 1.41421356, 1.73205081],
[ 2. , 2.23606798, 2.44948974],
[ 2.64575131, 2.82842712, 3. ]])
arr5.sum()
45
arr5.std()
2.5819888974716112
arr5.mean()
5.0
arr5.max()
9
def f(x):
return x ** 2
f(arr5)
array([[ 1, 4, 9],
[16, 25, 36],
[49, 64, 81]])
- 随机数
伪随机数,字库numpy.random。
import numpy.random as npr
import matplotlib.pyplot as plt
%matplotlib inline
# npr.rand()函数可以用来生成[0,1) 的随机多维数组
npr.rand(3, 2)
array([[ 0.89298191, 0.03415187],
[ 0.85438543, 0.26102217],
[ 0.25366176, 0.7302258 ]])
# 随机区间可以转化
a = 2
b = 4
npr.rand(3, 2) * (b - a) + a
array([[ 2.26095239, 2.85244207],
[ 2.90443128, 3.29532683],
[ 2.60474432, 3.14618094]])
可视化
size = 1000
rn1 = npr.rand(size, 2)
rn2 = npr.randn(size)
rn3 = npr.randint(0, 10, size)
rang = [0, 10, 20, 30, 40]
rn4 = npr.choice(rang, size = size)
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows = 2, ncols = 2, figsize = (10, 10))
ax1.hist(rn1, bins = 25, stacked = True)
ax1.set_title('rand')
ax1.set_ylabel('frequency')
ax1.grid(True)
ax2.hist(rn2, bins = 25)
ax2.set_title('randn')
ax2.grid(True)
ax3.hist(rn3, bins = 25)
ax3.set_title('randint')
ax3.set_ylabel('frequency')
ax3.grid(True)
ax4.hist(rn4, bins = 25)
ax4.set_title('choice')
ax4.grid(True)
3.2 Pandas 的使用
Pandas是基于NumPy 衍生出的一种工具,用于解决数据分析问题,他纳入了大量的库和一些标准的数据模型,提供了可用于高效操作大型数据集的工具。
import pandas as pd
一旦代码中看到了pd ,就是使用了Pandas。
- Pandas 的数据结构
- Series(一维数组)
Series 增加了对应的标签以用于索引,标签索引赋予了Series 强大的存取元素的功能。
obj = pd.Series([40, 12, -3, 25])
obj
0 40
1 12
2 -3
3 25
dtype: int64
obj[0]
40
obj.index # 可以通过index 与value获取Series的索引与数据
RangeIndex(start=0, stop=4, step=1)
obj.values
array([40, 12, -3, 25], dtype=int64)
# Series 建立时就指定索引
obj = pd.Series([40, 12, -3, 25],index=['a','b','c','d'])
obj
a 40
b 12
c -3
d 25
dtype: int64
# 通过索引获取数值
obj['c']
-3
# 对于Series 的各种计算,其他结果也会保留index
obj[obj>15]
a 40
d 25
dtype: int64
#
obj.describe()
count 4.000000
mean 18.500000
std 18.339393
min -3.000000
25% 8.250000
50% 18.500000
75% 28.750000
max 40.000000
dtype: float64
obj.mean()
18.5
# 转换为字典
obj.to_dict()
{'a': 40, 'b': 12, 'c': -3, 'd': 25}
- DataFrame(二维的表格型数据结构)
d = {'one' : pd.Series([1., 2., 3.], index=['a', 'b', 'c']),'two' : pd.Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])}
df = pd.DataFrame(d)
df
one two
a 1.0 1.0
b 2.0 2.0
c 3.0 3.0
d NaN 4.0
- Panel(三维数组)
- Pandas 输出设置
通过设置set_option 设置Pandas 的输出格式。
import pandas as pd
pd.set_option("display.max_rows",1000)
pd.set_option("display.max_columns",20)
pd.set_option('precision',7)
pd.set_option('large_repr', 'truncate')
- Pandas 数据读取与写入
读取本地文件如CSV、TXT、xlsx等
a=pd.read_csv('closeprice.csv',encoding='gbk',dtype={'ticker': str})
a
Unnamed: 0 ticker secShortName tradeDate closePrice
0 0 000001 平安银行 2017-06-20 9.12
1 1 000002 万科A 2017-06-20 21.03
2 2 000004 国农科技 2017-06-20 27.03
3 3 000005 世纪星源 2017-06-20 5.45
4 4 000006 深振业A 2017-06-20 8.87
5 5 000007 全新好 2017-06-20 15.87
保存文件
a.to_excel('closeprice.xls')
- 数据集快速描述性统计分析
基本的统计分析
import pandas as pd
data = pd.read_csv('closeprice.csv',encoding='gbk')
data.describe().T
count mean std min 25% 50% 75% max
Unnamed: 0 6.0 2.5000000 1.8708287 0.00 1.2500 2.500 3.75 5.00
ticker 6.0 4.1666667 2.3166067 1.00 2.5000 4.500 5.75 7.00
closePrice 6.0 14.5616667 8.2950550 5.45 8.9325 12.495 19.74 27.03
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6 entries, 0 to 5
Data columns (total 5 columns):
Unnamed: 0 6 non-null int64
ticker 6 non-null int64
secShortName 6 non-null object
tradeDate 6 non-null object
closePrice 6 non-null float64
dtypes: float64(1), int64(2), object(2)
memory usage: 320.0+ bytes
-
根据已有的列建立新列
ticker.map 函数 -
DataFrame 按多列排序
sort_values(by = ( ), ascending = (False, True) , inplace=True )方式调用 -
DataFrame 去重
data = pd.DataFrame({'k1': ['one'] * 3 + ['two'] * 4, 'k2': [3, 2, 1, 3, 3, 4, 4]})
data
k1 k2
0 one 3
1 one 2
2 one 1
3 two 3
4 two 3
5 two 4
6 two 4
# 在不加任何参数时,Pandas会将完全相同的行去重
data.drop_duplicates()
k1 k2
0 one 3
1 one 2
2 one 1
3 two 3
5 two 4
# subset 为k1 时,只要k1 重复,就认为是重复的,
#可以通过keep 参数确定保留哪个,一般在使用keep 时先排序
data.drop_duplicates(subset=['k1'],keep='last')
k1 k2
2 one 1
6 two 4
# 查看重复的行
data[data.duplicated()]
k1 k2
4 two 3
6 two 4
-
删除已有的列
drop()函数
axis = ‘columns’ 或者axis = 1 都是按照列来处理的。 -
Pandas 替换数据
批量替换数据中的指定数值,replace() -
DataFrame 重命名
重命名rename() -
DataFrame 切片与筛选
三种切片方法:loc 、 iloc、ix -
连续型变量分组
bins 、 cut 操作 -
Pandas 分组技术
groupby 函数
3.3 SciPy 的初步使用
SciPy 包含致力于解决在科学计算中的常见问题的各个工具箱,它的不同的子模块对应不用的应用,例如插值、积分、优化、图像处理和特殊函数等。
本章只选择与部分与金融量化分析相关的子库进行分析介绍。
- 回归分析
定义:是确定两种或两种以上变量之间相互依赖的定量关系的一种统计分析方法。
按涉及变量的多少:一元回归分析和多元回归分析。
按因变量的多少:简单回归分析和多重回归分析。
按自变量和因变量之间的关系:线性回归分析和非线性回归分析。
在CAPM 模型中beta 系数的计算,本质上就是一元线性回归,代码如下分析:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import datetime as dt
%matplotlib inline
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
data = pd.read_csv('data.csv', index_col='Date')
data.index = [dt.datetime.strptime(x, '%Y-%m-%d') for x in data.index]plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
data.head()
沪深300 中国平安
2015-06-23 0.03214 0.0496
2015-06-24 0.01965 0.0052
2015-06-25 -0.03557 -0.0287
2015-06-26 -0.07868 -0.0605
2015-06-29 -0.03336 -0.0119
data.plot(figsize=(10, 6))
plt.ylabel('涨跌幅')
可以发现,中国平安与沪深300的相关性还是比较大的。
接下来,使用StatsModels 模块。
import statsmodels.api as sm
x = data['沪深300'].values
X = sm.add_constant(x) #添加常数项
y = data['中国平安'].values
# 对二者的收益率进行线性回归,斜率即beta 系数
model = sm.OLS(y, X)
results = model.fit()
results.params
array([ 0.00095063, 0.80946537])
plt.figure(figsize=(10, 6))
plt.plot(x, y, 'o', label='中国平安-沪深300')
plt.plot(x, results.fittedvalues, 'r--', label='ordinary least square')
plt.legend()
plt.xlabel('沪深300')
plt.ylabel('中国平安')
plt.grid(True)
归因分析对于投资组合管理十分重要。我们认为一个虚拟投资组合是由两个随机因子和事先分配的权重构成的,这一过程类似于多元线性回归:
import numpy.random as npr
factor = npr.rand(1000, 3)
Factor = sm.add_constant(factor) #添加常数项
fac1 = factor[:, 0] #因子1
fac2 = factor[:, 1] #因子2
fac3 = factor[:, 2] #因子3
e = npr.random(1000) #噪声
port = fac1 * 0.3 + fac2 * 0.7 + fac3 * 0.4 + e #虚构投资组合及因子权重
model1 = sm.OLS(port, Factor)
results1 = model1.fit()
results1.params
array([ 0.53531625, 0.22141331, 0.70291227, 0.40377034])
- 插值
是在离散数据的基础上补插连续函数。使这条连续曲线通过全部给定的离散数据点。
例子:
data1 = pd.read_csv('data1.csv')
data1.head()
沪深300
0 3424.1940
1 3424.1669
2 3485.6581
3 3480.4345
4 3492.8845
import scipy.interpolate as spi
X = data1.index #定义数据点
Y = data1.values #定义数据点
x = np.arange(0, len(data1), 0.15) #定义观测点
ipo1 = spi.splrep(X,Y,k=1) #k 样条拟合顺序(1<=k<=5)
ipo3 = spi.splrep(X,Y,k=3)
iy1 = spi.splev(x,ipo1)
iy3 = spi.splev(x,ipo3)
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10,12))
ax1.plot(X, Y, label='沪深300')
ax1.plot(x, iy1, 'r.', label='插值点')
ax1.set_ylim(Y.min() - 10, Y.max() + 10)
ax1.set_ylabel('指数')
ax1.set_title('线性插值')
ax1.legend()
ax2.plot(X, Y, label='沪深300')
ax2.plot(x, iy3, 'r.', label='插值点')
ax2.set_ylim(Y.min() - 10, Y.max() + 10)
ax2.set_ylabel('指数')
ax2.set_title('三次样条插值')
ax2.legend()
- 正态检验
利用A股数据检验股票市场是否真的符合正态分布。
- 凸优化
指求最小值的目标函数为凸函数的一类优化问题。
马科维茨利用方差-均值模型分析得出通过投资组合可以有效降低风险的结论。
投资组合的优化关键在于对组合中各标的权重的优化,优化目标大致有:夏普最大化、收益最大化和风险最小化。
3.4 Matplotlib 的使用
Matplotlib 是Python 绘图的始祖。
虽然对于科学家而言,会吐的美观性可能并不重要,只要能清晰地表达出数据的含义就足够了,然而在金融领域或者互联网领域,绘图的美观性就显得尤为重要了,此时如果依旧使用Matplotlib ,代码的数量就会变得愈发冗长。Seaborn 就是为了解决这一问题而出现的。
3.5 Seaborn 的使用
Seaborn 的主要功能:
- 通过内置主题改善Matplotlib 的外观
- 有丰富的调色板工具,可更好的显示数据
- 对变量分布进行可视化
- 数据矩阵可视化,并使用聚类算法发现这些巨震中的结构
- 对自变量和因变量之间的线性回归结果进行可视化
- 绘制统计时间序列,并将其不确定性可视化
- 构建高级、抽象的网格图,可轻松地将复杂的问题可视化
- 主题管理
4个内置主题,分别为paper、 talk 、 poster 、 notebook,对应不同的场合。可使用set_context( ) 函数设置。 - 调色板
大致分为循环 、渐变、混合三类。利用set_palette( ) 函数进行设置。 - 分布图
distplot() 函数 - 回归图
Implot()函数 - 矩阵图
heatmap 是一种典型的矩阵图,通过颜色的深浅来表示数据的大小。 - 结构网格图
pairplot()函数
3.6 Scikit-Learn 的初步使用
第三方模块,对一些常用的机器学习方法进行了封装,这样在需要进行机器学习时只要调用Scikit-Learn 里的模块就行。
机器学习的功能主要包括分类、回归、降维、聚类。主要的分类算法包括决策树、贝叶斯分类、支持向量机和随机森林等,主要的回归算法有SVR 、Lasso等。常见的降维方位有主成分分析、主题模型等。常用的聚类算法有K-Means、Gaussian等。
同时还包含了特征提取、数据预处理和模型评估这三大模块。
-
Scikit-Learn 学习准备
安装
模块列表:包含哪些模块
应用于机器学习 -
常见的机器学习模型
- 决策树
- 支持向量机
- 朴素贝叶斯分类器
- 神经网络
-
模型的评价方法 --metric 模块
- 分类准确率
- 混淆矩阵
- ROC曲线
- 召回率
-
深度学习
大数据和云计算的到来,深度学习算法是对人工神经网络的进一步发展。
监督学习和无监督学习
3.7 SQLAIchemy 与常用数据库的连接
开源库,提供了SQL工具包及对象关系映射(ORM)工具,基本操作:增删改查。
- 连接数据库
安装数据库驱动
- 读取数据
read_sql( )函数 - 存储数据
to_sql( ) 函数