## Randomly generate 1 or -1 (positive or negative integer)

I wanted to generate 1 or -1 in `Python`

as a step to randomizing between non-negative and non-positive numbers or to randomly changing sign of an already existing integer. What would be the best way to generate 1 or -1 in `Python`

? Assuming even distribution I know I could use:

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

Using `timeit`

module I got the following results:

#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

So unexpectedly method 3 is the fastest. My bet was on method 1 to be the fastest as it is also shortest. Also both method 1 (since `Python 3.6`

I think?) and 3 give the possibility to introduce uneven distributions. Although method 1 is shortest (main advantege) for now I would choose method 3:

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

Testing:

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

Any better (faster or shorter) method to randomly generate -1 or 1 in `Python`

? Any reason why would you choose method 1 over method 3 or vice versa?

A one liner variation of #3:

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

It's fast(er) than the 'math' variants, because it doesn't involve additional arithmetic.

Here's another one-liner that my timings show to be faster than the if/else comparison to 0.5:

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

not sure what your application is exactly, but I needed something similar for a large vectorized array.

Here's a good way to get a sign array:

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

The result is an array, for example:

array([-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1])

and you can use the reshape command to get the above to the size of your matrix:

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

Then you can multiply a matrix by the above and get all of the members with random signs.

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

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

Then you get something like :

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

Pretty quick, if your data is vectorized.

The fastest way to generate random numbers if you're going to be doing lots of them is by using 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