Python拓展之Numpy

一、前言与简介

💡NumPy是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库

👉NumPy 是一个运行速度非常快的数学库,主要用于数组计算

👉NumPy 通常与 SciPy(Scientific Python)和 Matplotlib(绘图库)一起使用, 这种组合广泛用于替代 MatLab,是一个强大的科学计算环境,有助于我们通过 Python 学习数据科学或者机器学习

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

  • Matplotlib 是 Python 编程语言及其数值数学扩展包 NumPy 的可视化操作界面。它为利用通用的图形用户界面工具包,如 Tkinter, wxPython, Qt 或 GTK+ 向应用程序嵌入式绘图提供了应用程序接口(API)

二、numpy的数据与基础操作

1、Ndarray数据类型

  • numpy 支持的数据类型比 Python 内置的类型要多很多,基本上可以和 C 语言的数据类型对应上,其中部分类型对应为 Python 内置的类型

  • 下表列举了常用 NumPy 基本类型

2、Ndarray对象

  • NumPy 最重要的一个特点是其 N 维数组对象 ndarray,它是一系列同类型数据的集合,以 0 下标为开始进行集合中元素的索引

  • ndarray 对象是用于存放同类型元素的多维数组

  • ndarray 中的每个元素在内存中都有相同存储大小的区域

  • 创建一个 ndarray 只需调用 NumPy 的 array 函数即可

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

3、创建数组

(1)底层 ndarray 构造器

import numpy as np
# a=np.array([1,2,3])
# a = np.array([[1,  2],  [3,  4]]) # 多于一个维度  
a = np.array([1, 2, 3, 4, 5], ndmin=2)  # 最小维度,五行一列
print(a)

(2)numpy.empty

  • 创建一个指定形状(shape)、数据类型(dtype)且未初始化的数组

# 数组元素为随机值,因为它们未初始化
import numpy as np
x = np.empty([3, 2], dtype=int)
print(x) 
'''
[[ 105274832        496]
 [         0          0]
 [         1 1834972270]]
'''

(3)numpy.zeros、numpy.ones

  • 创建指定大小的数组,数组元素用0填充

  • 创建指定大小的数组,数组元素用1填充(默认是浮点数)

y = np.zeros((5), dtype=int)
x = np.ones(5)
print(x) # [1. 1. 1. 1. 1.]
print(y) # [0 0 0 0 0]

(4)numpy.asarray

  • 类似 numpy.array,但 numpy.asarray 参数只有三个,比 numpy.array 少两个

# 参数a可以是任意形式的输入参数,可以是列表, 列表的元组, 元组, 元组的元组, 元组的列表,多维数组
x = [1, 2, 3]
a = np.asarray(x)
print(a)

(5)numpy.arange

  • 创建数值范围并返回 ndarray 对象

 # 生成 0 到 5 的数组:
 x = np.arange(5)
 print(x) # [0 1 2 3 4]
 ​
 # 设置了起始值、终止值及步长:
 x = np.arange(10, 20, 2)
 print(x) # [10 12 14 16 18]

(6)numpy.linspace

  • 创建一个一维数组,数组是一个等差数列构成的

  • start 序列的起始值
  • stop 序列的终止值,如果endpoint为true,该值包含于数列中
  • num 要生成的等步长的样本数量,默认为50
  • endpoint 该值为 true 时,数列中包含stop值,反之不包含,默认是True。
  • retstep 如果为 True 时,生成的数组中会显示间距,反之不显示。
  • dtype ndarray 的数据类型
 np.linspace(start, stop, num=50, # 要生成的等步长的样本数量,默认为50
             endpoint=True, # 该值为 true 时,数列中包含stop值,反之不包含,默认是True
             retstep=False, # 如果为 True 时,生成的数组中会显示间距,反之不显示
             dtype=None)
 a = np.linspace(10, 20,  5, endpoint=False)
 print(a) # [10. 12. 14. 16. 18.]

