我有以下简单的代码来估计h乘n二进制矩阵具有某个属性的概率。它以指数时间运行(开始时很糟糕)但我很惊讶即使对于n = 12和h = 9它也是如此之慢。
#!/usr/bin/python
import numpy as np
import itertools
n = 12
h = 9
F = np.matrix(list(itertools.product([0,1],repeat = n))).transpose()
count = 0
iters = 100
for i in xrange(iters):
M = np.random.randint(2, size=(h,n))
product = np.dot(M,F)
setofcols = set()
for column in product.T:
setofcols.add(repr(column))
if (len(setofcols)==2**n):
count = count + 1
print count*1.0/iters
我使用n = 10和h = 7对其进行了分析。输出相当长,但是这些行需要花费更多时间。
23447867 function calls (23038179 primitive calls) in 35.785 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
2 0.002 0.001 0.019 0.010 __init__.py:1(<module>)
1 0.001 0.001 0.054 0.054 __init__.py:106(<module>)
1 0.001 0.001 0.022 0.022 __init__.py:15(<module>)
2 0.003 0.002 0.013 0.006 __init__.py:2(<module>)
1 0.001 0.001 0.003 0.003 __init__.py:38(<module>)
1 0.001 0.001 0.001 0.001 __init__.py:4(<module>)
1 0.001 0.001 0.004 0.004 __init__.py:45(<module>)
1 0.001 0.001 0.002 0.002 __init__.py:88(<module>)
307200 0.306 0.000 1.584 0.000 _methods.py:24(_any)
102400 0.026 0.000 0.026 0.000 arrayprint.py:22(product)
102400 1.345 0.000 32.795 0.000 arrayprint.py:225(_array2string)
307200/102400 1.166 0.000 33.350 0.000 arrayprint.py:335(array2string)
716800 0.820 0.000 1.162 0.000 arrayprint.py:448(_extendLine)
204800/102400 1.699 0.000 5.090 0.000 arrayprint.py:456(_formatArray)
307200 0.651 0.000 22.510 0.000 arrayprint.py:524(__init__)
307200 11.783 0.000 21.859 0.000 arrayprint.py:538(fillFormat)
1353748 1.920 0.000 2.537 0.000 arrayprint.py:627(_digits)
102400 0.576 0.000 2.523 0.000 arrayprint.py:636(__init__)
716800 2.159 0.000 2.159 0.000 arrayprint.py:649(__call__)
307200 0.099 0.000 0.099 0.000 arrayprint.py:658(__init__)
102400 0.163 0.000 0.225 0.000 arrayprint.py:686(__init__)
102400 0.307 0.000 13.784 0.000 arrayprint.py:697(__init__)
102400 0.110 0.000 0.110 0.000 arrayprint.py:713(__init__)
102400 0.043 0.000 0.043 0.000 arrayprint.py:741(__init__)
1 0.003 0.003 0.003 0.003 chebyshev.py:87(<module>)
2 0.001 0.000 0.001 0.000 collections.py:284(namedtuple)
1 0.277 0.277 35.786 35.786 counterfeit.py:3(<module>)
205002 0.222 0.000 0.247 0.000 defmatrix.py:279(__array_finalize__)
102500 0.747 0.000 1.077 0.000 defmatrix.py:301(__getitem__)
102400 0.322 0.000 34.236 0.000 defmatrix.py:352(__repr__)
102400 0.100 0.000 0.508 0.000 fromnumeric.py:1087(ravel)
307200 0.382 0.000 2.829 0.000 fromnumeric.py:1563(any)
271 0.004 0.000 0.005 0.000 function_base.py:3220(add_newdoc)
1 0.003 0.003 0.003 0.003 hermite.py:59(<module>)
1 0.003 0.003 0.003 0.003 hermite_e.py:59(<module>)
1 0.001 0.001 0.002 0.002 index_tricks.py:1(<module>)
1 0.003 0.003 0.003 0.003 laguerre.py:59(<module>)
1 0.003 0.003 0.003 0.003 legendre.py:83(<module>)
1 0.001 0.001 0.001 0.001 linalg.py:10(<module>)
1 0.001 0.001 0.001 0.001 numeric.py:1(<module>)
102400 0.247 0.000 33.598 0.000 numeric.py:1365(array_repr)
204800 0.321 0.000 1.143 0.000 numeric.py:1437(array_str)
614400 1.199 0.000 2.627 0.000 numeric.py:2178(seterr)
614400 0.837 0.000 0.918 0.000 numeric.py:2274(geterr)
102400 0.081 0.000 0.186 0.000 numeric.py:252(asarray)
307200 0.259 0.000 0.622 0.000 numeric.py:322(asanyarray)
1 0.003 0.003 0.004 0.004 polynomial.py:54(<module>)
513130 0.134 0.000 0.134 0.000 {isinstance}
307229 0.075 0.000 0.075 0.000 {issubclass}
5985327/5985305 0.595 0.000 0.595 0.000 {len}
306988 0.120 0.000 0.120 0.000 {max}
102400 0.061 0.000 0.061 0.000 {method '__array__' of 'numpy.ndarray' objects}
102406 0.027 0.000 0.027 0.000 {method 'add' of 'set' objects}
307200 0.241 0.000 1.824 0.000 {method 'any' of 'numpy.ndarray' objects}
307200 0.482 0.000 0.482 0.000 {method 'compress' of 'numpy.ndarray' objects}
204800 0.035 0.000 0.035 0.000 {method 'item' of 'numpy.ndarray' objects}
102451 0.014 0.000 0.014 0.000 {method 'join' of 'str' objects}
102400 0.222 0.000 0.222 0.000 {method 'ravel' of 'numpy.ndarray' objects}
921176 3.330 0.000 3.330 0.000 {method 'reduce' of 'numpy.ufunc' objects}
102405 0.057 0.000 0.057 0.000 {method 'replace' of 'str' objects}
2992167 0.660 0.000 0.660 0.000 {method 'rstrip' of 'str' objects}
102400 0.041 0.000 0.041 0.000 {method 'splitlines' of 'str' objects}
6 0.003 0.000 0.003 0.001 {method 'sub' of '_sre.SRE_Pattern' objects}
307276 0.090 0.000 0.090 0.000 {min}
100 0.013 0.000 0.013 0.000 {numpy.core._dotblas.dot}
409639 0.473 0.000 0.473 0.000 {numpy.core.multiarray.array}
1228800 0.239 0.000 0.239 0.000 {numpy.core.umath.geterrobj}
614401 0.352 0.000 0.352 0.000 {numpy.core.umath.seterrobj}
102475 0.031 0.000 0.031 0.000 {range}
102400 0.076 0.000 0.102 0.000 {reduce}
204845/102445 0.198 0.000 34.333 0.000 {repr}
矩阵的乘法似乎只占很短的一部分时间。是否有可能加快休息?
结果
现在有三个答案,但目前似乎有一个错误。我测试了剩下的两个,n = 18,h = 11,iters = 10.
有趣的是,矩阵乘法的时间仍然只占总时间的一小部分。
答案 0 :(得分:3)
要加快上面的代码,你应该避免循环。
import numpy as np
import itertools
def unique_rows(a):
a = np.ascontiguousarray(a)
unique_a = np.unique(a.view([('', a.dtype)]*a.shape[1]))
return unique_a.view(a.dtype).reshape((unique_a.shape[0], a.shape[1]))
n = 12
h = 9
iters=100
F = np.matrix(list(itertools.product([0,1],repeat = n))).transpose()
M = np.random.randint(2, size=(h*iters,n))
product = np.dot(M,F)
counts = map(lambda x: len(unique_rows(x.T))==2**n, np.split(product,iters,axis=0))
prob=float(sum(counts))/iters
#All unique submatrices M (hxn) with the sophisticated property...
[np.split(M,iters,axis=0)[j] for j in range(len(counts)) if counts[j]==True]
答案 1 :(得分:2)
尝试用
替换repr(col)
setofcols.add(tuple(column.A1.tolist()))
set
接受tuple
。 column.A1
是转换为1d数组的矩阵。然后,元组就像(0, 1, 0)
,set
可以轻松比较。
只需更换昂贵的repr
格式,就可以节省很多时间(25倍加速)。
修改
通过在一个语句中创建并填充set
,我可以进一步提高10倍速度。在我的测试中,它比bubble's
矢量化快2倍。
count = 0
for i in xrange(iters):
M = np.random.randint(2, size=(h,n))
product = np.dot(M,F)
setofcols = set(tuple(x) for x in product.T.tolist())
# or {tuple(x) for x in product.T.tolist()} if new enough Python
if (len(setofcols)==2**n):
count += 1
# print M # to see the unique M
print count*1.0/iters
修改
这里有更快的东西 - 使用dot([1,10,100,...],column)
将9个整数的每列转换为1。然后将np.unique
(或set
)应用于整数列表。这是进一步加速2-3倍。
count = 0
X = 10**np.arange(h)
for i in xrange(iters):
M = np.random.randint(2, size=(h,n))
product = np.dot(M,F)
setofcols = np.unique(np.dot(X,product).A1)
if (setofcols.size==2**n):
count += 1
print count*1.0/iters
这是最热门的电话
200 0.201 0.001 0.204 0.001 {numpy.core._dotblas.dot}
100 0.026 0.000 0.026 0.000 {method 'sort' of 'numpy.ndarray' objects}
100 0.007 0.000 0.035 0.000 arraysetops.py:93(unique)
答案 2 :(得分:1)
正如alko和seberg所指出的那样,你将大量的时间转换为大型字符串,以便将它们存储在你的列中。
如果我正确理解了您的代码,您将尝试查找product
矩阵中不同列的数量是否等于此矩阵的长度。您可以通过对其进行排序并查看从一列到下一列的差异来轻松实现:
D = (np.diff(np.sort(product.T, axis=0), axis=0) == 0)
这将为您提供布尔值D
矩阵。然后,您可以查看至少一个元素是否从一列更改为下一列:
C = (1 - np.prod(D, axis=1)) # i.e. 'not all(D[i,:]) for all i'
然后,您只需要查看all
值是否不同:
hasproperty = np.all(C)
它为您提供了完整的代码:
def f(n, h, iters):
F = np.array(list(itertools.product([0,1], repeat=n))).T
counts = []
for _ in xrange(iters):
M = np.random.randint(2, size=(h,n))
product = M.dot(F)
D = (np.diff(np.sort(product.T, axis=1), axis=0) == 0)
C = (1 - np.prod(D, axis=1))
hasproperty = np.all(C)
counts.append(1. if hasproperty else 0.)
return np.mean(counts)
f(12, 9, 100)
约需8秒。
如果你喜欢滑稽紧凑的表达式:
def g(n, h, iters):
F = np.array(list(itertools.product([0,1], repeat=n))).T
return np.mean([np.all(1 - np.prod(np.diff(np.sort(np.random.randint(2,size=(h,n)).dot(F).T, axis=1), axis=0)==0, axis=1)) for _ in xrange(iters)])
时间安排:
>>> setup = """import numpy as np
def g(n, h, iters):
F = np.array(list(itertools.product([0,1], repeat=n))).T
return np.mean([np.all(1 - np.prod(np.diff(np.sort(np.random.randint(2,size=(h,n)).dot(F).T, axis=1), axis=0)==0, axis=1)) for _ in xrange(iters)])
"""
>>> timeit.timeit('g(10, 7, 100)', setup=setup, number=10)
17.358669997900734
>>> timeit.timeit('g(10, 7, 100)', setup=setup, number=50)
83.06966196163967
每次拨打g(10,7,100)
或大约1.7s。