Примечания к выпуску NumPy 1.17.0#

Этот релиз NumPy содержит ряд новых функций, которые должны значительно улучшить его производительность и полезность, см. Основные моменты ниже для краткого обзора. Поддерживаемые версии Python — 3.5-3.7, обратите внимание, что Python 2.7 был исключён. Python 3.8b2 должен работать с выпущенными исходными пакетами, но никаких гарантий на будущее нет.

Разработчикам нижестоящих проектов следует использовать Cython >= 0.29.11 для поддержки Python 3.8 и OpenBLAS >= 3.7 (пока не выпущен), чтобы избежать проблем на архитектуре Skylake. Колеса NumPy на PyPI собраны из ветки разработки OpenBLAS, чтобы избежать этих проблем.

Основные моменты#

  • Новый расширяемый random модуль вместе с четырьмя выбираемыми генераторы случайных чисел и улучшенная инициализация генератора, предназначенная для использования в параллельных процессах, была добавлена. В настоящее время доступны следующие генераторы битов: MT19937, PCG64, Philox, и SFC64. См. ниже в разделе Новые возможности.

  • NumPy FFT реализация была изменена с fftpack на pocketfft, что привело к более быстрым и точным преобразованиям и лучшей обработке наборов данных простой длины. См. ниже в разделе Улучшения.

  • Новые методы сортировки: поразрядная сортировка и timsort. В настоящее время невозможно выбрать, какой из них будет использоваться. Они жестко привязаны к типу данных и используются, когда либо stable или mergesort передаётся как метод. Смотрите ниже в разделе Улучшения.

  • Переопределение функций numpy теперь возможно по умолчанию, см. __array_function__ ниже.

Новые функции#

  • numpy.errstate теперь также является декоратором функции

Устаревшие функции#

numpy.polynomial функции предупреждают при передаче float вместо int#

Ранее функции в этом модуле принимали float значения при условии, что они были целочисленными (1.0, 2.0, и т.д.). Для согласованности с остальной частью numpy, это теперь устарело, и в будущем будет вызывать TypeError.

Аналогично, передача числа с плавающей точкой, такого как 0.5 вместо целого числа теперь вызовет TypeError вместо предыдущего ValueError.

Устарело numpy.distutils.exec_command и temp_file_name#

Внутреннее использование этих функций было переработано, и есть лучшие альтернативы. Замените exec_command с subprocess.Popen и temp_file_name с tempfile.mkstemp.

Флаг записи массивов, обёрнутых в C-API#

Когда массив создается из C-API для обертывания указателя на данные, единственное указание на возможность чтения-записи данных — это writeable флаг, установленный при создании. Опасно принудительно устанавливать флаг в записываемый. В будущем будет невозможно переключить флаг записи на True из python. Это устаревание не должно затронуть многих пользователей, поскольку массивы, созданные таким образом, очень редки на практике и доступны только через NumPy C-API.

numpy.nonzero больше не должен вызываться на 0d массивах#

Поведение numpy.nonzero на 0d массивах было неожиданным, делая его использование почти всегда некорректным. Если старое поведение было задумано, его можно сохранить без предупреждения, используя nonzero(atleast_1d(arr)) вместо nonzero(arr). В будущем релизе, скорее всего, это вызовет ValueError.

Запись в результат numpy.broadcast_arrays будет предупреждать#

Обычно numpy.broadcast_arrays возвращает записываемый массив с внутренним перекрытием, что делает его небезопасным для записи. В будущей версии будет установлен writeable флаг для False, и требуют от пользователей вручную установить его в True если они уверены, что это то, что они хотят сделать. Теперь запись в него будет выдавать предупреждение об устаревании с инструкциями по установке writeable флаг True. Обратите внимание, что если проверить флаг перед его установкой, можно обнаружить, что он уже True. Явная установка этого параметра, хотя и потребуется в будущих версиях, очищает внутренний флаг, используемый для генерации предупреждения об устаревании. Для уменьшения путаницы добавлен FutureWarning будет выдаваться при доступе к writeable состояние флага для уточнения противоречия.

Обратите внимание, что для протокола буфера на стороне C такой массив вернет буфер только для чтения, если не запрошен буфер для записи. Если запрошен буфер для записи, будет выдано предупреждение. При использовании Cython, const квалификатор следует использовать с такими массивами, чтобы избежать предупреждения (например, cdef const double[::1] view).

