2016-07-27 15 views
1

データをbytearrayに最初にコピーせずにnumpy配列をハッシュしたいハッシュ可能numpyメモリビューを取得する

具体的には、一意の行を持つ連続した読み取り専用2次元int64 numpy配列Aがあります。具体的には、のは言わせて:

A = np.array([[1, 2], [3, 4], [5, 6]]) 
A.setflags(write=False) 

私はAのスライスに値が同じだ任意の配列apをマッピングし、一定時間関数を作りたい、例えばA[i]、そのインデックスiへ。例えば

lookup = {a: i for i, a in enumerate(A)} 

残念ながらnumpyの配列はハッシュ可能ではありません。

foo(np.array([1, 2])) == 0 
foo(np.array([3, 4])) == 1 
foo(np.array([5, 6])) == 2 

自然な選択のような辞書を作ることです。ハッシュnumpy配列にはwaysがありますが、理想的には、等価を保持して手動での衝突検出を行わずに辞書で使用できるようにしたいと思います。

参照記事は、私が何ができることを指摘ん:

lookup = {a.data.tobytes(): i for i, a in enumerate(A)} 

def foo(ap): 
    return lookup[ap.data.tobytes()] 

tobytes方法は、データのコピーを返します。ただし、したがって、メモリ使用量を倍増、a.dataで指されます。

私は何をしてみたいことのようなものです:は理想的、代わりに、配列オブジェクトまたはそのバイトのコピーの基本的なメモリへのポインタを使用していますが、a.dtype == int以来でしょう

lookup = {a.data: i for i, a in enumerate(A)} 

def foo(ap): 
    return lookup[ap.data] 

この

ValueError: memoryview: hashing is restricted to formats 'B', 'b' or 'c' 

これは結構ですが、私たちは今、我々が持っている、Aview = A.view(np.byte)それをキャストすることができます:これはで失敗

これをハッシュしようとしたとき

しかし、それはまだでエラー:

TypeError: unhashable type: 'numpy.ndarray' 

thisに触発された)可能な解決策を定義するには次のようになります。

class _wrapper(object) 
    def __init__(self, array): 
     self._array = array 
     self._hash = hash(array.data.tobytes()) 

    def __hash__(self): 
     return self._hash 

    def __eq__(self, other): 
     return self._hash == other._hash and np.all(self._array == other._array) 

lookup = {_wrapper(a): i for i, a in enumerate(A)} 

def foo(ap): 
    return lookup[_wrapper(ap)] 

しかし、これは洗練さそうです。 Pythonにメモリビューをbytearrayとして解釈させ、バイトスクリプトにコピーを作成するか、numpyを中断してハッシュを中止する必要なしに普通にハッシュするように指示する方法はありますか?

私が試した他のもの:

  1. Aのフォーマットは、私は異なる整数に各行をマッピングすることができないが、非常に大きなA可能アレイの空間がnp.iinfo(int).maxより大きい、及び私はPythonの整数型を使うことができますが、メモリをハッシングするよりも100倍遅いです。でもA.flags.writeable == FalseA[0].flags.writeable == Trueけれども、しかし

    Aview = A.view(np.void(A.shape[1] * A.itemsize)).squeeze()

  2. は、私はまた、のようなものをやってみました。試してみるとhash(A[0])のpythonはTypeError: unhashable type: 'writeable void-scalar'を発生させます。私はスカラーを読み取り専用としてマークすることが可能かどうか確信しています。そうでなければ、他のほとんどのスカラーがハッシュ可能なように見えるにもかかわらず、空のスカラーをハッシュします。

+0

配列全体をキーまたはその要素として使用しようとしていますか? – hpaulj

+0

@ hpaulj配列のスライスをハッシュしようとしています。私は、私がより明確にしたものを作るべきであるという質問に対する重要な更新を行った。 – Erik

答えて

-1

あなたは何をしようとしているのか分かりません。

私は配列を作成

In [111]: A=np.array([1,0,1,2,3,0,2]) 
In [112]: A.__array_interface__ 
Out[112]: 
{'data': (173599672, False), 
'descr': [('', '<i4')], 
'shape': (7,), 
'strides': None, 
'typestr': '<i4', 
'version': 3} 
In [113]: A.nbytes 
Out[113]: 28 
In [114]: id(A) 
Out[114]: 2984144632 

は、私はユニークな idndarrayオブジェクトを取得し、そして shapeなどの属性、および strides、および data buffer。このバッファは173599672から始まる28バイトです。

AにはA[3]オブジェクトはありません。私はそれ

In [115]: x=A[3] 
In [116]: type(x) 
Out[116]: numpy.int32 
In [117]: id(x) 
Out[117]: 2984723472 
In [118]: x.__array_interface__ 
Out[118]: 
{'__ref': array(2), 
'data': (179546048, False), 
'descr': [('', '<i4')], 
'shape':(), 
'strides': None, 
'typestr': '<i4', 
'version': 3} 

このxは、多くの方法である作成する必要がちょうど0D 1つの要素の配列(それは異なった表示します)。そのデータポインタはAのものとは無関係であることに注意してください。だから、メモリを共有することさえできません。

スライス共有メモリ

