请您帮忙解决以下问题。我希望按照方案构建 3 个 numpy 数组:
+---+
| a |
arr1 : +---+ +---+
| b | <- | b |
+---+ | |
+---+ : arr
+---+ | |
| c | <- | c |
arr2 : +---+ +---+
| d |
+---+
因此arr
与其他数组共享其值。
arr1
和 arr2
是由示例定义的经典 numpy 数组:
arr1 = np.array([1,2]); arr2 = np.array([3,4])
然后,我可以通过哪种方式构建 arr
以便具有行为
arr1[1] = 7 ### will give arr1 = [1,7] arr2 = [3,4] arr = [7,3]
arr[1] = 13 ### will give arr1 = [1,7] arr2 = [13,4] arr = [7,13]
?
我的测试
经过几个小时的网络测试,ctypes 功能似乎是模仿 Python 中 C 指针行为的解决方案。我已经尝试过这个:
import numpy as np
import ctypes
arr1 = np.array([1.0,0.2]).astype(np.float32)
arr2 = np.array([3.0,4.0]).astype(np.float32)
arr1_ptr = arr1.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
arr1bis = np.ctypeslib.as_array((ctypes.c_float * arr1.size).from_address(ctypes.addressof(arr1_ptr.contents)))
print(arr1bis) #### --> [ 1. 0.2]
arr1[0] = 7.0
print(arr1bis) #### --> [ 7. 0.2]
arr1bis[1] = 13.0
print(arr1) #### --> [ 7. 13.]
所以在这里我设法在同一个数组上有两个指针。但从多个内存位置构建一个数组似乎要困难得多。如果有人有想法......
感谢您的帮助。
编辑:我的测试 2 - 解决方案的开始
非常感谢您的回答。 大全局数组的想法是有用的,因为它比在每次修改副本时更新副本的双重存储的惰性解决方案更便宜。而且实现起来非常简单。以下性能测试代码
import numpy as np
from time import time
def benchmark(d_size,s_len):
print("Interraction domain size: ",d_size," state length: ",s_len)
arr_combined = np.arange(s_len*d_size**2).reshape((d_size,d_size,s_len))
list_of_state = [ np.ndarray.view(arr_combined[i,j,:]) for i in range(d_size) for j in range(d_size) ]
interraction_between_state = np.ndarray.view( arr_combined[:,:,0] )
t0 = time()
for state in list_of_state : state[0]+=1
interraction_between_state*= -1
for state in list_of_state : state[0]+=1
print( "Exec time with np.ndarray.view: ", time()-t0 )
list_of_state2 = [ np.arange(s_len)+s_len*(j+d_size*i) for i in range(d_size) for j in range(d_size) ]
interraction_between_state2 = np.array( [ state[0] for state in list_of_state2 ] ).reshape((d_size,d_size))
t0 = time()
for state in list_of_state2 : state[0]+=1
### Update interraction_between_state2
for i in range(d_size):
for j in range(d_size):
interraction_between_state2[i,j]= list_of_state2[j+d_size*i][0]
interraction_between_state2*= -1
### Update list_of_state2
for i in range(d_size):
for j in range(d_size):
list_of_state2[j+d_size*i][0] = interraction_between_state2[i,j]
for state in list_of_state2 : state[0]+=1
print("Exec time with array update: ", time()-t0 )
benchmark(100,5)
benchmark(1000,5)
benchmark(100,50)
给出
Interraction domain size: 100 state length: 5
Exec time with np.ndarray.view: 0.00500103759765625
Exec time with array update: 0.011001110076904297
Interraction domain size: 1000 state length: 5
Exec time with np.ndarray.view: 0.5620560646057129
Exec time with array update: 1.1111111640930176
Interraction domain size: 100 state length: 50
Exec time with np.ndarray.view: 0.0060007572174072266
Exec time with array update: 0.01200103759765625
因此,即使np.ndarray.view
给出的 View 生成非内存连续数据表示,与数据重复的解决方案相比,性能也更好。
但是
如果结构不一致(维度方面),如何将它们正确地放入全局数组中?例如,如果我回到第一个带有 arr
、arr1
和 arr2
的简单示例,并将 arr2
替换为
arr2 = np.array([3,4,5])
为了构建全局数组,我想到了两种解决方案:
- 将全局数组写在一行中。
global_arr = np.array([1,2,3,4,5])
如果arr1
和arr2
是二维或三维的,就会丢失一些结构,并且强制提前知道全局数组和局部 View 之间索引的对应关系。此外,任何子数组都将是内存连续的,因此应该需要一些补充测试来了解这种情况下性能的实际增益。
- 保留结构,并在被视为无效的单元格中添加
np.nan
值。
global_arr = np.array( [ [1,2,np.nan],
[3,4,5]])
您对这两种解决方案有何看法?还有另一种方法可以巧妙地构建这个全局数组吗?
最佳答案
我认为解决您问题的最简单方法是创建一个大数组,其中包含您想要操作的所有数据,然后您可以以任何您想要分组的方式创建数据的 View
它:
import numpy as np
arr_combined = np.array([1,2,3,4])
arr1 = np.ndarray.view(arr_combined[:2])
arr2 = np.ndarray.view(arr_combined[2:])
arr = np.ndarray.view(arr_combined[1:3])
这并不完全是您所要求的,但它至少使您可以按照您在示例中编写的方式访问数据。此外,当然这不仅限于四个元素的小情况,还可以用于具有数千个元素的用例。
关于Python numpy 数组之间共享指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45736951/