Будущие изменения#

Поля размерности 1 в типах данных не будут сворачиваться в скаляры в будущей версии#

В настоящее время поле, указанное как [(name, dtype, 1)] или "1type" интерпретируется как скалярное поле (т.е., то же самое, что [(name, dtype)] или [(name, dtype, ()]). Теперь это вызывает FutureWarning; в будущей версии это будет интерпретироваться как поле формы (1,), т.е. то же самое, что [(name, dtype, (1,))] или "(1,)type" (согласованно с [(name, dtype, n)] / "ntype" с n>1, что уже эквивалентно [(name, dtype, (n,)] / "(n,)type").

Примечания по совместимости#

float16 округление субнормальных чисел#

Преобразование из числа с плавающей точкой другой точности в float16 использовалось некорректное округление в некоторых крайних случаях. Это означает, что в редких случаях субнормальные результаты теперь будут округляться вверх вместо вниз, изменяя последний бит (ULP) результата.

Знаковый ноль при использовании divmod#

Начиная с версии 1.12.0, numpy некорректно возвращал отрицательный ноль при использовании divmod и floor_divide functions, когда результат был нулевым. Например:

>>> np.zeros(10)//1
array([-0., -0., -0., -0., -0., -0., -0., -0., -0., -0.])

С этим выпуском результат правильно возвращается как положительно знаковый ноль:

>>> np.zeros(10)//1
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])

MaskedArray.mask теперь возвращает представление маски, а не саму маску#

Возврат самой маски был небезопасен, так как её можно было изменить на месте, что нарушило бы ожидания кода маскированного массива. Поведение mask теперь согласуется с data, что также возвращает представление.

Базовая маска все еще может быть доступна с помощью ._mask если это необходимо. Тесты, которые содержат assert x.mask is not y.mask или аналогичные потребуют обновления.

Не искать __buffer__ атрибут в numpy.frombuffer#

Поиск __buffer__ атрибут в numpy.frombuffer был недокументированным и нефункциональным. Этот код был удален. При необходимости используйте frombuffer(memoryview(obj), ...) вместо этого.

out буферизуется для перекрытий памяти в take, choose, put#

Если аргумент out для этих функций предоставлен и имеет перекрытие памяти с другими аргументами, он теперь буферизуется, чтобы избежать поведения, зависящего от порядка.

Распаковка при загрузке требует явного согласия#

Функции load, и lib.format.read_array принять allow_pickle ключевое слово, которое теперь по умолчанию False в ответ на CVE-2019-6446.

Потенциальные изменения в потоке случайных чисел в старом модуле random#

Из-за ошибок в применении log к случайным числам с плавающей запятой, поток может измениться при выборке из beta, binomial, laplace, logistic, logseries или multinomial если 0 генерируется в базовом MT19937 случайный поток. Существует 1 в \(10^{53}\) вероятность этого события, поэтому вероятность того, что поток изменится для любого заданного сида, крайне мала. Если 0 встречается в базовом генераторе, то некорректное значение, полученное (либо numpy.inf или numpy.nan) теперь удаляется.

i0 теперь всегда возвращает результат с той же формой, что и входные данные#

Ранее выходные данные сжимались, так что, например, входные данные с единственным элементом приводили к возврату скаляра массива, а входные данные с такими формами, как (10, 1) даст результаты, которые не будут транслироваться на входные данные.

Обратите внимание, что мы обычно рекомендуем реализацию SciPy вместо numpy: это настоящая ufunc, написанная на C, и более чем на порядок быстрее.

can_cast больше не предполагает, что все небезопасные преобразования типов разрешены#

Ранее, can_cast возвращён True для почти всех входных данных для casting='unsafe', даже для случаев, когда приведение было невозможно, например, из структурированного dtype в обычный. Это исправлено, делая его более согласованным с фактическим приведением с использованием, например, .astype метод.

ndarray.flags.writeable может быть переключено на true немного чаще#

В редких случаях не удавалось переключить массив из режима только для чтения в режим записи, хотя базовый массив доступен для записи. Это может произойти, если промежуточный ndarray.base объект доступен для записи. Ранее только самый глубокий базовый объект учитывался для этого решения. Однако в редких случаях этот объект не имеет необходимой информации. В таких случаях переключение на запись никогда не разрешалось. Теперь это исправлено.

