You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: part-advanced-topics/01-simulation.qmd
+145Lines changed: 145 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -708,6 +708,148 @@ mean(riemann$y)
708
708
:::
709
709
:::
710
710
711
+
712
+
::: callout-caution
713
+
### Example: Integration in 2d
714
+
715
+
::: panel-tabset
716
+
#### Problem
717
+
718
+
Let's say that you want to find an estimate for $\pi$, and you know that a circle with radius 1 has an area of exactly that. You also know, that all of the points on this circle can be written as $x^2 + y^2 \le 1$.
719
+
720
+
```{r, echo = F}
721
+
#| fig-width: 4
722
+
#| fig-height: 4
723
+
#| out-width: 50%
724
+
#| fig-cap: "The unit circle."
725
+
#| fig-alt: "A circle centered in (0,0) with radius 1."
geom_polygon(aes(y = fn(x)), fill = "grey70", alpha = 0.8) +
729
+
geom_polygon(aes(y = -fn(x)), fill = "grey70", alpha = 0.8) +
730
+
geom_path(aes(x = sin(theta), y = cos(theta)),
731
+
data = data.frame(theta=seq(0,2*pi, by = 0.0001))) + ylab("y")
732
+
733
+
```
734
+
735
+
Evaluating the area of the circle mathematically, would need us to either change to polar-coordinates or separate the graph into suitable functions (half-circles), and evaluate the integral between the top and the bottom:
736
+
$$
737
+
\int_{-1}^1 2 \sqrt{1-x^2} dx
738
+
$$
739
+
Instead, we note that the circle is encapsulated in a square with side length 2. We can reach all points in that square by using two independent uniform random random variables over the interval $[-1,1]$, i.e. when we generate two random values from U[-1,1], and use one as the $x$ coordinate and one as the $y$ coordinate, we get a point in the square.
740
+
If the sum of the squares of the coordinates are less than 1, the point will also fall inside the circle. If not, the point falls in one of the four corners of the square that are outside the circle.
741
+
742
+
```{r, echo = F}
743
+
#| fig-width: 4
744
+
#| fig-height: 4
745
+
#| out-width: 50%
746
+
#| fig-cap: "The unit circle is encapsulated by a square and overlaid with uniform points from U[-1,1] x U[-1,1]. "
747
+
#| fig-alt: "A circle centered in (0,0) with radius 1 overlaid with randomly generated points. The points inside the circle are drawn in a different color from the ones outside the circle."
geom_path(aes(x = x, y = y), data = data.frame(x = c(-1, 1, 1, -1, -1), y = c( 1, 1, -1, -1, 1))) +
761
+
geom_polygon(aes(y = fn(x)), fill = "grey70", alpha = 0.8) +
762
+
geom_polygon(aes(y = -fn(x)), fill = "grey70", alpha = 0.8) +
763
+
geom_path(aes(x = sin(theta), y = cos(theta)),
764
+
data = data.frame(theta=seq(0,2*pi, by = 0.0001))) + ylab("y") +
765
+
geom_point(aes(x = x, y = y, colour = in_circle), data = random) +
766
+
coord_equal()
767
+
768
+
```
769
+
770
+
How do we get to an estimate of $\pi$ from there? We know that the area of the square is simply $2^2 = 4$. The area of the circle is then directly proportional to the rate at which points fall into the circle, ie.
771
+
772
+
$$
773
+
\hat{\pi} = 4 \times \frac{\text{Number of points with } x^2+y^2 \le 1}{\text{Number of points generated}}.
774
+
$$
775
+
The more points we generate, the closer our estimate will be to the real value.
776
+
777
+
778
+
779
+
This problem is an example for Monte-Carlo Integration using an Acceptance-Rejection approach: we can slightly re-write the simulation and think of the generation of a new point in the circle as a two step process, where we first generate a value for $x$ from U[-1,1], and in second step generate a candidate $c$ for $y$ from U[-1, 1], which we will only accept as $y$, if $|c| \le \sqrt{1-x^2}$. Acceptance-Rejection sampling is the basis of a lot of [Markov-Chain Monte-Carlo](https://en.wikipedia.org/wiki/Markov_chain_Monte_Carlo) (MCMC) methods, such as e.g. the [Metropolis-Hastings algorithm](https://en.wikipedia.org/wiki/Metropolis%E2%80%93Hastings_algorithm).
780
+
781
+
#### R Code
782
+
783
+
```{r}
784
+
set.seed(20491720)
785
+
786
+
calculate_pi <- function(R) {
787
+
x = runif(R, min=-1, max=1)
788
+
y = runif(R, min=-1, max=1)
789
+
in_circle = x^2+y^2<1
790
+
791
+
4 * sum(in_circle) / R
792
+
}
793
+
794
+
# Quite a bit of variability with just 100 values
795
+
calculate_pi(100)
796
+
calculate_pi(100)
797
+
calculate_pi(100)
798
+
799
+
# Better with 10,000
800
+
calculate_pi(10000)
801
+
calculate_pi(10000)
802
+
803
+
# Better, but still only good for about 2-3 digits
804
+
calculate_pi(1000000)
805
+
806
+
pi
807
+
808
+
```
809
+
810
+
#### Python Code
811
+
812
+
```{python}
813
+
random.seed(20491720)
814
+
815
+
def calculate_pi(R):
816
+
x = np.random.uniform(size = R)
817
+
y = np.random.uniform(size = R)
818
+
in_circle = x**2+y**2<1
819
+
820
+
return 4 * sum(in_circle) / R
821
+
822
+
823
+
# Quite a bit of variability with just 100 values
824
+
calculate_pi(100)
825
+
calculate_pi(100)
826
+
calculate_pi(100)
827
+
828
+
# Better with 10,000
829
+
calculate_pi(10000)
830
+
calculate_pi(10000)
831
+
832
+
# Better, but still only good for about 2-3 digits
833
+
calculate_pi(1000000)
834
+
835
+
np.pi
836
+
```
837
+
838
+
#### Numeric integration
839
+
840
+
```{r}
841
+
set.seed(20491720)
842
+
fn <- function(x) 2*sqrt(1-x^2)
843
+
844
+
integrate(fn, lower=-1, upper=1)
845
+
846
+
pi
847
+
```
848
+
849
+
:::
850
+
:::
851
+
852
+
711
853
::: callout-tip
712
854
### Try it out
713
855
@@ -792,6 +934,9 @@ plt.show()
792
934
:::
793
935
:::
794
936
937
+
938
+
939
+
795
940
## Other Resources
796
941
797
942
-[Simulation](https://bookdown.org/rdpeng/rprogdatascience/simulation.html) (R programming for Data Science chapter)
0 commit comments