(7)numpy.logspace

  • 创建一个于等比数列

 np.logspace(start, stop, num=50, endpoint=True, base=10.0, # 底数
             dtype=None)
 a = np.logspace(1.0,  2.0, num=10) # 从1~2,以10为底的指数,得到10个数字
 print(a) 
 '''
 [ 10.          12.91549665  16.68100537  21.5443469   27.82559402
   35.93813664  46.41588834  59.94842503  77.42636827 100.        ]

4、数组属性

  • numpy数组的维数称为秩(rank),秩就是轴(axis)的数量,即数组的维度(dimensions),一维数组的秩为 1,二维数组的秩为 2,以此类推

  • 对象属性

a = np.arange(24)
print(a.ndim)  # a 现只有一个维度
print(a)

# 现在调整其大小
b = a.reshape(2, 4, 3)  # b 现在拥有三个维度,要和数据数量对应
print(b.ndim)
print(b)
print(b.shape)
'''
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]]]
(2, 4, 3)
'''

5、索引与切片

  • 与list的索引、切片一样,但是numpy数组比python序列有更多的索引方式

a = np.arange(10)
print(a[2:7:2]) # 从索引 2 开始到索引 7 停止,间隔为2

a = np.array([[1, 2, 3], [3, 4, 5], [4, 5, 6]]) # 3*3
print(a)
print(a[1:]) # 从第二行开始进行整行切割

(1)整数数组索引

# 获取数组中(0,0),(1,1)和(2,0)位置处的元素
x = np.array([[1, 2], [3, 4], [5, 6]])
y = x[[0, 1, 2],  [0, 1, 0]] # 行列同时切割,组成坐标
print(y) # [1 4 5]

(2)布尔索引

👉通过一个布尔数组来索引目标数组

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

# 获取大于5的元素
x = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]])
print(x)
print('\n')
print(x[x > 5]) # [ 6  7  8  9 10 11]

(3)花式索引

👉利用整数数组进行索引

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

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

x = np.arange(9)
print(x)
print('******************')
x2 = x[[0, 6]]  # 使用花式索引
print(x2)
print(x2[0]) # 一维数组读取指定下标对应的元素
print(x2[1])
print('******************')
x = np.arange(32).reshape((8, 4))
print(x)
print(x[[4, 2, 1, 7]]) # 二维数组读取指定下标对应的行

6、数组操作

(1)迭代数组

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

a = np.arange(6).reshape(2, 3)
print(a)
for x in np.nditer(a):
    print(x, end=", ")
  • for x in np.nditer(a, order=‘F’):Fortran order,即是列序优先

  • for x in np.nditer(a, order=‘C’):C order,即是行序优先

a = np.arange(0, 60, 5).reshape(3, 4)
print(a)
'''
[[ 0  5 10 15]
 [20 25 30 35]
 [40 45 50 55]]
'''
for x in np.nditer(a, order='C'):
    print(x, end=", ") # 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 
print('\n')
for x in np.nditer(a, order='F'):
    print(x, end=", ") # 0, 20, 40, 5, 25, 45, 10, 30, 50, 15, 35, 55, 

(2)广播机制

💡广播是 numpy 对不同形状的数组进行数值计算的方式, 对数组的算术运算通常在相应的元素上进行

👉如果两个数组 a 和 b 形状相同,即满足 a.shape == b.shape,那么 a*b 的结果就是 a 与 b 数组对应位相乘。这要求维数相同,且各维度的长度相同。当运算中的 2 个数组的形状不同时,numpy 将自动触发广播机制

a = np.array([[ 0, 0, 0],
           [10,10,10],
           [20,20,20],
           [30,30,30]])
b = np.array([0,1,2])
print(a + b)
'''
[[ 0  1  2]
 [10 11 12]
 [20 21 22]
 [30 31 32]]
'''
数组 b 如何通过广播来与数组 a 兼容

👉广播的规则:对两个数组,分别比较它们的每一个维度,必须满足:

  • 数组拥有相同形状
  • 当前维度的值相等
  • 当前维度的值有一个是1
  • 若条件不满足,抛出 “ValueError: frames are not aligned” 异常
a = np.array([[0, 0, 0],
              [10, 10, 10],
              [20, 20, 20],
              [30, 30, 30]])
b = np.array([0, 1, 2])
print(a + b)

(3)数组操作

  • 修改数组形状:numpy.reshape、numpy.ndarray.flatten

numpy.reshape(arr, newshape, order='C')
'''
arr:要修改形状的数组
newshape:整数或者整数数组,新的形状应当兼容原有形状
order:‘C’ – 按行,‘F’ – 按列,‘A’ – 原顺序,‘k’ – 元素在内存中的出现顺序。
'''
# numpy.reshape 在不改变数据的条件下修改形状
a = np.arange(20)
print(a)
b = np.reshape(a, (4, 5))
print(b)

# numpy.ndarray.flatten 返回一份展平的数组拷贝,对拷贝所做的修改不会影响原始数组
a = np.arange(8).reshape(2, 4)
print(a)
print(a.flatten()) # 默认按行展开
print(a.flatten(order='F'))
'''
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19]
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]
 [15 16 17 18 19]]

