Day28: NumPy(Numerical Python)

本文参考:

https://www.runoob.com/numpy/numpy-tutorial.html

https://gitbook.cn/m/mazi/columns/5e37978dec8d9033cf916b5d/topics/5e3bceadec8d9033cf924665


 

  • NumPy 是一个运行速度非常快的数学库,主要用于数组计算,包含:
  1. 一个强大的N维数组对象 ndarray
  2. 广播功能函数
  3. 整合 C/C++/Fortran 代码的工具
  4. 线性代数、傅里叶变换、随机数生成等功能

 

如果不会用matlab,那么就可以不用学了,用Numpy+SciPy+ Matplotlib替代,在数据科学或者机器学习中被广泛使用。下面先看numpy.

  • SciPy 是一个开源的 Python 算法库和数学工具包。

SciPy 包含的模块有最优化、线性代数、积分、插值、特殊函数、快速傅里叶变换、信号处理和图像处理、常微分方程求解和其他科学与工程中常用的计算。

  • Matplotlib 是 Python 编程语言及其数值数学扩展包 NumPy 的可视化操作界面。

它为利用通用的图形用户界面工具包,如 Tkinter, wxPython, Qt 或 GTK+ 向应用程序嵌入式绘图提供了应用程序接口(API)。

NumPy安装

pip install numpy scipy matplotlib

验证:

>>> from numpy import *
>>> eye(5) # 生成对角矩阵
array([[1., 0., 0., 0., 0.],
       [0., 1., 0., 0., 0.],
       [0., 0., 1., 0., 0.],
       [0., 0., 0., 1., 0.],
       [0., 0., 0., 0., 1.]])
>>>

NumPy Ndarray 对象

N 维数组对象 ndarray,它是一系列同类型数据的集合,以 0 下标为开始进行集合中元素的索引。

  • 多维数组
  • 存放同类型元素
  • 每个元素在内存中都有相同存储大小的区域

 

 

 创建一个ndarry的函数原型:

numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)

参数说明:

名称描述
object 数组或嵌套的数列
dtype 数组元素的数据类型,可选
copy 对象是否需要复制,可选
order 创建数组的样式,C为行方向,F为列方向,A为任意方向(默认)
subok 默认返回一个与基类类型一致的数组
ndmin 指定生成数组的最小维度

创建数组:

复制代码
import numpy as np
a = np.array([1,2,3])  
print(a)
b = np.array([[1,2],[3,4]])  
print(b)

output:
[1 2 3]
[[1 2]
 [3 4]]
复制代码

numpy 数据类型

  • numpy 支持的数据类型比 Python 内置的类型要多很多
  • numpy 的数值类型实际上是 dtype 对象的实例,并对应唯一的字符
名称描述
bool_ 布尔型数据类型(True 或者 False)
int_ 默认的整数类型(类似于 C 语言中的 long,int32 或 int64)
intc 与 C 的 int 类型一样,一般是 int32 或 int 64
intp 用于索引的整数类型(类似于 C 的 ssize_t,一般情况下仍然是 int32 或 int64)
int8 字节(-128 to 127)
int16 整数(-32768 to 32767)
int32 整数(-2147483648 to 2147483647)
int64 整数(-9223372036854775808 to 9223372036854775807)
uint8 无符号整数(0 to 255)
uint16 无符号整数(0 to 65535)
uint32 无符号整数(0 to 4294967295)
uint64 无符号整数(0 to 18446744073709551615)
float_ float64 类型的简写
float16 半精度浮点数,包括:1 个符号位,5 个指数位,10 个尾数位
float32 单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位
float64 双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位
complex_ complex128 类型的简写,即 128 位复数
complex64 复数,表示双 32 位浮点数(实数部分和虚数部分)
complex128 复数,表示双 64 位浮点数(实数部分和虚数部分)

数据类型对象(numpy.dtype 类的实例)用来描述与数组对应的内存区域是如何使用.

创建dtype 对象函数原型:

numpy.dtype(object, align, copy)
  • object - 要转换为的数据类型对象
  • align - 如果为 true,填充字段使其类似 C 的结构体。
  • copy - 复制 dtype 对象 ,如果为 false,则是对内置数据类型对象的引用
复制代码
# 使用标量类型
dt = np.dtype(np.int32)
print(dt)
# int8, int16, int32, int64 四种数据类型可以使用字符串 'i1', 'i2','i4','i8' 代替
dt = np.dtype('i8')
print(dt)
# 字节顺序标注
dt = np.dtype('<i4') #  < 意味着小端法(最小值存储在最小的地址,即低位组放在最前面)。> 意味着大端法(最重要的字节存储在最小的地址,即高位组放在最前面)。
print(dt)

output:
int32
int64
int32
复制代码

下面实例展示结构化数据类型的使用,类型字段对应的实际类型将被创建。

复制代码
# 首先创建结构化数据类型
dt = np.dtype([('age',np.int8)]) 
print(dt)

# 将数据类型应用于 ndarray 对象
dt = np.dtype([('age',np.int8)]) 
a = np.array([(10,),(20,),(30,)], dtype = dt) 
print(a)

# 类型字段名可以用于存取实际的 age 列
dt = np.dtype([('age',np.int8)]) 
a = np.array([(10,),(20,),(30,)], dtype = dt) 
print(a['age'])

# 结构化数据类型 student,包含字符串字段 name,整数字段 age,及浮点字段 marks,并将这个 dtype 应用到 ndarray 对象。
student = np.dtype([('name','S20'), ('age', 'i1'), ('marks', 'f4')]) 
print(student)
a = np.array([('abc', 21, 50),('xyz', 18, 75)], dtype = student) 
print(a)

