内存分配如何在 numpy 数组中发生?

how does memory allocation occur in numpy array?

import numpy as np

a = np.arange(5)

for i in a:
    print("Id of {} : {} \n".format(i,id(i)))

>>>>

0 的 ID : 2295176255984

1 的 ID:2295176255696

2 的 ID:2295176255984

3 的 ID:2295176255696

ID 为 4:2295176255984

我想了解 numpy 数组的元素是如何在内存中分配的,我的理解与看到输出的 Python 数组不同。

感谢任何帮助。

我是 Code with Mosh 的粉丝。他在他的 YouTube 频道和 udemy 上教授所有此类内容。我已经购买了他关于数据结构和算法的 udemy 课程,该课程深入探讨了某些事物的工作原理。 例如,在教授数组时,他展示了如何制作数组以了解其背后的基本概念。

你可以看这里:https://www.youtube.com/watch?v=BBpAmxU_NQo

如果您只想了解 NumPy 数组:

首先我会告诉你不同之处:

NumPy 和数组的区别

Numpy 是 Python 中科学计算的核心库。它提供了一个高性能的多维数组对象和用于处理这些数组的工具。 NumPy 数组是值的网格,所有类型都相同,并由非负整数元组索引。维数是数组的秩;数组的形状是一个整数元组,给出数组沿每个维度的大小。

Python 核心库提供了列表。列表是数组的 Python 等价物,但可以调整大小并且可以包含不同类型的元素。

一个常见的初学者问题是这里真正的区别是什么。答案是性能。 Numpy 数据结构在以下方面表现更好:

大小 - Numpy 数据结构占用更少 space 性能——他们需要速度并且比列表更快 功能 - SciPy 和 NumPy 具有优化的功能,例如内置的线性代数运算。

另一个重要的显着区别在于它们存储和使用内存的方式 内存

使用 NumPy 数组的主要好处应该是更少的内存消耗和更好的运行时行为。

对于 Python 列表 - 我们可以由此得出结论,对于每个新元素,我们需要另外八个字节来引用新对象。新的整数对象本身占用 28 个字节。

NumPy 占用较少space。这意味着 NumPy 中长度为“n”的任意整数数组需要

如果你很好奇,想让我证明 NumPy 真的花更少的时间:

# importing required packages 
import numpy 
import time 

# size of arrays and lists 
size = 1000000

# declaring lists 
list1 = range(size) 
list2 = range(size) 

# declaring arrays 
array1 = numpy.arange(size) 
array2 = numpy.arange(size) 

# capturing time before the multiplication of Python lists 
initialTime = time.time() 

# multiplying elements of both the lists and stored in another list 
resultantList = [(a * b) for a, b in zip(list1, list2)] 

# calculating execution time 
print("Time taken by Lists to perform multiplication:", 
    (time.time() - initialTime), 
    "seconds") 

# capturing time before the multiplication of Numpy arrays 
initialTime = time.time() 

# multiplying elements of both the Numpy arrays and stored in another Numpy array 
resultantArray = array1 * array2 

# calculating execution time 
print("Time taken by NumPy Arrays to perform multiplication:", 
    (time.time() - initialTime), 
    "seconds") 

输出:

Time taken by Lists : 0.15030384063720703 seconds
Time taken by NumPy Arrays : 0.005921125411987305 seconds

等等..也有一个很大的缺点:

需要连续分配内存 - 插入和删除操作可能会变得代价高昂,因为数据存储在连续的内存位置,因为移动它需要移动。

如果您想了解更多关于 numpy 的信息: https://www.educba.com/introduction-to-numpy/

你以后可以感谢我!

In [68]: arr = np.arange(5)
In [69]: arr
Out[69]: array([0, 1, 2, 3, 4])

查看 numpy 数组属性的一种方法是:

In [70]: arr.__array_interface__
Out[70]: 
{'data': (139628245945184, False),
 'strides': None,
 'descr': [('', '<i8')],
 'typestr': '<i8',
 'shape': (5,),
 'version': 3}

data 类似于其数据缓冲区的 id,其中实际存储了值。我们不能在其他代码中使用这个数字,但它在检查 view 之类的东西时很有用。其余部分用于解释这些值。

arrmemory 是一个 c 数组,长度为 40 字节 (5*8)。那个地方对我们来说并不重要。 arr 中的任何 view 都将使用相同的数据缓冲区。 copy 将有自己的数据缓冲区。

迭代数组就像一个一个地访问值:

In [71]: i = arr[1]
In [72]: i
Out[72]: 1
In [73]: type(i)
Out[73]: numpy.int64

i 不是对 a 元素的引用。它是具有 相同值 的新对象。它很像一个 0d 数组,具有许多相同的属性,包括:

In [74]: i.__array_interface__
Out[74]: 
{'data': (25251568, False),
 'strides': None,
 'descr': [('', '<i8')],
 'typestr': '<i8',
 'shape': (),
 'version': 3,
 '__ref': array(1)}

这就是为什么在迭代中查看 id 没有多大意义。这也是为什么在 numpy 数组上迭代比在列表上迭代慢。我们强烈反对这样的迭代。

将其与列表进行对比,列表中的元素通过 reference:

存储(在某种数据缓冲区中)
In [78]: a,b,c = 100,'b',{}
In [79]: id(a)
Out[79]: 9788064
In [80]: alist=[a,b,c]
In [81]: id(alist[0])
Out[81]: 9788064

该列表实际上包含 a,或者如果您更喜欢对变量 a 引用的同一对象的引用。请记住,Python 一直是面向对象的。

总之,Python 列表包含引用。 Numpy 数组包含值,它自己的方法可以访问和操作这些值。有一个包含引用的对象数据类型,但我们不要去那里。