numpy dtypesをネイティブPythonタイプに変換する


238

numpy dtypeがある場合、それを最も近いpythonデータ型に自動的に変換するにはどうすればよいですか?例えば、

numpy.float32 -> "python float"
numpy.float64 -> "python float"
numpy.uint32  -> "python int"
numpy.int16   -> "python int"

私はこれらすべてのケースのマッピングを思い付くように試みることができましたが、numpyはそのdtypeを可能な限り最も近いネイティブのpythonタイプに自動的に変換する方法をいくつか提供していますか?このマッピングは完全である必要はありませんが、Pythonアナログに近い一般的なdtypeを変換する必要があります。私はすでにこれが派手にどこかで起こっていると思います。

回答:


325

val.item()ほとんどのNumPy値をネイティブPythonタイプに変換するために使用します。

import numpy as np

# for example, numpy.float32 -> python float
val = np.float32(0)
pyval = val.item()
print(type(pyval))         # <class 'float'>

# and similar...
type(np.float64(0).item()) # <class 'float'>
type(np.uint32(0).item())  # <class 'long'>
type(np.int16(0).item())   # <class 'int'>
type(np.cfloat(0).item())  # <class 'complex'>
type(np.datetime64(0, 'D').item())  # <class 'datetime.date'>
type(np.datetime64('2001-01-01 00:00:00').item())  # <class 'datetime.datetime'>
type(np.timedelta64(0, 'D').item()) # <class 'datetime.timedelta'>
...

(もう1つの方法はですがnp.asscalar(val)、NumPy 1.16以降は非推奨です)。


好奇心旺盛な方のために、システムのNumPy配列スカラーの変換表を作成するには:

for name in dir(np):
    obj = getattr(np, name)
    if hasattr(obj, 'dtype'):
        try:
            if 'time' in name:
                npn = obj(0, 'D')
            else:
                npn = obj(0)
            nat = npn.item()
            print('{0} ({1!r}) -> {2}'.format(name, npn.dtype.char, type(nat)))
        except:
            pass

含むいくつかのシステム上でネイティブのPython同等を持っていないいくつかのnumpyのタイプがありますclongdoubleclongfloatcomplex192complex256float128longcomplexlongdoublelongfloat。これらは、を使用する前に、最も近いNumPyに変換する必要があります.item()


私はパンダ(0.23.0)を使用しています。少なくともそのバージョンでは、np.strには.item()メソッドがないため、.item()をtryブロック内にラップするしかありませんでした。
Robert Lugg

3
@RobertLugg np.strはNumpy型ではないnp.str is strため、標準のPython型の単なるエイリアスです。同じnp.floatnp.intnp.boolnp.complex、とnp.object。Numpy型には末尾が_ありnp.str_ます。
マイクT

わかります。:問題は、私は何ができる「場合、それはいいだろう」であるので、np.float64(0).item()またしてnp.float(0).item()。つまり、何をすべきかわかっている.item()場合は、同じ値を返すだけでもメソッドをサポートします。そうすれ.item()ば、特別な大文字小文字を使わずに、より多くの厄介なスカラーに適用できます。このように、基礎となる実装のために、一見並列の概念は異なります。これがなぜ行われたのか私は完全に理解しています。しかし、それは図書館利用者にとって不快です。
Robert Lugg

45

私はnumpyタイプのセットと標準のpythonを混合していることに気付きました。すべてのnumpy型がから派生しているnumpy.genericので、すべてをpython標準型に変換する方法は次のとおりです。

if isinstance(obj, numpy.generic):
    return numpy.asscalar(obj)

5
受け入れられた回答ノートとして、NumPy 1.16はnp.asscalar()メソッドを非推奨にしました。どうして?おそらく、はっきりとした理由はありません。10年の相対的安定性にもかかわらず、NumPy APIは現在、不安定な移動ターゲットであり、ダウンストリームアプリケーションからの定期的なメンテナンスを義務付けています。少なくとも彼らは私たちにitem()方法を残しました... 今のところ。
セシルカレー

asscalarメソッドはnumpyのv1.6から減価償却されました
Eswar

あなたは簡単に答えを置き換えることができ if isinstance(o, numpy.generic): return o.item() raise TypeError、それは再び非推奨されない答えになります:D
バギー

19

(numpy.array OR numpyスカラーORネイティブ型OR numpy.darray)をネイティブ型に変換する場合は、次のように簡単に実行できます。

converted_value = getattr(value, "tolist", lambda: value)()

tolistは、スカラーまたは配列をpythonネイティブ型に変換します。デフォルトのラムダ関数は、値がすでにネイティブである場合を処理します。


2
混合型(ネイティブと非ネイティブ)に対する最もクリーンなアプローチ、よくできました!そして不思議に思う人のために、はい、tolistは、あなたが考えているようなリストではなく、単一の値でそれを呼び出すと、単一の値(スカラー)を返すだけです。注目に値するのは、ラムダを記述する最も簡単な方法はlambda: value、入力が必要ないためです。
fgblomqvist

