【问题标题】:How can I implement a dictionary with a NumPy array?如何使用 NumPy 数组实现字典?
【发布时间】:2016-12-19 16:54:40
【问题描述】:

我需要将大量数字-数字对写入 NumPy 数组。由于很多这些对的第二个值是 0,所以我想制作类似于字典的东西。问题是我已经阅读了有关结构化数组的 NumPy 文档,并且看起来像页面上那样构建的字典只能使用字符串作为键。

除此之外,我需要插入和搜索来获得 log(N) 复杂性。我曾想过使用常规的 NumPy 数组作为存储来制作我自己的红黑树结构,但我相当确定有一种更简单的方法来解决这个问题。

语言是 Python 2.7.12。

【问题讨论】:

  • 为什么需要专门使用 NumPy 数组?
  • @David Z 因为我使用的数据量太大而无法存储在 RAM 上。这就是为什么我需要将它提供给另一种数据类型(这个link),它支持直接写入硬盘驱动器的数据库。那东西本质上是一个 NumPy 数组,可以在需要时写入硬盘驱动器......
  • 啊,这是有用的信息(并包含在问题中)。如果有一个可以使这项任务变得更容易的话,它还提供了使用不同的大容量存储库的选项。
  • @DavidZ 好吧,使用另一个库并不是一个真正的选择,因为我必须在新系统上重做所有事情,这可以说比编写自己的包装器更困难。不管怎样,我会把这个留到下周去思考。希望有人有想法...

标签: python arrays numpy dictionary red-black-tree


【解决方案1】:

所以你有一个(N,2) 数组,x[:,1] 中的许多值都是 0。

insertion 是什么意思?向数组添加一个值以使其成为(N+1,2)?或者只是将x[i,:] 更改为新的东西?

那么搜索呢? numpy 数组非常适合查找第 i 个值 x[i,:],但不适用于查找匹配 z 的值。 python numpy filter two dimentional array by condition

scipy.sparse 实现了各种形式的稀疏矩阵,如果不到十分之一的可能值是非零的,这将很有用。一种格式是dok,一种键字典。它实际上是一个dict 子类,键是一个二维索引元组(i,j)。其他格式将它们的值存储为数组,例如行、列和数据。

structured arrays 适用于具有少量命名字段的情况,每个字段可以包含不同类型的数据。但我认为将 (N,2) 数组转换为具有 2 个字段的 (N,) 数组没有帮助。

=================

您的 cmets 表明您不熟悉 numpy 数组的存储或访问方式。

一个数组由一个平面一维data buffer(只是一个c字节数组)和shapestridesitemsizedtype等属性组成。

假设它是np.arange(100)

In [1324]: np.arange(100).__array_interface__
Out[1324]: 
{'data': (163329128, False),
 'descr': [('', '<i4')],
 'shape': (100,),
 'strides': (4,)
 'typestr': '<i4',
 'version': 3}

因此,如果我要求 x[50],它会计算步幅,4 个字节/元素,* 50 个元素 = 200 个字节,并在 c 代码中询问 163329128+200 的 4 个字节,然后返回它们作为整数(实际上是np.int32 类型的对象)。

对于结构化数组,每个元素的类型描述和字节数会更大,但访问权限是相同的。对于二维数组,它将考虑形状和跨步元组以找到适当的索引。

(N,2) 整数数组的步长为 (8,4)。所以对x[10,1] 元素的访问是使用10*8 + 1*4 = 84 偏移量。并且对x[:,1] 的访问是使用i*8 for i in range... 偏移量。

但在所有情况下,它都依赖于以矩形可预测模式排列的值。 numpy 数据结构没有什么特别之处。它们相对较快,仅仅是因为许多操作是在编译后的代码中编码的。

使用数组可以进行排序、按值访问项目和重新排列元素,但这不是强项。这些操作通常会生成一个新数组,其中的值以某种新模式从旧数组复制到新数组。

只有几个内置的numpy数组子类,主要是np.matrixnp.masked_array,它们没有扩展访问方法。子类化不像普通的 Python 类那么容易,因为它numpy 有一些自己的编译代码。子类必须有一个__new__ 方法,而不是常规的__init__

有一些 Python 模块维护排序列表,bisectheapq。但我看不出它们将如何帮助您解决大的内存溢出问题。

【讨论】:

  • 您可以说我想要一个 (N, 2) 数组,该数组按其第一个元素排序,这样它的插入和搜索复杂度为 O(logN)。通过插入,我的意思是向数组中添加一个新元素,以便它保持其排序状态。通过搜索,我的意思是找到索引,因此,在给定第一个值的情况下,找到元素的第二个值。我知道这是可能的,因为这是 Red-black trees 所做的,这也是 Python 字典的工作方式。我在问是否有具有这些属性的 numpy.array 的内置子类型,因为它具有索引...
  • NumPy's structured arrays page(指定名称而不是索引部分)中所述的元素。另外,我仅限于 NumPy 数组,所以没有 scipy 或其他库...
  • 我已经扩展了 numpy 数组的存储和访问方式。
【解决方案2】:

字典的最基本形式是称为HashMap 的结构。实现哈希图依赖于将您的键转换为可以快速查找的值。一个病态的例子是使用ints 作为键:键1 的值将进入array[1],键2 的值将进入array[2],哈希函数就是恒等函数。您可以使用 numpy 数组轻松实现。

如果您想使用其他类型,只需编写一个好的散列函数将这些键转换为数组中的 唯一 索引。例如,如果你知道你有一个 (int, int) 元组,并且第一个值永远不会超过 100,你可以使用 100*key[1] + key[0]

哈希函数的实现将决定您的字典替换成败。

【讨论】:

  • 是的,我明白了,我可以轻松地构建我的数组,以便快速找到值的位置,但插入是问题所在。如果我想保持数组排序,在插入后我需要将每个大于插入元素的元素向右移动,从而有效地使插入的复杂度为 O(n)。我需要达到 O(logN) 的复杂性,这可以使用红黑树(link 最好不需要自己编写...
猜你喜欢
  • 1970-01-01
  • 2014-10-28
  • 1970-01-01
  • 2016-12-17
  • 2014-05-18
  • 2016-01-08
  • 2018-09-07
  • 2017-06-03
  • 2016-03-15
相关资源
最近更新 更多