Изменения в C API#

аргументы измерения или шага теперь передаются по npy_intp const*#

Ранее эти аргументы функций объявлялись как более строгие npy_intp*, что предотвращало передачу постоянных данных вызывающей стороной. Это изменение обратно совместимо, но теперь позволяет код, подобный:

npy_intp const fixed_dims[] = {1, 2, 3};
// no longer complains that the const-qualifier is discarded
npy_intp size = PyArray_MultiplyList(fixed_dims, 3);

Новые возможности#

Новый расширяемый numpy.random модуль с выбираемыми генераторами случайных чисел#

Новый расширяемый numpy.random модуль вместе с четырьмя выбираемыми генераторами случайных чисел и улучшенным начальным заполнением, предназначенным для использования в параллельных процессах, был добавлен. В настоящее время доступные Bit Generators являются MT19937, PCG64, Philox, и SFC64. PCG64 является новым значением по умолчанию, в то время как MT19937 сохраняется для обратной совместимости. Обратите внимание, что устаревший модуль random не изменен и теперь заморожен, ваши текущие результаты не изменятся. Дополнительная информация доступна в Описание изменения API и в top-level view документация.

libFLAME#

Поддержка сборки NumPy с пакетом линейной алгебры libFLAME в качестве реализации LAPACK, см. libFLAME подробности.

Пользовательский порядок обнаружения BLAS#

distutils теперь использует переменную окружения, разделенную запятыми и нечувствительную к регистру, для определения порядка обнаружения библиотек BLAS. По умолчанию NPY_BLAS_ORDER=mkl,blis,openblas,atlas,accelerate,blas. Однако, чтобы принудительно использовать OpenBLAS, просто сделайте:

NPY_BLAS_ORDER=openblas python setup.py build

что вынуждает использовать OpenBLAS. Это может быть полезно для пользователей, у которых установлен MKL, но которые хотят попробовать другие реализации.

Пользовательский порядок обнаружения LAPACK#

numpy.distutils теперь использует переменную окружения, разделенную запятыми и нечувствительную к регистру, для определения порядка обнаружения библиотек LAPACK. По умолчанию NPY_LAPACK_ORDER=mkl,openblas,flame,atlas,accelerate,lapack. Однако, чтобы принудительно использовать OpenBLAS, просто сделайте:

NPY_LAPACK_ORDER=openblas python setup.py build

что вынуждает использовать OpenBLAS. Это может быть полезно для пользователей, у которых установлен MKL, но которые хотят попробовать другие реализации.

Timsort и поразрядная сортировка заменили сортировку слиянием для стабильной сортировки#

Были реализованы поразрядная сортировка и Timsort, которые теперь используются вместо сортировки слиянием. Из-за необходимости сохранения обратной совместимости, сортировка kind опции "stable" и "mergesort" были сделаны псевдонимами друг друга, причём фактическая реализация сортировки зависит от типа массива. Сортировка по основанию используется для небольших целочисленных типов размером 16 бит или меньше, а timsort — для остальных типов. Timsort обеспечивает улучшенную производительность на данных, которые уже или почти отсортированы, и работает как сортировка слиянием на случайных данных, требуя \(O(n/2)\) рабочее пространство. Подробности алгоритма timsort можно найти на CPython listsort.txt.

packbits и unpackbits принимать order ключевое слово#

The order ключевое слово по умолчанию равно big, и будет упорядочивать биты соответственно. Для 'order=big' 3 станет [0, 0, 0, 0, 0, 0, 1, 1], и [1, 1, 0, 0, 0, 0, 0, 0] для order=little

unpackbits теперь принимает count параметр#

count позволяет заранее ограничить количество битов, которые будут распакованы, вместо последующего изменения формы и ограничения, что делает packbits операция обратима, и распаковка менее расточительна. Счётчики, превышающие количество доступных битов, добавляют нулевое заполнение. Отрицательные счётчики обрезают биты с конца вместо подсчёта с начала. None счётчики реализуют существующее поведение распаковки всего.

linalg.svd и linalg.pinv может быть быстрее на эрмитовых входных данных#

Эти функции теперь принимают hermitian аргумент, соответствующий добавленному в linalg.matrix_rank в версии 1.14.0.

Операция divmod теперь поддерживается для двух timedelta64 операнды#

