NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。
numpy概述
Numerical Python,数值的Python,补充了Python语言所欠缺的数值计算能力。
Numpy是其它数据分析及机器学习库的底层库。
Numpy完全标准C语言实现,运行效率充分优化。
Numpy开源免费。
numpy历史
1995年,Numeric,Python语言数值计算扩充。
2001年,Scipy->Numarray,多维数组运算。
2005年,Numeric+Numarray->Numpy。
2006年,Numpy脱离Scipy成为独立的项目。
numpy的核心:多维数组
代码简洁:减少Python代码中的循环。
底层实现:厚内核(C)+薄接口(Python),保证性能。
numpy基础 ndarray数组 用np.ndarray类的对象表示n维数组
1 2 3 import numpy as npary = np.array([1 , 2 , 3 , 4 , 5 , 6 ]) print (type (ary))
内存中的ndarray对象 元数据(metadata)
存储对目标数组的描述信息,
字段
描述
dim
轴
count
长度
dimensions
dtype
类型
data
数据
…
…
实际数据
完整的数组数据
将实际数据与元数据分开存放,一方面提高了内存空间的使用效率,另一方面减少对实际数据的访问频率,提高性能。
ndarray数组对象的特点
Numpy数组是同质数组 ,即所有元素的数据类型必须相同
Numpy数组的下标从0开始,最后一个元素的下标为数组长度减1
ndarray数组对象的创建 np.array(任何可被解释为Numpy数组的逻辑结构)
1 2 3 import numpy as npa = np.array([1 , 2 , 3 , 4 , 5 , 6 ]) print (a)
np.arange(起始值(0),终止值,步长(1))
1 2 3 4 5 6 import numpy as npa = np.arange(0 , 5 , 1 ) print (a)b = np.arange(0 , 10 , 2 ) print (b)
np.zeros(数组元素个数, dtype=’类型’)
1 2 3 import numpy as npa = np.zeros(10 ) print (a)
np.ones(数组元素个数, dtype=’类型’)
1 2 3 import numpy as npa = np.ones(10 ) print (a)
ndarray对象属性的基本操作 数组的维度: np.ndarray.shape
1 2 3 4 5 6 7 8 9 import numpy as npary = np.array([1 , 2 , 3 , 4 , 5 , 6 ]) print (type (ary), ary, ary.shape)ary = np.array([ [1 ,2 ,3 ,4 ], [5 ,6 ,7 ,8 ] ]) print (type (ary), ary, ary.shape)
元素的类型: np.ndarray.dtype
1 2 3 4 5 6 7 8 9 10 ary = np.array([1 , 2 , 3 , 4 ]) print (ary, ary.dtype)ary = ary.astype('float64' ) print (ary, ary.dtype)ary = ary.astype('str' ) print (ary, ary.dtype)
数组元素的个数: np.ndarray.size
1 2 3 4 5 6 7 import numpy as npary = np.array([ [1 ,2 ,3 ,4 ], [5 ,6 ,7 ,8 ] ]) print (ary.shape, ary.size, len (ary))
数组元素索引(下标)
数组对象[…, 页号, 行号, 列号]
下标从0开始,到数组len-1结束。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import numpy as npa = np.array([[[1 , 2 ], [3 , 4 ]], [[5 , 6 ], [7 , 8 ]]]) print (a, a.shape)print (a[0 ])print (a[0 ][0 ])print (a[0 ][0 ][0 ])print (a[0 , 0 , 0 ])for i in range (a.shape[0 ]): for j in range (a.shape[1 ]): for k in range (a.shape[2 ]): print (a[i, j, k])
ndarray对象属性操作详解 Numpy的内部基本数据类型
类型名
类型表示符
布尔型
bool_
有符号整数型
int8(-128~127)/int16/int32/int64
无符号整数型
uint8(0~255)/uint16/uint32/uint64
浮点型
float16/float32/float64
复数型
complex64/complex128 3
字串型
str_,每个字符用32位Unicode编码表示
自定义复合类型 同时演示设置dtype的几种方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 import numpy as npdata = [('zs' , [50 ,51 ,52 ], 15 ), ('ls' , [83 ,71 ,62 ], 16 ), ('ww' , [90 ,91 ,92 ], 17 )] ary = np.array(data,dtype='U2, 3int32, int32' ) print (ary, ary[0 ][1 ])print (ary[0 ]['f0' ])ary = np.array(data, dtype=[ ('name' , 'str' , 2 ), ('scores' , 'int32' , 3 ), ('age' , 'int32' , 1 )]) print ('-' * 45 )print (ary, ary.dtype)print (ary[0 ]['age' ]) print (ary[2 ]['scores' ]) ary = np.array(data, dtype={ 'names' :['name' , 'scores' , 'age' ], 'formats' :['U2' , '3int32' , 'int32' ]}) print (ary)print (ary[0 ]['age' ]) print (ary[2 ]['scores' ]) d = np.array(data, dtype={'name' : ('U3' , 0 ), 'scores' : ('3int32' , 16 ), 'age' : ('int32' , 28 )}) print (d[0 ]['name' ], d[0 ]['scores' ], d.itemsize)dates = ['2011-01-01' , '2012-01-01' , '2011-02-01' , '2012' , '2011-01-01 10:10:10' ] ary = np.array(dates) print (ary, ary.dtype)ary = ary.astype('M8[D]' ) print (ary, ary.dtype, ary[1 ]-ary[0 ])
类型字符码
类型
字符码
np.bool_
?
np.int8/16/32/64
i1/i2/i4/i8
np.uint8/16/32/64
u1/u2/u4/u8
np.float/16/32/64
f2/f4/f8
np.complex64/128
c8/c16
np.str_
U<字符数>
np.datetime64
M8[Y] M8[M] M8[D] M8[h] M8[m] M8[s]
字节序前缀,用于多字节整数和字符串: </>/[=]分别表示小端/大端/硬件字节序。
类型字符码格式
<字节序前缀><维度><类型><字节数或字符数>
3i4
释义
3i4
3个元素的一维数组,每个元素都是整型,每个整型元素占4个字节。
<(2,3)u8
小端字节序,6个元素2行3列的二维数组,每个元素都是无符号整型,每个无符号整型元素占8个字节。
U7
包含7个字符的Unicode字符串,每个字符占4个字节,采用默认字节序。
ndarray数组对象的维度操作 视图变维(数据共享): reshape() 与 ravel()
1 2 3 4 5 6 7 8 9 import numpy as npa = np.arange(1 , 9 ) print (a) b = a.reshape(2 , 4 ) print (b)c = b.reshape(2 , 2 , 2 ) print (c)d = c.ravel() print (d)
复制变维(数据独立): flatten()
1 2 3 4 e = c.flatten() print (e)a += 10 print (a, e, sep='\n' )
就地变维:直接改变原数组对象的维度,不返回新数组
1 2 3 4 a.shape = (2 , 4 ) print (a)a.resize(2 , 2 , 2 ) print (a)
ndarray数组切片操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import numpy as npa = np.arange(1 , 10 ) print (a) print (a[:3 ]) print (a[3 :6 ]) print (a[6 :]) print (a[::-1 ]) print (a[:-4 :-1 ]) print (a[-4 :-7 :-1 ]) print (a[-7 ::-1 ]) print (a[::]) print (a[:]) print (a[::3 ]) print (a[1 ::3 ]) print (a[2 ::3 ])
多维数组的切片操作
1 2 3 4 5 6 7 8 print ('-' * 45 )a = np.arange(1 , 10 ) a = a.reshape(3 , 3 ) print (a)print (a[:2 , :]) print (a[:2 , :2 ]) print (a[::2 , :])
ndarray数组的掩码操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import numpy as npa = np.array([1 , 2 , 3 , 4 , 5 ]) print (a + 10 )print (a * 2.5 )print (a + a)a = np.arange(1 , 10 ) mask = a % 3 == 0 print (mask)print (a[mask])mask = [2 , 2 , 3 , 3 , 6 , 6 , 4 , 4 ] print (a)print (a[mask])
常用语从大数组中获取子集的操作
多维数组的组合与拆分 垂直方向操作:
1 2 3 4 5 6 7 import numpy as npa = np.arange(1 , 7 ).reshape(2 , 3 ) b = np.arange(7 , 13 ).reshape(2 , 3 ) c = np.vstack((a, b)) d, e = np.vsplit(c, 2 )
水平方向操作:
1 2 3 4 5 6 7 import numpy as npa = np.arange(1 , 7 ).reshape(2 , 3 ) b = np.arange(7 , 13 ).reshape(2 , 3 ) c = np.hstack((a, b)) d, e = np.hsplit(c, 2 )
深度方向操作:(3维)
1 2 3 4 5 6 7 import numpy as npa = np.arange(1 , 7 ).reshape(2 , 3 ) b = np.arange(7 , 13 ).reshape(2 , 3 ) i = np.dstack((a, b)) k, l = np.dsplit(i, 2 )
多维数组组合与拆分的相关函数:
1 2 3 4 5 6 7 8 9 10 11 np.concatenate((a, b), axis=0 ) np.split(c, 2 , axis=0 )
长度不等的数组组合:
1 2 3 4 5 6 7 8 9 10 import numpy as npa = np.array([1 ,2 ,3 ,4 ,5 ]) b = np.array([1 ,2 ,3 ,4 ]) b = np.pad(b, pad_width=(0 , 1 ), mode='constant' , constant_values=-1 ) print (b)c = np.vstack((a, b)) print (c)
简单的一维数组组合方案
1 2 3 4 5 6 7 8 a = np.arange(1 ,9 ) b = np.arange(9 ,17 ) c = np.row_stack((a, b)) print (c)d = np.column_stack((a, b)) print (d)
ndarray类的其他属性
shape - 维度
dtype - 元素类型
size - 元素数量
ndim - 维数,len(shape)
itemsize - 元素字节数
nbytes - 总字节数 = size x itemsize
real - 复数数组的实部数组
imag - 复数数组的虚部数组
T - 数组对象的转置视图
flat - 扁平迭代器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import numpy as npa = np.array([[1 + 1j , 2 + 4j , 3 + 7j ], [4 + 2j , 5 + 5j , 6 + 8j ], [7 + 3j , 8 + 6j , 9 + 9j ]]) print (a.shape)print (a.dtype)print (a.ndim)print (a.size)print (a.itemsize)print (a.nbytes)print (a.real, a.imag, sep='\n' )print (a.T)print ([elem for elem in a.flat])b = a.tolist() print (b)
相关函数 算数平均值
样本中的每个值都是真值与误差的和。
1 2 算数平均值: m = (s1 + s2 + ... + sn) / n
算数平均值表示对真值的无偏估计。
案例:计算收盘价的算术平均值。
1 2 3 4 5 6 7 8 9 10 11 import numpy as npclosing_prices = np.loadtxt( '../../data/aapl.csv' , delimiter=',' , usecols=(6 ), unpack=True ) mean = 0 for closing_price in closing_prices: mean += closing_price mean /= closing_prices.size print (mean)mean = np.mean(closing_prices) print (mean)
加权平均值 样本:S = [s1 , s2 , …, sn ]
权重:W = [w1 , w2 , …, wn ]
加权平均值:a = (s1 w1 +s2 w2 +…+sn wn )/(w1 +w2 +…+wn )
1 np.average(closing_prices, weights=volumes)
VWAP - 成交量加权平均价格(成交量体现了市场对当前交易价格的认可度,成交量加权平均价格将会更接近这支股票的真实价值)
1 2 3 4 5 6 7 8 9 10 11 12 13 import numpy as npclosing_prices, volumes = np.loadtxt( '../../data/aapl.csv' , delimiter=',' , usecols=(6 , 7 ), unpack=True ) vwap, wsum = 0 , 0 for closing_price, volume in zip ( closing_prices, volumes): vwap += closing_price * volume wsum += volume vwap /= wsum print (vwap)vwap = np.average(closing_prices, weights=volumes) print (vwap)
TWAP - 时间加权平均价格(时间越晚权重越高,参考意义越大)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import datetime as dtimport numpy as npdef dmy2days (dmy ): dmy = str (dmy, encoding='utf-8' ) date = dt.datetime.strptime(dmy, '%d-%m-%Y' ).date() days = (date - dt.date.min ).days return days days, closing_prices = np.loadtxt( '../../data/aapl.csv' , delimiter=',' , usecols=(1 , 6 ), unpack=True , converters={1 : dmy2days}) twap = np.average(closing_prices, weights=days) print (twap)
最值 np.max() np.min() np.ptp(): 返回一个数组中最大值/最小值/极差
1 2 3 4 5 import numpy as npa = np.random.randint(10 , 100 , 9 ) print (a)print (np.max (a), np.min (a), np.ptp(a))
np.argmax() mp.argmin(): 返回一个数组中最大/最小元素的下标
1 print (np.argmax(a), np.argmin(a))
np.maximum() np.minimum(): 将两个同维数组中对应元素中最大/最小元素构成一个新的数组
1 print (np.maximum(a, b), np.minimum(a, b), sep='\n' )
案例:评估AAPL股票的波动性。
1 2 3 4 5 6 7 import numpy as nphighest_prices, lowest_prices = np.loadtxt( '../../data/aapl.csv' , delimiter=',' , usecols=(4 , 5 ), dtype='f8, f8' , unpack=True ) max_price = np.max (highest_prices) min_price = np.min (lowest_prices) print (min_price, '~' , max_price)
查看AAPL股票最大最小值的日期,分析为什么这一天出现最大最小值。
1 2 3 4 5 6 7 8 import numpy as npdates, highest_prices, lowest_prices = np.loadtxt( '../../data/aapl.csv' , delimiter=',' , usecols=(1 , 4 , 5 ), dtype='U10, f8, f8' , unpack=True ) max_index = np.argmax(highest_prices) min_index = np.argmin(lowest_prices) print (dates[min_index], dates[max_index])
观察最高价与最低价的波动范围 ,分析这支股票底部是否坚挺。
1 2 3 4 5 6 7 8 import numpy as npdates, highest_prices, lowest_prices = np.loadtxt( '../../data/aapl.csv' , delimiter=',' , usecols=(1 , 4 , 5 ), dtype='U10, f8, f8' , unpack=True ) highest_ptp = np.ptp(highest_prices) lowest_ptp = np.ptp(lowest_prices) print (lowest_ptp, highest_ptp)
中位数 将多个样本按照大小排序,取中间位置的元素。
若样本数量为奇数,中位数为最中间的元素
1 2000 3000 4000 10000000
若样本数量为偶数,中位数为最中间的两个元素的平均值
1 2000 3000 4000 5000 10000000
案例:分析中位数的算法,测试numpy提供的中位数API:
1 2 3 4 5 6 7 8 9 import numpy as npclosing_prices = np.loadtxt( '../../data/aapl.csv' , delimiter=',' , usecols=(6 ), unpack=True ) size = closing_prices.size sorted_prices = np.msort(closing_prices) median = (sorted_prices[int ((size - 1 ) / 2 )] + sorted_prices[int (size / 2 )]) / 2 print (median)median = np.median(closing_prices) print (median)
标准差 样本:S = [s1, s2, …, sn] 平均值:m = (s1+s2+…+sn)/n 离差:D = [d1, d2, …, dn], di = si-m 离差方:Q = [q1, q2, …, qn], qi = di2 总体方差:v = (q1+q2+…+qn)/n 总体标准差:s = sqrt(v),方均根 样本方差:v’ = (q1+q2+…+qn)/(n-1) 样本标准差:s’ = sqrt(v’),方均根
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import numpy as npclosing_prices = np.loadtxt( '../../data/aapl.csv' , delimiter=',' , usecols=(6 ), unpack=True ) mean = np.mean(closing_prices) devs = closing_prices - mean dsqs = devs ** 2 pvar = np.sum (dsqs) / dsqs.size pstd = np.sqrt(pvar) svar = np.sum (dsqs) / (dsqs.size - 1 ) sstd = np.sqrt(svar) print (pstd, sstd)pstd = np.std(closing_prices) sstd = np.std(closing_prices, ddof=1 ) print (pstd, sstd)
时间数据处理 案例:统计每个周一、周二、…、周五的收盘价的平均值,并放入一个数组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import datetime as dtimport numpy as npdef dmy2wday (dmy ): dmy = str (dmy, encoding='utf-8' ) date = dt.datetime.strptime(dmy, '%d-%m-%Y' ).date() wday = date.weekday() return wday wdays, closing_prices = np.loadtxt('../data/aapl.csv' , delimiter=',' , usecols=(1 , 6 ), unpack=True , converters={1 : dmy2wday}) ave_closing_prices = np.zeros(5 ) for wday in range (ave_closing_prices.size): ave_closing_prices[wday] = closing_prices[wdays == wday].mean() for wday, ave_closing_price in zip ( ['MON' , 'TUE' , 'WED' , 'THU' , 'FRI' ], ave_closing_prices): print (wday, np.round (ave_closing_price, 2 ))
数组的轴向汇总 案例:汇总每周的最高价,最低价,开盘价,收盘价。
1 2 3 4 5 6 def func (data ): pass np.apply_along_axis(func, axis, array)
沿着数组中所指定的轴向,调用处理函数,并将每次调用的返回值重新组织成数组返回。
移动均线 收盘价5日均线:从第五天开始,每天计算最近五天的收盘价的平均值所构成的一条线。
移动均线算法:
1 2 3 4 5 (a+b+c+d+e)/5 (b+c+d+e+f)/5 (c+d+e+f+g)/5 ... (f+g+h+i+j)/5
在K线图中绘制5日均线图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import datetime as dtimport numpy as npimport matplotlib.pyplot as mpimport matplotlib.dates as mddef dmy2ymd (dmy ): dmy = str (dmy, encoding='utf-8' ) date = dt.datetime.strptime(dmy, '%d-%m-%Y' ).date() ymd = date.strftime('%Y-%m-%d' ) return ymd dates, closing_prices = np.loadtxt('../data/aapl.csv' , delimiter=',' , usecols=(1 , 6 ), unpack=True , dtype='M8[D], f8' , converters={1 : dmy2ymd}) sma51 = np.zeros(closing_prices.size - 4 ) for i in range (sma51.size): sma51[i] = closing_prices[i:i + 5 ].mean() mp.figure('Simple Moving Average' , facecolor='lightgray' ) mp.title('Simple Moving Average' , fontsize=20 ) mp.xlabel('Date' , fontsize=14 ) mp.ylabel('Price' , fontsize=14 ) ax = mp.gca() ax.xaxis.set_major_locator(md.WeekdayLocator( byweekday=md.MO)) ax.xaxis.set_minor_locator(md.DayLocator()) ax.xaxis.set_major_formatter(md.DateFormatter('%d %b %Y' )) mp.tick_params(labelsize=10 ) mp.grid(linestyle=':' ) dates = dates.astype(md.datetime.datetime) mp.plot(dates, closing_prices, c='lightgray' , label='Closing Price' ) mp.plot(dates[4 :], sma51, c='orangered' , label='SMA-5(1)' ) mp.legend() mp.gcf().autofmt_xdate() mp.show()
卷积 激励函数:g(t)
单位激励下的响应函数:f(t)
绘制时间(t)与痛感(h)的函数关系图。
a = [1 2 3 4 5] (理解为某单位时间的击打力度序列)
b = [6 7 8] (理解为痛感系数序列)
1 2 3 4 5 6 7 8 9 10 11 12 13 c = numpy.convolve(a, b, 卷积类型) 40 61 82 - 有效卷积(valid) 19 40 61 82 67 - 同维卷积(same) 6 19 40 61 82 67 40 - 完全卷积(full) 0 0 1 2 3 4 5 0 0 8 7 6 8 7 6 8 7 6 8 7 6 8 7 6 8 7 6 8 7 6
5日移动均线序列可以直接使用卷积实现
1 2 a = [a, b, c, d, e, f, g, h, i, j] b = [1 /5 , 1 /5 , 1 /5 , 1 /5 , 1 /5 ]
使用卷积函数numpy.convolve(a, b, 卷积类型)实现5日均线
1 2 3 sma52 = np.convolve( closing_prices, np.ones(5 ) / 5 , 'valid' ) mp.plot(dates[4 :], sma52, c='limegreen' , alpha=0.5 , linewidth=6 , label='SMA-5(2)' )
使用卷积函数numpy.convolve(a, b, 卷积类型)实现10日均线
1 2 sma10 = np.convolve(closing_prices, np.ones(10 ) / 10 , 'valid' ) mp.plot(dates[9 :], sma10, c='dodgerblue' , label='SMA-10' )
使用卷积函数numpy.convolve(a, b, 卷积类型)实现加权5日均线
1 2 3 4 5 weights = np.exp(np.linspace(-1 , 0 , 5 )) weights /= weights.sum () ema5 = np.convolve(closing_prices, weights[::-1 ], 'valid' ) mp.plot(dates[4 :], sma52, c='limegreen' , alpha=0.5 , linewidth=6 , label='SMA-5' )
布林带 布林带由三条线组成:
中轨:移动平均线
上轨:中轨+2x5日收盘价标准差 (顶部的压力)
下轨:中轨-2x5日收盘价标准差 (底部的支撑力)
布林带收窄代表稳定的趋势,布林带张开代表有较大的波动空间的趋势。
绘制5日均线的布林带
1 2 3 4 5 6 7 8 9 10 11 12 13 14 weights = np.exp(np.linspace(-1 , 0 , 5 )) weights /= weights.sum () em5 = np.convolve(closing_prices, weights[::-1 ], 'valid' ) stds = np.zeros(em5.size) for i in range (stds.size): stds[i] = closing_prices[i:i + 5 ].std() stds *= 2 lowers = medios - stds uppers = medios + stds mp.plot(dates, closing_prices, c='lightgray' , label='Closing Price' ) mp.plot(dates[4 :], medios, c='dodgerblue' , label='Medio' ) mp.plot(dates[4 :], lowers, c='limegreen' , label='Lower' ) mp.plot(dates[4 :], uppers, c='orangered' , label='Upper' )