# Answers - In Class Activity - Sampling¶

Note

This exercise authored by Todd Gureckis and Brenden Lake, and is released under the license.

In the chapter, we discussed some basic issues in sampling. In this notebook, you will explore some handy python methods for sampling and consider the implications of sampling on what you understand about some target group (i.e., what you can generalize).

## Importing and using existing functions¶

```import numpy as np
import numpy.random as npr
import pandas as pd
import seaborn as sns
```

## Problem 0: Seeding a random number generator¶

When we use the computer to play with random numbers (or random samples), we aren’t actually using random numbers. Generally speaking your computer is a deterministic machine so it is unable to make truely random numbers. Intead the numbers your computer gives you are known as pseudo-random because they have many of the properties we want from random numbers but are not exactly and entirely random.

Anytime we use random numbers in a script, simulation, or analysis it is important to “seed” the random number generator. This initialized the random number generator function to a particularly “state” and this makes the number in the script random but repeatable.

Let’s experiment with this. First try running the following cell and seeing what the output is. Try running it multiple times and seeing how the numbers change.

```npr.randint(0,10,10)
```
```array([5, 7, 6, 8, 4, 3, 6, 9, 9, 8])
```

Now run this cell:

```npr.seed(10)
print(npr.randint(0,10,10))
print(npr.randint(0,10,10))
```
```[9 4 0 1 9 0 1 8 9 0]
[8 6 4 3 0 4 6 8 1 8]
```

Again, try repeating the cell execution over and over. What do you observe?

Try restarting the kernel and run the cell again. What do you notice? Compare to other people in your group. Also change the argument to `npr.seed()` and see what happens.

```## Enter solution here
npr.seed(9)
print(npr.randint(0,10,10))
print(npr.randint(0,10,10))
```
```[5 6 8 6 1 6 4 8 1 8]
[5 1 0 8 8 8 2 6 8 1]
```

Bottom line: Always seed the random number generator at the start of any script that uses random numbers so your code is more repeatable.

## Problem 1: Sampling from a finite population¶

Imagine I create a list with 100 randomly determined values as below. Using the web, research the the numpy random `choice()` function. Use it generate a random sample of size 10 from this data. Do it twice, once with replacement and once without replacement.

```my_data = np.array([75, 25, 59, 63, 48, 29,  3, 17, 68, 39,  9, 62, 61, 52, 64, 45, 90,
87,  0, 42, 26, 52, 22, 25, 20, 22, 81, 25, 48, 79, 37,  6, 33, 30,
81,  5, 37, 85, 65,  0, 27, 40, 96, 67, 77, 29, 32, 25,  4, 53, 46,
7, 51, 65, 46, 91, 60, 52, 93, 26,  2, 42, 18, 19, 97, 45, 78, 33,
25, 30, 97, 96, 99, 32, 86, 43, 81, 83, 51, 81, 36, 29,  2, 33, 95,
39, 79,  1, 80, 17, 50, 38,  1, 98, 30, 89, 93, 27, 43, 30])
```

```## Enter solution here
print(npr.choice(my_data,size=10,replace=True))
print(npr.choice(my_data,size=10,replace=False))
```
```[60 30 62 85 42 39 36 60 53 19]
[52 25 43 45 30  1 68  7 81 81]
```

## Problem 2: Sampling from a data frame¶