Оператор divmod теперь обрабатывает два timedelta64 операнды, с сигнатурой типа mm->qm.

fromfile теперь принимает offset аргумент#

Эта функция теперь принимает offset ключевой аргумент для бинарных файлов, который указывает смещение (в байтах) от текущей позиции файла. По умолчанию 0.

Новый режим "empty" для pad#

Этот режим дополняет массив до желаемой формы без инициализации новых элементов.

Скаляры с плавающей точкой реализуют as_integer_ratio чтобы соответствовать встроенному float#

Это возвращает пару (числитель, знаменатель), которую можно использовать для построения fractions.Fraction.

Структурированный dtype объекты могут индексироваться несколькими именами полей#

arr.dtype[['a', 'b']] теперь возвращает dtype, эквивалентный arr[['a', 'b']].dtype, для согласованности с arr.dtype['a'] == arr['a'].dtype.

Подобно dtype структурированных массивов, индексированных списком полей, этот dtype имеет то же самое itemsize как исходный, но сохраняет только подмножество полей.

Это означает, что arr[['a', 'b']] и arr.view(arr.dtype[['a', 'b']]) эквивалентны.

.npy файлы поддерживают имена полей в юникоде#

Была введена новая версия формата 3.0, которая позволяет структурированным типам с именами полей не на латинице. Это используется автоматически при необходимости.

Улучшения#

Утверждения сравнения массивов включают максимальные различия#

Сообщения об ошибках из тестов сравнения массивов, таких как testing.assert_allclose теперь включают «максимальную абсолютную разницу» и «максимальную относительную разницу» в дополнение к предыдущему проценту «несоответствия». Эта информация упрощает обновление абсолютных и относительных допусков ошибок.

Замена основанного на fftpack fft модуль библиотекой pocketfft#

Обе реализации имеют общего предка (Fortran77 FFTPACK от Paul N. Swarztrauber), но pocketfft содержит дополнительные модификации, которые улучшают как точность, так и производительность в некоторых случаях. Для длин БПФ, содержащих большие простые множители, pocketfft использует алгоритм Блюстейна, который сохраняет \(O(N log N)\) временная сложность выполнения вместо ухудшения до \(O(N*N)\) для простых длин. Также точность для вещественных FFT с почти простыми длинами улучшилась и сравнялась с точностью комплексных FFT.

Дальнейшие улучшения для ctypes поддержка в numpy.ctypeslib#

Новый numpy.ctypeslib.as_ctypes_type функция была добавлена, которая может использоваться для преобразования dtype в наилучшее предположение ctypes тип. Благодаря этой новой функции, numpy.ctypeslib.as_ctypes теперь поддерживает гораздо более широкий диапазон типов массивов, включая структуры, логические значения и целые числа с нестандартным порядком байтов.

numpy.errstate теперь также является декоратором функции#

В настоящее время, если у вас есть функция, такая как:

def foo():
    pass

и вы хотите обернуть все это в errstate, вам нужно переписать это так:

def foo():
    with np.errstate(...):
        pass

но с этим изменением вы можете сделать:

@np.errstate(...)
def foo():
    pass

тем самым сохраняя уровень вложенности

numpy.exp и numpy.log ускорение для реализации float32#

реализация float32 exp и log теперь используют преимущества набора инструкций AVX2/AVX512, которые определяются во время выполнения. exp имеет максимальную ошибку ulp 2.52 и log имеет максимальную ошибку ulp 3.83.

Улучшена производительность numpy.pad#

Производительность функции была улучшена для большинства случаев путем заполнения предварительно выделенного массива желаемой формой с заполнением вместо использования конкатенации.

numpy.interp более надежно обрабатывает бесконечности#

В некоторых случаях, когда interp ранее возвращал nan, теперь он возвращает соответствующую бесконечность.

Поддержка Pathlib для fromfile, tofile и ndarray.dump#

fromfile, ndarray.ndarray.tofile и ndarray.dump теперь поддерживают pathlib.Path тип для file/fid параметр.

Специализированный isnan, isinf, и isfinite ufuncs для типов bool и int#

Булевские и целочисленные типы не способны хранить nan и inf значений, что позволяет нам предоставлять специализированные универсальные функции, которые работают до 250 раз быстрее, чем предыдущий подход.

