关于numpy.array和列表list的区别

2023-10-19 11:05:56 浏览数 (1)

某一天写代码的时候突然遇到一个场景,需要批量对标注信息box进行操作(box包括[x1,y1,x2,y2])。

最简单的操作就是,for循环遍历将box一个一个存到list中最终转化为numpy的二维数组进行操作:

代码语言:javascript复制
bboxes = []
for k in range(num_objs):
    ann = anns[k]
    bbox = self._coco_box_to_bbox(ann['bbox'])
    # 构造array的时候需要 [[]] 二维方式构造
    sbbox = np.array([[bbox[0], bbox[1], bbox[2], bbox[3]]])
    bboxes.append(sbbox)

if bboxes != []:
    bboxes = np.concatenate(bboxes, 0)

需要注意的是我们在构造numpy数组的时候,需要提前把二维这个维度信息告诉np.array:

代码语言:javascript复制
>>> import numpy as np
>>> a = np.array([1,2,3,4])
>>> b = []
>>> b.append(a)
>>> b.append(a)
>>> b
[array([1, 2, 3, 4]), array([1, 2, 3, 4])]
>>> c = np.concatenate(b)
>>> c
array([1, 2, 3, 4, 1, 2, 3, 4])
>>> c.shape # 此时concat后的c还是一维的
(8,)
# 这样
>>> a = np.array([[1,2,3,4]])  # 需要提前指明2维
>>> b = []
>>> b.append(a)
>>> b.append(a)
>>> b
[array([[1, 2, 3, 4]]), array([[1, 2, 3, 4]])]
>>> c = np.concatenate(b)
>>> c
array([[1, 2, 3, 4],
       [1, 2, 3, 4]])
>>> c.shape # 此时concat后的维度才是2维
(2, 4)  

np.concatenate后bboxes的维度是(N,5),此时可以通过这种方式去批量处理x1,y1,x2,y2

代码语言:javascript复制
offset_x = 1
offset_y = 2
bboxes[:, 0] = bboxes[:, 0]   offset_x
bboxes[:, 1] = bboxes[:, 1]   offset_y
bboxes[:, 2] = bboxes[:, 2]   offset_x
bboxes[:, 3] = bboxes[:, 3]   offset_y

numpy的array可以这样操作,但是对于list来说是不行的:

代码语言:javascript复制
>>> a=[[1,2,3],[4,5,6]]
>>> a[0]    #取第一行是可以的
[1, 2, 3]
>>> a[:,0]  #尝试用数组索引方式失败
TypeError: list indices must be integers or slices, not tuple

这是因为python中的list和numpy中的array是完全不一样的两个东西,list可以存放不同类型的数据,比如int、float和str,甚至布尔型;而一个numpy数组中存放的数据类型必须全部相同,例如int或float。

在list中的数据类型保存的是数据的存放的地址,即指针而非数据(底层是C语言,这样想想也很正常),例如a=[1,2,3,4]需要4个指针和四个数据,增加了存储和消耗cpu,而a=np.array([1,2,3,4])只需要存放四个数据,读取和计算更加方便。

所以列表List可以存放不同类型的数据,因此列表中每个元素的大小可以相同,也可以不同,所以也就不支持一次性读取一列。即使是对于标准的二维数字列表([[1,2,3,4]]这种),所以纯数字的我们最好都使用numpy的数据类型去操作。

0 人点赞