python数组列表操作简记三之numpy广播机制

发布于:2024-12-18 ⋅ 阅读:(42) ⋅ 点赞:(0)

一、numpy数组常用的两种类型转换

1.1numpy数组与图片文件互转

再进行图像处理时,首先需要将图片文件转换为numpy数组,最后将输出结果保存为图片,这个功能可以使用Opencv完成,也可以使用PIL软件包的Image类完成,代码如下:

from PIL import Image
import numpy as np

#图片文件转换为numpy数组
image = Image.open('*.jpg')
image_data = np.array(image)

#图像处理过程
new_image_data = deal_image_Func(image_data)

#numpy数组转换为图片文件
new_image = Image.fromarray(new_image_data)
new_image.save('*_new.jpg', quality = 95)

1.2numpy数组与pytorch中tensor类型互转

pytorch架构使用的变量类型为tensor,因此在数据读取和读出的时候通常需要与numpy数组互转,代码如下:

import numpy as np
import torch

#numpy数组转换为tensor
a01 = np.array([[[1,2,3,6],[4,5,6,15],[7,8,9,24]],[[10,20,30,60],[40,50,60,150],[70,80,90,240]]])
print(type(a01))#输出<class 'numpy.ndarray'>
t01 = torch.tensor(a01)
print(type(t01))#输出<class 'torch.Tensor'>

#tensor转换为numpy数组
a02 = t01.numpy()
print(type(a02))#输出<class 'numpy.ndarray'>

二、numpy多维数组排序

以numpy三维数组为例,展示如何对数组不同维度排序及获取数组排序后对应的索引,代码如下:

import numpy as np

a01 = np.random.randint(0,10,size=(2,3,4))
print(a01)
array([[[8, 7, 4, 8],
        [8, 6, 2, 1],
        [4, 1, 5, 1]],

       [[0, 0, 7, 4],
        [2, 7, 5, 7],
        [3, 9, 3, 9]]])

print(np.sort(a01,axis=0))
[[[0 0 4 4]
  [2 6 2 1]
  [3 1 3 1]]

 [[8 7 7 8]
  [8 7 5 7]
  [4 9 5 9]]]
print(np.argsort(a01,axis=0))
[[[1 1 0 1]
  [1 0 0 0]
  [1 0 1 0]]

 [[0 0 1 0]
  [0 1 1 1]
  [0 1 0 1]]]

print(np.sort(a01,axis=1))
[[[4 1 2 1]
  [8 6 4 1]
  [8 7 5 8]]

 [[0 0 3 4]
  [2 7 5 7]
  [3 9 7 9]]]
print(np.argsort(a01,axis=1))
[[[2 2 1 1]
  [0 1 0 2]
  [1 0 2 0]]

 [[0 0 2 0]
  [1 1 1 1]
  [2 2 0 2]]]

print(np.sort(a01,axis=2))
[[[4 7 8 8]
  [1 2 6 8]
  [1 1 4 5]]

 [[0 0 4 7]
  [2 5 7 7]
  [3 3 9 9]]]
print(np.argsort(a01,axis=2))
[[[2 1 0 3]
  [3 2 1 0]
  [1 3 0 2]]

 [[0 1 3 2]
  [0 2 1 3]
  [0 2 1 3]]]

三、numpy数组指定区域赋值

有时需要对numpy数组指定区域赋值,这个区域可以是事先指定的形状,也可以是对数据筛选后的不规则区域,如何筛选可参考博客另一篇博文:python数组列表操作简记二

区域赋值操作主要是使用布尔类型数组示例代码如下:

import numpy as np

a01 = np.random.randint(0,10,size=(2,3,4))
print(a01)
array([[[8, 7, 4, 8],
        [8, 6, 2, 1],
        [4, 1, 5, 1]],

       [[0, 0, 7, 4],
        [2, 7, 5, 7],
        [3, 9, 3, 9]]])
a02 = np.random.randint(10,20,size=(2,3,4))
print(a02)
array([[[17, 18, 11, 16],
        [17, 14, 12, 15],
        [10, 14, 11, 19]],

       [[12, 17, 12, 14],
        [17, 16, 19, 10],
        [14, 14, 10, 15]]])
a03 = a01<5
print(a03)
array([[[False, False,  True, False],
        [False, False,  True,  True],
        [ True,  True, False,  True]],

       [[ True,  True, False,  True],
        [ True, False, False, False],
        [ True, False,  True, False]]])

a01[a03] = a02[a03]
print(a01)
array([[[ 8,  7, 11,  8],
        [ 8,  6, 12, 15],
        [10, 14,  5, 19]],

       [[12, 17,  7, 14],
        [17,  7,  5,  7],
        [14,  9, 10,  9]]])

四、numpy广播机制的使用

4.1广播规则和步骤总结

