消除Python和Numpy构造中的for循环

Hen*_*ton 7 python for-loop numpy

我正在寻找Python和/或Numpy矢量化的方法,以消除以下的for循环使用:

for i in list_range_values:
    v[list_list_values[i]] += list_comp_values[i]
Run Code Online (Sandbox Code Playgroud)

哪里:

  • list_range_values是一个整数值的Python列表,例如.[1,3,5],从范围(0,R-1,1)中抽取

  • list_comp_values是数值的Python列表,例如.[0.7,9.8,1.25,5,10,11.7,6,0.2]这样len(list_comp_values)= R

  • v是长度为V的numpy向量,使得R可以是<,=,>而不是V.

  • list_list_values是一个列表的Python列表(每个列表包含不同数量的整数值,例如[[3,6,7],[5,7,11,25,99],[8,45],[4,7] ,8],[0,1],[21,31,41],[9,11,22,33,44],[17,19]])从范围(0,V-1,1)中绘制并使用len(list_list_values)= R.

例如.

for i in list_range_values (= [1, 3, 5]):
    i=1: v[[5, 7, 11, 25, 99]] += list_comp_values[1] (= 9.8)
    i=3: v[[4, 7, 8]] += list_comp_values[3] (= 5)
    i=5: v[[21, 31, 41]] += list_comp_values[5] (= 11.7)
Run Code Online (Sandbox Code Playgroud)

有没有可用的方法可以消除for循环?

Cython,Scipy/Weave/Blitz和C模块是替代解决方案,但是要确保首先是否存在Numpy矢量化答案.

Jos*_*del 6

虽然它通常会导致大量加速以消除for循环并利用numpy内置插件/矢量化.我只想指出情况并非总是如此.定时简单的for循环与更多涉及的矢量化,不会给你一个大的加速,而且更冗长.需要考虑的事情:

from timeit import Timer

setstr="""import numpy as np
import itertools
import random

Nlists = 1000
total_lists = 5000
outsz = 100
maxsublistsz = 100


# create random list of lists
list_range_values = random.sample(xrange(total_lists),Nlists)
list_list_values = [random.sample(xrange(outsz),np.random.randint(1,maxsublistsz)) for k in xrange(total_lists)]

list_comp_values = 10*np.random.uniform(size=(total_lists,))

v = np.zeros((outsz,))

def indices(start, end):
    lens = end - start
    np.cumsum(lens, out=lens)
    i = np.ones(lens[-1], dtype=int)
    i[0] = start[0]
    i[lens[:-1]] += start[1:]
    i[lens[:-1]] -= end[:-1]
    np.cumsum(i, out=i)
    return i

def sum_by_group(values, groups):
    order = np.argsort(groups)
    groups = groups[order]
    values = values[order]
    values.cumsum(out=values)
    index = np.ones(len(groups), 'bool')
    index[:-1] = groups[1:] != groups[:-1]
    values = values[index]
    groups = groups[index]
    values[1:] = np.diff(values)
    return values, groups


"""

method1="""
list_list_lens = np.array(map(len, list_list_values))
comp_vals_expanded = np.repeat(list_comp_values, list_list_lens)

list_vals_flat = np.fromiter(itertools.chain.from_iterable(list_list_values),dtype=int)
list_list_starts = np.concatenate(([0], np.cumsum(list_list_lens)[:-1]))

toadd = indices(list_list_starts[list_range_values],(list_list_starts + list_list_lens)[list_range_values])

v[list_vals_flat[toadd]] += comp_vals_expanded[toadd]
"""

method2="""
for k in list_range_values:
    v[list_list_values[k]] += list_comp_values[k]

"""

method3="""
llv = [list_list_values[i] for i in list_range_values]
lcv = [list_comp_values[i] for i in list_range_values]
counts = map(len, llv)
indices = np.concatenate(llv)
values = np.repeat(lcv, counts)

totals, indices_unique = sum_by_group(values, indices)
v[indices_unique] += totals
"""


t1 = Timer(method1,setup=setstr).timeit(100)
print t1

t2 = Timer(method2,setup=setstr).timeit(100)
print t2

t3 = Timer(method3,setup=setstr).timeit(100)
print t3
Run Code Online (Sandbox Code Playgroud)

对于列表中的大量元素:

方法1 :(不用于循环-jterrace)1.43秒

方法2 :( for循环)4.62秒

方法3 :(不用于循环 - bago)2.99秒

对于少量列表(更改Nlists为10),for循环明显快于jterrace的解决方案:

方法1 :(不用于循环-jterrace)1.05秒

方法2 :( for循环)0.045秒

方法3 :(不用于循环 - bago)0.041秒

这不是敲@jterrace或@ bago的解决方案,这是非常优雅的.相反,它要指出的是,通常简单的for循环不会表现不佳.