In [119]: y=A[3:4] 
In [120]: y.__array_interface__ 
Out[120]: 
{'data': (173599684, False), # 173599672+3*4 
'descr': [('', '<i4')], 
'shape': (1,), 
'strides': None, 
'typestr': '<i4', 
'version': 3} 

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

あなたがマッピングarbitrary A[i] to its B[i]によって正確に何を意味するのでしょうか?キーとしてA[i]の値を使用していますか、キーとしての位置はありますか?私の例では、Aの要素は一意ではありません。私はA[0]またはA[2]に(索引によって)一意的にアクセスできますが、どちらの場合も1という値が得られます。

しかし、この状況を考えてみましょう。 1d配列の値を見つけるには比較的速い方法があります - in1d

In [121]: np.in1d(A,1) 
Out[121]: array([ True, False, True, False, False, False, False], dtype=bool) 

Bアレイ作る:

In [123]: B[np.in1d(A,1)] 
Out[123]: array([0, 2]) 
In [124]: B[np.in1d(A,0)] # to 0 
Out[124]: array([1, 5]) 
In [125]: B[np.in1d(A,2)] # to 2 
Out[125]: array([3, 6]) 

Aから作成された辞書は、(最後の)同じを与える:A1値に対応B

In [122]: B=np.arange(A.shape[0]) 

すべての要素値:

In [134]: dict(zip(A,B)) 
Out[134]: {0: 5, 1: 2, 2: 6, 3: 4} 

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

__hash__方法を有することが必要についてはPythonのドキュメントの会談でhashableについての段落。

だから私は、オブジェクトをチェックする:

In [200]: {}.__hash__ # None 
In [201]: [].__hash__ # None 
In [202]:().__hash__ 
Out[202]: <method-wrapper '__hash__' of tuple object at 0xb729302c> 

In [204]: class MyClass(object): 
    ...:  pass 
    ...: 
In [205]: MyClass().__hash__ 
Out[205]: <method-wrapper '__hash__' of MyClass object at 0xb3008c4c> 

numpy整数を - np.int32ラッパーとINT:

In [206]: x 
Out[206]: 2 
In [207]: x.__hash__ 
Out[207]: <method-wrapper '__hash__' of numpy.int32 object at 0xb1e748c0> 
In [208]: x.__hash__() 
Out[208]: 2 

numpyの配列

In [209]: A 
Out[209]: 
array(['one', 'two'], 
     dtype='<U3') 
In [210]: A.__hash__ # None 

In [212]: np.float(12.232).__hash__() 
Out[212]: 1219767578 

ので、最低でもキー辞書のためには、hash、ユニークなideを生成する方法が必要ですntifier。インスタンスid(デフォルトの場合)か、オブジェクトの値(何らかのチェックサム?)から派生したものかもしれません。辞書はこれらのハッシュのテーブルを保持しており、おそらくkeyvalueの両方を指すポインタである。辞書getを実行すると、与えられたオブジェクトのハッシュが生成され、それを検索し、対応する値があればそれを返します。

ハッシュ可能でないクラスには、__hash__メソッドがありません(またはメソッドはNoneです)。彼らはこの一意のIDを生成することはできません。明らかに、クラスnp.ndarrayのオブジェクトには、__hash__がありません。そして、writabilityフラグで遊んでもそれは変わりません。

配列の行のハッシュや辞書を作成しようとすると大きな問題は、配列の特定のインスタンス(スライスビューで作成されたオブジェクト)をハッシュすることには関心がありませんが、ハッシュベースその行の値について調べます。

だからあなたの2D配列取る:

In [236]: A 
Out[236]: 
array([[1, 2], 
     [3, 4], 
     [5, 6]]) 

をあなたはA[1,:]をしたい、との両方にnp.array([3,4])は同じ__hash__()値を生成します。 A[0,:]+2、そしておそらくA.mean(axis=0)(これは浮動小数点配列です)。

メモリが不安なので、非常に大きな配列、たとえば(1000,1000)を扱う必要があります。これは1000個の異なる数字に基づいたハッシュ値と、いくつかのユニークな方法を意味します。

+0

ご協力ありがとうございます。私は重要な側面を見逃しました。つまり、Aは2次元なので、インデックスを作成しているものは、共有メモリを持つスライスです。質問への私の編集はもっとはっきりしているはずです。また、 'np.in1d'は' O(A.shape [0]) 'なので十分な解決策ではありません。私はその次元で一定の時間を探しています。私がそうでなかったら、 'np.in1d'よりも各行をvoid型にキャストすることになります。 – Erik

+0

これは '一意の行'問題のように見え始めています。それは以前に起こったことです。これを見る別の方法は、タプルのリストです。タプルはハッシュ可能です。スパース 'dok'形式では、2つの要素タプルを辞書サブクラスのキーとして使用します。 – hpaulj

+0

それは確かにユニークな行の問題に似ていますが、重要な違いがあります。ユニークな行は、void型にキャストしてから 'np.unique'を使うことでかなり簡単に作成できます。私はこれらの行が一意であることを知っていますが、メモリコピーなしでそれらをハッシュしたいと思います。 'a.data.tobytes()'に加えて私は 'tuple(a)'を確かに行うことができましたが、それはメモリオーバヘッドよりも大きくないでしょう。 – Erik

関連する問題