簡體   English   中英

需要加快 python 中 numpy arrays 上的操作

[英]Need to speed up the operations on numpy arrays in python

我通過將 Cplex 作為庫導入 Python 來解決 integer 編程 model。 假設優化問題具有以下形式的約束(Ax = b)x0+x1+x1+x3 = 1

此約束中的 x 變量的索引是 0,1,1 和 3。它們存儲在一個列表中: indices=[0,1,1,3]這些變量的系數也存儲在另一個列表中coeff = [1,1,1,1]

Cplex 不能接受重復的索引,因此約束應如下所示:

x0+2x1+x3 = 1

所以這兩個列表應該像這樣更新:

indices=[0,1,3]
 coeff = [1,2,1]

我有這個 function 將索引和系數作為兩個 arguments 並給我操縱列表:

def manipulate(indices, coeff):
    u = np.unique(indices)
    sums  = { ui:np.sum([  coeff[c[0]] for c in np.argwhere(indices == ui) ]) for     ui in u }
    return list(sums.keys()),list(sums.values())

因此, manipulate([0,1,1,3], [1,1,1,1])返回([0, 1, 3], [1, 2, 1])

我的問題是當我有這么多變量時,列表的長度可能為一百萬,而我有數百萬個這樣的約束。 當我使用 cplex 解決我的優化問題時,程序變得非常慢。 我跟蹤了每個 function 所花費的時間,並意識到我的代碼中最耗時的部分是這些計算,我猜這是因為使用了 numpy。 我需要讓這個 function 更有效率,以希望減少執行時間。 您能否就如何更改 function 操作與我分享任何想法和建議?

非常感謝,

如果不使用基於本機代碼的擴展,可能總會有妥協:

  • Numpy / 矢量化方法錯過了基於哈希的算法,恕我直言,算法復雜性將受到影響(例如,需要排序;需要進行多次傳遞......)

  • 基於 Python 的基於散列的方法將受到緩慢循環的影響。

盡管如此,我確實認為,您的方法在某種程度上接近了兩全其美的情況,您可以獲得一些東西

一些代碼

from time import perf_counter as pc
from collections import defaultdict
import numpy as np
np.random.seed(0)

def manipulate(indices, coeff):
    u = np.unique(indices)
    sums  = { ui:np.sum([  coeff[c[0]] for c in np.argwhere(indices == ui) ]) for     ui in u }
    return list(sums.keys()),list(sums.values())

# this assumes pre-sorted indices
def manipulate_alt(indices, coeff):
  unique, indices = np.unique(indices, return_index=True)
  cum_coeffs = np.cumsum(coeff)
  bla = cum_coeffs[indices-1]
  blub = np.roll(bla, -1)
  bluab = np.ediff1d(blub, to_begin=blub[0])

  return unique.tolist(), bluab.tolist()

def manipulate_pure_py(indices, coeff):
  final = defaultdict(int)
  n = len(indices)
  for i in range(n):
    final[indices[i]] += coeff[i]

  return list(final.keys()), list(final.values())

# BAD NON-SCIENTIFIC BENCHMARK
# ----------------------------

ITERATIONS = 10
SIZE = 1000000

accu_time_manipulate = 0.0
accu_time_manipulate_alt = 0.0
accu_time_manipulate_py = 0.0

for i in range(ITERATIONS):
  indices = np.sort(np.random.randint(0, 10000, size=SIZE))
  coeffs = np.random.randint(1, 100, size=SIZE)

  start = pc()
  sol = manipulate(indices, coeffs)
  end = pc()
  accu_time_manipulate += (end-start)

  start = pc()
  sol_alt = manipulate_alt(indices, coeffs)
  end = pc()
  accu_time_manipulate_alt += (end-start)

  start = pc()
  sol_py = manipulate_pure_py(indices, coeffs)
  end = pc()
  accu_time_manipulate_py += (end-start)

  assert sol[0] == sol_alt[0]
  assert sol[1] == sol_alt[1]

  assert sol[0] == sol_py[0]
  assert sol[1] == sol_py[1]


print(accu_time_manipulate)
print(accu_time_manipulate_alt)
print(accu_time_manipulate_py)

計時

164.34614480000005
0.24998690000001744
8.751806900000059

評論

  • 基准很差
  • 我不相信基於 numpy 的 hack 100%
  • 只需使用簡單的基於 dict 的方法(或 go 本機代碼路線)
  • (取決於建模任務:您也可以在構建 model 時結合此合並:直接進行,不要延遲到后處理)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM