从 b.diagonal() 获得的 ndarray a 在 b 修改后其值发生了变化

问题描述 投票:0回答:1

我对下面代码的行为有点困惑,想知道是否有人可以解释这一点。基本上,我有一个名为

mat
的矩阵,它是一个 numpy
ndarray
。我使用
mat.diagonal()
获取它的对角线并将其分配给变量
diag
。我把
mat
的所有对角线值都改为100。现在我发现
diag
的值也全部改为100,这似乎表明
diag
直接引用了
mat
中的元素。然而,当我检查
dia
g 中第一个元素的内存地址并将其与
mat
的内存地址进行比较时,它们是不同的。正确的看待这个问题的方法是什么?

import numpy as np
import pandas as pd

mat_df = pd.DataFrame(data=[[1,2,3], [4,5,6], [7,8,9]])
print(mat_df)

mat = mat_df.values
diag = mat.diagonal()
print(diag)
diag_loc = np.diag_indices_from(mat)
mat[diag_loc] = 100
print(diag)

print(diag[0])
print(id(diag[0]))
print(mat[0][0])
print(id(mat[0][0]))

mat

   0  1  2
0  1  2  3
1  4  5  6
2  7  8  9

diag

[1 5 9]

diag
的值会因
mat
的变化而变化:

[100 100 100]

diag
的第一个值:

100

及其地址

139863357577488

mat的第一个值:

100

及其地址

139863376059664
python numpy numpy-ndarray
1个回答
1
投票

您无法通过

id
知道地址。首先,
id
不返回地址(尽管如此,CPython 实现使用内存地址来构建
id
,这只是一种实现,并且本身不是地址)。其次,这只是 python 对象的地址(在您的情况下是包装
numpy.int64
的地址)。

该 python 对象只是为了包装任何 numpy 函数(对 python 不透明:python 不知道它们何时应该返回相同的值)返回而构建。

您可以做一些简单的实验来说服自己,您的

id
毫无意义

id(diag[0])
# 139729998312368
id(diag[0])
# 139730045496016

看,即使是连续两次完全相同的调用也不会返回相同的 id!

diag[0]
是对 numpy 的
diag.__getitem__(0)
的调用。包装到每次都不同的 python 容器中,就像调用任何函数
f(0)
的结果一样,没有理由假设每个相同的调用都会返回完全相同的结果。

因此,如果你想知道实际的

int64
存储在哪里,你不能问 python(及其
id
函数),因为这不仅是现在
id
的用途,而且更重要的是,python 不这样做我不知道。
int64
存储在哪里是 numpy 库的内部问题。所以你需要问numpy。

最好的方法是使用

base
恕我直言。

diag.base
#array([[100,   2,   3],
#       [  4, 100,   6],
#       [  7,   8, 100]])
diag.base is mat.base
# True

但是,如果您坚持拥有某种地址,您也可以

diag.ctypes.data
# 61579664
mat.ctypes.data
# 61579664

或者,有关查看哪些数据以及如何通过数组查看数据的更完整信息

mat.__array_interface__
# {'data': (61579664, False), 'strides': (8, 24), 'descr': [('', '<i8')], 'typestr': '<i8', 'shape': (3, 3), 'version': 3}
diag.__array_interface__
# {'data': (61579664, True), 'strides': (32,), 'descr': [('', '<i8')], 'typestr': '<i8', 'shape': (3,), 'version': 3}

展示了两者如何使用相同的“数据”但使用不同的“步幅”和“形状”来使用它。

© www.soinside.com 2019 - 2024. All rights reserved.