<jupyter_start><jupyter_text>Exploration of the numpy.random package:__Overall Purpose of the numpy.random package:__The overall purpose of the numpy.random package is to generate random numbers.Possible reasons for generating random numbers are to simulate data that is inaccessible, or to create data in order to practice data representation.Below I will explore several functions of the numpy.random package to demonstrate what they do and how they work. The first sampling of numpy functions to demonstrate is a set of functions called simple random data.These are integers, random, choice, and bytes. __Integers:__<jupyter_code>import numpy as np
rng = np.random.default_rng()
rng.integers(4, size=10)

#A random array of 10 integers up to, but not including, 4 was generated in the output.<jupyter_output><empty_output><jupyter_text>__Random:__<jupyter_code>import numpy as np
rng = np.random.default_rng()
rng.random()

#Generates a random number as a float.
type(rng.random())
rng.random((5,))

#Generates an array of 5 floats. 
#If you choose a different number, like 3 for example, you would get an array of three floats.
#You can also create a three by two array with the following:
#This method gives you an array of two columns of random floats up to, but not including, 4.

4 * rng.random((3, 2)) - 4<jupyter_output><empty_output><jupyter_text>__Choice:__<jupyter_code>#This function allows us to specify probability for each value.

import numpy as np
rng = np.random.default_rng()
rng.choice(7, 4)

#Outputs an array of 4 integers up to but never including 7
import numpy as np
rng = np.random.default_rng()
rng.choice(7, 4)
rng.choice(([4, 2, 4, 1]), p=([0.1, 0.3, 0.6, 0.0]), size=(100))

#Output is a 1-D Array containing 100 values where each value has to be 4,2, or 1.
#4 is assigned to 0.1, 2 to 0.3, 4 again to 0.6, and 1 to 0.0
#p always needs to be equal to 1

#You don't have to use only numbers for the arrays, but can also use lists.

import numpy as np
composers_arr = ['Mozart' , 'Bach' , 'Handel' , 'Beethoven' , 'Haydn' , 'Vivaldi']
rng.choice(composers_arr, 5 , p=([0.2, 0.1, 0.1, 0.1, 0.2, 0.3]))<jupyter_output><empty_output><jupyter_text>__Bytes:__<jupyter_code>#This function returns random bytes

import numpy as np
np.random.default_rng().bytes(20)<jupyter_output><empty_output><jupyter_text>The second sampling of Numpy functions to demonstrate are the two permutations functions: shuffle and permutation. __Shuffle:__<jupyter_code>#The shuffle method allows us to change or shuffle the elements in an array, but the contents stay the same.

import numpy as np
rng = np.random.default_rng()
arr = np.arange(12)
#rng.shuffle(arr)
arr

#Here, there is a random array of integers up to but not including 12
import numpy as np
rng = np.random.default_rng()
arr = np.arange(12)
rng.shuffle(arr) #By adding the Shuffle method, we've changed the order of the integers in the array.
arr<jupyter_output><empty_output><jupyter_text>A practical/real world usage for the shuffle method would be for the lottery.You draw a set number of lotto balls with numbers on them, 6 numbers for example, out of 100.You could use the shuffle method to choose the 6 random numbers:<jupyter_code>import numpy as np
lotto = list(range(1, 100)) #create a list of 100 numbers
x = np.array(lotto) #convert to a numpy array
np.random.shuffle(x) #shuffle the numbers
x
draw = x[0:6] #output first 6 random numbers
'The lotto numbers are', draw # dispay the lotto numbers<jupyter_output><empty_output><jupyter_text>__Permutations:__<jupyter_code>#The permutations method makes a copy of the original array and then returns a rearrangement of it.

