Numpy türlerini yerel python türlerine dönüştürme


238

Bir numpy dtype varsa, otomatik olarak en yakın python veri türüne nasıl dönüştürebilirim? Örneğin,

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

Ben tüm bu vakaların bir harita ile gelip deneyebilirsiniz, ama numpy türlerini mümkün olan en yakın yerel python türlerine dönüştürmek için otomatik bir yol sağlar? Bu eşlemenin kapsamlı olması gerekmez, ancak yakın bir python analogu olan ortak dtypes'i dönüştürmelidir. Bence bu zaten numpy'de bir yerde oluyor.

Yanıtlar:


325

val.item()Çoğu NumPy değerini yerel bir Python türüne dönüştürmek için kullanın :

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'>
...

( np.asscalar(val)Ancak başka bir yöntem NumPy 1.16'dan beri kullanımdan kaldırılmıştır).


Meraklı olmak için, sisteminiz için NumPy dizi skaler dönüşümleri tablosu oluşturmak için:

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

Dahil olmak üzere bazı sistemlerde, üzerinde hiçbir yerli Python eşdeğer bir kaç NumPy tipi vardır: clongdouble, clongfloat, complex192, complex256, float128, longcomplex, longdoubleve longfloat. Bunların kullanılmadan önce en yakın NumPy eşdeğerine dönüştürülmesi gerekir .item().


Panda kullanıyorum (0.23.0). En azından bu sürüm için, np.str .item () yöntemine sahip olmadığından, gördüğüm tek yol .item () öğesini bir try bloğunun içine sarmaktı.
Robert Lugg

3
@RobertLugg np.strbir Numpy türü değildir, yani np.str is strstandart bir Python türü için bir takma addır . İle aynı np.float, np.int, np.bool, np.complex, ve np.object. Numpy tiplerinin bir sonu vardır _, örn np.str_.
Mike T

Anlıyorum. Yani mesele "yapabilirse iyi olur" diyebilirim: np.float64(0).item()ve ayrıca np.float(0).item(). Başka bir deyişle, ne yapılacağı bilinen durumlarda .item(), aynı değeri döndürse bile yöntemi destekleyin . Bu şekilde .item()özel kasa olmadan çok daha numpy skalerlere uygulayabilirim . Olduğu gibi, görünüşte paralel kavramlar, temeldeki uygulama nedeniyle farklılık gösterir. Bunun neden yapıldığını tamamen anlıyorum. Ancak kütüphane kullanıcısı için bir sıkıntıdır.
Robert Lugg

45

kendimi karışık tipler ve standart python kümesi buldum. tüm numpy türleri türetildiği gibi numpy.generic, her şeyi python standart türlerine nasıl dönüştürebileceğiniz aşağıda açıklanmıştır:

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

5
Gibi kabul cevap notları , NumPy 1.16 kaldırılmış np.asscalar()yöntem. Neden? Muhtemelen iyi bir neden yok. On yıllık göreceli kararlılığa rağmen, NumPy API artık aşağı akış uygulamalarından sürekli bakım gerektiren istikrarsız bir hareketli hedeftir. En azından bize item()yöntemi bıraktılar ... şimdilik.
Cecil Curry

asscalar yöntem Numpy ait v1.6 beri değer kaybetti
Eswar

Cevabı kolayca değiştirebilirsiniz ve if isinstance(o, numpy.generic): return o.item() raise TypeErrortekrar kullanımdan kaldırılmış bir cevaba dönüşür: D
Buggy

19

(Numpy.array VEYA numpy skaler VEYA yerel tip VEYA numpy.darray) yerel türe dönüştürmek istiyorsanız şunları yapabilirsiniz:

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

tolist, skaler veya dizinizi python yerel türüne dönüştürür. Varsayılan lambda işlevi, değerin zaten yerel olduğu durumla ilgilenir.


2
Karışık türler için en temiz yaklaşım (yerli ve yerli olmayan), aferin! Ve merak edenler için, evet, listeyi düşündüğünüz gibi bir liste değil, tek bir değer olarak çağırdığınızda tek bir değer (skaler) döndürür. Kayda değer bir şey, lambda: valueherhangi bir girdi istemediğimiz için lambda yazmanın daha kolay yoludur .
fgblomqvist

getattr+ tolistcombo sadece evrensel değil, vektörize bile! (unlinke .item ())
mirekphd

11

Nasıl olur:

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
Sorumun sonunda bir olasılık olarak bu tür bir çözümden bahsediyorum. Ancak, sadece birkaç örneği kapsayan sabit kodlu değil sistematik bir çözüm arıyorum. Örneğin, numpy gelecekte daha fazla dtype eklerse, çözümünüz bozulur. Bu yüzden bu çözümden memnun değilim.
conradlee

Olası dtiplerin sayısı sınırsızdır. np.dtype('mint8')Herhangi bir pozitif tamsayı düşünün m. Kapsamlı bir haritalama olamaz. (Bu dönüşümü sizin için yapacak yerleşik bir işlev olduğuna da inanmıyorum. Yanlış olabilirim, ama öyle düşünmüyorum :))
unutbu

