Давайте попробуем найти соответствующие биты в документации.
из строки документа np.array
:
array (...)
[...]
Параметры
[...]
dtype: тип данных, необязательный Требуемый тип данных для массива.Если не указан, то тип будет определен как минимальный тип, необходимый для хранения объектов в последовательности. Этот аргумент может использоваться только для «выгрузки» массива.Для удушения используйте метод .astype (t).
[...]
(мой акцент)
Следует отметить, что это неПолностью точный, например, для целочисленных массивов, целое число по умолчанию в системе (C) предпочтительнее, чем целочисленные типы меньшего размера, как видно из вашего примера.
Обратите внимание, что для быстрой работы numpy важно, чтобы все элементы массивабыть одинакового размера.В противном случае, как бы вы быстро нашли 1000-й элемент, скажем?Кроме того, смешивание типов не сэкономит столько места, поскольку вам придется хранить типы каждого отдельного элемента поверх необработанных данных.
Ваш второй вопрос.Прежде всего.В numpy есть правила продвижения типа.Лучшим документом, который я смог найти для этого, является строка документа np.result_type
:
result_type (...) result_type (* arrays_and_dtypes)
Возвращает тип, полученный в результате примененияПравила продвижения типов NumPy к аргументам.
Продвижение типов в NumPy работает аналогично правилам в таких языках, как C ++, с некоторыми небольшими отличиями.Когда используются и скаляры, и массивы, тип массива имеет приоритет и учитывается фактическое значение скаляра.
Например, вычисление 3 * a, где a - это массив 32-битных чисел с плавающей запятой,интуитивно должно привести к 32-битному плавающему выводу.Если 3 является 32-разрядным целым числом, правила NumPy указывают, что он не может преобразовать без потерь в 32-разрядное число с плавающей запятой, поэтому тип результата должен быть 64-разрядным.Изучив значение константы '3', мы увидим, что она вписывается в 8-битное целое число, которое может быть без потерь приведено к 32-битному числу с плавающей запятой.
[...]
Я не цитирую все здесь, обратитесь к строке документации для более подробной информации.
Точный способ применения этих правил сложен и, по-видимому, представляет собой компромисс между интуитивностью и эффективностью..
Например, выбор основан на входах, а не на результате
>>> A = np.full((2, 2), 30000, 'i2')
>>>
>>> A
array([[30000, 30000],
[30000, 30000]], dtype=int16)
# 1
>>> A + 30000
array([[-5536, -5536],
[-5536, -5536]], dtype=int16)
# 2
>>> A + 60000
array([[90000, 90000],
[90000, 90000]], dtype=int32)
Здесь эффективность выигрывает.Возможно, было бы более интуитивно понятно, что # 1 ведет себя как # 2.Но это будет дорого.
Кроме того, и, что более прямо связано с вашим вопросом, продвижение по типу применяется только на месте, а не на месте:
# out-of-place
>>> A_new = A + 60000
>>> A_new
array([[90000, 90000],
[90000, 90000]], dtype=int32)
# in-place
>>> A += 60000
>>> A
array([[24464, 24464],
[24464, 24464]], dtype=int16)
или
# out-of-place
>>> A_new = np.where([[0, 0], [0, 1]], 60000, A)
>>> A_new
array([[30000, 30000],
[30000, 60000]], dtype=int32)
# in-place
>>> A[1, 1] = 60000
>>> A
array([[30000, 30000],
[30000, -5536]], dtype=int16)
Опять же, это может показаться неинтуитивным.Однако для этого выбора есть веские причины.
И они должны ответить на ваш второй вопрос:
Переход на больший тип d потребует выделения большего буфера и копирования всех данных.Мало того, что это будет дорого для больших массивов.
Многие идиомы в numpy полагаются на представления и тот факт, что запись в представление напрямую изменяет базовый массив (и другие перекрывающиеся представления).Поэтому массив не может свободно менять свой буфер данных, когда ему это нравится.Чтобы не нарушать связь между представлениями, массиву необходимо было бы знать обо всех представлениях в своем буфере данных, что привело бы к большим накладным расходам администратора, и все эти представления также должны были бы изменить свои указатели данных и метаданные.И если первый массив сам по себе является представлением (скажем, срезом) другого массива, все становится еще хуже.
Полагаю, мы можем согласиться с тем, что это не стоит того, и поэтому типы не продвигаютсяместо.