Sometimes what we are interested in is sampling from a pandas dataframe rather than a list or numpy array. Why might we want to sample from a dataset? One is to randomly select a subset of the data, for a training vs. test split, if we are doing machine learning projects on the data (we’ll talk about this later). Another is if there are too many records to analyze so it makes sense to randomly select a subset and analyze those. Another is to repeatedly sample over and over again from a dataset to do a statistical method called “boostrapping” (https://en.wikipedia.org/wiki/Bootstrapping_(statistics))

This code loads an example pandas dataset of different penguins.

```penguins_df = sns.load_dataset('penguins')
```
```penguins_df.head()
```
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex
0 Adelie Torgersen 39.1 18.7 181.0 3750.0 Male
1 Adelie Torgersen 39.5 17.4 186.0 3800.0 Female
2 Adelie Torgersen 40.3 18.0 195.0 3250.0 Female
3 Adelie Torgersen NaN NaN NaN NaN NaN
4 Adelie Torgersen 36.7 19.3 193.0 3450.0 Female
```penguins_df.info()
```
```<class 'pandas.core.frame.DataFrame'>
RangeIndex: 344 entries, 0 to 343
Data columns (total 7 columns):
#   Column             Non-Null Count  Dtype
---  ------             --------------  -----
0   species            344 non-null    object
1   island             344 non-null    object
2   bill_length_mm     342 non-null    float64
3   bill_depth_mm      342 non-null    float64
4   flipper_length_mm  342 non-null    float64
5   body_mass_g        342 non-null    float64
6   sex                333 non-null    object
dtypes: float64(4), object(3)
memory usage: 18.9+ KB
```

Research the pandas `sample()` method and randomly sample 20 penguins from the dataframe.

```## Enter solution here
penguins_df.sample(n=20)
```
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex
329 Gentoo Biscoe 48.1 15.1 209.0 5500.0 Male
190 Chinstrap Dream 46.9 16.6 192.0 2700.0 Female
207 Chinstrap Dream 52.2 18.8 197.0 3450.0 Male
255 Gentoo Biscoe 48.4 16.3 220.0 5400.0 Male
268 Gentoo Biscoe 44.9 13.3 213.0 5100.0 Female
224 Gentoo Biscoe 47.6 14.5 215.0 5400.0 Male
138 Adelie Dream 37.0 16.5 185.0 3400.0 Female
2 Adelie Torgersen 40.3 18.0 195.0 3250.0 Female
271 Gentoo Biscoe 48.5 14.1 220.0 5300.0 Male
342 Gentoo Biscoe 45.2 14.8 212.0 5200.0 Female
60 Adelie Biscoe 35.7 16.9 185.0 3150.0 Female
322 Gentoo Biscoe 47.2 15.5 215.0 4975.0 Female
185 Chinstrap Dream 51.0 18.8 203.0 4100.0 Male
122 Adelie Torgersen 40.2 17.0 176.0 3450.0 Female
279 Gentoo Biscoe 50.4 15.3 224.0 5550.0 Male
267 Gentoo Biscoe 50.5 15.9 225.0 5400.0 Male
334 Gentoo Biscoe 46.2 14.1 217.0 4375.0 Female
57 Adelie Biscoe 40.6 18.8 193.0 3800.0 Male
106 Adelie Biscoe 38.6 17.2 199.0 3750.0 Female
311 Gentoo Biscoe 52.2 17.1 228.0 5400.0 Male

Now, for part b of this question, in a for loop, 100 times create a random sample of the dataframe and compute the mean body mass of the penguins in your sample. Append all these values to a list and then plot a histogram of these values (using `sns.displot`). Compare it to the mean of the dataset containing all the penguins.

```## Enter solution here
overall_mean = penguins_df['body_mass_g'].mean()

list_sample_mean = []
for i in range(100):
sample_mean = penguins_df.sample(n=20)['body_mass_g'].mean()
list_sample_mean.append(sample_mean)

sns.displot(list_sample_mean)
print("Overall mean is ", overall_mean)
```
```Overall mean is  4201.754385964912
```

## Problem 3: Stratified sampling¶

One problem with the simple random samples we made of the penguins is that in each sample we might exclude some important groups of the data. For example, if we only sampled 10 penguins perhaps all of them are male. If we wanted to be more even handed name make sure our samples were representative of the sex differences then we might want to sample from the subpopulations. This is called “stratified sampling”.

Please read this example webpage: https://www.statology.org/stratified-sampling-pandas/ on stratified sampling and adapt the code to generate a random sample of 10 penguins that is stratified so that there are 5 male and 5 female examples in the sample

```## Enter solution here
penguins_df.groupby('sex').sample(5)
```
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex
184 Chinstrap Dream 42.5 16.7 187.0 3350.0 Female
16 Adelie Torgersen 38.7 19.0 195.0 3450.0 Female
104 Adelie Biscoe 37.9 18.6 193.0 2925.0 Female
64 Adelie Biscoe 36.4 17.1 184.0 2850.0 Female
27 Adelie Biscoe 40.5 17.9 187.0 3200.0 Female
168 Chinstrap Dream 50.3 20.0 197.0 3300.0 Male
179 Chinstrap Dream 49.5 19.0 200.0 3800.0 Male
123 Adelie Torgersen 41.4 18.5 202.0 3875.0 Male
101 Adelie Biscoe 41.0 20.0 203.0 4725.0 Male
194 Chinstrap Dream 50.9 19.1 196.0 3550.0 Male