isfinite поддерживает datetime64 и timedelta64 типы#

Ранее, isfinite использовался для вызова TypeError при использовании на этих двух типах.

Новые ключевые слова, добавленные в nan_to_num#

nan_to_num теперь принимает ключевые слова nan, posinf и neginf позволяя пользователю определить значение для замены nan, положительные и отрицательные np.inf значения соответственно.

MemoryErrors, вызванные выделением слишком больших массивов, более описательны#

Часто причиной MemoryError является некорректное вещание, которое приводит к очень большой и неправильной форме. Сообщение об ошибке теперь включает эту форму, чтобы помочь диагностировать причину сбоя.

floor, ceil, и trunc теперь учитываются встроенные магические методы#

Эти ufunc теперь вызывают __floor__, __ceil__, и __trunc__ методы при вызове на объектных массивах, делая их совместимыми с decimal.Decimal и fractions.Fraction объекты.

quantile теперь работает на fraction.Fraction и decimal.Decimal объекты#

В целом, это более корректно обрабатывает массивы объектов и избегает операций с плавающей точкой, если используются типы для точной арифметики.

Поддержка массивов объектов в matmul#

Теперь можно использовать matmul (или @ оператор) с массивами объектов. Например, теперь можно сделать:

from fractions import Fraction
a = np.array([[Fraction(1, 2), Fraction(1, 3)], [Fraction(1, 3), Fraction(1, 2)]])
b = a @ a

Изменения#

median и percentile семейство функций больше не предупреждает о nan#

numpy.median, numpy.percentile, и numpy.quantile используется для выдачи RuntimeWarning при встрече с nan. Поскольку они возвращают nan значение, предупреждение избыточно и было удалено.

timedelta64 % 0 поведение скорректировано для возврата NaT#

Операция модуля с двумя np.timedelta64 операнды теперь возвращает NaT в случае деления на ноль, а не возврата нуля

Функции NumPy теперь всегда поддерживают переопределения с __array_function__#

NumPy теперь всегда проверяет __array_function__ метод для реализации переопределений функций NumPy на не-NumPy массивах, как описано в NEP 18. Функция была доступна для тестирования в NumPy 1.16, если установлены соответствующие переменные окружения, но теперь всегда включена.

lib.recfunctions.structured_to_unstructured не сжимает представления с одним полем#

Ранее structured_to_unstructured(arr[['a']]) привело бы к сжатому результату, несовместимому с structured_to_unstructured(arr[['a', b']]). Это было случайно. Прежнее поведение можно сохранить с помощью structured_to_unstructured(arr[['a']]).squeeze(axis=-1) или гораздо проще, arr['a'].

clip теперь использует ufunc в основе#

Это означает, что регистрация функций clip для пользовательских типов данных в C через descr->f->fastclip устарел - вместо этого следует использовать механизм регистрации ufunc, прикрепляя к np.core.umath.clip универсальная функция.

Это также означает, что clip принимает where и casting аргументы, и могут быть переопределены с помощью __array_ufunc__.

Следствием этого изменения является то, что некоторые поведения старого clip были устаревшими:

  • Передача nan означает "не обрезать" как одну или обе границы. Это не работало во всех случаях в любом случае, и может быть лучше обработано передачей бесконечностей соответствующего знака.

  • Использование «небезопасного» приведения по умолчанию, когда out аргумент передается. Используя casting="unsafe" явно отключит это предупреждение.

Кроме того, есть некоторые крайние случаи с изменениями поведения:

  • Заполнение max < min изменился, чтобы быть более согласованным между типами данных, но на это не следует полагаться.

  • Скаляр min и max участвуют в правилах продвижения типов, как и во всех других универсальных функциях.

__array_interface__ offset теперь работает как описано в документации#

Интерфейс может использовать offset значение, которое было ошибочно проигнорировано.

Протокол Pickle в savez установлено в 3 для force zip64 флаг#

savez не использовал force_zip64 флаг, который ограничивал размер архива 2 ГБ. Но использование флага требует от нас использования протокола pickle 3 для записи object массивы. Используемый протокол был обновлен до версии 3, что означает, что архив не будет читаться Python2.

Структурированные массивы, индексированные несуществующими полями, вызывают KeyError не ValueError#

arr['bad_field'] на структурированном типе вызывает KeyError, для согласованности с dict['bad_field'].