import numpy as np
rng = np.random.default_rng()
arr = np.arange(15)
arr #random array
import numpy as np
rng = np.random.default_rng()
arr = np.arange(15)
rng.permutation(15) #rearranged array<jupyter_output><empty_output><jupyter_text>A practical usage for the permutations method would be when generating a good password for a computer or website.<jupyter_code>import numpy as np
letnumb = np.array(['1', 'n', 'z', 'h', 't', '8', 'J', 'K', '6', '4', '9', 'G'])
password = np.random.permutation(letnumb)
print('Password is=', password[1:9])<jupyter_output>Password is= ['t' 'G' '8' '1' 'z' 'J' '4' '6']<jupyter_text>The final set of functions in the numpy.random package that will be explored in this task is the Distributions set of functions.There are several Distributions functions, on each of which a person could complete a PhD, in the numpy.random package.For the purpose of this project, I will explore 5: Normal Distribution, Poisson Distribution, Exponential Distribution, Binomial Distribution, and Uniform Distribution __Normal Distribution:__Also known as the Gaussian Distribution, named after German mathematician <NAME>, the Normal Distribution is probably the most important distribution function, as it can be used in a myriad situations ranging from test scores, heartbeats, sports teams scores etc.This function has three parameters: - loc - or the mean- scale - or standard deviation- size - or shape of the arrayThe Normal Distribution function is also called 'The Bell Curve" due to the shape it creates on a graph.A practical example where one could use this function is when a teacher is trying to decipher the probabilities of  test scores of her students.<jupyter_code>#Code showing practical example mentioned above
from numpy import random
import matplotlib.pyplot as plt
import seaborn as sns

x = random.normal(loc=70, scale=3, size=(1, 30))#70 is average test score, 3 is std deviation,30 is num of students
sns.distplot(x, hist=False)

plt.title('Normal Distribution')
plt.xlabel('Test Scores')
plt.ylabel('p(x)')

plt.show()<jupyter_output><empty_output><jupyter_text>__Analysis:__ What we can see in this graph is that about 10% of students had a probability of scoring between 66% and 75% on their test. __Poisson Distribution:__The Poisson Distribution function is a probability distribution which shows the probability of events occuring at regular intervals when the events are independent of eachother.It is named after French mathematician <NAME>. https://en.wikipedia.org/wiki/Sim%C3%A9on_Denis_PoissonThere are two parameters for the Poisson Distribution function:- lam - the rate of known occurences of an event- size - shape of the returned array (optional parameter)Just for fun, the Poisson formula is:P(x; μ) = (e-μ) (μx) / x!The average number of successes within a given region is μ.x is the actual number of successes that result from the experiment, and e is approximately equal to 2.71828.e is Euler's number, a mathematical constant.Below I have created a Poisson experiment using Numpy.<jupyter_code>#Experiment: on an average sea safari in Summer in Ireland, you will see 4 dolphins per day.
#What's the probability of seeing 7 dolphins on a given day?

import numpy as np

#count number of days in an Irish Summer
Summer = np.busday_count(begindates=['2020-05-01'], enddates=['2020-08-01'])

print(Summer)

#66 days in an Irish Summer
#Experiment: on an average sea safari in Summer in Ireland, you will see 4 dolphins per day.
#What's the probability of seeing 7 dolphins on a given day?

import numpy as np

#count number of days in an Irish Summer
SummerDays = np.busday_count(begindates=['2020-05-01'], enddates=['2020-08-01'])

s = np.random.poisson(4, SummerDays)

import matplotlib.pyplot as plt
count, bins, ignored = plt.hist(s, 10, density=True)