[[0 1 2 3]
 [4 5 6 7]]
[0 1 2 3 4 5 6 7]
[0 4 1 5 2 6 3 7]
'''
  • 翻转数组:np.transpose、np.swapaxes

numpy.swapaxes(arr, axis1, axis2)
'''
arr:输入的数组
axis1:对应第一个轴的整数
axis2:对应第二个轴的整数
'''
# np.transpose 对换数组的维度,类似numpy.ndarray.T 转置
a = np.arange(12).reshape(3,4)
print(a )
print(np.transpose(a)) # 等价于print(a.T)

# np.swapaxes:交换数组的两个轴
a = np.arange(8).reshape(2,2,2)
print(a)
print(np.swapaxes(a, 2, 0)) # 现在交换轴 0(深度方向)到轴 2(宽度方向)
'''
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
[[ 0  4  8]
 [ 1  5  9]
 [ 2  6 10]
 [ 3  7 11]]
 
[[[0 1]
  [2 3]]

 [[4 5]
  [6 7]]]
[[[0 4]
  [2 6]]

 [[1 5]
  [3 7]]]
'''
  • 修改数组维度:numpy.expand_dims、numpy.squeeze

# np.expand_dims 通过在指定位置插入新的轴来扩展数组形状
x = np.array(([1, 2], [3, 4]))
y = np.expand_dims(x, axis=0) # 在第0维增加一个维度
print(x)
print(y)
print(x.shape, y.shape)
'''
[[1 2]
 [3 4]]
[[[1 2]
  [3 4]]]
(2, 2) (1, 2, 2)
'''

# np.squeeze 从给定数组的形状中删除一维的条目
x = np.arange(9).reshape(1, 3, 3)
y = np.squeeze(x)
print(x)
print(y)
print(x.shape, y.shape)
'''
[[[0 1 2]
  [3 4 5]
  [6 7 8]]]
[[0 1 2]
 [3 4 5]
 [6 7 8]]
(1, 3, 3) (3, 3)
'''
  • 连接数组:numpy.concatenate、numpy.stack、numpy.hstack、numpy.vstack

👉np.concatenate:用于沿指定轴连接相同形状的两个或多个数组

numpy.concatenate((a1, a2, ...), axis)
'''
a1, a2, ...:相同类型的数组
axis:沿着它连接数组的轴,默认为 0
'''
a = np.array([[1,2],[3,4]])
b = np.array([[5,6],[7,8]])

# 两个数组的维度相同
print ('沿轴 0 连接两个数组:') # 在行的维度上拼接
print (np.concatenate((a,b)))
print ('沿轴 1 连接两个数组:')
print (np.concatenate((a,b),axis = 1))
'''
沿轴 0 连接两个数组:
[[1 2]
 [3 4]
 [5 6]
 [7 8]]
沿轴 1 连接两个数组:
[[1 2 5 6]
 [3 4 7 8]]
'''

👉np.stack:用于沿新轴连接数组序列,增加了一个新轴

numpy.stack(arrays, axis)
'''
arrays相同形状的数组序列
axis:返回数组中的轴,输入数组沿着它来堆叠
'''
a = np.array([[1,2],[3,4]])
b = np.array([[5,6],[7,8]])
 
print ('沿轴 0 堆叠两个数组:')
print (np.stack((a,b),0))
print ('沿轴 1 堆叠两个数组:')
print (np.stack((a,b),1))
'''
沿轴 0 堆叠两个数组:
[[[1 2]
  [3 4]]

 [[5 6]
  [7 8]]]
沿轴 1 堆叠两个数组:
[[[1 2]
  [5 6]]

 [[3 4]
  [7 8]]]
'''

👉np.hstack:通过水平堆叠来生成数组

a = np.array([[1,2],[3,4]])
b = np.array([[5,6],[7,8]])
c = np.hstack((a,b))
print (c)
'''
[[1 2 5 6]
 [3 4 7 8]]
'''

👉np.vstack:通过垂直堆叠来生成数组

a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
c = np.vstack((a, b))
print(c)
'''
[[1 2]
 [3 4]
 [5 6]
 [7 8]]
