用Python做科学计算(工具篇)——1.1. NumPy 数组对象[亲测有效]

Python (77) 2023-04-11 10:12

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说用Python做科学计算(工具篇)——1.1. 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

练习:使用函数创建数组

  • 与试验arangelinspaceoneszeroseyediag
  • 使用随机数创建不同类型的数组。
  • 在创建具有随机值的数组之前尝试设置种子。
  • 看看功能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() #显示图
用Python做科学计算(工具篇)——1.1. NumPy 数组对象[亲测有效]_https://bianchenghao6.com/blog_Python_第1张

  • 二维数组:
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()
用Python做科学计算(工具篇)——1.1. NumPy 数组对象[亲测有效]_https://bianchenghao6.com/blog_Python_第2张

三维图

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()
用Python做科学计算(工具篇)——1.1. NumPy 数组对象[亲测有效]_https://bianchenghao6.com/blog_Python_第3张

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()
用Python做科学计算(工具篇)——1.1. NumPy 数组对象[亲测有效]_https://bianchenghao6.com/blog_Python_第4张

练习:简单的可视化

  • 绘制一些简单的数组:作为时间函数的余弦和二维矩阵。
  • 尝试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
  • 对于多维aa[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 索引和切片的一个小插图

用Python做科学计算(工具篇)——1.1. NumPy 数组对象[亲测有效]_https://bianchenghao6.com/blog_Python_第5张

您还可以结合分配和切片:

>>> 
>>> 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,endstep: 从 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

这种行为乍一看可能令人惊讶……但它可以节省内存和时间。

工作示例:素数筛

用Python做科学计算(工具篇)——1.1. NumPy 数组对象[亲测有效]_https://bianchenghao6.com/blog_Python_第6张

用筛子计算 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]])

下图说明了各种花哨的索引语法

用Python做科学计算(工具篇)——1.1. NumPy 数组对象[亲测有效]_https://bianchenghao6.com/blog_Python_第7张

练习:花式索引

  • 再次,重现上图中显示的花哨索引。
  • 使用左侧的花哨索引和右侧的数组创建将值分配到数组中,例如通过将上图中的数组部分设置为零。

发表回复