getattr+ tolistコンボはユニバーサル、それでもベクトル化だけではありません!(unlinke .item())
mirekphd

11

どうですか:

In [51]: dict([(d, type(np.zeros(1,d).tolist()[0])) for d in (np.float32,np.float64,np.uint32, np.int16)])
Out[51]: 
{<type 'numpy.int16'>: <type 'int'>,
 <type 'numpy.uint32'>: <type 'long'>,
 <type 'numpy.float32'>: <type 'float'>,
 <type 'numpy.float64'>: <type 'float'>}

1
私は私の質問の最後でそのタイプの解決策を可能性として述べています。しかし、私は、いくつかのケースをカバーするだけのハードコーディングされたソリューションではなく、体系的なソリューションを探しています。たとえば、numpyが将来さらにdtypeを追加した場合、ソリューションは壊れます。だから私はその解決策に満足していません。
conradlee

可能なdtypeの数は無制限です。np.dtype('mint8')正の整数を考慮してくださいm。完全なマッピングはありません。(また、この変換を行う組み込み関数があるとは思いません。間違っている可能性もありますが、そうは思いません:))
unutbu

2
Pythonはnumpy dtypesをpythonタイプにマップします。方法はわかりませんが、どのような方法でも使用したいと思います。これは、たとえば、numpy dtypesとpython型の間の乗算(およびその他の演算)を可能にするために起こる必要があると思います。私はそれらの方法がすべての可能なナンピータイプを網羅的にマップするのではなく、少なくともそれが理にかなっている最も一般的なものをマッピングすると思います。
conradlee

一貫して機能しない:>>> print([numpy.asscalar(x) for x in numpy.linspace(1.0, 0.0, 21)]) [1.0, 0.95, 0.9, 0.85, 0.8, 0.75, 0.7, 0.6499999999999999, 0.6, 0.55, 0.5, 0.44999999999999996, 0.3999999999999999, 0.35, 0.29999999999999993, 0.25, 0.19999999999999996, 0.1499999999999999, 0.09999999999999998, 0.04999999999999993, 0.0]ご覧のとおり、すべての値が正しく変換されたわけではありません。
Alex F

:あなたがPythonのネイティブ型の代わりに、numpyのネイティブ型にラウンドを配置する必要があるでしょうけれども、私が持っているでしょうが、私の以前のコメント、妙にこの1つの作品次 >>> print([numpy.asscalar(round(x,2)) for x in numpy.linspace(1.0, 0.0, 21)]) [1.0, 0.95, 0.9, 0.85, 0.8, 0.75, 0.7, 0.65, 0.6, 0.55, 0.5, 0.45, 0.4, 0.35, 0.3, 0.25, 0.2, 0.15, 0.1, 0.05, 0.0]
アレックス・F

9

tolist()これを実現するためのより一般的なアプローチです。任意のプリミティブdtypeで動作し、配列または行列でも動作します。

プリミティブ型から呼び出された場合、実際にはリストを生成しません。

numpy == 1.15.2

>>> import numpy as np

>>> np_float = np.float64(1.23)
>>> print(type(np_float), np_float)
<class 'numpy.float64'> 1.23

>>> listed_np_float = np_float.tolist()
>>> print(type(listed_np_float), listed_np_float)
<class 'float'> 1.23

>>> np_array = np.array([[1,2,3.], [4,5,6.]])
>>> print(type(np_array), np_array)
<class 'numpy.ndarray'> [[1. 2. 3.]
 [4. 5. 6.]]

>>> listed_np_array = np_array.tolist()
>>> print(type(listed_np_array), listed_np_array)
<class 'list'> [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]


6

私はあなたがこのような一般的な型変換関数を書くことができると思います:

import numpy as np

def get_type_convert(np_type):
   convert_type = type(np.zeros(1,np_type).tolist()[0])
   return (np_type, convert_type)

print get_type_convert(np.float32)
>> (<type 'numpy.float32'>, <type 'float'>)

print get_type_convert(np.float64)
>> (<type 'numpy.float64'>, <type 'float'>)

つまり、固定リストはなく、コードはより多くの型でスケーリングされます。


numpy型をpython型にマップするtolist()メソッドの部分のソースコードがどこにあるか知っていますか?ざっと見ましたが見つかりませんでした。
conradlee

これは、私がやっていることを少しハックnumpy.ndarrayして、使用して1ゼロを生成しzeros()ndarrays tolist()関数を呼び出してネイティブ型に変換することです。ネイティブ型に入ると、型を返してください。 tolist()の機能ですndarray
Matt Alcock

ええ、私はそれが私が望んでいることで動作するので、私はあなたの解決策を受け入れました。しかし、tolist()がどの型にキャストするかを決定する仕事をしているのではないかと思います。ソースを見つける方法はわかりません。
conradlee

