numpy——数组的操作方法

文章详细介绍了NumPy数组的索引和切片操作,包括一维和多维数组的访问方法。接着讨论了改变数组结构的函数,如reshape、resize、ravel和transpose。还涵盖了数组的合并与拆分,以及复制(浅复制和深复制)的区别。此外,文章阐述了数组的排序功能,如sort和argsort,以及查找最大值和最小值的索引。最后,讲解了如何在数组中筛选元素和读写数组到文件的I/O操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1 索引和切片

2 改变结构

3 合并和拆分

4 复制

5 排序

6 查找和筛选

6.1 查找

6.2 筛选

7 数组的I/O


1 索引和切片

a = np.arange(10)
print(a)
#返回最后一个元素
print(a[-1])
#返回2到第7个元素
print(a[2:7])
print(a[:7:3]) #返回0到7的元素,步长为3
print(a[::-1]) #返回倒序数组

多维数组也可以

#获取元素
print(a[1][2][3])      #不规范写法
print(a[1,2,3])         #标准写法
print(a[:,0,0])                            # 所有楼层的第1排第1列
print(a[0,:,:]) #获取第一层的所有行和列
print(a[:,:,1:3])    # 所有楼层所有排的第2到4列
print(a[1,:,-1])       # # 2层每一排的最后一个房间

注意:

  1. 对多维数组切片或索引得到的结果,维度不是确定的;

  2. 切片返回的数组不是原始数据的副本,而是指向与原始数组相同的内存区域。数组切片不会复制内部数组数据,只是产生了原始数据的一个新视图。

b = a[:,1:,2:]
print(b)
b[1,1,1] = 55
print(a)  #改变b,a也会改变
​
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]
​
 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 55]]]
​
Process finished with exit code 0

2 改变结构

NumPy数组的存储顺序和数组的视图是相互独立的,因此改变数组的维度是非常便捷的操作,这一类操作不会改变所操作的数组本身的存储顺序, resize() 除外。

# reshape() - 按照指定的结构(形状)返回数组的新视图,但不会改变数组
# resize() - 按照指定的结构(形状)改变数组,无返回值
# ravel() - 返回多维数组一维化的视图,但不会改变原数组
# transpose() - 返回行变列的视图,但不会改变原数组
# rollaxis() - 翻滚轴,返回新的视图
a = np.arange(12)
b = a.reshape((3,4))
print(a) #不会改变a的结构
print(b)
​
a.resize([4,3]) # resize()则真正改变了数组a的结构
print(a.shape)
​
print( a.ravel())  # 返回多维数组一维化的视图,但不会改变原数组
​
print(a.transpose()) # 返回行变列的视图,但不会改变原数组
print(a.T ) # 返回行变列的视图,等价于transpose()
​
print(np.rollaxis(a, 1, 0))  # 翻滚轴,1轴变0轴

3 合并和拆分

NumPy数组一旦创建就不能再改变其元素数量了。如果要动态改变数组元素数量,只能通过合并或者拆分的方法,生成新的数组。NumPy仍然保留了append() 方法,只不过这个方法不再是NumPy数组的方法,而是是升级到最外层的NumPy命名空间,并且该方法的功能不再是追加元素,而是合并数组。

print(np.append([[1,2,3]],[4,5,6]))    #[1 2 3 4 5 6]
print(np.append([[1,2,3]],[[4,5,6]],axis=0))    #按行添加
print(np.append([[1,2,3]],[[4,5,6]],axis=1))     #按列添加

除了append()方法,还可以使用stack方法,实现水平,垂直和深度合并

a = np.arange(4).reshape(2,2)
b = np.arange(4,8).reshape(2,2)
print(a)
print(np.hstack((a,b)))  #水平合并
print(np.vstack((a,b))) #垂直合并
print(np.dstack((a,b))) #深度合并
print(np.stack((a,b)))  #不改变原来数组的结构,直接合并

4 复制

改变数组结构返回的是原元数据的一个新视图,而不是原元数据的副本。浅复制(view)和深复制(copy)则是创建原数据的副本,但二者之间也有细微差别:浅复制(view)是共享内存,深复制(copy)则是独享。