plt.ylabel("% Probability")
plt.title("Probability of Number of Dolphins Seen During Sea Safari in Summer 2020")
plt.xlabel('Number of Dolphins')
plt.grid(True)
plt.show()<jupyter_output><empty_output><jupyter_text>__Analysis:__ What we can see from this graph is that there is a 0.06 percent probability that you will see 7 dolphins on sea safari. You are most likely to see 5 dolphins (~0.25% probability). Luckily for you, and especially for the dolphins, there is a 0% probability of seeing 4.5 dolphins whilst on sea safari in Ireland in Summer 2020. Finally, it is also unlikely for you to see 0 dolphins. __Exponential Distribution:__Exponential Distribution is the probability distribution of time between events, ie; time between earthquakes, volcano eruptions, lifetime of a product, dolphin sightings etc.It is related to Poisson Distribution in that Poisson corresponds to the number of occurances for an event in a given time period, and Exponential deals with the time itself between these events.Using the dolphin sighting experiment from above, let's now explore the probability percentage of the time between dolphin sightings on sea safari in Summer 2020 in Ireland.<jupyter_code>import numpy as np

#count number of dolphin sightings in an Irish Summer
DolphinSightings = np.busday_count(begindates=['2020-05-01'], enddates=['2020-08-01'])

s = np.random.poisson(1, DolphinSightings)#find array of dolphin sightings during above time period
                                          #assuming average would be one sighting per day
print(s)

r = np.mean(s) #Find mean of array 
print(r)

t = np.random.exponential(r, DolphinSightings)#Find out time in days between dolphin sightings
print(t)

from numpy import random
import matplotlib.pyplot as plt
import seaborn as sns

sns.distplot(random.exponential(size=1000), hist=False)


plt.ylabel("% Probability")
plt.title("Probability of Time Between Dolphin Sightings")
plt.xlabel('Number of Days Between Dolphin Sightings')
plt.grid(True)
plt.show()<jupyter_output>[4 1 2 1 2 1 1 0 1 1 0 1 0 0 0 0 0 0 1 1 0 0 1 0 2 2 1 0 1 1 2 2 0 2 2 2 2
 2 1 0 0 0 2 1 1 0 0 3 2 1 1 2 1 3 3 2 1 0 0 0 0 0 0 0 0 1]
0.9696969696969697
[0.0045153  1.80700773 1.11959498 1.38902519 0.82958317 0.77511994
 0.24578543 0.22936765 1.40223149 1.1130951  0.24820145 0.43281391
 0.19010317 0.05451702 0.34787404 1.16243956 1.08993067 0.01473698
 0.28440113 0.28101835 0.94566709 0.09514852 0.34521412 0.79428566
 0.03196293 0.37326507 0.68589929 0.98313391 0.73283687 0.90533651
 0.6190685  0.54598294 0.58115555 1.8076207  0.97727347 0.75232055
 1.42253572 0.2959548  0.6064811  0.485458   1.46898577 0.16482336
 0.26198501 2.75487876 2.6856126  1.65277318 0.26844925 1.41689648
 1.19700664 1.18354533 0.18588612 0.81910471 0.06643177 0.77079543
 0.31570809 1.40050577 0.09111159 0.79773365 0.20670599 0.93271495
 0.20032306 1.02576015 0.01863825 0.42838224 0.18001121 0.08475415]<jupyter_text>__Analysis:__What this graph shows us is that the highest percentage probability of time between dolphin sightings is 1 day at 0.6% and it steadily drops off to 0% probability between sightings at 5 days.  __Binomial Distribution:__Binomial distribution is a discrete probability distribution of a the number of successes in a sequence of n independent experiments, each asking a yes–no question.The outcome is a Boolean value where success (with probability p) or failure (with probability q = 1 − p).There are three parameters for this distribution:- n - number of trials.- p - probability of occurence of each trial- size - The shape of the returned array.A practical example of the Binomial Distribution function would be a coin toss, where the question would be heads or tails over a certain amount of coin tosses, and the outcome would show how often the result was either heads or tails (or success/failure).<jupyter_code>#use numpy and scipy.stats to analyse coin toss
import numpy as np
import scipy.stats as ss

#Typical coin has a head and a tail, so there's a 50% chance of getting each in a coin toss
#Let's say the probability of heads is 0.5 and for tails is 0.5

np.random.binomial(1, 0.5, 1) #array for one coin toss
                              #assigning 1 for heads and 0 for tails
    