output:
[('age', 'i1')]
[(10,) (20,) (30,)]
[10 20 30]
[('name', 'S20'), ('age', 'i1'), ('marks', '<f4')]
[(b'abc', 21, 50.) (b'xyz', 18, 75.)]
复制代码

结构化数据类型就是   类型字段  对应 实际类型,其实很好理解,我希望数据有方便地别称来表示他在我的使用中的意义(类型字段),同时在计算机中他需要固定的类型去存储和做各种计算(实际类型)。

NumPy 数组的一些基本属性

比较重要 ndarray 对象属性有:

属性说明
ndarray.ndim 秩,即轴的数量或维度的数量
ndarray.shape 数组的维度,对于矩阵,n 行 m 列
ndarray.size 数组元素的总个数,相当于 .shape 中 n*m 的值
ndarray.dtype ndarray 对象的元素类型
ndarray.itemsize ndarray 对象中每个元素的大小,以字节为单位,一个字节8个bit
ndarray.flags ndarray 对象的内存信息
ndarray.real ndarray元素的实部
ndarray.imag ndarray 元素的虚部
ndarray.data 包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。
  • NumPy 也提供了 reshape 函数来调整数组大小。
复制代码
a = np.arange(24)  
print (a.ndim)             # a 现只有一个维度
print(a)
# 现在调整其大小
b = a.reshape(2,4,3)  # b 现在拥有三个维度
print (b.ndim)
print(b)

output:
1
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
3
[[[ 0  1  2]
  [ 3  4  5]
  [ 6  7  8]
  [ 9 10 11]]

 [[12 13 14]
  [15 16 17]
  [18 19 20]
  [21 22 23]]]
复制代码
  • ndarray.shape 也可以用于调整数组大小。
复制代码
a = np.array([[1,2,3],[4,5,6]])  
print(a)
print (a.shape)
a.shape =  (3,2) 
print(a)

output:
[[1 2 3]
 [4 5 6]]

(2, 3)

[[1 2]
 [3 4]
 [5 6]]
复制代码
  • 内存信息长森么样
复制代码
a = np.array([1,2,3,4,5])  
print (a.flags)

output:
  C_CONTIGUOUS : True
  F_CONTIGUOUS : True
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  WRITEBACKIFCOPY : False
  UPDATEIFCOPY : False
复制代码

NumPy 创建数组

创建初始化数组

上面说过创建数组的原语,用底层 ndarray 构造器来创建,但除此之外,python还提供了很多的方法:

1)numpy.empty
numpy.empty(shape, dtype = float, order = 'C')
  • 用来创建一个指定形状(shape)、数据类型(dtype)且未初始化的数组
  • order有"C"和"F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序。'C' 用于 C 的行数组,或者 'F' 用于 FORTRAN 的列数组
复制代码
import numpy as np 
x = np.empty([3,2], dtype = int,order = 'F') 
print (x)

y = np.empty([3,2], dtype = int,order = 'C') 
print (x)

output:
[[25775744192           0]
 [ 6445641960           0]
 [          0           0]]
[[25775744192           0]
 [ 6445641960           0]
 [          0           0]]
复制代码
  • 上面输出的随机值是因为数组未初始化,所以 emmm ... np.empty()
2)numpy.zeros
numpy.zeros(shape, dtype = float, order = 'C')

和empty不同的是,数据以0来填充

3)numpy.ones
numpy.ones(shape, dtype = None, order = 'C')

数据以1来填充

从已有的数组来创建数组

4)numpy.asarray
numpy.asarray(a, dtype = None, order = None)
  • a, 任意形式的输入参数,可以是,列表, 列表的元组, 元组, 元组的元组, 元组的列表,多维数组
复制代码
import numpy as np 
 
x =  [1,2,3] 
a = np.asarray(x)  
print (a)

x =  (1,2,3) 
a = np.asarray(x)  
print (a)

x =  [(1,2,3),(4,5)] 
a = np.asarray(x)  
print (a)

x =  [1,2,3] 
a = np.asarray(x, dtype =  float)  
print (a)

output:
[1 2 3]
[1 2 3]
[(1, 2, 3) (4, 5)]
[1. 2. 3.]
example
复制代码
5)numpy.frombuffer
  • 用于实现动态数组。
  • 接受 buffer 输入参数,以流的形式读入转化成 ndarray 对象:
numpy.frombuffer(buffer, dtype = float, count = -1, offset = 0)
参数描述
buffer 可以是任意对象,以流的形式读入。
dtype 返回数组的数据类型,可选
count 读取的数据数量,默认为-1,读取所有数据。
offset 读取的起始位置,默认为0。

python3栗子:

import numpy as np 
 
s =  b'Hello World' 
a = np.frombuffer(s, dtype =  'S1')  
print (a)

output:
[b'H' b'e' b'l' b'l' b'o' b' ' b'W' b'o' b'r' b'l' b'd']
6)numpy.fromiter

iter,想到了什么,可迭代对象。从可迭代对象中建立 ndarray 对象,返回一维数组

numpy.fromiter(iterable, dtype, count=-1)

栗子:

复制代码
import numpy as np 
 
# 使用 range 函数创建列表对象  
list=range(5)
it=iter(list)
 
# 使用迭代器创建 ndarray 
x=np.fromiter(it, dtype=int)
print(x)

output:
[0 1 2 3 4]
复制代码