a = np.arange(4).reshape(2,2)
b = a.view()
print(b is a,b.base is a,b.flags.owndata)  #False False False
​
c = a.copy()
print(c is a,c.base is a,c.flags.owndata)  #False False True

5 排序

NumPy 数组排序函数有两个,一个是sort(),一个是argsort()。sort()返回输入数组的排序副本,argsort()返回的是数组值从小到大的索引号。从函数原型看,这两个函数的参数是完全一样的。

方法原型为:

# numpy.sort(a, axis=-1, kind=‘quicksort’, order=None)
# numpy.argsort(a, axis=-1, kind=‘quicksort’, order=None)
# a - 要排序的数组
# axis - 沿着它排序数组的轴,如果没有,则沿着最后的轴排序
# kind - 排序方法,默认为’quicksort’(快速排序),其他选项还有 ‘mergesort’(归并排序)和 ‘heapsort’(堆排序)
# order - 如果数组包含字段,则是要排序的字段
a = np.random.random((2,3))
print(np.argsort(a)) # 返回行内从小到大排序的索引序号(列排序),相当于axis=1(最后的轴)
print(np.sort(a)) # 返回行内从小到大排序的一个新数组(列排序)
​
print(np.sort(a,axis=0)) # 返回列内每一行都是从小到大排序(行排序

可以使用order参数,传入数据类型,按照order排序:

dt = np.dtype([('name',  'S10'),('age',  int)])
a = np.array([("zhang",21),("wang",25),("li",  17),  ("zhao",27)], dtype = dt)
print(np.sort(a, order='name')) # 如果指定姓名排序,结果是李王张赵
​
print(np.sort(a, order='age'))  # 如果指定年龄排序,结果则是李张王赵

6 查找和筛选

6.1 查找

返回数组中最大值和最小值的索引:

a = np.random.randint(low=0,high=10,size=(3,3))
print(a)
print(a.argmax())  #返回最大值的索引
print(a.argmin()) #返回最小值的索引
print(a.nonzero())  #返回非零索引

除此之外,numpy.where() 用于返回数组中满足给定条件的元素的索引,还可以用于替换符合条件的元素:

# numpy.where(condition[, x, y])
a = np.arange(10)
print(a)
print(np.where(a<5))
a = a.reshape((2,-1))
print(a)
print(np.where(a<5,a,2*a)) #改变数组,满足条件的元素不变,其他元素变为原来的两倍

6.2 筛选

筛选有3种方式,一是使用np.where()返回的python元组,二是使用逻辑表达式返回的布尔型数组,三是使用整型数组。

a = np.random.random((3,4))
print(a)
print(a[np.where(a>0.5)]) # 返回大于0.5的元素(使用np.where()返回的python元组)
print(a[(a>0.3)&(a<0.7)]) # 返回大于0.3且小于0.7的元素(使用逻辑表达式返回的布尔型数组)
print(a[np.array([2,1])]) # 返回整形数组指定的项(使用整型数组)
a = a.ravel()
print(a)
print(a[np.array([[3,5],[7,11]])]) # 返回整形数组指定的项(使用整型数组)

比如使用快速使用numpy得到灰度字符表

img = np.random.randint(0, 256, (5, 10), dtype=np.uint8) # 生成10x5的灰度图
print(img)
img = (img/32).astype(np.uint8) # 将256级灰度值转为8级灰度值
print(img)
chs = np.array([' ', '.', '-', '+', '=', '*', '#', '@']) # 灰度字符集
print(chs[img]) # 用整型数组筛选数组元素

7 数组的I/O

所谓数组I/O,就是讨论如何分发、交换数据。在机器学习算法模型的例子中,海量的训练数据通常都是从数据文件中读出来的,而数据文件一般是csv格式,NumPy 自带的csv文件读写函数,可以很方便的读写csv格式的数据文件。除了支持通用的csv格式的数据文件, NumPy 为数组对象引入了新的二进制文件格式,用于数据交换。后缀名为.npy 文件用于存储单个数组,后缀名为.npz 文件用于存取多个数组。

