GitHub

@@ -281,11 +281,13 @@ We will say more about this {doc}`later <writing_good_code>`.

281281

Consider again this code from the {doc}`previous lecture <python_by_example>`

282282283283

```{code-cell} python3

284+

rng = np.random.default_rng()

285+284286

ts_length = 100

285287

ϵ_values = [] # empty list

286288287289

for i in range(ts_length):

288-

e = np.random.randn()

290+

e = rng.standard_normal()

289291

ϵ_values.append(e)

290292291293

plt.plot(ϵ_values)

@@ -306,7 +308,7 @@ This is accomplished in the next program

306308

def generate_data(n):

307309

ϵ_values = []

308310

for i in range(n):

309-

e = np.random.randn()

311+

e = rng.standard_normal()

310312

ϵ_values.append(e)

311313

return ϵ_values

312314

@@ -336,9 +338,9 @@ def generate_data(n, generator_type):

336338

ϵ_values = []

337339

for i in range(n):

338340

if generator_type == 'U':

339-

e = np.random.uniform(0, 1)

341+

e = rng.uniform(0, 1)

340342

else:

341-

e = np.random.randn()

343+

e = rng.standard_normal()

342344

ϵ_values.append(e)

343345

return ϵ_values

344346

@@ -358,7 +360,7 @@ Notes

358360359361

Now, there are several ways that we can simplify the code above.

360362361-

For example, we can get rid of the conditionals all together by just passing the desired generator type *as a function*.

363+

For example, we can get rid of the conditionals all together by just passing the desired generator type as a function, method, or other [callable](https://typing.python.org/en/latest/spec/callables.html) object.

362364363365

To understand this, consider the following version.

364366

@@ -371,19 +373,19 @@ def generate_data(n, generator_type):

371373

ϵ_values.append(e)

372374

return ϵ_values

373375374-

data = generate_data(100, np.random.uniform)

376+

data = generate_data(100, rng.uniform)

375377

plt.plot(data)

376378

plt.show()

377379

```

378380379-

Now, when we call the function `generate_data()`, we pass `np.random.uniform`

381+

Now, when we call the function `generate_data()`, we pass `rng.uniform`

380382

as the second argument.

381383382-

This object is a *function*.

384+

This object is a *callable* — that is, an object that can be called using parentheses.

383385384-

When the function call `generate_data(100, np.random.uniform)` is executed, Python runs the function code block with `n` equal to 100 and the name `generator_type` "bound" to the function `np.random.uniform`.

386+

When the function call `generate_data(100, rng.uniform)` is executed, Python runs the function code block with `n` equal to 100 and the name `generator_type` "bound" to the callable `rng.uniform`.

385387386-

* While these lines are executed, the names `generator_type` and `np.random.uniform` are "synonyms", and can be used in identical ways.

388+

* While these lines are executed, the names `generator_type` and `rng.uniform` are "synonyms", and can be used in identical ways.

387389388390

This principle works more generally---for example, consider the following piece of code

389391

@@ -399,9 +401,7 @@ m(7, 2, 4)

399401

Here we created another name for the built-in function `max()`, which could

400402

then be used in identical ways.

401403402-

In the context of our program, the ability to bind new names to functions

403-

means that there is no problem *passing a function as an argument to another

404-

function*---as we did above.

404+

In the context of our program, the ability to bind names to functions, or more generally to callable objects, means that there is no problem passing one callable object as an argument to another callable --- as we did with `rng.uniform` above.

405405406406407407

(recursive_functions)=

@@ -507,7 +507,7 @@ factorial(4)

507507508508

The [binomial random variable](https://en.wikipedia.org/wiki/Binomial_distribution) $Y \sim Bin(n, p)$ represents the number of successes in $n$ binary trials, where each trial succeeds with probability $p$.

509509510-

Without any import besides `from numpy.random import uniform`, write a function

510+

Using `rng = np.random.default_rng()`, write a function

511511

`binomial_rv` such that `binomial_rv(n, p)` generates one draw of $Y$.

512512513513

```{hint}

@@ -527,12 +527,12 @@ If $U$ is uniform on $(0, 1)$ and $p \in (0,1)$, then the expression `U < p` eva

527527

Here is one solution:

528528529529

```{code-cell} python3

530-

from numpy.random import uniform

530+

rng = np.random.default_rng()

531531532532

def binomial_rv(n, p):

533533

count = 0

534534

for i in range(n):

535-

U = uniform()

535+

U = rng.uniform()

536536

if U < p:

537537

count = count + 1 # Or count += 1

538538

return count

@@ -558,7 +558,7 @@ Second, write another function that does the same task except that the second ru

558558559559

- If a head occurs `k` or more times within this sequence, pay one dollar.

560560561-

Use no import besides `from numpy.random import uniform`.

561+

Use `rng = np.random.default_rng()` to generate random numbers.

562562563563

```{exercise-end}

564564

```

@@ -573,15 +573,15 @@ Here's a function for the first random device.

573573574574575575

```{code-cell} python3

576-

from numpy.random import uniform

576+

rng = np.random.default_rng()

577577578578

def draw(k): # pays if k consecutive successes in a sequence

579579580580

payoff = 0

581581

count = 0

582582583583

for i in range(10):

584-

U = uniform()

584+

U = rng.uniform()

585585

count = count + 1 if U < 0.5 else 0

586586

print(count) # print counts for clarity

587587

if count == k:

@@ -601,7 +601,7 @@ def draw_new(k): # pays if k successes in a sequence

601601

count = 0

602602603603

for i in range(10):

604-

U = uniform()

604+

U = rng.uniform()

605605

count = count + ( 1 if U < 0.5 else 0 )

606606

print(count)

607607

if count == k:

Read the original on github.com ↗