2014-09-20 1 views
4

말 2와 8의 모든 가능한 조합의 목록 (또는 배열)을 효율적으로 생성하는 방법이 있습니까? 예 :0과 b의 모든 가능한 조합 생성

[[0,0,0,0,0,0,0,0,1,1], 
[0,0,0,0,0,0,0,1,0,1,], 
...] 

이 방법이 효과적 일 수 있습니까?

import numpy as np 
result = [] 
for subset in itertools.combinations(range(10), 2): 
    subset = list(subset) 
    c = np.zeros(10) 
    c[subset] = 1 
    result.append(c) 

이 코드를 최적화하는 방법에 대한 아이디어가 있습니다.

답변

4

글쎄, 그것은 훨씬 적은 오버 헤드를 가지고 바인딩 많이 다르지만 NumPy와 배열에 대량 작업을 수행 아니다 : 시간의

import itertools 
import numpy 

which = numpy.array(list(itertools.combinations(range(10), 2))) 
grid = numpy.zeros((len(which), 10), dtype="int8") 

# Magic 
grid[numpy.arange(len(which))[None].T, which] = 1 

grid 
#>>> array([[1, 1, 0, 0, 0, 0, 0, 0, 0, 0], 
#>>>  [1, 0, 1, 0, 0, 0, 0, 0, 0, 0], 
#>>>  [1, 0, 0, 1, 0, 0, 0, 0, 0, 0], 
#>>>  [1, 0, 0, 0, 1, 0, 0, 0, 0, 0], 
#>>>  [1, 0, 0, 0, 0, 1, 0, 0, 0, 0], 
#>>> ... 

대량 다음 numpy.array(list(itertools.combinations(range(10), 2)))을 수행하는 데있다. 나는 numpy.fromiter을 사용하여 시도했지만 어떤 속도 향상도 얻지 못했습니다. 시간의 절반은 말 그대로 튜플을 생성하기 때문에 더 개선 할 수있는 유일한 방법은 C 또는 Cython과 같은 것으로 조합을 생성하는 것입니다.

+0

감사합니다. 이것은 잘 작동하는 것 같습니다. 시간 (원래 솔루션) : 13.2389998436 시간 (np.arange) : 1.6970000267 – furukama

+1

환상적인 색인 생성을 멋지게 사용하십시오! FWIW np.fromiter (조합 (범위 (55), 5), np.dtype ("i4, i4, i4, i4, i4"), 3478761) .view ("i4"). '는 목록을 먼저 작성하는 것보다 약 1.7 배 빠르지 만 작은 크기의 경우 장점이 없습니다. – Jaime

+0

@Jaime 타이밍을 내 주셔서 감사합니다. 그러나 Python 2.7 또는 3.4에서 속도 향상 기능을 재현 할 수 없습니다. 어쩌면 최근 버전의 Numpy가 변경되었을 수도 있습니다. – Veedrac

1

numpy.bincount 사용하여 대안 :

>>> [np.bincount(xs, minlength=10) for xs in itertools.combinations(range(10), 2)] 
[array([1, 1, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int64), 
array([1, 0, 1, 0, 0, 0, 0, 0, 0, 0], dtype=int64), 
array([1, 0, 0, 1, 0, 0, 0, 0, 0, 0], dtype=int64), 
array([1, 0, 0, 0, 1, 0, 0, 0, 0, 0], dtype=int64), 
...] 
+0

솔루션을 한 줄에 사용하는 것이 좋지만 위의 해결 방법만큼 빠르지는 않습니다. 50 개의 포지션에서 5 1의 경우,이 솔루션은 위의 1.7 초에 비해 6.3 초 걸립니다. – furukama

0

것은 우리가 이것에 대한 순열을 사용하지할까요? 예 :

from itertools import permutations as perm 
a, b = 6, 2 
print '\n'.join(sorted([''.join(s) for s in set(t for t in perm(a*'0' + b*'1'))])) 
+2

원본 전체가 너무 비효율적이었습니다. 순열과 정렬을 사용하면 상당히 나쁜 타이밍 특성을 갖게됩니다. 순열의 수는'O (a!)'이며, 조합의 수는'O (a!/(b! (ab)!))'이고'b! (ab)! ' 큰. – Veedrac

+0

좋아, @Veedrac, 그건 의미가있다. :어리둥절한: –