首先导入并检查你的numpy版本
import numpy
numpy.__version__
'1.14.3'
NumPy数组
NumPy数组指的是由同一类型元素(一般是数字)组成的多维数组。
基础知识
数组的维度、形状、大小
一维数组由一个中括号内的数字组成。
import numpy as np #这里的一个惯例是使用np作为numpy的别名
>>>a = np.array([1,2,3])
>>>a
array([1, 2, 3])
二维数组由多个一维数组组成
>>>b = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>>b
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
同理,n维数组由多个n-1维数组组成
>>>c = np.array([[[1,2,1],[1,3,2,]],[[2,2,2],[1,1,1]]])
>>>c
array([[[1, 2, 1],
[1, 3, 2]],
[[2, 2, 2],
[1, 1, 1]]])
查看数组的维度使用 np.ndim
>>>print('数组a的维度是:',a.ndim)
>>>print('数组b的维度是:',b.ndim)
>>>print('数组c的维度是:',c.ndim)
数组a的维度是: 1
数组b的维度是: 2
数组c的维度是: 3
np.shape :显示在每个维度里数组的大小,或者说数组的“形状”。如 n 行 m 列的矩阵,它的 shape 就是(n,m)。
>>>print('数组a的形状是:',a.shape)
>>>print('数组b的形状是:',b.shape)
>>>print('数组c的形状是:',c.shape)
数组a的形状是: (3,)
数组b的形状是: (3, 3)
数组c的形状是: (2, 2, 3)
np.size :数组中所有元素的总量,相当于数组的 shape 中所有元素的乘积,例如矩阵的元素总量为行与列的乘积。
>>>print('数组a的大小是:',a.size)
>>>print('数组b的大小是:',b.size)
>>>print('数组c的大小是:',c.size)
数组a的大小是: 3
数组b的大小是: 9
数组c的大小是: 12
数组的元素类型和存储大小
np.dtype :查看数组中元素的类型。创建数组时,可以指定dtype参数用于创建指定数据类型的数组
>>>a.dtype
dtype('int64')
>>>d = np.array([1.2, 2.3, 3.4], dtype = np.float)
>>>d
array([1.2, 2.3, 3.4])
np.itemsize :用于查看数组中元素占用的字节,例如,一个元素类型是float64的数组,其中的元素占用的字节大小是8(也就是64bit/8)
>>>d.itemsize
8
np.data :查看存储数组的真实内存地址
>>>d.data
创建数组
有很多种方法创建数组。
例如,你可以通过使用数组函数从一个python的列表或元组创建。数组元素的类型由原数据的类型推断得到。
>>>b = np.array([1.2, 3.5, 5.1])
>>>b.dtype
dtype('float64')
np.array创建数组时,会将多层嵌套的列表转换为多维数组。
>>>b = np.array([(1.5,2,3), (4,5,6)])
>>>b
array([[1.5, 2. , 3. ],
[4. , 5. , 6. ]])
创建数组时我们还可以指定数据类型
>>>c = np.array( [ [1,2], [3,4] ], dtype=complex )#指定数据类型为复数
>>>c
array([[1.+0.j, 2.+0.j],
[3.+0.j, 4.+0.j]])
我们经常遇到这样的情况,我们并不知道数组的元素,但是知道数组的大小。因此,NumPy提供了多个函数,用于创建有初始数值的占位数组,这样可以减少不必要的数组增长及运算成本。
zeros 函数创建包含全是0的数组, ones 函数创建全是1的数组, empty 函数创建一个随机数值数组,其中的数值由当时的内存状态决定。这些函数创建的数组的数据类型都是默认的float64.
>>>np.zeros( (3,4) )
array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
>>>np.ones( (2,3,4), dtype=np.int16 )
array([[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]],
[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]]], dtype=int16)
>>>np.empty( (2,3) )
array([[1.5, 2. , 3. ],
[4. , 5. , 6. ]])
为了生成连续的数值,NumPy提供了一个模拟 range 的函数,不同点是,numpy的range返回的是数组而不是列表
>>>np.arange( 10, 30, 5 ) # 三个参数分别代表起始值10,终止值30,步进5
array([10, 15, 20, 25])
>>>np.arange( 0, 2, 0.3 )
array([0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])
当 arange 使用浮点型作为参数时,因为浮点精度的有限性,不能预测创建的数组有多少个元素。在这种情况下,换成 linspace 函数可以更好地确定区间内到底需要产生多少个数组元素。
from numpy import pi
>>>np.linspace( 0, 2, 9 ) # 在[0,2]区间内生成9个值
array([0. , 0.25, 0.5 , 0.75, 1. , 1.25, 1.5 , 1.75, 2. ])
打印数组
当你在屏幕打印一个数组时,NumPy显示这个数组的方式和嵌套的列表是相似的。但遵守以下布局:
最后一维由左至右打印
倒数第二维从上到下打印
其余维都是从上到下打印,且通过空行分隔
如下所示,一维数组输出为一行、二维为矩阵、三维为矩阵列表。
>>>a = np.arange(6)
>>>a
array([0, 1, 2, 3, 4, 5])
>>>b = np.arange(12).reshape(4,3)
>>>a
array([0, 1, 2, 3, 4, 5])
>>>c = np.arange(24).reshape(2,3,4)
>>>c
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]]])
如果数组太大了,NumPy自动跳过中间的部分不显示,只显示两边。
>>>print(np.arange(10000))
[ 0 1 2 ... 9997 9998 9999]
>>>print(np.arange(10000).reshape(100,100))
[[ 0 1 2 ... 97 98 99]
[ 100 101 102 ... 197 198 199]
[ 200 201 202 ... 297 298 299]
...
[9700 9701 9702 ... 9797 9798 9799]
[9800 9801 9802 ... 9897 9898 9899]
[9900 9901 9902 ... 9997 9998 9999]]
如果你想强制输出所有数据,可以设置 set_printoptions 参数。
>>>np.set_printoptions(threshold=np.nan)
基本运算
数组中的算术运算一般是元素级的运算,运算结果会产生一个新的数组。
不同于很多矩阵语言,乘积运算操作 * 在NumPy中是元素级的运算。如果想要进行矩阵运算,可以使用 dot 函数或方法。
>>>A = np.array( [[1,1],[0,1]] )
>>>B = np.array( [[2,0],[3,4]] )
>>>A*B# 元素乘积
array([[2, 0],
[0, 4]])
>>>A.dot(B)# 矩阵运算
array([[5, 4],
[3, 4]])
>>>np.dot(A, B)# 另一种方式矩阵运算
array([[5, 4],
[3, 4]])
一些运算,例如 += 和 *= ,会内在的改变一个数组的值,而不是生成一个新的数组。
>>>a = np.ones((2,3), dtype=int)
>>>b = np.random.random((2,3))
>>>a *= 3
>>>a
array([[3, 3, 3],
[3, 3, 3]])
>>>b += a
>>>b
array([[3.69902298, 3.1334804 , 3.62673199],
[3.37038178, 3.74769131, 3.62235315]])
>>>a += b # b不会自动转换为整型
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in ()
----> 1 a += b # b不会自动转换为整型
TypeError: Cannot cast ufunc add output from dtype('float64') to dtype('int64') with casting rule 'same_kind'
当操作不同数据类型的数组时,最后输出的数组类型一般会与更普遍或更精准的数组相同(这种行为叫做 Upcasting)。
>>>a = np.ones(3, dtype=np.int32)
>>>b = np.linspace(0,pi,3)
>>>b.dtype.name
'float64'
>>>c = a+b
>>>c.dtype.name
'float64'
>>>d = np.exp(c*1j)
>>>d.dtype.name
'complex128'
许多一元运算,如计算数组中所有元素的总和,是属于 ndarray 类的方法。
>>>a = np.random.random((2,3))
>>>a
array([[0.85827711, 0.5385761 , 0.0843277 ],
[0.2609027 , 0.36414539, 0.12940627]])
>>>a.sum()
2.2356352707158513
>>>a.min()
0.08432769616897462
>>>a.max()
0.8582771053112916
默认状态下,这些运算会把数组视为一个数字列表而不关心它的shape。然而,可以指定axis参数针对哪一个维度进行运算。例如axis=0将针对每一个列进行运算。
>>>b = np.arange(12).reshape(3,4)
>>>b
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>>b.sum(axis=0)# 列相加
array([12, 15, 18, 21])
>>>b.min(axis=1) #行相加
array([0, 4, 8])
>>>b.cumsum(axis=1)#行累加
array([[ 0, 1, 3, 6],
[ 4, 9, 15, 22],
[ 8, 17, 27, 38]])
通用函数
NumPy提供一些熟悉的数学函数,例如sin, cos,和exp等。在NumPy中,这些函数称为“通用函数”, 这些运算是元素级的,生成一个数组作为结果。
>>>B = np.arange(3)
>>>B
array([0, 1, 2])
>>>np.exp(B)
array([1. , 2.71828183, 7.3890561 ])
>>>np.sqrt(B)
array([0. , 1. , 1.41421356])
>>>C = np.array([2., -1., 4.])
>>>np.add(B, C)
array([2., 0., 6.])
索引、切片和迭代
一维数组可以索引、切片和迭代,就像列表和其他python数据类型。
>>>a = np.arange(10)**3
>>>a[2]
8
>>>a[2:5]
array([ 8, 27, 64])
>>>a[:6:2] = -1000 #从0到6,每隔2个设为-1000
>>>a
array([-1000, 1, -1000, 27, -1000, 125, 216, 343, 512,
729])
>>>a[ : :-1] #翻转数组a
array([ 729, 512, 343, 216, 125, -1000, 27, -1000, 1,
-1000])
多维数组可以每个维度有一个索引值。这些索引值被逗号分开。
>>>def f(x,y):#定义一个函数用于生成数组
>>> return 10*x+y
>>>b = np.fromfunction(f,(5,4),dtype=int)#利用函数f生成数组,数组的形状是(5,4),数组中(x,y)的元素值等于 f(x,y)
>>>b
array([[ 0, 1, 2, 3],
[10, 11, 12, 13],
[20, 21, 22, 23],
[30, 31, 32, 33],
[40, 41, 42, 43]])
>>>b[2,3] #第2行,第3列
23
>>>b[0:5, 1] #等于b[ : ,1] ,第0-5行,第1列
array([ 1, 11, 21, 31, 41])
>>>b[1:3, : ] #1-3行,所有列
array([[10, 11, 12, 13],
[20, 21, 22, 23]])
当索引值的数量少于数组的维度时,其他的索引值默认为分号 :
>>>b[-1] #相当于b[-1,:]
array([40, 41, 42, 43])
b[i] 中的i代表i后面有足够多的:,用于表示其他维度的索引。你也可以使用点号 ... 来表示。
点号代表需要的足够多的列,用于使其他维度的索引值完整。例如,x是一个五维数组,那么
x[1,2,...] 相当于 x[1,2,:,:,:]
x[...,3] 相当于 x[:,:,:,:,3]
x[4,...,5,:] 相当于 x[4,:,:,5,:]
>>>c = np.array( [[[ 0, 1, 2], #构建一个三维数组
[ 10, 12, 13]],
[[100,101,102],
[110,112,113]]])
>>>c.shape
(2, 2, 3)
>>>c[1,...]
array([[100, 101, 102],
[110, 112, 113]])
>>>c[...,2]
array([[ 2, 13],
[102, 113]])
多维数组中的迭代:
>>>for row in b:
>>> print(row)
[0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]
但是,如果你想迭代输出数组中的每一个元素,你可以使用 flat 属性实现,这个属性生成一个可以迭代所有元素的迭代器。
>>>for element in b.flat:
>>> print(element)
0
1
2
3
10
11
12
13
20
21
22
23
30
31
32
33
40
41
42
43