<jupyter_start><jupyter_text>Task  No. 1 : CountsWrite a Python function called counts that takes a list asinput and returns a dictionary of unique items in the list as keys and the number oftimes each item appears as values Background Research: [1,2]  Lists and Dictionaries In python , a Dictionary and a list are basically a collection of objects and share a number of characteristics such as being mutable and changeable. It is how elements in a list or dictionary is accessed that the difference between them arises :- Lists elements are accessed through their position in that list whereas dictionary elements are accessed through their keysSo for this assignment , we are asked to count a list of unique items and to output the results in a form of a dictionary collection of keys and values. Where keys are the items in list and value is the number of times each item appears. Its important to note ,key/value elements are in curly brackets separated by a colon in dictionaries. To access information from dictionaries ,we use square brackets.  A dictionary Key  ( any data type or built in function) can only be used once , otherwise it will be overwritten however this is not the case for a value .Example code below taken from the task details shows the difference in order between lists and dictionaries :<jupyter_code>List = ['A', 'A', 'B', 'C', 'A']
List [0]
Dictionary = {'A': 3, 'B': 1, 'C': 1}
Dictionary ['A']<jupyter_output><empty_output><jupyter_text>For a list above , looking for the element in position 0 gives you 'A' , however looking the an element in a dictionary such as 'A' just gives you the corresponding value i.e number of times it appears.  Methods of Counting elements in list and outputing via a Dictionary [3,4] There are different Ways in Python to count words without the use of any modules  : 1.For loop :where the number of spaces between the two characters are counted2.Split() : by removing the spaces from the start and end, breaking every word whenever encountered a space and storing them in a list. The length (len) of the list is the total count of words.There are different Ways in Python to  count the frequency of words in a string : 1.Initializing a dictionary to store the frequency of words.The keys operation returns a list of keys that are defined in the dictionary. 2.Count() can be used to count the number of times a word occurs in a string or in other words it is used to tell the frequency of a word in a string. We just need to pass the word in the argument.  Development [3]Here we will look at the 2 ways mentioned of counting the frequency of words in a string : 1. Using the Task example of list elements and creating a dictionary. Also incorporating a For loop and an IF statement to return a dictionary output where each list element is key. For this example it is the length of the original list can be complex and content of the list that can be limiting or govern the output dictionary result. See Code Example no. 1<jupyter_code>#CODE EXAMPLE NO.1

my_list =["A","A","B","C","A"]
f = {} # created an empty dictionary
for item in my_list:
    if item in f:
        f[item] += 1
    else:
        f[item] = 1
print(f)<jupyter_output><empty_output><jupyter_text>Limitations [5]It is important to consider the data types to be examined. In terms of strings , they may need to be preprocessed prior to been counted. By Preprocessed , I mean removing spaces , making the string in the same cases ( either uppercase or lowercase). Also if we are using boolean expressions in the same list , these must be positioned last in the list in order to be counted.  Below is example of this : A limitation to this function is the data types /elements contained in the list. For example , if our list contain one type of element , either a string ( lower case or higher case elements) or integers or even boolean expressions then the function would work. The arrangement of the data types in the list is important also. For example if there are integers /string elements before a boolean expressions , than the function would output a correct count. However if they were arrangement after the boolean expression , then the python output would be incorrect. That is in python , the True expression counts as 1 and the False expression counts as 0. In Code example no. 2  we have included various data types in list and also created the function count(). Count() can be used to count the number of times a word occurs in a string or in other words it is used to tell the frequency of a word in a string. We just need to pass the list element in the argument<jupyter_code>#CODE EXAMPLE NO.2

def CountFrequency(my_list): 
      
    # Creating an empty dictionary  
    freq = {} 
    for items in my_list: 
        freq[items] = my_list.count(items) 
        
    for key, value in freq.items(): 
        print (key ,value)
        
# Driver function 
if __name__ == "__main__":  
   
    #my_list1 =[True, False, True ,"A","A","B","C","A", 1,2,2,2,1,1,1]
    #my_list2 =["A","A","B","C","A",True,True,True]
    CountFrequency(my_list)<jupyter_output><empty_output><jupyter_text>The Python program to counted the frequency of elements in a list using a dictionary and the in-built count() function but the output returned a dictionary stating the True expression appeared 6 times , however it was only there 3 times but because there were integers at the end of the list , it counted the 1s as true as well To overcome this and other examples of data types issues , variables can be added to the function, See code example no. 3 below which shows an example of case sensitivity and use of .lower() :<jupyter_code>####Code example no. 3