2
Python numpy dtypes'i python türleriyle eşleştirir, nasıl olduğundan emin değilim, ancak yaptıkları yöntemi kullanmak istiyorum. Bu, örneğin, numpy dtypes ve python türleri arasında çarpma (ve diğer işlemler) izin vermek gerektiğini düşünüyorum. Onların yöntemi tüm olası numpy türlerini kapsamlı bir şekilde eşlemiyor, ama en azından mantıklı olduğu en yaygın olanları tahmin ediyor.
Şubat'ta conradlee

Tutarlı çalışmıyor: >>> 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]Gördüğünüz gibi tüm değerler doğru bir şekilde dönüştürülmedi.
Alex F

önceki yorumumu takip, garip bir şekilde çalışır, gerçi ben Numpy yerli türü yerine Python yerli türü üzerinde yuvarlak koymak gerekir olurdu: >>> 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]
Alex F

9

tolist()bunu başarmak için daha genel bir yaklaşımdır. Herhangi bir ilkel tipte ve ayrıca dizilerde veya matrislerde çalışır.

İlkel türlerden çağrılırsa aslında bir liste vermezim:

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]]

8

Dönüştürmek istediğiniz nesnenin item()yöntemini de çağırabilirsiniz :

>>> from numpy import float32, uint32
>>> type(float32(0).item())
<type 'float'>
>>> type(uint32(0).item())
<type 'long'>

6

Ben sadece böyle genel tip dönüştürme işlevi yazabilirsiniz düşünüyorum:

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'>)

Bu, sabit listelerin olmadığı ve kodunuzun daha fazla türle ölçekleneceği anlamına gelir.


Kaynak kodun, tolist () yönteminin numpy türlerini python türleriyle eşleyen kısmı için nerede olduğunu biliyor musunuz? Hızlıca baktım ama bulamadım.
conradlee

Bu yaptığım bir kesmek biraz numpy.ndarraykullanarak kullanarak 1 sıfır zeros()ve ndarrays tolist()yerel türlere dönüştürmek için işlev çağırıyor . Yerli türlerde bir kez yazın bir dönüş isteyin. tolist()ndarray
Matt Alcock

Evet görüyorum --- istediğim işe yarıyor ve bu yüzden çözümünüzü kabul ettim. Ama nasıl tolist () hangi tür içine dökülecek karar verme işini merak ediyorum, ve kaynak bulmak için nasıl emin değilim.
conradlee

numpy.sourceforge.net/numdoc/HTML/numdoc.htm#pgfId-36588 işlevin belgelendiği yerdir. Teftişin daha fazla bilgi bulmasına yardımcı olabileceğini düşündüm, ama sevinç yok. Bir sonraki adım github.com/numpy/numpy.git klonlamaya ve çalıştırmaya çalıştım grep -r 'tolist' numpy. (hala devam ediyor, numpy muazzam!)
Matt Alcock

3

numpy typeDict, aşağıdaki gibi bir şey yapabilmeniz için bu bilgileri bir haritalamada tutar :

>>> 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'}

Adları yerine gerçek python türlerini istiyorsanız, şunları yapabilirsiniz:

>>> {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

Kısmen geç kaldığım için üzgünüm, ama sadece numpy.float64normal Python'a dönüştürme sorununa bakıyordum float. Bunu yapmanın 3 yolunu gördüm:

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

İşte IPython'un ilgili zamanlamaları:

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

Çok float(npValue)daha hızlı görünüyor.


1

Yaklaşımım biraz zorlayıcı, ancak tüm durumlar için iyi görünüyor:

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])

Kullanımı:

>>> 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'>

Bunun temel olarak Matt Alcock'un cevabı ile aynı olduğunu görüyorum.
Simon Streicher

1

Otomatik dönüştürmeye ihtiyaç duymayan ve değerin sayısal dtype'ını bilenler için dizi skaleri hakkında bir yan not:

Dizi skalaları Python skalasından farklıdır, ancak çoğunlukla birbirlerinin yerine kullanılabilirler (birincil istisna, tamsayı dizi skalasının listeler ve tuples için indeks olarak işlev göremediği v2.x'ten daha eski Python sürümleri içindir). Kodun bir skaler için çok özel nitelikler gerektirmesi veya bir değerin bir Python skaleri olup olmadığını özellikle kontrol etmesi gibi bazı istisnalar vardır. Genellikle, ilgili Python tipi işlevi (örneğin int, float, karmaşık, str, unicode) kullanılarak dizi skalerlerinin açıkça Python skalerlerine dönüştürülmesi ile problemler kolayca giderilebilir.

Kaynak

Bu nedenle, çoğu durumda dönüştürme işlemi gerekli olmayabilir ve dizi skaleri doğrudan kullanılabilir. Etki, Python skaler kullanımı ile aynı olmalıdır:

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

Ancak, herhangi bir nedenden ötürü, açık bir dönüşüme ihtiyaç duyulursa, karşılık gelen Python yerleşik işlevini kullanmak gidilecek yoldur. Diğer cevapta gösterildiği gibi, dizi skaler item()yönteminden de daha hızlıdır .


0

Bunun yerine ndarray'ın tamamını bir birim veri nesnesi olarak çevirin:

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

Ancak, büyük veri çerçeveleri işlenirken birkaç dakika sürer. Ayrıca daha verimli bir çözüm arıyorum. Umarım daha iyi bir cevap.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.