Chuyển đổi các loại numpy sang các loại trăn bản địa


237

Nếu tôi có một dtype numpy, làm thế nào để tôi tự động chuyển đổi nó thành kiểu dữ liệu python gần nhất của nó? Ví dụ,

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

Tôi có thể cố gắng đưa ra một bản đồ của tất cả các trường hợp này, nhưng liệu numpy có cung cấp một số cách tự động để chuyển đổi các kiểu chữ của nó thành các loại trăn bản địa gần nhất có thể không? Ánh xạ này không cần phải đầy đủ, nhưng nó sẽ chuyển đổi các loại phổ biến có một tương tự python gần. Tôi nghĩ rằng điều này đã xảy ra ở đâu đó trong numpy.

Câu trả lời:


325

Sử dụng val.item()để chuyển đổi hầu hết các giá trị NumPy sang loại Python gốc:

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)Tuy nhiên, một phương pháp khác là không được chấp nhận kể từ NumPy 1.16).


Đối với người tò mò, để xây dựng bảng chuyển đổi vô hướng mảng NumPy cho hệ thống của bạn:

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

Có một vài loại NumPy rằng không có Python tương đương nguồn gốc trên một số hệ thống, bao gồm: clongdouble, clongfloat, complex192, complex256, float128, longcomplex, longdoublelongfloat. Chúng cần được chuyển đổi thành tương đương NumPy gần nhất trước khi sử dụng .item().


Tôi đang sử dụng gấu trúc (0.23.0). Ít nhất là đối với phiên bản đó, np.str không có phương thức .item () nên cách duy nhất tôi thấy là bọc .item () trong một khối thử.
Robert Lugg

3
@RobertLugg np.strkhông phải là một loại Numpy np.str is str, vì vậy, nó chỉ là bí danh của một loại Python tiêu chuẩn. Cùng với np.float, np.int, np.bool, np.complex, và np.object. Các loại Numpy có một dấu _, ví dụ np.str_.
Mike T

Tôi hiểu. Vì vậy, vấn đề là "nó sẽ tốt nếu" tôi có thể làm được: np.float64(0).item()và cả np.float(0).item(). Nói cách khác, đối với các trường hợp đã biết phải làm gì, hãy hỗ trợ .item()phương thức ngay cả khi nó chỉ trả về cùng một giá trị. Bằng cách đó tôi có thể áp dụng .item()trên vô hướng numpy xa hơn mà không cần vỏ đặc biệt. Như nó là, các khái niệm dường như song song khác nhau do thực hiện cơ bản. Tôi hoàn toàn hiểu tại sao điều này đã được thực hiện. Nhưng nó là một phiền toái cho người dùng thư viện.
Robert Lugg

45

thấy mình có hỗn hợp các loại numpy và python tiêu chuẩn. vì tất cả các loại numpy có nguồn gốc từ numpy.genericđây, đây là cách bạn có thể chuyển đổi mọi thứ thành các loại tiêu chuẩn python:

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

5
Khi ghi chú câu trả lời được chấp nhận , NumPy 1.16 không dùng np.asscalar()phương thức này. Tại sao? Có lẽ không có lý do rõ ràng tốt. Mặc dù có một thập kỷ ổn định tương đối, API NumPy hiện là mục tiêu di chuyển không ổn định bắt buộc phải bảo trì liên tục từ các ứng dụng tiếp theo. Ít nhất là họ đã để lại cho chúng ta item()phương pháp ... bây giờ.
Cecil Curry

phương pháp asscalar đã mất giá kể từ v1.6 của numpy
Eswar

Bạn có thể dễ dàng thay thế câu trả lời bằng if isinstance(o, numpy.generic): return o.item() raise TypeErrorvà nó lại biến thành câu trả lời không bị phản đối: D
Buggy

19

Nếu bạn muốn chuyển đổi (numpy.array HOẶC numpy HOẶC loại bản địa HOẶC numpy.darray) sang loại bản địa, bạn có thể chỉ cần làm:

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

Tolist sẽ chuyển đổi vô hướng hoặc mảng của bạn thành kiểu gốc python. Hàm lambda mặc định sẽ xử lý trường hợp giá trị đã có sẵn.


2
Cách tiếp cận sạch nhất cho các loại hỗn hợp (bản địa và không bản địa), cũng được thực hiện! Và đối với những người thắc mắc, vâng, tolist chỉ trả về một giá trị duy nhất (vô hướng) khi bạn gọi nó trên một giá trị duy nhất, không phải là một danh sách như bạn nghĩ. Đáng chú ý là cách đơn giản hơn để viết lambda là lambda: valuevì chúng tôi không muốn bất kỳ đầu vào nào.
fgblomqvist

getattr+ tolistcombo không chỉ phổ quát, mà thậm chí còn được vector hóa! (unlinke .item ())
mirekphd

11

Làm thế nào về:

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
Tôi đề cập đến loại giải pháp như một khả năng ở cuối câu hỏi của tôi. Nhưng tôi đang tìm kiếm một giải pháp có hệ thống chứ không phải là một giải pháp được mã hóa cứng chỉ bao gồm một vài trường hợp. Ví dụ, nếu numpy thêm nhiều dtypes trong tương lai, giải pháp của bạn sẽ bị phá vỡ. Vì vậy, tôi không hài lòng với giải pháp đó.
conradlee

Số lượng các loại dtypes có thể là không giới hạn. Xem xét np.dtype('mint8')cho bất kỳ số nguyên dương m. Không thể có một bản đồ toàn diện. (Tôi cũng không tin có chức năng dựng sẵn để thực hiện chuyển đổi này cho bạn. Tôi có thể sai, nhưng tôi không nghĩ vậy :))
unutbu