对csv格式文件的操作方法主要为:

1、loadtxt()

2、savetxt()

对npy或者npz格式文件的操作方法有:

1、load()

2、save()

3、savez()

对csv文件进行操作:

a = np.random.random((15,5))
np.savetxt('demo.csv', a, delimiter='\t') # 将数组a保存成CSV格式的数据文件
data = np.loadtxt('demo.csv', delimiter='\t') # 打开CSV格式的数据文件
print(data)
7.690719892083013320e-01    7.519683883565675409e-02   9.521626760626727970e-01
   
​

NumPy 自定义的数据交换格式也是一个非常好用的数据交换方式,使用它保存 NumPy 数组时不会丢失任何信息,特别是数据类型的信息。

例如:

single_arr_fn = 'single_arr.npy' # 存储单个数组文件名
multi_arr_fn = 'multi_arr.npz' # 存储多个数组文件名
lon = np.linspace(10,90,9)
lat = np.linspace(20,60,5)
np.save(single_arr_fn, lon) # 用save()函数把经度数组保存成.npy文件
lon = np.load(single_arr_fn) # 接着用load()函数读出来
np.savez(multi_arr_fn, longitude=lon, latitude=lat) #保存两个数组到一个文件
data = np.load(multi_arr_fn) # 用load()函数把这个.npz文件读成一个结构data
print(data.files) # 查看所有的数组名
print(data['longitude']) # 使用data[数组名],就可以取得想要的数据

### 使用 NumPy 拆分数组的方法 #### 方法一:水平拆分 `hsplit` 当需要将多维数组沿着水平轴(即行的方向)进行拆分时,`np.hsplit()` 函数是非常有效的工具。此函数接受两个参数:要被分割的数组以及指示切割次数或位置的整数或列表。 ```python import numpy as np arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15], [16, 17, 18]]) newarr = np.hsplit(arr, 3) print(newarr) ``` 上述代码会创建一个新的三维数组集合,每个子数组包含了原矩阵中的部分列[^2]。 #### 方法二:通用拆分 `split` 对于更灵活的需求,比如按照指定索引处切片或将整个数组均匀分配给若干个新数组的情况,则应考虑使用更为通用的 `np.split()` 函数。该函数同样适用于任何维度的数据结构,并允许用户自定义划分方式。 ```python import numpy as np # 创建一个简单的二维数组作为演示对象 data = np.arange(16).reshape((4, 4)) # 均匀地将其划分为四个相同大小的一维向量 result = np.split(data.flatten(), 4) print(result) ``` 这里展示了如何先展平原始数组再做均等分割的操作[^3]。 #### 方法三:垂直拆分 `vsplit` 如果目标是在竖直方向上对数组实施分区——也就是按照行来进行分离的话,那么应该选用 `np.vsplit()` 来完成这项工作。这与前面提到过的 `hsplit` 类似,只不过作用于不同的轴线上而已。 ```python import numpy as np matrix = np.random.rand(6, 3) * 100 sub_matrices = np.vsplit(matrix, 3) for i, sub_matrix in enumerate(sub_matrices): print(f'Sub-matrix {i}:') print(sub_matrix) ``` 这段脚本实现了随机生成的一个 \(6 \times 3\) 的浮点型数值表单被切成三个独立的小表格的过程。 #### 组合应用实例 有时可能还会遇到更加复杂的场景,例如既要在横向也要在纵向执行多次连续性的切割动作;此时可以通过组合运用这些基础命令来达成目的: ```python import numpy as np original_array = np.arange(24).reshape((6, 4)) horizontal_parts = np.hsplit(original_array, 2) final_result = [] for part in horizontal_parts: vertical_slices = np.vsplit(part, 3) final_result.extend(vertical_slices) for idx, slice_ in enumerate(final_result): print(f'Final Slice #{idx}:\n{slice_}') ``` 以上程序片段先是把输入的大矩形区域依据宽度劈成两半,接着又分别在这两份基础上进一步细分成更多小块[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值