''' 
  • 分割数组:numpy.split

👉np.split 函数沿特定的轴将数组分割为子数组

numpy.split(ary, indices_or_sections, axis)
'''
ary:被分割的数组
indices_or_sections:如果是一个整数,就用该数平均切分,如果是一个数组,为沿轴切分的位置(左开右闭)
axis:设置沿着哪个方向进行切分,默认为 0,横向切分,即水平方向。为 1 时,纵向切分,即竖直方向。
'''
a = np.arange(9)
 
print ('第一个数组:')
print (a)
print ('\n')
 
print ('将数组分为三个大小相等的子数组:')
b = np.split(a,3)
print (b)
print ('\n')
 
print ('将数组在一维数组中表明的位置分割:')
b = np.split(a,[4,7])
print (b)
'''
第一个数组:
[0 1 2 3 4 5 6 7 8]


将数组分为三个大小相等的子数组:
[array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])]


将数组在一维数组中表明的位置分割:
[array([0, 1, 2, 3]), array([4, 5, 6]), array([7, 8])]
'''

  • 数组元素的添加与删除:np.append、np.insert、np.delete

👉np.append 在数组的末尾添加值。追加操作会分配整个数组,并把原来的数组复制到新数组中。此外,输入数组的维度必须匹配否则将生成ValueError

mpy.append(arr, values, axis=None)
'''
arr:输入数组
values:要向arr添加的值,需要和arr形状相同(除了要添加的轴)
axis:默认为 None。
'''
  • axis=None,是横向加成,返回总是为一维数组
  • axis=0,数组是加在下边(列数要相同)
  • axis=1,数组是加在右边(行数要相同)
a = np.array([[1, 2, 3], [4, 5, 6]])
print(np.append(a, [7, 8, 9]))
print(np.append(a, [[7, 8, 9]], axis=0))
print(np.append(a, [[5, 5, 5], [7, 8, 9]], axis=1))
'''
[1 2 3 4 5 6 7 8 9]
[[1 2 3]
 [4 5 6]
 [7 8 9]]
[[1 2 3 5 5 5]
 [4 5 6 7 8 9]]
'''

👉np.insert 在给定索引之前,沿给定轴在输入数组中插入值

👉如果值的类型转换为要插入,则它与输入数组不同。 插入没有原地的,函数会返回一个新数组。 此外,如果未提供轴,则输入数组会被展开

numpy.insert(arr, obj, values, axis)
'''
arr:输入数组
obj:在其之前插入值的索引
values:要插入的值
axis:沿着它插入的轴,如果未提供,则输入数组会被展开
'''
a = np.array([[1,2],[3,4],[5,6]])
 
print ('第一个数组:')
print (a)
 
print ('未传递 Axis 参数。 在删除之前输入数组会被展开。')
print (np.insert(a,3,[11,12]))
print ('传递了 Axis 参数。 会广播值数组来配输入数组。')
print ('沿轴 0 广播:')
print (np.insert(a,1,[11],axis = 0))
print ('\n')
print ('沿轴 1 广播:')
print (np.insert(a,1,11,axis = 1))
'''
第一个数组:
[[1 2]
 [3 4]
 [5 6]]

未传递 Axis 参数。 在删除之前输入数组会被展开。
[ 1  2  3 11 12  4  5  6]

传递了 Axis 参数。 会广播值数组来配输入数组。
沿轴 0 广播:
[[ 1  2]
 [11 11]
 [ 3  4]
 [ 5  6]]

沿轴 1 广播:
[[ 1 11  2]
 [ 3 11  4]
 [ 5 11  6]]
'''

👉np.delete 返回从输入数组中删除指定子数组的新数组

👉如果未提供轴参数,则输入数组将展开

numpy.delete(arr, obj, axis) 
'''
obj:可以被切片,整数或者整数数组,表明要从输入数组删除的子数组。
axis:沿着它删除给定子数组的轴,如果未提供,则输入数组会被展开
'''
import numpy as np
 
a = np.arange(12).reshape(3,4)
 
print ('第一个数组:')
print (a)
print ('\n')
 
print ('未传递 Axis 参数。 在插入之前输入数组会被展开。')
print (np.delete(a,5))
print ('\n')
 
print ('删除第二列:')
print (np.delete(a,1,axis = 1))
print ('\n')
 
print ('包含从数组中删除的替代值的切片:')
a = np.array([1,2,3,4,5,6,7,8,9,10])
print (np.delete(a, np.s_[::2]))
'''
第一个数组:
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

未传递 Axis 参数。 在插入之前输入数组会被展开。
[ 0  1  2  3  4  6  7  8  9 10 11]

删除第二列:
[[ 0  2  3]
 [ 4  6  7]
 [ 8 10 11]]

