گردش تصادفی

در این بخش از پایتون برای تولید داده برای گردش ت127 صادفی استفاده می‌کنیم و سپس به کمک Matplotlib نمایش بصری جذّابی از این داده‌ها می‌سازیم. گردش تصادفی مسیری است که هیچ جهت مشخّصی ندارد امّا بر اساس دنباله‌ای از تصمیم‌های تصادفی تعیین می‌شود که هر کدام از تصمیم‌ها کاملاً تصادفی گرفته می‌شوند. شما می‌توانید گردش تصادفی را مانند حرکت مورچه‌ای سرگردان در نظر بگیرید که هر قدم خود را در جهتی تصادفی برمی‌دارد.

گردش‌های تصادفی کاربردهایی عملی در علوم طبیعی، فیزیک، زیست‌شناسی، شیمی و اقتصاد دارد. برای مثال دانه‌ی گرده‌ای که در قطره‌ای آب شناور است به این دلیل روی سطح آب حرکت می‌کند که مولکول‌های آب آن به طور مداوم به اطراف هل می‌دهند. حرکت مولکولی در یک قطره‌ی آب تصادفی است بنابراین مسیری که دانه‌ی گرده روی سطح طی می‌کند گردشی تصادفی به حساب می‌آید. کدی که در ادامه می‌نویسیم بسیاری از وضعیّت‌های جهان واقعی را مدل می‌کند.

ساختن کلاس RandomWalk()

برای ایجاد یک گردش تصادفی کلاس RandomWalk را ایجاد می‌کنیم که در مورد جهت حرکتی که باید انجام بگیرد تصمیم‌های تصادفی می‌گیرد. کلاس سه مشخّصه نیاز دارد: یک متغیّر برای ذخیره کردن تعداد نقطه‌ها در گردش و دو لیست برای ذخیره کردن مقدار مختصّات x و y هر نقطه‌ی حرکت.

تنها دو متد در کلاس RandomWalk مورد نیاز است: __init__() و fill_walk() که نقطه‌های حرکت را محاسبه می‌کند. از متد __init__() شروع می‌کنیم:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from random import choice

class RandomWalk:
    """A class to generate random walks."""

    def __init__(self, num_points=5000):
        """Initialize attributes of a walk."""
        self.num_points = num_points

        # All walks start at (0, 0).
        self.x_values = [0]
        self.y_values = [0]

برای گرفتن تصمیم‌های تصادفی حرکت‌های ممکن را در لیستی ذخیره می‌کنیم و سپس از تابع choice() از ماژول random استفاده می‌کنیم تا تصمیم بگیریم که در هر گام کدام حرکت را انجام دهیم. سپس تعداد پیش‌فرض نقطه‌ها را در یک گردش ۵۰۰۰ قرار می‌دهیم که برای تولید چند الگوی جالب کافی است و در عین حال برای تولید سریع گردش‌ها به اندازه‌ی کافی کوچک است. سپس دو لیست برای مقدارهای x و y می‌سازیم و شروع هر گردش را نقطه‌ی (0, 0) قرار می‌دهیم.

انتخاب جهت

مانند آن‌چه در ادامه می‌آید، از متد fill_walk() برای پر کردن مسیر گردش خود از نقطه‌ها استفاده و در هر گام جهت حرکت را تعیین می‌کنیم. این متد را به random_walk.py اضافه کنید:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def fill_walk(self):
    """Calculate all the points in the walk."""
    # Keep taking steps until the walk reaches the desired length.
    while len(self.x_values) < self.num_points:
        # Decide which direction to go and how far to go in that direction.
        x_direction = choice([1, -1])
        x_distance = choice([0, 1, 2, 3, 4])
        x_step = x_direction * x_distance

        y_direction = choice([1, -1])
        y_distance = choice([0, 1, 2, 3, 4])
        y_step = y_direction * y_distance

        # Reject moves that go nowhere.
        if x_step == 0 and y_step == 0:
            continue

        # Calculate the new position.
        x = self.x_values[-1] + x_step
        y = self.y_values[-1] + y_step

        self.x_values.append(x)
        self.y_values.append(y)

حلقه‌ای برپا می‌کنیم که اجرای آن تا پر شدن گردش با تعداد درستی نقطه ادامه می‌یابد. بخش اصلی متد fill_walk() از پایتون می‌خواهد که چهار تصمیم تصادفی را شبیه‌سازی کند: گردش به چپ می‌رود یا راست؟ در آن جهت چه‌قدر پیش می‌رود؟ آیا بالا می‌رود یا پایین؟ در این جهت چه‌قدر حرکت می‌کند؟