两个相同shape的numpy数组进行加减乘除操作,是对应位置的元素进行运算,但当一个numpy数组与一个常数进行加减乘除,结果是数组的所有元素都与这个常数进行运算,这就是numpy的广播机制,即numpy可以将参与运算的两个数组调整为具有相同形状然后进行计算

广播的规则和步骤可以总结为:
(1)如果两个数组的维度数不相同,则扩充小维度数的数组的维度,向外一层层扩充维度,直到维度数相同(自动扩充按照此规则,但也可手动扩充)。例如形状(4, 2, 2)与形状(2, )进行运算,会将第二个数组扩充为形状(1, 1, 2);

(2)扩充后,除形状为1外的维度形状不一致,则报错,无法进行计算。例如(4, 2, 2)与形状(4, )进行运算,会将第二个数组扩充为形状(1, 1, 4),此时第一个数组最后一个维度的形状为2,第二个数组最后一个维度的形状为4,二者不一致,则报错;

(3)扩充后,除形状为1外维度形状一致,则进行计算,此时广播机制会沿着形状为1的维度复制内层元素,复制的次数即为对齐的数组形状。例如(4, 2, 2)与扩充后的形状(1, 1, 2)进行运算,将第二个数组最内层元素复制2次变为(1, 2, 2),然后将倒数一二层元素复制四次变为(4, 2, 2),然后进行计算。

上述规则和步骤可结合示例进行理解。

4.2使用示例

4.2.1形状(4, 2)-形状(2, )=形状(4, 2)

例如形状为(4, 2)的二维数组a01减去一个(2, )的一维数组a02,广播机制会将a02扩充为(1, 2),即在现有维度之外增加维度,示例代码如下:

import numpy as np

a01 = np.random.randint(10, size=[4,2])#shape:(4, 2)
print(a01)
array([[8, 6],
       [7, 8],
       [3, 2],
       [0, 6]])

a02 = np.array([1,2])#shape:(2, )
print(a01-a02)
array([[ 7,  4],
       [ 6,  6],
       [ 2,  0],
       [-1,  4]])
a03 = np.array([[1,2]])#shape:(1, 2)
print(a01-a03)
array([[ 7,  4],
       [ 6,  6],
       [ 2,  0],
       [-1,  4]])

4.2.2形状(4, 2)-形状(4, )=形状(4, 2)

注意广播机制无法在现有维度之内增加维度,例如一维数组a02形状为(4, ),那么广播机制无法将a02扩充为(4, 1),然后与a01进行减法计算,但可以使用np.newaxis手动增加维度,示例代码如下:

import numpy as np

a01 = np.random.randint(10, size=[4,2])#shape:(4, 2)
print(a01)
array([[8, 6],
       [7, 8],
       [3, 2],
       [0, 6]])

a02 = np.array([1,2,3,4])#shape:(4, )
print(a01-a02)#报错:ValueError: operands could not be broadcast together with shapes (4,2) (4,)

print(a01-a02[:,np.newaxis])#正常运行
array([[ 7,  5],
       [ 5,  6],
       [ 0, -1],
       [-4,  2]])

4.2.3形状(4, 2)-形状(3, 2)=形状(4, 3, 2)

是指,要使第一个数组的每行分别减去第二个数组的每行,最终得到数组形状为(4, 3, 2),示例代码如下:

import numpy as np

a01 = np.random.randint(10, size=[4,2])#shape:(4, 2)
print(a01)
array([[8, 8],
       [1, 4],
       [7, 0],
       [2, 2]])
a02 = np.random.randint(10, size=[3,2])#shape:(3, 2)
print(a02)
array([[5, 5],
       [5, 3],
       [2, 4]])
print(a01-a02)#报错:ValueError: operands could not be broadcast together with shapes (4,2) (3,2)
print(a01[:,np.newaxis,:]-a02)#正常运行
array([[[ 3,  3],
        [ 3,  5],
        [ 6,  4]],

       [[-4, -1],
        [-4,  1],
        [-1,  0]],

       [[ 2, -5],
        [ 2, -3],
        [ 5, -4]],

       [[-3, -3],
        [-3, -1],
        [ 0, -2]]])

4.2.4形状(4, 2)-形状(4, 2)=形状(4, 2, 2)

是指,要使第一个数组的每行中的每列元素分别减去本行的每列元素,最终得到数组形状为(4, 2, 2),示例代码如下:

import numpy as np

a01 = np.random.randint(10, size=[4,2])#shape:(4, 2)
print(a01)
array([[8, 8],
       [1, 4],
       [7, 0],
       [2, 2]])

print(a01[:,:,np.newaxis]-a01[:,np.newaxis,:])
array([[[ 0,  0],
        [ 0,  0]],

       [[ 0, -3],
        [ 3,  0]],

       [[ 0,  7],
        [-7,  0]],

       [[ 0,  0],
        [ 0,  0]]])

网站公告

今日签到

点亮在社区的每一天
去签到