从数值范围创建数组

7)numpy.arange
numpy.arange(start, stop, step, dtype)

numpy 包中的使用 arange 函数创建数值范围并返回 ndarray 对象:

参数说明:

参数描述
start 起始值,默认为0
stop 终止值(不包含)
step 步长,默认为1
dtype 返回ndarray的数据类型,如果没有提供,则会使用输入数据的类型。
复制代码
import numpy as np
# 生成0-4一维数组
x = np.arange(5)  
print (x)

# 设置了起始值、终止值及步长
x = np.arange(10,20,2)  
print (x)

output:
[0 1 2 3 4]
[10 12 14 16 18]
复制代码
8)numpy.linspace

创建一个一维数组,数组是一个等差数列构成的,格式如下:

np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)

参数说明:

参数描述
start 序列的起始值
stop 序列的终止值,如果endpointtrue,该值包含于数列中
num 要生成的等步长的样本数量,默认为50
endpoint 该值为 true 时,数列中包含stop值,反之不包含,默认是True。
retstep 如果为 True 时,生成的数组中会显示间距,反之不显示。
dtype ndarray 的数据类型
  • 没有地方设置步长哦,由起始、终止、个数决定
复制代码
import numpy as np
a = np.linspace(1,10,10)
print(a)

# 元素全部是1的等差数列
a = np.linspace(1,1,10)
print(a)

# 将 endpoint 设为 false,即不包含终止值
a = np.linspace(10, 20,  5, endpoint =  False)  
print(a)


# 显示间距
a = np.linspace(10, 20,  5, endpoint =  False,retstep= True)
print(a)

output:
[ 1.  2.  3.  4.  5.  6.  7.  8.  9. 10.]
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
[10. 12. 14. 16. 18.]
(array([10., 12., 14., 16., 18.]), 2.0)
复制代码
9)numpy.logspace

用于创建一个于等比数列。格式如下:

np.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)
参数描述
start 序列的起始值为:base ** start
stop 序列的终止值为:base ** stop。如果endpointtrue,该值包含于数列中
num 要生成的等步长的样本数量,默认为50
endpoint 该值为 true 时,数列中中包含stop值,反之不包含,默认是True。
base 对数 log 的底数。
dtype ndarray 的数据类型
  • base 参数意思是取对数的时候 log 的下标。默认值10
复制代码
import numpy as np
# 默认底数是 10
a = np.logspace(1.0,  2.0, num =  10)  
print (a)

# 底数设置为2
a = np.logspace(0,9,10,base=2)
print (a)

output:
[ 10.          12.91549665  16.68100537  21.5443469   27.82559402
  35.93813664  46.41588834  59.94842503  77.42636827 100.        ]
[  1.   2.   4.   8.  16.  32.  64. 128. 256. 512.]
复制代码

NumPy 切片和索引

切片和索引

ndarray对象也可以像list对象一样,使用索引和切片操作来进行访问或者修改。

python有内置一个slice函数,设置 start, stop 及 step 参数,从原数组中切割出一个新数组。

复制代码
import numpy as np

a = np.arange(7)
s = slice(1,7,2)
print(a[s])
print(s)
a[s][2] = 7
print(a)

output:
[1 3 5]  # 这个是新数组
slice(1, 7, 2)
[0 1 2 3 4 7 6]
复制代码

切片:

复制代码
import numpy as np

a = np.arange(7)
b = a[1:7:2]
print(b)
print(a)
b[2] = 7
print(a)

output:
[1 3 5]
[0 1 2 3 4 5 6]
[0 1 2 3 4 7 6]
复制代码

这样操作的话,可见改变了b的值,相应的a的值也被改变了。

p.s. 

  • 通过冒号分隔切片参数 start:stop:step 来进行切片操作
  • 如果只放置一个参数,如 [2],将返回与该索引相对应的单个元素。
  • 如果为 [2:],表示从该索引开始以后的所有项都将被提取。
  • 如果使用了两个参数,如 [2:7],那么则提取两个索引(不包括停止索引)之间的项

小知识,多维数组同样可以使用切片啊😁

复制代码
import numpy as np
a = np.array([[1,2,3],[4,5,6],[8,9,10]])
print(a)
# 从某个索引处开始切割
print('从数组索引 a[1:] 处开始切割')
print(a[1:])

# 使用一个参数
print('使用一个参数a[2]')
print(a[2])

# 使用2个参数
print('使用2个参数a[0:2]')
print(a[0:2])


output:
[[ 1  2  3]
 [ 4  5  6]
 [ 8  9 10]]
从数组索引 a[1:] 处开始切割
[[ 4  5  6]
 [ 8  9 10]]
使用一个参数a[2]
[ 8  9 10]
使用2个参数a[0:2]
[[1 2 3]
 [4 5 6]]
复制代码

小知识,切片还可以用省略号来操作😁

如果在行(列)位置使用省略号,它将返回包含行(列)中元素的 ndarray。

复制代码
import numpy as np
a = np.array([[1,2,3],[4,5,6],[8,9,10]])
print(a)
# 返回第2行元素
print('返回第2行元素')
print(a[1,...])
# 返回第2列元素
print('返回第2列元素')
print(a[...,1])
# 返回第2列之后的所有元素
print('返回第2列之后的所有元素')
print(a[...,1:])

output:
[[ 1  2  3]
 [ 4  5  6]
 [ 8  9 10]]
返回第2行元素
[4 5 6]
返回第2列元素
[2 5 9]
返回第2列之后的所有元素
[[ 2  3]
 [ 5  6]
 [ 9 10]]