از choice([1, -1]) برای انتخاب مقدار x_direction استفاده می‌کنیم که یا ۱ (برای حرکت به راست) برمی‌گرداند یا -۱ (برای رفتن به چپ). سپس choice([0, 1, 2, 3, 4]) به پایتون می‌گوید که با انتخاب عددی صحیح بین ۰ و ۴، در آن جهت (x_direction) چه‌قدر حرکت کند. (آوردن ۰ در این لیست به ما امکان می‌دهد که در جهت محور y حرکت کنیم و در عین حال بتوانیم گام‌هایی در جهت هر دو محور داشته باشیم.)

طول هر گام در جهت‌های x و y را با ضرب کردنِ جهتِ هر حرکت در فاصله‌ای که انتخاب‌شده حساب می‌کنیم. حاصل مثبت برای x_step به معنای حرکت به راست، حاصل منفی به معنای حرکت به چپ و صفر به معنای حرکت عمودی است. مقداری مثبت برای y_step به معنای حرکت به بالا، مقدار منفی به معنای حرکت به سمت پایین و ۰ به معنای حرکت افقی است. اگر هر دو مقدار x_step و y_step صفر شود به جایی نمی‌رویم در نتیجه با صرف نظر از این حرکت حلقه را ادامه می‌دهیم.

برای به دست آوردن مقدار بعدی x، مقدار x_step را به آخرین مقدار ذخیره‌شده‌ی x_values اضافه می‌کنیم و همین کار را برای مقدارهای y تکرار می‌کنیم. زمانی که این مقدارها محاسبه شدند آن‌ها را به x_values و y_values الحاق می‌کنیم.

رسم گردش تصادفی

کد زیر تمام نقطه‌های یک گردش را رسم می‌کند:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import matplotlib.pyplot as plt
from random_walk import RandomWalk

# Make a random walk.
rw = RandomWalk()
rw.fill_walk()

# Plot the points in the walk.
plt.style.use('classic')
fig, ax = plt.subplots()
ax.scatter(rw.x_values, rw.y_values, s=15)

plt.show()

کار را با وارد کردن pyplot و RandomWalk شروع می‌کنیم. سپس گردشی تصادفی می‌سازیم و آن را در rw ذخیره می‌کنیم و سپس از فراخوانی fill_walk() مطمئن می‌شویم. مقادیر x و y گردش را به scatter() می‌دهیم و اندازه‌ی مناسبی برای نقطه‌ها انتخاب می‌کنیم. شکل ۱۵-۹ نمودار حاصل را با ۵۰۰۰ نقطه نشان می‌دهد. (در تصویرهای این بخش نمایشگر Matplotlib حذف شده‌اند ولی شما هنگام اجرای rw_visual.py آن را خواهید دید.)

![][image24]

شکل ۱۵-۹: یک گردش تصادفی با ۵۰۰۰ نقطه

تولید چند گردش تصادفی

هر کدام از گردش‌های تصادفی متفاوت‌اند و کند و کاو الگوهای مختلفی که می‌توانند تولید شوند کار جالبی است. یکی از راه‌ها برای به‌کارگیری کد قبلی برای تولید چند گردش بدون نیاز به اجرای مکرّر برنامه، قرار دادن آن در یک حلقه‌ی while است، مانند زیر:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import matplotlib.pyplot as plt
from random_walk import RandomWalk

# Keep making new walks, as long as the program is active.
while True:
    # Make a random walk.
    rw = RandomWalk()
    rw.fill_walk()

    # Plot the points in the walk.
    plt.style.use('classic')
    fig, ax = plt.subplots()
    ax.scatter(rw.x_values, rw.y_values, s=15)

    plt.show()

    keep_running = input("Make another walk? (y/n): ")
    if keep_running == 'n':
        break

این کد یک گردش تصادفی تولید می‌کند، آن را در نمایشگر Matplotlib نمایش می‌دهد و نمایشگر را باز نگه می‌دارد. زمانی که آن را ببندید از شما می‌پرسد که آیا می‌خواهید گردشی دیگر تولید کنید. y را وارد کنید تا گردش‌هایی در حوالی نقطه‌ی شروع تولید شود که اغلب در یک جهت حرکت می‌کنند و بخش‌های نازکی دارند که گروه‌های بزرگی از نقطه‌ها را به هم متّصل می‌کنند. برای پایان دادن به برنامه n را بزنید.