что делает .dtype? - PullRequest
       4

что делает .dtype?

14 голосов
/ 27 февраля 2012

Я новичок в Python и не понимаю, что делает .dtype.
Например:

>>> aa
array([1, 2, 3, 4, 5, 6, 7, 8])
>>> aa.dtype = "float64"
>>> aa
array([  4.24399158e-314,   8.48798317e-314,   1.27319747e-313,
     1.69759663e-313])

Я думал, что dtype - это свойство aa, которое должно быть int, и если я присваиваю aa.dtype = "float64"
, тогда aa должно стать array([1.0 ,2.0 ,3.0, 4.0, 5.0, 6.0, 7.0, 8.0]).

Почему он меняет свое значение и размер?
Что это значит?

Я действительно учился на куске кода, и я вставлю его сюда:

def to_1d(array):
 """prepares an array into a 1d real vector"""
    a = array.copy() # copy the array, to avoid changing global
    orig_dtype = a.dtype
    a.dtype = "float64" # this doubles the size of array
    orig_shape = a.shape
    return a.ravel(), (orig_dtype, orig_shape) #flatten and return

Я думаю, что это не должно изменить значение входного массива, а только изменить его размер. Запутался, как работает функция

Ответы [ 4 ]

41 голосов
/ 27 февраля 2012

Во-первых, код, который вы изучаете, имеет недостатки.Это почти наверняка не делает то, что, по мнению оригинального автора, было сделано на основе комментариев в коде.

Что, вероятно, имел в виду автор, было так:

def to_1d(array):
    """prepares an array into a 1d real vector"""
    return array.astype(np.float64).ravel()

Однако, если array всегда будет массивом комплексных чисел, тогда оригинальный код имеет некоторый смысл.

Единственный случай, когда просмотр массива (a.dtype = 'float64' эквивалентен выполнению a = a.view('float64')) удвоит его размер:если это сложный массив (numpy.complex128) или 128-битный массив с плавающей запятой.Для любого другого dtype это не имеет особого смысла.

Для конкретного случая complex array исходный код преобразует что-то вроде np.array([0.5+1j, 9.0+1.33j]) в np.array([0.5, 1.0, 9.0, 1.33]).

Более чистый способ написания:

def complex_to_iterleaved_real(array):
     """prepares a complex array into an "interleaved" 1d real vector"""
    return array.copy().view('float64').ravel()

(на данный момент я игнорирую часть о возвращении исходного dtype и формы.)


Справочная информация о numy массивах

Чтобы объяснить, что здесь происходит, вам нужно немного понять, что такое numpy массивы.

Массив numpy состоит из «сырого» буфера памяти, который интерпретируется как массив через «views».Вы можете думать обо всех массивах numpy как о представлениях.

Представления, в смысле numpy, представляют собой просто другой способ нарезки и нарезания одного и того же буфера памяти без создания копии.

Представление имеетформа, тип данных (dtype), смещение и шаги.Там, где это возможно, операции индексирования / изменения формы в массиве numpy просто возвращают представление исходного буфера памяти.

Это означает, что такие вещи, как y = x.T или y = x[::2], не используют никакой дополнительной памяти, и нене копировать x.

Итак, если у нас есть массив, подобный следующему:

import numpy as np
x = np.array([1,2,3,4,5,6,7,8,9,10])

Мы могли бы изменить его, выполнив:

x = x.reshape((2, 5))

или

x.shape = (2, 5)

Для удобства чтения первый вариант лучше.Они (почти) точно эквивалентны, хотя.Ни один из них не сделает копию, которая будет занимать больше памяти (первая приведет к созданию нового объекта python, но это не относится к делу, на данный момент.).


Dtypes и views

То же самое относится и к dtype.Мы можем просмотреть массив как другой тип dtype, установив x.dtype или вызвав x.view(...).

. Таким образом, мы можем сделать что-то вроде этого:

import numpy as np
x = np.array([1,2,3], dtype=np.int)

print 'The original array'
print x

print '\n...Viewed as unsigned 8-bit integers (notice the length change!)'
y = x.view(np.uint8)
print y

print '\n...Doing the same thing by setting the dtype'
x.dtype = np.uint8
print x

print '\n...And we can set the dtype again and go back to the original.'
x.dtype = np.int
print x

Что даст:

The original array
[1 2 3]

...Viewed as unsigned 8-bit integers (notice the length change!)
[1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0]

...Doing the same thing by setting the dtype
[1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0]

...And we can set the dtype again and go back to the original.
[1 2 3]

Имейте в виду, однако, что это дает вам низкоуровневый контроль над тем, как интерпретируется буфер памяти.