复制代码

上面大部分是关于切片的操作,来看一下在NumPy中,它有何表现:

NumPy 高级索引

除了之前看到的用整数和切片的索引外,数组可以由整数数组索引、布尔索引及花式索引三种方式:

1)整数数组索引
import numpy as np 
 
x = np.array([[1,2],[3,4],[5,6]]) 
y = x[[0,1,2],[0,1,0]]  # 看成匹配行和列  (0行,0列)+ (1行,1列)+ (2行,0列)
print (y)

output:
[1 4 5]

把单独的元素pick出来:

复制代码
import numpy as np 
 
x = np.array([[  0,  1,  2],[  3,  4,  5],[  6,  7,  8],[  9,  10,  11]])  
print ('我们的数组是:' )
print (x)
print ('\n')
rows = np.array([[0,0],[3,3]]) 
print('rows:\n',rows)
cols = np.array([[0,2],[0,2]]) 
print('cols:\n',cols)
y = x[rows,cols]  
print  ('这个数组的四个角元素是:(0行,0列)(0,2)(3,0)(3,2)')
print (y)

output:
我们的数组是:
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]


rows:
 [[0 0]
 [3 3]]
cols:
 [[0 2]
 [0 2]]
这个数组的四个角元素是:(0行,0列)(0,2)(3,0)(3,2)
[[ 0  2]
 [ 9 11]]
复制代码

返回的结果是ndarray 对象!

试试在ndarray 对象上使用索引和切片:

复制代码
import numpy as np 
 
x = np.array([[0,1,2],[3,4,5],[6,7,8],[9,10,11]])  
print ('数组是:' )
print (x)
print ('\n')

b = x[1:3, 1:3]
c = x[1:3,[1,2]]
d = x[...,1:]
print(b)  #(第1行,第1列) (1,2) (2,1),(2,2)
print ('\n')
print(c)  #(第1行,第1列) (1,2) (2,1),(2,2)
print ('\n')
print(d)  #(遍历所有行,遍历【1,2】列)

output:
数组是:
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]


[[4 5]
 [7 8]]


[[4 5]
 [7 8]]


[[ 1  2]
 [ 4  5]
 [ 7  8]
 [10 11]]
复制代码
2)布尔索引

布尔索引通过布尔运算(如:比较运算符)来获取符合指定条件的元素的数组。

复制代码
# 布尔索引
# 获取大于 5 的元素:
import numpy as np

x = np.array([[0,1,2],[3,4,5],[6,7,8],[9,10,11]])
print ('我们的数组是:')
print (x)
print ('\n')
print('x中大于5的元素是:')
print(x[x>5])

output:
我们的数组是:
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]


x中大于5的元素是:
[ 6  7  8  9 10 11]
复制代码

用来过滤元素:

复制代码
import numpy as np 
 
a = np.array([np.nan,  1,2,np.nan,3,4,5]) # np.nan是一个float类型的数据 None是一个NoneType类型,nan 不是一个数
print(a) 
print(a[~np.isnan(a)])# 过滤nan

b = np.array([1,  2+6j,  5,  3.5+5j])  
print(b)
print (b[np.iscomplex(b)]) # 过滤实数or复数

output:
[nan  1.  2. nan  3.  4.  5.]
[1. 2. 3. 4. 5.]
[1. +0.j 2. +6.j 5. +0.j 3.5+5.j]
[2. +6.j 3.5+5.j]
复制代码
3)花式索引

花式索引根据索引数组的值作为目标数组的某个轴的下标来取值。

对于使用一维整型数组作为索引,如果目标是一维数组,那么索引的结果就是对应下标的行,

如果目标是二维数组,那么就是对应位置的元素。

花式索引跟切片不一样,它总是将数据复制到新数组中。

  • 注意:    [[]]
复制代码
# 花式索引
import numpy as np

x = np.arange(32).reshape((8,4))
print(x)
print('\n')
# 顺序索引数组
print(x[[4,2,1,7]])
print('\n')
# 倒序索引数组
print(x[[-4,-2,-1,-7]])
print('\n')
# 多个索引数组(要使用np.ix_)
print (x[np.ix_([1,5,7,2],[0,3,1,2])]) # (1,0)(1,3)(1,1)(1,2) ...

output:
[[ 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]]


[[16 17 18 19]
 [ 8  9 10 11]
 [ 4  5  6  7]
 [28 29 30 31]]


[[16 17 18 19]
 [24 25 26 27]
 [28 29 30 31]
 [ 4  5  6  7]]


[[ 4  7  5  6]
 [20 23 21 22]
 [28 31 29 30]
 [ 8 11  9 10]]
复制代码

NumPy 广播(Broadcast)

一般数组的运算,通常在相应的元素上进行。

和一般的数组乘法不同,array的乘需要shape相同:即满足 a.shape == b.shape,那么 a*b 的结果就是 a 与 b 数组对应位相乘。这要求维数相同,且各维度的长度相同。

复制代码
import numpy as np 
 
a = np.array([1,2,3,4]) 
b = np.array([10,20,30,40])
print(a,b)
c = a * b 
print (c)

output:
[1 2 3 4] [10 20 30 40]
[ 10  40  90 160]


---------------------------分割线---------------------------------
import numpy as np 
 
a = np.array([1,2,3,4]) 
b = np.array([10,20,30,40]).reshape((4,1))
print(a,b)
c = a * b 
print (c)

output:
[1 2 3 4]
 [[10]
 [20]
 [30]
 [40]]
