การแปลงชนิด dtypes ให้เป็นชนิดไพ ธ อลดั้งเดิม


238

ถ้าฉันมี ntyy dtype ฉันจะแปลงมันเป็นชนิดข้อมูลหลามที่ใกล้เคียงที่สุดโดยอัตโนมัติได้อย่างไร ตัวอย่างเช่น,

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

ฉันสามารถลองทำแผนที่ของกรณีเหล่านี้ได้ทั้งหมด แต่ไม่มีการจัดเรียงให้เป็นวิธีอัตโนมัติในการแปลงชนิดของมันให้เป็นชนิดไพ ธ อลแบบดั้งเดิมที่ใกล้เคียงที่สุดหรือไม่? การทำแผนที่นี้ไม่จำเป็นต้องละเอียดถี่ถ้วน แต่ควรแปลง dtypes ทั่วไปที่มีอะนาล็อก python แบบปิด ฉันคิดว่าสิ่งนี้เกิดขึ้นที่ไหนสักแห่งใน numpy

คำตอบ:


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

(วิธีอื่นคือ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

มีประเภท NumPy ไม่กี่ที่ไม่มีเทียบเท่าหลามพื้นเมืองในบางระบบรวมถึง: clongdouble, clongfloat, complex192, complex256, float128, longcomplex, และlongdouble longfloatความต้องการเหล่านี้จะถูกแปลงเป็นเทียบเท่า NumPy .item()ที่ใกล้ที่สุดก่อนที่จะใช้


ฉันใช้นุ่น (0.23.0) อย่างน้อยสำหรับรุ่นนั้น np.str ไม่มีวิธีการ. item () ดังนั้นวิธีเดียวที่ฉันเห็นคือการตัด. item () ภายในบล็อกลอง
Robert Lugg

3
@RobertLugg np.strไม่ใช่ประเภท Numpy นั่นคือnp.str is strดังนั้นจึงเป็นเพียงนามแฝงสำหรับประเภท Python มาตรฐาน เช่นเดียวกันกับnp.float, np.int, np.bool, และnp.complex np.objectประเภท Numpy มีต่อท้ายเช่น_ np.str_
Mike T

ฉันเข้าใจ. ดังนั้นปัญหาคือ "มันคงจะดีถ้า" ฉันจะทำและยังnp.float64(0).item() np.float(0).item()กล่าวอีกนัยหนึ่งสำหรับกรณีที่ทราบว่าต้องทำอย่างไรสนับสนุน.item()วิธีการแม้ว่าจะส่งคืนค่าเดียวกัน ด้วยวิธีนี้ฉันสามารถทา.item()ลงบนสเกลาที่มีขนาดใหญ่ขึ้นได้โดยไม่ต้องใช้ปลอกพิเศษ มันเป็นแนวคิดที่ดูเหมือนขนานแตกต่างกันไปเนื่องจากการใช้งานพื้นฐาน ฉันเข้าใจโดยสิ้นเชิงว่าทำไมสิ่งนี้ถึงเกิดขึ้น แต่มันเป็นเรื่องน่ารำคาญสำหรับผู้ใช้ห้องสมุด
Robert Lugg

45

พบว่าตัวเองมีชุดประเภท numpy และ python มาตรฐานที่ผสมกัน เป็นประเภท numpy ทั้งหมดมาจากต่อnumpy.genericไปนี้เป็นวิธีที่คุณสามารถแปลงทุกอย่างเป็นประเภทมาตรฐานหลาม:

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

5
ในฐานะที่เป็นบันทึกคำตอบที่ได้รับการยอมรับ , NumPy 1.16 เลิกใช้np.asscalar()วิธีการ ทำไม? อาจเป็นเพราะไม่มีเหตุผลที่ดีที่มองเห็นได้ แม้ว่าทศวรรษที่ผ่านมาของความเสถียรสัมพัทธ์ NumPy API เป็นเป้าหมายเคลื่อนที่ที่ไม่เสถียรซึ่งทำให้การบำรุงรักษาคงที่จากแอพพลิเคชั่นดาวน์สตรีม อย่างน้อยพวกเขาก็ปล่อยให้เราเป็นitem()วิธี ... ในตอนนี้
เซซิลแกงกะหรี่

วิธี asscalar ได้คิดค่าเสื่อมราคาตั้งแต่ v1.6 ของ numpy
Eswar

คุณสามารถแทนที่คำตอบได้อย่างง่ายดาย if isinstance(o, numpy.generic): return o.item() raise TypeErrorและมันจะกลายเป็นคำตอบที่ไม่เลิกใช้อีกครั้ง: D
Buggy

19

หากคุณต้องการแปลง (numpy.array หรือ scalar numpy หรือชนิดเนทีฟหรือ numpy.darray) เป็นชนิดเนทิฟคุณสามารถทำ:

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

tolist จะแปลงสเกลาร์หรืออาเรย์ของคุณเป็นประเภทเนทิฟหลาม ฟังก์ชั่นเริ่มต้นของแลมบ์ดาจะดูแลเคสที่มีค่าอยู่แล้ว


2
วิธีการที่สะอาดที่สุดสำหรับประเภทผสม (ดั้งเดิมและไม่ใช่เจ้าของภาษา) ทำได้ดีมาก! และสำหรับผู้ที่สงสัยว่าใช่ tolist เพียงแค่ส่งกลับค่าเดียว (เซนต์คิตส์และเนวิส) เมื่อคุณเรียกมันเป็นค่าเดียวไม่ใช่รายการตามที่คุณอาจคิดว่า น่าสังเกตคือวิธีที่ง่ายกว่าในการเขียนแลมบ์ดาคือlambda: valueเนื่องจากเราไม่ต้องการอินพุตใด ๆ
fgblomqvist

getattr+ tolistคำสั่งผสมไม่เพียง แต่เป็นสากล แต่รวมถึง vectorized! (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 เพิ่มจำนวน dtypes มากขึ้นในอนาคตโซลูชันของคุณจะพัง ดังนั้นฉันจึงไม่พอใจกับการแก้ปัญหานั้น
conradlee

จำนวน dtypes ที่เป็นไปได้นั้นมีไม่ จำกัด พิจารณาสำหรับจำนวนเต็มบวกใดnp.dtype('mint8')mไม่สามารถทำแผนที่ครบถ้วนสมบูรณ์ได้ (ฉันยังไม่เชื่อว่ามีฟังก์ชั่นบิวอินในการทำ Conversion นี้สำหรับคุณฉันอาจผิด แต่ฉันไม่คิดอย่างนั้น :))
unutbu

2
Python แมปชนิดของ numpy กับ 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

ตามความคิดเห็นก่อนหน้าของฉัน, แปลกนี้ใช้งานได้แม้ว่าฉันจะมีแม้ว่าคุณจะต้องใส่รอบในประเภทพื้นเมืองงูหลามแทนประเภทพื้นเมือง Numpy: >>> 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'>)

ซึ่งหมายความว่าไม่มีรายการที่แน่นอนและโค้ดของคุณจะขยายตามประเภทอื่น


คุณรู้หรือไม่ว่าซอร์สโค้ดนั้นมีไว้สำหรับส่วนใดส่วนหนึ่งของเมธอด tolist () ที่แมปประเภท numpy กับ python หรือไม่? ฉันมองอย่างรวดเร็ว แต่หาไม่เจอ
conradlee

นี่เป็นบิตของแฮ็คสิ่งที่ฉันทำคือการสร้างnumpy.ndarrayด้วย 1 ศูนย์ในการใช้zeros()และการเรียกndarrays tolist()ฟังก์ชั่นการแปลงเป็นประเภทพื้นเมือง เมื่ออยู่ในประเภทพื้นเมืองฉันขอประเภทกลับมา tolist()เป็น fucntion ของndarray
Matt Alcock

ใช่ฉันเห็นแล้ว --- มันใช้ได้กับสิ่งที่ฉันต้องการและฉันก็ยอมรับวิธีแก้ปัญหาของคุณ แต่ฉันสงสัยว่า tolist () ทำงานอย่างไรในการตัดสินใจเลือกประเภทที่จะใช้และฉันไม่แน่ใจว่าจะหาแหล่งที่มาได้อย่างไร
conradlee

numpy.sourceforge.net/numdoc/HTML/numdoc.htm#pgfId-36588เป็นที่ที่บันทึกฟังก์ชัน ฉันคิดว่าการตรวจสอบอาจช่วยหาข้อมูลเพิ่มเติมได้ แต่ไม่มีความสุข ขั้นตอนต่อไปผมพยายามที่จะโคลนgithub.com/numpy/numpy.gitgrep -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'}

ถ้าคุณต้องการไพ ธ อนประเภทที่แท้จริงไม่ใช่ชื่อพวกมันคุณสามารถทำได้ ::

>>> {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เป็นงูหลามธรรมดา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'>

ฉันเห็นว่านี่เป็นสิ่งเดียวกับคำตอบของ Matt Alcock
Simon Streicher

1

หมายเหตุด้านเกี่ยวกับสเกลาร์อาเรย์สำหรับผู้ที่ไม่ต้องการการแปลงแบบอัตโนมัติและทราบจำนวนชนิดที่มีค่า:

Array scalars แตกต่างจาก Python scalars แต่ส่วนใหญ่สามารถใช้แทนกันได้ (ข้อยกเว้นหลักสำหรับ Python เวอร์ชันเก่ากว่า v2.x โดยที่ scalars array จำนวนเต็มไม่สามารถทำหน้าที่เป็นดัชนีสำหรับรายการและสิ่งอันดับได้) มีข้อยกเว้นบางประการเช่นเมื่อรหัสต้องการคุณลักษณะที่เฉพาะเจาะจงมากของสเกลาร์หรือเมื่อตรวจสอบโดยเฉพาะว่าค่าเป็นสเกลาร์ Python หรือไม่ โดยทั่วไปปัญหาจะได้รับการแก้ไขอย่างง่ายดายโดยการแปลงสเกลาร์อาเรย์ให้เป็นสเกลาร์ Python อย่างชัดเจนโดยใช้ฟังก์ชันประเภท Python ที่สอดคล้องกัน (เช่น int, float, complex, str, unicode)

แหล่ง

ดังนั้นสำหรับกรณีส่วนใหญ่การแปลงอาจไม่จำเป็นเลยและสเกลาอาร์เรย์สามารถใช้โดยตรง เอฟเฟกต์ควรเหมือนกับการใช้ Python scalar:

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

แปลทั้ง 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.