2014-12-22 3 views
4

Например, скажем, я имитируя кучу частиц делать что-то в течение долгого времени, и у меня есть многомерный массив называется particles с этими индексами:Порядок индексов в многомерном массиве Numpy

  • X/у/Z координата частицы (длины a, который 3 для 3D пространства)
  • индекса отдельной частицы (длины b)
  • индекса временного шага он находится на (длины c)

Лучше ли построить такой массив, что particles.shape == (a, b, c) или particles.shape == (c, b, a)?

Я больше заинтересован в согласии, чем в эффективности: массивы Numpy могут быть настроены либо в C-стиле (последний индекс меняется наиболее быстро), либо в стиле Fortran (первый индекс), поэтому он может эффективно поддерживать любую настройку. Я также понимаю, что могу использовать transpose, чтобы поместить индексы в любом порядке, в котором я нуждаюсь, но я хотел бы свести это к минимуму.

Я начал исследовать это сам и нашел поддержку обоих способов:

Pro- (с, Ь, а):

  • По умолчанию Numpy использует массивы C-стиле, где последний индекс является самым быстрым.
  • Большинство функций векторной алгебры (inner, cross и т. Д.) Действуют на последний индекс. (dot действует на последнем и втором и на последнем.)
  • Объекты коллекции matplotlib (LineCollection, PolyCollection) ожидают массивы с пространственными координатами на последней оси.

Pro- (а, б, в):

  • Если я должен был использовать meshgrid и mgrid производить множество точек, было бы поставить пространственную ось первой. Например, np.mgrid[0:5,0:5,0:5].shape == (3,5,5,5). Я понимаю, что эти функции в основном предназначены для integer array indexing, но это не редкость использовать их для создания сетки точек.
  • В matplotlibscatter и plot функции разделить свои аргументы, так что агностик в форме массива, но ax.plot3d(particles[0], particles[1], particles[2]) короче набирать, чем версия с particles[..., 0]

В целом представляется, что есть две разные (вероятно, из-за исторических различий между C и Fortran), и неясно, что более распространено в сообществе Numpy, или более подходящим для того, что я делаю.

ответ

4

Условные обозначения для чего-то подобного имеют гораздо больше общего с конкретными файловыми форматами, чем все остальное, по моему опыту. Тем не менее, есть быстрый способ ответить, который, вероятно, будет лучшим для того, что вы делаете:

Если вам нужно перебирать ось, какую из них вы, скорее всего, перебираете? Другими словами, какой из них наиболее вероятно:

# a first 
for dimension in particles: 
    ... 

# b first 
for particle in particles: 
    ... 

# c first 
for timestep in particles: 
    ... 

Насколько эффективность идет, это предполагает, что C-заказ, но это на самом деле не имеет значения здесь. На уровне python доступ к массивам numpy рассматривается как C-упорядоченный независимо от макета памяти. (Вы всегда итерации по первой оси, даже если это не самая «смежная» ось в памяти.)

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

Если ничего, надеюсь, это даст вам полезный способ подумать о вопросе.

2

Другое смещение заключается в том, что при добавлении нового измерения предпочтение следует отдавать слева. Это x[None,...] автоматического

np.array([x,y,z]) # produces a (3,...) array 

np.ones((3,2)) + np.ones((1,2,10)) # error 
np.ones((3,2,1)) + np.ones((2,10)) # (3,2,10) 

Но я не вижу, как это фронт-первых вещание выступает на одну позицию или другие для x/y/z координат.

В то время как np.dot использует соглашение last/2nd to last, np.tensordot и np.einsum являются гораздо более общими.


Apocheir указывает на то, что делает сокращение на последней оси может потребовать добавления newaxis обратно, например,

x/np.linalg.norm(x,axis=0) # automatic newaxis at beginning 
x/np.linalg.norm(x,axis=-1)[...,np.newaxis] # explicit newaxis 

для малых x, это явно newaxis добавляет измеримое время выполнения. Но для больших x 2-й расчет выполняется быстрее. Я думаю, это потому, что уменьшение на последней оси происходит быстрее - это ось, которая изменяется быстрее (для order='C').

Ряд встроенных методов восстановления имеет параметр keepdims, чтобы облегчить вещание в таких целях (например, sum, mean).

+0

Фактически, это имеет эффект ... сравните 'x = np.ones ((3,4,5)); y = np.linalg.norm (x, axis = 0) 'to' x = np.ones ((5,4,3)); y = np.linalg.norm (x, axis = -1) '. Сначала с пространственным индексом, 'x/y' нормализует' x' без какого-либо сгибания индекса. С последним пространственным индексом вы должны сделать что-то вроде 'x/y [..., np.newaxis]' – Apocheir

+0

. Ряд методов «сокращения» (например, 'sum',' mean') имеет 'keepdims' чтобы исключить необходимость добавления этого «newaxis» обратно. – hpaulj

Смежные вопросы