[[ 10  20  30  40]
 [ 20  40  60  80]
 [ 30  60  90 120]
 [ 40  80 120 160]]
复制代码

为什么会这样?

当运算中的 2 个数组的形状不同时,numpy 将自动触发广播机制!!!

广播的规则:

  • 让所有输入数组都向其中形状最长的数组看齐,形状中不足的部分都通过在前面加 1 补齐。
  • 输出数组的形状是输入数组形状的各个维度上的最大值。
  • 如果输入数组的某个维度和输出数组的对应维度的长度相同或者其长度为 1 时,这个数组能够用来计算,否则出错。
  • 当输入数组的某个维度的长度为 1 时,沿着此维度运算时都用此维度上的第一组值。

简单理解:对两个数组,分别比较他们的每一个维度(若其中一个数组没有当前维度则忽略),满足:

  • 数组拥有相同形状。
  • 当前维度的值相等。
  • 当前维度的值有一个是 1。

若条件不满足,抛出 "ValueError: frames are not aligned" 异常。

NumPy 迭代数组

NumPy 迭代器对象 numpy.nditer 提供了一种灵活访问一个或者多个数组元素的方式。

复制代码
# NumPy 迭代器对象 numpy.nditer 提供了一种灵活访问一个或者多个数组元素的方式。
import numpy as np
a = np.arange(6).reshape(2,3)
print ('我们的数组是:')
print (a)
print ('\n')
print ('迭代输出元素:')
# 默认一行一行迭代访问
for x in np.nditer(a):
    print(x,end=',')
print ('\n') 
# 一列一列访问
for x in np.nditer(a.T.copy(order='C')):
    print (x, end="," )

output:
我们的数组是:
[[0 1 2]
 [3 4 5]]


迭代输出元素:
0,1,2,3,4,5,

0,3,1,4,2,5,
复制代码
  • for x in np.nditer(a, order='F'): Fortran order,即是列序优先;
  • for x in np.nditer(a, order='C'): C order,即是行序优先; 一行读完再一行

nditer 对象有另一个可选参数 op_flags。 默认情况下,nditer 将视待迭代遍历的数组为只读对象(read-only),为了在遍历数组的同时,实现对数组元素值得修改,必须指定 read-write 或者 write-only 的模式。

复制代码
import numpy as np
 
a = np.arange(0,60,5) 
a = a.reshape(3,4)  
print ('原始数组是:')
print (a)
print ('\n')
for x in np.nditer(a, op_flags=['readwrite']): 
    x[...]=2*x 
print ('修改后的数组是:')
print (a)

output:
原始数组是:
[[ 0  5 10 15]
 [20 25 30 35]
 [40 45 50 55]]


修改后的数组是:
[[  0  10  20  30]
 [ 40  50  60  70]
 [ 80  90 100 110]]
复制代码
  • nditer 对象有flags参数,接受以下值:
c_index ?可以跟踪 C 顺序的索引,一个元素一个元素给出
f_index ?可以跟踪 Fortran 顺序的索引,一个元素一个元素给出
multi-index ?每次迭代可以跟踪一种索引类型
external_loop 给出的值是具有多个值的一维数组,而不是零维数组,一维一维给出
  • 如果两个数组是可广播的,nditer 组合对象能够同时迭代它们。

 

上面说了这么多,打基础,下面就来玩转numpy

Numpy 数组操作

Numpy 中包含了一些函数用于处理数组,大概可分为以下几类:

  • 修改数组形状
  • 翻转数组
  • 修改数组维度
  • 连接数组
  • 分割数组
  • 数组元素的添加与删除

修改数组形状

函数描述
reshape 不改变数据的条件下修改形状
flat 数组元素迭代器
flatten 返回一份数组拷贝,对拷贝所做的修改不会影响原始数组,展开!!
ravel 返回展开数组
 numpy.reshape(arr, newshape, order='C')
  • arr:要修改形状的数组
  • newshape:整数或者整数数组,新的形状应当兼容原有形状
  • order:'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'k' -- 元素在内存中的出现顺序。
numpy.ndarray.flat数组元素迭代器
复制代码
import numpy as np
 
a = np.arange(9).reshape(3,3) 
print ('原始数组:')
for row in a:
    print (row)
 
#对数组中每个元素都进行处理,可以使用flat属性,该属性是一个数组元素迭代器:
print ('迭代后的数组:')
for element in a.flat:
    print (element)

output:
原始数组:
[0 1 2]
[3 4 5]
[6 7 8]
迭代后输出:
0
1
2
3
4
5
6
7
8
复制代码
numpy.ndarray.flatten
ndarray.flatten(order='C')
  • order:'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'K' -- 元素在内存中的出现顺序。
numpy.ravel

numpy.ravel() 展平的数组元素,

  • 顺序通常是"C风格",
  • 返回的是数组视图(view,有点类似 C/C++引用reference的意味),
  • 修改会影响原始数组。

翻转数组

函数描述
transpose 对换数组的维度
ndarray.T 和 self.transpose() 相同
rollaxis 向后滚动指定的轴
swapaxes 对换数组的两个轴
numpy.transpose

numpy.transpose 函数用于对换数组的维度,格式如下:

numpy.transpose(arr, axes) = arr.T
numpy.rollaxis

numpy.rollaxis 函数向后滚动特定的轴到一个特定位置,格式如下:

numpy.rollaxis(arr, axis, start)
  • arr:数组
  • axis:要向后滚动的轴,其它轴的相对位置不会改变
  • start:默认为零,表示完整的滚动。会滚动到特定位置。

 

