簡體   English   中英

隨機生成1或-1(正整數或負整數)

[英]Randomly generate 1 or -1 (positive or negative integer)

我想在Python生成1或-1作為在非負數和非正數之間隨機化或者隨機改變已存在整數的符號的步驟。 Python生成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現在最短(主要優點),但我會選擇方法3:

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

測試:

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

Python隨機生成-​​1或1的更好(更快或更短)的方法? 你有什么理由選擇方法1而不是方法3,反之亦然?

#3的單線間變化:

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

它比“數學”變體快(呃),因為它不涉及額外的算術。

這是另一個單行,我的時間顯示比if / else比較為0.5更快:

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

不確定你的應用程序是什么,但我需要類似的大型矢量化數組。

這是獲得符號數組的好方法:

(2 * np.random.randint(0,2,大小=(your_size)) - 1)

結果是一個數組,例如:

數組([ - 1,-1,-1,1,1,1,-1,-1,1,1,1,-1,-1,1,-1])

並且您可以使用reshape命令將上面的內容調整到矩陣的大小:

(2 * np.random.randint(0,2,大小=(m * n個)) - 1).reshape(M,N)

然后你可以用上面的矩陣乘以一個矩陣,並用隨機符號得到所有成員。

A = np.array([[1,2,3],[4,5,6]])

B = A *(2 * np.random.randint(0,2,size =(2 * 3)) - 1).reshape(2,3)

然后你會得到類似的東西:

B =數組([[1,2,-3],[4,5,-6]])

非常快,如果您的數據是矢量化的。

如果您需要單個位(每個呼叫一個),您已經完成了基准測試,其他答案提供了額外的信息。

如果您需要很多位或者可以預先計算位數以供以后使用,那么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-math!)

生成隨機數的最快方法是使用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

我的代碼是

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

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM