2016-04-15 4 views
2

このように動作させるラッパークラスを作成するにはどうすればよいですか?numpy配列をkwarg-splattingする

def foo(a, b): 
    print a 

data = np.empty(20, dtype=[('a', np.float32), ('b', np.float32)]) 

data = my_magic_ndarray_subclass(data) 

foo(**data[0]) 

いくつかのより多くの背景:

は私がベクトル化したかった。このような関数のペアを持っていた:

def start_the_work(some_arg): 
    some_calculation = ... 
    something_else = ... 

    cost = some_calculation * something_else 

    return cost, dict(
     some_calculation=some_calculation, 
     some_other_calculation=some_other_calculation 
    ) 

def finish_the_work(some_arg, some_calculation, some_other_calculation): 
    ... 

start_the_workはの束と呼ばれることを意図して異なる議論が行われ、最低原価項目が完成する。同じ計算の多くは両方の機能によって使用されているので、辞書やkwarg-スプラッティングは、その結果に渡すために使用される次のように私はそれらをベクトル化することができ

def run(): 
    best, best_cost, continuation = min(
     ((some_arg,) + start_the_work(some_arg) 
     for some_arg in [1, 2, 3, 4]), 
     key=lambda t: t[1] # cost 
    ) 
    return finish_the_work(best, **continuation) 

一つの方法は次のとおりです。

def start_the_work(some_arg): 
    some_calculation = ... 
    something_else = ... 

    cost = some_calculation * something_else 

    continuation = np.empty(cost.shape, dtype=[ 
     ('some_calculation', np.float32), 
     ('some_other_calculation', np.float32) 
    ]) 
    continuation['some_calculation'] = some_calculation 
    continuation['some_other_calculation'] = some_other_calculation 

    return cost, continuation 

しかし、辞書のように見えても、continuationはkwarg-splattedできません。

+0

'FOO(*データ[0])'ので動作します構造化配列のレコードは、タプルのように(反復の目的で)動作します。 – hpaulj

+0

クラスは '** kwarg'として動作するためにどのような振る舞いをする必要がありますか? – Eric

+0

その質問に対する答えは 'keys()'と '__getitem__'です。 – Eric

答えて

2

それは正確に何をしたいことが、パンダのデータフレームに配列をラップすると、このような何かができないことがあります。パンダの主要指標が列ではなくなるためデータフレームが転置されていることを

import pandas as pd 

def foo(a, b): 
    print(a) 

data = np.empty(20, dtype=[('a', np.float32), ('b', np.float32)]) 

data = pd.DataFrame(data).T 

foo(**data[0]) 
# 0.0 

は注意を、行

+0

それは知っておく価値があります、ありがとう!私はパンダが本当に私がやっていることのほとんどのためにあまりにも右だとは思わない – Eric

1

構造化配列のフィールドに名前でアクセスでき、辞書の項目として渡すことができると考えていますか?辞書に変換

In [26]: x=np.ones((3,),dtype='i,f,i') 

In [27]: x 
Out[27]: 
array([(1, 1.0, 1), (1, 1.0, 1), (1, 1.0, 1)], 
     dtype=[('f0', '<i4'), ('f1', '<f4'), ('f2', '<i4')]) 

In [28]: x['f0'] 
Out[28]: array([1, 1, 1]) 

作品:

In [29]: dd={'f0':x['f0'], 'f1':x['f1'], 'f2':x['f2']} 

In [30]: def foo(**kwargs): 
    ...:  print kwargs 
    ...:  

In [31]: foo(**dd) 
{'f0': array([1, 1, 1]), 'f1': array([ 1., 1., 1.], dtype=float32), 'f2': array([1, 1, 1])} 

In [32]: foo(**x) # the array itself won't work 
... 
TypeError: foo() argument after ** must be a mapping, not numpy.ndarray 

または辞書内包表記を使用して:

In [34]: foo(**{name:x[name] for name in x.dtype.names}) 
{'f0': array([1, 1, 1]), 'f1': array([ 1., 1., 1.], dtype=float32), 'f2': array([1, 1, 1])} 

**kwargs.keys()メソッドを持つオブジェクトに依存してもよいです。配列はありません。


構造化された配列の要素がnp.voidです:

In [163]: a=np.array([(1,2),(3,4)],dtype='i,i') 

In [164]: a[0] 
Out[164]: (1, 2) 

In [165]: type(a[0]) 
Out[165]: numpy.void 

それはDTYPEと名前を持っている:あなたの配列のサブクラス、view

In [166]: a[0].dtype.names 
Out[166]: ('f0', 'f1') 

In [167]: [{k:b[k] for k in b.dtype.names} for b in a] 
Out[167]: [{'f0': 1, 'f1': 2}, {'f0': 3, 'f1': 4}] 

このkeysがあります

class spArray(np.ndarray): 
    def keys(self): 
     return self.dtype.names 

In [171]: asp=a.view(spArray) 

In [172]: asp 
Out[172]: 
spArray([(1, 2), (3, 4)], 
     dtype=[('f0', '<i4'), ('f1', '<i4')]) 

In [173]: asp.keys() 
Out[173]: ('f0', 'f1') 

このクラスを構築する他の方法は機能しません(つまり、ダイレクトコール) - それはサブクラス化の複雑さの一部ですndarray

def foo(**kwargs): 
    print kwargs 

In [175]: foo(**asp) 
{'f0': spArray([1, 3]), 'f1': spArray([2, 4])} 

In [176]: foo(**asp[0]) 
... 
TypeError: foo() argument after ** must be a mapping, not numpy.void 

In [177]: foo(**asp[[0]]) 
{'f0': spArray([1]), 'f1': spArray([2])} 

アレイをスプラッティング、又はそれから抽出された1個の素子アレイは動作するが、要素は、この場合にはnp.void要素がありません。それはkeyメソッドを持っていません。

配列のようにサブクラス化np.voidを試しました。定義を受け入れます。しかし、私はそのようなオブジェクトを作成する方法を見つけることができません。

+0

ここの問題は、 kwarg splattable型が期待されており、そのコードは辞書が返されたときにも動作し続ける必要があります。代わりに 'data.view(my_class)'でkwargs-splattingを追加できるかどうか疑問に思っています – Eric

+0

'ndarray'クラスを新しいメソッドまたは変更されたメソッドで変更するのは大変です。しかし、この配列を他の方法で辞書変換に実装することができます。スタンドアロン関数、ラッパークラスのメソッドなど – hpaulj

0

これはほとんど動作します:

class SplattableArray(np.ndarray): 
    def keys(self): 
     return self.dtype.names 

data = np.empty(20, dtype=[('a', np.float32), ('b', np.float32)]) 
data_splat = data.view(SplattableArray) 

def foo(a, b): 
    return a*b 

foo(**data_splat) # works! 
foo(**data_splat[0]) # doesn't work :(

我々はひどい人であることが喜んでいる場合は、この作品:

from forbiddenfruit import curse 
import numpy as np 

def keys(obj): 
    return obj.dtype.names 

curse(np.void, 'keys', keys) 
curse(np.ndarray, 'keys', keys) 

data = np.empty(10, dtype='i,i') 
def foo(**kwargs): 
    return kwargs 

foo(**data[0]) 
foo(**data) 
+0

私はこの変更のいくつかの調査を私の答えに追加しました。 – hpaulj

+0

@hpaulj:もし私がmonkeypatchに喜んでいるなら、私は解決策を持っています – Eric