Random walk's weird outcome in python 3?

2019-02-21 06:49发布

问题:

I just start learning python and have a problem to print a new location of random walk in 3 dimensions. There is no error popping up, but it's obvious that the output (x, y, z) being printed is unreasonable! When simulating random walk step by step, I assume only one value in the (x, y, z) should be changed in each time. But it seems not in the output. I'm trying to debug it but still confused about identifying what the real problem is.

The output's head lines:

(0,-1,1)
(-1,0,1)
(-2,0,1)
(-2,1,2)
(-2,2,2)
(-2,2,3)
(-1,2,3)
(0,1,3)

My motivation:

The purpose of this code is to simulate N steps of a random walk in 3 dimensions. At each step, a random direction is chosen (north, south, east, west, up, down) and a step of size 1 is taken in that direction. The new location is then printed. The starting location is the origin (0, 0, 0).

My code:

import pdb
import random  # this helps us generate random numbers
N = 30  # number of steps
n = random.random()  # generate a random number

x = 0
y = 0
z = 0
count = 0 
while count <= N:
  if n < 1/6:
      x = x + 1           # move east
      n = random.random() # generate a new random number
  if n >= 1/6 and n < 2/6:
      y = y + 1           # move north
      n = random.random() # generate a new random number
  if n >= 2/6 and n < 3/6:
      z = z + 1           # move up
      n = random.random() # generate a new random number
  if n >= 3/6 and n < 4/6:
      x = x - 1           # move west
      n = random.random() # generate a new random number
  if n >= 4/6 and n < 5/6:
      y = y - 1           # move south
      n = random.random() # generate a new random number
  if n >= 5/6:
      z = z - 1           # move down
      n = random.random() # generate a new random number

  print("(%d,%d,%d)" % (x,y,z)) 
  count = count + 1
print("squared distance = %d" % (x*x + y*y + z*z))

Environment:

Python 3.5 in Jupyter Notebook, Windows 10, Dell XPS 13

回答1:

You set n to a new random number in every if test:

if n < 1/6:
    x = x + 1           # move east
    n = random.random() # generate a new random number

This means the next if test can then also match on the new n, giving you more than one change per step.

Move the n = random.random() step to the top of the loop, generating it only once per step. You probably want to use elif as well to avoid making too many tests:

N = 30  # number of steps

x = 0
y = 0
z = 0

for count in range(N):
    n = random.random() # generate a new random number
    if n < 1/6:
        x = x + 1           # move east
    elif n < 2/6:
        y = y + 1           # move north
    elif n < 3/6:
        z = z + 1           # move up
    elif n < 4/6:
        x = x - 1           # move west
    elif n < 5/6:
        y = y - 1           # move south
    else:
        z = z - 1           # move down

    print("(%d,%d,%d)" % (x,y,z)) 

I also switched to using a for loop over range() so you don't have to manually increment and test count.

This can be further simplified by using a list to store the directions, random.range() to pick an index in that list at random, and random.choice() to pick what direction to change the step in:

N = 30  # number of steps

pos = [0, 0, 0]

for count in range(N):
    index = random.randrange(3) # generate a new random index
    change = random.choice([-1, 1])
    pos[index] += change

    print(tuple(pos))


标签: python random