16

MATLAB が行操作よりも列操作を好むこと、およびデータのレイアウトによってパフォーマンスが大幅に異なる可能性があることを示す記事がいくつかあります。これは、MATLAB が配列を表すために列優先の順序を使用しているためと思われます。

Python (NumPy) が行優先順序を使用していることを読んだことを覚えています。これで、私の質問は次のとおりです。

  1. NumPy を使用する場合、同様のパフォーマンスの違いを期待できますか?
  2. 上記の答えが「はい」の場合、この違いを際立たせる例は何ですか?
4

4 に答える 4

15

多くのベンチマークと同様に、これは実際には状況の詳細に依存します。デフォルトでは、numpy が C 連続 (行優先) 順序で配列を作成することは事実です。そのため、抽象的には、列をスキャンする操作は、行をスキャンする操作よりも高速である必要があります。ただし、配列の形状、ALU のパフォーマンス、およびプロセッサの基盤となるキャッシュは、詳細に大きな影響を与えます。

たとえば、私の MacBook Pro では、小さな整数または浮動小数の配列を使用して、時間は似ていますが、小さな整数型は浮動小数点型よりも大幅に遅くなります。

>>> 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

、、などのorder='F'キーワード引数を使用するか、 を使用して既存の配列を変換することにより、Fortran 連続 (列優先) 配列を作成するように numpy に指示できます。予想どおり、この順序付けは行または列操作の効率を入れ替えます。numpy.asarraynumpy.onesnumpy.zerosnumpy.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
于 2013-07-30T20:11:10.390 に答える
2

データや操作によって異なると思います。

簡単な答えは、使用を計画している種類の同じ実世界のデータと使用を計画している関数を使用していくつかのテストを作成し、使用方法に応じて、操作のために速度を使用cprofileまたは比較することです。timeitデータを構造化します。

于 2013-07-30T18:57:25.410 に答える
1

他の返信が指摘したように、numpy 関数を使用しても劇的なパフォーマンスの違いはない傾向がありますが、何らかの手動のインデックス作成を行っている場合 (通常は可能な限り避ける必要があります)、それは非常に重要です。この効果を示す「おもちゃ」の例を次に示します。

import numpy as np
from time import time

n = 100
m = n ** 2
x = np.ones((m, m),  dtype="float64")


def row(mat):
    out = 0
    for i in range(n):
        out += np.sum(mat[i, :])
    return out


def col(mat):
    out = 0
    for i in range(n):
        out += np.sum(mat[:, i])

    return out


p = 100
t = time()
for i in range(p):
    s = row(x)
print(time()-t)


t = time()
for i in range(p):
    s = col(x)
print(time()-t)

「row()」の場合 = 0.2618 秒

「col()」 = 1.9261 秒の場合

行をループする方がかなり高速であることがわかります。

于 2021-12-23T16:59:02.070 に答える