Типы данных#
Смотрите также
Типы массивов и преобразования между типами#
NumPy поддерживает гораздо больше числовых типов, чем Python. В этом разделе показано, какие типы доступны и как изменить тип данных массива.
Числовые типы NumPy являются экземплярами numpy.dtype объекты (типы данных), каждый из которых имеет уникальные характеристики. После импорта NumPy с помощью import
numpy as np вы можете создавать массивы с указанным dtype, используя скалярные
типы в API верхнего уровня numpy, например. numpy.bool, numpy.float32, и т.д.
Эти скалярные типы в качестве аргументов ключевого слова dtype, которые принимают многие функции или методы numpy. Например:
>>> z = np.arange(3, dtype=np.uint8)
>>> z
array([0, 1, 2], dtype=uint8)
Типы массивов также могут обозначаться символьными кодами, например:
>>> np.array([1, 2, 3], dtype='f')
array([1., 2., 3.], dtype=float32)
>>> np.array([1, 2, 3], dtype='d')
array([1., 2., 3.], dtype=float64)
См. Задание и построение типов данных для получения дополнительной информации о задании и построении объектов типа данных, включая указание параметров, таких как порядок байтов.
Чтобы определить тип массива, посмотрите на атрибут dtype:
>>> z.dtype
dtype('uint8')
Объекты dtype также содержат информацию о типе, такую как его битовая ширина и порядок байтов. Тип данных также может использоваться косвенно для запроса свойств типа, например, является ли он целым числом:
>>> d = np.dtype(np.int64)
>>> d
dtype('int64')
>>> np.issubdtype(d, np.integer)
True
>>> np.issubdtype(d, np.floating)
False
Для преобразования типа массива используйте метод .astype(). Например:
>>> z.astype(np.float64)
array([0., 1., 2.])
Обратите внимание, что выше мы могли бы использовать Python объект float как dtype вместо numpy.float64. NumPy знает, что
int относится к numpy.int_, bool средние значения
numpy.bool, что float является numpy.float64 и
complex является numpy.complex128. Другие типы данных не имеют
эквивалентов в Python.
Иногда преобразование может вызвать переполнение, например, при преобразовании numpy.int64 значение
300 до numpy.int8. NumPy следует правилам приведения типов C, поэтому это значение переполнится и станет 44 (300 - 256). Если вы хотите избежать таких переполнений, вы можете указать, чтобы действие при переполнении завершалось ошибкой, используя same_value для casting аргумент (см. также
Ошибки переполнения):
>>> z.astype(np.float64, casting="same_value")
array([0., 1., 2.])
Числовые типы данных#
Существует 5 основных числовых типов, представляющих логические значения (bool), целые числа (int), беззнаковые целые числа (uint) с плавающей запятой (float) и
complex. Базовое числовое имя типа в сочетании с числовым размером в битах определяет конкретный тип. Размер в битах — это количество битов, необходимых для представления одного значения в памяти. Например, numpy.float64 является 64-битным типом данных с плавающей точкой. Некоторые типы, такие как numpy.int_ и
numpy.intp, имеют разный размер в битах, зависящий от платформы
(например, 32-битные vs. 64-битные архитектуры CPU). Это следует учитывать
при взаимодействии с низкоуровневым кодом (таким как C или Fortran), где адресуется
сырая память.
Типы данных для строк и байтов#
В дополнение к числовым типам, NumPy также поддерживает хранение строк Unicode через numpy.str_ тип данных (U символьный код), нуль-терминированные байтовые последовательности через
numpy.bytes_ (S символьный код) и произвольные последовательности байтов через
numpy.void (V код символа).
Все вышеперечисленное является фиксированной ширины типы данных. Они параметризуются шириной, в байтах или точках юникода, в которую должен помещаться один элемент данных в массиве. Это означает, что хранение массива последовательностей байтов или строк с использованием этого dtype требует знания или вычисления размеров самого длинного текста или последовательности байтов заранее.
В качестве примера мы можем создать массив, хранящий слова "hello" и
"world!":
>>> np.array(["hello", "world!"])
array(['hello', 'world!'], dtype='
Здесь тип данных определяется как строка Unicode максимальной длиной в 6 кодовых точек, достаточной для хранения обеих записей без усечения. Если мы укажем более короткий или более длинный тип данных, строка либо усекается, либо дополняется нулями, чтобы соответствовать указанной ширине:
>>> np.array(["hello", "world!"], dtype="U5")
array(['hello', 'world'], dtype='
>>> np.array(["hello", "world!"], dtype="U7")
array(['hello', 'world!'], dtype='
Мы можем увидеть дополнение нулями немного яснее, если используем тип данных bytes и попросим NumPy вывести байты в буфере массива:
>>> np.array(["hello", "world"], dtype="S7").tobytes()
b'hello\x00\x00world\x00\x00'
Каждая запись дополняется двумя дополнительными нулевыми байтами. Однако обратите внимание, что NumPy не может отличить намеренно сохраненные конечные нули от нулей заполнения:
>>> x = [b"hello\0\0", b"world"]
>>> a = np.array(x, dtype="S7")
>>> print(a[0])
b"hello"
>>> a[0] == x[0]
False
Если вам нужно хранить и передавать любые завершающие нулевые байты, вам потребуется использовать неструктурированный тип данных void:
>>> a = np.array(x, dtype="V7")
>>> a
array([b'\x68\x65\x6C\x6C\x6F\x00\x00', b'\x77\x6F\x72\x6C\x64\x00\x00'],
dtype='|V7')
>>> a[0] == np.void(x[0])
True
Расширенные типы, не перечисленные выше, рассматриваются в разделе Структурированные массивы.
Связь между типами данных NumPy и типами данных C#
NumPy предоставляет как имена типов с указанием размера в битах, так и имена на основе имён типов C. Поскольку определение типов C зависит от платформы, это означает, что явно указанные размеры в битах следует предпочитать, чтобы избежать платформозависимого поведения в программах, использующих NumPy.
Для упрощения интеграции с кодом на C, где более естественно ссылаться на зависящие от платформы типы C, NumPy также предоставляет псевдонимы типов, соответствующие типам C для платформы. Некоторые типы данных имеют завершающее подчеркивание, чтобы избежать путаницы со встроенными именами типов Python, такими как numpy.bool_.
Каноническое имя Python API |
Имя Python API в "C-подобном" стиле |
Фактический тип C |
Описание |
|---|---|---|---|
Н/Д |
|
Логическое значение (True или False), хранящееся как байт. |
|
|
Целочисленный тип, определённый платформой, с 8 битами. |
||
|
Целочисленный тип, определённый платформой, с 8 битами без знака. |
||
|
Определяемый платформой целочисленный тип с 16 битами. |
||
|
Определяемый платформой целочисленный тип с 16 битами без знака. |
||
|
Определяемый платформой целочисленный тип с 32 битами. |
||
|
Платформо-определённый целочисленный тип с 32 битами без знака. |
||
Н/Д |
|
Целочисленный тип, определённый платформой, размером |
|
Н/Д |
|
Целочисленный тип, определенный платформой, способный хранить максимальный размер выделения. |
|
Н/Д |
|
|
Гарантированно содержит указатели. Только символьный код (Python и C). |
Н/Д |
|
|
Гарантированно хранит указатели без знака. Только символьный код (Python и C). |
|
Целочисленный тип, определенный платформой, с как минимум 32 битами. |
||
|
Целочисленный тип, определенный платформой, с как минимум 32 битами без знака. |
||
Н/Д |
|
Целочисленный тип, определённый платформой, с как минимум 64 битами. |
|
Н/Д |
|
Целочисленный тип, определённый платформой, с не менее чем 64 битами без знака. |
|
Н/Д |
Число с плавающей запятой половинной точности: знаковый бит, 5 бит экспоненты, 10 бит мантиссы. |
||
|
Определяемая платформой одинарная точность с плавающей точкой: обычно знаковый бит, 8 бит экспоненты, 23 бита мантиссы. |
||
|
Платформо-определённое число двойной точности: обычно знаковый бит, 11 бит экспоненты, 52 бита мантиссы. |
||
|
|
Расширенная точность с плавающей запятой, определённая платформой. |
|
|
Комплексное число, представленное двумя числами с плавающей запятой одинарной точности (действительная и мнимая части). |
||
|
Комплексное число, представленное двумя числами с плавающей запятой двойной точности (действительная и мнимая части). |
||
|
|
Комплексное число, представленное двумя числами с расширенной точностью (действительная и мнимая части). |
Поскольку многие из них имеют платформозависимые определения, предоставляется набор псевдонимов фиксированного размера (см. Псевдонимы с размером).
Скаляры массива#
NumPy обычно возвращает элементы массивов как скаляры массива (скаляр
с ассоциированным dtype). Скаляры массива отличаются от скаляров Python, но
в большинстве случаев их можно использовать взаимозаменяемо (основное
исключение — версии Python старше v2.x, где целочисленные скаляры массива
не могут использоваться как индексы для списков и кортежей). Есть некоторые
исключения, например, когда код требует очень специфичных атрибутов скаляра
или когда он явно проверяет, является ли значение скаляром Python. Обычно
проблемы легко решаются явным преобразованием скаляров массива
в скаляры Python с использованием соответствующей функции типа Python
(например, int, float, complex, str).
Основное преимущество использования скаляров массива заключается в том, что они сохраняют тип массива (в Python может не быть соответствующего скалярного типа, например, int16). Поэтому использование скаляров массива гарантирует
идентичное поведение между массивами и скалярами, независимо от того,
находится ли значение внутри массива или нет. Скаляры NumPy также имеют многие из тех же
методов, что и массивы.
Ошибки переполнения#
Фиксированный размер числовых типов NumPy может вызывать ошибки переполнения, когда значение требует больше памяти, чем доступно в типе данных. Например,
numpy.power вычисляет 100 ** 9 корректно для 64-битных целых чисел,
но даёт -1486618624 (некорректно) для 32-битного целого числа.
>>> np.power(100, 9, dtype=np.int64)
1000000000000000000
>>> np.power(100, 9, dtype=np.int32)
np.int32(-1486618624)
Поведение целочисленных типов NumPy и Python значительно различается при переполнении и может сбить с толку пользователей, ожидающих, что целые числа NumPy будут вести себя аналогично целым числам Python. int. В отличие от NumPy, размер Python
int гибкая. Это означает, что целые числа Python могут расширяться для размещения
любого целого числа и не будут переполняться.
NumPy предоставляет numpy.iinfo и numpy.finfo для проверки
минимальных или максимальных значений целочисленных и чисел с плавающей точкой NumPy
соответственно
>>> np.iinfo(int) # Bounds of the default integer on this system.
iinfo(min=-9223372036854775808, max=9223372036854775807, dtype=int64)
>>> np.iinfo(np.int32) # Bounds of a 32-bit integer
iinfo(min=-2147483648, max=2147483647, dtype=int32)
>>> np.iinfo(np.int64) # Bounds of a 64-bit integer
iinfo(min=-9223372036854775808, max=9223372036854775807, dtype=int64)
Если 64-битные целые числа всё ещё слишком малы, результат может быть приведён к числу с плавающей точкой. Числа с плавающей точкой предлагают больший, но неточный диапазон возможных значений.
>>> np.power(100, 100, dtype=np.int64) # Incorrect even with 64-bit int
0
>>> np.power(100, 100, dtype=np.float64)
1e+200
Точность чисел с плавающей запятой#
Многие функции в NumPy, особенно те, что в numpy.linalg, включают операции с плавающей запятой, которые могут вносить небольшие неточности из-за способа представления десятичных чисел компьютерами. Например, при выполнении базовых арифметических операций с числами с плавающей запятой:
>>> 0.3 - 0.2 - 0.1 # This does not equal 0 due to floating-point precision
-2.7755575615628914e-17
Для обработки таких случаев рекомендуется использовать функции, такие как np.isclose для сравнения значений, а не проверки точного равенства:
>>> np.isclose(0.3 - 0.2 - 0.1, 0, rtol=1e-05) # Check for closeness to 0
True
В этом примере, np.isclose учитывает небольшие неточности, возникающие в вычислениях с плавающей запятой, применяя относительный допуск, что гарантирует, что результаты в пределах небольшого порога считаются близкими.
Для информации о точности вычислений см. Арифметика с плавающей точкой.
Расширенная точность#
Числа с плавающей точкой в Python обычно являются 64-битными числами с плавающей точкой, почти эквивалентными numpy.float64. В некоторых необычных ситуациях может быть
полезно использовать числа с плавающей запятой с большей точностью. Возможно ли это
в numpy, зависит от оборудования и среды разработки:
в частности, машины x86 предоставляют аппаратную плавающую запятую
с 80-битной точностью, и хотя большинство компиляторов C предоставляют это как их
long double тип, MSVC (стандарт для сборок Windows) делает
long double идентично double (64 бита). NumPy использует long double доступен как numpy.longdouble (и
np.clongdouble для комплексных чисел). Вы можете узнать, что предоставляет ваш numpy с помощью np.finfo(np.longdouble).
NumPy не предоставляет dtype с большей точностью, чем C
long double; в частности, 128-битный IEEE четверной точности
тип данных (FORTRAN’s REAL*16) недоступно.
Для эффективного выравнивания памяти, numpy.longdouble обычно хранится с дополнением нулевыми битами, либо до 96, либо до 128 бит. Что эффективнее, зависит от оборудования и среды разработки; обычно в 32-битных системах дополняется до 96 бит, а в 64-битных системах обычно дополняется до 128 бит. np.longdouble дополняется до системного значения по умолчанию; np.float96 и np.float128 предоставляются для пользователей, которые
хотят определённое заполнение. Несмотря на названия, np.float96 и
np.float128 предоставляют только столько точности, сколько np.longdouble,
то есть 80 бит на большинстве машин x86 и 64 бита в стандартных
сборках Windows.
Имейте в виду, что даже если numpy.longdouble предлагает большую точность, чем
python float, легко потерять эту дополнительную точность, поскольку
Python часто принудительно преобразует значения через float. Например, % оператор форматирования требует преобразования своих аргументов в стандартные типы Python, и поэтому невозможно сохранить расширенную точность, даже если запрошено много десятичных знаков. Может быть полезно протестировать ваш код со значением
1 + np.finfo(np.longdouble).eps.