def CountFrequency(my_list): 
    
    my_list=my_list.lower()
    my_list=my_list.split(" ")
    # Creating an empty dictionary  
    freq = {} 
    for items in my_list: 
        freq[items] = my_list.count(items) 
        
    for key, value in freq.items(): 
        print (key ,value)
# Driver function 
if __name__ == "__main__":  
    

    user_input= str(input("Enter a string:"))
    
    print(CountFrequency(user_input))<jupyter_output><empty_output><jupyter_text>Code example no. 4 and 5 [6,7]A Python program to count the frequency of elements determined by user input by using the get() function. Python dictionary method get() returns a value for the given key. If key is not available then returns default value None.<jupyter_code>####Code example no. 4
user_str = input('Enter String:')
l = user_str.split()
d={} #create a dictionary
for i in l: 
    d[i]=d.get(i,0)+1 #functionality available in dictionary
print(d)<jupyter_output><empty_output><jupyter_text>Code example no. 5 is another example of using if/else statement in a for loop to output keys and values into a dictionary.<jupyter_code>#Code example no. 5 

def CountFrequency(string):
    
    string=string.lower() # converting string to lowercase
    string=string.split(" ")
    Count_Frequency={}# creating a dictionary

    for i in string: # using a for loop to count the frequencies of all the characters. 

        if i in Count_Frequency:
            Count_Frequency[i]+=1
        else:
            Count_Frequency[i]=1

    return(Count_Frequency)
    

user_input= str(input("Enter a string:"))
print(CountFrequency(user_input)) # the values of the characters and the frequencies stored as keys in the dictionary<jupyter_output><empty_output><jupyter_text>References : [1] https://www.w3schools.com/python/python_dictionaries.asp[2] https://realpython.com/python-dicts/[3] https://www.geeksforgeeks.org/counting-the-frequencies-in-a-list-using-dictionary-in-python/[4] https://www.geeksforgeeks.org/python-frequency-of-each-character-in-string/[5] https://www.tutorialspoint.com/counting-the-frequencies-in-a-list-using-dictionary-in-python[6] https://www.pythonpool.com/python-count-words-in-string/[7] https://www.includehelp.com/python/find-the-frequency-of-each-character-in-a-string.aspx------  Task no. 2 Rolling the Dice  [1-5] Aim :Write a Python function call dicerolls that simulates rolling dice :     It should :         - have 2 parameters (k) number of dice  and (n) no. of times to roll the dice     - simulate randomly rolling k dice n times, keeping track of each total face value    - return a dictionary with the number of times each possible total face value occurred         Development : Using the random module to randomize the numbers we get from the dice. Specifically Random.randint which needs a min and max value ( DIE_SIDES = 6 , then min is 1 and max is 7). Its depends on the number of DIE_SIDES selected which in turn relates to the number of dice to be rolled. Using a for loop to iterate through the range which is the number of NUM_ROLLS gives us a count which is return in the dictionary called rolls.<jupyter_code>##### Code 


import numpy as np
import random
def Diceroll (NUM_ROLLS,DIE_SIDES):
    NUM_ROLLS = 1000
    DIE_SIDES = 12 # enter the desired number of sides dependent of the number of die you want to roll.
# Create the dictionary to store the results of each roll of the die.
rolls = {}
#Loop for rolling the die NUM_ROLLS times
for r in range (1000):
    roll_result = random.randint(1, 13)
    if roll_result in rolls:
        # Add to the count for this number.
        rolls[roll_result] += 1
    else:
        # Record the first roll result for this number.
        rolls[roll_result] = 1

# Print how many times each number was rolled
for roll_result in range(1, 13):
    print("The number", str(roll_result), "was rolled", str(rolls[roll_result]), "times.")

#Total roll between all of them
#sum = 0
#for roll_result in rolls:
   # sum += roll_result * rolls[roll_result]

