Python 随机生成1或-1(正整数或负整数)

Python 随机生成1或-1(正整数或负整数),python,random,Python,Random,我想在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.rand

我想在
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
因此,出乎意料的是,方法3是最快的。我打赌方法1是最快的,因为它也是最短的。另外,方法1(因为
python3.6
I think?)和方法3都提供了引入不均匀分布的可能性。虽然方法1是最短的(主要优点),但目前我会选择方法3:

def positive_or_negative():
    if random.random() < 0.5:
        return 1
    else:
        return -1
def正片或负片()
如果random.random()<0.5:
返回1
其他:
返回-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
s=”“”
随机输入
def正极或负极()
如果random.random()<0.5:
返回1
其他:
返回-1
"""
timeit.timeit(stmt=“my\u number=positive\u或\u negative()”,setup=s)
>0.3916183138621818
Python
中,有没有更好(更快或更短)的方法来随机生成-1或1?你为什么选择方法1而不是方法3?反之亦然?

我的代码如下

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

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

如果要生成大量随机数,最快的方法是使用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
[1]中的
:将numpy作为np导入
在[2]中:导入随机
在[3]中:%timeit[random.choice([-1,1])用于范围(100000)内的i)
10个回路,最佳3个:每个回路88.9毫秒
在[4]中:%timeit[(-1)**random.randrange(2)表示范围(100000)中的i)
10个回路,最好为3:110 ms/回路
在[5]中:%timeit[1 if random.random()<0.5 else-1表示范围内的i(100000)]
100个回路,最佳3个:每个回路18.4毫秒
[6]中:%timeit[random.randint(0,1)*2-1表示范围内的i(100000)]
1个回路,最好为3:180毫秒/回路
[7]中:%timeit np.random.choice([-1,1],size=100000)
1000个回路,最佳3个:每个回路1.52毫秒
3的单线性变化:

如果为random,则返回1。random()<0.5否则返回-1

它比“数学”变体快(er),因为它不涉及额外的算术。

这里是另一条直线,我的计时显示它比if/else与0.5的比较快:

[-1,1][random.randrange(2)]
如果您需要单个位(每个调用一个),那么您已经完成了基准测试,其他答案提供了额外的信息

如果您需要很多位,或者可以预先计算位数组以供以后使用,numpy的方法可能会大放异彩

下面是一些使用numpy的演示方法(令人惊讶的是,它没有专门用于此工作的方法):

总的想法是:

  • 使用numpy一步生成多个uint8
    • (如果没有randint API,使用内部函数可能会更好)
  • 将uint8解包为8位
    • 一致性源自randint的一致性保证
同样,这只是一个演示:

  • 针对一个具体案例
  • 不关心这些函数的不同结果类型
  • 不关心-1和0(在您的用例中可能很重要)
  • (与更低级的方法相比,甚至不是最优的;内部使用的MT可以用作位源,与许多其他PRNG一样,它不需要fp math!)

不确定您的应用程序到底是什么,但我需要一个类似的大型矢量化阵列

下面是获取符号数组的一个好方法:

(2*np.random.randint(0,2,size=(您的大小))-1)

结果是一个数组,例如:

数组([-1,-1,-1,1,1,1,1,-1,1,1,1,1,1,-1,1,1,-1])

您可以使用“重塑”命令将上述内容调整为矩阵的大小:

(2*np.random.randint(0,2,size=(m*n))-1).重塑(m,n)

然后你可以把一个矩阵乘以上面的数,得到所有随机符号的成员

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

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

然后你会得到这样的结果:

B=数组([[1,2,-3],[4,5,-6]]


如果你的数据是矢量化的,速度会很快。

方法3是最快的,因为所有其他方法都必须在内部执行类似的操作。为什么要使用
randint(0,7)%2
而不仅仅是
randint(0,1)
?我的测试表明这比OP的所有选项都慢。至少最后一个方法不仅返回-1,+1。最后一个不是(7)吗相当于
random.choices([-1,1],k=100000)
random
模块中?@Siemkowski有一个编辑,上面的评论提到(8)我想。@sascha我知道,我指的是(7)是的。但是python的random模块不是numpy的random模块
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.randrandRange(1,2)],setup=“import random”)
<2.5639535604734647
@Siemkowski您的范围规格与我的不同,不同版本的Python之间可能存在差异。对不起,粘贴了错误的行,但对我来说仍然较慢。我使用的是
python3.6.1
。你在哪个版本上测试它?@Siemkowski Python 2.7.10在MacOS上。我喜欢这段代码的简单性。在我的场景中,不要太在意性能上的差异-谢谢!(:
return 1 if random.random() < 0.5 else -1
[-1,1][random.randrange(2)]
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