包含从数组中删除的替代值的切片:
[ 2  4  6  8 10]
'''

三、numpy的函数与常用功能

1、字符串函数

2、数学函数

(1)三角函数:sin()、cos()、tan()以及arcsin()、arccos()、arctan()

a = np.array([0, 30, 45, 60, 90])
# 通过乘 pi/180 转化为弧度
print(np.sin(a*np.pi/180))
print(np.cos(a*np.pi/180))
print(np.tan(a*np.pi/180))

(2)舍入函数

  • np.around() 四舍五入值

  • np.floor() 向下取整

  • np.ceil() 向上取整

a = np.array([1.0, 5.55,  123,  0.567,  25.532])
print(np.around(a))
print(np.around(a, decimals=1)) # 指定保留的小数位数
print(np.floor(a))
print(np.ceil(a))
'''
[  1.   6. 123.   1.  26.]
[  1.    5.6 123.    0.6  25.5]
[  1.   5. 123.   0.  25.]
[  1.   6. 123.   1.  26.]
'''

3、统计函数

(1)np.amin()和np.amax()

  • 计算数组中的元素沿指定轴的最小(大)值

a = np.array([[3, 7, 5], [8, 4, 3], [2, 4, 9]])
print(a)
print(np.amin(a, 1)) # 横轴
print(np.amin(a, 0)) # 竖轴
print(np.amax(a))
print(np.amax(a, axis=0))
'''
[[3 7 5]
 [8 4 3]
 [2 4 9]]
[3 3 2]
[2 4 3]
9
[8 7 9]
'''

(2)np.percentile()

(3)np.median()、np.mean()、np.average()

  • 计算数组 a 中元素的中位数(中值)

  • 返回数组中元素的算术平均值。 如果提供了轴,则沿其计算。算术平均值是沿轴的元素的总和除以元素的数量

  • 根据在另一个数组中给出的各自的权重计算数组中元素的加权平均值。该函数可以接受一个轴参数。 如果没有指定轴,则数组会被展开。加权平均值即将各数值乘以相应的权数,然后加总求和得到总体值,再除以总的单位数。

    如:考虑数组[1,2,3,4]和相应的权重[4,3,2,1],通过将相应元素的乘积相加,并将和除以权重的和,来计算加权平均值。

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')
# 加权平均值 = (1*4+2*3+3*2+4*1)/(4+3+2+1)

(4)标准差std

💡一组数据平均值分散程度的一种度量。 标准差是方差的算术平方根。

  • 是一组数据平均值分散程度的一种度量

  • 标准差是方差的算术平方根

  • 公式如下:std = sqrt(mean((x - x.mean())**2))

print (np.std([1,2,3,4])) # 1.118033988749895

(5)方差var

  • 每个样本值与全体样本值的平均数之差的平方值的平均数

  • 公式如下:var = mean((x - x.mean())** 2)

print (np.var([1,2,3,4])) # 1.25

(6)排序sort

💡返回输入数组的排序副本

numpy.sort(a, axis, kind, order)
'''
a: 要排序的数组
axis: 沿着它排序数组的轴, axis=0 按列排序,axis=1 按行排序
kind: 默认为’quicksort’(快速排序)
order: 如果数组包含字段,则是要排序的字段
'''

(7)np.where

  • 返回输入数组中满足给定条件的元素的索引

x = np.arange(9.).reshape(3,  3)
print(x)
y = np.where(x > 3)
print(y)
print(x[y])
'''
[[0. 1. 2.]
 [3. 4. 5.]
 [6. 7. 8.]]
(array([1, 1, 2, 2, 2], dtype=int64), array([1, 2, 0, 1, 2], dtype=int64))
[4. 5. 6. 7. 8.]
'''

(8)np.extract()

  • 根据某个条件从数组中抽取元素,返回满足条件的元素

x = np.arange(9.).reshape(3,  3)
print(x)
# 定义条件, 选择偶数元素
condition = np.mod(x, 2) == 0
print(condition)
print(np.extract(condition, x))
'''
[[0. 1. 2.]
 [3. 4. 5.]
 [6. 7. 8.]]
[[ True False  True]
 [False  True False]
 [ True False  True]]
[0. 2. 4. 6. 8.]
'''

4、副本与视图

(1)副本

💡副本是一个数据的完整的拷贝,如果我们对副本进行修改,它不会影响到原始数据,物理内存不在同一位置

👉副本一般发生在:

  • Python 序列的切片操作,调用deepCopy()函数
  • 调用 ndarray 的 copy() 函数产生一个副本
import numpy as np 
 
a = np.array([[10,10],  [2,3],  [4,5]])  
print ('数组 a:')
print (a)
print(id(a))

print("\n********************\n")
print ('创建 a 的深层副本:')
b = a.copy()  
print ('数组 b:')
print (b)
print(id(b))

print("\n********************\n")

# b 与 a 不共享任何内容  
print ('我们能够写入 b 来写入 a 吗?')
print (b is a)
print ('修改 b 的内容:')
b[0,0]  =  100  
print ('修改后的数组 b:')
print (b)
print ('a 保持不变:')
print (a)
'''
数组 a:
[[10 10]
 [ 2  3]
 [ 4  5]]
2986478476944

********************

创建 a 的深层副本:
数组 b:
[[10 10]
 [ 2  3]
 [ 4  5]]
2986478483952

********************

我们能够写入 b 来写入 a 吗?
False
修改 b 的内容:
修改后的数组 b:
[[100  10]
 [  2   3]
 [  4   5]]
a 保持不变:
[[10 10]
 [ 2  3]
 [ 4  5]]
'''

(2)视图

💡视图是数据的一个别称或引用,通过该别称或引用亦便可访问、操作原有数据,但原有数据不会产生拷贝。如果我们对视图进行修改,它会影响到原始数据,物理内存在同一位置

👉视图一般发生在:

  • numpy 的切片操作返回原数据的视图,会影响到原始数组
  • 调用 ndarray 的 view() 函数产生一个视图,维数变化不会改变原始数据的维数

👉ndarray.view() 方会创建一个新的数组对象,该方法创建的新数组的维数变化不会改变原始数据的维数

import numpy as np 
 
# 最开始 a 是个 3X2 的数组
a = np.arange(6).reshape(3,2)  
print ('数组 a:')
print (a)
print ('创建 a 的视图:')
b = a.view()  
print (b)
print ('两个数组的 id() 不同:')
print ('a 的 id():')
print (id(a))
print ('b 的 id():' )
print (id(b))
# 修改 b 的形状,并不会修改 a
b.shape =  2,3
print ('b 的形状:')
print (b)
print ('a 的形状:')
print (a)
'''
数组 a:
[[0 1]
 [2 3]
 [4 5]]
创建 a 的视图:
[[0 1]
 [2 3]
 [4 5]]
两个数组的 id() 不同:
a 的 id():
2986478482320
b 的 id():
2986471500528
b 的形状:
[[0 1 2]
 [3 4 5]]
a 的形状:
[[0 1]
 [2 3]
 [4 5]]
'''

👉使用切片创建视图修改数据会影响到原始数组

👉变量 a,b 都是 arr 的一部分视图,对视图的修改会直接反映到原数据中。但是我们观察 a,b 的 id,他们是不同的,也就是说,视图虽然指向原数据,但是他们和赋值引用还是有区别的。

import numpy as np 
 
arr = np.arange(12)
print ('我们的数组:')
print (arr)
print ('创建切片:')
a = arr[3:]
b = arr[3:]
a[1] = 123
b[2] = 234
print(arr)
print(id(a),id(b),id(arr[3:]))
'''
我们的数组:
[ 0  1  2  3  4  5  6  7  8  9 10 11]
创建切片:
[  0   1   2   3 123 234   6   7   8   9  10  11]
2986478482704 2986478482320 2986471500528
'''

(3)赋值

💡简单的赋值不会创建数组对象的副本。 相反,它使用原始数组的相同id()来访问它。 id()返回 Python 对象的通用标识符,类似于 C 中的指针。

import numpy as np 
 
a = np.arange(6)  
print ('数组是:')
print (a)

print ('调用 id() 函数:')
print (f'a的id是:{id(a)}')

print ('a 赋值给 b:')
b = a 
print (b)

print ('b 拥有相同 id():')
print (f'b的id是{id(b)}')

print ('修改 b 的形状:')
b.shape =  3,2  
print (b)
print ('a 的形状也修改了:')
print (a)
'''
数组是:
[0 1 2 3 4 5]
调用 id() 函数:
a的id是:2986471501872
a 赋值给 b:
[0 1 2 3 4 5]
b 拥有相同 id():
b的id是2986471501872
修改 b 的形状:
[[0 1]
 [2 3]
 [4 5]]
a 的形状也修改了:
[[0 1]
 [2 3]
 [4 5]]
'''

 

 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盾山狂热粉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值