成为华尔街金融巨鳄第一课:学会使用NumPy
一、为什么要使用numpy
import numpy as np # 导包
分析如下两个例子,numpy提供的方式将大大简便操作
例1:已知若干家跨国公司的市值(美金),将其转换为人民币
例2:已知购物车中的每件商品的价格与商品件数,求总金额
numpy提供了ndarray(多维数组)对象
创建ndarray: np.array(array_like)
数组与列表的区别:
数组:元素类型必须相同,大小不可修改 列表:元素类型可以不同,可以通过append添加元素
二、ndarray相关属性
import random
a = np.array(range(10))
属性
a.dtype #数组类型
dtype('int32')
a.size #数组大小
10
a = np.array([[1,2,3],[4,5,6]]) # 创建二维数组
a
array([[1, 2, 3],
[4, 5, 6]])
a.size
6
a.shape #数组的形状为2行3列
(2, 3)
a = a.T #数组转置(行变列,列边行)
a
array([[1, 4],
[2, 5],
[3, 6]])
a.ndim #查看尾数
2
三、数组的创建
方法一:直接用python列表创建
np.array([1,2,3,4,5])
array([1, 2, 3, 4, 5])
方法二:创建全为0或1的数组
# 愚蠢的列表创建方法
np.array([0]*10)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
# 机智的numpy创建方法
a = np.zeros(10)
a
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
# 注意事项
# 1.numpy绝大部分运算要使用小数运算,所以自动创建的为浮点类型的0
a.dtype
dtype('float64')
# 2.如果实在想创建整型,如下
a = np.zeros(10,dtype='int')
a
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
# 3.仿照上面的内容,创建10个元素全为1的数组
np.ones(10)
array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])
方法三:np.empty
np.empty(100)
array([1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1.])
注意事项:empty函数向内存申请空间,我们所看到的数值均为内存中残存的数值
方法四:类range方法创建:np.arange
# 创建从0到100的数组
np.arange(100)
array([ 0, 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, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99])
# 创建从2到100的数组(左闭右开)
np.arange(2,100)
array([ 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, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99])
# 创建从0到100,步长为2的数组
np.arange(0,100,2)
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32,
34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66,
68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98])
参数说明:
1.第一个参数为起始值,第二个参数为终了值,第三个参数为步长
2.三个参数均可以为浮点类型(python range无此功能)
例:
np.arange(1.2,100.6,1.5)
array([ 1.2, 2.7, 4.2, 5.7, 7.2, 8.7, 10.2, 11.7, 13.2,
14.7, 16.2, 17.7, 19.2, 20.7, 22.2, 23.7, 25.2, 26.7,
28.2, 29.7, 31.2, 32.7, 34.2, 35.7, 37.2, 38.7, 40.2,
41.7, 43.2, 44.7, 46.2, 47.7, 49.2, 50.7, 52.2, 53.7,
55.2, 56.7, 58.2, 59.7, 61.2, 62.7, 64.2, 65.7, 67.2,
68.7, 70.2, 71.7, 73.2, 74.7, 76.2, 77.7, 79.2, 80.7,
82.2, 83.7, 85.2, 86.7, 88.2, 89.7, 91.2, 92.7, 94.2,
95.7, 97.2, 98.7, 100.2])
方法五:numpy线性空间:np.linspace
#创建从0到10,并且分割为11份的数组
a = np.linspace(0,10,11)
a
array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.])
a.size
11
#创建从0到10.5,并且分割为150份的数组
a = np.linspace(0,10.5,50)
a
array([ 0. , 0.21428571, 0.42857143, 0.64285714, 0.85714286,
1.07142857, 1.28571429, 1.5 , 1.71428571, 1.92857143,
2.14285714, 2.35714286, 2.57142857, 2.78571429, 3. ,
3.21428571, 3.42857143, 3.64285714, 3.85714286, 4.07142857,
4.28571429, 4.5 , 4.71428571, 4.92857143, 5.14285714,
5.35714286, 5.57142857, 5.78571429, 6. , 6.21428571,
6.42857143, 6.64285714, 6.85714286, 7.07142857, 7.28571429,
7.5 , 7.71428571, 7.92857143, 8.14285714, 8.35714286,
8.57142857, 8.78571429, 9. , 9.21428571, 9.42857143,
9.64285714, 9.85714286, 10.07142857, 10.28571429, 10.5 ])
对比arange了解参数说明:
1.第一个参数为起始值,第二个参数为终了值,注意linspace为全闭区间,而arange为左闭右开区间
2.第三个参数为创建的数组大小(size)
3.三前两个参数均可以为浮点类型,第三个参数必须为整形
4.linspace的含义:将a到b分割为c个数,两两之间的差值相等
例:
在以下这个例子中,我们将向你展示如何使用linspace做出函数图像以便更好地理解这个函数,众所周知函数图像为连续的无穷点构成的图像,而计算机无法绘制出无穷点,因此我们可以以足够大的有穷代无穷
通过这个例子,你将会理解为什么区间需要用闭区间,以及分割的具体含义,理论上讲如果分割成无数个点就可以表示在数学上的一段数轴
x = np.linspace(-10,10,100000)
x
array([-10. , -9.9998, -9.9996, ..., 9.9996, 9.9998, 10. ])
# 绘制y=x**2,定义域为-10到10的图像
y = x**2
y
array([100. , 99.996 , 99.99200008, ..., 99.99200008,
99.996 , 100. ])
import matplotlib.pyplot as plt
plt.plot(x,y)
[<matplotlib.lines.Line2D at 0x192fc547848>]
方法六:生成单位矩阵
# 生成线性代数中的单位矩阵
np.eye(10)
array([[1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 1.]])
四、ndarray批量运算与索引切片
a = np.arange(0,10)
a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
b = np.arange(10,20)
b
array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
1、与标量进行运算
a+1
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
a*2
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
a/3
array([0. , 0.33333333, 0.66666667, 1. , 1.33333333,
1.66666667, 2. , 2.33333333, 2.66666667, 3. ])
2、与数组进行运算
# 对应元素相加
a+b
array([10, 12, 14, 16, 18, 20, 22, 24, 26, 28])
# 对应元素比大小,返回布尔值
a>b
array([False, False, False, False, False, False, False, False, False,
False])
3、索引与切片
# 一维数组的索引
a[1]
1
# 二维数组的索引
c = np.arange(15).reshape((3,5))
# reshape函数:重塑数组,将0到15的一维数组重塑为3行5列,注意参数为元组
c
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
# 以下两种写法均可
c[0][0]
0
c[0,0]
0
# 取出12这个数
c[2,2]
12
a = np.arange(15)
a
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
#一维数组的切片
a[0:4]
array([0, 1, 2, 3])
a[:4]
array([0, 1, 2, 3])
a[4:]
array([ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
# 对比列表理解一维数组的切片
# 使用方法和列表切片类似
a = np.arange(10)
b = list(range(10))
a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
c = a[0:4]
d = b[0:4]
c
array([0, 1, 2, 3])
d
[0, 1, 2, 3]
c[0]=20
d[0]=20
c
array([20, 1, 2, 3])
d
[20, 1, 2, 3]
a
array([20, 1, 2, 3, 4, 5, 6, 7, 8, 9])
b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
#切片注意事项1: 在对数组进行切片时进行的是浅拷贝,而列表切片是深拷贝,也就是上面所示修改切片后的c的元素会影响a的值
在使用numpy进行科学计算时,往往数值大,数量多,因此使用深拷贝会大大增加运行时间并且占用内存,因而在默认情况下一般都是浅拷贝,如果一定要使用深拷贝可以使用下面的copy函数
c = a[0:4].copy()
c
array([20, 1, 2, 3])
a
array([20, 1, 2, 3, 4, 5, 6, 7, 8, 9])
c[0]=0
c
array([0, 1, 2, 3])
a
array([20, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# 二维数组的切片
a = np.arange(15).reshape((3,5))
a
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
目标:切出
0,1
5,6
a[0:2,0:2]
array([[0, 1],
[5, 6]])
#切片注意事项2: a[m:n,x:y]指从第m行切到第n行,第x列切到第y列,注意索引从0开始,且任然是左闭右开,逗号左边是行右边是列
固a[0:2,0:2]指从行数取区间[0,2)的整数,列数取区间[0,2)的整数。
# 类似于列表切片,:前后不赋值默认从最前面开始取(取到最后)
a[1:,:3]
array([[ 5, 6, 7],
[10, 11, 12]])
4、布尔型索引
引入问题:选出给定数组中所有大于5的数
python给出的解决方案:
a = [random.randint(0,10) for i in range(20)]
a
[3, 7, 5, 5, 4, 5, 4, 9, 7, 5, 4, 7, 10, 7, 6, 8, 3, 10, 4, 4]
list(filter(lambda x : x>5,a))
[7, 9, 7, 7, 10, 7, 6, 8, 10]
numpy给出的解决方案:
a = np.array(a)
a
array([ 3, 7, 5, 5, 4, 5, 4, 9, 7, 5, 4, 7, 10, 7, 6, 8, 3,
10, 4, 4])
a[a>5]
array([ 7, 9, 7, 7, 10, 7, 6, 8, 10])
原理解释:
# 回忆numpy标量运算,a>5:# 所有元素与5比大小,返回布尔值
a>5
array([False, True, False, False, False, False, False, True, True,
False, False, True, True, True, True, True, False, True,
False, False])
# 了解布尔索引
# a[b]:b为与a长度一样的数组或列表,b中的元素均为布尔类型,a会返回True对应位置的元素
a = np.arange(4)
a
array([0, 1, 2, 3])
b = [True,False,True,False]
a[b]
array([0, 2])
a[[False,False,True,True]]
array([2, 3])
问题2:选出给定数组中所有大于5的偶数
a = [random.randint(0,10) for i in range(20)]
a = np.array(a)
a
array([ 0, 2, 8, 1, 1, 2, 2, 8, 9, 1, 10, 3, 0, 5, 3, 3, 4,
10, 4, 8])
b = a[a>5]
b
array([ 8, 8, 9, 10, 10, 8])
b[b%2==0]
array([ 8, 8, 10, 10, 8])
是否可以简化合并成一行?
尝试:
a[a>5][a%2==0]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-362-109e9a75f8d4> in <module>
----> 1 a[a>5][a%2==0]
IndexError: boolean index did not match indexed array along dimension 0; dimension is 6 but corresponding boolean dimension is 20
报错原因:
# 首先看下a%2==0的size
a%2==0
array([ True, True, True, False, False, True, True, True, False,
False, True, False, True, False, False, False, True, True,
True, True])
(a%2==0).size
20
# 再来看 a[a>5]的size
a[a>5]
array([ 8, 8, 9, 10, 10, 8])
a[a>5].size
6
显然两者size不等无法连续使用布尔索引,那是否有其他方案
a[(a>5) & a%2==0)]
array([ 8, 8, 10, 10, 8])
a[(a>5) and (a%2==0)]
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-376-fee222ad41de> in <module>
----> 1 a[(a>5) and (a%2==0)]
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
#注意事项:1.记得加括号,因为&运算级更高 2.不得使用and 3.取反是~
# 或运算 |
a[(a>5) | (a%2==0)]
array([ 0, 2, 8, 2, 2, 8, 9, 10, 0, 4, 10, 4, 8])
五、花式索引
引入问题:选出给定数组中的1,3,4,6,7号元素,组成新的二维数组
a = np.arange(20)
a
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19])
# 一维数组花式索引:a[list(m)]去取出数组a中列表m元素对应索引的元素
# 注意是中括号嵌套中括号,因为一般情况下,最外层中括号里面的逗号用以分割行列,如切片中的a[0:2,0:2]
a[[1,3,4,6,7]]
array([1, 3, 4, 6, 7])
# 二维数组花式索引
a = a.reshape(4,5)
a
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])
# 所谓花式索引就是将之前的所有索引方式搭配使用,只需记住“,”前面表示行,后面表示列
# 回顾普通索引 a[m,n]表示第m行第n列索引 a[m]表示第m行元素 如:
a[0]
array([0, 1, 2, 3, 4])
# 回顾切片索引
a[0:2,1:4]
array([[1, 2, 3],
[6, 7, 8]])
# 回顾布尔索引
a[[True,False,True,False]]
array([[ 0, 1, 2, 3, 4],
[10, 11, 12, 13, 14]])
a[a>2]
array([ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
# 搭配使用
# 普通索引与切片索引搭配
a[0,2:]
array([2, 3, 4])
# 普通索引与布尔索引搭配
a[0]>2
array([False, False, False, True, True])
a[0,a[0]>2]
array([3, 4])
# 一维花式索引与且切片索引搭配
a[[1,3],2:]
array([[ 7, 8, 9],
[17, 18, 19]])
#禁忌:禁止逗号两边同时使用花式索引
例如:取6,8,16,18这几个数字
a
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])
# 两边同时使用花式索引,会出现以下情况
a[[1,3],[1,3]]
array([ 6, 18])
# 只能像下面这么取
a[[1,3],:][:,[1,3]]
array([[ 6, 8],
[16, 18]])
六、numpy常函数
1.np.abs():取绝对值函数 对每个元素取绝对值
2.np.sqrt():开方函数 对每个元素开方
3.np.floor():向下取整
4.np.ceil():向上取整
5.np.round()/np.rint():四舍五入
6.np.trunc():向0取整
7.np.modf():返回两个数组,分割小数部分和整数部分
eg.
a = np.arange(-5.5,5.5)
a
array([-5.5, -4.5, -3.5, -2.5, -1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5])
x,y = np.modf(a)
print(x,y)
np.modf(a)
[-0.5 -0.5 -0.5 -0.5 -0.5 -0.5 0.5 0.5 0.5 0.5 0.5] [-5. -4. -3. -2. -1. -0. 0. 1. 2. 3. 4.]
(array([-0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5]),
array([-5., -4., -3., -2., -1., -0., 0., 1., 2., 3., 4.]))
#向数轴左边取整
np.floor(a)
array([-6., -5., -4., -3., -2., -1., 0., 1., 2., 3., 4.])
#向数轴右边取整
np.ceil(a)
array([-5., -4., -3., -2., -1., -0., 1., 2., 3., 4., 5.])
np.round(a)
array([-6., -4., -4., -2., -2., -0., 0., 2., 2., 4., 4.])
np.trunc(a)
array([-5., -4., -3., -2., -1., -0., 0., 1., 2., 3., 4.])
np.sqrt(a)
C:\Users\Lenovo\miniconda3\lib\site-packages\ipykernel_launcher.py:1: RuntimeWarning: invalid value encountered in sqrt
"""Entry point for launching an IPython kernel.
array([ nan, nan, nan, nan, nan,
nan, 0.70710678, 1.22474487, 1.58113883, 1.87082869,
2.12132034])
np.abs(a)
array([5.5, 4.5, 3.5, 2.5, 1.5, 0.5, 0.5, 1.5, 2.5, 3.5, 4.5])
补充——浮点数的特殊值:
nan(Not a Number):代表不等于任何浮点数 甚至不等于自己
inf : 无穷大,比任何值都大 但是等于自己
np.nan == np.nan
False
a = np.array([0,1,1,1,1])
a
array([0, 1, 1, 1, 1])
b = a/a
b
C:\Users\Lenovo\miniconda3\lib\site-packages\ipykernel_launcher.py:1: RuntimeWarning: invalid value encountered in true_divide
"""Entry point for launching an IPython kernel.
array([nan, 1., 1., 1., 1.])
# 如何判断是否存在nan?
b == np.nan
array([False, False, False, False, False])
# 显然上面这种方法不行
# numpy提供了np.isnan()函数用以判断nan类型
np.isnan(b)
array([ True, False, False, False, False])
# 练习:选出数组b里所有数字
b[~(np.isnan(b))]
array([1., 1., 1., 1.])
np.maximum/minimun(a,b,c,…)函数:取出对应元素的最大/小值并构成新的数组
a = np.array([3,5,7,6,3])
b = np.array([2,6,8,4,3])
np.maximum(a,b)
array([3, 6, 8, 6, 3])
np.minimum(a,b)
array([2, 5, 7, 4, 3])
七、numpy数学和统计方法
a = np.array([3,5,7,6,3])
a
array([3, 5, 7, 6, 3])
# 求和
a.sum()
24
# 求均值
a.mean()
4.8
# 求标准差
a.std()
1.6
# 求方差
a.var()
2.56
# 求最小值
a.min()
3
# 求最大值
a.max()
7
# 求最小值索引
a.argmin()
0
# 求最大值索引
a.argmax()
2
# 随机数生成
np.random.randint(0,10)
4
np.random.randint(0,10,5)
array([7, 1, 7, 9, 5])
a = np.random.randint(0,10,(5,4))
a
array([[9, 3, 3, 7],
[4, 8, 3, 0],
[8, 6, 1, 1],
[2, 3, 9, 1],
[5, 4, 5, 1]])
# 洗牌
np.random.shuffle(a)
a
array([[5, 4, 5, 1],
[8, 6, 1, 1],
[4, 8, 3, 0],
[9, 3, 3, 7],
[2, 3, 9, 1]])
# 随机从列表抽
np.random.choice([1,3,5,6],10)
array([3, 5, 6, 5, 5, 6, 6, 3, 1, 3])
python random里所有的函数都被np.random()重写了所有功能