Во-первых, код, который вы изучаете, имеет недостатки.Это почти наверняка не делает то, что, по мнению оригинального автора, было сделано на основе комментариев в коде.
Что, вероятно, имел в виду автор, было так:
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 базового буфера памяти, мы получим массив, в два раза длиннее.
Надеюсь, это поможет немного прояснить ситуацию ...