【问题标题】:Parallelize reassignment of elements in large array并行重新分配大型数组中的元素
【发布时间】:2018-02-15 16:00:41
【问题描述】:

我有一个 numpy 数组 chop_preds,它非常大(约 1000 万个元素),需要对其进行修改,使其包含 1.0、0.5 或 0 的值(见下文)。

如何并行执行这种重新分配?

chop_preds=chop_preds.flatten()

for k in range(len(chop_preds)):
    if(chop_preds[k]>=0.4):
        chop_preds[k]=1.0 
    elif(chop_preds[k]<0.1):
        chop_preds[k]=0 
    else:
        chop_preds[k]=0.5 

my_sum=np.sum(chop_preds)

【问题讨论】:

  • 对于它的价值,在我的 macbook 上,读取并为 10M 元素数组的每个元素分配一个整数在 1.2 秒内连续运行。根据您的用例,可能没有理由打扰。
  • 很遗憾,这只是较大代码中的一小部分,对于许多不同的chop_preds,这部分需要重复。这个 sn-p,一旦重复,需要 8 分钟中的 7 分钟才能运行我的程序,我还没有扩大它。

标签: python numpy parallel-processing multiprocessing python-multiprocessing


【解决方案1】:

如果chop_preds 已经是numpy 数组,则可以使用:

chop_preds_flat = chop_preds.flatten()
chop_preds = 0.5 * np.ones_like(chop_preds_flat)
chop_preds[chop_preds_flat >= 0.4] = 1.
chop_preds[chop_preds_flat < 0.1] = 0.

my_sum = chop_preds.sum()

或者,如果您真的只需要总和,请在这些选项上使用 numpy.count_nonzero

my_sum = 0.5 * np.count_nonzero((chop_preds_flat >= 0.1) & (chop_preds_flat < 0.4))
my_sum += np.count_nonzero(chop_preds_flat >= 0.4)

更简单,但更难阅读:

my_sum = ((chop_preds_flat >= 0.4) + 0.5 * ((chop_preds_flat >= 0.1) & (chop_preds_flat < 0.4))).sum()

在这三种方式中,numpy.count_nonzero 似乎是最快的:

作为比较,您的原始实现在该图上的最后一个输入大约需要 0.2 秒,因此比最差的 numpy 实现长约 20 倍(比最快的实现长约 100 倍)。

【讨论】:

  • 这要快得多!聪明!
【解决方案2】:

对于多处理,您可以使用可以使用 pip 安装的“pathos”(github page) 包。

在你的情况下,我会尝试这样的事情:

from pathos.multiprocessing import ProcessingPool as Pool

def chopper(value):
  if(value >= 0.4):
     value = 1.0 
  elif(value < 0.1):
    value = 0 
  else:
    value = 0.5
  return

chop_preds = chop_preds.flatten()
#-------------------------------------------------------------SETUP
pass;                                                         from zmq import Stopwatch; aClock = Stopwatch(); aPrintMASK = "The Critical Section took {0: > 12d} [us] to complete on [{1: >12d}] sized array"
#-------------------------------------------------------------SECTION-TO-TEST:
pass;                                                         aClock.start()
#----------------<_!_>
myPool = Pool(8)                   # assuming you have an 8 cpu cores machines
myPool.map(chopper,chop_preds)
#----------------<_!_>
pass;                                                         D = aClock.stop()
pass;                                                         print aPrintMASK.format( D, chop_preds.shape[0] )
#-------------------------------------------------------------SECTION-TO-TEST.End

【讨论】:

  • 希望您不会介意注入的 [us] 分辨率计时工具。 您是否介意在您的机器上重新运行您的提案并对其进行基准测试,以便在以更好的性能为目标的情况下使该概念在数量上与其他方法相当?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-29
  • 2017-05-08
  • 1970-01-01
  • 1970-01-01
  • 2022-11-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多