Numpy学习——Numpy初探
Numpy&Numpy arrays
Numpy arrays
-
Python对象
高级数字对象,包含整数、浮点类型;
低成本的插入和添加数据以及快速查找功能。 -
Numpy提供:
多维数组支持;
贴近硬件底层(效率);
为科学计算设计(方便);
面向数组计算。
>>> import numpy as np
>>> a = np.array([0, 1, 2, 3])
>>> a
array([0, 1, 2, 3])
例如,一个array包含:
- 仿真和实验过程中离散时间的数值
- 通过测量装置记录信号内容,例如声波信号
- 图像的像素,灰度或颜色
- 再不同坐标系下测量的3D数据,核磁共振扫描
Numpy再数值处理上表现高效的性能
In [1]: L = range(1000)
In [2]: %timeit [i**2 for i in L]
1000 loops, best of 3: 403 us per loop
In [3]: a = np.arange(1000)
IN [4]: %timeit a**2
100000 loops, best of 3: 12.7 us per loop
可以看出执行同样的平方操作,numpy的速度明显更快
NumPy参考文档
Numpy Doc
也可以利用numpy自带的交互帮助,或者np.lookfor(’ ’ )
Import约定
导入numpy包常用的语法约定:
import numpy as np
创建arrays
手动构造arrays
- 1-D:
>>> a = np.array([0, 1, 2, 3])
>>> a
array([0, 1, 2, 3])
>>> a.ndim
1
>>> a.shape
(4,)
>>> len(a)
4
- 2-D, 3-D, ···
>>> b = np.array([[0, 1, 2], [3, 4, 5]]) # 2 x 3 array
>>> b
array([[0, 1, 2],
[3, 4, 5]])
>>> b.ndim
2
>>> b.shape
(2, 3)
>>> len(b) # returns the size of the first dimension
2
>>> c = np.array([[[1], [2]], [[3], [4]]])
>>> c
array([[[1],
[2]],
[[3],
[4]]])
>>> c.shape
(2, 2, 1)
函数创建arrays
实际上,我们几乎不一个一个输入
- 均匀分布
>>> a = np.arange(10) # 0 .. n-1 (!)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> b = np.arange(1, 9, 2) # start, end (exclusive), step
>>> b
array([1, 3, 5, 7])
>>> c = np.linspace(0, 1, 6) # start, end, num-points
>>> c
array([0., 0.2, 0.4, 0.6, 0.8, 1. ])
>>> d = np.linspace(0, 1, 5, endpoint=False)
>>> d
array([0. , 0.2, 0.4, 0.6, 0.8])
- 常见数组
>>> a = np.ones((3, 3)) # reminder: (3, 3) is a tuple
>>> a
array([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
>>> b = np.zeros((2, 2))
>>> b
array([[0., 0.],
[0., 0.]])
>>> c = np.eye(3)
>>> c
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
>>> d = np.diag(np.array([1, 2, 3, 4]))
>>> d
array([[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0],
[0, 0, 0, 4]])
- 随机数组
>>> a = np.random.rand(4) # uniform in [0, 1]
>>> a
array([ 0.95799151, 0.14222247, 0.08777354, 0.51887998])
>>> b = np.random.randn(4) # Gaussian
>>> b
array([ 0.37554699, -0.11425369, -0.47616538, 1.79664113])
>>> np.random.seed(1234) # Setting the random seed
基本数据类型(basic data types)
你可能会注意到,在一些例子中,被显示的数组元素后面尾随一个点(例如2.)。这是由于不同的数据类型所导致的:
>>> a = np.array([1, 2, 3])
>>> a.dtype
dtype('int64')
>>> b = np.array([1., 2., 3.])
>>> b.dtype
dtype('float')
不同的数据类型允许我们在内存中更紧凑的存储,但是多数时候我们只使用浮点数。值得注意的是,在以上的例子中,numpy自动从输入中检测数据类型。
你可以直接显示指定你想要的数据类型:
>>> c = np.array([1, 2, 3], dtype=float)
>>> c.dtype
dtype('float')
默认数据类型是浮点型
>>> a = np.ones((3, 3))
>>> a.dtype
dtype('float')
其他的数据类型:
关键字 | 类型 |
---|---|
complex | 复数 |
bool | 布尔 |
strings | 字符串 |
int32 int64 | 整数 |
uint32 uint64 | 无符号整数 |
可视化(visualization)
现在我们有了我们的第一个数据数组,我们要来将 它们可视化。
matpotlib是一个2D绘图包,我们可以import它的函数如下:
>>> import matplotlib.pyplot as plt # the tidy war
接下来使用
>>> plt.plot(x, y)
>>> plt.show()
- 1D绘图
>>> x = np.linspace(0, 3, 20)
>>> y = np.linspace(0, 9, 20)
>>> plt.plot(x, y) # line plot
>>> plt.plot(x, y, 'o') # dot plot
>>> plt.show()
- 2D绘图
>>> image = np.random.rand(30, 30)
>>> plt.imshow(image, cmap=plt.cm.hot)
>>> plt.colorbar()
>>> plt.show()
索引(indexing) &切片(slicing)
数组中的某一项可以像python其他序列(例如list)一样被直接索引:
>>> a = np.arange(10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a[0], a[2], a[-1]
(0, 2, 9)
索引从0开始,像其他的python序列。相反在matlab中索引从1开始。
支持python常用的反转序列方法:
>>> a[::-1]
array([9, 8, 7, 6, 5, 4, 3, 2, 1])
对于多维数组,索引是元组或者整数:
>>> a = np.diag(np.arange(3))
>>> a
array([[0, 0, 0],
[0, 1, 0],
[0, 0, 2]])
>>> a[1, 1]
1
>>> a[2, 1] = 10
>>> a
array([[ 0, 0, 0],
[ 0, 1, 0],
[ 0, 10, 2]])
>>> a[1]
array([0, 1, 0])
注意
在二维数组中,第一维度是行,第二是列
对于多维数组a,a[0]是通过取出所有未指定维度的元素
数组也可以像python其他的序列一样被切片:
>>> a = np.arange(10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a[2:9:3] # [start:end:step]
array([2, 5, 8])
注意,最后一个索引并不被包含:
>>> a[:4]
array([0, 1, 2, 3])
三个索引值都不是必须的:start默认值是0,end默认值是最后一位,step默认值是1:
>>> a[1:3]
array([1, 2])
>>> a[::2]
array([0, 2, 4, 6, 8])
>>> a[3:]
array([3, 4, 5, 6, 7, 8, 9])
关于numpy索引和切片的一个小的说明
也可以结合赋值和切片:
>>> a = np.arange(10)
>>> a[5:] = 10
>>> a
array([0, 1, 2, 3, 4, 10, 10, 10, 10, 10])
>>> b = np.arange(5)
>>> a[5:] = b[::-1]
>>> a
array([0, 1, 2, 3, 4, 4, 3, 2, 1, 0])
复制(copy) & 视图(view)
一个切片操作在原始数组上生成一个视图,这只是访问数据数组的一种方式。因此原始数组并没有在内存中拷贝,你可以使用np.may_share_memory()来检查是否有两个数组共享同一块内存块。注意,可能会有warning。
当你修改视图的时候,原始数组也会发生修改:
>>> a = np.arange(10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> b = a[::2]
>>> b
array([0, 2, 4, 6, 8])
>>> np.may_share_memory(a, b)
True
>>> b[0] = 12
>>> b
array([12, 2, 4, 6, 8])
>>> a # (!)
array([12, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a = np.arange(10)
>>> c = a[::2].copy() # force a copy
>>> c[0] = 12
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> np.may_share_memory(a, c)
False
乍一看,这种行为可能令人吃惊,但它可以节省内存和时间。
应用举例:
计算0~99之间的质数,
- 构造一个(100,)布尔数组is_prime, 填充成True:
>>> is_prime = np.ones((100,), dtype=bool)
- 去掉不是质数的0和1:
>>> is_prime[:2] = 0
- 对于每一个从2开始的整数j,划掉更高的倍数```
>>> N_max = int(np.sqrt(len(is_prime) - 1))
>>> for j in range(2, N_max + 1):
is_prime[2*j::j] = False
- 在上述操作以后,is_prime中的True就是我们要的质数,遍历即可。
花式索引(fancy indexing)
Numpy数组可以被索引通过切片,也可以通过布尔和整数数组(masks)。这种方法被称作fancy indexing。它生成copies而不是views。
使用布尔数组
>>> np.random.seed(3)
>>> a = np.random.randint(0, 21, 15)
>>> a
array([10, 3, 8, 0, 19, 10, 11, 9, 10, 6, 0, 20, 12, 7, 14])
>>> (a % 3 == 0)
array([False, True, False, True, False, False, False, True, False, True, True, False, True, False, False])
>>> mask = (a % 3 == 0)
>>> extract_from_a = a[mask]
>>> extract_from_a
array([3, 0, 9, 6, 0, 12])
在赋值一个新的值到子数组的时候,使用数组索引非常有用:
>>> a[a % 3 == 0] = -1
>>> a
array([10, -1, 8, -1, 19, 10, 11, -1, 10, -1, -1, 20, -1, 7, 14])
使用整数数组索引
>>> a = np.arange(0, 100, 10)
>>> a
array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90])
可以用一个整数数组索引,其中相同的索引重复几次:
>>> a[[2, 3, 2, 4, 2]] # note: [2, 3, 2, 4, 2] is a Python list
>>> a
array([20, 30, 20, 40, 20])
新的值可以被赋值通过这种索引:
>>> a[[9, 7]] = -100
>>> a
array([ 0, 10, 20, 30, 40, 50, 60, -100, 80, -100,])
当一个新的数组被整数数组索引创建的时候,新的数组有和整数数组同样的形状:
>>> a = np.arange(10)
>>> idx = np.array([[3, 4], [9, 7]])
>>> idx.shape
(2, 2)
>>> a[idx]
array([[3, 4],
[9, 7]])