numpy.random.choice的性能表现

4

我更新了代码和时间。

我正在尝试改进我的代码中的一个函数性能。我必须生成一个带有随机元素的列表。然而,列表的不同部分必须被来自不同集合的元素填充。以下是一段示例代码。我必须逐个生成数百万个这样的列表。

函数foo1是最快的,但它不能满足我的需求。它只是用于性能参考。函数foo2和foo3能够满足我的需求,但处理时间几乎是foo1的三倍。

Python 2.7.9 (默认,Feb 10 2015, 03:29:19). [GCC 4.2.1 兼容苹果 LLVM 6.0 (clang-600.0.56)] 在Darwin上。numpy.version '1.8.1'

import numpy

import timeit

_ops_1 = ["-123.456", "3.1416", "1", "2"]
_ops_2 = ["ABC", "XYZ", 'A', 'B', 'C']

size = 10

def foo1 (): 
    return numpy.random.choice(_ops_1 + _ops_2, 5*size)

def foo2 (): 
    return list(numpy.concatenate((numpy.random.choice(_ops_1, 2*size), 
        numpy.random.choice(_ops_1 + _ops_2, size),
        numpy.random.choice(_ops_2, 2*size)), 0))

def foo3 (): 
    return numpy.random.choice(_ops_1, 2*size).tolist() + \
        numpy.random.choice(_ops_1 + _ops_2, size).tolist() + \
        numpy.random.choice(_ops_2, 2*size).tolist()

### Suggested by Divakar
def random_choice_replace_True(arr,size):
    return numpy.take(arr,numpy.random.randint(0,len(arr),size))

def foo4 (): 
    return random_choice_replace_True(_ops_1, 2*size).tolist() + \
        random_choice_replace_True(_ops_1 + _ops_2, size).tolist() + \
        random_choice_replace_True(_ops_2, 2*size).tolist()

### 2nd suggestion by Divakar
def random_choice_replace_True_idx(arr,size):
    return numpy.array(arr)[numpy.random.randint(0,len(arr),size)]

def foo5 (): 
    return random_choice_replace_True_idx(_ops_1, 2*size).tolist() + \
        random_choice_replace_True_idx(_ops_1 + _ops_2, size).tolist() + \
        random_choice_replace_True_idx(_ops_2, 2*size).tolist()

###########

setup = '''import numpy

_ops_1 = ["-123.456", "3.1416", "1", "2"]
_ops_2 = ["ABC", "XYZ", 'A', 'B', 'C']

size = 10'''

# As required, Number was increased to 10 million to get closer to actual timings
timeit.timeit(foo1, setup=setup, number=10000000)

timeit.timeit(foo2, setup=setup, number=10000000)

timeit.timeit(foo3, setup=setup, number=10000000)

timeit.timeit(foo4, setup=setup, number=10000000)

timeit.timeit(foo5, setup=setup, number=10000000)

我机器上的运行时间为:

timeit.timeit(foo1, setup=setup, number=10000000) 235.22050380706787

timeit.timeit(foo2, setup=setup, number=10000000) 760.1884841918945

timeit.timeit(foo3, setup=setup, number=10000000) 560.77258586883545

timeit.timeit(foo4, setup=setup, number=10000000) 388.69550228118896

timeit.timeit(foo5, setup=setup, number=10000000) 252.32089233398438

目前,我会采纳Divakar提出的第二个建议,这个建议很不错。但其他建议也欢迎!

所以你的代码比1秒更快,而你需要提高性能?在这样低的运行时间下,运行时间将取决于你的系统现在正在做什么(后台进程),我不知道你的问题是否真的是一个问题。 - Ian
如果您分享实际问题(如何生成数百万个列表),可能更容易进行优化。 - ayhan
按要求,我已经更新了代码和时间。 - user1348438
1个回答

2
那个名为np.random.choice的函数可以选择输入数组中的元素,可选参数replace设置为True时会返回重复的元素。我们可以通过创建覆盖数组长度的随机索引来模拟这种行为,并通过索引选择数组中的元素。因此,我们可以用类似于以下的方法来模拟内置函数的行为 -
def random_choice_replace_True(A,size):
    return np.array(A)[np.random.randint(0,len(A),size)]

如果你处理的输入数据已经是NumPy数组,你可以跳过将其转换为np.array(A)的步骤,直接使用A


亲爱的Divakar,感谢您的建议。它显著提高了性能。进一步改进将是非常好的。 - user1348438
@user1348438 我已经用简单的索引替换了 numpy.take,根据我刚刚运行的一些测试,似乎能够进一步缩短运行时间。你可以看看!此外,我认为我无法再进行优化 :) - Divakar
亲爱的Divakar,感谢您的建议。现在好多了!最好的祝福。 - user1348438

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接