Выполнение операций строк и столбцов в NumPy

Есть несколько статей, которые показывают, что MATLAB предпочитает операции с столбцами, чем операции с строками, и что в зависимости от вас выкладывают ваши данные, производительность может значительно варьироваться. По-видимому, это связано с тем, что MATLAB использует колонку-майор для представления массивов.

Помню, что Python (NumPy) использует ряд строк. При этом мои вопросы:

  • Можно ли ожидать аналогичной разницы в производительности при работе с NumPy?
  • Если ответ на вышеприведенный вопрос - да, то какие были бы примеры, подчеркивающие эту разницу?

Ответ 1

Как и во многих тестах, это действительно зависит от особенностей ситуации. Это правда, что по умолчанию numpy создает массивы в C-смежном (row-major) порядке, поэтому в реферате операции, которые сканируют по столбцам, должны быть быстрее, чем те, которые сканируют по строкам. Однако форма массива, производительность ALU и основной кэш на процессоре оказывают огромное влияние на данные.

Например, на моем MacBook Pro с небольшим целым числом или массивом с плавающей точкой времена аналогичны, но малый целочисленный тип значительно медленнее, чем тип float:

>>> x = numpy.ones((100, 100), dtype=numpy.uint8)
>>> %timeit x.sum(axis=0)
10000 loops, best of 3: 40.6 us per loop
>>> %timeit x.sum(axis=1)
10000 loops, best of 3: 36.1 us per loop

>>> x = numpy.ones((100, 100), dtype=numpy.float64)
>>> %timeit x.sum(axis=0)
10000 loops, best of 3: 28.8 us per loop
>>> %timeit x.sum(axis=1)
10000 loops, best of 3: 28.8 us per loop

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

>>> x = numpy.ones((1000, 1000), dtype=numpy.uint8)
>>> %timeit x.sum(axis=0)
100 loops, best of 3: 2.36 ms per loop
>>> %timeit x.sum(axis=1)
1000 loops, best of 3: 1.9 ms per loop

>>> x = numpy.ones((1000, 1000), dtype=numpy.float64)
>>> %timeit x.sum(axis=0)
100 loops, best of 3: 2.04 ms per loop
>>> %timeit x.sum(axis=1)
1000 loops, best of 3: 1.89 ms per loop

Вы можете указать numpy создать массив Fortran-смежных (массив столбцов), используя аргумент ключевого слова order='F' для numpy.asarray, numpy.ones, numpy.zeros и т.п., или путем преобразования существующего массива с использованием numpy.asfortranarray. Как и ожидалось, это упорядочение меняет эффективность операций с строками или столбцами:

in [10]: y = numpy.asfortranarray(x)
in [11]: %timeit y.sum(axis=0)
1000 loops, best of 3: 1.89 ms per loop
in [12]: %timeit y.sum(axis=1)
100 loops, best of 3: 2.01 ms per loop

Ответ 2

In [38]: data = numpy.random.rand(10000,10000)

In [39]: %timeit data.sum(axis=0)
10 loops, best of 3: 86.1 ms per loop

In [40]: %timeit data.sum(axis=1)
10 loops, best of 3: 101 ms per loop

Ответ 3

Я подозреваю, что он будет отличаться в зависимости от данных и операций.

Легкий ответ - написать несколько тестов с использованием того же самого реального мира, данных того типа, который вы планируете использовать, и функций, которые вы планируете использовать, а затем использовать cprofile или timeit для сравнения скоростей, для ваших операций, в зависимости от того, как вы структурируете свои данные.