How can I speed up this two-lines code?
我需要加速以下代码:
1 2 3
| for i in range(0, 2**N):
output[i] = f(np.array(map(int, bin(i)[2:].zfill(N)))) |
N在30附近,因此代码非常慢(在我的笔记本电脑上大约需要33小时)。函数f()的参数是索引i的二进制表示,f()可以是任意可向量函数。我不是专家,但为了加快代码的速度,我想去掉for循环,这意味着我需要向量化f()的论点。换句话说,我必须用从0到2**N的数字的二进制表示来创建一个矩阵。这可以通过以下代码实现:
1
| list(itertools.product([0, 1], repeat=N)) |
我在这个链接上找到的。然而,在我看来,itertools的速度非常慢,而且很明显,由于2**30大约有10亿,它需要大量的内存。
你有什么建议可以让这段代码更快吗?事先谢谢。
- 你似乎把output的最后一个值都扔掉了。
- 为什么不重写为一个生成器,而不是生成一个十亿元数组呢?
- 查找生成器和yield命令。
- @用户2357112:跳跃,你是对的。我把它修好了!
- 也可以尝试更多的python语法['do something' for i in ...]。
- 如果f的计算成本很高,那么您可能做不到什么。如果单次功能评估需要十分之一毫秒的时间,并且您正在进行超过十亿次这样的评估,那么不管怎样,您都会看到大约30个小时。也许您可以重构以便f所做的计算直接在循环中实现。至少这样可以节省10亿个函数调用的开销。
- 另外,如果您使用的是python 2.7,那么一定要使用"xrange",而不是"range"——仅此一项就可以在系统内存中创建2^30个对象。
- 你真的使用了所有十亿的价值吗?您能在调用时生成每个值,然后在再次调用时存储该值吗?
- 我不知道发电机,所以我也要试试这个选项。不幸的是,我认为记忆不能应用于我的案件,但感谢您的建议!
简介:总是
1 2 3 4
| >>> timeit.timeit("for i in range(0, 2**N): numpy.array(map(int, bin(i)[2:].zfill(N)))","import numpy; N=5", number=100000)
26.472519159317017
>>> timeit.timeit("for t in itertools.product((0, 1), repeat=N): numpy.array(t)","import numpy, itertools; N=5", number=100000)
6.129688024520874 |
你可以看到,这是considerably itertools.product方法更快,因为它不与已在弦的小提琴。
问题是,大多数的时间是花在f功能虽然。
另一个解决方案可以让f在接受和使用它作为一个整数的二进制字段。
- 另外:在接收MBP上进行2^24次pass操作的时间:仅使用range的883ms,使用xrange的501ms,使用pass和range的函数调用的1.92s,使用函数调用+xrange的1.58s。
- 很酷,我试过用N=20,用了1分钟而不是1.5分钟。这会为更大的N节省很多时间。我猜22小时对33小时对1号[8]。