【问题标题】:numpy ndarray buffer is too small for requested arraynumpy ndarray 缓冲区对于请求的数组来说太小了
【发布时间】:2021-04-20 22:13:34
【问题描述】:

我正在尝试使用结构化的 numpy 数组设置共享内存缓冲区。

如果我只使用 (datetime's, int's, float's) 或 (string's, int's, float's) 我没有问题。但是,如果我尝试使用 (string's, datetime's, int's, float's),我会遇到“TypeError: buffer is too small for requested array”错误。

想知道为什么这不起作用。任何帮助表示赞赏。

这行得通:

import numpy as np
from datetime import datetime

N_list_size = 100_000

a = [
     (datetime.now(), 
      np.uint64(1234), 
      np.float64("123.4"))
] * N_list_size

np_array = np.ndarray(shape=(N_list_size,),
                      buffer=np.array(a),
                      dtype=[
                              ('a', np.datetime64),
                              ('b', np.uint64),
                              ('c', np.float64),
                      ])

shape, dtype = np_array.shape, np_array.dtype
print(f"np_array's size = {np_array.nbytes / 1e6}MB")
print(f"np_array's dtype = {dtype}")

这也有效:

import numpy as np
from datetime import datetime

N_list_size = 100_000

a = [
     ("d50ec984-77a8-460a-b958-66f114b0de9b", 
      np.uint64(1234), 
      np.float64("123.4"))
] * N_list_size

np_array = np.ndarray(shape=(N_list_size,),
                      buffer=np.array(a),
                      dtype=[
                              ('a', np.str_, 36),
                              ('b', np.uint64),
                              ('c', np.float64),
                      ])

shape, dtype = np_array.shape, np_array.dtype
print(f"np_array's size = {np_array.nbytes / 1e6}MB")
print(f"np_array's dtype = {dtype}")

这不起作用:

import numpy as np
from datetime import datetime

N_list_size = 100_000

a = [
     ("d50ec984-77a8-460a-b958-66f114b0de9b", 
      datetime.now(),
      np.uint64(1234), 
      np.float64("123.4"))
] * N_list_size

np_array = np.ndarray(shape=(N_list_size,),
                      buffer=np.array(a),
                      dtype=[
                              ('a', np.str_, 36),
                              ('b', np.datetime64),
                              ('c', np.uint64),
                              ('d', np.float64),
                      ])

shape, dtype = np_array.shape, np_array.dtype
print(f"np_array's size = {np_array.nbytes / 1e6}MB")
print(f"np_array's dtype = {dtype}")

失败:

TypeError: buffer is too small for requested array

为什么在这里同时使用日期时间和字符串会导致问题?

如何解决这个问题?

【问题讨论】:

  • 不确定,但指定日期时间的单位似乎可行:np_array = np.array(a, dtype=[('a', 'U36'), ('b', 'datetime64[m]'), ('c', np.uint64), ('d', np.float64)])
  • 您也可以使用日期的字符串表示,而不是使用 python 的日期时间。只需使用str(datetime.now()) 而不是datetime.now()。使用日期时间作为字符串通常更方便 imo
  • datetune.now() 创建一个 Python 数据时间对象。这与 np.datetime64 元素不同。
  • 当我尝试显示第一个 np_array(对于少数元素)时,我收到一个关于通用 datetime64 显示的 ValueError。即使我纠正了我仍然得到相对无意义的值显示。
  • np.array(a) 创建一个对象 dtype 数组。也就是说,它包含指向内存中其他位置的对象的指针。您无法将这些指针有意义地视为float64int 等。测试这是非常小的数组,您可以详细检查这些数组。仅仅检查 shape 和 dtype 是不够的!

标签: python numpy shared-memory numpy-ndarray


【解决方案1】:

本着让事情顺利进行的精神,并基于@Kevin 的评论,以下简单的日期时间固定长度字符串表示(例如 datetime.isoformat())当然有效:

import numpy as np
from datetime import datetime

N_list_size = 100_000

a = [
     ("d50ec984-77a8-460a-b958-66f114b0de9b", 
      datetime.now().isoformat(),
      np.uint64(1234), 
      np.float64("123.4"))
] * N_list_size

dtype=[
    ('a', 'U36'),
    ('b', 'U25'),
    ('c', np.uint64),
    ('d', np.float64),
]

np_array = np.ndarray(shape=(N_list_size,),
                      buffer=np.array(a,dtype=dtype),
                      dtype=dtype)

shape, dtype = np_array.shape, np_array.dtype
print(f"np_array's size = {np_array.nbytes / 1e6}MB")
print(f"np_array's dtype = {dtype}")

输出:

np_array's size = 28.4MB
np_array's dtype = [('a', '<U36'), ('b', '<U25'), ('c', '<u8'), ('d', '<f8')]

【讨论】:

  • 所以它运行了。但是这些值看起来合理吗?比较 np.array(a)[0]np_array[0]。你在后面看到1234 吗?更好的是,看看下一个元素,[1]。
  • @hpaulj 仅当您将 np.array(a,dtype=dtype) 复制到 np_array 时,值才会相同(例如 np.copyto(np_array, np.array(a,dtype=dtype) ))。对我来说重要的部分是确保我得到正确的内存大小,以便我可以使用带有 np_array 的多处理共享内存缓冲区。
  • 我错过了您现在使用 dtype 来创建缓冲区的事实:np.array(a,dtype=dtype)。但是如果你这样做,那么使用ndarray 有什么意义呢?另外,现在我认为您的dtype 可以毫无问题地包含datetime64[n]。您最初的问题是因为 np.array(a)objectU32 结尾,缓冲区大小错误(太大或太小)。
  • @hpaulj 我使用 ndarray 的主要原因本质上是为了让共享内存缓冲区的内存大小正确,类似于这里所做的 (mingze-gao.com/posts/python-shared-memory-in-multiprocessing)
  • np.zeros(N_list_size, dtype=dtype) 创建一个大小合适的数组。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多