轴  

  • 对numpy中轴的理解,:

  • 使用 a[6] 访问数组 a 中 index 为 6 的元素。从背后实现看,NumPy 会辅助一个轴,轴的取值为 0 到 11。
[ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18, 20, 22]

从概念上看,它的示意图如下所示:

 

  •  对于二维数组b = a.reshape(2,6): 其中a=np.arange(0,24,2)
[[ 0,  2,  4,  6,  8, 10],
       [12, 14, 16, 18, 20, 22]]

 

 

  •  shape,(12,) 和 (12,1),其实前者一个轴,后者两个轴,示意图分别如下。

 

 vs

 

 

 并且,通过上面几幅图看到,无论 shape 如何变化,变化的是视图,底下的 buffer 始终未变。

  • 三个轴,变化数组 a 的 shape 为 (2,3,2):
[[[ 0,  2],
        [ 4,  6],
        [ 8, 10]],

       [[12, 14],
        [16, 18],
        [20, 22]]]

 

 

  •  可以升4维吗?

    原始的一维数组 a 它一共有 12 个元素,后来,我们变化它为数组 c,shape 为 (2,3,2),那么如何升级为 4 维或任意维呢?

    4 维可以为:(1,2,3,2),示意图如下:

 

 

 

轴 i 索引取值只有 0,它被称为自由维度,可以任意插入到原数组的任意轴间。

比如,5 维可以为:(1,2,1,3,2):

 

 

 


复制代码
import numpy as np
 
# 创建了三维的 ndarray
a = np.arange(8).reshape(2,2,2)
 
print ('原数组:')
print (a)
print ('获取数组中一个值:')
print(np.where(a==6))   
print(a[1,1,0])  # 为 6
print ('\n')
 
 
# 将轴 2 滚动到轴 0(宽度到深度)
 
print ('调用 rollaxis 函数:')
b = np.rollaxis(a,2,0) # 0-1-2 -》 2-0-1 shape(2,2,2)
print (b)
# 查看元素 a[1,1,0],即 6 的坐标,变成 [0, 1, 1]
# 最后一个 0 移动到最前面
print(np.where(b==6))   
print ('\n')
 
# 将轴 2 滚动到轴 1:(宽度到高度)
 
print ('调用 rollaxis 函数:')
c = np.rollaxis(a,2,1)
print (c)
# 查看元素 a[1,1,0],即 6 的坐标,变成 [1, 0, 1]
# 最后的 0 和 它前面的 1 对换位置
print(np.where(c==6))   
print ('\n')

python:
原数组:
[[[0 1]
  [2 3]]

 [[4 5]
  [6 7]]]
获取数组中一个值:
(array([1]), array([1]), array([0]))
6


调用 rollaxis 函数:
[[[0 2]
  [4 6]]

 [[1 3]
  [5 7]]]
(array([0]), array([1]), array([1]))


调用 rollaxis 函数:
[[[0 2]
  [1 3]]

 [[4 6]
  [5 7]]]
(array([1]), array([0]), array([1]))
复制代码

修改数组维度

维度描述
broadcast 产生模仿广播的对象
broadcast_to 将数组广播到新形状,在原始数组上返回只读视图, 它通常不连续
expand_dims 扩展数组的形状
squeeze 从数组的形状中删除一维条目
numpy.expand_dims

numpy.expand_dims 函数通过在指定位置插入新的轴来扩展数组形状,函数格式如下:

 numpy.expand_dims(arr, axis)

参数说明:

  • arr:输入数组
  • axis:新轴插入的位置
numpy.squeeze 

numpy.squeeze 函数从给定数组的形状中删除一维的条目,函数格式如下:

numpy.squeeze(arr, axis)

参数说明:

  • arr:输入数组
  • axis:整数或整数元组,用于选择形状中一维条目的子集
复制代码
import numpy as np
 
x = np.array(([1,2],[3,4]))
 
print ('数组 x:')
print (x)
print ('\n')
y = np.expand_dims(x, axis = 0)
 
print ('数组 y:')
print (y)
print ('\n')
 
print ('数组 x 和 y 的形状:')
print (x.shape, y.shape)
print ('\n')
# 在位置 1 插入轴
y = np.expand_dims(x, axis = 1)
 
print ('在位置 1 插入轴之后的数组 y:')
print (y)
print ('\n')
 
print ('x.ndim 和 y.ndim:')
print (x.ndim,y.ndim)
print ('\n')
 
print ('x.shape 和 y.shape:')
print (x.shape, y.shape)

output:
数组 x:
[[1 2]
 [3 4]]


数组 y:
[[[1 2]
  [3 4]]]


数组 x 和 y 的形状:
(2, 2) (1, 2, 2)


在位置 1 插入轴之后的数组 y:
[[[1 2]]

 [[3 4]]]


x.ndim 和 y.ndim:
2 3


x.shape 和 y.shape:
(2, 2) (2, 1, 2)
expand_dims
复制代码
复制代码
import numpy as np
 
x = np.arange(9).reshape(3,3,1)
 
print ('数组 x:')
print (x)
print ('\n')
y = np.squeeze(x)
 
print ('数组 y:')
print (y)
print ('\n')
 
print ('数组 x 和 y 的形状:')
print (x.shape, y.shape)

output:
数组 x:
[[[0]
  [1]
  [2]]

 [[3]
  [4]
  [5]]

 [[6]
  [7]
  [8]]]


