python使用numpy求数组最大值(用Python做科学计算工具篇)
python使用numpy求数组最大值(用Python做科学计算工具篇)更接近硬件(效率)用于多维数组的 Python 扩展包高级数字对象:整型、浮点型容器:列表(无成本的插入和追加)、字典(快速查找)NumPy提供:
目录
- 什么是 numpy 和 NumPy 数组?
- 创建数组
- 基本数据类型
- 基本可视化
- 索引和切片
- 副本和查看
- 花式索引
1.1.1. 什么是 NumPy 和 NumPy 数组?
NumPy 数组
Python对象: |
高级数字对象:整型、浮点型 容器:列表(无成本的插入和追加)、字典(快速查找) |
NumPy提供: |
用于多维数组的 Python 扩展包 更接近硬件(效率) 专为科学计算而设计(方便) 也称为面向矩阵的计算 |
>>>
>>> import numpy as np
>>> a = np.array([0 1 2 3])
>>> a array([0 1 2 3])
例如,一个包含以下内容的数组:
- 离散时间步长的实验/模拟值
- 测量设备记录的信号,例如声波
- 图像的像素,灰度或颜色
- 在不同 XYZ 位置测量的 3-D 数据,例如 MRI 扫描
- …
为什么有用:提供快速数值运算的内存高效容器。
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 参考文档
- 在网络上:https : //numpy.org/doc/
- 互动帮助:
In [5]: np.array?
String Form:<built-in function array> Docstring: array(object dtype=None copy=True order=None subok=False ndmin=0 ...
- 寻找东西:
>>>
>>> np.lookfor('create array') Search results for 'create array' --------------------------------- numpy.array Create an array. numpy.memmap Create a memory-map to an array stored in a *binary* file on disk.
In [6]: np.con*?
np.concatenate
np.conj
np.conjugate
np.convolve
导入约定
导入 numpy 的推荐约定是:
>>>
>>> import numpy as np
1.1.2. 创建数组
手动构建数组
- 一维:
>>>
>>> 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)
练习:简单数组
- 创建一个简单的二维数组。首先,重做上面的例子。然后创建您自己的:如何在第一行倒数奇数,在第二行倒数偶数?
- 在这些数组上使用函数len() numpy.shape()。它们之间的关系如何?以及ndim数组的属性?
用于创建数组的函数
在实际中,我们不可能一个一个地手动输入数组元素......
- 均匀分布的:
>>>
>>> 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]])
- np.random:随机数(Mersenne Twister PRNG):
>>>
>>> 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.37544699 -0.11425369 -0.47616538 1.79664113])
>>> np.random.seed(1234) # Setting the random seed
练习:使用函数创建数组
- 与试验arange,linspace,ones,zeros,eye和 diag。
- 使用随机数创建不同类型的数组。
- 在创建具有随机值的数组之前尝试设置种子。
- 看看功能np.empty。它有什么作用?这什么时候有用?
1.1.3. 基本数据类型
大家可能已经注意到,在某些情况下,数组元素以尾随点显示(例如2.vs 2)。这是由于使用的数据类型不同:
>>>
>>> a = np.array([1 2 3])
>>> a.dtype dtype('int64')
>>> b = np.array([1. 2. 3.])
>>> b.dtype dtype('float64')
不同的数据类型允许我们在内存中更紧凑地存储数据,但大多数时候我们只是使用浮点数。请注意,在上面的示例中,NumPy 会自动检测输入中的数据类型。
你可以明确指定所需的数据类型:
>>>
>>> c = np.array([1 2 3] dtype=float)
>>> c.dtype dtype('float64')
默认的数据类型是浮点型:
>>>
>>> a = np.ones((3 3))
>>> a.dtype dtype('float64')
还有其他类型:
复杂的: |
>>> >>> d = np.array([1 2j 3 4j 5 6*1j]) >>> d.dtype dtype('complex128') |
布尔: |
>>> >>> e = np.array([True False False True]) >>> e.dtype dtype('bool') |
字符串: |
>>> >>> f = np.array(['Bonjour' 'Hello' 'Hallo']) >>> f.dtype # <--- strings containing max. 7 letters dtype('S7') |
更多的: |
int32 int64 uint32 uint64 |
1.1.4. 基本可视化
现在我们有了第一个数据数组,我们将把它们可视化。
首先启动Spyder:
>>>
>>> %matplotlib
或者,从笔记本中,在笔记本中启用绘图:
>>>
>>> %matplotlib inline
绘图显示在笔记本中而不是在新窗口中。
- 一维绘图:
>>>
import numpy as np
import matplotlib.pyplot as plt
#X轴,Y轴数据
x = np.arange(0 7)
y = [0.3 0.4 2 5 3 4.5 4]
plt.figure(figsize=(8 4)) #创建绘图对象
plt.plot(x y ":ro" linewidth=1) #在当前绘图对象绘图(X轴,Y轴,蓝色虚线,线宽度)
plt.xlabel("Time(s)") #X轴标签
plt.ylabel("Volt") #Y轴标签
plt.title("Line plot") #图标题
plt.grid(True) #添加网格
plt.show() #显示图
- 二维数组:
from matplotlib import pyplot as mpl
import numpy as np data=np.clip(np.random.randn(5 5) -1 1) #生成随机数据 5行5列 最大值1 最小值-1
fig = plt.figure() # 第一个子图 按照默认配置
ax = fig.add_subplot(221) ax.imshow(data) # 第二个子图 使用自定义的colormap
ax = fig.add_subplot(222)
cmap=mpl.cm.cool #可以使用自定义的colormap
ax.imshow(data cmap=cmap) # 第三个子图增加一个colorbar
ax = fig.add_subplot(223)
cmap=mpl.cm.hot #可以使用自定义的colormap
im=ax.imshow(data cmap=cmap)
plt.colorbar(im) ## 第四个子图可以调整colorbar
ax = fig.add_subplot(224)
cmap = mpl.cm.winter
im=ax.imshow(data cmap=cmap)
plt.colorbar(im cmap=cmap ticks=[-1 0 1]) plt.show()
三维图
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = Axes3D(fig)
X = np.arange(-4 4 0.25)
Y = np.arange(-4 4 0.25)
X Y = np.meshgrid(X Y)
R = np.sqrt(X**2 Y**2)
Z = np.sin(R)
ax.plot_surface(X Y Z rstride=1 cstride=1 cmap='hot')
plt.show()
import numpy as np
import matplotlib.pyplot as plt
n = 8
X Y = np.mgrid[0:n 0:n]
plt.quiver(X Y)
plt.show()
练习:简单的可视化
- 绘制一些简单的数组:作为时间函数的余弦和二维矩阵。
- 尝试gray在 2D 矩阵上使用颜色图。
1.1.5. 索引和切片
可以像其他 Python 序列(例如列表)一样访问和分配数组的项:
>>>
>>> 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 序列(和 C/C )一样。相比之下,在 Fortran 或 Matlab 中,索引从 1 开始。
支持用于逆序列的常用 Python 语法:
>>>
>>> a[::-1]
array([9 8 7 6 5 4 3 2 1 0])
对于多维数组,索引是整数元组:
>>>
>>> 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 # 赋值第三行第二列元素为10
>>> a array([[ 0 0 0] [ 0 1 0] [ 0 10 2]])
>>> a[1] array([0 1 0])
笔记
- 在 2D 中,第一个维度对应rows,第二个维度对应columns。
- 对于多维a,a[0]通过获取未指定维度中的所有元素来解释。
切片:数组,像其他 Python 序列一样也可以切片:
>>>
>>> a = np.arange(10)
>>> a array([0 1 2 3 4 5 6 7 8 9])
In [15]:a[2:10:2] # [start:end:step]
Out[15]: array([2 4 6 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])
练习:索引和切片
- 尝试不同风格的切片,使用start end和 step: 从 linspace 开始,尝试获得向后计数的奇数和向前计数的偶数。
- 重现上图中的切片。你可以使用以下表达式来创建数组:
>>>
>>> np.arange(6) np.arange(0 51 10)[: np.newaxis]
array([[ 0 1 2 3 4 5] [10 11 12 13 14 15] [20 21 22 23 24 25] [30 31 32 33 34 35] [40 41 42 43 44 45] [50 51 52 53 54 55]])
练习:数组创建
创建以下数组(具有正确的数据类型):
[[1 1 1 1] [1 1 1 1] [1 1 1 2] [1 6 1 1]] [[0. 0. 0. 0. 0.] [2. 0. 0. 0. 0.] [0. 3. 0. 0. 0.] [0. 0. 4. 0. 0.] [0. 0. 0. 5. 0.] [0. 0. 0. 0. 6.]]
课程标准:每人 3 个陈述
提示:可以像访问列表一样访问单个数组元素,例如a[1]或。a[1 2]
提示:检查 .doc 的文档字符串diag。
练习:用于创建数组的平铺
浏览 的文档np.tile,并使用此函数构造数组:
[[4 3 4 3 4 3] [2 1 2 1 2 1] [4 3 4 3 4 3] [2 1 2 1 2 1]]
1.1.6. 复制和查看
切片操作在原始数组上创建查看,这只是访问数组数据的一种方式。因此原始数组不会复制到内存中。你可以使用np.may_share_memory()检查两个数组是否共享同一个内存块。但是请注意,这使用了启发式方法,可能会误报。
修改查看时,原始数组也被修改:
>>>
>>> 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
- 对于j从 2 开始的每个整数,划掉其更高的倍数:
>>>
>>> N_max = int(np.sqrt(len(is_prime) - 1))
>>> for j in range(2 N_max 1): ... is_prime[2*j::j] = False
- 浏览help(np.nonzero)并打印质数
- 跟进:
- 将上面的代码移动到一个名为的脚本文件中 prime_sieve.py
- 运行它以检查它是否有效
- 使用Eratosthenes 筛中建议的优化:
- 跳过j那些已经知道不是素数的
- 第一个划掉的数字是
1.1.7. 花式索引
NumPy 数组可以用切片索引,也可以用布尔或整数数组(掩码)索引。这种方法称为花式索引。它创建副本而不是查看。
使用布尔掩码
>>>
>>> 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] # or a[a%3==0]
>>> extract_from_a # extract a sub-array with the mask 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 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]])
下图说明了各种花哨的索引语法
练习:花式索引
- 再次,重现上图中显示的花哨索引。
- 使用左侧的花哨索引和右侧的数组创建将值分配到数组中,例如通过将上图中的数组部分设置为零。