#print("The total roll result was", str(sum))<jupyter_output><empty_output><jupyter_text>References:[1] https://www.instructables.com/How-to-Roll-a-Dice-Using-Python/[2] https://numpy.org/devdocs/reference/random/generated/numpy.random.random_integers.html[3] https://gist.github.com/cosme12/8e63641ae58d34b684eae8a36d7f3f26[4] https://www.codegrepper.com/code-examples/python/python+random+dice[5] https://www.pythonforbeginners.com/code-snippets-source-code/game-rolling-the-dice------------------------------------------------------------------------------------------------------  Task No.3 Stimulate Flipping a Coin [1-4] Aim :  - Write a python code that simulates flipping a coin 1000 times - Run this code 1000 times - keeping track of the number of heads in each of the 1000 simulations - Plot to depict the resulting list of 1000 numbers showing that it roughly follows a bell-shaped curve - Give a detailed explanation Background : To stimulate flipping a coin is a real life example of the use of the numpy.random binomial function, where the coin toss demonstrates the probability of getting a head as success at each coin toss is P. The Binomial function parameters include :n =  number of trials/size /coin tossesp =  probability of success in each trialk =  number of success in n trials.Code no. 1 below is a simple example of using the numpy.random Generator.binomial distribution. However it does not keep track of number of heads in each coin flip.Code no. 2Using numpy.random Generator.binomial function , we toss a fair coin ( p=0.7 ), 100 times and repeated this experiment 1000 times and measured how many successes/heads. Using seaborn distplot to show the bell shaped curve.Following this , looking at calculating the probability of seeing x heads out of n=100 tosses,Estimating the probability of getting heads in n=100 coin tosses dividing by the no. of experiments and Plotting the probability of head (successes). Which again results in a bell shaped curveNB: To use an unfair coin ( biased) toss , where if you want to see more heads , the P  0.5 to produce more Tail results.  Discussion :The purpose of this task was to show when a coin is flipped many times (n=100, 1000 experiments) then the number of heads is well approximated by a bell-shaped curve. Looking the results and the curve from code no.2, it does show a bell shaped curve, where the highest point/success at achieving heads is at 70 but these chances decrease the further away you go from 70 , to the point where the chances of getting 0 or 100 heads is relatively low. So basically , the chances of getting any number of heads decreases as you move away from the highest point which is 70. Development :<jupyter_code>#Code no. 1 Flipping a Coin 10 times , tested 1000 times

# using the numpy.random.Generator.binomial distribution

import numpy as np
import random
import matplotlib.pyplot as plt 
rng = np.random.default_rng()
n=100 
p = .5  # number of trials, probability of each trial
s = rng.binomial(n, p, 1000)
print(s)
#Code no. 2  Using the random.binomial function to 

import numpy as np
import pandas as pd
import random
import matplotlib.pyplot as plt
import seaborn as sns


# Tossing a coin 1000 times where in each experiment we toss the coin 100 times. How many heads in each of the 100 experiments ?

rng = np.random.default_rng()
n=100
p=0.7 # no. of trials, probability of each trial
# let us repeat our experiment for 1000 times
size=1000
dist=rng.binomial(n=n, p=p, size=size)
print(dist)

#Graphing the results to demonstrate a bell-shaped curve


sns.distplot(rng.binomial(n=n, p=p, size=size),hist=False,label='binomial')


import pandas as pd
import random
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

rng = np.random.default_rng()
n=100
p=0.7 # no. of trials, probability of each trial
# let us repeat our experiment for 1000 times
size=1000
dist=rng.binomial(n=n, p=p, size=size)
print(dist)


#calculating the probability of seeing x heads out of n=100 tosses
HeadProb=[np.equal(dist,i). sum() for i in range(n)]
#print(HeadProb)
 
#Estimating the probability of getting heads in n=100 coin tosses dividing by the no. of experiments
probs_1000 = [np.equal(dist,i).mean() for i in range(n)]
#print(probs_1000)

#Plotting the probability of head (successes)

plt.plot(list(range(n)), probs_1000, color='blue', marker='o')
plt.xlabel('Number of Heads',fontsize=14)
plt.ylabel('Probability',fontsize=14)
plt.xlim([25, 100])
plt.show()<jupyter_output><empty_output><jupyter_text>[1] https://cmdlinetips.com/2018/12/simulating-coin-toss-experiment-with-binomial-random-numbers-using-numpy/[2] https://www.w3schools.com/python/numpy_random_binomial.asp[3] https://www.geeksforgeeks.org/python-binomial-distribution/[4] https://cmdlinetips.com/2018/12/simulating-coin-toss-experiment-with-binomial-random-numbers-using-numpy/[5] https://seaborn.pydata.org/generated/seaborn.distplot.html-------------------------------------------------------------------  Task No. 4:  Simpsons Paradox - How data can fool you  ? Aim:To create 4 datasets , each with an x array and a corresponding y array , to demonstrate Simpson's Paradox. Suggested : To create the x arrays using numpy.linspace and create the y array for each x using notation like :y = a * x + b where the a and b for each pair to demonstrate the paradox.Background :Simpson's paradox has been around since 1899 but wasnt offically named until 1972 by <NAME> based on <NAME>'s paper in 1951. It is a statistical and probability phenomenon where a total dataset shows one trend while the subsets of the data set show the opposite trends or none at all.A resolution to this paradox can be achieved when the casual relations and varibles are examined.There are many examples of this paradox in reality , a classic example is the admissions data for graduate school at Berkeley in 1972 where the overall admissions showed that men appeared  more likely to be admitted than women.The most important word , here is appeared, leading to the term gender discrimination been highlighted. However it was further research into the actual individual departments admissions that showed that men were less likely to be admitted than women.This raised questions as to what data do you look at and what ways exist to detect Simpsons Paradox ? For this example is makes more sense to look at the individual departments. In order to deal with it , we need to detect it in a given dataset through either plotting points or combining results in a dataset. Wikipedia gives good real life examples of simpsons paradox. Development:A number of examples of simpsons paradox were reviewed and examined to gain an understanding of it. The first dataset below , shows an attempt to simulate a set of results and graph to visualise the paradox using the suggested np.linspace random function and the adapted equation of a line. Other datasets below show the paradox but using other random functions to create datasets.   Dataset 1 : SImulated Train DataA dataset to show the total no. of trains and  no.of those trains delayed of 50 train journeys each from the Westport and Cork Train stations to Dublin Heusten. My premise is that the dataset will show a difference in the time delayed between the individual stations in comparsion to them combined. I plotted the total train vs the train delayed for each station and then combined.  The conclusion from these results are that from combined station delayed trains  numbers , you would not see a difference in the delay times at heusten station  , however looking at the individual trains stations feeding into dublin , you can see that the the cork to dublin heusten have more trains delayed.<jupyter_code>import pandas as pd
import random
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np