数组 y:
[[0 1 2]
 [3 4 5]
 [6 7 8]]


数组 x 和 y 的形状:
(3, 3, 1) (3, 3)
squeeze
复制代码

连接数组

函数描述
concatenate 连接沿现有轴的数组序列
stack 沿着新的轴加入一系列数组。
hstack 水平堆叠序列中的数组(列方向)
vstack 竖直堆叠序列中的数组(行方向)

分割数组

函数数组及操作
split 将一个数组分割为多个子数组
hsplit 将一个数组水平分割为多个子数组(按列)
vsplit 将一个数组垂直分割为多个子数组(按行)

数组元素的添加与删除

函数元素及描述
resize 返回指定形状的新数组
append 将值添加到数组末尾
insert 沿指定轴将值插入到指定下标之前
delete 删掉某个轴的子数组,并返回删除后的新数组
unique 查找数组内的唯一元素
 

NumPy 位运算

NumPy "bitwise_" 开头的函数是位运算函数。

NumPy 位运算包括以下几个函数:

函数描述
bitwise_and 对数组元素执行位与操作  &
bitwise_or 对数组元素执行位或操作 ^
invert 按位取反 ~
left_shift 向左移动二进制表示的位 
right_shift 向右移动二进制表示的位
  • 也可以使用 "&"、 "~"、 "|" 和 "^" 等操作符进行计算。
invert

invert() 函数对数组中整数进行位取反运算,即 0 变成 1,1 变成 0。

对于有符号整数,取该二进制数的补码,然后 +1。二进制数,最高位为0表示正数,最高位为 1 表示负数。

看看 ~1 的计算步骤:

    • 1(这里叫:原码)转二进制 = 00000001
    • 按位取反 = 11111110
    • 发现符号位(即最高位)为1(表示负数),将除符号位之外的其他数字取反 = 10000001
    • 末位加1取其补码 = 10000010
    • 转换回十进制 = -2
表达式

二进制值(2 的补数)

十进制值
5 00000000 00000000 00000000 0000010 5
~5 11111111 11111111 11111111 11111010 -6
复制代码
import numpy as np 
 
print ('13 的位反转,其中 ndarray 的 dtype 是 uint8:')
print (np.invert(np.array([13], dtype = np.uint8)))
print ('\n')
# 比较 13 和 242 的二进制表示,我们发现了位的反转
 
print ('13 的二进制表示:')
print (np.binary_repr(13, width = 8))
print ('\n')
 
print ('242 的二进制表示:')
print (np.binary_repr(242, width = 8))

output:
13 的位反转,其中 ndarray 的 dtype 是 uint8:
[242]


13 的二进制表示:
00001101


242 的二进制表示:
11110010
invert()
复制代码

  • 有符号数在内存中转化为二进制补码进行保存,无符号数直接转化为二进制存储。

有符号数表示方法3种:原码、反码、补码
构成:符号位+数值部分组成
符号位 1 负 0 正

1.原码
正数的    原码 = 反码 = 补码

2.反码
负数:符号位不变,数值位取反(即上面的操作)

3.补码
负数:反码加1得到补码


NumPy 字符串函数

以下函数用于对 dtype 为 numpy.string_ 或 numpy.unicode_ 的数组执行向量化字符串操作。 它们基于 Python 内置库中的标准字符串函数。

这些函数在字符数组类(numpy.char)中定义。

函数描述
add() 对两个数组的逐个字符串元素进行连接
multiply() 返回按元素多重连接后的字符串
center() 居中字符串
capitalize() 将字符串第一个字母转换为大写
title() 将字符串的每个单词的第一个字母转换为大写
lower() 数组元素转换为小写
upper() 数组元素转换为大写
split() 指定分隔符对字符串进行分割,并返回数组列表
splitlines() 返回元素中的行列表,以换行符分割
strip() 移除元素开头或者结尾处的特定字符
join() 通过指定分隔符来连接数组中的元素
replace() 使用新字符串替换字符串中的所有子字符串
decode() 数组元素依次调用str.decode
encode() 数组元素依次调用str.encode

NumPy 数学函数

NumPy 提供了标准的三角函数:sin()、cos()、tan()等。

arcsin,arccos,和 arctan 函数返回给定角度的 sin,cos 和 tan 的反三角函数。

这些函数的结果可以通过 numpy.degrees() 函数将弧度转换为角度。

舍入函数

numpy.around() 函数返回指定数字的四舍五入值。

numpy.around(a,decimals)

参数说明:

  • a: 数组
  • decimals: 舍入的小数位数。 默认值为0。 如果为负,整数将四舍五入到小数点左侧的位置
numpy.floor()向下取整

numpy.floor() 返回小于或者等于指定表达式的最大整数,即向下取整。

numpy.ceil()向上取整

numpy.ceil() 返回大于或者等于指定表达式的最小整数,即向上取整。

NumPy 算术函数

NumPy 算术函数包含简单的加减乘除: 

复制代码
import numpy as np 
 
a = np.arange(9, dtype = np.float_).reshape(3,3)  
print ('第一个数组:')
print (a)
print ('\n')
print ('第二个数组:')
b = np.array([10,10,10])  
print (b)
print ('\n')
print ('两个数组相加:')
print (np.add(a,b))
print ('\n')
print ('两个数组相减:')
print (np.subtract(a,b))
print ('\n')
print ('两个数组相乘:')
print (np.multiply(a,b))
print ('\n')
print ('两个数组相除:')
print (np.divide(a,b))