Например:

import numpy as np
x = np.arange(10, dtype=np.int)

print 'An integer array:', x
print 'But if we view it as a float:', x.view(np.float)
print "...It's probably not what we expected..."

Это дает:

An integer array: [0 1 2 3 4 5 6 7 8 9]
But if we view it as a float: [  0.00000000e+000   4.94065646e-324   
   9.88131292e-324   1.48219694e-323   1.97626258e-323   
   2.47032823e-323   2.96439388e-323   3.45845952e-323
   3.95252517e-323   4.44659081e-323]
...It's probably not what we expected...

Итак, мы интерпретируем базовые биты исходного буфера памяти как числа с плавающей запятой, в данном случае.

Если бы мы хотели сделать новую копию, в которой целые числа были преобразованы как плавающие, мы использовали бы x.astype (np.float).


Комплексные числа

Комплексные числа хранятся (как в C, Python, так и в numpy) как два числа с плавающей запятой.Первая - это действительная часть, а вторая - мнимая часть.

Итак, если мы сделаем:

import numpy as np
x = np.array([0.5+1j, 1.0+2j, 3.0+0j])

Мы можем увидеть реальную (x.real) и мнимую (* 1088)*) запчасти.Если мы преобразуем это в число с плавающей точкой, мы получим предупреждение об отбрасывании мнимой части и получим массив только с реальной частью.

print x.real
print x.astype(float)

astype делает копию и преобразуетзначения для нового типа.

Однако, если мы рассмотрим этот массив как число с плавающей точкой, мы получим последовательность item1.real, item1.imag, item2.real, item2.imag, ....

print x
print x.view(float)

выход:

[ 0.5+1.j  1.0+2.j  3.0+0.j]
[ 0.5  1.   1.   2.   3.   0. ]

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

Надеюсь, это поможет немного прояснить ситуацию ...

5 голосов
/ 27 февраля 2012

Изменяя dtype таким образом, вы изменяете способ интерпретации фиксированного блока памяти.

Пример:

>>> import numpy as np
>>> a=np.array([1,0,0,0,0,0,0,0],dtype='int8')
>>> a
array([1, 0, 0, 0, 0, 0, 0, 0], dtype=int8)
>>> a.dtype='int64'
>>> a
array([1])

Обратите внимание, как изменение с int8 на int64 изменило 8-элементный 8-битный целочисленный массив в 1-элементный 64-битный массив. Однако это тот же самый 8-байтовый блок. На моей машине i7 с собственным порядком байтов шаблон байтов такой же, как 1 в формате int64.

Изменить положение на 1:

>>> a=np.array([0,0,0,1,0,0,0,0],dtype='int8')
>>> a.dtype='int64'
>>> a
array([16777216])

Другой пример:

>>> a=np.array([0,0,0,0,0,0,1,0],dtype='int32')
>>> a.dtype='int64'
>>> a
array([0, 0, 0, 1])

Изменить позицию 1 в 32-байтовом 32-битном массиве:

>>> a=np.array([0,0,0,1,0,0,0,0],dtype='int32')
>>> a.dtype='int64'
>>> a
array([         0, 4294967296,          0,          0]) 

Это тот же блок битов, переосмысленный.

2 голосов
/ 27 февраля 2012

После возни с этим, я думаю, что ручное назначение dtype делает переосмысление приведения, а не то, что вы хотите.То есть я думаю, что он интерпретирует данные напрямую как число с плавающей точкой, а не конвертирует их в единицу.Возможно, вы могли бы попробовать aa = numpy.array(aa.map(float, aa)).

Дальнейшее объяснение: dtype - это тип данных.Чтобы дословно процитировать цитату из документации

Объект типа данных (экземпляр класса numpy.dtype) описывает, как байты в блоке памяти фиксированного размера соответствуют массиву.Элемент должен быть интерпретирован.

. Типы int и float не имеют одинаковых битовых комбинаций, что означает, что вы не можете просто смотреть на память для целого числа, и это будет то же число, когда вы смотритеэто как поплавок.Установив для dtype значение float64, вы просто указываете компьютеру считывать эту память как float64 вместо фактического преобразования целых чисел в числа с плавающей запятой.

1 голос
/ 27 февраля 2012

Документация для атрибута dtype ndarray не очень полезна.Глядя на ваш вывод, кажется, что буфер из восьми 4-байтовых целых чисел переосмысливается как четыре 8-байтовых числа с плавающей запятой.

Но вам нужно указать dtype при создании массива:

array([1, 2, 3, 4, 5, 6, 7, 8], dtype="float64")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...