#Now let's see how many heads we get when we flip the coin 50 times

np.random.binomial(50, 0.5, 1)


import matplotlib.pyplot as plt
import seaborn as sns

sns.distplot(np.random.binomial(50, 0.5, 50))#50 coin tosses, 0.5 probability for heads, repeated 50 times

plt.ylabel("% Probability")
plt.title("Occurences of Heads in a Coin Toss of 50 Tosses")
plt.xlabel('Number of Coin Tosses')
plt.grid(True)
plt.show()<jupyter_output><empty_output><jupyter_text>__Analysis:__ This graph shows us the number of times a coin toss would result in heads when tossing the coin 50 times and repeating the test 50 times. This shows us that there is a 14% chance of heads being called 25 times for each of the 50 tests. __Uniform Distribution:__There are two types of uniform distribution: discrete uniform distribution and continuous uniform distribution.In both types, there are three parameters:- a - lower bound - default 0.0- b - upper bound - default 1.0- size - The shape of the returned arrayDiscrete Uniform Distribution states that the probability of outcomes is equally likely and with finite values.For example, if you roll one die, you have an equal chance of rolling a 1,2,3,4,5, or 6 regardless of how many times you roll the die. It is impossible to roll a 2.3 or a 5.7, there are only the values of 1,2,3,4,5, and 6.Continuous Uniform (or Rectangular) Distribution states that the probability of outcomes is equally likely and with infinite values.For example, if you give a range of numbers to a random number generator, let's say 1 to 100, with continuous uniform distribution, you would have an equal chance drawing ANY number from between the specified range. You could draw a 5 or a 23.89 or a 99.99, or 100. All would have an equal probability of occurring.Let's take a look at these two examples with numpy and some visualisations.<jupyter_code>#Example 1: Discrete Uniform Distribution: Single Die Roll 
import numpy as np
s = np.random.default_rng().uniform(1,6,1000)#smallest value, highest value, times rolled
#print(s)

import matplotlib.pyplot as plt
count, bins, ignored = plt.hist(s, 15, density=True)
plt.plot(bins, np.ones_like(bins), linewidth=2, color='r')
#plt.show()

plt.ylabel("% Probability")
plt.title("Uniform Distribution: Single Die Roll")
plt.xlabel('Values of Six-Sided Die')
plt.grid(True)
plt.show()<jupyter_output><empty_output><jupyter_text>__Analysis:__ This graph shows us that for a single six-sided die rolled 1000 times, there is a 100% probability that you will roll a 1,2,3,4,5, or 6.<jupyter_code>#Example 2: Continuous Uniform Distribution: Random Number Generator w/ Range 1 to 100 inclusive

import numpy as np

#(b - a) * random_sample() + a

data = (100 - 1) * np.random.default_rng().random(100) + 1 #use this function to activate random number generator
print(data)
import numpy as np

#(b - a) * random_sample() + a

data = (100 - 1) * np.random.default_rng().random(100) + 1
#print(data)

import matplotlib.pyplot as plt
count, bins, ignored = plt.hist(data, 15, density=True)
plt.plot(bins, np.ones_like(bins), linewidth=2, color='r')
#plt.show()

plt.ylabel("% Probability")
plt.title("Uniform Continuous Distribution: Random Numbers Range 1 to 100")
plt.xlabel('Values 1 to 100')
plt.grid(True)
plt.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.0795416694424089, 'fraction_numerical': 0.06848311238425155, 'mean_word_length': 4.778290993071593, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 57, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 13, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '14', 'dir': 'jupyter-structured-clean-dedup', 'id': '384405', 'license': 'MIT', 'n_tokens_mistral': 5375, 'n_tokens_neox': 4530, 'n_words': 2041, 'path': 'numpy.random package.ipynb', 'repo_name': 'KeelyC0d3s/ProgrammingDataAnalysisHW', 'size': '15039'}