output:
第一个数组:
[[0. 1. 2.]
 [3. 4. 5.]
 [6. 7. 8.]]


第二个数组:
[10 10 10]


两个数组相加:
[[10. 11. 12.]
 [13. 14. 15.]
 [16. 17. 18.]]


两个数组相减:
[[-10.  -9.  -8.]
 [ -7.  -6.  -5.]
 [ -4.  -3.  -2.]]


两个数组相乘:
[[ 0. 10. 20.]
 [30. 40. 50.]
 [60. 70. 80.]]


两个数组相除:
[[0.  0.1 0.2]
 [0.3 0.4 0.5]
 [0.6 0.7 0.8]]
add(),subtract(),multiply() 和 divide()
复制代码
numpy.reciprocal()

numpy.reciprocal() 函数返回参数逐元素的倒数。

需要注意的是数组必须具有相同的形状或符合数组广播规则。

numpy.power()

numpy.power() 函数将第一个输入数组中的元素作为底数,计算它与第二个输入数组中相应元素的幂。

numpy.mod()

numpy.mod() 计算输入数组中相应元素的相除后的余数。 函数 numpy.remainder() 也产生相同的结果。

NumPy 统计函数

NumPy 提供了很多统计函数,用于从数组中查找最小元素,最大元素,百分位标准差和方差等。

  • numpy.amin() 用于计算数组中的元素沿指定轴的最小值。
  • numpy.amax() 用于计算数组中的元素沿指定轴的最大值。
复制代码
import numpy as np 
 
a = np.array([[3,7,5],[8,4,3],[2,4,9]])  
print ('我们的数组是:')
print (a)
print ('\n')
print ('调用 amin() 函数:')
print (np.amin(a,1))
print ('\n')
print ('再次调用 amin() 函数:')
print (np.amin(a,0))
print ('\n')
print ('调用 amax() 函数:')
print (np.amax(a))
print ('\n')
print ('再次调用 amax() 函数:')
print (np.amax(a, axis =  0))

output:
我们的数组是:
[[3 7 5]
 [8 4 3]
 [2 4 9]]


调用 amin() 函数:
[3 3 2]


再次调用 amin() 函数:
[2 4 3]


调用 amax() 函数:
9


再次调用 amax() 函数:
[8 7 9]
amin和amax
复制代码
numpy.ptp()  

numpy.ptp()函数计算数组中元素最大值与最小值的差(最大值 - 最小值)。

numpy.ptp()函数和numpy.amin()一样具有axis参数!

numpy.percentile()

百分位数是统计中使用的度量,表示小于这个值的观察值的百分比。 函数numpy.percentile()接受以下参数。

numpy.percentile(a, q, axis)

参数说明:

  • a: 输入数组
  • q: 要计算的百分位数,在 0 ~ 100 之间
  • axis: 沿着它计算百分位数的轴
numpy.median()

numpy.median() 函数用于计算数组 a 中元素的中位数(中值)

具有axis参数!

numpy.mean()

numpy.mean() 函数返回数组中元素的算术平均值。 如果提供了轴,则沿其计算。

算术平均值是沿轴的元素的总和除以元素的数量。

numpy.average()

numpy.average() 函数根据在另一个数组中给出的各自的权重计算数组中元素的加权平均值。

该函数可以接受一个轴参数。 如果没有指定轴,则数组会被展开。

加权平均值即将各数值乘以相应的权数,然后加总求和得到总体值,再除以总的单位数。

复制代码
import numpy as np 
 
a = np.array([1,2,3,4])  
print ('我们的数组是:')
print (a)
print ('\n')
print ('调用 average() 函数:')
print (np.average(a))
print ('\n')
# 不指定权重时相当于 mean 函数
wts = np.array([4,3,2,1])  
print ('再次调用 average() 函数:')
print (np.average(a,weights = wts))
print ('\n')
# 如果 returned 参数设为 true,则返回权重的和  
print ('权重的和:')
print (np.average([1,2,3,  4],weights =  [4,3,2,1], returned =  True))

output:
我们的数组是:
[1 2 3 4]


调用 average() 函数:
2.5


再次调用 average() 函数:
2.0


权重的和:
(2.0, 10.0)
average()
复制代码
标准差std

标准差是一组数据平均值分散程度的一种度量。标准差是方差的算术平方根。标准差公式如下:

std = sqrt(mean((x - x.mean())**2))
import numpy as np 
 
print (np.std([1,2,3,4]))
方差var

统计中的方差(样本方差)是每个样本值与全体样本值的平均数之差的平方值的平均数,即

mean((x - x.mean())** 2)。

换句话说,标准差是方差的平方根。

import numpy as np
 
print (np.var([1,2,3,4]))

NumPy 排序、条件刷选函数

看原出处:->   😑   <-

NumPy 矩阵库(Matrix)

https://www.runoob.com/numpy/numpy-matrix.html

NumPy 线性代数

https://www.runoob.com/numpy/numpy-linear-algebra.html

NumPy 提供了线性代数函数库 linalg,该库包含了线性代数所需的所有功能,可以看看下面的说明:

函数描述
dot 两个数组的点积,即元素对应相乘。
vdot 两个向量的点积
inner 两个数组的内积
matmul 两个数组的矩阵积
determinant 数组的行列式
solve 求解线性矩阵方程
inv 计算矩阵的乘法逆矩阵



先这样了,用到再看再学是🥱

 

posted @   PiaYie  阅读(78)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
历史上的今天:
2020-08-12 simpSubCipher and simpleSubHacker
点击右上角即可分享
微信分享提示