# Dataset 1 - train journeys from westport /cork train stations to Dublin Heusten station

#x1 = Total trains from westport station
#y1 = Total delayed from westport Station


x1 = np.linspace(0 ,30, 50)
#creating variables for y using the equation of the line
y1 = 3.0 * x1 + 2.0 + np.random.normal(3, 1,50)

#x2 = Total trains from Cork station
#y2 = Total delayed from Cork Stationn


x2 = np.linspace(5, 30, 50)
y2 = 6.0 * x2 + 5 + np.random.normal(2, 1, 50)

# Fit each using polyfit
coeffs1 = np.polyfit(x1,y1,1)
coeffs1

coeffs2 = np.polyfit(x2,y2,1)
coeffs2

# Plot both on one plot.
plt.plot(x1, y1, '.', label="Data set Cork train")
plt.plot(x1, coeffs1[0] * x1 + coeffs1[1], '-', label='Best fit line Cork Trains')
plt.plot(x2, y2, '.', label="Data set Westport Train")
plt.plot(x2, coeffs2[0] * x2 + coeffs2[1], '-', label='Best fit Westport Trains')
plt.legend();

# To combine results
x = np.concatenate([x1, x2])
y = np.concatenate([y1, y2])

coeffs = np.polyfit(x, y, 1)
coeffs

#What does the x/y relationship look like in the combined
#versus the original?
#plt.plot(x1, y1, '.', label="Data set Cork train")
plt.plot(x1, coeffs1[0] * x1 + coeffs1[1], '-', label='Best fit line Cork Trains')
#plt.plot(x2, y2, '.', label="Data set Westport Train")
plt.plot(x2, coeffs2[0] * x2 + coeffs2[1], '*', label='Best fit Westport Trains')
#plt.plot(x, y, '.', label="Combined")
plt.plot(x, coeffs[0] * x + coeffs[1], '-', label='Trains combined')

plt.legend();<jupyter_output><empty_output><jupyter_text>Dataset Example 2 BMI measurementLooking at the measurement of BMI and effect of height and weight between men and women.It is the body mass index value. It is the weight divided by the square of the height. It is used to categorize a personas underweight, normal weight and overweight if not obese. The datasets below shows height and weight data generated by np. random.normal for men and women. Individually the plots show that the BMI decreases with height. However when the genders are combined , the bmi increases with height. This demonstrates simpsons paradox.<jupyter_code>import pandas as pd
import seaborn as sns
import numpy as np

#Simulate height and weight data for men, then plot
men = pd.DataFrame({'height': np.random.normal(1.79, 0.05, 90) , 'weight':np.random.normal(85, 1, 90)})
men["bmi"] = men['weight']/men['height']**2
sns.lmplot(x='height', y='bmi', data=men)
men
women = pd.DataFrame({'height': np.random.normal(1.6, 0.05, 90) , 'weight':np.random.normal(60, 1, 90)})
women["bmi"] = women['weight']/women['height']**2
sns.lmplot(x='height', y='bmi', data=women)
women

#add a gender column to both dataframe to allow us to separate in future
men["gender"] = 'male'
women["gender"] = 'female'
#Combine the 2 dataframes
people = pd.concat([men,women])
sns.lmplot(x='height', y='bmi', data=people,)<jupyter_output><empty_output>
StarcoderdataJupyterStructuredCleanDedup