numpy.sourceforge.net/numdoc/HTML/numdoc.htm#pgfId-36588は、関数が文書化されている場所です。私は検査がより多くの情報を見つけるのを助けることができるかもしれないと思っていましたが、喜びはありません。次のステップでは、github.com / numpy / numpy.gitのクローンを作成して実行しましたgrep -r 'tolist' numpy。(まだ進行中、numpyは巨大です!)
Matt Alcock

3

numpyはtypeDict、以下のようなことができるように公開されたマッピングにその情報を保持します。

>>> import __builtin__
>>> import numpy as np
>>> {v: k for k, v in np.typeDict.items() if k in dir(__builtin__)}
{numpy.object_: 'object',
 numpy.bool_: 'bool',
 numpy.string_: 'str',
 numpy.unicode_: 'unicode',
 numpy.int64: 'int',
 numpy.float64: 'float',
 numpy.complex128: 'complex'}

名前ではなく実際のPythonタイプが必要な場合は、次のようにできます::

>>> {v: getattr(__builtin__, k) for k, v in np.typeDict.items() if k in vars(__builtin__)}
{numpy.object_: object,
 numpy.bool_: bool,
 numpy.string_: str,
 numpy.unicode_: unicode,
 numpy.int64: int,
 numpy.float64: float,
 numpy.complex128: complex}

3

一部遅れて申し訳ありませんが、numpy.float64通常のPython floatのみに変換する問題を検討していました。私はそれを行う3つの方法を見ました。

  1. npValue.item()
  2. npValue.astype(float)
  3. float(npValue)

IPythonからの関連するタイミングは次のとおりです。

In [1]: import numpy as np

In [2]: aa = np.random.uniform(0, 1, 1000000)

In [3]: %timeit map(float, aa)
10 loops, best of 3: 117 ms per loop

In [4]: %timeit map(lambda x: x.astype(float), aa)
1 loop, best of 3: 780 ms per loop

In [5]: %timeit map(lambda x: x.item(), aa)
1 loop, best of 3: 475 ms per loop

float(npValue)はるかに速いように思えます。


1

私のアプローチは少し強力ですが、すべての場合にうまくいくようです:

def type_np2py(dtype=None, arr=None):
    '''Return the closest python type for a given numpy dtype'''

    if ((dtype is None and arr is None) or
        (dtype is not None and arr is not None)):
        raise ValueError(
            "Provide either keyword argument `dtype` or `arr`: a numpy dtype or a numpy array.")

    if dtype is None:
        dtype = arr.dtype

    #1) Make a single-entry numpy array of the same dtype
    #2) force the array into a python 'object' dtype
    #3) the array entry should now be the closest python type
    single_entry = np.empty([1], dtype=dtype).astype(object)

    return type(single_entry[0])

使用法:

>>> type_np2py(int)
<class 'int'>

>>> type_np2py(np.int)
<class 'int'>

>>> type_np2py(str)
<class 'str'>

>>> type_np2py(arr=np.array(['hello']))
<class 'str'>

>>> type_np2py(arr=np.array([1,2,3]))
<class 'int'>

>>> type_np2py(arr=np.array([1.,2.,3.]))
<class 'float'>

これは本質的にマット・アルコックの答えと同じだと思います。
Simon Streicher

1

自動変換を必要とせず、値のnumpy dtypeを知っている人のための配列スカラーに関する補足:

配列スカラーはPythonスカラーとは異なりますが、ほとんどの場合交換可能に使用できます(主な例外はv2.xより古いバージョンのPythonで、整数配列スカラーはリストやタプルのインデックスとして機能できません)。コードがスカラーの非常に特定の属性を必要とする場合や、値がPythonスカラーかどうかを具体的にチェックする場合など、いくつかの例外があります。一般的に、問題は、対応するPython型関数(int、float、complex、str、unicodeなど)を使用して、配列スカラーを明示的にPythonスカラーに変換することで簡単に修正できます。

ソース

したがって、ほとんどの場合、変換はまったく必要なく、配列スカラーを直接使用できます。効果は、Pythonスカラーを使用した場合と同じになります。

>>> np.issubdtype(np.int64, int)
True
>>> np.int64(0) == 0
True
>>> np.issubdtype(np.float64, float)
True
>>> np.float64(1.1) == 1.1
True

しかし、何らかの理由で明示的な変換が必要な場合は、対応するPython組み込み関数を使用する方法があります。他の答えに示されているように、配列スカラーitem()メソッドよりも高速です。


0

1つの単位データオブジェクトではなく、ndarray全体を変換します。

def trans(data):
"""
translate numpy.int/float into python native data type
"""
result = []
for i in data.index:
    # i = data.index[0]
    d0 = data.iloc[i].values
    d = []
    for j in d0:
        if 'int' in str(type(j)):
            res = j.item() if 'item' in dir(j) else j
        elif 'float' in str(type(j)):
            res = j.item() if 'item' in dir(j) else j
        else:
            res = j
        d.append(res)
    d = tuple(d)
    result.append(d)
result = tuple(result)
return result

ただし、大きなデータフレームを処理する場合は数分かかります。より効率的なソリューションも探しています。より良い答えを願っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.