2
Python ánh xạ các dtypes numpy thành các loại python, tôi không biết làm thế nào, nhưng tôi muốn sử dụng bất kỳ phương pháp nào chúng làm. Tôi nghĩ rằng điều này phải xảy ra để cho phép, ví dụ, phép nhân (và các hoạt động khác) giữa các loại dtypes numpy và python. Tôi đoán phương pháp của họ không ánh xạ triệt để tất cả các loại numpy có thể, nhưng ít nhất là những loại phổ biến nhất có ý nghĩa.
conradlee

Nó không hoạt động nhất quán: >>> 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]Như bạn thấy không phải tất cả các giá trị đều được chuyển đổi chính xác.
Alex F

Theo nhận xét trước đây của tôi, điều kỳ lạ là cái này hoạt động, mặc dù tôi sẽ có mặc dù bạn sẽ cần đặt vòng trên loại bản địa Python thay vì loại bản địa 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]
Alex F

9

tolist()là một cách tiếp cận tổng quát hơn để thực hiện điều này. Nó hoạt động trong bất kỳ dtype nguyên thủy nào và cả trong mảng hoặc ma trận.

Tôi không thực sự mang lại một danh sách nếu được gọi từ các loại nguyên thủy:

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

Bạn cũng có thể gọi item()phương thức của đối tượng bạn muốn chuyển đổi:

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

6

Tôi nghĩ bạn chỉ có thể viết hàm chuyển đổi loại chung như vậy:

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

Điều này có nghĩa là không có danh sách cố định và mã của bạn sẽ mở rộng với nhiều loại hơn.


Bạn có biết mã nguồn ở đâu cho một phần của phương thức tolist () ánh xạ các loại numpy thành các loại python không? Tôi đã xem nhanh nhưng không thể tìm thấy nó.
conradlee

Đây là một chút hack mà tôi đang làm là tạo ra numpy.ndarray1 không trong đó bằng cách sử dụng zeros()và gọi ndarrays tolist()hàm để chuyển đổi thành các kiểu gốc. Khi ở kiểu bản địa, tôi yêu cầu trả về kiểu đó. tolist()là một fucntion củandarray
Matt Alcock

Vâng tôi thấy rằng --- nó hoạt động cho những gì tôi muốn và vì vậy tôi đã chấp nhận giải pháp của bạn. Nhưng tôi tự hỏi làm thế nào tolist () thực hiện công việc của mình là quyết định loại nào được đưa vào, và tôi không chắc làm thế nào để tìm được nguồn.
conradlee

numpy.sourceforge.net/numdoc/HTML/numdoc.htm#pgfId-36588 là nơi chức năng được ghi lại. Tôi nghĩ rằng thanh tra có thể giúp tìm thêm thông tin nhưng không có niềm vui. Bước tiếp theo tôi đã cố gắng sao chép github.com/numpy/numpy.git và chạy grep -r 'tolist' numpy. (vẫn đang được tiến hành, numpy là rất lớn!)
Matt Alcock

3

numpy giữ thông tin đó trong một ánh xạ được phơi bày typeDictđể bạn có thể làm một cái gì đó như dưới đây ::

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

Nếu bạn muốn các loại python thực tế hơn là tên của chúng, bạn có thể làm ::

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

Xin lỗi vì đến muộn một phần, nhưng tôi đã xem xét vấn đề chuyển đổi numpy.float64sang Python thông thường float. Tôi đã thấy 3 cách để làm điều đó:

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

Dưới đây là thời gian liên quan từ 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

Nghe float(npValue)có vẻ nhanh hơn nhiều.


1

Cách tiếp cận của tôi là một chút mạnh mẽ, nhưng dường như chơi tốt cho tất cả các trường hợp:

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

Sử dụng:

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

Tôi thấy điều này về cơ bản giống như câu trả lời của Matt Alcock.
Simon Strerich

1

Một lưu ý phụ về vô hướng mảng cho những người không cần chuyển đổi tự động và biết loại dtype numpy của giá trị:

Vô hướng mảng khác với vô hướng Python, nhưng đối với hầu hết các phần chúng có thể được sử dụng thay thế cho nhau (ngoại lệ chính là các phiên bản Python cũ hơn v2.x, trong đó các vô hướng mảng số nguyên không thể đóng vai trò là chỉ mục cho danh sách và bộ dữ liệu). Có một số trường hợp ngoại lệ, chẳng hạn như khi mã yêu cầu các thuộc tính rất cụ thể của vô hướng hoặc khi nó kiểm tra cụ thể xem giá trị có phải là vô hướng Python hay không. Nói chung, các vấn đề dễ dàng được khắc phục bằng cách chuyển đổi rõ ràng các vô hướng mảng thành vô hướng Python, sử dụng hàm loại Python tương ứng (ví dụ: int, float, phức tạp, str, unicode).

Nguồn

Do đó, đối với hầu hết các trường hợp, chuyển đổi có thể không cần thiết chút nào và vô hướng mảng có thể được sử dụng trực tiếp. Hiệu ứng phải giống hệt với sử dụng vô hướng 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

Nhưng nếu, vì một số lý do, việc chuyển đổi rõ ràng là cần thiết, sử dụng hàm tích hợp Python tương ứng là cách để đi. Như thể hiện trong câu trả lời khác, nó cũng nhanh hơn item()phương pháp vô hướng mảng .


0

Dịch toàn bộ ndarray thay vì một đối tượng dữ liệu đơn vị:

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

Tuy nhiên, phải mất vài phút khi xử lý các tệp dữ liệu lớn. Tôi cũng đang tìm kiếm một giải pháp hiệu quả hơn. Hy vọng một câu trả lời tốt hơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.