引言
前两篇文章有介绍 Python 动态类型 共享引用,赋值和拷贝的原理,对 Python list 列表应该有一个深刻的了解。那么 NumPy 中的 ndarray 数组和 list 列表有啥区别呢。更多 Python 进阶系列文章,请参考 Python 进阶学习 玩转数据系列
内容提要:
- Python 中不同类型的内存需求
- NumPy ndarray Vs. Python list 内存需求
- NumPy ndarray Vs. Python list 结构
- NumPy ndarray Vs. Python list 计算
- NumPy subarray Vs. Python sublist
- NumPy ndarray Vs. Python list 总结
Python 中不同类型的内存需求
一个变量被赋值成不同类型的值,它在内存中的存储需求也是不一样的。如下:
from sys import getsizeof as byte_size
x = 5
print("byte size of int_type:{}".format(byte_size(x)))
x = 'hello'
print("byte size of str_type:{}".format(byte_size(x)))
x = True
print("byte size of bool_type:{}".format(byte_size(x)))
x = 5.0
print("byte size of float_type:{}".format(byte_size(x)))
输出:
byte size of int_type:28
byte size of str_type:54
byte size of bool_type:28
byte size of float_type:24
list 中每个元素所占用内存大小取决于每个元素的类型,如下:
from sys import getsizeof as byte_size
list_object = ['Five', 5, 5.0, True]
print("byte size of list_object:{}".format(byte_size(list_object)))
print("byte size of each list item in list_object:{}".format([byte_size(item) for item in list_object]))
print("total byte size of list items in list_object:{}".format(sum([byte_size(item) for item in list_object])))
输出:
byte size of list_object:96
byte size of each list item in list_object:[53, 28, 24, 28]
byte total size of list items in list_object:133
NumPy ndarray Vs. Python list 内存的需求
先通过代码来了解一下:
from sys import getsizeof as byte_size
import numpy as np
list_object = [1,2,3,4,5,6]
np_array = np.array(list_object, dtype='int16')
print("list_object:{}".format(list_object))
print("byte size of list_object:{}".format(byte_size(list_object)))
print("byte size of each list item in list_object:{}".format([byte_size(item) for item in list_object]))
print("total byte size of list items in list_object:{}\n".format(sum([byte_size(item) for item in list_object])))
print("np_array:{}".format(np_array))
print("byte size of each item in np_array:{}".format([item.nbytes for item in np_array]))
print("total byte size of items in np_array:{}".format(np_array.nbytes))
输出:
可见 NumPy array 数组所需内存更少
list_object:[1, 2, 3, 4, 5, 6]
byte size of list_object:112
byte size of each list item in list_object:[28, 28, 28, 28, 28, 28]
total byte size of list items in list_object:168
np_array:[1 2 3 4 5 6]
byte size of each item in np_array:[2, 2, 2, 2, 2, 2]
total byte size of items in np_array:12
NumPy ndarray Vs. Python list 结构:
NumPy ndarray:存储的是数组里元素的值
一个指向数据(内存或内存映射文件中的一块数据)的指针。
数据类型或 dtype,描述在数组中的固定大小值的格子。
一个表示数组形状(shape)的元组,表示各维度大小的元组。
一个跨度元组(stride),其中的整数指的是为了前进到当前维度下一个元素需要"跨过"的字节数。
Python list:存储的是 list 元素的引用,即内存地址,不是值
NumPy ndarray Vs. Python list 计算:
NumPy ndarry 可以进行数据间的算术运算。
Python list 之间不可以直接进行算术运算
import numpy as np
list_object = [1,2,3,4,5,6]
np_array = np.array(list_object, dtype='int16')
list_object_plus= list_object + list_object
np_array_plus = np_array + np_array
np_array_minus = np_array - np_array
np_array_divide = np_array / np_array
np_array_multi = np_array * np_array
print("list_object:{}".format(list_object))
print("list_object + list_object:{}\n".format(list_object_plus))
print("np_array:{}".format(np_array))
print("np_array + np_array:{}".format(np_array_plus))
print("np_array - np_array:{}".format(np_array_minus))
print("np_array * np_array:{}".format(np_array_divide))
print("np_array / np_array:{}".format(np_array_multi))
输出:
list_object:[1, 2, 3, 4, 5, 6]
list_object + list_object:[1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]
np_array:[1 2 3 4 5 6]
np_array + np_array:[ 2 4 6 8 10 12]
np_array - np_array:[0 0 0 0 0 0]
np_array * np_array:[1. 1. 1. 1. 1. 1.]
np_array / np_array:[ 1 4 9 16 25 36]
NumPy subarray Vs. Python sublist
我们通过例子来看一下 subarray 和 sublist 的不同
import numpy as np
list_object = [1,2,3,4,5,6]
np_array = np.array(list_object, dtype='int16')
list_object_sub = list_object[0:4]
np_array_sub = np_array[0:4]
print("origin list_object:{}".format(list_object))
print("origin np_array:{}".format(np_array))
print("origin list_object_sub:{}".format(list_object_sub))
print("origin np_array_sub:{}".format(np_array_sub))
list_object_sub[0] = 0
np_array_sub[0] = 0
print("after changed list_object_sub:{}".format(list_object_sub))
print("after changed np_array_sub:{}".format(np_array_sub))
print("list_object:{}".format(list_object))
print("np_array:{}".format(np_array))
输出:
可以看出 NumPy subarray 就是一个原 array 的一个视图,它的改变会影响到原 array。而 Python sublist 其实是原 list 的一个浅copy,它的改动不会影响到原list。
origin list_object:[1, 2, 3, 4, 5, 6]
origin np_array:[1 2 3 4 5 6]
origin list_object_sub:[1, 2, 3, 4]
origin np_array_sub:[1 2 3 4]
after changed list_object_sub:[0, 2, 3, 4]
after changed np_array_sub:[0 2 3 4]
list_object:[1, 2, 3, 4, 5, 6]
np_array:[0 2 3 4 5 6]
NumPy ndarray Vs. Python list 总结:
NumPy Array | Python List | |
创建时size | 创建 array时,size是固定的,一旦改变size,原来的array会被删除,重新创建一个新的array | list 的size可以动态变化 |
存储方式 | 连续内存空间 | 不连续内存空间 |
item 内存 | 每个item所占内存一样 | 每个item所占内存可以不一样 |
item 类型 | 每个item 类型必须一致 | 每个item类型可以不一样 |
总体内存 | 内存占用较少 | 内存占用比较多用来支持动太类型 |
矢量计算 | 直接支持大量数学计算 | 不直接支持 |