【问题标题】:Python: Fastest Way to Traverse 2-D ArrayPython:遍历二维数组的最快方法
【发布时间】:2014-07-14 19:14:30
【问题描述】:

我有一个二维浮点数组,并且想要计算每列中大于阈值的字段数并将其存储在一维数组中。当前我正在使用以下代码,但需要很长时间(数组大小:27000 x 27000)。谁能告诉我一个更快的方法。

以下是我的代码:

for Column in range(len(CorrelationData)):
BestMatchCount[0][Column] = sum(i >= Threshold for i in CorrelationData[:][Column])

【问题讨论】:

  • 有什么特别的原因为什么要为每次迭代创建输入数组的副本 (CorrelationData[:])?对我来说似乎没有必要......
  • 你尝试过 Cython、PyPy、Numba 吗?

标签: python arrays performance optimization numpy


【解决方案1】:

您应该为此使用纯 NumPy,Python 的 for 循环会减慢速度:

>>> arr = np.random.rand(1000, 1000)                                   
>>> %timeit [sum(i >= 0.5 for i in arr.T[c]) for c in xrange(len(arr))]
1 loops, best of 3: 1.58 s per loop
>>> %timeit np.sum(arr >= 0.5, axis=0)
1000 loops, best of 3: 1.53 ms per loop

【讨论】:

    【解决方案2】:

    不幸的是,除非您使用矢量化处理或其他一些并行方法作弊,否则列的总和非常严格 O(n^2)。如果您的语言灵活,R 的隐式向量化可能被证明是一个简单的解决方案。如果不是,那么我认为一些线程在完成时采用连续列的并行化可能是最快的方法(正如 Andrew 在我之前建议的那样)。

    【讨论】:

      【解决方案3】:

      首先使用以下命令对数组进行排序

      a = [5, 2, 3, 1, 4]
      a.sort()
      

      然后你可以使用 if 命令。一旦达到阈值,您就可以停止搜索。

      这可能会加快您的搜索速度。在 python 中排序要快得多。

      要反转您的排序列表,您可以使用以下命令

      def reverse_numeric(x, y):
            return y - x
      sorted([5, 2, 4, 1, 3], cmp=reverse_numeric)
      [5, 4, 3, 2, 1]
      

      https://wiki.python.org/moin/HowTo/Sorting了解更多信息

      【讨论】:

      • 首先,OP 有一个二维数组而不是一维数组。对数组的单次遍历总是比O(N log N) 排序更快,因此对数组进行排序然后循环遍历它不会使其更快。最后 cmp 不应该再使用了,它很慢并且在 Python 3 中被删除了。
      【解决方案4】:

      提高性能的最好但可能不是最简单的方法是遵循分而治之的方法。创建一个子线程以遍历每一列,并让线程进行所需的计算。然后,一旦所有线程都完成并返回它们的值,编译这些值以找到您的结果。

      编辑:添加了一些示例代码。变量 2DArray 表示 OP 问题中的二维数组。

      import threading
      
      class Worker(threading.Thread):
          def __init__(self, threadID, name, column):
              threading.Thread.__init__(self)
              self.threadID = threadID
              self.name = name
              self.column = column
      
              self.start()
      
          def run(self):
              # Do work here.
      
              threadLock.acquire()
              # Increment threshold counter here.
              counter += self.doWork(self.column)
              threadLock.release()
      
          def doWork(self, colum):
              count = 0
              for row in column:
                  # Test if number is above threshold.
      
      threadLock = threading.Lock()
      threads = []
      counter = 0
      
      tid = 0
      for column in 2DArray:
          threads.append(Worker(tid, 'thread-{0}'.format(tid), column))
          tid += 1
      
      for thread in threads:
          thread.join()
      

      【讨论】:

      • @Alex 向multiprocessing问好。
      • Numpy 1.9 在索引时释放 GIL。所以你实际上可以非常有效地使用多线程。
      猜你喜欢
      • 2010-11-03
      • 1970-01-01
      • 2016-09-04
      • 2020-09-25
      • 2013-11-07
      相关资源
      最近更新 更多