В чем разница между функциями flatten и ravel в numpy?

292
import numpy as np
y = np.array(((1,2,3),(4,5,6),(7,8,9)))
OUTPUT:
print(y.flatten())
[1   2   3   4   5   6   7   8   9]
print(y.ravel())
[1   2   3   4   5   6   7   8   9]

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

cryptomanic
источник
14
Равель обычно возвращает представление в существующий массив (иногда он возвращает копию). Flatten возвращает новый массив.
Алекс
5
Возможный дубликат В чем разница между flatten и ravel в numpy?
finnw
1
Вот практическая демонстрация тонкой разницы.
Прости
Так может ли кто-нибудь привести пример, когда лучше сплющить массив, а когда его расправить?
Александар

Ответы:

371

Текущий API таков:

  • flatten всегда возвращает копию.
  • ravelпо возможности возвращает вид исходного массива. Это не видно в выводе на печать, но если вы измените массив, возвращаемый ravel, он может изменить записи в исходном массиве. Если вы измените записи в массиве, возвращенном из flatten, этого никогда не произойдет. ravel часто работает быстрее, поскольку память не копируется, но вы должны быть более осторожны при изменении возвращаемого массива.
  • reshape((-1,)) получает представление всякий раз, когда шаги массива позволяют это, даже если это означает, что вы не всегда получаете непрерывный массив.
IanH
источник
30
Есть идеи, почему разработчики NumPy не придерживались одной функции с некоторым параметром copy = [True, False]?
Франк Дернонкур
41
Гарантии Backcompat иногда приводят к тому, что такие странные вещи случаются. Например: недавно разработчики (numy) (в версии 1.10) добавили ранее неявную гарантию, что ravel будет возвращать непрерывный массив (свойство, которое очень важно при написании расширений C), поэтому теперь API a.flatten()должен обязательно получать копию, a.ravel()чтобы избежать большинство копий, но все же гарантируют, что возвращаемый массив является смежным, и a.reshape((-1,))действительно получает представление, когда шаги массива позволяют это, даже если это означает, что вы не всегда получаете смежный массив.
Янв
4
@Hossein IanH объяснил это: ravelгарантирует непрерывный массив, и поэтому не гарантируется, что он возвращает представление; reshapeвсегда возвращает представление, и поэтому не гарантируется, что он возвращает непрерывный массив.
ILED
4
@ Хоссейн Это был бы совершенно новый вопрос. Вкратце, гораздо быстрее читать и записывать в непрерывное пространство памяти. Есть несколько вопросов и ответов по этому вопросу здесь ( хороший пример здесь ), не стесняйтесь открывать новый, если у вас есть какие-либо дополнительные вопросы.
ILED
2
reshape(-1)эквивалентноreshape((-1,))
Том Пол
53

Как объясняется здесь, ключевое отличие состоит в том, что:

  • flatten является методом ndarray-объекта и, следовательно, может быть вызван только для истинных numpy массивов.

  • ravel является функцией уровня библиотеки и, следовательно, может вызываться для любого объекта, который может быть успешно проанализирован.

Например, ravelбудет работать со списком ndarrays, пока flattenне доступен для этого типа объекта.

@IanH также указывает на важные различия с обработкой памяти в своем ответе.

Брайан П
источник
4
ТНХ для этой информации о Равель () работает в списках ndarray«S
javadba
Не только списки массивов, но и списки списков :)
timtody
15

Вот правильное пространство имен для функций:

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

import numpy
a = numpy.array([[1,2],[3,4]])

r = numpy.ravel(a)
f = numpy.ndarray.flatten(a)  

print(id(a))
print(id(r))
print(id(f))

print(r)
print(f)

print("\nbase r:", r.base)
print("\nbase f:", f.base)

---returns---
140541099429760
140541099471056
140541099473216

[1 2 3 4]
[1 2 3 4]

base r: [[1 2]
 [3 4]]

base f: None

В верхнем примере:

  • места в памяти результатов различны,
  • результаты выглядят одинаково
  • Flatten вернул бы копию
  • Равель вернет взгляд.

Как мы проверяем, является ли что-то копией? Используя .baseатрибут ndarray. Если это представление, база будет исходным массивом; если это копия, база будет None.

прости
источник