2017-10-18 363 views
2

我想在Python中生成1或-1,作爲在非負數和非正數之間隨機化或隨機更改已存在整數的符號的步驟。在Python中生成1或-1的最佳方法是什麼?假設均勻分佈的,我知道我可以使用:隨機生成1或-1(正整數或負整數)

import random 

#method1 
my_number = random.choice((-1, 1)) 

#method2 
my_number = (-1)**random.randrange(2) 

#method3 
# if I understand correctly random.random() should never return exactly 1 
# so I use "<", not "<=" 
if random.random() < 0.5: 
    my_number = 1 
else: 
    my_number = -1 

#method4 
my_number = random.randint(0,1)*2-1 

使用timeit模塊,我得到了以下結果:

#method1 
s = "my_number = random.choice((-1, 1))" 
timeit.timeit(stmt = s, setup = "import random") 
>2.814896769857569 
#method2 
s = "my_number = (-1)**random.randrange(2)" 
timeit.timeit(stmt = s, setup = "import random") 
>3.521280517518562 
#method3 
s = """ 
if random.random() < 0.5: my_number = 1 
else: my_number = -1""" 
timeit.timeit(stmt = s, setup = "import random") 
>0.25321546903273884 
#method4 
s = "random.randint(0,1)*2-1" 
timeit.timeit(stmt = s, setup = "import random") 
>4.526625442240402 

如此出人意料方法3是最快的。我打賭方法1是最快的,因爲它也是最短的。另外方法1(因爲Python 3.6我認爲?)和3給出了引入不均勻分佈的可能性。雖然方法1是最短的(主要advantege)現在我會選擇方法3:在Python

s = """ 
import random 
def positive_or_negative(): 
    if random.random() < 0.5: 
     return 1 
    else: 
     return -1 
     """ 
timeit.timeit(stmt = "my_number = positive_or_negative()", setup = s) 
>0.3916183138621818 

沒有更好的(更快或更短)方法隨機生成-​​1或1:

def positive_or_negative(): 
    if random.random() < 0.5: 
     return 1 
    else: 
     return -1 

測試?任何原因爲什麼你會選擇方法1而不是方法3,反之亦然?

+2

方法3是最快的,因爲所有其他方法都必須在內部執行類似的操作。 – Barmar

回答

2

的一個班輪變化#3:

return 1 if random.random() < 0.5 else -1 

它比'數學'變種更快(er),因爲它不涉及額外的算術。

-4

我的代碼

vals = array("i", [-1, 1]) 

def my_rnd(): 
    return vals[randint(0, 7) % 2] 
+1

你是否聲稱這更快?爲什麼使用'array.array'? –

+1

爲什麼使用'randint(0,7)%2'而不是'randint(0,1)'? – Barmar

+0

我的測試顯示這比所有OP的選項都要慢。 – RobertB

0

生成,如果你打算做很多,其中通過使用numpy的隨機數的最快方法:

In [1]: import numpy as np 

In [2]: import random 

In [3]: %timeit [random.choice([-1,1]) for i in range(100000)] 
10 loops, best of 3: 88.9 ms per loop 

In [4]: %timeit [(-1)**random.randrange(2) for i in range(100000)] 
10 loops, best of 3: 110 ms per loop 

In [5]: %timeit [1 if random.random() < 0.5 else -1 for i in range(100000)] 
100 loops, best of 3: 18.4 ms per loop 

In [6]: %timeit [random.randint(0,1)*2-1 for i in range(100000)] 
1 loop, best of 3: 180 ms per loop 

In [7]: %timeit np.random.choice([-1,1],size=100000) 
1000 loops, best of 3: 1.52 ms per loop 
+0

至少最後一個不僅返回-1,+ 1。 –

+0

是不是最後一個(7)相當於'random.choices([ - 1,1],k = 100000)'在'random'模塊中? – Siemkowski

+0

@Siemkowski有一個編輯,上面的評論提到(8)我想。 – sascha

2

這裏還有一個班輪,我的時機展示給比的if/else比較0.5速度更快:

[-1,1][random.randrange(2)] 
+0

我測試了這個 - 它不是更快。 'timeit.timeit(stmt =「my_number = 1 if random.random()<0.5 else -1」,setup =「import random」)''> 0.17129717730503558'和'timeit.timeit(「my_number = [-1,1 ] [random.randrange(1,2)]「,setup =」import random「)''> 2.5639535604734647' – Siemkowski

+0

@Siemkowski您的範圍指定與我的不同,並且各種版本的Python之間可能存在差異。 – pjs

+0

對不起,貼錯線,但對我來說還是比較慢。我使用'Python 3.6.1'。你測試了什麼版本? – Siemkowski

1

如果需要單位(每個呼叫一個),你已經做了你的基準和其他答案提供了更多信息。

如果您需要很多位或可以預先計算位陣列供以後使用,numpy的方法可能閃耀。

下面是使用numpy的(這令人驚訝的沒有一個專門用於這項工作正是法)一些演示的方法

import numpy as np 
import random 

def sample_bits(N): 
    assert N % 8 == 0 # demo only 
    n_bytes = N // 8 

    rbytes = np.random.randint(0, 255, dtype=np.uint8, size=n_bytes) 
    return np.unpackbits(rbytes) 

def alt(N): 
    return np.random.choice([-1,1],size=N) 

def alt2(N): 
    return [1 if random.random() < 0.5 else -1 for i in range(N)] 

if __name__ == '__main__': 
    import timeit 
    print(timeit.timeit("sample_bits(1024)", setup="from __main__ import sample_bits", number=10000)) 
    print(timeit.timeit("alt(1024)", setup="from __main__ import alt", number=10000)) 
    print(timeit.timeit("alt2(1024)", setup="from __main__ import alt2", number=10000)) 

輸出:

0.06640421246836543 
0.352129537507486 
1.5522800431775592 

的總體思路是:

  • 使用numpy在一個步驟中生成許多uint8
    • (有可能是一個更好的利用內部功能,而randint-API)
  • 解壓UINT8的8位
    • 從randint的均勻度均勻性擔保如下

再次,這只是一個演示:

  • 爲一個特定的情況下
  • 不關心不同的結果類型的這些功能
  • 不關心-1對0(可能是您的使用情況很重要)
  • (即使不是最優的比較到更低級別的方法;內部使用的MT可以用作比特源,與其他許多PRNG不同,它不需要fp數學)