我是Python的新手。在阅读时,请提及有关改进Python代码的其他建议。
问题:如何在包含随机数的Python中生成8xN维数组? 约束条件是此数组的每一列必须包含8个绘制而不替换整数集[1,8] 。更具体地说,当N = 10时,我想要这样的东西。
[[ 6. 2. 3. 4. 7. 5. 5. 7. 8. 4.]
[ 1. 4. 5. 5. 4. 4. 8. 5. 7. 5.]
[ 7. 3. 8. 8. 3. 8. 7. 3. 6. 7.]
[ 3. 6. 7. 1. 5. 6. 2. 1. 5. 1.]
[ 8. 1. 4. 3. 8. 2. 3. 4. 3. 3.]
[ 5. 8. 1. 7. 1. 3. 6. 8. 1. 6.]
[ 4. 5. 2. 6. 2. 1. 1. 6. 4. 2.]
[ 2. 7. 6. 2. 6. 7. 4. 2. 2. 8.]]
为此,我使用以下方法:
import numpy.random
import numpy
def rand_M(N):
M = numpy.zeros(shape = (8, N))
for i in range (0, N):
M[:, i] = numpy.random.choice(8, size = 8, replace = False) + 1
return M
在实践中,N将是~1e7。上述算法的时间为O(n),当N = 1e3时大约需要0.38秒。因此,当N = 1e7时,时间约为1小时(即3800秒)。必须有一种更有效的方式。
定时功能
from timeit import Timer
t = Timer(lambda: rand_M(1000))
print(t.timeit(5))
0.3863314103162543
答案 0 :(得分:3)
创建一个指定形状的随机数组,然后沿着要保持限制的轴排序,从而为我们提供矢量化且非常有效的解决方案。这将基于此smart answer
到MATLAB randomly permuting columns differently
。这是实施 -
示例运行 -
In [122]: N = 10
In [123]: np.argsort(np.random.rand(8,N),axis=0)+1
Out[123]:
array([[7, 3, 5, 1, 1, 5, 2, 4, 1, 4],
[8, 4, 3, 2, 2, 8, 5, 5, 6, 2],
[1, 2, 4, 6, 5, 4, 4, 3, 4, 7],
[5, 6, 2, 5, 8, 2, 7, 8, 5, 8],
[2, 8, 6, 3, 4, 7, 1, 1, 2, 6],
[6, 7, 7, 8, 6, 6, 3, 2, 7, 3],
[4, 1, 1, 4, 3, 3, 8, 6, 8, 1],
[3, 5, 8, 7, 7, 1, 6, 7, 3, 5]], dtype=int64)
运行时测试 -
In [124]: def sortbased_rand8(N):
...: return np.argsort(np.random.rand(8,N),axis=0)+1
...:
...: def rand_M(N):
...: M = np.zeros(shape = (8, N))
...: for i in range (0, N):
...: M[:, i] = np.random.choice(8, size = 8, replace = False) + 1
...: return M
...:
In [125]: N = 5000
In [126]: %timeit sortbased_rand8(N)
100 loops, best of 3: 1.95 ms per loop
In [127]: %timeit rand_M(N)
1 loops, best of 3: 233 ms per loop
因此,等待 120x
加速!
答案 1 :(得分:1)
洗牌怎么样,也就是说,置换?
import random
import numpy
from timeit import Timer
def B_rand_M(N):
a = numpy.arange(1,9)
M = numpy.zeros(shape = (8, N))
for i in range (0, N):
M[:, i] = numpy.random.permutation(a)
return M
# your original implementation
def J_rand_M(N):
M = numpy.zeros(shape = (8, N))
for i in range (0, N):
M[:, i] = numpy.random.choice(8, size = 8, replace = False) + 1
return M
一些时间:
def compare(N):
for f in (J_rand_M, B_rand_M):
t = Timer(lambda: f(N)).timeit(6)
print 'time for %s(%s): %.6f' % (f.__name__, N, t)
for i in range(6):
print 'N = 10^%s' % i
compare(10**i)
print
给出
N = 10^0
time for J_rand_M(1): 0.001199
time for B_rand_M(1): 0.000080
N = 10^1
time for J_rand_M(10): 0.001112
time for B_rand_M(10): 0.000335
N = 10^2
time for J_rand_M(100): 0.011118
time for B_rand_M(100): 0.003022
N = 10^3
time for J_rand_M(1000): 0.110887
time for B_rand_M(1000): 0.030528
N = 10^4
time for J_rand_M(10000): 1.100540
time for B_rand_M(10000): 0.304696
N = 10^5
time for J_rand_M(100000): 11.151576
time for B_rand_M(100000): 3.049474
答案 2 :(得分:0)
只是评论您对问题的运行时分析 - 我的直觉是O(n)是生成O(n)真正随机数时可能获得的最佳运行时。
您是否尝试过实际运行n = 1000万的代码?当输入增长1000倍时,运行时将缩放1000的假设在实践中可能不正确,因为在执行任何程序(加载库等)时通常会有一个常数项,这可能很重要,具体取决于问题。
话虽如此,看起来the question linked by Eric Wright做得非常透彻,可以很容易地适应你的问题。
答案 3 :(得分:0)
使用以下代码生成数组
import numpy as np
N=1e7 # THe value you want to have
np.random.randint(1,high=8,size=(8,N))
希望这会有所帮助,肯定不会花费那么多时间。