前兩篇文章有介紹 Python 動態類型 共享引用,賦值和拷貝的原理,對 Python list 列表應該有一個深刻的了解。那麼 NumPy 中的 ndarray 數組和 list 列表有啥區別呢。更多 Python 進階系列文章,請參考 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
先通過代碼來了解一下:
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:存儲的是數組裡元素的值
一個指向數據(內存或內存映射文件中的一塊數據)的指針。
數據類型或 dtype,描述在數組中的固定大小值的格子。
一個表示數組形狀(shape)的元組,表示各維度大小的元組。
一個跨度元組(stride),其中的整數指的是為了前進到當前維度下一個元素需要"跨過"的字節數。
Python list:存儲的是 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]
我們通過例子來看一下 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]