diff --git a/.gitattributes b/.gitattributes index bdb0cabc..cee6d0d8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,7 @@ -# Auto detect text files and perform LF normalization +# Auto detect the text files and perform LF normalization easily! * text=auto -# Custom for Visual Studio +# Custom for Visual Studio (Any Version) *.cs diff=csharp # Standard to msysgit diff --git a/BinaryToDecimal.py b/BinaryToDecimal.py index ac41308d..1c3096c8 100644 --- a/BinaryToDecimal.py +++ b/BinaryToDecimal.py @@ -1,25 +1,25 @@ # Python: Binary to Decimal Conversion # binToDec and decToBin functions are rendered obsolete by the universal convert function -def binToDec(binNum): +def binToDec(binNum): #function created to convert binary to decimal with parametere binNum decNum = 0 power = 0 - while binNum > 0: - decNum += 2 ** power * (binNum % 10) - binNum //= 10 - power += 1 + while binNum > 0: #loop will run till binNum is greater than 0 + decNum += 2 ** power * (binNum % 10) + binNum //= 10 # reducing binNum everytime by 1 digit + power += 1 # increasing power by 1 each loop return decNum -def decToBin(decNum): +def decToBin(decNum): #function created to convert decimal to binary with parametere decNum binNum = 0 power = 0 - while decNum > 0: + while decNum > 0:#loop will run till decNum is greater than 0 binNum += 10 ** power * (decNum % 2) - decNum //= 2 - power += 1 + decNum //= 2 # reducing decNum everytime by 1 digit + power += 1 # increasing power by 1 each loop return binNum -def convert(fromNum, fromBase, toBase): +def convert(fromNum, fromBase, toBase): #function for converting from any base to any other base toNum = 0 power = 0 while fromNum > 0: @@ -31,4 +31,4 @@ def convert(fromNum, fromBase, toBase): # print (str(binToDec(101011))) # print (str(decToBin(128))) print (str(convert(127, 10, 8))) # converts 127 in base 10 to base 8 -print (str(convert(101001, 2, 2))) \ No newline at end of file +print (str(convert(101001, 2, 2))) diff --git a/Contributing.txt b/Contributing.txt new file mode 100644 index 00000000..52d1fd31 --- /dev/null +++ b/Contributing.txt @@ -0,0 +1,21 @@ +Contributions are always welcome!!!! +If you want to contribute to this repository follow the below procedure - +1. Fork this repository +2. Clone the code to your local system and go through readme.md +3. You can create another branch to add further commits + +GIT COMMANDS FOR CONTRIBUTING - +1. To clone this repository +`git clone [code link]` +2.To create new branch +`git checkout -b [branch name] ` +3. To stage files +`git add .` +4.To commit changes +`git commit -m "commit message"` +5. To push changes +`git push [remote branch] [new branch]` + +HAPPY CONTRIBUTION!!!!!!!! + + \ No newline at end of file diff --git a/Datasets.txt b/Datasets.txt new file mode 100644 index 00000000..ce44cedb --- /dev/null +++ b/Datasets.txt @@ -0,0 +1,75 @@ +Data.gov +NOAA - https://www.ncdc.noaa.gov/cdo-web/ + atmospheric, ocean +Bureau of Labor Statistics - https://www.bls.gov/data/ + employment, inflation +US Census Data - https://www.census.gov/data.html + demographics, income, geo, time series +Bureau of Economic Analysis - http://www.bea.gov/data/gdp/gross-domestic-product + GDP, corporate profits, savings rates +Federal Reserve - https://fred.stlouisfed.org/ + curency, interest rates, payroll +Quandl - https://www.quandl.com/ + financial and economic + +Data.gov.uk +UK Dataservice - https://www.ukdataservice.ac.uk + Census data and much more +WorldBank - https://datacatalog.worldbank.org + census, demographics, geographic, health, income, GDP +IMF - https://www.imf.org/en/Data + economic, currency, finance, commodities, time series +OpenData.go.ke + Kenya govt data on agriculture, education, water, health, finance, … +https://data.world/ +Open Data for Africa - http://dataportal.opendataforafrica.org/ + agriculture, energy, environment, industry, … +Kaggle - https://www.kaggle.com/datasets + A huge variety of different datasets +Amazon Reviews - https://snap.stanford.edu/data/web-Amazon.html + 35M product reviews from 6.6M users +GroupLens - https://grouplens.org/datasets/movielens/ + 20M movie ratings +Yelp Reviews - https://www.yelp.com/dataset + 6.7M reviews, pictures, businesses +IMDB Reviews - http://ai.stanford.edu/~amaas/data/sentiment/ + 25k Movie reviews +Twitter Sentiment 140 - http://help.sentiment140.com/for-students/ + 160k Tweets +Airbnb - http://insideairbnb.com/get-the-data.html + A TON of data by geo +UCI ML Datasets - http://mlr.cs.umass.edu/ml/ + iris, wine, abalone, heart disease, poker hands, …. +Enron Email dataset - http://www.cs.cmu.edu/~enron/ + 500k emails from 150 people + From 2001 energy scandal. See the movie: The Smartest Guys in the Room. +Spambase - https://archive.ics.uci.edu/ml/datasets/Spambase + Emails +Jeopardy Questions - https://www.reddit.com/r/datasets/comments/1uyd0t/200000_jeopardy_questions_in_a_json_file/ + 200k Questions and answers in json +Gutenberg Ebooks - http://www.gutenberg.org/wiki/Gutenberg:Offline_Catalogs + Large collection of books + +IMAGES +ImageNet - http://image-net.org + 14M images of objects +Google - https://ai.googleblog.com/2016/09/introducing-open-images-dataset.html + 9M image URLs with labels +Microsoft Coco - http://cocodataset.org + 330k images, most labeled +Labelled Faces in the Wild - http://vis-www.cs.umass.edu/lfw/ + 13k face images with names +Stanford Dogs - http://vision.stanford.edu/aditya86/ImageNetDogs/ + 120 dog breeds, 20k images + +AUTONOMOUS CARS +Berkeley DeepDrive - https://bdd-data.berkeley.edu/ + Massive dataset including 100k videos with 1100 hours of hd driving +Belgian Traffic Signs - http://www.vision.ee.ethz.ch/~timofter/traffic_signs/ + 10k images +Bosch Small Traffic Signals - https://hci.iwr.uni-heidelberg.de/node/6132 + 5k training and 8k test images +WPI Traffic Light, Pedestrian, Lane-Keeping - http://computing.wpi.edu/dataset.html + 30GB of training and test data from Worcester, Mass +UCSD Lisa - http://cvrr.ucsd.edu/LISA/datasets.html + Vehicle detection, traffic signals diff --git a/Date Time Timestamp/Date_Time.ipynb b/Date Time Timestamp/Date_Time.ipynb new file mode 100644 index 00000000..795b0b61 --- /dev/null +++ b/Date Time Timestamp/Date_Time.ipynb @@ -0,0 +1,424 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Using Times, Dates & Timestamps in Python" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Summary of Time and Date classes:\n", + "**datetime** # superclass for most of the date and time libraries \n", + "    **date** # general purpose date library \n", + "    **time** # general purpose time library \n", + "    **datetime** # for date and time in one object \n", + "    **timedelta** # for a duration or elapsed time \n", + "**time** # for Unix timestamp and process_time \n", + "**calendar** # for calendars \n", + "**dateutil** # extended datetime functionality, esp string parsing and delta calculation" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Today's Date\n", + "- Use datetime.date.today()\n", + "- datetime.date class has the following integer attributes, date(year, month, day)\n", + "- get day of the week using date.weekday() # Monday is 0" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2019-02-03\n", + "2 3 2019\n", + "6\n" + ] + } + ], + "source": [ + "from datetime import date\n", + "d1 = date.today()\n", + "print(d1)\n", + "print(d1.month, d1.day, d1.year)\n", + "print(d1.weekday())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### ISO format is a string format, yyyy-mm-dd\n", + "- date_object.isoformat() does the same thing as str(date_object)" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2011-11-23\n", + "2011-11-23\n", + "2011-11-23\n" + ] + }, + { + "data": { + "text/plain": [ + "datetime.date(2011, 11, 23)" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "d1 = date.fromisoformat('2011-11-23')\n", + "print(d1)\n", + "print(str(d1))\n", + "print(d1.isoformat())\n", + "d1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Comparison, addition and sutraction of dates\n", + "- Comparison gives boolean result. Later date is greater than earlier date.\n", + "- Date addition & subtraction give result as a datetime.timedelta object (explained more below).\n", + "- The same comparison and add/subtract operations can be used with time objects." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "1359 days, 0:00:00\n" + ] + } + ], + "source": [ + "d1 = date.today()\n", + "d2 = date(2015, 5, 14)\n", + "print(d1 > d2)\n", + "print(d1 - d2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Time\n", + "- time objects have the following attributes, time(hour, minute, second, microsecond, tzinfo)\n", + "- use datetime.time to compare time objects: t1 < t2 if t1 occurs before t2\n", + " - attributes are all optional, so you can just work with hours and minutes if you want\n", + "- daylight savings is handled by the time.dst() function (if tzinfo is set)" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "14:25:36.018625\n", + "02:19:00\n", + "False\n" + ] + } + ], + "source": [ + "from datetime import time\n", + "t1 = time(14, 25, 36, 18625)\n", + "print(t1)\n", + "\n", + "t2 = time(2, 19)\n", + "print(t2)\n", + "print(t1 < t2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### datetime.datetime combines date and time attributes into a datetime object\n", + "- datetime.datetime(year, month, day, hour, minute, second, microsecond, tzinfo)\n", + "- datetime.datetime objects can be used as dictionary keys\n", + "- includes functions: date(), time()" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1941-12-07 07:53:00\n", + "1941-12-07\n", + "07:53:00\n" + ] + } + ], + "source": [ + "from datetime import datetime\n", + "dt1 = datetime(1941, 12, 7, 7, 53)\n", + "print(dt1)\n", + "print(dt1.date())\n", + "print(dt1.time())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Use datetime.datetime.now() to get the current date and time" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10:02:21.354040\n", + "2019-02-03\n", + "10 2\n", + "2-3-2019\n" + ] + } + ], + "source": [ + "from datetime import datetime\n", + "t3 = datetime.now()\n", + "\n", + "print(t3.time())\n", + "print(t3.date())\n", + "print(t3.hour, t3.minute)\n", + "print(str(t3.month) + '-' + str(t3.day) + '-' + str(t3.year))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Use datetime.strftime() to get names of months and weekdays." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Sunday\n", + "Sun, Sunday, Feb, February, 02/03/19\n" + ] + } + ], + "source": [ + "from datetime import datetime\n", + "t3 = datetime.now()\n", + "print(t3.strftime('%A'))\n", + "print(t3.strftime('%a, %A, %b, %B, %x'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### A timedelta is used for a duration, or the time difference between two dates or times\n", + "- datetime.timedelta(days, seconds, microseconds)\n", + "- A timedelta can also be multiplied or divided by an integer or float" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "461 days, 0:00:00 \n", + "39830400.0\n", + "1383 days, 0:00:00\n" + ] + } + ], + "source": [ + "from datetime import timedelta, date, time\n", + "d1 = date(2011, 6, 15)\n", + "d2 = date(2012, 9, 18)\n", + "td = d2 - d1\n", + "print(td, type(td))\n", + "print(td.total_seconds())\n", + "print(td * 3)" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1008 days to event.\n", + "1008 days, 0:00:00 days to event.\n" + ] + } + ], + "source": [ + "from datetime import datetime\n", + "today = datetime.today().date()\n", + "my_event = date(2021, 11, 6)\n", + "days_to_event = abs(my_event - today)\n", + "print(days_to_event.days, 'days to event.')\n", + "print(days_to_event, 'days to event.')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Get a UNIX timestamp (time since the epoch)\n", + "- A timestamp is the time since Jan 1, 1970 in seconds\n", + "- Use time.time() to get timestamp\n", + "- Use datetime.fromtimestamp(ts) and datetime.timestamp(datetime_obj) to convert between timestamp and datetime\n", + "- Use time.process_time() to get runtime of an operation on your computer" + ] + }, + { + "cell_type": "code", + "execution_count": 117, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1549156155.9644115\n", + "Sat Feb 2 17:09:15 2019\n" + ] + } + ], + "source": [ + "import time\n", + "ts = time.time()\n", + "print(ts)\n", + "print(time.ctime(ts))" + ] + }, + { + "cell_type": "code", + "execution_count": 118, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2019-02-02 17:09:15.964411\n", + "1549156155.964411\n" + ] + } + ], + "source": [ + "from datetime import datetime\n", + "now = datetime.fromtimestamp(ts)\n", + "print(now)\n", + "print(datetime.timestamp(now))" + ] + }, + { + "cell_type": "code", + "execution_count": 119, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "operation executed in 0.0\n" + ] + } + ], + "source": [ + "start_time = time.process_time()\n", + "# do some stuff\n", + "end_time = time.process_time()\n", + "print('operation executed in ', end_time - start_time)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Date Time Timestamp/Date_Time_Timestamp.py b/Date Time Timestamp/Date_Time_Timestamp.py new file mode 100644 index 00000000..cc533dcf --- /dev/null +++ b/Date Time Timestamp/Date_Time_Timestamp.py @@ -0,0 +1,133 @@ +"""############################################################################## +Using Times, Dates & Timestamps in Python + +Summary of Time and Date classes: +datetime # superclass for most of the date and time libraries + date # general purpose date library + time # general purpose time library + datetime # for date and time in one object + timedelta # for a duration or elapsed time +time # for Unix timestamp and process_time +calendar # for calendars +dateutil # extended datetime functionality, esp string parsing and delta calculation +##############################################################################""" + +# Today's Date +# --------------------------- +# Use datetime.date.today() +# datetime.date class has the following integer attributes, date(year, month, day) +# get day of the week using date.weekday() # Monday is 0 + +from datetime import date +todays_date = date.today() +print(todays_date) +print(todays_date.month, todays_date.day, todays_date.year) +print(todays_date.weekday()) + +# ISO format is a string format, yyyy-mm-dd +# --------------------------- +# date_object.isoformat() does the same thing as str(date_object) + +from datetime import date +todays_date = date.fromisoformat('2011-11-23') +print(todays_date) +print(str(todays_date)) +print(todays_date.isoformat()) +todays_date + +# Comparison, addition and sutraction of dates +# --------------------------- +# Comparison gives boolean result. Later date is greater than earlier date. +# Date addition & subtraction give result as a datetime.timedelta object (explained more below). +# The same comparison and add/subtract operations can be used with time objects. + +from datetime import date +todays_date = date.today() +d2 = date(2015, 5, 14) +print(todays_date > d2) +print(todays_date - d2) + +# Time +# --------------------------- +# time objects have the following attributes, time(hour, minute, second, microsecond, tzinfo) +# use datetime.time to compare time objects: t1 < t2 if t1 occurs before t2 +# attributes are all optional, so you can just work with hours and minutes if you want +# daylight savings is handled by the time.dst() function (if tzinfo is set) + +from datetime import time +t1 = time(14, 25, 36, 18625) +print(t1) + +t2 = time(2, 19) +print(t2) +print(t1 < t2) + +# datetime.datetime combines date and time attributes into a datetime object +# --------------------------- +# datetime.datetime(year, month, day, hour, minute, second, microsecond, tzinfo) +# datetime.datetime objects can be used as dictionary keys +# includes functions: date(), time() + +from datetime import datetime +dt1 = datetime(1941, 12, 7, 7, 53) +print(dt1) +print(dt1.date()) +print(dt1.time()) + +# Use datetime.datetime.now() to get the current date and time + +t3 = datetime.now() + +print(t3.time()) +print(t3.date()) +print(t3.hour, t3.minute) +print(str(t3.month) + '-' + str(t3.day) + '-' + str(t3.year)) + +# Use datetime.strftime() to get names of months and weekdays. + +t3 = datetime.now() +print(t3.strftime('%A')) +print(t3.strftime('%a, %A, %b, %B, %x')) + +# A timedelta is used for a duration, or the time difference between two dates or times +# --------------------------- +# datetime.timedelta(days, seconds, microseconds) +# A timedelta can also be multiplied or divided by an integer or float + +from datetime import timedelta, date, time +todays_date = date(2011, 6, 15) +d2 = date(2012, 9, 18) +td = d2 - todays_date +print(td, type(td)) +print(td.total_seconds()) +print(td * 3) + +from datetime import datetime +today = datetime.today().date() +my_event = date(2021, 11, 6) +days_to_event = abs(my_event - today) +print(days_to_event.days, 'days to event.') +print(days_to_event, 'days to event.') + +# Get a UNIX timestamp (time since the epoch) +# --------------------------- +# A timestamp is the time since Jan 1, 1970 in seconds +# Use time.time() to get timestamp +# Use datetime.fromtimestamp(ts) and datetime.timestamp(datetime_obj) to convert between timestamp and datetime +# Use time.process_time() to get runtime of an operation on your computer + +import time +ts = time.time() +print(ts) +print(time.ctime(ts)) + + +from datetime import datetime +now = datetime.fromtimestamp(ts) +print(now) +print(datetime.timestamp(now)) + +start_time = time.process_time() +# do some stuff +end_time = time.process_time() +print('operation executed in ', end_time - start_time) diff --git a/Happy Pi Day.ipynb b/Happy Pi Day.ipynb new file mode 100644 index 00000000..fd0c8e51 --- /dev/null +++ b/Happy Pi Day.ipynb @@ -0,0 +1,105 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Happy Pi Day!\n", + "\n", + "### Two Ways to Calculate Pi: \n", + "Real pi = 3.14159265359\n", + "\n", + "### 1. percentage of unit square random points that lie in unit circle\n", + "This method is only as good as our random number generator. And with number of iterations the accuracy improves, up to about 1 million." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3.1419916\n" + ] + } + ], + "source": [ + "import random\n", + "in_square = in_circle = pi = 0\n", + "\n", + "for i in range(10000000):\n", + " x = random.random()\n", + " y = random.random()\n", + " dist = (x*x + y*y) ** 0.5\n", + "\n", + " in_square += 1\n", + " if dist <= 1.0:\n", + " in_circle += 1\n", + " \n", + "pi = 4 * in_circle / in_square\n", + "print(pi)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. using series addition\n", + "pi = 4/1 - 4/3 + 4/5 - 4/7 + 4/9 - 4/11 + 4/13 - 4/15 ... \n", + "This method is the more accurate of the two, and is faster. Its accuracy only depends on the size of n." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3.1415924535897797\n" + ] + } + ], + "source": [ + "pi = 0.0\n", + "for i in range(1, 10000000, 4):\n", + " pi += 4/i\n", + " pi -= 4/(i+2)\n", + "print(pi)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/HashMap.py b/HashMap.py index 445509c5..c5808e00 100644 --- a/HashMap.py +++ b/HashMap.py @@ -1,55 +1,62 @@ # Hash Map class HashMap: - def __init__(self): - self.size = 6 - self.map = [None] * self.size + def __init__(self): + self.size = 6 + self.map = [None] * self.size - def _get_hash(self, key): - hash = 0 - for char in str(key): - hash += ord(char) - return hash % self.size + def _get_hash(self, key): + hash = 0 + for char in str(key): + hash += ord(char) + return hash % self.size - def add(self, key, value): - key_hash = self._get_hash(key) - key_value = [key, value] + def add(self, key, value): + key_hash = self._get_hash(key) + key_value = [key, value] - if self.map[key_hash] is None: - self.map[key_hash] = list([key_value]) - return True - else: - for pair in self.map[key_hash]: - if pair[0] == key: - pair[1] = value - return True - self.map[key_hash].append(key_value) - return True + if self.map[key_hash] is None: + self.map[key_hash] = list([key_value]) + return True + else: + for pair in self.map[key_hash]: + if pair[0] == key: + pair[1] = value + return True + self.map[key_hash].append(key_value) + return True - def get(self, key): - key_hash = self._get_hash(key) - if self.map[key_hash] is not None: - for pair in self.map[key_hash]: - if pair[0] == key: - return pair[1] - return None + def get(self, key): + key_hash = self._get_hash(key) + if self.map[key_hash] is not None: + for pair in self.map[key_hash]: + if pair[0] == key: + return pair[1] + return None - def delete(self, key): - key_hash = self._get_hash(key) + def delete(self, key): + key_hash = self._get_hash(key) - if self.map[key_hash] is None: - return False - for i in range (0, len(self.map[key_hash])): - if self.map[key_hash][i][0] == key: - self.map[key_hash].pop(i) - return True - return False + if self.map[key_hash] is None: + return False + for i in range (0, len(self.map[key_hash])): + if self.map[key_hash][i][0] == key: + self.map[key_hash].pop(i) + return True + return False + + def keys(self): + arr = [] + for i in range(0, len(self.map)): + if self.map[i]: + arr.append(self.map[i][0]) + return arr - def print(self): - print('---PHONEBOOK----') - for item in self.map: - if item is not None: - print(str(item)) + def print(self): + print('---PHONEBOOK----') + for item in self.map: + if item is not None: + print(str(item)) h = HashMap() h.add('Bob', '567-8888') @@ -64,4 +71,4 @@ def print(self): h.delete('Bob') h.print() print('Ming: ' + h.get('Ming')) - \ No newline at end of file +print(h.keys()) diff --git a/Intro to Python Data Structures/Intro Python Data Structures.pptx b/Intro to Python Data Structures/Intro Python Data Structures.pptx new file mode 100644 index 00000000..0619f324 Binary files /dev/null and b/Intro to Python Data Structures/Intro Python Data Structures.pptx differ diff --git a/Intro to Python Data Structures/Python Data Structures.ipynb b/Intro to Python Data Structures/Python Data Structures.ipynb new file mode 100644 index 00000000..3b42851f --- /dev/null +++ b/Intro to Python Data Structures/Python Data Structures.ipynb @@ -0,0 +1,1096 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Intro to Python Data Structures\n", + "Lists, Tuples, Sets, Dicts \n", + "(c) 2019 Joe James \n", + "## Sequences: String, List, Tuple\n", + "****\n", + "**indexing** - access any item in the sequence using its index. \n", + "Indexing starts with 0 for the first element." + ] + }, + { + "cell_type": "code", + "execution_count": 116, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "g\n", + "cow\n" + ] + } + ], + "source": [ + "# string\n", + "x = 'frog'\n", + "print (x[3])\n", + "\n", + "# list\n", + "x = ['pig', 'cow', 'horse']\n", + "print (x[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**slicing** - slice out substrings, sublists, subtuples using indexes. \n", + "[start : end+1 : step]" + ] + }, + { + "cell_type": "code", + "execution_count": 117, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "omp\n", + "opt\n", + "puter\n", + "compu\n", + "r\n", + "ter\n", + "comput\n" + ] + } + ], + "source": [ + "x = 'computer'\n", + "print(x[1:4])\n", + "print(x[1:6:2])\n", + "print(x[3:])\n", + "print(x[:5])\n", + "print(x[-1])\n", + "print(x[-3:])\n", + "print(x[:-2])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**adding / concatenating** - combine 2 sequences of the same type by using +" + ] + }, + { + "cell_type": "code", + "execution_count": 118, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "horseshoe\n", + "['pig', 'cow', 'horse']\n" + ] + } + ], + "source": [ + "# string\n", + "x = 'horse' + 'shoe'\n", + "print(x)\n", + "\n", + "# list\n", + "y = ['pig', 'cow'] + ['horse']\n", + "print(y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**multiplying** - multiply a sequence using *" + ] + }, + { + "cell_type": "code", + "execution_count": 119, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "bugbugbug\n", + "[8, 5, 8, 5, 8, 5]\n" + ] + } + ], + "source": [ + "# string\n", + "x = 'bug' * 3\n", + "print(x)\n", + "\n", + "# list\n", + "y = [8, 5] * 3\n", + "print(y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**checking membership** - test whether an item is or is not in a sequence." + ] + }, + { + "cell_type": "code", + "execution_count": 120, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "False\n" + ] + } + ], + "source": [ + "# string\n", + "x = 'bug'\n", + "print('u' in x)\n", + "\n", + "# list\n", + "y = ['pig', 'cow', 'horse']\n", + "print('cow' not in y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**iterating** - iterating through the items in a sequence" + ] + }, + { + "cell_type": "code", + "execution_count": 121, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "7\n", + "8\n", + "3\n", + "0 7\n", + "1 8\n", + "2 3\n" + ] + } + ], + "source": [ + "# item\n", + "x = [7, 8, 3]\n", + "for item in x:\n", + " print(item)\n", + " \n", + "# index & item\n", + "y = [7, 8, 3]\n", + "for index, item in enumerate(y):\n", + " print(index, item)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**number of items** - count the number of items in a sequence" + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n", + "3\n" + ] + } + ], + "source": [ + "# string\n", + "x = 'bug'\n", + "print(len(x))\n", + "\n", + "# list\n", + "y = ['pig', 'cow', 'horse']\n", + "print(len(y))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**minimum** - find the minimum item in a sequence lexicographically. \n", + "Alpha or numeric types, but cannot mix types." + ] + }, + { + "cell_type": "code", + "execution_count": 123, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "b\n", + "cow\n" + ] + } + ], + "source": [ + "# string\n", + "x = 'bug'\n", + "print(min(x))\n", + "\n", + "# list\n", + "y = ['pig', 'cow', 'horse']\n", + "print(min(y))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**maximum** - find the maximum item in a sequence lexicographically. \n", + "Alpha or numeric types, but cannot mix types." + ] + }, + { + "cell_type": "code", + "execution_count": 124, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "u\n", + "pig\n" + ] + } + ], + "source": [ + "# string\n", + "x = 'bug'\n", + "print(max(x))\n", + "\n", + "# list\n", + "y = ['pig', 'cow', 'horse']\n", + "print(max(y))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**sum** - find the sum of items in a sequence. \n", + "Entire sequence must be numeric." + ] + }, + { + "cell_type": "code", + "execution_count": 125, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "27\n", + "20\n" + ] + } + ], + "source": [ + "# string -> error\n", + "# x = [5, 7, 'bug']\n", + "# print(sum(x)) # generates an error\n", + "\n", + "# list\n", + "y = [2, 5, 8, 12]\n", + "print(sum(y))\n", + "print(sum(y[-2:]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**sorting** - returns a new list of items in sorted order. \n", + "Does not change the original list." + ] + }, + { + "cell_type": "code", + "execution_count": 126, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['b', 'g', 'u']\n", + "['cow', 'horse', 'pig']\n" + ] + } + ], + "source": [ + "# string\n", + "x = 'bug'\n", + "print(sorted(x))\n", + "\n", + "# list\n", + "y = ['pig', 'cow', 'horse']\n", + "print(sorted(y))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**count(item)** - returns count of an item" + ] + }, + { + "cell_type": "code", + "execution_count": 127, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n", + "2\n" + ] + } + ], + "source": [ + "# string\n", + "x = 'hippo'\n", + "print(x.count('p'))\n", + "\n", + "# list\n", + "y = ['pig', 'cow', 'horse', 'cow']\n", + "print(y.count('cow'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**index(item)** - returns the index of the first occurence of an item." + ] + }, + { + "cell_type": "code", + "execution_count": 128, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n", + "1\n" + ] + } + ], + "source": [ + "# string\n", + "x = 'hippo'\n", + "print(x.index('p'))\n", + "\n", + "# list\n", + "y = ['pig', 'cow', 'horse', 'cow']\n", + "print(y.index('cow'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**unpacking** - unpack the n items of a sequence into n variables" + ] + }, + { + "cell_type": "code", + "execution_count": 129, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "pig cow horse\n" + ] + } + ], + "source": [ + "x = ['pig', 'cow', 'horse']\n", + "a, b, c = x\n", + "print(a, b, c)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Lists \n", + "****\n", + "- General purpose\n", + "- Most widely used data structure \n", + "- Grow and shrink size as needed\n", + "- Sequence type\n", + "- Sortable \n", + "\n", + "**constructors** - creating a new list" + ] + }, + { + "cell_type": "code", + "execution_count": 130, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, 1, 2, 3, 4, 5, 6, 7]\n", + "[25, 36, 49, 64, 81]\n" + ] + } + ], + "source": [ + "x = list()\n", + "y = ['a', 25, 'dog', 8.43]\n", + "tuple1 = (10, 20)\n", + "z = list(tuple1)\n", + "\n", + "# list comprehension\n", + "a = [m for m in range(8)]\n", + "print(a)\n", + "b = [i**2 for i in range(10) if i>4]\n", + "print(b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**delete** - delete a list or an item in a list" + ] + }, + { + "cell_type": "code", + "execution_count": 131, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5, 8, 6]\n" + ] + } + ], + "source": [ + "x = [5, 3, 8, 6]\n", + "del(x[1])\n", + "print(x)\n", + "del(x) # list x no longer exists" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**append** - append an item to a list" + ] + }, + { + "cell_type": "code", + "execution_count": 132, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5, 3, 8, 6, 7]\n" + ] + } + ], + "source": [ + "x = [5, 3, 8, 6]\n", + "x.append(7)\n", + "print(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**extend** - append a sequence to a list" + ] + }, + { + "cell_type": "code", + "execution_count": 133, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5, 3, 8, 6, 12, 13]\n" + ] + } + ], + "source": [ + "x = [5, 3, 8, 6]\n", + "y = [12, 13]\n", + "x.extend(y)\n", + "print(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**insert** - insert an item at a given index" + ] + }, + { + "cell_type": "code", + "execution_count": 134, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5, 7, 3, 8, 6]\n", + "[5, ['a', 'm'], 7, 3, 8, 6]\n" + ] + } + ], + "source": [ + "x = [5, 3, 8, 6]\n", + "x.insert(1, 7)\n", + "print(x)\n", + "x.insert(1, ['a', 'm'])\n", + "print(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**pop** - pops last item off list and returns item" + ] + }, + { + "cell_type": "code", + "execution_count": 135, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5, 3, 8]\n", + "8\n" + ] + } + ], + "source": [ + "x = [5, 3, 8, 6]\n", + "x.pop() # pop off the 6\n", + "print(x)\n", + "print(x.pop())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**remove** - remove first instance of an item" + ] + }, + { + "cell_type": "code", + "execution_count": 136, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5, 8, 6, 3]\n" + ] + } + ], + "source": [ + "x = [5, 3, 8, 6, 3]\n", + "x.remove(3)\n", + "print(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**reverse** - reverse the order of the list. It is an in-place sort, meaning it changes the original list." + ] + }, + { + "cell_type": "code", + "execution_count": 137, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[6, 8, 3, 5]\n" + ] + } + ], + "source": [ + "x = [5, 3, 8, 6]\n", + "x.reverse()\n", + "print(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**sort** - sort the list in place. \n", + "Note: \n", + "sorted(x) returns a new sorted list without changing the original list x. \n", + "x.sort() puts the items of x in sorted order (sorts in place)." + ] + }, + { + "cell_type": "code", + "execution_count": 138, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[3, 5, 6, 8]\n" + ] + } + ], + "source": [ + "x = [5, 3, 8, 6]\n", + "x.sort()\n", + "print(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tuples\n", + "****\n", + "- Immutable (can’t add/change)\n", + "- Useful for fixed data\n", + "- Faster than Lists\n", + "- Sequence type \n", + " \n", + "**constructors** - creating new tuples." + ] + }, + { + "cell_type": "code", + "execution_count": 139, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(2,) \n", + "(2, 4, 6) \n" + ] + } + ], + "source": [ + "x = ()\n", + "x = (1, 2, 3)\n", + "x = 1, 2, 3\n", + "x = 2, # the comma tells Python it's a tuple\n", + "print(x, type(x))\n", + "\n", + "list1 = [2, 4, 6]\n", + "x = tuple(list1)\n", + "print(x, type(x))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**tuples are immutable**, but member objects may be mutable." + ] + }, + { + "cell_type": "code", + "execution_count": 140, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(1, 2, 3)\n", + "([1], 3)\n" + ] + } + ], + "source": [ + "x = (1, 2, 3)\n", + "# del(x[1]) # fails\n", + "# x[1] = 8 # fails\n", + "print(x)\n", + "\n", + "y = ([1, 2], 3) # a tuple where the first item is a list\n", + "del(y[0][1]) # delete the 2\n", + "print(y) # the list within the tuple is mutable" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Sets\n", + "****\n", + "- Store non-duplicate items \n", + "- Very fast access vs Lists \n", + "- Math Set ops (union, intersect) \n", + "- Sets are Unordered \n", + " \n", + "**constructors** - creating new sets" + ] + }, + { + "cell_type": "code", + "execution_count": 141, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{3, 5}\n", + "set()\n", + "{2, 3, 4}\n" + ] + } + ], + "source": [ + "x = {3, 5, 3, 5}\n", + "print(x)\n", + "\n", + "y = set()\n", + "print(y)\n", + "\n", + "list1 = [2, 3, 4]\n", + "z = set(list1)\n", + "print(z)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**set operations**" + ] + }, + { + "cell_type": "code", + "execution_count": 142, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{8, 3, 5}\n", + "{8, 3, 5, 7}\n", + "{8, 5, 7}\n", + "3\n", + "True\n", + "8 {5, 7}\n", + "set()\n" + ] + } + ], + "source": [ + "x = {3, 8, 5}\n", + "print(x)\n", + "x.add(7)\n", + "print(x)\n", + "\n", + "x.remove(3)\n", + "print(x)\n", + "\n", + "# get length of set x\n", + "print(len(x))\n", + "\n", + "# check membership in x\n", + "print(5 in x)\n", + "\n", + "# pop random item from set x\n", + "print(x.pop(), x)\n", + "\n", + "# delete all items from set x\n", + "x.clear()\n", + "print(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Mathematical set operations** \n", + "intersection (AND): set1 & set2 \n", + "union (OR): set1 | set1 \n", + "symmetric difference (XOR): set1 ^ set2\n", + "difference (in set1 but not set2): set1 - set2 \n", + "subset (set2 contains set1): set1 <= set2 \n", + "superset (set1 contains set2): set1 >= set2" + ] + }, + { + "cell_type": "code", + "execution_count": 143, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{3}\n", + "{1, 2, 3, 4, 5}\n", + "{1, 2, 4, 5}\n", + "{1, 2}\n", + "False\n", + "False\n" + ] + } + ], + "source": [ + "s1 = {1, 2, 3}\n", + "s2 = {3, 4, 5}\n", + "print(s1 & s2)\n", + "print(s1 | s2)\n", + "print(s1 ^ s2)\n", + "print(s1 - s2)\n", + "print(s1 <= s2)\n", + "print(s1 >= s2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Dictionaries (dict)\n", + "****\n", + "- Key/Value pairs\n", + "- Associative array, like Java HashMap\n", + "- Dicts are Unordered" + ] + }, + { + "cell_type": "code", + "execution_count": 144, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'pork': 25.3, 'beef': 33.8, 'chicken': 22.7}\n", + "{'pork': 25.3, 'beef': 33.8, 'chicken': 22.7}\n", + "{'pork': 25.3, 'beef': 33.8, 'chicken': 22.7}\n" + ] + } + ], + "source": [ + "x = {'pork':25.3, 'beef':33.8, 'chicken':22.7}\n", + "print(x)\n", + "x = dict([('pork', 25.3),('beef', 33.8),('chicken', 22.7)])\n", + "print(x)\n", + "x = dict(pork=25.3, beef=33.8, chicken=22.7)\n", + "print(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**dict operations**" + ] + }, + { + "cell_type": "code", + "execution_count": 145, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'pork': 25.3, 'beef': 33.8, 'chicken': 22.7, 'shrimp': 38.2}\n", + "{'pork': 25.3, 'beef': 33.8, 'chicken': 22.7}\n", + "3\n", + "{}\n" + ] + } + ], + "source": [ + "x['shrimp'] = 38.2 # add or update\n", + "print(x)\n", + "\n", + "# delete an item\n", + "del(x['shrimp'])\n", + "print(x)\n", + "\n", + "# get length of dict x\n", + "print(len(x))\n", + "\n", + "# delete all items from dict x\n", + "x.clear()\n", + "print(x)\n", + "\n", + "# delete dict x\n", + "del(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**accessing keys and values in a dict**" + ] + }, + { + "cell_type": "code", + "execution_count": 146, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dict_keys(['pork', 'beef', 'chicken'])\n", + "dict_values([25.3, 33.8, 22.7])\n", + "dict_items([('pork', 25.3), ('beef', 33.8), ('chicken', 22.7)])\n", + "True\n", + "False\n" + ] + } + ], + "source": [ + "y = {'pork':25.3, 'beef':33.8, 'chicken':22.7}\n", + "print(y.keys())\n", + "print(y.values())\n", + "print(y.items()) # key-value pairs\n", + "\n", + "# check membership in y_keys (only looks in keys, not values)\n", + "print('beef' in y)\n", + "\n", + "# check membership in y_values\n", + "print('clams' in y.values())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**iterating a dict - note, items are in random order**" + ] + }, + { + "cell_type": "code", + "execution_count": 147, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "pork 25.3\n", + "beef 33.8\n", + "chicken 22.7\n", + "pork 25.3\n", + "beef 33.8\n", + "chicken 22.7\n" + ] + } + ], + "source": [ + "for key in y:\n", + " print(key, y[key])\n", + " \n", + "for k, v in y.items():\n", + " print(k, v)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Intro to Python Data Structures/Some Basic Terminologies in Python Data Structure b/Intro to Python Data Structures/Some Basic Terminologies in Python Data Structure new file mode 100644 index 00000000..754c07a5 --- /dev/null +++ b/Intro to Python Data Structures/Some Basic Terminologies in Python Data Structure @@ -0,0 +1,31 @@ +##Data Structure Overview +Data structures are fundamental concepts of computer science which helps is writing efficient programs in any language. Python is a high-level, interpreted, interactive and object-oriented scripting language using which we can study the fundamentals of data structure in a simpler way as compared to other programming languages. + +In this chapter we are going to study a short overview of some frequently used data structures in general and how they are related to some specific python data types. There are also some data structures specific to python which is listed as another category. + +##General Data Structures +The various data structures in computer science are divided broadly into two categories shown below. We will discuss about each of the below data structures in detail in subsequent chapters. + +#Liner Data Structures +These are the data structures which store the data elements in a sequential manner. + +Array: It is a sequential arrangement of data elements paired with the index of the data element. +Linked List: Each data element contains a link to another element along with the data present in it. +Stack: It is a data structure which follows only to specific order of operation. LIFO(last in First Out) or FILO(First in Last Out). +Queue: It is similar to Stack but the order of operation is only FIFO(First In First Out). +Matrix: It is two dimensional data structure in which the data element is referred by a pair of indices. + +#Non-Liner Data Structures +These are the data structures in which there is no sequential linking of data elements. Any pair or group of data elements can be linked to each other and can be accessed without a strict sequence. + +Binary Tree: It is a data structure where each data element can be connected to maximum two other data elements and it starts with a root node. +Heap: It is a special case of Tree data structure where the data in the parent node is either strictly greater than/ equal to the child nodes or strictly less than it’s child nodes. +Hash Table: It is a data structure which is made of arrays associated with each other using a hash function. It retrieves values using keys rather than index from a data element. +Graph: .It is an arrangement of vertices and nodes where some of the nodes are connected to each other through links. + +#Python Specific Data Structures +These data structures are specific to python language and they give greater flexibility in storing different types of data and faster processing in python environment. + +List: It is similar to array with the exception that the data elements can be of different data types. You can have both numeric and string data in a python list. +Tuple: Tuples are similar to lists but they are immutable which means the values in a tuple cannot be modified they can only be read. +Dictionary: The dictionary contains Key-value pairs as its data elements. diff --git a/Iris Dataset/Iris_Dataset.ipynb b/Iris Dataset/Iris_Dataset.ipynb new file mode 100644 index 00000000..398f454e --- /dev/null +++ b/Iris Dataset/Iris_Dataset.ipynb @@ -0,0 +1,1174 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Data Science\n", + "### Exploring the Iris Dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Load Data\n", + "Load the data from CSV file into a Pandas dataframe, and print the top few rows." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idsepal_lengthsepal_widthpetal_lengthpetal_widthspecies
005.13.51.40.2Iris-setosa
114.93.01.40.2Iris-setosa
224.73.21.30.2Iris-setosa
334.63.11.50.2Iris-setosa
445.03.61.40.2Iris-setosa
\n", + "
" + ], + "text/plain": [ + " id sepal_length sepal_width petal_length petal_width species\n", + "0 0 5.1 3.5 1.4 0.2 Iris-setosa\n", + "1 1 4.9 3.0 1.4 0.2 Iris-setosa\n", + "2 2 4.7 3.2 1.3 0.2 Iris-setosa\n", + "3 3 4.6 3.1 1.5 0.2 Iris-setosa\n", + "4 4 5.0 3.6 1.4 0.2 Iris-setosa" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = pd.read_csv('iris.data')\n", + "data.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Customize columns\n", + "Drop the redundant id column, and rename Attribute columns to integers. Save column names for use later." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
0123species
05.13.51.40.2Iris-setosa
507.03.24.71.4Iris-versicolor
1006.33.36.02.5Iris-virginica
\n", + "
" + ], + "text/plain": [ + " 0 1 2 3 species\n", + "0 5.1 3.5 1.4 0.2 Iris-setosa\n", + "50 7.0 3.2 4.7 1.4 Iris-versicolor\n", + "100 6.3 3.3 6.0 2.5 Iris-virginica" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = data.drop('id', 1)\n", + "cols = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']\n", + "data.rename(columns = {cols[0]:0, cols[1]:1, cols[2]:2, cols[3]:3}, inplace=True)\n", + "data.loc[::50]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Statistical Overview\n", + "Show shape of dataframe and statistical overview of attribute columns." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(150, 5)\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
0123
count150.000000150.000000150.000000150.000000
mean5.8433333.0540003.7586671.198667
std0.8280660.4335941.7644200.763161
min4.3000002.0000001.0000000.100000
25%5.1000002.8000001.6000000.300000
50%5.8000003.0000004.3500001.300000
75%6.4000003.3000005.1000001.800000
max7.9000004.4000006.9000002.500000
\n", + "
" + ], + "text/plain": [ + " 0 1 2 3\n", + "count 150.000000 150.000000 150.000000 150.000000\n", + "mean 5.843333 3.054000 3.758667 1.198667\n", + "std 0.828066 0.433594 1.764420 0.763161\n", + "min 4.300000 2.000000 1.000000 0.100000\n", + "25% 5.100000 2.800000 1.600000 0.300000\n", + "50% 5.800000 3.000000 4.350000 1.300000\n", + "75% 6.400000 3.300000 5.100000 1.800000\n", + "max 7.900000 4.400000 6.900000 2.500000" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(data.shape)\n", + "data.describe()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Iris-virginica 50\n", + "Iris-setosa 50\n", + "Iris-versicolor 50\n", + "Name: species, dtype: int64" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# same as data['species'].value_counts()\n", + "data.species.value_counts()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Histograms\n", + "Histograms are useful for showing how the data is distributed. They're ridiculously easy to use, but can only show two axes." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([ 9., 23., 14., 27., 16., 26., 18., 6., 5., 6.]),\n", + " array([4.3 , 4.66, 5.02, 5.38, 5.74, 6.1 , 6.46, 6.82, 7.18, 7.54, 7.9 ]),\n", + " )" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.hist(data[0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we give 4 columns of data to the Histogram maker, and it automatically color codes them." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([[ 0., 0., 0., 0., 0., 11., 48., 49., 31., 11.],\n", + " [ 0., 0., 11., 97., 38., 4., 0., 0., 0., 0.],\n", + " [ 0., 44., 6., 1., 10., 34., 30., 20., 5., 0.],\n", + " [50., 52., 45., 3., 0., 0., 0., 0., 0., 0.]]),\n", + " array([0.1 , 0.88, 1.66, 2.44, 3.22, 4. , 4.78, 5.56, 6.34, 7.12, 7.9 ]),\n", + " )" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.hist([data[0], data[1], data[2], data[3]])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To add a Legend we need to add labels to the Histogram builder as a list of column names, and call the legend function." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXcAAAD4CAYAAAAXUaZHAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+j8jraAAAah0lEQVR4nO3deXCV9dn/8fclIEFFRIgUCRpQBEyCIQZZAmlcUHyCa1N/ZbAENypuqB0FrS1onY62jGtRJ27BecCKUUalalEfGcCiECAOS7BukQYQAwqIkLJ4/f7IIU0wgZwlOYebz2uG8Zx7vTjIh2++931fx9wdEREJliPiXYCIiMSewl1EJIAU7iIiAaRwFxEJIIW7iEgAtY53AQCdO3f21NTUeJchInJIWbp06SZ3T25o3UHD3cyeA0YC37h7emjZ8cBLQCpQAVzh7t+ZmQGPAv8D7ADGuvuyg50jNTWV0tLSpv1uREQEADP7qrF1TZmWKQZG7LdsEvCeu/cC3gu9B7gQ6BX6NQ54MtxiRUQkegcNd3efD3y73+JLgOmh19OBS+ssf8FrfAgcZ2ZdY1WsiIg0TaQXVLu4+4bQ66+BLqHX3YB/19muMrTsJ8xsnJmVmllpVVVVhGWIiEhDor6g6u5uZmH3MHD3IqAIIDs7Wz0QRBLM7t27qayspLq6Ot6lHPaSkpJISUmhTZs2Td4n0nDfaGZd3X1DaNrlm9DydUD3OtulhJaJyCGmsrKS9u3bk5qaSs29EhIP7s7mzZuprKykR48eTd4v0mmZ14HC0OtC4LU6y8dYjUHA1jrTNyJyCKmurqZTp04K9jgzMzp16hT2T1BNuRXyRSAP6GxmlcBk4AFglpldA3wFXBHa/E1qboP8jJpbIa8KqxoRSSgK9sQQyZ/DQcPd3Uc1surcBrZ14MawqxARkZhKiCdURSTxpU76e0yPV/FAfkyPJ/Wpt4zE1pQODf8SSTDz5s1j5MiRja4vLi7mpptuivl5i4uLWb9+fe371NRUNm3aFPPzKNxFRFrQ/uHeXBTuIpKwfvjhB/Lz8znjjDNIT0/npZdeYunSpfz85z/nzDPP5IILLmDDhpob8vLy8pgwYQKZmZmkp6ezePFiABYvXszgwYPp378/Q4YM4ZNPPgm7jqqqKn7xi18wYMAABgwYwAcffADAlClTuPrqq8nLy6Nnz5489thjtfv88Y9/pHfv3gwdOpRRo0YxdepUSkpKKC0tZfTo0WRmZrJz504AHn/8cbKyssjIyGDNmjXRfmyAwl1EEtjbb7/NiSeeyMcff8zKlSsZMWIEN998MyUlJSxdupSrr76a3/3ud7Xb79ixg7KyMp544gmuvvpqAPr06cOCBQtYvnw59913H3fffXfYdUyYMIHbbruNJUuW8Morr3DttdfWrluzZg3/+Mc/WLx4Mffeey+7d++u3e7jjz/mrbfeqm2MWFBQQHZ2NjNmzKCsrIx27doB0LlzZ5YtW8b48eOZOnVqNB9ZLV1QFZGElZGRwW9/+1smTpzIyJEj6dixIytXrmT48OEA7N27l65d/9u+atSompv7cnNz2bZtG1u2bOH777+nsLCQTz/9FDNj9+7dYdfx7rvvsnr16tr327ZtY/v27QDk5+fTtm1b2rZtywknnMDGjRv54IMPuOSSS0hKSiIpKYmLLrrogMe//PLLATjzzDN59dVXw66vIQp3EUlYp512GsuWLePNN9/knnvu4ZxzziEtLY1FixY1uP3+94ObGb///e85++yzmT17NhUVFeTl5YVdx48//siHH35IUlLST9a1bdu29nWrVq3Ys2dP2Mffd4xI92+Iwl1EmiQety6uX7+e448/niuvvJLjjjuOJ554gqqqKhYtWsTgwYPZvXs3//rXv0hLSwPgpZde4uyzz2bhwoV06NCBDh06sHXrVrp1q+lfWFxcHFEd559/Po8//jh33HEHAGVlZWRmZja6fU5ODr/5zW+466672LNnD3PmzGHcuHEAtG/fnu+//z6iOsKhcBeRhLVixQruuOMOjjjiCNq0acOTTz5J69atueWWW9i6dSt79uzh1ltvrQ33pKQk+vfvz+7du3nuuecAuPPOOyksLOT+++8nPz+yf6Aee+wxbrzxRvr168eePXvIzc3lqaeeanT7AQMGcPHFF9OvXz+6dOlCRkYGHTrU3BI8duxYrr/+etq1a9foTyCxYDUPlcZXdna265uYAqKxe9qnbG3ZOiRq5eXl9O3bN95lNFleXh5Tp04lOzs73qUAsH37do455hh27NhBbm4uRUVFZGVlRXy8hv48zGypuzf4G9bIXUSkGYwbN47Vq1dTXV1NYWFhVMEeCYW7iATCvHnzItrv+eef59FHH623LCcn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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.hist([data[0], data[1], data[2], data[3]], label=[cols[0],cols[1],cols[2],cols[3]])\n", + "plt.legend()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or we can make 4 separate calls to the Histogram builder and get 4 overlapping plots." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([41., 8., 1., 7., 8., 33., 6., 23., 9., 14.]),\n", + " array([0.1 , 0.34, 0.58, 0.82, 1.06, 1.3 , 1.54, 1.78, 2.02, 2.26, 2.5 ]),\n", + " )" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.hist(data[0])\n", + "plt.hist(data[1]) \n", + "plt.hist(data[2])\n", + "plt.hist(data[3])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use alpha to control the opacity of plots. alpha of 1 is opague. alpha of 0 is transparent." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([41., 8., 1., 7., 8., 33., 6., 23., 9., 14.]),\n", + " array([0.1 , 0.34, 0.58, 0.82, 1.06, 1.3 , 1.54, 1.78, 2.02, 2.26, 2.5 ]),\n", + " )" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.hist(data[0])\n", + "plt.hist(data[1], alpha=1) \n", + "plt.hist(data[2], alpha=0.6)\n", + "plt.hist(data[3], alpha=0.5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also plot the 4 columns on separate subplots to make it more readable. This is very readable, but beware that each plot automatically scales its axes to the data." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(2, 2, figsize=(8, 4))\n", + "ax[0, 0].hist(data[0])\n", + "ax[0, 1].hist(data[1])\n", + "ax[1, 0].hist(data[2])\n", + "ax[1, 1].hist(data[3])\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding titles to the previous plot makes it more readable." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(2, 2, figsize=(8, 6))\n", + "ax[0, 0].hist(data[0])\n", + "ax[0, 1].hist(data[1])\n", + "ax[1, 0].hist(data[2])\n", + "ax[1, 1].hist(data[3])\n", + "ax[0, 0].set_title(cols[0])\n", + "ax[0, 1].set_title(cols[1])\n", + "ax[1, 0].set_title(cols[2])\n", + "ax[1, 1].set_title(cols[3])\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Scatter Plots\n", + "These are probably more useful for this dataset because they can show clusters by species. The most basic scatter plot does not distinguish species." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.scatter(\n", + " data[0], \n", + " data[1],)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding color coding by species allows us to see clustering for 2 attributes for each species. Here setosa is secluded, but virginica and versicolor overlap." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "colors = {'Iris-setosa':'red', 'Iris-virginica':'blue', 'Iris-versicolor':'green'}\n", + "plt.scatter(\n", + " data[2], \n", + " data[3], \n", + " c=data['species'].map(colors))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Adding labels to the x and y axes is useful, but we can see the data for virginica and versicolor still overlap. If we could find 1 attribute where there's no overlap for these 2 species then we could use those to definitively distinguish them. But unfortunately all 4 attributes have some overlap." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0, 0.5, 'petal_length')" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.scatter(\n", + " data[0], \n", + " data[2], \n", + " c=data['species'].map(colors))\n", + "plt.xlabel(cols[0])\n", + "plt.ylabel(cols[2])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we add a title to the plot, and show attributes 1 and 3. " + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 1.0, 'Iris Data Scatter Plot')" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.scatter(\n", + " data[1], \n", + " data[3], \n", + " c=data['species'].map(colors))\n", + "plt.xlabel(cols[1])\n", + "plt.ylabel(cols[3])\n", + "plt.title('Iris Data Scatter Plot')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Correlation\n", + "We can see the correlation between attributes. A correlation close to 1 helps us distinguish between species. Low correlation doesn't help us." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
0123
01.000000-0.1093690.8717540.817954
1-0.1093691.000000-0.420516-0.356544
20.871754-0.4205161.0000000.962757
30.817954-0.3565440.9627571.000000
\n", + "
" + ], + "text/plain": [ + " 0 1 2 3\n", + "0 1.000000 -0.109369 0.871754 0.817954\n", + "1 -0.109369 1.000000 -0.420516 -0.356544\n", + "2 0.871754 -0.420516 1.000000 0.962757\n", + "3 0.817954 -0.356544 0.962757 1.000000" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data.corr()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Box and Whisker Plots\n", + "Box plots show the distribution of data over an attribute by showing the 25th, 50th (median) and 75th percentiles. Again, the simplest plots are not very useful, but when we add labels and color coding the plots are revealing." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'whiskers': [,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ],\n", + " 'caps': [,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ,\n", + " ],\n", + " 'boxes': [,\n", + " ,\n", + " ,\n", + " ],\n", + " 'medians': [,\n", + " ,\n", + " ,\n", + " ],\n", + " 'fliers': [,\n", + " ,\n", + " ,\n", + " ],\n", + " 'means': []}" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.boxplot([data[0], data[1], data[2], data[3]])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This shows a boxplot for one attribute, sorted by species. For this attribute we can see a big overlap between the 3 species, so it's not very useful for distinguishing. An iris with 5.5 or 6.0 for this attribute could be any of the 3 species." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "data.boxplot(column=[0], by=['species'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It's tricky to do subplots, but worth it. We can see setosa has smaller petals than the other 2 species. And versicolor has, on average, smaller sepals and smaller petals than virginica; but there is some overlap." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 1.0, 'petal_width')" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(2, 2, figsize=(8, 6))\n", + "A = [data[0][data.species == 'Iris-setosa'], data[0][data.species == 'Iris-virginica'], data[0][data.species == 'Iris-versicolor']]\n", + "B = [data[1][data.species == 'Iris-setosa'], data[1][data.species == 'Iris-virginica'], data[1][data.species == 'Iris-versicolor']]\n", + "C = [data[2][data.species == 'Iris-setosa'], data[2][data.species == 'Iris-virginica'], data[2][data.species == 'Iris-versicolor']]\n", + "D = [data[3][data.species == 'Iris-setosa'], data[3][data.species == 'Iris-virginica'], data[3][data.species == 'Iris-versicolor']]\n", + "\n", + "ax[0, 0].boxplot(A, widths = 0.7)\n", + "ax[0, 0].set_title(cols[0])\n", + "ax[0, 1].boxplot(B, widths = 0.7)\n", + "ax[0, 1].set_title(cols[1])\n", + "ax[1, 0].boxplot(C, widths = 0.7)\n", + "ax[1, 0].set_title(cols[2])\n", + "ax[1, 1].boxplot(D, widths = 0.7)\n", + "ax[1, 1].set_title(cols[3])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This plot does an awsome job of showing distributions of all 4 attributes for all 3 species. 12 box plots in 1 graph! The color coding makes it more readable. " + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/ipykernel_launcher.py:21: MatplotlibDeprecationWarning: Adding an axes using the same arguments as a previous axes currently reuses the earlier instance. In a future version, a new instance will always be created and returned. Meanwhile, this warning can be suppressed, and the future behavior ensured, by passing a unique label to each axes instance.\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "def set_color(bp):\n", + " plt.setp(bp['boxes'][0], color='blue')\n", + " plt.setp(bp['boxes'][1], color='red')\n", + " plt.setp(bp['boxes'][2], color='green')\n", + "\n", + "A = [data[0][data.species == 'Iris-setosa'], data[0][data.species == 'Iris-virginica'], data[0][data.species == 'Iris-versicolor']]\n", + "B = [data[1][data.species == 'Iris-setosa'], data[1][data.species == 'Iris-virginica'], data[1][data.species == 'Iris-versicolor']]\n", + "C = [data[2][data.species == 'Iris-setosa'], data[2][data.species == 'Iris-virginica'], data[2][data.species == 'Iris-versicolor']]\n", + "D = [data[3][data.species == 'Iris-setosa'], data[3][data.species == 'Iris-virginica'], data[3][data.species == 'Iris-versicolor']]\n", + "\n", + "# add this to remove outlier symbols: 0, '',\n", + "bp = plt.boxplot(A, 0, '', positions = [1, 2, 3], widths = 0.7)\n", + "set_color(bp)\n", + "bp = plt.boxplot(B, 0, '', positions = [5, 6, 7], widths = 0.7)\n", + "set_color(bp)\n", + "bp = plt.boxplot(C, 0, '', positions = [9, 10, 11], widths = 0.7)\n", + "set_color(bp)\n", + "bp = plt.boxplot(D, 0, '', positions = [13, 14, 15], widths = 0.7)\n", + "set_color(bp)\n", + "\n", + "ax = plt.axes()\n", + "ax.set_xticks([2, 6, 10, 14])\n", + "ax.set_xticklabels(cols)\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Iris Dataset/KNN-IrisData.ipynb b/Iris Dataset/KNN-IrisData.ipynb new file mode 100644 index 00000000..d49be354 --- /dev/null +++ b/Iris Dataset/KNN-IrisData.ipynb @@ -0,0 +1,629 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Classification \n", + "predict which group a new target object belongs to by comparing it to identified objects. The identified, or labeled objects are called the training set." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## KNN - K-Nearest Neighbors\n", + "Find the k nearest objects to the target object using some distance metric. Then these k nearest neighbors get to vote on the identity of the target object. \n", + "For example, if k=5, we find the 5 nearest objects in our training set. If three of them are apples, one is a pear and one is an orange then we predict our target object is an apple. " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idsepal_lengthsepal_widthpetal_lengthpetal_widthspecies
005.13.51.40.2Iris-setosa
114.93.01.40.2Iris-setosa
224.73.21.30.2Iris-setosa
334.63.11.50.2Iris-setosa
445.03.61.40.2Iris-setosa
\n", + "
" + ], + "text/plain": [ + " id sepal_length sepal_width petal_length petal_width species\n", + "0 0 5.1 3.5 1.4 0.2 Iris-setosa\n", + "1 1 4.9 3.0 1.4 0.2 Iris-setosa\n", + "2 2 4.7 3.2 1.3 0.2 Iris-setosa\n", + "3 3 4.6 3.1 1.5 0.2 Iris-setosa\n", + "4 4 5.0 3.6 1.4 0.2 Iris-setosa" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train = pd.read_csv('iris.data')\n", + "train.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Rename columns of training set, and add a column for distance." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
0123speciesdistance
05.13.51.40.2Iris-setosa9999
14.93.01.40.2Iris-setosa9999
24.73.21.30.2Iris-setosa9999
34.63.11.50.2Iris-setosa9999
45.03.61.40.2Iris-setosa9999
\n", + "
" + ], + "text/plain": [ + " 0 1 2 3 species distance\n", + "0 5.1 3.5 1.4 0.2 Iris-setosa 9999\n", + "1 4.9 3.0 1.4 0.2 Iris-setosa 9999\n", + "2 4.7 3.2 1.3 0.2 Iris-setosa 9999\n", + "3 4.6 3.1 1.5 0.2 Iris-setosa 9999\n", + "4 5.0 3.6 1.4 0.2 Iris-setosa 9999" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train = train.drop('id', 1)\n", + "cols = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']\n", + "train.rename(columns = {cols[0]:0, cols[1]:1, cols[2]:2, cols[3]:3}, inplace=True)\n", + "train['distance'] = 9999\n", + "train.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create an unidentified Target instance, then we will try to predict its species using knn." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 7.0\n", + "1 3.1\n", + "2 5.6\n", + "3 1.9\n", + "dtype: float64" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "target = pd.Series([7.0, 3.1, 5.6, 1.9])\n", + "target" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Distance\n", + "There are a variety of ways to measure [distance](https://towardsdatascience.com/9-distance-measures-in-data-science-918109d069fa). If there are many attributes, we may use a subset of the attributes to compare objects. \n", + "We'll use Euclidean distance, similar to Pythagorean Theorem but scaled to more attributes. \n", + "We compute the distance of every training instance from the target." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
0123speciesdistance
05.13.51.40.2Iris-setosa4.929503
105.43.71.50.2Iris-setosa4.756049
205.43.41.70.2Iris-setosa4.555217
304.83.11.60.2Iris-setosa4.871345
405.03.51.30.3Iris-setosa5.020956
507.03.24.71.4Iris-versicolor1.034408
605.02.03.51.0Iris-versicolor3.229551
705.93.24.81.8Iris-versicolor1.367479
805.52.43.81.1Iris-versicolor2.572936
905.52.64.41.2Iris-versicolor2.104757
1006.33.36.02.5Iris-virginica1.024695
1106.53.25.12.0Iris-virginica0.721110
1206.93.25.72.3Iris-virginica0.435890
1307.42.86.11.9Iris-virginica0.707107
1406.73.15.62.4Iris-virginica0.583095
\n", + "
" + ], + "text/plain": [ + " 0 1 2 3 species distance\n", + "0 5.1 3.5 1.4 0.2 Iris-setosa 4.929503\n", + "10 5.4 3.7 1.5 0.2 Iris-setosa 4.756049\n", + "20 5.4 3.4 1.7 0.2 Iris-setosa 4.555217\n", + "30 4.8 3.1 1.6 0.2 Iris-setosa 4.871345\n", + "40 5.0 3.5 1.3 0.3 Iris-setosa 5.020956\n", + "50 7.0 3.2 4.7 1.4 Iris-versicolor 1.034408\n", + "60 5.0 2.0 3.5 1.0 Iris-versicolor 3.229551\n", + "70 5.9 3.2 4.8 1.8 Iris-versicolor 1.367479\n", + "80 5.5 2.4 3.8 1.1 Iris-versicolor 2.572936\n", + "90 5.5 2.6 4.4 1.2 Iris-versicolor 2.104757\n", + "100 6.3 3.3 6.0 2.5 Iris-virginica 1.024695\n", + "110 6.5 3.2 5.1 2.0 Iris-virginica 0.721110\n", + "120 6.9 3.2 5.7 2.3 Iris-virginica 0.435890\n", + "130 7.4 2.8 6.1 1.9 Iris-virginica 0.707107\n", + "140 6.7 3.1 5.6 2.4 Iris-virginica 0.583095" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train['distance'] = ((train.loc[:,0]-target[0])**2 + (train.loc[:,1]-target[1])**2 + (train.loc[:,2]-target[2])**2 + (train.loc[:,3]-target[3])**2) ** 0.5\n", + "train.loc[::10]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We sort the training records by distance, and add the species of the (k=7) items nearest to the target to a list." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['Iris-virginica',\n", + " 'Iris-virginica',\n", + " 'Iris-virginica',\n", + " 'Iris-virginica',\n", + " 'Iris-virginica',\n", + " 'Iris-virginica',\n", + " 'Iris-virginica']" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "k = 7\n", + "train = train.sort_values('distance', ascending=True)\n", + "knn = list(train.head(k).species)\n", + "knn" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We use mode to get the most popular of the knn list. In this example the whole knn list is Iris-virginica, so our prediction is obvious. But sometimes the list of nearest neighbors will be a variety, and the mode tells us our prediction." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iris-virginica\n" + ] + } + ], + "source": [ + "from statistics import mode\n", + "print(mode(knn))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To check our prediction, we plot the training set on a scatter plot, then plot our target. Here we can see our target is surrounded by Iris-virginica instances, so our prediction is probably correct." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 1.0, 'Iris Data Scatter Plot')" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "colors = {'Iris-setosa':'red', 'Iris-virginica':'blue', 'Iris-versicolor':'green'}\n", + "plt.scatter(\n", + " train[2], \n", + " train[3], \n", + " c=train['species'].map(colors))\n", + "plt.scatter(target[2], target[3], c='orange')\n", + "plt.xlabel(cols[2])\n", + "plt.ylabel(cols[3])\n", + "plt.title('Iris Data Scatter Plot')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Iris Dataset/iris.data b/Iris Dataset/iris.data new file mode 100644 index 00000000..835f8b44 --- /dev/null +++ b/Iris Dataset/iris.data @@ -0,0 +1,151 @@ +id,sepal_length,sepal_width,petal_length,petal_width,species +0,5.1,3.5,1.4,0.2,Iris-setosa +1,4.9,3.0,1.4,0.2,Iris-setosa +2,4.7,3.2,1.3,0.2,Iris-setosa +3,4.6,3.1,1.5,0.2,Iris-setosa +4,5.0,3.6,1.4,0.2,Iris-setosa +5,5.4,3.9,1.7,0.4,Iris-setosa +6,4.6,3.4,1.4,0.3,Iris-setosa +7,5.0,3.4,1.5,0.2,Iris-setosa +8,4.4,2.9,1.4,0.2,Iris-setosa +9,4.9,3.1,1.5,0.1,Iris-setosa +10,5.4,3.7,1.5,0.2,Iris-setosa +11,4.8,3.4,1.6,0.2,Iris-setosa +12,4.8,3.0,1.4,0.1,Iris-setosa +13,4.3,3.0,1.1,0.1,Iris-setosa +14,5.8,4.0,1.2,0.2,Iris-setosa +15,5.7,4.4,1.5,0.4,Iris-setosa +16,5.4,3.9,1.3,0.4,Iris-setosa +17,5.1,3.5,1.4,0.3,Iris-setosa +18,5.7,3.8,1.7,0.3,Iris-setosa +19,5.1,3.8,1.5,0.3,Iris-setosa +20,5.4,3.4,1.7,0.2,Iris-setosa +21,5.1,3.7,1.5,0.4,Iris-setosa +22,4.6,3.6,1.0,0.2,Iris-setosa +23,5.1,3.3,1.7,0.5,Iris-setosa +24,4.8,3.4,1.9,0.2,Iris-setosa +25,5.0,3.0,1.6,0.2,Iris-setosa +26,5.0,3.4,1.6,0.4,Iris-setosa +27,5.2,3.5,1.5,0.2,Iris-setosa +28,5.2,3.4,1.4,0.2,Iris-setosa +29,4.7,3.2,1.6,0.2,Iris-setosa +30,4.8,3.1,1.6,0.2,Iris-setosa +31,5.4,3.4,1.5,0.4,Iris-setosa +32,5.2,4.1,1.5,0.1,Iris-setosa +33,5.5,4.2,1.4,0.2,Iris-setosa +34,4.9,3.1,1.5,0.1,Iris-setosa +35,5.0,3.2,1.2,0.2,Iris-setosa +36,5.5,3.5,1.3,0.2,Iris-setosa +37,4.9,3.1,1.5,0.1,Iris-setosa +38,4.4,3.0,1.3,0.2,Iris-setosa +39,5.1,3.4,1.5,0.2,Iris-setosa +40,5.0,3.5,1.3,0.3,Iris-setosa +41,4.5,2.3,1.3,0.3,Iris-setosa +42,4.4,3.2,1.3,0.2,Iris-setosa +43,5.0,3.5,1.6,0.6,Iris-setosa +44,5.1,3.8,1.9,0.4,Iris-setosa +45,4.8,3.0,1.4,0.3,Iris-setosa +46,5.1,3.8,1.6,0.2,Iris-setosa +47,4.6,3.2,1.4,0.2,Iris-setosa +48,5.3,3.7,1.5,0.2,Iris-setosa +49,5.0,3.3,1.4,0.2,Iris-setosa +50,7.0,3.2,4.7,1.4,Iris-versicolor +51,6.4,3.2,4.5,1.5,Iris-versicolor +52,6.9,3.1,4.9,1.5,Iris-versicolor +53,5.5,2.3,4.0,1.3,Iris-versicolor +54,6.5,2.8,4.6,1.5,Iris-versicolor +55,5.7,2.8,4.5,1.3,Iris-versicolor +56,6.3,3.3,4.7,1.6,Iris-versicolor +57,4.9,2.4,3.3,1.0,Iris-versicolor +58,6.6,2.9,4.6,1.3,Iris-versicolor +59,5.2,2.7,3.9,1.4,Iris-versicolor +60,5.0,2.0,3.5,1.0,Iris-versicolor +61,5.9,3.0,4.2,1.5,Iris-versicolor +62,6.0,2.2,4.0,1.0,Iris-versicolor +63,6.1,2.9,4.7,1.4,Iris-versicolor +64,5.6,2.9,3.6,1.3,Iris-versicolor +65,6.7,3.1,4.4,1.4,Iris-versicolor +66,5.6,3.0,4.5,1.5,Iris-versicolor +67,5.8,2.7,4.1,1.0,Iris-versicolor +68,6.2,2.2,4.5,1.5,Iris-versicolor +69,5.6,2.5,3.9,1.1,Iris-versicolor +70,5.9,3.2,4.8,1.8,Iris-versicolor +71,6.1,2.8,4.0,1.3,Iris-versicolor +72,6.3,2.5,4.9,1.5,Iris-versicolor +73,6.1,2.8,4.7,1.2,Iris-versicolor +74,6.4,2.9,4.3,1.3,Iris-versicolor +75,6.6,3.0,4.4,1.4,Iris-versicolor +76,6.8,2.8,4.8,1.4,Iris-versicolor +77,6.7,3.0,5.0,1.7,Iris-versicolor +78,6.0,2.9,4.5,1.5,Iris-versicolor +79,5.7,2.6,3.5,1.0,Iris-versicolor +80,5.5,2.4,3.8,1.1,Iris-versicolor +81,5.5,2.4,3.7,1.0,Iris-versicolor +82,5.8,2.7,3.9,1.2,Iris-versicolor +83,6.0,2.7,5.1,1.6,Iris-versicolor +84,5.4,3.0,4.5,1.5,Iris-versicolor +85,6.0,3.4,4.5,1.6,Iris-versicolor +86,6.7,3.1,4.7,1.5,Iris-versicolor +87,6.3,2.3,4.4,1.3,Iris-versicolor +88,5.6,3.0,4.1,1.3,Iris-versicolor +89,5.5,2.5,4.0,1.3,Iris-versicolor +90,5.5,2.6,4.4,1.2,Iris-versicolor +91,6.1,3.0,4.6,1.4,Iris-versicolor +92,5.8,2.6,4.0,1.2,Iris-versicolor +93,5.0,2.3,3.3,1.0,Iris-versicolor +94,5.6,2.7,4.2,1.3,Iris-versicolor +95,5.7,3.0,4.2,1.2,Iris-versicolor +96,5.7,2.9,4.2,1.3,Iris-versicolor +97,6.2,2.9,4.3,1.3,Iris-versicolor +98,5.1,2.5,3.0,1.1,Iris-versicolor +99,5.7,2.8,4.1,1.3,Iris-versicolor +100,6.3,3.3,6.0,2.5,Iris-virginica +101,5.8,2.7,5.1,1.9,Iris-virginica +102,7.1,3.0,5.9,2.1,Iris-virginica +103,6.3,2.9,5.6,1.8,Iris-virginica +104,6.5,3.0,5.8,2.2,Iris-virginica +105,7.6,3.0,6.6,2.1,Iris-virginica +106,4.9,2.5,4.5,1.7,Iris-virginica +107,7.3,2.9,6.3,1.8,Iris-virginica +108,6.7,2.5,5.8,1.8,Iris-virginica +109,7.2,3.6,6.1,2.5,Iris-virginica +110,6.5,3.2,5.1,2.0,Iris-virginica +111,6.4,2.7,5.3,1.9,Iris-virginica +112,6.8,3.0,5.5,2.1,Iris-virginica +113,5.7,2.5,5.0,2.0,Iris-virginica +114,5.8,2.8,5.1,2.4,Iris-virginica +115,6.4,3.2,5.3,2.3,Iris-virginica +116,6.5,3.0,5.5,1.8,Iris-virginica +117,7.7,3.8,6.7,2.2,Iris-virginica +118,7.7,2.6,6.9,2.3,Iris-virginica +119,6.0,2.2,5.0,1.5,Iris-virginica +120,6.9,3.2,5.7,2.3,Iris-virginica +121,5.6,2.8,4.9,2.0,Iris-virginica +122,7.7,2.8,6.7,2.0,Iris-virginica +123,6.3,2.7,4.9,1.8,Iris-virginica +124,6.7,3.3,5.7,2.1,Iris-virginica +125,7.2,3.2,6.0,1.8,Iris-virginica +126,6.2,2.8,4.8,1.8,Iris-virginica +127,6.1,3.0,4.9,1.8,Iris-virginica +128,6.4,2.8,5.6,2.1,Iris-virginica +129,7.2,3.0,5.8,1.6,Iris-virginica +130,7.4,2.8,6.1,1.9,Iris-virginica +131,7.9,3.8,6.4,2.0,Iris-virginica +132,6.4,2.8,5.6,2.2,Iris-virginica +133,6.3,2.8,5.1,1.5,Iris-virginica +134,6.1,2.6,5.6,1.4,Iris-virginica +135,7.7,3.0,6.1,2.3,Iris-virginica +136,6.3,3.4,5.6,2.4,Iris-virginica +137,6.4,3.1,5.5,1.8,Iris-virginica +138,6.0,3.0,4.8,1.8,Iris-virginica +139,6.9,3.1,5.4,2.1,Iris-virginica +140,6.7,3.1,5.6,2.4,Iris-virginica +141,6.9,3.1,5.1,2.3,Iris-virginica +142,5.8,2.7,5.1,1.9,Iris-virginica +143,6.8,3.2,5.9,2.3,Iris-virginica +144,6.7,3.3,5.7,2.5,Iris-virginica +145,6.7,3.0,5.2,2.3,Iris-virginica +146,6.3,2.5,5.0,1.9,Iris-virginica +147,6.5,3.0,5.2,2.0,Iris-virginica +148,6.2,3.4,5.4,2.3,Iris-virginica +149,5.9,3.0,5.1,1.8,Iris-virginica diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..3322e0ac --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Joe James + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Lambda Functions/Python Lambda Functions.ipynb b/Lambda Functions/Python Lambda Functions.ipynb new file mode 100644 index 00000000..61c11f0c --- /dev/null +++ b/Lambda Functions/Python Lambda Functions.ipynb @@ -0,0 +1,364 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python Lambda Functions\n", + "Anonymous, single-use, or throw-away functions. \n", + "**lambda arguments : expression** \n", + "Here are some single-argument lambdas:" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "12\n" + ] + } + ], + "source": [ + "add5 = lambda x: x + 5\n", + "print(add5(7))" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "64\n" + ] + } + ], + "source": [ + "square = lambda x: x * x\n", + "print(square(8))" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4\n", + "3\n" + ] + } + ], + "source": [ + "get_tens = lambda p: int(p/10)%10\n", + "print(get_tens(749))\n", + "print(get_tens(836.21))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Lambdas as an argument in other functions** \n", + "One of the most popular uses for lambda functions is as an argument inside sort, or filter functions. \n", + "### Sorting a List of Tuples using Lambda" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('carrots', 1.1), ('peaches', 2.45), ('eggs', 5.25), ('honey', 9.7)]\n" + ] + } + ], + "source": [ + "list1 = [('eggs', 5.25), ('honey', 9.70), ('carrots', 1.10), ('peaches', 2.45)]\n", + "list1.sort(key = lambda x: x[1])\n", + "print(list1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Sorting a List of Dictionaries using Lambda" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[{'make': 'Tesla', 'model': 'X', 'year': 1999},\n", + " {'make': 'Mercedes', 'model': 'C350E', 'year': 2008},\n", + " {'make': 'Ford', 'model': 'Focus', 'year': 2013}]\n" + ] + } + ], + "source": [ + "import pprint as pp\n", + "list1 = [{'make':'Ford', 'model':'Focus', 'year':2013}, {'make':'Tesla', 'model':'X', 'year':1999}, {'make':'Mercedes', 'model':'C350E', 'year':2008}]\n", + "list2 = sorted(list1, key = lambda x: x['year'])\n", + "pp.pprint(list2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Filtering a List of Integers using Lambda" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2, 4, 6]\n" + ] + } + ], + "source": [ + "list1 = [1, 2, 3, 4, 5, 6]\n", + "list2 = list(filter(lambda x: x%2 == 0, list1))\n", + "print(list2)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 3, 5]\n" + ] + } + ], + "source": [ + "odds = lambda x: x%2 == 1\n", + "list1 = [1, 2, 3, 4, 5, 6]\n", + "list2 = list(filter(odds, list1))\n", + "print(list2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Lambda Function on a List using Map\n", + "Python's map function applies the lambda to every element in the list." + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 4, 9, 16, 25, 36]\n" + ] + } + ], + "source": [ + "list1 = [1, 2, 3, 4, 5, 6]\n", + "list2 = list(map(lambda x: x ** 2, list1))\n", + "print(list2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Lambda Conditionals\n", + "**lambda args: a if boolean_expression else b** " + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "starts_with_J = lambda x: True if x.startswith('J') else False\n", + "print(starts_with_J('Joey'))" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "and\n" + ] + } + ], + "source": [ + "wordb4 = lambda s, w: s.split()[s.split().index(w)-1] if w in s else None\n", + "sentence = 'Four score and seven years ago'\n", + "print(wordb4(sentence, 'seven'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Lambdas on DataTime Objects\n", + "You sometimes want to get just the year, month, date or time for comparision. \n", + "This would typically be most useful as a parameter in sort or filter functions." + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2019-03-07 19:36:58.442863\n", + "2019\n" + ] + } + ], + "source": [ + "import datetime\n", + "\n", + "now = datetime.datetime.now()\n", + "print(now)\n", + "year = lambda x: x.year\n", + "print(year(now))" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4096\n", + "125\n" + ] + } + ], + "source": [ + "def do_something(f, val):\n", + " return f(val)\n", + "\n", + "func = lambda x: x**3\n", + "print(func(16))\n", + "print(do_something(func, 5))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Extreme Lambdas\n", + "This is probably a stretch -- you shouldn't be trying to do this much with Lambdas. \n", + "Some things are better done in a regular function. But this shows what's possible with Lambdas." + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "True\n", + "False\n", + "False\n", + "True\n", + "-1\n", + "-21.67 \n" + ] + } + ], + "source": [ + "isnum = lambda q: q.replace('.','',1).isdigit()\n", + "print(isnum('25983'))\n", + "print(isnum('3.1415'))\n", + "print(isnum('T57'))\n", + "print(isnum('-16'))\n", + "\n", + "is_num = lambda r: isnum(r[1:]) if r[0]=='-' else isnum(r)\n", + "print(is_num('-16.4'))\n", + "\n", + "tonum = lambda s: float(s) if is_num(s) else -1\n", + "print(tonum('30y'))\n", + "print(tonum('-21.67'), type(tonum('-21.67')))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/LinkedLists/CircularLinkedList.py b/LinkedLists/CircularLinkedList.py new file mode 100644 index 00000000..48a5a9df --- /dev/null +++ b/LinkedLists/CircularLinkedList.py @@ -0,0 +1,116 @@ +class Node(object): + + def __init__ (self, d, n = None): + self.data = d + self.next_node = n + + def get_next (self): + return self.next_node + + def set_next (self, n): + self.next_node = n + + def get_data (self): + return self.data + + def set_data (self, d): + self.data = d + + def __str__(self): + return "Node value: " + str(self.data) + +class CircularLinkedList (object): + + def __init__ (self, r = None): + self.root = r + self.size = 0 + + def get_size (self): + return self.size + + def add (self, d): + if self.get_size() == 0: + self.root = Node(d) + self.root.set_next(self.root) + else: + new_node = Node (d, self.root.get_next()) + self.root.set_next(new_node) + self.size += 1 + + def remove (self, d): + this_node = self.root + prev_node = None + + while True: + if this_node.get_data() == d: # found + if prev_node is not None: + prev_node.set_next(this_node.get_next()) + else: + while this_node.get_next() != self.root: + this_node = this_node.get_next() + this_node.set_next(self.root.get_next()) + self.root = self.root.get_next() + self.size -= 1 + return True # data removed + elif this_node.get_next() == self.root: + return False # data not found + prev_node = this_node + this_node = this_node.get_next() + + def find (self, d): + this_node = self.root + while True: + if this_node.get_data() == d: + return d + elif this_node.get_next() == self.root: + return False + this_node = this_node.get_next() + + def print_list (self): + print ("Print List..........") + if self.root is None: + return + this_node = self.root + print (this_node) + while this_node.get_next() != self.root: + this_node = this_node.get_next() + print (this_node) + +def main(): + myList = CircularLinkedList() + myList.add(5) + myList.add(7) + myList.add(3) + myList.add(8) + myList.add(9) + print("Find 8", myList.find(8)) + print("Find 12", myList.find(12)) + + cur = myList.root + print (cur) + for i in range(8): + cur = cur.get_next(); + print (cur) + + print("size="+str(myList.get_size())) + myList.print_list() + myList.remove(8) + print("size="+str(myList.get_size())) + print("Remove 15", myList.remove(15)) + print("size="+str(myList.get_size())) + myList.remove(5) # delete root node + myList.print_list() + +main() + + + + + + + + + + + + diff --git a/DoublyLinkedList.py b/LinkedLists/DoublyLinkedList1.py similarity index 95% rename from DoublyLinkedList.py rename to LinkedLists/DoublyLinkedList1.py index 2fd60b81..c4a8d406 100644 --- a/DoublyLinkedList.py +++ b/LinkedLists/DoublyLinkedList1.py @@ -1,78 +1,78 @@ -class Node(object): - - def __init__ (self, d, n = None, p = None): - self.data = d - self.next_node = n - self.prev_node = p - - def get_next (self): - return self.next_node - - def set_next (self, n): - self.next_node = n - - def get_prev (self): - return self.prev_node - - def set_prev (self, p): - self.prev_node = p - - def get_data (self): - return self.data - - def set_data (self, d): - self.data = d - - -class LinkedList (object): - - def __init__(self, r = None): - self.root = r - self.size = 0 - - def get_size (self): - return self.size - - def add (self, d): - new_node = Node (d, self.root) - if self.root: - self.root.set_prev(new_node) - self.root = new_node - self.size += 1 - - def remove (self, d): - this_node = self.root - - while this_node: - if this_node.get_data() == d: - next = this_node.get_next() - prev = this_node.get_prev() - - if next: - next.set_prev(prev) - if prev: - prev.set_next(next) - else: - self.root = this_node - self.size -= 1 - return True # data removed - else: - this_node = this_node.get_next() - return False # data not found - - def find (self, d): - this_node = self.root - while this_node: - if this_node.get_data() == d: - return d - else: - this_node = this_node.get_next() - return None - -myList = LinkedList() -myList.add(5) -myList.add(8) -myList.add(12) -myList.remove(8) -print(myList.remove(12)) +class Node(object): + + def __init__ (self, d, n = None, p = None): + self.data = d + self.next_node = n + self.prev_node = p + + def get_next (self): + return self.next_node + + def set_next (self, n): + self.next_node = n + + def get_prev (self): + return self.prev_node + + def set_prev (self, p): + self.prev_node = p + + def get_data (self): + return self.data + + def set_data (self, d): + self.data = d + + +class LinkedList (object): + + def __init__(self, r = None): + self.root = r + self.size = 0 + + def get_size (self): + return self.size + + def add (self, d): + new_node = Node (d, self.root) + if self.root: + self.root.set_prev(new_node) + self.root = new_node + self.size += 1 + + def remove (self, d): + this_node = self.root + + while this_node: + if this_node.get_data() == d: + next = this_node.get_next() + prev = this_node.get_prev() + + if next: + next.set_prev(prev) + if prev: + prev.set_next(next) + else: + self.root = this_node + self.size -= 1 + return True # data removed + else: + this_node = this_node.get_next() + return False # data not found + + def find (self, d): + this_node = self.root + while this_node: + if this_node.get_data() == d: + return d + else: + this_node = this_node.get_next() + return None + +myList = LinkedList() +myList.add(5) +myList.add(8) +myList.add(12) +myList.remove(8) +print(myList.remove(12)) print(myList.find(5)) \ No newline at end of file diff --git a/LinkedLists/DoublyLinkedList2.py b/LinkedLists/DoublyLinkedList2.py new file mode 100644 index 00000000..84fa0202 --- /dev/null +++ b/LinkedLists/DoublyLinkedList2.py @@ -0,0 +1,113 @@ +class Node(object): + + def __init__ (self, d, n = None, p = None): + self.data = d + self.next_node = n + self.prev_node = p + + def get_next (self): + return self.next_node + + def set_next (self, n): + self.next_node = n + + def get_prev (self): + return self.prev_node + + def set_prev (self, p): + self.prev_node = p + + def get_data (self): + return self.data + + def set_data (self, d): + self.data = d + + def to_string (self): + return "Node value: " + str(self.data) + + def has_next (self): + if self.get_next() is None: + return False + return True + +class DoublyLinkedList (object): + + def __init__ (self, r = None): + self.root = r + self.last = r + self.size = 0 + + def get_size (self): + return self.size + + def add (self, d): + if self.size == 0: + self.root = Node(d) + self.last = self.root + else: + new_node = Node(d, self.root) + self.root.set_prev(new_node) + self.root = new_node + self.size += 1 + + def remove (self, d): + this_node = self.root + while this_node is not None: + if this_node.get_data() == d: + if this_node.get_prev() is not None: + if this_node.has_next(): # delete a middle node + this_node.get_prev().set_next(this_node.get_next()) + this_node.get_next().set_prev(this_node.get_prev()) + else: # delete last node + this_node.get_prev().set_next(None) + self.last = this_node.get_prev() + else: # delete root node + self.root = this_node.get_next() + this_node.get_next().set_prev(self.root) + self.size -= 1 + return True # data removed + else: + this_node = this_node.get_next() + return False # data not found + + def find (self, d): + this_node = self.root + while this_node is not None: + if this_node.get_data() == d: + return d + elif this_node.get_next() == self.root: + return False + else: + this_node = this_node.get_next() + + def print_list (self): + print ("Print List..........") + if self.root is None: + return + this_node = self.root + print (this_node.to_string()) + while this_node.has_next(): + this_node = this_node.get_next() + print (this_node.to_string()) + +def main(): + myList = DoublyLinkedList() + myList.add(5) + myList.add(9) + myList.add(3) + myList.add(8) + myList.add(9) + print("size="+str(myList.get_size())) + myList.print_list() + myList.remove(8) + print("size="+str(myList.get_size())) + print("Remove 15", myList.remove(15)) + myList.add(21) + myList.add(22) + myList.remove(5) + myList.print_list() + print("size="+str(myList.get_size())) + print(myList.last.get_prev().to_string()) + +main() \ No newline at end of file diff --git a/LinkedLists.py b/LinkedLists/LinkedList0.py similarity index 95% rename from LinkedLists.py rename to LinkedLists/LinkedList0.py index cb21684f..19e30946 100644 --- a/LinkedLists.py +++ b/LinkedLists/LinkedList0.py @@ -1,69 +1,69 @@ -class Node(object): - - def __init__ (self, d, n = None): - self.data = d - self.next_node = n - - def get_next (self): - return self.next_node - - def set_next (self, n): - self.next_node = n - - def get_data (self): - return self.data - - def set_data (self, d): - self.data = d - - -class LinkedList (object): - - def __init__(self, r = None): - self.root = r - self.size = 0 - - def get_size (self): - return self.size - - def add (self, d): - new_node = Node (d, self.root) - self.root = new_node - self.size += 1 - - def remove (self, d): - this_node = self.root - prev_node = None - - while this_node: - if this_node.get_data() == d: - if prev_node: - prev_node.set_next(this_node.get_next()) - else: - self.root = this_node.get_next() - self.size -= 1 - return True # data removed - else: - prev_node = this_node - this_node = this_node.get_next() - return False # data not found - - def find (self, d): - this_node = self.root - while this_node: - if this_node.get_data() == d: - return d - else: - this_node = this_node.get_next() - return None - -myList = LinkedList() -myList.add(5) -myList.add(8) -myList.add(12) -print("size="+str(myList.get_size())) -myList.remove(8) -print("size="+str(myList.get_size())) -print(myList.remove(12)) -print("size="+str(myList.get_size())) +class Node(object): + + def __init__ (self, d, n = None): + self.data = d + self.next_node = n + + def get_next (self): + return self.next_node + + def set_next (self, n): + self.next_node = n + + def get_data (self): + return self.data + + def set_data (self, d): + self.data = d + + +class LinkedList (object): + + def __init__(self, r = None): + self.root = r + self.size = 0 + + def get_size (self): + return self.size + + def add (self, d): + new_node = Node (d, self.root) + self.root = new_node + self.size += 1 + + def remove (self, d): + this_node = self.root + prev_node = None + + while this_node: + if this_node.get_data() == d: + if prev_node: + prev_node.set_next(this_node.get_next()) + else: + self.root = this_node.get_next() + self.size -= 1 + return True # data removed + else: + prev_node = this_node + this_node = this_node.get_next() + return False # data not found + + def find (self, d): + this_node = self.root + while this_node: + if this_node.get_data() == d: + return d + else: + this_node = this_node.get_next() + return None + +myList = LinkedList() +myList.add(5) +myList.add(8) +myList.add(12) +print("size="+str(myList.get_size())) +myList.remove(8) +print("size="+str(myList.get_size())) +print(myList.remove(12)) +print("size="+str(myList.get_size())) print(myList.find(5)) \ No newline at end of file diff --git a/LinkedLists/LinkedList1.py b/LinkedLists/LinkedList1.py new file mode 100644 index 00000000..6cca75fd --- /dev/null +++ b/LinkedLists/LinkedList1.py @@ -0,0 +1,118 @@ +class Node(object): + + def __init__ (self, d, n = None): + self.data = d + self.next_node = n + + def get_next (self): + return self.next_node + + def set_next (self, n): + self.next_node = n + + def get_data (self): + return self.data + + def set_data (self, d): + self.data = d + + def to_string (self): + return "Node value: " + str(self.data); + + def has_next (self): + if self.get_next() is None: + return False; + return True; + + def compare_to (self, y): + if self.to_string() < y.to_string(): + return -1; + elif self.to_string() > y.to_string(): + return 1; + return 0; + + +class LinkedList (object): + + def __init__ (self, r = None): + self.root = r + self.size = 0 + + def get_size (self): + return self.size + + def add (self, d): + new_node = Node (d, self.root); + self.root = new_node; + self.size += 1; + + def add_node (self, n): + n.set_next(self.root); + self.root = n; + self.size += 1; + + def remove (self, d): + this_node = self.root + prev_node = None + + while this_node: + if this_node.get_data() == d: + if prev_node: # removing node that is not the root + prev_node.set_next(this_node.get_next()) + else: # removing root node + self.root = this_node.get_next() + self.size -= 1 + return True # data removed + else: + prev_node = this_node + this_node = this_node.get_next() + return False # data not found + + def find (self, d): + this_node = self.root + while this_node: + if this_node.get_data() == d: + return d + else: + this_node = this_node.get_next() + return None + + def print_list (self): + print ("Print List.........."); + if self.root is None: + return; + current = self.root; + print (current.to_string()); + while current.has_next(): + current = current.get_next(); + print (current.to_string()); + + def sort (self): + if self.size > 1: + newlist = []; + current = self.root; + newlist.append(self.root); + while current.has_next(): + current = current.get_next(); + newlist.append(current); + newlist = sorted(newlist, key = lambda node: node.get_data(), reverse = True); + newll = LinkedList(); + for node in newlist: + newll.add_node(node); + return newll; + return self; + +myList = LinkedList() +myList.add(5) +myList.add(9) +myList.add(3) +myList.add(8) +myList.add(9) +print("size="+str(myList.get_size())) +myList.print_list(); +myList = myList.sort(); +myList.print_list(); +myList.remove(8) +print("size="+str(myList.get_size())) +print(myList.remove(12)) +print("size="+str(myList.get_size())) \ No newline at end of file diff --git a/LinkedLists/LinkedList2.py b/LinkedLists/LinkedList2.py new file mode 100644 index 00000000..93d730bf --- /dev/null +++ b/LinkedLists/LinkedList2.py @@ -0,0 +1,126 @@ +class Node(object): + + def __init__ (self, d, n = None): + self.data = d + self.next_node = n + + def get_next (self): + return self.next_node + + def set_next (self, n): + self.next_node = n + + def get_data (self): + return self.data + + def set_data (self, d): + self.data = d + + def has_next (self): + if self.get_next() is None: + return False + return True + + def to_string (self): + return "Node value: " + str(self.data) + +class LinkedList (object): + + def __init__ (self, r = None): + self.root = r + self.size = 0 + + def get_size (self): + return self.size + + def add (self, d): + new_node = Node (d, self.root) + self.root = new_node + self.size += 1 + + def add_node (self, n): + n.set_next(self.root) + self.root = n + self.size += 1 + + def remove (self, d): + this_node = self.root + prev_node = None + + while this_node is not None: + if this_node.get_data() == d: + if prev_node is not None: + prev_node.set_next(this_node.get_next()) + else: + self.root = this_node.get_next() + self.size -= 1 + return True # data removed + else: + prev_node = this_node + this_node = this_node.get_next() + return False # data not found + + def find (self, d): + this_node = self.root + while this_node is not None: + if this_node.get_data() == d: + return d + elif this_node.get_next() == None: + return False + else: + this_node = this_node.get_next() + + def print_list (self): + print ("Print List..........") + if self.root is None: + return + this_node = self.root + print (this_node.to_string()) + while this_node.has_next(): + this_node = this_node.get_next() + print (this_node.to_string()) + + def sort (self): + if self.size > 1: + newlist = []; + current = self.root; + newlist.append(self.root); + while current.has_next(): + current = current.get_next(); + newlist.append(current); + newlist = sorted(newlist, key = lambda node: node.get_data(), reverse = True); + newll = LinkedList(); + for node in newlist: + newll.add_node(node); + return newll; + return self; + +def main(): + myList = LinkedList() + myList.add(5) + myList.add(9) + myList.add(3) + myList.add(8) + myList.add(9) + print("size="+str(myList.get_size())) + myList.print_list() + myList = myList.sort() + myList.print_list() + myList.remove(8) + print("size="+str(myList.get_size())) + print("Remove 15", myList.remove(15)) + print("size="+str(myList.get_size())) + print("Find 25", myList.find(25)) + myList.print_list() + +main() + + + + + + + + + + diff --git a/Matplotlib/Python Matplotlib Tutorial.ipynb b/Matplotlib/Python Matplotlib Tutorial.ipynb new file mode 100644 index 00000000..a5a7f77c --- /dev/null +++ b/Matplotlib/Python Matplotlib Tutorial.ipynb @@ -0,0 +1,436 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python Matplotlib Tutorial\n", + "Ten examples using Python 3.6" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "### 1. Simple plot with 4 numbers" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot([1, 3, 2, 4])\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "### 2. Points have x and y values; add title and axis labels" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot([1, 2, 3, 4], [1, 4, 9, 16])\n", + "plt.title('Test Plot', fontsize=8, color='g')\n", + "plt.xlabel('number n')\n", + "plt.ylabel('n^2')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "### 3. Change figure size. plot red dots; set axis scales x: 0-6 and y: 0-20" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure(figsize=(2,5)) # 2 inches wide x 5 inches tall\n", + "plt.plot([1, 2, 3, 4], [1, 4, 9, 16], 'ro') # red-o\n", + "plt.axis([0, 6, 0, 20]) # [xmin, xmax, ymin, ymax]\n", + "plt.annotate('square it', (3,6))\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "### 4. Bar chart with four bars" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.clf() # clear figure\n", + "x = np.arange(4)\n", + "y = [8.8, 5.2, 3.6, 5.9]\n", + "plt.xticks(x, ('Ankit', 'Hans', 'Joe', 'Flaco'))\n", + "# plt.bar(x, y)\n", + "# plt.bar(x, y, color='y')\n", + "plt.bar(x, y, color=['lime', 'r', 'k', 'tan'])\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "### 5. Two sets of 10 random dots plotted" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "d = {'Red O' : np.random.rand(10),\n", + " 'Grn X' : np.random.rand(10)}\n", + "df = pd.DataFrame(d)\n", + "df.plot(style=['ro','gx'])\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "### 6. Time series - six months of random floats" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXwAAAEHCAYAAACtAv3IAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJzsnXd8G/X9/58nyfKS9957JE7i7B0SMiAEKARo2dAWSmnLKgVa2m+/UL5llV9pmaVAKatlhL0hhIRMEpzp2LFjO/Gekpcsyda63x8nyXYs23K8nXs+HnnYvjvdfRTLr3vfewqiKCIjIyMjM/VRjPcCZGRkZGTGBlnwZWRkZM4QZMGXkZGROUOQBV9GRkbmDEEWfBkZGZkzBFnwZWRkZM4QZMGXkZGROUOQBV9GRkbmDEEWfBkZGZkzBNV4L6An4eHhYnJy8ngvQ0ZGRmZSsX//fq0oihGDHTehBD85OZm8vLzxXoaMjIzMpEIQhApPjpNdOjIyMjJnCLLgy8jIyJwhyIIvIyMjc4YwoXz47rBYLFRXV9PZ2TneSxkQHx8f4uPj8fLyGu+lyMjIyLhlwgt+dXU1AQEBJCcnIwjCeC/HLaIootPpqK6uJiUlZbyXIyMjI+OWCe/S6ezsJCwsbMKKPYAgCISFhU34pxAZGZkzmwkv+MCEFnsnk2GNMjKeYDLbxnsJMqPEpBB8GRmZseHz/Dqm/e8XnPfEDj48VDPey5EZYWTB95D3338fQRAoKioa76XIyIwa/91XSbjGG7PVxu/fy8dstY/3kmRGEFnwPeSNN95g+fLlvPnmm+O9FBmZUaG+rZNdpVquWpjA786bhsFsI6+8ebyXJTOCTPgsnZ786eMCCmvbR/Sc02MDue/CnAGP6ejoYNeuXWzdupUf/OAH3H///SO6BhmZicCHh2qwi7BxbjyRAd6olQq2FjeyND18vJcmM0LIFr4HfPDBB6xfv57MzExCQ0M5cODAeC9JRmZEEUWR9w7UMCcxmJRwf/y9VSxKDWVrcVO/r2nSd2G3i2O4SpnhMiIWviAILwEXAI2iKM5wbAsF3gKSgXLgR6IotgznOoNZ4qPFG2+8wR133AHAFVdcwRtvvMHcuXPHZS0yMqNBdYuJ4gY991043bVtVVYk//dJIVXNRhJC/Xodf6Kpg3V/205csC83r0zjqkWJY71kmdNgpCz8l4H1p2z7HbBFFMUMYIvj50mHTqfjm2++4cYbbyQ5OZnHHnuMt956C1GULRuZycupn98DlZIttiA51LXt7Cyp2+7W4sY+r99W3ITNLuLvreL37+dT12YaxdXKjBQjIviiKG4HTo3uXAS84vj+FeDikbjWWPPOO+9w3XXXUVFRQXl5OVVVVaSkpLBz587xXpqMzGnR2N7J7Ac28/z2Mte2g5Wt+HopyY4OcG1LCfcnJdyfrwoa+pxjd5mOpDA/Hr5kJgCHKltHf+Eyw2Y0ffhRoijWATi+Rro7SBCEmwRByBMEIa+pqX9/4XjxxhtvsHHjxl7bLr30Uv773/+O04pkZIbHkeo22kwWHvqsiMe/KgbgYGULs+KDUCm7JUEQBM6bEc2eEzpaDGbXdqvNzt4TOpamhTM9JhC1SsHBKlnwh8NR7VHautpG/TrjnqUjiuLzwPMA8+fPn3B+km3btvXZdtttt439QmRkRojSpg4Azp8Zw5PflHJWZgQFte3cuCK1z7EbZsbw7LYyNhc2EB3kw96TOlZnR6HvsrIsPQy1SkFObCAHK4cVnjuj6TB3cNs3t5EZmslza58b1WuNpuA3CIIQI4pinSAIMUBfR6CMjMyYU9rYQUSANw9fOpNvjzdxz7tHsNpF5iYG9zk2JzaQhFBfXt5dTrnOgNFs48NDtQAsSQ0DYE5CCP/dV4HFZsdLKSf+DZVnDz+L1qTlidwnRv1ao/nb+Qi43vH99cCHo3gtGRkZDylr6iAtwp9AHy+uWpTIiSYDALPdCL4gCGyYEUNhXTt+ahUb58RR3WIiOzqAMI03AHMSg+m02Cmu14/p+5gKHG85zn+P/ZdLMy9lZsTMUb/eiAi+IAhvAHuALEEQqgVBuAF4BFgnCEIJsM7xs4yMzDgiiiKljR2kR2oA+MmyZFQKgfgQXyIDfNy+5rJ58aRHanjmqjn85bJZXDo3nuuXJrv2z3HcKJxuHX2nhfcOVMuZbB7w3OHn8Pfy5/Y5t4/J9UbEpSOK4pX97FozEueXkZEZGZr0Xeg7raRHSIIfE+TLPeuz8PVS9vuajKgAvr5zpevnv/4ot9f+uGBfwjXe5FW0cO2SZB75vIj/7K0kJzaIrB5ZPzK90Zq0bK3cytXTribYp+/T1Wgw7kFbGRmZscMZsE1zWPgAN52VNqxzCoLA+hlR/HdvJQtTQnnz+yoATmoNsuAPwAelH2AVrVyWedmYXVOOsMjInEGUNUqCn95D8EeCe8+bRnKYP394/yjeKklWKpsNI3qNqYRdtPPO8XdYGL2Q5KDkMbuuLPgeoFQqmT17Nrm5ucydO5fdu3eP95JkZE6L0sYO/NVKogPd++tPF39vFU9dNQeNt4o712US7OdFuc44oteYaHxc9jE3fXXTacUqdtfupqajhh9m/XAUVtY/suB7gK+vL4cOHeLw4cM8/PDD3HvvveO9JBmZ06KsyUBapGZUJrTlxAaR9z9ruXFFKklh/lQOUfCL6/Ucb5g8mT7bq7ezp24PVfqqAY8zWAy8c/wdbPbuSWKbijcR6hPKmoSxDXNOLh/+57+D+vyRPWf0TDjP8wSi9vZ2QkJCRnYNMv1iMtt4emsJNy5PJcRfPd7LmfSUNOpZljZ67Y59HMHfpFA/DlYNrRjrrk2Hae+0sPU3q1AoJv7I0Ir2CgD2N+wnMbD/5nEflX3EQ3sfwlvpzYVpF9JgaODb6m+5Pud6vJReY7VcQLbwPcJkMjF79myys7O58cYb+eMf/zjeSzpj+M/eCp7ZWsYn+XXjvZRJT6vRTEN715gEUpPC/KhpMXk8MctstVNU306Fzsi+STB0RRRFKvWVgCT4A3FUexSAl46+hF20817pe9hE25gGa51MLgt/CJb4SOJ06QDs2bOH6667jqNHj8qDy0eJTXlVfJpfx19/mMvz208AcKSqFRYnjfPKJjdFjsKozDERfH/sItS0mkgJ9x/0+OMNeiw2yRf+dl4Vix1VvBMVXacOg0UKSh9oHHg+Rr42nwCvAEpbS/lr3l/5qOwjlsYuJSEgYSyW2gvZwh8iS5YsQavVMhEbvU0VPj9az7biJs79+w4a9V1EBHhzpHr0G0tNdZz+8ewxsvABKnSeZeo4J9ktTg3ls/w69J2WUVvbSOD02y+KWUSVvoomo3s90Jv1lLeVc830a4jXxPNq4auE+4Zz9/y7x3K5LmTBHyJFRUXYbDbCwia2BTKZOd6gJz7EF52hi9z4IK5cmEhJox6j2TreS5vUFNXrCfRRjXiGjjuSQp2Cb+Tpb0o4PEg3zYLaNvzVSu4+N5tOi50PDtaM+hqHg9N/vzFd6qS7v9G9W6dQV4iIyOyI2Tx61qPcv+R+3r7wbdJD0sdsrT2ZXC6dccLpwwfJd/fKK6+gVPZfmShz+hjNVqpbTNy5LpNFKaHEhfhSXK/HLsLRmnYWpoQOfhIZtxTX68mODhwTV2REgDe+Xkqe336CmlYTpY0d/P2KOf0ef7S2nemxgcxNDGZ2QjDPfXuCyxckolZNTJu0sr0SpaBkTeIafFW+5NXnsT751BlQkjsHICc8hyDvIGZFzBrrpfZiYv5vTjBsNhuHDh1ypWaef/75472kKUupozAoM0rDotQw4kP8mBUvlZ0fqZZ7rp8uoihyvF4/ZpWvgiBIgdtWaRLWoQEsfJtd5FhdOzmxQQiCwO1rM6hpNfHegeoxWevpUKmvJE4Th4/Kh5XxK/nsxGcYLUbautrYXr3dlZt/VHuUxIBEgryDxnnFErLgy0woShqclaDdwhQR4E1skA+HZT/+aVPTakLfZR3TVgdpkRo03iquWZxIuc5Iq9Hs9jhn2+XpsYEArMqMIDc+iKe3lmKxeZblM9ZUtleSECgFXa+Zfg16i573St7jrm/v4ldbfsXfD/wdo8VIflM+M8JnjPNqu5EFX2ZCUdLYgZdSIDms99DsWfHBI2rhtxrNfHCwhjbTxA4OjhRjGbB1ct8F0/nwlmVsmBkD0O8Nu8ARsJ0RK1nBgiBw44pUqltMEzJYL4oiFe0VJAVIWWO5EbnkRuTyt/1/47u675gZPpOXjr7EyrdW0mhqZEX8inFecTey4MtMKEoa9KSGa3qN2gOYERdIhc44IoHbl3aeZOFDW7jjrUP8bfNxAA5Xtbod1j0UXtldzpNbSoa9vtHgWJ0k+BlRYyf4kYE+pEVomBkXhCD0P/d2f3kzvl7KXv19nMPU8yeYG6/eUM/+hv0YrcZexVbXTr8Ws93MqvhVvL7hdW6YcQNrk9by8vqXOT9l4riA5aCtzISipLGDWfF9/Z0JjqyP2tbOYTf+emVPuTTAw1/Nprwqbl6Zxg2v5NFiNLPp5iXMTRx6JXVeeTN/+riAMI03t63JGNb6RpqOLiuvf1fBzLgggnzHtrITIMDHi4xIDYf7Ee8dJVqWpIX1CtBGBXpL6bg1E8fCt9gtXPbxZa7ZsymBKa5965LW8eiKR1kevxyFoOCOeXeM1zIHRLbwZUadLqvNFbwbCJPZRlWLkUw3VmhssC8AtR6cZyAsNjvVLSZWZkbw63WZGMw2rnrhO7QdXYT4eXHHm4fo6BraU0RHl5U73z6MXZT6zXdabIO/aAz52+bj1Ld38qeLcsZtDbnxwRyqau3TaKyq2cgJrYHl6b3bPQiCwKy4IPInkEvnmO4YbV1t/CTnJzy84mEWxSxy7VMICjakbiBQHTiOKxwcWfBlRp1/7ypn1WNbB22MVdbUgShChhsL3in4ntw4BqKmxYTNLpIYKmX/zEsK4YTWwIW5sTx3zTyqW4w89c3Q3DKf5ddR2WzkigVSEK+6ZeJ0iTzR1MG/d53kqoWJp/XkMlLkJgTTbDBT1dz797ezVAvAWZl9+/vMjA+itKkDwxBvwKNFXkMeANflXMcFqRegVEy+1GxZ8D2kvr6eK664grS0NKZPn86GDRs4fvz4eC9rUnCsrh2LTeT37+VToTNw96bDlLgR/zI3wzmcRAV4oxCGb+GXOyo/kx3l/recnU5MkA/3nJvF/ORQzpsRw1vfVw3JSq/UGVEqBC6ZGw/QR9TGkz0ndNhF+Pkwh5wMF6cF/+4pqZY7SpqICZJ8/acyKz4IUewO6o43efV5JAcmE+47es3nRhtZ8D1AFEU2btzIqlWrKCsro7CwkIceeoiGhobxXtqk4KTWgMZbRV5FC2sf/5ZN+6v5x7dlfY4r1xoRBEgM9euzT6VUEB3oM2wLv8LRstdZ+n92diR77l3jihFcsziJVqOFT4543qytptVEdKCPK7OoagJZ+Mfq2gnwUZEQ6juu60gO92fd9Che3VPuCrzb7CI7S7SsyAh3Www2M27i1F/Y7DYONh5kfvT88V7KsJhUQdtH9z1KUXPRiJ4zOzSb3y787YDHbN26FS8vL26++WbXNmflrczAiKLIySYDl8yNo7G9C4PZirdKwZdH6+ncaHO10wXJ+o4N8u21rSexwb6nZeE3G8z8+dNCfnNOFuU6A35qJREab7fHLk4NJT1Sw2vfVXDZvHiPzl/dYiQuxJeIAG+8VQqqmieO4BfWtjMtZmyqawfj5pWpXFrYwKa8aq5fmsyeMh3tnVZWZka6Pd5ZfzERUjOLWorosHQwP2pyC75s4XvA0aNHmTdv3ngvY1Ki7TCj77KSGu7Pc9fO47UbFvHjpSkYzDa+KeqdBlmuM7gsb3fEhfhS29o5pOuLosgf3s/nvQM1vLe/mgqdkaQw/34FUBAErlmUyOGqVo8ty5oWE/EhvgiCQHyI74Rx6djsIkX1eqbHTIxA4rykUOYnhfD89hOYzDZe/66CUH81a6a5F3yQ6i/2V7Sc1lSpkSSvXvLfT3bBn1QW/mCWuMz48NqechalhrnNrjmplXzmKT18tEvSwgjXePPhoRpXUQ5AudbAeT1+PpXYYF8+y6/Dbhc9HpDx4aFaPj9aj5dSYHtJEzqDmaxBctEvmRfPo18U8/p3FfzlsuABj7XY7NS3dxLvCConhPqNuUvHYrPzu3fz+cmyZGbEdae0VpxSwToR+M05WVz5wnf8zwdH2XysgZ+tSO33iQ5g9bRIviio50h1G7kJA/8uTqW0sYO/fFHEgxtnEhHg/onOU/Ia8kgMSCTKP2pY5xlvZAvfA3Jycti/f+AhB2cqXVYbf/ywgPs+LHC7/6RWCsSm9uiJrlQIXJgbw9aiJnaXSVkabUYLLUZLnwrbnsQG+2KxiTR1dHm0NlEU+csXRcxOCObGFakcqGylqlmy8Aci0MeLi+fE8eGhWtqMUiWu3S7y8eHaPsHc+rZO7KL09AGQEOI35i6dvSeaefdANS/vLgek9y2KIoV1UrBzolj4IN3sL5sXz7sHqrGLIlcv6n9SFMA506NQKQQ+Ozr0ATjfFDXwVWED97xzmBaDmfs/KuD70xiuYhftHGg4MOn99yALvkesXr2arq4uXnjhBde277//nm+//XYcVzUxaDZI/VH2nNBx1E2RzAmtAbVS4UqrdHLD8hTiQ3y5+sW9/GNbWXf2zABiHBcstfX1NHBb19ZJbVsnF8+OZXV2JDa7iMUmDnhTcXLN4kS6rHY27Zf6nm8tbuTWNw7y6SnB3OoWaS3xIdI5E0P9aO+0um4UY8FXhfXSGosasdtF/vRxIZf8Yzd55S2oFAIZUcMrVBtpfr9hmuTKyY50Bcv7I9hPzbL0cD7LrxuyW8fZiG9rcRMrH9vKy7vLef802i6XtJTQbm6f9O4ckAXfIwRB4P3332fz5s2kpaWRk5PD/fffT2xs7HgvbdzRdXQ3xPrXzpN99p9skvzyylNcMPEhfnxy23LOzorkiS3HXal3A01HGmrxlbMH++zEEGYnBBPgLXkwEz0Q/JzYIOYlhfDadxVYbXY+OFQLQFF97xRBZ859nMulI30dK7eOKIp8VdBAgLcKncHMV4UNvP5dBQcrW3llTznpkRq8VRMrXzzUX83nt6/g8cs9S3w4f2YMVc0mjtYMLT2zrMnAwuRQzs2JIsDHi3CNmuYO9w3cBsKZfy8LvgcIglAuCEK+IAiHBEHIG+3rjRaxsbG8/fbblJWVUVBQwKeffkpGxsQqoR8PtA73yuyEYD4+XMvPX8vjn9+W0WWVXB8ntYZ+RdxPreLmlWl0Wuy8tOskgsCAFt9QBf9QdSteSoFpMQF4KRUsc+SCD/QU0ZOfrUilQmfk9e8q2Oywop1jAp04nzZiHE8fTkvf6db59ngTd7x5kC8L6kel82N+TRv17Z3cvjYDpULg9+/nYxNFfjgvHlGcWO6cnkQF+hDo41mbh3NyolAqBL4sqPf4/KIoUtrYQXqUhn9cPY/t95xNaoSG5n46dp6K0WLkrm/vYnfNbvLq84jTxBGj6T++NFkYq6Dt2aIoasfoWjJjiNZhMf3xgmm8tLOcovp2vixoYNP+au49L5sKnZHVA2RhzE8KISbIh9LGDuKC+0/JBMm3HuCj8jhT51BlK9NjAl0W7rVLklAo8Hji07k5UcyMC+L/Pj2GzS6SGuFP8amC32IiKtDbdQ3nDctp4b+86yRbi5v44FAt1y1J4oGLRrZV7lcFDSgEuHRuPF8VNrDvZDOrsyN55NJZhGrUrJs2uYOMILl1cmIDyavw3P+u7TDTZrKQHqFxBfjD/NWUONw8g/Hckef4svxLvqv7DlEUWZWw6nSWPuGQXTpnGIW17dz0at6IjQvUOSz8rOhAnrl6Llt+s4qXf7IAk9nGDa/kYbbZewVsT0WhELhglmQ5DZSS6SQu2NflNx8Im10kv6aN2T0yO5alh/Ps1fM8zvARBIHfnJOJzS4SF+zL5fMTaNR30WLothKrW0wudw5AkK8XkQHe5Ne0Y7eL7K9o4bJ58Zw/K4b3D9a4nnxGgo4uK5v2SwO/Q/zVrHXcWK9fmoxSIXDvedOYnzw1JoTNTQzhSHUbVg+fkpz++56N9kL91a6Y00CUtJTwWsFrLI9bjtlmnjL+exgbwReBrwRB2C8Iwk2n7hQE4SZBEPIEQcjrbzD4eOfgesJkWCPAlwX1fFXYwGf5nj8eD4TOYMZbpcBf3W2Zr8qKZOtdq3jmqrn8aH48q7MHtjIvzJViIckD3BicRAR4e5SlI83AtQ05le9UVmZGcMWCBG5dnU62wz3S061T02oiLqT3jWpZeji7SrWUNHbQ3mllUUool82LR99pZWfJyD3oPrWlhIb2Lu46NwuAaxcn8/y18zgrY/KW/vfHnMRgjGYbxQ16uqw2GvUDP+W5a9MR5q+mxWjGZh/4b/XvB/6ORq3hoeUPce/Ce/FV+bIkdsnw38QEYCwEf5koinOB84BfCYJwVs+doig+L4rifFEU50dERPR5sY+PDzqdbkILqiiK6HQ6fHxGfzj0cHE2MHt3/8iMj9N2dBGu8e5TyKRWKTh/Vgx/uSx30BzomXFBXL8kiYtyBw+CR2i80eoHF3xn7/XZwxR8QRB45NJZXLEw0TU8pNgRuLXa7NS19bbwQeob02ww8/p30qDr+cmhLEsLJ8jXq0+Wz+lS2qjnXztPcvn8BFdTNF+1knNyoidEVe1IMydBeo8HK1u5/6NCzn9y54CaUNrYgZ9aSWxQ999kqL8aUaTfyVsg+e731O7h4vSLCfEJYWPGRnZfuZto/+iRezPjyKj78EVRrHV8bRQE4X1gIbDd09fHx8dTXV1Nf9b/RMHHx4f4eM9K8ceT4gY9giClUVa3GF1BxtNF12EmXKMe1jkEQeBPHvq2wwO80XZ0IYqiW2Fr77Twu3ePsLmwgahAb48DtJ4QGeBNsJ8XxQ16WgxmbnvzIBabyOyE3v37lzss7Le+ryLMX01ymB+CIHBuThSf59fTabENGKvwhJd3l+OlVHDP+qxhnWeykBDqS5i/mq+PNbC7TIfZaqfFaCHUv/dn7443D9JmsmAw20iL0PT6jIQ62mk0G8yE9dNaY1/9Pix2C8vjlru2qRSTqj51QEb1nQiC4A8oRFHUO74/B3hgKOfw8vIiJSVl8ANlBqXTYqNca2DjnDjeO1DDu/truH3t8DKNtB1dRHkYBB0JwjVquqx2OrqsBLjJ8nj7+yo+y6/nhuUpXLs4yWN/vScIgkBWVAC7y3Rc+PROGtu7eOSSmayf0Tt7IyrQh8woDccbOpibFOISnQ0zY3g7r5o9J3ScndV/IHsw7HYpFXNlZkS/wjXVEASBOYkhfH2su2FhZbOxl+Afrmp1pc8CbJwT1+scoX7SsTqDmf4+9Tuqd+Cn8mNu5NyRW/wEYrRdOlHATkEQDgP7gE9FUfxilK8p0w9lTR3YRViTHcXy9HD+9vVxfvD0zj6ZJ0NB12EmzH94Fv5QCHcInLaffOrPj9YzPSaQP14w3aOYwFDJig6gQmfEZhd5++YlXLHQfaXo8nTJPTkvqbsH/ax4yb1U1k+miNVm5443D3LhUzs5VNV/H59D1a006rs4d8bkz8AZCnMSpf8/Z3D/1Irmp7eWEuij4jfrMgH6FJw5bw79BW5FUWRHzQ4WxyzGSzn2k8HGglEVfFEUT4iimOv4lyOK4oOjeT2ZgXH677OiNTx91Rz+sGEaZY0dvLjjxGmdTxRFdIauMbUynYLf5MaPX9/Wyf6KFjbMHD1/6+ULErhqUSIf37p8wPjAuulRCAIsS+sOoIb4eeGvVrrNMhJFkXvfy+eDQ7VUtRi55NldfHKkts9xAF8erUelEAYNhk81lqeHoxDgfy+YDkgWvpOi+nY2Fzbwk2Up3Lomg9dvWMQ1i5N6vT5M023hu+NE2wnqDHUTauj4SCOnZZ5BFNd34KUUSArzJ9hPzc/OSmVRahgHKltO63ztnVYsNnHYPvyh0G3h9xV8Z2HOqS6WkSQnNoiHNs50raM/lqSFsff3a5jZYz6vIAhSc7VTLFNRFHnos2Ns2l/NbWsy2HHP2cSF+PKBmzYAoijyZUE9S9LCxmU+7XiSmxDMofvOYc20KMI16l7/j89sLcNfreQny5IBKY5yamFXiMOl01+17daqrdJre/jvpxqy4J9BHG/QkxahwUvZ/WufmxhMWZPhtHq/OHPwBxO/kSQ8QPqjdSf4n+XXkRmlGfaQ85EiMqBvbCM+pG83zWe3lfHCjpNcvySJX6/NIMDHiyWpYeRVtGA/JYVwT5mOcp2Rc3OmRtbIUHGKeEKon8vCP9HUwSdHarlmSRLBfv0bH2qVggAfFc2Gvp8dURT5oPQD5kXNmzIZOe6QBf8M4niDvk8LY2dK38GqoVv5Tj962Bha+KF+agSBPqmZJrON78ubWTvBK0sTQqV++c6UwmaDmf/3VTHnz4rhvgtzXAHe+cmhtBotnNB2+/uNZiu/fe8ISWF+XDI3zu35zxQSetw4/7GtDLVSwY3LUwd9XZi/updLJ78pn4r2Cg40HqCivYKN6RtHbc0TAVnwzxAMXVaqW0xknhLImpUQjEKQ8puHitPCD/MfOwtfpVQQ6qem6ZTH8pJGPXZRyumfyCSE+GGy2FyBw5NaA6IIl86N65VRNN8R7P2+vPtG/NiXxVS3mHjsslz81FMnVfB0SAz1o7a1k6pmI+8frOHKhYke9bw/tdr27u13c+WnV/L0wafx9/JnXdK60Vz2uCML/hmC0xo6NXNF460iMyrgtPz4Wscfzlj68KXrefdx6TgzjbKiBx5uMt5099qRAreVzVJb6MTQ3r+XlHB/wvzVrv7toijyzv5qLsqNZWHK1GiXMBwSQ/2w2UWe3VaG1S7y46XJHr0u1N/bJfgWu4U6Qx16s568hjzWJ6/Hz2t4dSkTHVnwzxBqHAJzalUowJzEEA5VtfbxFw+G08I/tfhltAkPULsVfG+VYtDhJuONq32yw/9coTM6uoT2/r0IgsD85BD2V0g34tq2TvSdVuZNkd44w8V543xnfxXzkkI8TsHt6dKp76jHLtr5Ze4vOT/1fH7Ru4AQAAAgAElEQVQ646ejtt6Jgiz4ZwjOlsLuBH9uYjD6TisFte1YbXYufmYXz24rHfScug4zIX5eqJRj+zFya+E36MmI0vTpuz/RcLVPdjxxVeqMxAT6uO1ZPz8plAqdkcb2Tlc7h2kT/AlmrHDeIC02sU+B1UCEatS0GMyIokh1h9ReZF7UPB5Z8QiJgQNP35oKyII/hSnXGtiUJ01sqm41oVYq3GbUrJ0WhcZbxTNbS3n/YA2HqlrZd3LwVrTajrHNwXcSrvFGq+/twy+q15MVNTF7v/dE460ixM/LNei8otnY70CWBQ7Xzd6TzRyrk1xWmbLgAxAT5ItKIaBWKlzdVj0hzF+N1S7SbrJS2yHVOcQFnDkB8DM78jOFaTNZuP7f+6jQGVk3PYqaFhMxwT5uWw2E+Ku5YXkKT2wpcfmMPWlBXNfW6XFv+ZEkXOONyWLD0GXF31tFs8FMk77L1dxsopMQ6uealFWhM7Im232bhRmxgQR4q9hdpsPQZSUu2NfjoSFTHaVCIDsmgNRwzYCpmKcS4mqv0EVNRw1KQUmU38TO7BpJZMGfgoiiyF2bDlOhk0TleEMHta19uzr25MYVKbyypxydwUx2dADlOkO/Dcqc1LaaWJXVt8PpaOMMEms7uvD3VrnGDk70gK2ThBA/CmrbMHRZ0XZ09Wvhq5QKFqWGsqdMi7dKOWluaGPFf3+2GPUQ3YnOFOImfRfVHdVE+0dPqeZogyG7dKYg35e3OMrMkwHJv10ziOAH+Hhx34XTuXJhAlcsSKDTYu+3Xw3g6Ene1Wc4+VgQHtC72taZoTNZBDE+1JeaVhMnmqQMnYEGvyxJC6dcZ+R4o37S3NDGikAfryF3Hc2JldJ2951spqajhjjNmePOAVnwpyQ7S5pQCHDH2kwCfFQU1LR5JM4b58Tz8CWzXBkQ1QMM4m5ok8R2PAQ/wtVPR7ohFdXpCfHz8igPeyKwOCUMi03kn9vLACnFsD+WpoUBIIq4BrDInD4RAd7kxgfxTXEjtR21suDLTH52lemYFR9MkK8XWVEBfHu8CVGEuBDPxNmZSTKQH7+2rf+sn9Em0iHsJ7QdmMw2vnD0lpksgz9WZkaQFObHJ45hKEmh/acUZkUFuLqRTpYnmInO2dmRHKpuQmvSyoIvM7np6LJyuKqVZemSZZgZHUBdmzQOzlNxdt4YBhR8R5pnTNDYB20jArxZmBLKSzvL+c/eCilAvSR5zNdxuigUAtc6OjkG+XoR5Nd/IFahEFicFoZaqSBlFNo9n4mszo5EUEn1DWdShg7Igj/l2HdSh9UuutryZvXoneOp4DtTB6tbjIii6LYgyyn44+HSEQSBe87NQtvRxcOfF5ETGzjpqk9/OD8BXy+lR4Pb7z4ni39cM7dX0zuZ02dGbBBBgVKPItnClxk5TmyD2kNjesldpTq8VQrmOnqx9GyWFj0Ea1xKHTTxyu5yFj+8BYvN3mt/TWsnYf7qYY/qO13mJ4eyOjsSm13kJ8tSJo07x0mQrxcPXzKTX65KH/TY5HB/1kzwpnCTCYVCIDNOikHZzCGDHD21ODMF39QCWx4As2H0rnHsE3htI3x93+hdww27SrXMTw5xCbGzWVpEgPeQxDk+xJeqFiOv7KmgUd9FSUPvKU11baZxse57ct+F07lheQoX5o5e//vR5OI5cayfMXVb8U5ksuMtIKr47dsn0XcOvTX4ZOXMFPySzbDjr7D3n6Nz/hPb4J2fgmiH1qrRuYYb2jstFDfoWZgc5toWpvEmXOM9ZHGOD/HjRJOBk1rppni0tq3X/tpWE7HBY++/70lSmD9/vGC627YEMjID0dBZQYImmXKticc3Hx/v5YwZU7Li4M/f/ZkI3wh+nvvz7o1f/wlMzXDhE9DmEOE9T8PCm8B7GAMzbBYo/hyKPoGAaAhNg8/uhrA0iJsLRzZJOXVj4HI4UtWGKMLcpN6j965dnETwAIFBd8Q7Arc+XgoUgkBBTRvMT8BsteOlFKhpMbG0x/g+GZnJRElLCYtiFuETHzSsmc6Tjakh+FYzVO6GuPkYFALvlrxLjH9Mb8EveB+sUrYKbdWgUIFRB3kvwbLbTv/a3/wZdv0dfEOhsw1EG8TNg6vfgfx34ODrYGgCjfvy+ZHkYGULgiCNguvJ7Wszhnwup+Cvz4mmtrWTo7XtNOo7Wf3/vuWms1IxmG3jkpIpIzNc2rraaDQ1khGSQWuQD0VnkOBPDZdO9T549SIo+4Z9dfuw2q1U6avQmXTS/s42aDkJ+jqwdEJbDUROg9SzYfeTYDZCUzH8JQ0eToCX1kNXx8DXdHJiKyQuhbtK4M5CuPgfcN2H4BcKQfHSMW1j49Y5WNVKeoRmRPqt5MQGER3ow3VLk5keG8ixunY+PFhLR5eVv30tPQKPtw9/KmO0GLHZbeO9jCnJ8Rbp85sRkkF0oC/1bZ2uCWRTnakh+AmLwDsISr5kV+0u1+YjDQekb+rzu49trZQs/KAEWPlbyfre/7IUxLV2wcwfQuV3kuU+GNYuaCiEhIWgVEkundlXgbcjMyY4wXHN0Rd8URQ5WNnCnMTgwQ/2gKhAH777/RrmJoYwIy4Io9nGP7efICXcH19H8He8ffhTFbPNzIb3NvDMoWfGeylTkpKWEgAygjOICfLBaLah77KO86rGhikh+FZB4N9J0+ks2cyuym0sNplQiSKHv/ub5D+vO9J9cGuFJPiBcZC0BJJXwLZHJB/80lvhgsdhwY2w9zmozhv4wg0FYLdA7Bz3+10WfvXIvNEBqNAZaTFamJM48mlmM+Kkkn5tRxdXL0rknnOz8PGSC4FGi711e9F16th0fBNmW//9jGROj5LWEgLVgUT6RRLlSFWudxQnTnWmhODvb9jP3yw1XBcoUG1qYLWxiyxVEIdbS+DI21B3GJyjy+rzoautW4xX/lb62S8MlvxS2rbmfyVr/dtHB75w7UHpa3+C7xMMas3ggm9sBl2ZZ2+2H5xDyEfKwu9JeoQGb5UChQA/yI3lx8tSOPS/5wypLa2M53xT9Q0CAq1drWyp3DLey5lylLSUkBGSgSAIrkpxWfAnESGK6UyzXUOJWvJdL4+cS27GBRT4+GDd/STUH4GkZaDygQqHy8cp+MnLYfEvYcP/63bF+ARC5nqo3At2u5srOqg9KAVrg/uZlCMIkutoMB/+1/fDS+dKTyOnyaHKVvzUSjIiR77fikqpYH5yCKuzo4h09L8fr4KrqUantZOLPriIrZVbAbCLdrZVbWNt0lriNHG8c/ydcV7h1EIURUpbS8kIlhIZnPMcZMGfRPiplew9PoNH9BruaG4hYfZ15EbkYhLgeEsxNBZC7GwITpJEHLoFXxBg/cMw45LeJ01YJFn+2uL+L1x3SDrvQCmXQfGDC37NASmW0FI+6Hvtj2P1erKjA0ZtxN+/rl/A01f18yQjc9pUtFdwou0Ebxa/CUC+Nh+tScuaxDVclnkZ++r3UaUfu1qOqU6toRaDxUBGiCT4kYFSI746WfBHBkEQ1guCUCwIQqkgCL8bjWvEh/iRGOqHjrXcIAZB1gZyI3MBOBzg6LESPQtCksDsSMFyCn5/JCyUvlbtdb/fYoLGY/27c5wEJwwctLWaoalI+r7OfRsGu13ki6N1GPoJLImiSHG9nqzo0Wuf6+OllK36UaCivQKQ/PbNnc1sqdiCSlCxIn4FK+JWAFCgKxjPJU4pTrSeACA9WGpp4a1SEuavpr5dFvxhIwiCEngGOA+YDlwpCML00bjWktQwHtGtwHZ7Pnj5EusfS7hvOIejHTnoTgsfQFCAZpCS9tBUya9ftc/9/oYCsFsHF/ygeKngq782Dk1FUuAXumMCPRBFkT99XMDNrx/gma3uB4s36rtoM1nk9rmTkEp9JQA20cbLBS/zZvGbnJ14NoHqQNdQ7Yq2ivFc4pTC+bTUc2B5dJAP9W0mthU3ctk/dtNsmLqB8tG28BcCpaIonhBF0Qy8CVw0Ghdamh5Ge6eVQsewZ0EQyI3I5YjCDj/9SvKzhyRLBwfESmmUAyEIklunPwu/ZDPgOGYgghypmW017vfXOzKI/MLcNlp76ptSXtlTgcZbxcdHat3mCzsLR3o2SpOZHFS2VxLmE0ZKUAr/PvpvBATuWXAPAL4qX6L9oylvLx/SOU+2neRw0+FRWO3kp7qjGh+lD2E+3e1HogN9qG/v4o19leRVtHDXpsNTNi9/tAU/Dujpz6h2bHMhCMJNgiDkCYKQ19TUdNoXWpIq/QJ3l2ld23IjcqnqqEYX4ehIGOKw8IM8bImasBB0pWDQ9d137CNIXDJ4Ba1L8Cvd76/PBy9/yL5AEvweH7STWgNPbinhB7mx3HfhdKqaTRysanXtf+LrEvKr2yh2zHSVLfzJR6W+kqTAJM5LPg+A2+feTrR/99NncmCyy+3jCVa7ldu+uY2fb/45bV1tg7/gDKNKX0V8QHyv7qrRQT5UtxjZUaIlLtiXb4oa+feu8vFb5Cgy2oLvLoLY69YpiuLzoijOF0VxfkTE6Q/Ejgz0IT1Sw+6ybnHOjZD8+EeaHFa006UzmP/eidN6rz7FraMtlQLB038w+DmcTxUHXgObGx98fT5E5UjtGLraoPmEa9dfvihCrVLwPxdMY/2MaNQqBR8dqgWgXGvgb18f5y9fFlFUrycywJsQfzlNcrJR1V5FQkACV0+/mgeWPsDlWZf32p8UmER5W7nHFufHZR9T3l6OwWLgjaI3RmPJk5pqfTXxAb3//qMDfdB3WjGabfzfxTksTAnlv/v6MdAmOaMt+NVAQo+f44Ha0brY0rQwvi9vpssqlaRPD5uOSlB1P96GDFHwY2YDQu/CLZCse4BpFw5+jsAYWHMfFH4A7/ykd5qnKEqCHz2zOxbgCNweqGzh86P1/PysNCIDfAjw8WJNdiSfHKnDarPz7XHpaWhnqZbdpTp5wPUkxGgx0mhqJCkwiUB1IBszNqJU9A6MpwSloLfoae5sdnuOF468wIv5LwJShe5zh58jJyyHs+LP4vVjr2O09D+X+ExDFEVqOmqI15wi+EHOVGMFS9PCWZ4eTllTx5Rsmzzagv89kCEIQoogCGrgCuCj0brY2VmRGM029jisfB+VD9mh2d2C7xMEFz8H82/w7IRqPwhNgcZTsiSOfSRZ5J7eOFbcCesekF539F1pm65M+r6rXRL8yGmg9JZSNIEtxxpQKgRuXJHiOs3GOXFoO7rYUtTI9uNNhGski76+vbPXZCuZyYEzgJgQmNDvMcmByQD9+vHfKHqD5488j9Fi5OOyj6k11HLrnFu5adZNtHW18X7p+yO97EmLrlOHyWoiIaD3/3dMkNQTanl6OD5eSnITghFFyK9pk/L2G6dOc7VRFXxRFK3ALcCXwDHgbVEURy3HbElaGH5qJZsLG1zbZkXMokBXgNXucKfMvrLb0veEyOlSvxwndUeg9iD69B/w710n+0yC6n9xt0LUTNj6IBR/AU8vgHcdN574+aD0gvgFcPJbAFqMFoJ9vfD37g4ur86OJDbIh3/tOMmeEzo2zIxhZabkBpMt/MmHM0MnKaD/z2NSoLTPnR9fa9LSZGrCZDWxrWobbxa/SWZIJktjl5IbkUuEbwTFzQPUkUwhKtsreeLAE7xZ9CZV7dKN1GK3sL16u6sJXbVeqng/1aXjHDN5bo4UO5kVFwTAkeo23vy+irWPb+ffu06OyfsYbUY9D18Uxc9EUcwURTFNFMUHR/NaPl5KVmZG8PWxBtcc1ulh0zFZTa5f9pCJyoHmMinvHmD3k9jVGq78Po0/fVzIlmMNA7/eiUIBa/4ode184wrJov/J5/CLPZKFD5C+RnLx6OtpM1r69LBXKRVcvTiJfeXNGM02zsqI4PolySiE0WmpIDO6VLZLgt8zRfBUYvxjUCvUlLeV99l3THcMAKWg5KmDT1HUXMTlWZe7ApLR/tHUGepGfuETDKvdyj3b7+HF/Bd5cO+D3LX9LgDeLn6bX235FQ/ufRBRFF1PVKcKfkKoH1/9+iwumydtD/FXkxjqx5HqVt47IOnGA58U8szWUl7ccYKq5snrJpsSlbY9WTc9iob2LvJrpAwF55DiWsNphg4ip0uTq5qKobUS8eh7vG1fQ4VRjb9ayTdFjZ6fK+McqVlbYCxc9TYkLYWoHmUJGeukr2Xf0GI0u+1Vc8WCBNRKBV5KgSVpYZydHcnBP55D+ii0VJAZXar0VYT5hOHv1X8TOqVCSWJgoluXTlGzVLC3MWMj1R3VaLw0XJB6gWt/tH809Yb6EV/3ROO1wtco0BXw2FmP8YvcX1CoK0Rr0rKzZicqhYpNxzfxxIEnqNZXIyC4HVyeGRXQK3MnNyGYnSVavi9v4Vdnp5EbH8xjXxbz50+P8ey24fW9Gk+mnOCvzo5EqRBcbh3nL7emo588+MGIypG+NhbCnmcREXiiYy1PXzWXVdmRbC1u8jxnVxDg6k1wS5771NCoGaCJgpLNtBothPh5SUNUSja7DgnTeHPjihQumxfvcvcEDXGalczEoKK9YkDr3klyYDLHW45jsPQu3jvWfIyEgASuyLoCgB+k/QA/Z5NAJMFvMDZM2ZxygPK2cp459AyrE1ZzbvK5nJ1wNgDfVH5DXn0el2ddziUZl/DS0ZfYUrmFSL9IvJXeg543Nz6I9k7JDXz5/ETeuXkJ3969irmJwZQ0TF6f/pQT/GA/NQuSQ1yCH+kXiUpQUdtxmhZ+aKqr6Zp44FW+Vi4nLC6FszLCOTsrkiZ9FwW17Z6fz8tXCga7QxAgfS2UfUO7wUSIjwI+vbNP18571mfz8CWzTu/9ONGV9Z4TIDPmnGg7QWpQ6qDHrUpYRU1HDRve28Afdv6BR/c9itak5ZjuGNmh2WSFZvHU6qe4Zc4tvV4X7ReNyWqasvn4dtHO/XvuR61Q84fFf0AQBLJDswn3DeefR/5Jp62T5XHLuXv+3YT5hlHcUtwnYNsfzqlxsxOCSQzzQ6VUkBTmT3ZMICWNHZP2JjrlBB9g3fRoihv0VOqMKBVKov2jPbLwjzQdwS6eEoRVKCEiCw7+B8Fi4HHDem46Kw1BEFiVFYEgMDS3zmCkr4HOVpI6C5lpL5KmdTUdH1YnTbd8eie842G2ksyIozPpaO5sJi04bdBjL0q/iDfOf4OskCzy6vN4s+hN7vr2Lqo7qpkeJrkEVyWsIkDd260Xo4kBoN44Nd06m4o3sb9hP3cvuJtIP6kAUhAElsUuo9HYiFqhZl7UPDRqDb+Z/xugr/++P2bEBhGu8eaaxb0D6pmRGtpMFpr0XSP7ZsaIKSn450yPAuCrQumDHqeJG9TCP9BwgKs/u5o9tXv67BMjpwMiu8jFEJLFhhlSND9c482s+GA+OFjDkerWPq87LdLXIao1bBS3kGP4TtrW1QZ6N3+0+16QYgs9sXTCYKPxRFGaEaArlZq3yYw5Za2SH9gTwQeYET6D5895ni8v+5K7FtzF/ob9AGSHZvf7mmg/6XNa1zE1A7cv5L/A/Kj5XJx+ca/ty+OXAzA/ej6+Kinl8vyU87lx5o19ju0PX7WS7/+wxhXIdZLhSH8uafRwBOoEY0oKfkKoH9nRAS63TqwmdlDB31sv9cxx9yRw1Cb5Wb8OvpyXf7IQlbL7v+0XK1Np1Hfxg6d3sf7v23n0iyJe21POdyfctGPwBJ9ATNN+yIWKPWTpvgan1XZqm2aLCT67Cz6+vdv6F0X451nwzf8NfI32GjC1SAPXmydvAGoyU9oqNcJzdm0cCldmX8ncyLnAIILvaNEwFS38ekM9DcYG1iat7RVsBVgSs4QArwDWJa1zbRMEgdvn3s68qHkeX+PU8wJkRGkAJq0ff5AOYpOXddOjeGZrKS0GM7GaWJpMTXTZuvoN2DgtJq1J22ff610rMSsE/nrrL1Aoe98j18+IYVl6OO/ur+bzo/X889sy7CIoBPju92uIDBj63NeGrGtJOfxvvE210tjF3U9Jlnzqqu6DnBZ/5R4o3wkpKySLXVsMdYM8ttYf7f5ee1xKEZUZU8paywhQBxDhO/R2IgpBwV9X/ZXDjYcJ9w3v97gw3zBUCtWUzNTJ10rxp5nhM/vsC/IO4usffu2y7keSCI03Qb5eHJct/InF2mlR2EXYXtLkytTp79HWYrNwuFGqxm0y9W3gtrOqC3PauX3E3kmAjxc/XpbCWz9fQuED63n3F0uxi/B5/un9oTX6JLPT5sgOmnu9NKD9VNeNy8UjdAd1T2yTvrYO0gekoUewtul43/36+u66A5lRobS1lPTgdLdWpCeE+4azJmnNgMcoBAVRflFTMhc/vykfL4VXv084fl5+p/1/OxCCIJARqaG0QRb8CYXz0au2tZNYTSzQf2pmga6ATps0AEFr7G3hV7cYqWk1sTAl1KPr+ngpmZcUQlZUAJ8cOb3MoBajhQet19Aw/x4IS4eITMkS74ne8Uc891oo3wEVe7oFv6164CBvfT6EpEidPE91FR19F56YDf8+r/8e/jLDQhRFytrKPPbfD4do/2gaDB4WBw5CW1cbpS3uZzKMJla7lR99/KNezeCOaI+QHZqNWjn2DQMzogI43qiflJk6U1bw/dQqfL2U6Dq6Bs3Fd7pzpoVO62Phf18uNa1akOyZ4Du5YFYM35e3UNdmotNiG9KHo9Vo5piYhHX5nVKqZkRW91QsJ04Lf9W94B8B2x6WhF/pDVYTGPq6plzUH4XoGRCe2f3kIIqw7RF456cQliYFdd+5YfAAsMyQ0XXqaOtqOy3//VCJ8Y8ZMZfO80ee56rPrsJgMaA367lz252uNgajyb66fRxrPsYHpR8A0g2gUFfo1p0zFmREamg1WtB2TL6Ehykr+ADhAWp0BjMRvhGoFP3n4u9v2E9qUCqZIZk0Gps4WtOdt7zvZDOBPqoh96q5IFd6qrjmxb1M+98v+ORI78fqL47WU9fm3m3SapK69AX7OgqqwrOkmbfGHh0T9XWSuAfEwNLbpB48nW0wzVFp2V///a4OqQVz9CzpRqItkdo2f36PdNPIvQp+thXO+wsc/xw++KUs+iOMM2A7Zha+scHVT2Y4VLZXYrKa2FG9g89OfMbmis1srtw8+AuHyScnPgFwVdCWtZZhspqYGTFOgu/wHpROQj/+lBb8MH9vtB1dKBVKYvxj3Aq+3qwnryGPBdELiPCLQGvSceHT29l3UhLXvSebWZAcOuTh4Cnh/ixIDkFnMKNRq/jiaLeVdVJr4ObX9/Pgp8fcvrbFaEatVOCndrTKjciSvvb04+vrISBaegKY/1PwdTyBzLlG+tqfH7+xEBClqt7wTOlp4Ivfwr7nYcktcPGzoFLDwp/B2f8DR96Ej28b0nuXGZgCrdQ/cCws/Gi/aGyizW0ywlBxZvt8VfEVH5Z9CMBR7dGBXjJsjBYjX1d+zaxwqdBwR/UOV/db57axJjlMaoUxGXvqTGnBD9eoXY9d8Zp4DjQeQGfqnS75UdlHmKwmNmZsJNw3HBEbKIz8+q1DPLO1lBNNBo/996fy+o2L2Pf7tZw7I5qdpVpsjoZu7+yXHoO/LKh3W8DRZrQQ5OfVHXSKcASmelbG6usk6x7AWwPrH5baPsdK6Xr9Dk53jlSMntl9I/n+Ram3/zl/lm4gTlbeDQt+BgdfB9MI1Rmc4RgsBl4tfJW5kXMHzLAZKUay+MoZ/N1atZV8rRQ0LdQVDvKq4bGtahsmq4k75t1BpF8kX1Z8yevHXifaP9rjqtmRJibIB6VCoFIW/IlFmL83ug5JUH8x+xe0m9v52eaf0dopiZddtPNm0ZvMiphFTliO6w8wKdJGfXsnj31ZzLk5UVy1aPB+J+7wVilRqxSsyAinzWQhv6YNm13k3f01ZEcHYLGJvJ3XV5hbjGapj46T4EQIy4Cij7u3OS18J7lXwAWPg28weAdCW3+Cf1SaCxAUL7mKAPzC4YK/9xZ7JylnSV9b5UHaI8G/8v9Fc2czdy+4e0yu56xAHW7g1mgx0tbVxtLYpVjtVpSCkiuzr6Smo4aWzpaRWKpbvq78mii/KOZFzWNF3Ap21eyior2CB5c9OCpZOJ6gUiqIDfbxWPA7LTa+KqifEEHeqS34GjXNBjN2u8icyDk8ufpJKtoquGnzTbSb29lZs5Py9nKuyr4KgCAvaS7uvFQlT105h2evnstz18wjwGd4zcmWp0s3kp0lTews1VLf3smtqzNYmhbGf/dWuix/J61GC8G+PbIPBAFyNkr59h2ONg76+m4L/1SCEgaw8POlvvyCAP5hsPiXcNlL4N+Ptekc0dhS7tmblemXKn0Vrxa+yoaUDcwInzEm13QKfqNx4PYfZpuZ327/LTuqd7jd73xCOD/1fCJ8I1get5yV8SsBRs3KF0WRg40HWRC9AIWgcDVGuzn3ZhbGLByVa3pKYqgfVS2eCf57B2q46bX9HKoa/6fkKS344RpvrHaRdseossUxi/n72X+npLWEjR9u5NYtt+KvDKOxPov6tk46u6SmZgH+JjbMjGHDzJgRsSLCNN7MiAvkkyN1PPJ5EcF+XqydHsmVCxOpaTWRV957fF2rm1745GyU2jQf+wi69GDW97bwexKc6N7Ct9skH350j2DX+ochdWX/i3cOi5EFf1hY7BZ+u/23qBVqfj3v12N23RDvELwUXoMK/nd13/HZyc/4zbe/4XhL39oMZ6ZPnCaO1za8xoPLH2RamFSwV6AbnZlGtYZatCatazb1WfFn8ep5r/LzWT8flesNhcRQP499+AcrpSeg78vdj6kcS6a04Ic5RgD2TJ9aEb+Cv678K74qX2KF9TQU3cSfPirmgU8K0LVJVbFq75GPvq/IiKCoXk9dm4lHL52Ft0rpsvzzKno/EreazH0FP3Ka5IIp+AD0jsfz/iz84AT3QdvmE2AxSimZnuITJAWEZcEfFv849A/ytfnct/Q+V8uDsUAQBCL9ImkwDkYyazUAACAASURBVOzS+briazReGjReGn759S957vBzroEh0C340f7RxGniCPIOIkAdQHJg8qgFbp3FkE7BFwSBOZFzUAjjL1sJoX5oO8wYuqyDHuu07L8vHz3Xl6eM///cKBKukdooaDt6B0ZXJ67mk42f0NV4HmsyMrh8fgLfFjdR2mBGtHljVwyh3bGH/HhpMretyWDzr1e6RqmF+KtJj9S4LPzfvH2Y1/aU02K0EHLq8JOebp1aae5tvxZ+UII0K/fUQKsz6Bs9xHS2kGRonhoj3sYDURR5q/gt1iWt49zkc8f8+pF+kQNa+Fa7la1VW1mZsJKn1jxFmG8Yzx56lh9/8WPXaNB6Qz0CgstF5CQnPIcCbcGo+KcPNR3CV+VLRkjGiJ97uCSESN6Awdw6+k4LpU0dKBUCeeXN4+7Hn9KC77TwdW4KJExmGyd1BnJig1g/MxqD2cbb31ehFINo7hp+CtupRAX6cOe6TCICevfyWZAcQl5FC8X1et49UM3/fXoMs9XufqhJ7uWACDsel34eyMKHvm6d+nxQqLqzfjwlJFm28IdBk6mJdnM786Pmj8v1BxP8/Q37ae1qZV3iOnLCcnjrgrd4fNXjNBobXT79OkMdEb4ReCl6fy4XRS+i0dTIi/kvDnudm45v4r7d97GtahtWu5XDTYeZGT4TlWLitfxKDHUIfvPALUiOVLchinDejGhajBbKmsa3en1qC76/JK46Q9/Ux+MNekQRpsUEsCRVGn6uM5jxV4X2Sd0cTeYnhaLvtPLYl8UoBFA6YgZ9LHyQhrGkroImR/5+fxa+M9B6av+dhqOSW0g1+MSfPudrq5IKtM4UjKfnb23ubOaSjy7hlYJXXNuc7QjGy1J1Cn5/1uXmis34qnxZGrfUtW1lwkrCfcN5r+Q9QBJ8d66oi9Iv4oLUC3jy4JO8mP8iZtvpV5++cOQF3it5j1u/uZVbttzC8ebjLnfORMMp+BU6A9e8uJfHN7vpSUW3O+fGFdKgm/H2409pwQ/x80IQcFsCXVQvuW2yowPx8VJyVobUtTDUO8xtA7XRwtmy4etjDSxLD+eW1VIxjlvBB6mZGoCXH3j3U/0bPQs00VDwfu/tzpYKQyUkGexWqa3ymcDJHfBYGlTn9dlltBj7DVLaRTv37riXkpYSnjjwhGvw+FhW1rojyi+KTlsn7Wb3rsq8eqnwsGd3SS+FFxenX8z2mu00GBpoMDS4FXyFoOCBZQ+wKmEVTxx4gvPeO49DjYeGvEadSUedoY7b597OvQvvZU/dHqyidcIKfrCfFwHeKjblVbOzVMu2YvdPUAcrW0mN8Cc3PogwfzX/2VvBj57bc9p9tobLlBZ8lVJBqJ/alYvfk2N1evzUStedep1jaEqMRrKGegasRpOEUF+Xm+ei2XH8bEUqD22cycrMftrmZl8g5c07q2zdoVDCjEug5KtuP35HI+hrh+6/BwhNkb6eKW6dgveljKjDb/TZ9Wrhq1zz2TV0mPsG9l8rfI3dtbu5ZfYt+Ch9+PN3f0YURUpbSwn1CSXU5/QK+IZLlJ/02Xbn1umydVHeXu626+Ql6ZdgF+3859h/+rXwQbo5PHn2k/xz3T/xUnhx7457MVqGVpTkvInOjpjNVdOu4vGVj3NW/FnMjx4fN9hgCIJAQqgfxY6++CUNHdhPSa+22uwcqmpldkIwgiCwJC2MozXt7K9sYVNe9Xgse2oLPkh+fHc+/KL6drKiA1A4WiacNzOaG5en8NPZG1Er1Pzo4x+xq2bXqK9PEAQWJofirVJwbk4UapWCqxYl4utsq3AqKjWc96jUJ38gZl4GNjMccxRrndwufU1a2v9r+uNMysUXRSj+XPq+4IM+bqxCXSFWu5Xy9vI+L91evZ3pYdO5adZN3Db3NvbW72VP3R7KWsvGpI1CfwyUi3+i9QQ20UZmSGaffQmBCVyUdhEv///2zjs8rura2+8e9d6b1W3LcpG7bGMbGxvbNAOmmhBqKAmhfSGBC2k3ISGEhACBkNAJIZeYTsDYgDHYYAPuRW5ylaxi9d7r/v7YM6ORNBrNSBrNyN7v8+iZmXP2ObPOSFpnz9pr/daB12jpaCEuoI81I9Tf8bxR83hk/iMU1Bfwt91/c8jGfeX7MAiDuWXjkuQl/H3J3wnwCnDoPMNJYrj6RjQuJpCmtg4Kqrri+TWNbfzgte2U17ewOF19/o9clsHn9y3kmlmJ7DpZ1av+Zjg4/R2+UU/HEikl2cV1jI8NNm/z9/bkVxdPZG7CdN659B3CfMN4bu9zw2LjQxeO5/VbZttf4DX5KqWfY4tRM5QE8r531OsTG8A3FOKmOW5gcLxa7D0THH7RXvVNKH05NJZDzsZuu0056idqTvQ6tLC+kJTgFIQQXJ52OUFeQaw+vtqsfe8qbDn8o9VHAaw6fICfz/m5uQ+sPemkmbGZXJN+DW8cesMhlc795fsZHTIafy9/u49xNRPiggnz9+KXy9VNyjTb7+yU3Pqv7Ww5UcGfrpzMJUYhxVB/b9JigpiVEkZdSztHXNA16/R3+IFKMRMwL1qV1LZQ3djGhDjrMfD4wHjOSTiHw5WHh0RlsD8Sw/2ZMzpiaE8qBExZqWb2Fcfh+EYlk2Do45uDLQweqpirsreTGzLKj7lH05XDn4AwwEWPK4mKfe+Zd9W11pkltnNquqepdnR2UNJQYu694OPhw3kp5/Fpzqc0tjcyNsz1Dt9aLv6RyiP4ePiQFGRdPiTAK4A/L/wz48PH210dvHz0ciTSagGXNaSUHCg/MGzVx0PFXYvHsuH+RcxICgUwO/APdhey42QVf7hsMtfM6v25Ziar0F7PgsvhwGkOXwjxWyFEoRBij/HnIme9ly0iA30orW3mupe3cPeq3QAcLFLyx5Yz/J5MjJhIc0dzr3/sEUXmreDhrfre1hZ0b5HoKDEZULjTdmOVgdJSB8+fDf+5xvVSzIfXQsJsCImHCZfCwQ/NchZHq46ah/X8uyhrKqNdtpsdPsDFoy+mXaqQkCtn+N4e3oT5hFmd4R+pOsKY0DF42JgIZERm8M4l79hdMJYarNZ87P3fOdVwiqqWKjIiRpbD9/IwEOrvTZCvF6NCfDlSUkddcxt//CSbaYmhvRqgm0gI8yM6yMdccNnS3sHr3+WyJsv5ncmcPcN/Sko5zfiz1snvZZXIQG8aWjv45lgFnx8oobmtg50nq/A0CDLi+3b4E8JV2fihSusSxiOCoBgll5xr1EcZs3jg50pdqFIznRHWOfGVkmnO+ar/BuzOJHezUhOddLl6ffZ90NGi+gTQFc7JiMjoFdIxzfxHBXQ5/BkxM8yvXZWhY6KvatsjVUf6DOcMlFDfUMJ9w62GvaxhqtQdaTN8S8bFBnG4uI7nNh6nvL6Fhy+dZF4f7IkQglkp4ezIreKjvadY/PhG/vfDA3x+0Pm9h0/7kM64mCACvD24cW4yrR2d7CusYXtuFZNGBePv3XdBR2pIKr4evk6Xf3U68+8FYQzJhKUO/Dwm1UzT4u9Qcuxz8A6C6TfA5qeg1AU3WSlh/cMQNApmGlNfI8eqb0k7X4PSbA5XHSbEJ4Q5cXPIr82nrbPNfLip14LlDN8gDNw46UbmjZpHsHffk4vhwFrxVXlTORXNFUPu8EH9/9g7w99atBU/Tz+n2DFcpMcEcbysnle/yWHFtFFMTQy1OX5mchiF1U3cu2o3kUE+/N+tc3jqmgGsrzmIsx3+3UKILCHEq0KIMGsDhBA/FELsEELsKCsb+vz38ybFsvc35/GTpeqP6Ztj5ezNryazn5aFHgYP0sPTR77DD0uBpb+Fcx7sO43THiLHQWDM0Dn8zk6oKVSO9ujnMGaR6twFauF0uDm8Fgq2waKHwKsrH51zHlQ3o89/bZ4Njw4dTbts75a6a3L4PTNZrptwHS8se2FYLsEWMQExnKo/RafsNG8zhaicURCWGpLKiZoT/UoJdHR28EXeFyyIX4CXx+BUaV1JWoySO+/olPxsWXq/45dMiCY5wp+HLhzPB3fO5+y0yGGRex6UwxdCrBdC7LfyswJ4DhgDTAOKgCesnUNK+aKUMlNKmRkV1Ufu+SDx9DAQbtSt+c/WPFraO5mVYvX+042JERPJrszu9k9iD2WNZWzM3zhAa53A/Hu7OmENFCEgZYEKDw1FHH/fO/DURPjid6qga+wyle9v8OxdIexsSg7CR/eom9q067rvC4iAhT+j8+g6jlZkkx6WzugQVTVpOYM91XCKCN8IfD19h9Nyu5kVM4va1lp2FKtissa2RnNT8LTQoXf4o0NGU9NSQ2Wz7YXJPWV7qGyuZFnysiG3YTgZb2yB+v3ZSSRF9J9plBwRwFcPLOaOc8Y43E1vMAzK4Uspl0opM6z8fCilLJFSdkgpO4GXANcKWKN0a0qNHaZmJvdfBDMhfAKN7Y2crHWs+cff9/yde7+8l4Y21+pmDDmpC6C+BMrty76wyUljjcNmoy5Q2jLw8FLyEUNx/r7o7IQvfg87/qleV+XC65eqxe1r3wSP3mG+z2PT+FFCEk2drYwLHUtKcArQw+HXnyI+MN55dg+SxUmLCfAK4OMTH1PdXM11a69jY/5G7pt5HxF+Q5whBlZvitZYf3I93gZvFiQsGHIbhpNJo4J5cuVU7j+//9m9K3Fmlo7ld9vLAec2v7QDUzpUSoR/LxEza5iKQB746gGe2fUMTe39pw12yk425m9EIq0W54xohjKOX7gLEs9S9QLJ8yHYGPuOHOe8Gb6UsPZ+2PQXtRDb2Qk7/6V0c278CCKsL6w+suNPnPAP4saaWpa2SAK9A4n2j+7l8C3j9+6Gn6cfS5OWsu7kOn797a/Jrc3l+aXPc0tGP/UcAyQ1RK0X2Vq4lVKyPm8980bNc+sCK3sQQnDFjIRBN0tyNs6M4f9ZCLFPCJEFLAaGr+tDH5h0a/qL35tIC0vjjql34O/lz8v7XuamT27qt5hkf/l+KpqV+JpJS8Vebv3sVl7d/6pDx9iio7PDqgTAgAlLVdLLg3X4rY2qEUvqArj9S7j+/a59Uekq37994CJcfbJ3Fex4BUZNV99UirPgyGeq+jjK+oJhS0cLlc2VrJx4Aw/UdxBkzHhKC0szr+90yk6KGorM/WPdlUvGXEJDWwMb8zdyz/R7uomlDTWxAbH4efrZnOFvKtxEcUMxS5OXOs0OTXec5vCllDdIKSdLKadIKS+VUjo/ybQfEsP9uGvxGG6am2LXeIMwcNe0u3j9wtd5dsmz5NXlcfcXdyOlpLihmN9++9temiEb8zfiITwwCINDM/yOzg52lexid+luB67INm8feZuL3r/IrGk+aMxx/M1qdjxQirNAdkD8THVOL4u4d2S62ueMIq/CXeATAt9/W73e8SqUHoBxfWvUlzaozJaYwDjVGezYlyAlM6JncKz6GDUtNZQ3ldPW2UZ8gPuGdAAyYzKJD4wnMyaTmybe5NT3MggDKcEpfTr8ts42Ht/+OCnBKVyU6pISnTOS0z4t0xIhBA+cP57JCSEOH7swYSEPznqQw1WH2V68nef2Psd7R9/rpQy4IX+DOf/akaKtiuYK2mX7oJtNW3Kk6ghVLVVDK/ecuhCaKpWjHCiFO9XjqBm995lm2s6I49fkq14BgdFqlr/rdbV93AV9HmLq5RobEAtjzoWaPKg4zvTo6QDsKd1jNSXTHfEwePDWxW/x3NLnbBZaDRVjQ8eSXZltNVPnzew3ya3N5f7M+0d0ds5I44xy+IPlotEXEeYTxjO7n+GjYx8BcLKua0H3VP0pjlUfY1HCIlJCUhwK6ZhCRf21onMEU971kMo9pxoX13KsN7u2i8JdEJygCsN6EmHMGCl3Qhy/pkCFpADSzgOkClNF9F0Fa/q9xPjHKIcPcPwLc2OOnaU7zTd2d3f4ACE+IcOWSTQtehoVzRXk1XVvt9na0cpLWS8xN24uCxMWDostGoV2+A7g4+HDVeOuYm/ZXhDgbfAmr7brj9lUiTk1eiqpIamcrD3ZZ0rny/te5nBll1MzOfrK5spBNZGwxOTw+2tg3ROb+kEhCSqTpr84fmdn3+mbhTshfrr1fT6B6mZQ5oQZfnV+VzewtPPU47gLbNYnmH4vMf4xKm00fDQc/xJfT18mRUxiV8kuVmWvIiU4xZy9o1HMjJkJwK6SXd22f5n/JVUtVdw06aZhyT3XdKEdvoOsTF+Jp8GTFWNWkBKS0m32YkrfTA5KJiU4heaOZqshmlP1p3h619M8tesp8zbLxeChmuWbZ/iN9s/wWzpauOKjK2zL26YsUGmVfXXAamuCf8yBz37Ze199KVTlqPh9X0SNG/oZfnMNtNSoGxaocNK5v4a5d9o8rLihmGDv4C4VxzHnqm83HW3MiJ7B3rK9HKo8xC0ZtwxLmGQkMTpkNKE+oews2dlt+7tH3mVUwCjmjprrIsvOXLTDd5DYgFjeveRdHpz9IMnByd1m+Hm1eQR7BxPqG2pOS7MWxzf9A3xb+K05/mt5YxiKOH5rR6u56MWRG8jrB17nRM0J24vHKQtUk/SSPjJtNz+lYvA7X4PmWpVmueU5NeM/pEJh5hm2NaInQmk2tDXbbXe/VBurYk0hHYMBFt6vJCdsUNLYo9NT0lxoa4Cyw+Y4frR/NMtHLx86W08ThBDMiJ7BrtKuGX5+bT5bi7ZyedrlGIR2P8ON/sQHwJjQMfh5+pEUlERBXYE5C+Zk3UmSg5OBrjzknNreDn9X6S5zO7kPjqk2hMWNxeZmzUMxw7eM29sbwy9rLOOlfS8B/RTMJBpr6Aq2995XeQI2/1UtirY1wO5/w1s3wKcPKU3+/R+oTJzoiX2fP+VsJVpm7fwDpcbYYagfB9+TkoYSc8coAOKMLfeK9jAjZgb+nv7cNvk2vD36aEl5hjMjZgb5dfnmb5sfHv8QgzBw2djLXGzZmYl2+IMgOTiZdtlOUb3KOM2vzScpWDmUCN8IAr0Cu0nqmthZspNZsbOYFz+P94++T3unys4ZH6bazPXn8F/b/xpP7XzK5hjLuL2tkE5pY6n5hvVC1gu0dbZx1birKG8qp661jwYNoUkQEK16vna0wYuLIcuY6vjdP5Se/Pf+o5qtfP6/KjzjHaSen/xGqVHait0mzwNh4MiR1ZQ3ldu8Trup6THDt5NeM/zwMeAdCEV7CfEJYcPKDVw7/tqhsfE0pGccf3PhZqZGTbVbalkztGiHPwhMzv1k3UlaOlooaigiOUjN8IUQzIiZwXtH3+MHn/7AXHFY0VRBTk0OM6JncMXYKyhtLGV36W6KG4tJDUklyDvIZnFXa0crL+57kVXZq7qpNfbEdNOID4yntMn6ou3aE2s5/93z+dO2P9HQ1sDq46u5KPUiFsSrTJw+s4yEULP8gm1KW+fUrq62gEV7IX6Gqpyddatqfj7xMlj8CyjeB0jVb9cWviGcisvguqJP+ct3v4fXL1NNXAZDdZ6STwiwX6/JVHTVbYZvMKgm8UaBt5HUockVjA8fT4BXAJsLN1PTUsPBioPMjdOxe1ehHf4gMHUJyqvNo6CuAIkkMbhrBvn4wsd5IPMBjlcf5wef/oDDlYfNsfGZMTOZN2oeHsKD7059R1ljGbEBscT4x9iM4W8u3Exdax1N7U1kV2T3Oc5UMJQRmWF1hr/6+Goe2vQQ3h7evHv0XV7KeonG9kZWpq+0GY4ykzBLhW+2v6JelxxQmTmlh7rCNZNXUnb2T3gqKZ1fteUh/SMgepKqpu2HP4X40SwkBwq+UaGgo5/3e4xNavLVgq3B/j9502fYazYaN1XdvFzdrGUE4GnwZFnyMtbnrefrgq+RSL1Y60K0wx8EkX6R+Hv6k1eX1y1Dx4S/lz83TrqRf1/0b7w9vLl+7fU8tu0xfD1USl+gdyCTIiaxNmctHbKDGP8YYgJiKGksIassiz9s+UMv/Z61OWsJ9AoE6JX9YElpYyneBm/Gho6luqWalo7ufX1f2vcSEyIm8M4l72DAwCv7XyE9LJ0pkVNICErAU3jariMwxfGzPwYEVBxVP611EDMJgOLWai4u+ZRXD6/iw5w1lF/9Clz5cr+f66aCTXzZXER8Wzu5soV6IaBskBr5ljn4dmIquooJ6FEvEDcV2hqhvHe4TtObS8dcSkNbA3/d9VcCvQJHdKOTkY52+INACEFScBIna0+as3VMYR5LkoOTef2C17k87XLCfcNZMXaFubpwVuwsc7ek2IBYYv1jKWks4YkdT/Dm4Tf56cafUtlcyfbi7ewv38/G/I1cPPpikoKS2Fna3eF3yk7+56v/4Z0j71DaVEq0f7Q5HGE5y8+vzSenJodLRl9CUnASK9NXAirlVAiBl8GLhKAE2wu3cdOUlDGopuqyE/Yb+78aHf53p76jsb2RH0/9sXpf/xCIsbFYa2TdyXWE+YTyYJVqRXkoNl1l7QwGyxx8OzGF1mL9rczwwTW6/SOQmTEziQuIo7SxlFmxs8zJCZrhR3/ygyQpKIndpbtVOqZPKCE+1mUb4gLj+MWcX/TaPjtuNq/sV2ERU0invKmc8qZyMmMy2Vy4mXPeOqfbMctHL6e5o5kN+RvolJ3m9LbPcj/jk9xPyCrPIsY/hmj/aKL8Vcy6rKmMhCCVg/51oSqaMlU53jH1DoK9g7l0zKXm9+i3Y5G3v+pzW34U5v9E6dubFm6jVXvIvWV7CfYO5sLUC3lu73Pk1+UzI8aKnEIPShtLSQhKZPKsC+HkKg6FxzPr+A6V1jmQQp32FqgvhhAHM3RMRVc9Z/iR48DTD4r2wNRroKVeLUzbqi04gzEIAxePvpiX9r3EWXFnudqcMxrt8AfJlWlX8kXeF6zNWcuUqCkOHz89ejqeBk/aO9uJ8Y8xx4u9Dd48tegptpds50T1CSZFTqKutY72znamRk0ltzaX/x77LyeqTzA2bCytHa08vetpfDx8KKwvpKSxhGVJy4jyUw7fMmvn64KvSQlOMX8bCfEJ4cfTftzNrpSQFDYXbqa9s73vGdniX0JjhYrZe/mrgqrQZPBRzSD2lO5hStQUEgITMAhDtw5RtihtLCU5OJnIRb8g+p0vOOgpVOFUXTEEO6hIWZ0H21SqqbnoyoID5Qd4fMfj/O3cvxHkHdRtX0FdAaE+oeYUWjMenpA0R523o1Upbtbkw482QZzjfwNnAivTV3Kw8uCIb3Qy0tEhnUEyL34ev5+vGm8PpLTez9OPqVFT8fXwJcQnxByCOT/lfEJ9Q1mWvIwfTf0RZ8efzYWpF3LJmEsQQjAzWs0mn896ng15G/j5pp9TWF/Io2c/irfBm/bO9m4hnVP1p3huz3Osy13H9uLt/WqYpAan0tbZZi4Ms8q482DatWoh1LRQawzn1LbWcrzmONOipuHl4UWsfywF9QV2fSaljaXmG9XEiIkcbFOhHYfi+J2dqtjr2Vnw7d9g7FL104NPcj5hZ8lOqx3KssqzmBQxyfr5r3xFhbK2v6xudsIAh1bbb98ZRmxALM8vfd78jVPjGvQMfwi4ZMwlRPlHkRjkWIzYxC0Zt3Cw4iBCCCZETCAjIoObM262eUxCUAJXpl3Jh8c/5LPcz/D18OWmiTdxXsp5fJLzCevz1hPtH02ITwheBi9eyHqhWweufh2+RQMLa+sSvYjNgMIdZsefVZYFKF0hgMSgRLtm+M3tzdS21hLtHw0oh/9V/lc0CEFAaXaXgFl/bHoCNjwCaefD8r/0WXC1u0xlTX2Z9yWXjLnEvL2utY5jVcf6npEGRMLlz8PCB9Ri8OsrIHsNnGtFTkKjcRO0wx8iBhObXJiw0OyAw3zDWHXxqn6PEULw23m/5b6Z93Gw4iBTo6aac8IvTL2Q9XnriQmIQQhBtH80hfWF3Db5NtLD0smuzDYXxPTF2FClIHm06iiLEhf1fxExxswL46Ls3rK9GISByZGTAXWD2pC/od/TmBaXzQ4/fCISSXZwJDMdmeEfXQfxmfD9t/qM+ze3N3Ow4iCewpPNhZtpam9izYk1aiG9rhCJZFrUNNvvY+qSNeFi+OwXKlU1fLT9dmo0w4h2+COcEJ+QXnnNS5KW8Pv5vzc76rmj5tLa0co90+/BIAxckNq3/ruJQO9A4gPjOVxlp4jZ2KWQOEfp7AC7S3eTFppmbl2XGJRIZXMlDW0NNtvZmRZKTV/9p0ZNRSDYGhbDzNJsdhTvwMfDh8lRk/u2pb1VZdDMvt3mIu+BigO0d7Zz3YTreOPQG9z75b1sKdrCnLg5zIie0e2G1S/jlyuHf+hj1TReo3FDdAz/NMTD4MFlYy/Dx0P17f3N3N/wh7P/4LBY1biwcWbJ534JT4Vb10FgNKuyV7G1aCvz4+ebd5syhPoL65h0f0xrD6G+oUyJmsLXXtBWls3PvvopD3/3sG1bSvYpLZ6EWTaHmZrX3JpxK8HewWwp2kK0XzRbi7ay+vhq0kLTCPQOtP1eJsJSIGZy7zh+yQHIese+c2g0TkY7fE2fpIenc7L2JM3t9qtWrjmxhke3PsrixMXcPe1u83bT+kZ/Dt+UTWS5uLcwYSEH2mv5r3cHlc1VHK46bFYCtUrBDvWYkGnzvfaU7iElOIUo/yium3Ad5yScw6qLV+Hn6UdBfQHTovsJ5/Rk0golN1FtcY0bHoUP79RVuRq3QDt8TZ+MCxtHp+zkWPUxu49558g7jAkZwxPnPNGtdZ0jDt/Xw5cgr64USdP6xhPhYXgKpTm/rXhb10EbHoW3ru96XbAdguIguO8es1JK9pTtMTv1O6fdybNLniXaP9pcjzA1aqodV2xBxlXq0VSA1tmp+v92tHaJt2k0LkQ7fE2fpIcpzZueYZ395fu5+dObezVwb2xrZG/ZXhYmLOzVpzTIO4hQn1C7HH60f3S3TkjpYelE+4TRYDBwTdRsAr0C2Vq0teugY+tVKCVvi3pdsEPN7m3E73Nqc6huqTZr2ltya8atLEteZhaRGPKVUgAAHXdJREFUs5vwVLVQvP9d9bpkHzRXq+cV/dw060pg45+U+qhG4yS0w9f0SUJQAn6eft1aMQJsKtzEzpKdHK/urmC5u3Q37Z3tzImbY/V8KcEpHKw4aPM9SxtLe+VqCyFYMEqtB1zul0hmTCbbirYhpeRQxSFebSlgnb8ffPM0NJQbO2qpcM47R95he3FvXX1T/N5a2CYuMI4nFz1JqG+oTVutMvkqJaxWdrh739/+1D6z3oSNj8LBDx1/T43GTrTD1/SJQRhIC0vrNcM3iar1bE69tWgrngZPq7NmgKXJSzlYcdCmZINpht+TH02/h0cq60lvbmRO3Bzy6vK4bd1trPx4JU8F+fDbqEjaDq9VUsoAyfNp62jjsa2P8dddf+11vt2luwn1CSU1ONXWR+A4ky5XRVjf/k1JR4ePAZ/g/mf4Jl0eU1WwRuMEtMPX2CQ9LJ3DVYeRFg3JTcqglu0dAbYUbelWD9CTi1IvwiAMfHziY6v7pZSUNZUR7dfb4ccFjWKFVxRU55lrHrLKsvhp2vf4dXkldQbBnsAwFUK54mVInMWRqiO0draSVZbVSyJ6T+kepkVNG/om2kGxMPdu1enr6OeQukDl6vfr8LPA4AX5W4x9AzSaoUc7fI1NpkRNoa61juxKpVYppexy+BYz/OrmarIrs20WoEX5R3FW3FmsObGGto62bvo+oOQYWjpa+i6/D02EmgLGho3l8XMe5/1L3+cHoRksr2/AU3jw9bxb4Z6dMOVqQBV/mbAs+qpqriK3NtdcBTzkLPkNJJ8NskPVJUSMte3wW+rU/tm3g6evkmvQaJzAoBy+EOJqIcQBIUSnECKzx76fCyGOCSEOCyHOH5yZGldxdvzZCARfFyiFzYrmCurb6oHuM/xdpbuQSGbHzrZ5votHX0xhfSEL3lrA+e+ez4nqE+Z9ZnVK/xjrB4ckmrNdLki5QDWbqcwhQEpmRc/gq9Lt4OljHp5VnkWUXxRJQUl8mf+lebspft9X6GnQeHjC1a/B2T+F9AuVw6/OV03Za4uU6qclxfsBCannQMaVsO89aGuydmaNZlAMdoa/H7gC+NpyoxBiIvA9YBJwAfAPIYz5dJoRRaRfJBmRGWaHb5rdjwoY1W2Gf7jyMAZhYELEBJvnW5K0hNmxs1mcuBiDMPDGoTdoam/ils9u4ZrV1wBWOkyZCElQ6pytFtlBVbngH8E5yUvIqcnpdhPKKstiStQUzk06l61FW6lvVTeq3WW78TR49i2MNhQERsHS34B3gHL4SBXmeXJC7+KsYqU7RNwUmLJSNZE58pnzbNOcsQzK4UspD0kprdXerwDelFK2SClzgGOA7amfxm1ZmLCQfeX7qGiqMDv8BQkLqG6ppqZFKVlmV2aTHJzcW0q4B/5e/rxy/iv8ccEfWT56OatPrOaxbY+xvXg71064lkfmP9K3nIFJAK3GQnWzKgfCUlgYr3L1V2WvQkpJVXMV+XX5Zoff3tnOmhNr6JSdbCrYxMSIifh6+g7ug7EXk97Oul8BsncmTtFe1Ws3KE6FgAJjVH8BjWaIcVYMPx6wTLguMG7rhRDih0KIHUKIHWVlvXuvalzPwoSFSCSbCzeTW5uLl8HLHKs35dUfrjrM+LDxDp33ugnX0dTexPtH3+fqcVfzP7P+hxVjV+Bh6OPLoEnPvsZisbgqF8JSSAxO5NIxl/J/h/6PhzY9xLrcdQBMiZzCtKhpTI+eznN7n2NV9iqOVR/j2vHXOmTroAg3Ovz2ZlUMduzz7vn2RXtVY3QhwOABk65QC75N1cNno+aMoF+HL4RYL4TYb+Vnha3DrGyTVrYhpXxRSpkppcyMitJa2e7IhPAJRPtFs+bEGnJrckkKSjJr/+fV5lHbWkthfSHp4f03J7ckPTydeaPmERsQy30z7+v/AFNPWtMMv6NNxcbDVGrlI/Mf4e5pd/NJzic8svURPIQHEyMmIoTg/sz7qWiu4LFtjzElagrLU5c7ZOug8A1Wjj52Cpz/qGrmkrcFTn4Lq/+favweZ7GAPPlqpQWUbT2bSaMZKP2qZUope3eN6J8CwFIcPgGw0UlD484IIbhp0k08vuNxvAxeLIhfYBZDy6vLMxdmjQ93bIYP8PTip2nvbLdPpCwoDoRHl1ZNTYHKhAlLMdv5o6k/4pIxl7A2Zy2+Hr7mFNEpUVO4IOUCPs39lAdnPTj06Zj9ce0q8I8E3xDw8Iav/gT5W1WrxNGLYOr3usbGzwD/CLV/+vV9nVGjcRhnySN/BPxHCPEkMApIA7bZPkTjzlw34TrW561nd+lukkOS8fX0JTYglrzaPLPcsaMzfMCxOLqHJwSP6tKlqTIWcIV3L54aFTiK2ybf1uvwh+c9zI0Tb7QtrewsLGfwKQvg+BcQmQ63fAr+4d3HCqH65pbbr2Gk0djDYNMyLxdCFABzgTVCiM8ApJQHgLeBg8CnwF1SSi0XOILxMHjw+/m/J9w3nBnRqhF5UlASe8v2srt0N5F+kUT6RTrfkFHTVZZL8X5VlSo8lHO0A38vf9c4+57Mvl1dx/Xv9nb2JiLGQsXR4bVLc9ojZM+cYBeSmZkpd+zY4WozNDaQUprDIRvzN/KTDT+hQ3YwP34+zy993vkG1BXDCwuhuRbam+DCx2HOD53/vsPN5r/C+t/Agychfxvkfg3nPeJqqzRuihBip5TSth44utJW4yCWse9FiYv488I/4yE87O8MNViCYlVRk+yA2T88PZ09QGSaeqw4DttegG+fhdYG28doNP2gWxxqBsV5KecxIWICUX7DmGGVPA8eOKZEyU5XIlRPYcqPQP52QCoFzvgZLjVL4yS++wcExynxPSeiZ/iaQZMYlDh8RUwmfENs6t2PeMJSlepm9sdgLG6j1IEm7pqRxbfPwJF1Tn8b7fA1GnfE0xtCk+HIp8YNAkpt9xLQjFBa6qCuCCLHOv2ttMPXaNyVyDTobFdSCzEZeoY/WD64Aw5+5GoremNSUo1Ic/pbaYev0bgrpjh+4hyImQhl2a61ZyTTWAl7V8G2F11tSW9M9RaR2uFrNGcuJoefdBZET4DaQq2vM1BM4bC8LdBS71pbelJxFBBmiRBnoh2+RuOuJM5R0gtjl0L0RLVNz/IHRonR4Xe2qdaT7kT5UaUE6+X8xAft8DUadyU2A35ZBFHpaoYPeuF2oJQeUJldXgFwbL2rrelOxdFhCeeAzsPXaNwbU+ppSCJ4Bxq7Y2kcpuQgxEwGn0A49oWrremis1MV1yWfPSxvp2f4Gs1IQAhIXah0hCy19DX9I6XKcIqeoMJjVTnKyboDdaegrXFYUjJBO3yNZuQw4yZoKIXDn9h/TPlReGqye81qh5uafNU2MmYijDlXbTv+pe1jnE1HO+x4FU5+p14PQ0omaIev0Ywcxi5VjVR2vmb/MYW7VIewt643SjScgZgWbKMnqXaTYSmuj+Mf/xI+vg/ev129HqYYvnb4Gs1IwcMTpt+gnEVVrn3HmHoHBETB2zeomPGZRukB9Wha+B67FHI2QXuL62yqNIaUIsdBcIJq7jMMaIev0Ywkpn0fkJC9xr7xNfmqe9biX6ry/eK9TjXP5VTm9L4ZlhxQi96+RrG9MUugrUHl5LuKyhy1CH/nd3D3tmHThdIOX6MZSYQlq4KsExvtG19ToJq/j16kXtt7nKvZswr+kg4N5fYfU3JA9Up4s0dbyPztED+z63XqAjB4qa5joLRstjyvHoeLqhzVqc3gAd4Bw/a22uFrNCON1HMg9xv7snVqCtTsNihGFW8d3+B8+wZL/nZYfS/UF6vmL31Re0pJJoC6zjeuVk67ZB9U53WNqclTRWwmfIJU9fL+D9SN5eVl8OmDsOvfzrumnlTmDEtlbU+0w9doRhqjF6mQREE/3eGk7HL4AKMXqzBGW5OzLRw47S3w9o2q0Q0CirPU9oZyaG/tPu7FxfDsLNXq8uWlqgva1f9U+w8bVUZNNwxLhw8w924lO/3fO9SNxT8C8r516qXR1qxs7OxQYadw7fA1Gk1/pC4AhApJrH0ANj1hfVxTFbTWq5AOwJjF0NECed8Nm6kOU7xf5aYv+50KXRVlKUf/99mw7ldd4w5+pBy1hxesvV+FaG79TDUQiRjbJSudvw08fSG2R0e29AvggRNw2xdw1zZIO0/dDJ3Z8vWTB+CV85QmUmcbhI923nv1gXb4Gs1Iwy9MNUHf9KRSf9z4GNSX9R5XU6AeQ40z/OR5xti1G4d1Cneqx4TZEDdFzfDzt0BjBez+d1cIZ/tLymHesxMufgpu/xJiJql94y5QejktdZC/FUbNUP0FeuLhCQmZEBitQjwNZc4tyDq+EcoOwVFjoxMd0tFoNHYxdklXX9+OVtj5z659taeMsWujwzfN8L0DIG6qys13Vwp3QmAsBI+C2CkqyyjrbRAeqiJ11+tQtFc58lm3q2vKvAUCLVpspl+oPpNtL6qxibP6f9+keepxKL/9SAkb/ghlR7rWEkCFoMAlM3ytpaPRjEQW/AzSzlfOrPIEbH9ZNUnZ9S81gwxJgLPuUmNNMXxQoY0D7ytn5I4tIgt3qowaIdTNCWDvm+rbiTDAt3+D7/6uRNCmfd/6ORLPguT58MXvjK/nWB9nSWQa+IUrhz/jhqG5lrLD8NVjKl6ffoHa5umnFE89vNVNbZjRM3yNZiTi5dc1c51zB9SXwJvXwqndkH6RylLJehM8fFTRlYnYDGiu6Zr9O4uBFDU1VSvlSFOjdpPD72xTxVLz7oXGcuWcb/4Y/EKtn8fDE25aDef9AVIWQIodwmRCQNLcoZ3h5xvz/LPXQM7XytlPN6aMhiarlMxhRjt8jWakM2YJLH0YVv4b7jsAV74M3kHK+YckdJ/Jx05Rj8X7urbVFUN96dDZk70WHkty/JyndqtHU868f7iqQgXl8NOWws8Ow81rum4KfWHwgHl3qxuDb4h97588T31bqj3lmN2WtLeoEA4YM4SE0vHZ/X/K5vQL1T4XhHNAO3yNZuRjMMDZP4GJl6qsFS8/mLhC7TPF701ETwQElBhllo9+Dn+bCe/dNnT27F0F7c2ON2spNKaZjpretS1+htIPMi3IBsU6LxQ1+hz16GhxWu43UGq81m0vwj/OUou/eVtU9o9/pFpTSJytQk0+IV0yD8PMoBy+EOJqIcQBIUSnECLTYnuKEKJJCLHH+PP84E3VaDR2M2WlegxN7L7dJ1DlfxdnKdXN/1yjFkMLdw6Nzk5bU5cwWXW+Y8cW7lKqkZahmov+osIzw7HeED1Jhb8czWL674/h04fU87wtajF942NKLyd5Hky6TO1LnKO6Wt3xNSx8YGhtt5PBLtruB64AXrCy77iUctogz6/RaAZCygK1qDt2We99sZOhcLfKeY9KV7LLnz6owhmD1WU//qW6gUCXcJu9lBzoLoEAqkKYmMHZZC8GgypqO7FR3fwMdsyHpTRW/FYoyWNTWum+t9Vj0lngd6FaMzGtJYSlDL3tdjKoGb6U8pCU8vBQGaPRaIYIgwGue7trdmlJzGSVIliVA0t+o2ahAEV7Bv5+lSdUDP7gRypmHhDl2Ay/tUEtNLso1GFm9GLVc8CksNkfjZVqUbm1Ho59rgTqJl2h9nl4Q9w0dVP9/ltK0sHFODMtM1UIsRuoBX4lpXSzzsEazRmKqeo0cQ6MO19p8nh4qzDP5KscP1/5UaO0QbV6PeV76gZQfdKxcyCVc3QlYxarx+MbelfnWqO+uOv5d39Xj2fdqW6mPkHD0pjcEfqd4Qsh1gsh9lv5WWHjsCIgSUo5Hfgp8B8hRHAf5/+hEGKHEGJHWZmVakGNRjO0JM1RlawX/FHFxj291cy6aC+0NjrWUauhHN64CgyeKt6ecSXMvVOtHTgS0ikzBgqixjt2LUNN8CiITO9S0uyPOguHn7tJVTLHToYbPoCVrzvHxkHQ7wxfSrnU0ZNKKVuAFuPznUKI48A4oJfak5TyReBFgMzMTCcKWWg0GkBJM9z2efdtcVNVv9x1v1St927f0H/qI6hZbXU+3LpOyRTMNnZwCklU4Z3ODvvyzcuy1U3DRemK3Rh/EXzzjArX+IfbHmty+PGZKssoNkPN6t1sZm/CKWmZQogoIYSH8floIA044Yz30mg0Q0DcVCW2tuNV9dre1MRj69XCZEJm9+2hSSq2bTkDtkXZYSV65uFlt8lOY+JlKtPm0Or+x5pCOqa1klF23CRdyGDTMi8XQhQAc4E1QojPjLsWAllCiL3Au8AdUsrKwZmq0WicRpwxoc4/Us2yc77q/5j6UhX3H7uk977QJPVoLazTUg/fPK3y102UZbs+fm8ibqrKpDn43/7H1hWrvPq089TrpLlONW2wDGrRVkr5AfCBle3vAe8N5twajWYYiclQseezf6oqRHf+U+m3WwtNVBxXmTjHv1Svx1hx+Cb9nuo82P++KjqafBUc+Qw+ukdJQcRnwu1fqPepyhnYgrEzEELJLH/zDDRUQEBE32PrilXqaFQ63LlFxf/dGC2eptFojAVBm43P/WDrc1CwDVIXdh8nJby+QmX1RIxR6ZcmuQZLTAVfO/6pGotse1EVJe38p1ogTl0I+95Vi751RSA73WeGDyqss/kp2PQXOP/Rvgu/6kuMzVpwfUqpHWhpBY1G053k+UqO+ISVsE71SRWmqTyuVDnHnGu9QMk7oKuLVEiiKjra/hIkzIKb18LcuwCppB3cJUPHkripqiBtyz/g/dv7rkKuK1JyziMEPcPXaDTd8Q1WGTo5X/fel7dVPc67F759pksMzBohiaoCdd69Ssr4wAeQcYW6GcROhcAY1ZmqoQx8Q9WirbsgBFzytGqO8vXjMPPm3qqbUkJdibEaeGSgZ/gajaY3CbPVgmxHe/ft+VvAJxiW/lYpc060UslrInKcCvlMv15p+My4QTl7UN8K0pbBwQ/h5DeqpaGnj7OuZmAIAfPuMX7b2dh7f1OVahkZFDfspg0U7fA1Gk1vYicrxcvKHi3/8raqsIzBo7f0ck8ueEy1HvT2t74/7XxAqhDS9CFqOjLU+IYofR9rgmr1JeoxUM/wNRrNSMYkK2Cpm99UDaUHVd69PQREdKVnWiNtGWTeCiuetU+ozFWMWQyndqkZvSWmGgM9w9doNCOayHFd+jomCrYD0n6H3x9efnDxk+5RXWuL0YtVFlFODzkws8MfOYu22uFrNJreeHqrrBnLGX72GhXP7ilhfLqTkAnegXCiR1jHVGWrQzoajWbEEztZaeaDcvY7/wmZP+haeD1T8PBSOvm7/g3/vRNqi9T20kOq8blPoCutcwjt8DUajXViJytt+Nxv4IMfq9aD5z/qaqtcw/InVWrm/vdgzc9UdXD2WiW0NoLQefgajcY6poXbN64CL3+4+l/ulzo5XATFwPK/qBqFzU/B9pdVc/KMK11tmUPoGb5Go7FOTIZ6lBK+/zaEJbvWHncg81ZAwPrfqBqDlIX9HuJOaIev0Wis4xcK5zwE1/4HEs6whdq+CImHCZdAZ7sqOvMYWUGSkWWtRqMZXhb/3NUWuB/z7lWqn9Ovc7UlDqMdvkaj0ThCwkz4ZZHtKmM3RYd0NBqNxlFGoLMH7fA1Go3mjEE7fI1GozlD0A5fo9FozhC0w9doNJozBO3wNRqN5gxBO3yNRqM5Q9AOX6PRaM4QhJTS1TaYEULUAYctNoUANQ6cIhIot3Oso+d2xXhb16PtH5qxjo6PBNqceP7hHG/v/4s72W9rrLXrcSfbHRlvuhZ7xkcCAVLKqH7PKqV0mx9gR4/XLw7m+H7GOnruYR9v63q0/a65VmDHSPjs7Rlv7/+LO9lva6y163En2x0Zb7oWe8Y74vfcPaSz2o3OrcePnPHuZIseP7Tj3ckWdxxvE3cL6eyQUma66nh3Y6Rfz0i33xqn0zWdTtcCp9f1OHItjox1txn+iy4+3t0Y6dcz0u23xul0TafTtcDpdT2OXIvdY91qhq/RaDQa5+FuM3yNRqPROAnt8DUajeYMYcQ5fCFEvattGCqEEB1CiD0WPyk2xi4SQnw8fNbZRgghhRD/tnjtKYQocycbB4oQ4nLj9Y13tS0D4XT+3cDp5QNM9HdNQoiNQohBL0iPOId/mtEkpZxm8ZPraoMcoAHIEEL4GV8vAwodOYEQwl07rl0LbAa+58hBQggP55jjMIP+3WhOT0akwxdCBAohvhBC7BJC7BNCrDBuTxFCHBJCvCSEOCCEWGfxRz8iEEJ4CCEeF0JsF0JkCSF+ZLE7WAjxgRDioBDieSGEq39/nwDLjc+vBVaZdgghZgshvhVC7DY+phu33yyEeEcIsRpYN/wm20YIEQjMB27F6PCN366+tvbZCyHqhRC/E0JsBea6zvJeDOR3s0kIMc1i3DdCiCnDarWd9PzGK4R4Vghxs/F5rhDiYQv/MCK+qdm6pqHC1Q5joDQDl0spZwCLgSeEMPccSwP+LqWcBFQDV7rIRnvwswjnfGDcditQI6WcBcwCbhdCpBr3zQZ+BkwGxgBXDLvF3XkT+J4QwheYAmy12JcNLJRSTgf+F3jUYt9c4CYp5bnDZqn9XAZ8KqU8AlQKIWYYt/f12QcA+6WUc6SUm4fd2r4ZyO/mZeBmACHEOMBHSpk1bBYPLeVG//AccL+rjXEX3PUrdX8I4FEhxEKgE4gHYoz7cqSUe4zPdwIpw2+e3TRJKaf12HYeMEUIcZXxdQjqJtYKbJNSngAQQqwCzgbeHS5jeyKlzDKuO1wLrO2xOwT4lxAiDZCAl8W+z6WUlcNipONcC/zV+PxN4+s19P3ZdwDvucBOmwzwd/MO8GshxAPALcBrw2Ksc3jf+LgT10+M3IaR6vCvA6KAmVLKNiFELuBr3NdiMa4DGFEhHdTN7B4p5WfdNgqxCPXPaYk7FFF8BPwFWAREWGz/PbBBSnm50fFstNjXMEy2OYQQIgI4FxX/loAH6jNeS9+ffbOUsmP4rHQIh343UspGIcTnwApgJeDOVavtdI9Q+PbYb/IDHYwcP9ffNQ2akRrSCQFKjc5+MZDsaoOGkM+AHwshvEB9tRZCBBj3zRZCpBrjx9egFhZdzavA76SU+3psD6FrofDmYbVo4FwFvC6lTJZSpkgpE4Ec1GzeHT/7/hjI7+Zl4Blguxt/CwM4CUwUQvgIIUKAJa42aAhw+jWNKIdvzOpoAd4AMoUQO1Cz/WyXGja0vAwcBHYJIfYDL9A1Q/kOeAzYj3JEH1g9wzAipSyQUj5tZdefgT8KIb5BzZRHAtfS+zN9D/g+bvjZ98dAfjdSyp1ALfDPYTDRYUw+QEqZD7wNZKH8wW6XGjYIhvOaRpS0ghBiKvCSlHK2q23RnDkYw2n3SykvdrUtzkYIMQoV4hkvpex0sTm9OB19wHBe04iZ4Qsh7kCllv3K1bZoNKcjQogbUdk8v3RTZ3/a+YDhvqYRNcPXaDQazcAZMTN8jUaj0QwOt3b4QohEIcQGY/XsASHE/zNuDxdCfC6EOGp8DDNuHy+E+E4I0SKEuL/Hue4znmO/EGKVsSBFo9Fozhjc2uGj8lJ/JqWcAJwF3CWEmAg8BHwhpUwDvjC+BqgE7kXlHpsRQsQbt2dKKTNQmQkO6aRoNBrNSMetHb6UskhKucv4vA44hKqqXQH8yzjsX6hyeKSUpVLK7UCbldN5oqQMPAF/4JSTzddoNBq3wq0dviXGisDpqCyCGCllEaibAhBt61gpZSFq1p8HFKG0atxOuEuj0WicyYhw+EYFw/eAn0gpawdwfBjqW0EqMAoIEEJcP7RWajQajXvj9g7fKDHwHvCGlNIkiFQihIgz7o8DSvs5zVKUqFqZlLINJaw0z1k2azQajTvi1g7fKHn8CnBISvmkxa6PgJuMz28CPuznVHnAWUIIf+M5l6DWAzQajeaMwa0Lr4QQZwObgH0oGWSAX6Di+G8DSShnfrWUslIIEQvsAIKN4+uBiVLKWiHEwyjRq3aURsVtUkpLZU2NRqM5rXFrh6/RaDSaocOtQzoajUajGTq0w9doNJozBO3wNRqN5gxBO3yNRqM5Q9AOX6PRaM4QtMPXaDSaMwTt8DUajeYM4f8DiIx151a1nJMAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ts = pd.Series(np.random.randn(180), index=pd.date_range('1/1/2018', periods=180))\n", + "df = pd.DataFrame(np.random.randn(180, 3), index=ts.index, columns=list('ABC'))\n", + "df.cumsum().plot()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "### 7. Random dots in a scatter" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXcAAAD8CAYAAACMwORRAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJzsvXeQXNd95/s5N3QOMz15MAAGmUQmCYCkwCSRlCWRFq24lGRRDmutLcvrrXUob+17W659ta/83tZbl7csyyv52ZItW7KkJ0oUSYlikESKERkgkcMgzGDyTOd07/29PxqAQGBCz8ztifdThSKn+/S5v+6+99vn/s4vKBHBw8PDw2Nxoc21AR4eHh4e7uOJu4eHh8cixBN3Dw8Pj0WIJ+4eHh4eixBP3D08PDwWIZ64e3h4eCxCPHH38PDwWIR44u7h4eGxCPHE3cPDw2MRYszVgRsbG6Wzs3OuDu/h4eGxINm3b9+giDRNNm7OxL2zs5O9e/fO1eE9PDw8FiRKqfPVjPPcMh4eHh6LEE/cPTw8PBYhnrh7eHh4LEI8cffw8PBYhHji7uHh4bEI8cTdw8PDYxEyaSikUurvgUeBfhHZPMbzCvgr4ENADvgNEdnvtqG1JpMr0jeUpn8oxUimACJEQn5aG2M0J6LURYNzbaKHh4dH1VQT5/414K+Bfxzn+Q8C6678uxP48pX/Lggu9o7w1pHzHDvXd+0xw6jc0Ni2IFL5t7I9wd1bV7FmeSOapubK3AXH1TaOlTWAh4fHbDGpuIvIy0qpzgmGPAb8o1Su4jeUUnVKqTYRueySjTUhXyjz0lsn2Xv0An7ToKk+jKaN7aUSEfqG0vzzs3tZv7KJR+7dRNxbyY9JzhpmsHCckVIXmfJlyk4BTWkE9HrivuUkfGtIBNagK3OuTfXwWNS4kaG6DLh43d+Xrjx2k7grpT4PfB5gxYoVLhx6eoykcnzjmb0k03laG6LjivpVlFLURYPEIwHOXx7mb7/7Kp/+4B0sb62fJYvnPzlrkDPpFxkunEEphaFC+LQofq0OECwp0Z8/Rm/uEIYWYGXkHtpDt6OpOUuS9vBY1LixoTrW/baMNVBEviIiO0RkR1PTpKURakIyk+cff7iHXKFESxXCfj1KKRrrIvgMnW88s4eegWQNLV0YiAjd2b3sHfw7kqWLhI0WwkYLfj2KpgyUUiilYWoBQkaCiNmKoYKcTj3PweFvkLOG5/oteHgsStwQ90vA8uv+7gB6XJjXdRxH+OHP3yGbL5KIhaY9TyTkx2cYfPf5gxRKZRctXFiICGfTL3Eq9SMCej1BPVGVb93Q/ESMVnLWIAeHvk7WGpwFaz08lhZuiPtTwBOqwl1Acr762w+f6ub0hQEa68IznisWCZBM5/n53jMuWLYw6cnt42L2NcJG65R96EopgnoCQTgy/E1KTq5GVnp4LE0mFXel1DeB14ENSqlLSqnfVkr9rlLqd68MeRY4C5wGvgp8oWbWzgDLdnjprVMk4iHXIjeaEhH2vH2edLbgynwLiYqP/QVCRjOa0qc9T0Cvo+RkOJt68VpkjYeHx8ypJlrmU5M8L8Dvu2ZRjejqGSKbK9LaGHNtTl3TQODt05e5e9sq1+ZdCJxOvYCmDFeiXkJ6E735w7SFbiPu63DBOg8PjyWToXqiqx/DmP4KczwiYT9vn56XXqiakbOGGCmeIaC5Ey2klIaufHTnvPr+Hh5usWTE/ULPMOGA+7HVQb9J/3Aay7Jdn3u+Mpg/jlKaq4lJQb2ewcIxyk7etTk9PJYyS0LcHUcYGM0S8Lsv7pqmEIHkEvK7j5S7MNT0o43GQqnKqZizhlyd18NjqbI0xL3WKfAKbNupzdzzkHS5B1NzP0NXRMjbXty7h4cbLAlx1zWFptQ1kXcdAUN3358/HxFxsKWEojbv13PLeHi4w5IQd6UUjfVhCkX3E44cp7Jij0UCrs89P1GMnZQ8cwTQlsYp6eFRc5bMlbSitZ5cvuT6vLlCmdbGGIa+ND5KpRQBvQ5bijWYG/y6e6GqHh5LmaWhSMAtq1oo18Avns4V2bq+3fV55zNxcznlmmSUKkJGQw3m9fBYeiwZcV/ZniAeCZAvuLd6t2wHXVNsWt3q2pwLgYR/Lba4exdUdgr4tDAB3au06eHhBktG3HVN48FdGxhO5V1Lcx8cyXD31lWEQ35X5lsoNPjXYGh+VwW+6IyyPHzXjEoZeHjMBiJCNlMglczN6yi5JVVMe9PaVt4+08yZi0M0JyIzmms0nScRD3HP7atdsm7hoGs+VoR3cybzIlGjbcbzlZ08hvLTHLypi6OHx7zCth1e/PERDu3vQilFc2ucj3xyF9HY/Gves2RW7lDZDHz0vs3URQMMJbPTnieVLeCI8ImHb8NnLqnfx2ssC+8garSSn2E9dhGHgj3C+tgj+DR3E6M8PNzmwN5zHNh7jqaWOM2tcYb6Uzzz/fnZMnpJiTtUarH/+qM7qYsE6R1MTem2SkToH86AwBO/uovmhmgNLZ3faMrg1rpfQymNgj29piUiDhmrl2XhnTQGNrhsoYeH+3SdHSASDVzro5xoinLxwiC2Nf/cM0tO3AHikSC/+Wt3cdfWVfSPZBgYyWBNIPKOIwwnc1weTLNhVTP/7hO7aXOxuuRCJWQ0sD3x62hKI2sNIFL9CV528qStyywL72RN9CGvgbbHgiASCVC8Ll+mVLTw+0w0ff6dv0vTpwD4fQYP372BLeva2Hv0AodO9CAiCKBfERrHkWv5OutXNrNz8wo626vrNrRUCJvN3NHwbzmdfp6Bwjto+AnqdddqxdyI5RQoOKMYys/muk/QGNjgfZ4eC4Y7d6/l9InL9F8eRdM1LMvm0Y/cMS/PYTVXDRJ27Nghe/fOnxKvhWK5soofzpDK5BGplPNtqo/QXB9ZchExU0VESJYv0p3dy2DxBEpAcKjcHFZ+JBUKUwuzPHwXzYFN+PSZd8Ty8JhtkqM5jr3TTalYZvXaFjpWzG5uhlJqn4jsmHScJ+4eblN2cuSsQbLWELZTAKUR1OsIGg0E9fpphTvaUiZnDZAtD1KwRxAEUwsTNhoJmy3eZqzHkqFacV+ybhmP2mFqIeK+FcR9K2Y8V9FOczl3kO7cHiwpAg7q2mlrAwoBmgK30hHaRcy3tLKFPTzGwxP3OUZEsKWyQaMrY1xf9VJDRBgoHOVk6kfYUiao1RPQ68YZ6zBUOEV/4R06QrvojNyHoXluNI+ljSfuc4DllBgonKUnf4yRcs+VOi0KTRnEzRZaAmtpC95KQJ9ZotVCRcThTPpFLmXfIKg3ENQnrriplEbIaMARm+7cHpKlC2yp/zf4lujn5+EBnrjPKiJCd/4ox5MvUZYCpgri00IEzUpYpSM2OWuUE6mXOZF6hZXh21kXfQ+G5ptjy2eXrswrXMq+QcRom9KdjKZ0IkYrOWuAIyPfZlviM94K3mPJ4vkAZgnLKXFg5CkOjTyDoQWJma0EjTi69svWf5rS8esRomYzYSNBV3Yvrw58nUx56bSeGy1d4HzmFcJG67RdVCGjiUz5Muczv3DZOg+PhYMn7rOALWX2D/+Avvwp4mYrZhWrSU3pxMwWyk6RN4e+RdYamQVL5xZHLE4kf4hPi864gFjIaOZS7g3S5V6XrPPwWFh44j4LnE6/wWDxHFGzecrJDkEjjiM2B0d+iCN2jSycH4yUuihYSfz6zMs6aEpHUybdOS/c1mNp4ol7jUmW+zibeXNawn6VkFFPstTH+ewBl62bX/Rk92Jo7rUrDGj19OffxnIKrs3psfAREc6e7OXVF49y7PCFa60yFxvehmqN6crsQ1fmjN0MYSPBmcybrAhvR1eL72sTcRgtXyCgjR3uOB0qn7mQtQaI+5a7Nq/HwubAm2d44amDmD6dcsmm++5hHvrV7XNtlut4K/caUnLyXM4fJ6jHZzyXofko23mGixdcsGz+UbCTiNhoLv9wiQg5a+lsSHtMzps/P0GiKUpjS5yW9joOvXWW0nXFwBYLnrjXkEx5EMC17kJKaYyUelyZa77hdtu+X6KwnHyN5vZYiBiGds0V44iglEJp86/w10zxxJ3K6q4WNXYy1vCV4lnuYGpBRkqXXJtvPqFQXCvB6SoCXtavx3Xc/4EtpEfz9PeMMtib4p6HN2IuwqY7Vb0jpdQHgL8CdODvROQvbnh+BfB1oO7KmD8TkWddttU1+vMpTqcH6MoMcSE7RLpcRBD8mkFrKM7qSCOdkQZWRRoxtOmvui0p4aZgaUq/Mufiw6dHEHGQKysp11AQcMEt5rF4WL+pg89+IcJgf4p4XZj2FYm5NqkmTCruSikd+BLwMHAJ2KOUekpEjl437H8Dvi0iX1ZKbQSeBTprYO+0ERFOpft5ufckZzODKCCo+wgZPtqClbhzW4SRYpaXsyP8rPckEdPPvc3r2NG4koBuTnyAMdDRwcU7AhFn0TaQNrUQfj2GLSUM5V5WqUIRMhpdm89jcdDcVkdzm3ub9/ORalbuu4DTInIWQCn1LeAx4HpxF+Bqa6I4MK8cw5lygWcuHeHg8EXCpp/2YHzM1aGhFFEtQNSshOPlrTLPdB/htYEzfLLzDjojUxOJkFHv6iq0LAVajXWuzTffaAreSnd2D4bW7Mp8ZaeAqYUJ6vWuzOfhsZCoRtyXARev+/sScOcNY/4c+IlS6g+AMPCQK9a5QHduhK+dfp2CXaY9VIc2BbENGiYdRh2pcoH/deJl3t++kQdaq+8cFDEaEMQ1V4MjZer9y2Y8z0TYjsP57mH2vX2B/uEMmlKs7Wxi+y0dNCVqW4irLbiNS5k3EXFcqY5ZdEZZG3140d7teHhMRDVX0FiqdKOv4VPA10SkA/gQ8E9qjKtTKfV5pdRepdTegYGBqVs7RS5lR/jqyVfQlKI1GJuSsF9PzAzQGozzXM87PN9ztOrN16ARI+HroOCkp3Xc63HERsOgwb9yxnONRzZX5B+ffIt/fmoPXd3DgGDZDnsPn+dvv/UKL752otJ6sEaEjEaag5vJ2YMznqvkZDG1MM3BzS5Y5uGx8KhG3C8B12eAdHCz2+W3gW8DiMjrQAC4yYchIl8RkR0isqOpqWl6FldJspTnH06/hl83iZkzz3o0NI32YB0v9p5g/3D1searI7so2dkZR+NkrWE6QlvxacEZzTMepbLFt57dT+9AitamGPXxEH6fSTBg0tQQpbkhyqv7z/DK3tM1Of5V1sQewtAClOzMtOdwxKJoj7Ih9ghmjT4vD4/5TjXivgdYp5RapZTyAY8DT90w5gLwIIBS6lYq4l77pfk4iAg/vHiIsmO7IuxX0TWN5kCEpy4eYqSYreo1jf5VtAQ3kLWnn0hTsnOYmp910bunPcdknOrqp6d3lKaGyJguJF3TaGmM8Yt9Z0lna5fO79NCbK77JJYUKNpTv+OxpUzW6mNV5L0k/GtqYKGHx8JgUnEXEQv4IvAccIxKVMw7Sqn/qpT68JVhfwT8jlLqEPBN4DdkrpqzAkdHL/P2aA/NAfd9xFejZp66eKiq1bhSik3xB/FpIXLW6JSPV3YKFOw02+oexafXrk/oawfOEY1M/EOo6xoiwtHTta20GPO1sy3x66Aga/UhUl2uQMEeJW8PsTb6flZEds/LjvQeHrNFVXHuV2LWn73hsf9y3f8fBXa7a9r0EBFe7D1OnS9Ys4u7yR/hRKqP/kKalmBs0vEBPcKuhn/D3qHvkC73EzYa0SbZMBQR8nYSW8rcnvgIjYHa+dptx6F3ME1r4+TVGIMBk0u9I9y5rbNm9kBF4Hc2/g5n0y/Rmz+MQuHTYhgqcO17FREcyhTtNI6UCJstbIt/hojZMu3jFnJFlFL4g7VvkJIvlMkXyygFoYCJ3zf1cFsPj/FYdGlZ3blRevNJ2oO1S1xRSqErjb2D53lk+ZaqXhM26ri76bOcTL3ChdxBdAyCRt1NRcBEHPJ2CsspUOdrZ0vdB4iYDbV4G9Nmtu7JTC3EhvijrAjvpi9/hIHCMbJ2/5UdfoXgYGohmgIbaAttJ2Z2zDjKxvQZUKNFgYjQ05/k4LFLnLkwSCpTuLLJLzgCiXiI9aua2XbLMpoSMy977LG0WXTifnS0B11pNb8lb/CH2TvUxQc7Nk26Cr+KTwuwue5hVoS3cTF7hJ78O1eaY1eS769qZqN/JSvDd9DgXz4rYXy6ptHaGCWbKxEJT5xAVCiW6Wid3eSPoFFPZ/Q+OqP3YTlFSk4WEAwVwNRCrn7XulGbz3tgOM3TP32bS72jmIZONBygpSH6rruQQsliz6HzvHHgHOtWNfPB+zYSi3gbwh7TY9GJ+9nMIGGj9rfUpqZTcmxGS3kS/vCUXhszm9lU9yAb4+8jb6coOhlEBFMLEDbq5yQu++7tq3jy+UMTirttO4Bi07q22TPsBgzNv6D6oooI+96+wHOvHMM0dVobY2P+GCmlCPpNgn4TEeHcxSG+/C+/4Nce2sqG1dN3M3ksXRZVRSVbHC7nk4RmQdyhcvc+UJh+DLtSipARp963jIS/g6jZOGcJN+tXNdPWHGdgeOz3U/HLp9h9x2qiYfcikBYzIsLrB87yzM/eIVEXJhEPV3WXoZSisT5COOjjX5/dz9FTl2fB2sVP/0iGF/ad5MdvHedi/9SDGxYai2rlXrQtLMdBn6UqgCJCzl4chbx8psHjj9zBd350gEt9owR8BqGgD0eETLaAbQu7b1/NfTvWzrWpC4ZTXQO88OoJWhqjGPrUf7QDfpOGuhBPPn+IRH2Y1sbJN+89xuZM9yDfeH4/SlWyMl9/p4tfu2cLt62rbcb3XLKoxL2S5l/b+UVyOJIFHGwnR6F0DssOomsNrqTMzyWRkJ8nPrKL893D7Dlygf6hNIauuGPTCm7b2OFt8k2BbL7E0z89Ql0sNC1hv4rfZ+L3lXnqxSP81sfuwqjRnsBi57k9JwgHTKKhyl1noWTx3J4TbF7VirlIP9NFJe6GpuGIe7VcoBK9YjtDlK3z2M4IUPE7g1AqKwqFYwwmv4/CwG9uJBS4B9NYs2CFXtc0Vi9vZPVyr5LiTNj/zkVy+TKtTTPfEK2LhejpT3LiXB+b1rW7YN3SQkToG0nTlvjlnU/AZzCSyVEolT1xXwj4NIOoGaDk2Pj1mb01EbDsy5TKxxFKKAw0FeL6Uju6JjQEfJi6hohFsXycQvkgutZINPRx/OYtM/qRsWyHs5eHOHC6m1S2gC1CJOBjc2crt6xoIeBbVF/fosGybN461EV93L2ks2jYz+sHuti4ts1LzpoiSik6WxP0DqVJxCrfSSZfJB4OEA7cvDmfSuYIh/01i5yaLRaVOiilWBlu4Ey6f0bi7kiBYukYtt2LUiE0dbM7ouKigQbflahrZWDolXo5tpNmNP1lgoG7iQY/jKZNLZrGsh3ePHaeX7xzjmyhTMBn4DcNFJDM5jnVPYj5xjF2bujgvq1rCPq95Jf5xOWBFIVimXjUvTDGSMhP32CKZDpPXax2mcqLlQ/eeStf//EeeoaSAJiGzqcfvB3thvZ6I0MZ/t+/foG77l3PPe/bOBemusaiEneAtbEm3hntnvbrHSdDvrQXkRKaNn4iVM6GJr8ioI9VhyWKpsLki29RLp+jPvZ76Fp1NcWLZYvvvnyY4xf6aIhHiIdvFoh4OEjZsnnt6HlO9Qzx2YfuIO5FsMwJyXyB04ND3N7Rfm1F3T+Uvqls6kxRqpILMTSa9cR9GrQmovzBR+/hTM8QjgirWhPExrhmwhE/2+7oZOVqd3oKzCUL0zE8AZvi7WhKw3am3rvUcXLki3tAbDQ1cV2atAW7EuPftimlYerLsGWUkdTfYDupSY9vOw7ff/VtTl4aoL0xPqHbxTR02hpijGbyfOOFfeQXYff2hcDF0SQvnTpLwbKuPdY3mKqJH9cWYSSZc33epUIo4GPL6ja2rWkfU9gBfH6Thx/dzvLOhb/ntOjEPWz6uT2xgsHS1ErGitgUSvsRHJSa+Ha65AimBuujk1/AhtaM5QyTzH5j0gJYx873ceRcL62JaNV+1cZ4mP7RDL94+1xV4z3cZVNrM394/3sImr90jZUt56bbfTdQSlG23Gu47rG4WXTiDnB/63oQRdG2Jh98hZJ1DkcyaJMIu4gwVBLe22SM6ZIZC0NrpVQ+Tr745oTz/uKdLmJh/5Q3zBrjYd48foFiufr36+EOSil8N4Q6+n0Gjl2DAjwi+H0Le5PPY/ZYlOKe8Id5tGML/YV0VWV5HSdD2TozqSsGYKQMy0Mat9VXf5EppdC1ZtK5J8d1z1weTtMzmCIanHpqvWnolC2bExf7p/xaD/dpa4pRtmzX51VKoz4+tc15j6XLohR3gB2NK9lav4yefHJSgS9bF6mEOE78caTKgq7g0TYTfYqra00FEEoUivvGfL6rdxilph+fH/SbHD3fN63XzgRHhGSxwEAuS7JYmHHHqcVAU0PU9WQ6uZK/0VjvibtHdSy6aJmraErj4513YJ9zOJrspS0YG7MsgUiZsn3pSgz7+AyXKsL+6RU+Er7p/SbqqoFs8aeEAveibij1m8kXZ5TJaOgamfzslULIl8scHujlpxfOMpTPAyAILaEI712xms1NzQSMpRmi2dIYJRIOkC+UCQbc+QyS6QKdHQmvro9H1SzalTtUkpoeX7WLe5rXcjmXJFXK3zTGdkapZJ2O/VGUHeFywSHhUzyx0kdLYPofmaYFcZw0ln1zqKauazMOn6vFJt5Y9GRS/Pe3XuE7J96mbNu0R6KVf+EoeavMN48d5n/seZX+7PT7oM4mIkI+UyA9nCE9nKGQK85oPl3TeM/tqxhNuxPZIiLkCkXu2r7Klfk8lgaLduV+FVPTeaRjC5vq2vhu1366c6MEdZN6X6UOuO0kuT7r9CoFW0haFcl/X7PJznodwxXxFMpWH6bx7s5KsVDgSkndsbFLFlahjNgOus/ACPne5cIpli3qZqH2d38uy5f3v4VSsCzy7kJWSimiPj9Rn5/hQp4vH3iLP7jjLhLB+ReXnR7JcvrQec4f66bnbD/5bOFdtdUj8RDta1ro3LiMtVtXEpykBeGNbLtlGW8d6iKVKRCb4mtvZDiZY41XEqJqUuU0ZzJnGSoOU5IyPmWS8CdYE1lF3Fw6xdcWvbhfpTPSyH/Y+CBnM4P8ou80Z9IDaAryxUHARCkHQcGVujQRAx5qNtgY0wkb7q2IFX7K1hlg17seX7uscuE6jlxbgYsIub4UA29fYuhE77UWSCIQSIRovb2T+tXN6H6DUtlm+5ra1x158uRRbISmwMSCnQgE6ctmePrMCZ7YfFvN7aqW/otDvPX8YU7sO4c4QjDsJxgJEE380pctIpSLFuePdXNy3zle0F9jy+717HhoC3VN1YmDzzR47KFtfO17b+D3GfinWSoimyuigA+9d/Os3ZktVC7nezk8eoTzuYsoFKZmoisNRxzOZbvYO7yPFaHlbKnbxLLg4q/Rs2TEHcDQdNbHWlgfayFnlRgopDk1eJCsbSBi4NcVDT5Fg08jblKTGh5K+bGdoZser48EuWV5M+d6h0nEQpSyRc7+6DCZnlE0UyNQF0LpFZeQiGDlS3S98A4XjOO03beB2JomVrZUlwU7XfqzGU6NDNIerq46ZFMozOGBXkYLeeoCc9tRqFyyeOu5Q7z+7AFMn0FjWx2aPraLTSmFL2Diu+Ivt8o2R147yZFXT/K+T97F5t0b0Md57fV0tNbxkYe38r3nDlEXCxIMTK3PQCpToFAq8+sf3km9l5U6LiLCodEjvDm8B7/mo8GXGPPaFRF6C32c77nAzsQObqvbuqjr9Cwpcb+ekOFjZaSBoCVo6Cg1O5t/CoXI2PHod29cydELfeRGc5z+/j6sfJlg080JTUopzJAfM+THLpY5+fQBHvudh9C12m6hHOy/jEJVfUFoV8Yd7u/lvhVz5y9ODWd48m9+wkD3MA1t9Rjm1DauDVOnsb2eUqHMT/75VU4e6OJX/+37CEzSkhBg07p2/D6D7z9/mHS2SGN9GG2S78myHQaHM8SjQR5/9A7am2vXD3gxcHD0MG8O7SHhq8fQxpc0pRQxM4otId4c2oOIwx2J+XNX6TaLekO1GhQGwuxl/VUyYMf+IelsTfC+Las4/P+9RTlXIlA/ceceQcjZNh2rWuh66Sjn3r5QK7MB6MtlCRhTWw/4NJ3BwtylzCeH0nzr/3ma5GCGlhWNUxb26/EFTFpWNnDpVC/f+Z8/Ip8pVPW6tSub+d1P38vm9W30D2foG0yRyhSwrouFL5dtkuk8vYMpRpJZ7rqtk88//h5P2CehO9fDW8N7afAnJhT269GVTqM/wZ7hfVzMXaqxhXPHkl25X8XQmylbF2CSzFS3EClg6OP3IG21NRqVwVBAkSuWCPrMMQS+0ky5bNm0JqJs6Ggml8rx8++8Qeem5Yv6VnMqFHJFvvs/f0wxX6K+xZ2NNKUUjcvqGbw0zFNfeZGP//sPVFUaNhLy8+EHt/LAnes5dqaXMxcG6e4doViyECAc9LGivZ41Kxq5ZU0roSm6cJYqB0YPEdD86FNsT6krnZARZP/IITqCyxblNbPkxd1nrKNYPo5Obf3VVxHK+IzOsZ8TYe9zh1m9spmVPp1LA6MMJLMIcs3FISIIirpwgOXNdTREwygF4XiI/gtD9HYN0LaqNhXtWkJhDvf3Tuk1JcehcZLN11rxix/sJTmYpqkj4frcDcvquXDyMvt/+g47H95a9etikQB3buvkzm2diAi2U+kepqnq3V0eFUZLo/TkL9Pgm973G9bD9BX6GCmPkvDNzvU/myx5cTeMjjECIWvD1exNXW8d8/mBS8P0nh+geXkDSini4VaKZYvhdI5S2UZE8Jk68XCQ8A0rO6UUhk/n8MtHaybu21va+UnX6ao7XdnioBC2No/9fmvJ+ePdHPjZUZqXN9RkfqUUDW11vPzkHlZtWk5j+9TFQSmFUWV9Io+bOZE+XSmFPM0fRaUUGhonU6e4q3HX5C9YYCx5n7vPWAUqgCPV+U9ngkgGQ28Z1y2THEzdtILzmwZtiRgrW+rpbE3Q3hC/SdivEooG6e0aqIntAM2hMOvqGxks3JwMNhaDuRxbmlpnPVLKRVpHAAAgAElEQVRGRPjpd94kUhcaNyLGDUyfgekzeO3psUtKeNSWoeIQAW1mOQQB3c9A8ebotcXAkhd3pUzCgQfGDE90G1uShPwPjrvSsErWjGqzaLpGMVfbEgQfWb8RHcXIJAI/XMgTNEx+de0tNbVnLHq7BhjsGSbsYpu78Yg3RTl18Dyp4YWRjbuYKDrFa+7K6aIpjZLMLCN5vrLkxR0g6N+FQq/p6t1x0mgqSsC/Zdwxps9kJhWnHNvBH6rtRlxzKMzv3b4LQ9PozqTIlH55YYgIqVKRS+kUQcPg927bRf0cxLcffuU4ps+YFR+2pmkoFMfeOlPzY3m8G1MzcWZYqM4RB3OWwqBnG0/cAV2rJxr6OLbdV5OqhiIOtjNMLPypCevF17fEwZFp25BL5lm2tvb+7fZIjD/ZdS+f2LAZU9fpzqS4nEnTk00TMkw+vXEr/3HnbprDk5dQdhsR4fThC0QTs3fsUDzI6UPnZ+14HhXqzTqKzszuVItOmTpfnUsWzS+q2lBVSn0A+CtAB/5ORP5ijDGfBP4cEOCQiHzaRTtrTtC/i2L5AKXy6QlDFaeKiGA53QQD78Fv3jrh2Ib2etrXtTLcO0psiuIkIliWxdb7pt7U1ykdhPIh8O1GM9dW9ZqgaXJn+3J2tnWQLhUp2TY+XSfmm3qzETfJjOYo5krEGmZP3INhP/0Xh7Atu6qwSA93WB9bx9upY1Vv8N+IiGCJxYbouhpYN/dMunJXSunAl4APAhuBTymlNt4wZh3wn4DdIrIJ+A81sLWmKKURDz+Brrdg2ZddmVNEsOxL+MwNREMfreoE3PUr28mn8lNevadHsrStbply2J84ach/C6wzkPunKR9XU4q4P0BTKEzcH5jzcL6R/uSsH1PTNUSE0cH0rB97KdPoa6DRlyBnV7fBfyN5u0DCV0+zv8lly+YH1bhldgGnReSsiJSAbwGP3TDmd4AvicgIgIgsyJZAmhamPvp7GEYHZfsiItNvOi1SwrIv4vdtoi7yW2iqug5LnZs7WLaulaGe0aqPVcyXyKcLPPCJu6cursoHKgKSB61xzsV5phTz5RmXTp4OSkFpFuvpe1RCGbfXbSVjZXEm6U98IyJC2sqwvW7Lgj/nx6MacV8GXLzu70tXHrue9cB6pdSrSqk3rrhxFiS6FiUR/X3CwV/Bcvqw7MEprWZFHCynH9sZJBr+GHWR30ZT1YdrGabBY7//K9S3xBi8NDzpsXPpPCO9ozzy+QfpWD91d5JSflTkC6jw51Dh35zy6+cb4jiud0Gq6rhyrWinxyyyOrKKzbFbGSwOVS3wIsJAaYiNsVtYE1ldYwvnjmp87mNdKjeexgawDngA6ABeUUptFpF3LT+VUp8HPg+wYsWKKRs7WyjlIxr8EAFzC+ncDylZJ1FoaCqGUiHUDR2dRGwcyeFIGhD85haioUcw9JZpHT8cC/H4nz7Gc1/7GacOdKHpirrmOOaVsrEiQno4Qz5TJBQL8ok/epRVm6f/eSotAZr7WZxzwUxqx8wEpdScHXspo5TiPU13IQjvpI4TM6ME9fEXUwW7QKqc5pbYBnY33oU2Rne2xUI14n4JWH7d3x1Azxhj3pCKH+OcUuoEFbHfc/0gEfkK8BWAHTt2zPt1jmksJxH7ApbdT764h1L5HSy7l8pv25VyAAgKDUNfRsh3D0HfHej6zIUyGAnwa1/8AEOXRzjyi+Mc+tlRrFL5Ws35jvVt7Hz/NlZu6sAwl3yi8TViDdGxlyM1RESwbXvKm+Ae7qArnXubdtMaaGH/6CEGi0MYyiCoB1BKQ8Sh4BQoORYxM8oDzfexPrp2UQs7VCfue4B1SqlVQDfwOHBjJMz3gU8BX1NKNVJx05x109C5xNCbiYYeAR5BpIztDFHZflAo5UfXEjf1RHWLhrZ6HvjE3dz70TspFUo4toMv4Lu2il9s2E6BdPEdhgqvULIHAI2QuYJE8F7C5lq0ST7n+uYYCoXjOJOW1nWLUqFMvCFaVQlgj9qglGJ9bB1ro2voK/RzLHWC4dIwRaeEX/PRFGhiY+wWWgMti17UrzKpQoiIpZT6IvAclVDIvxeRd5RS/xXYKyJPXXnu/Uqpo4AN/ImILMqcXqVMjHFqw9QSXdcILvLmyPnyRS6mvo7lZDC0GD6tEsVQKF/mYukfCBjLWB57AlMfPy5ZN3RaVjaSHEwRqQuPO85Nsskct9yxeH23CwlNabQFW2kLzv41Ot+o6idMRJ4VkfUiskZE/tuVx/7LFWFHKvxHEdkoIltE5Fu1NNpj8VG0+jif/CqCImAsw9CiKKWjlI6p1xMwOijZ/VxI/T22M3F9+Nse2EguVftaQVcplyw2vWf9rB3Pw6MaFue9vUfViAjZZI6hy6Nkkjkc20E3dOINERKtdVNuDD1d+rPPIYBPG7/uuk9vIW9dYqSwh8bQ/eOOW7NlBabfoFyyau6+yqUL1DfFaF9dm0qcHh7TxRP3JUo2meP43jPsff4I6dEcSoE4V/a4VcWHKSI0ttez8+GtrN3eiT9Ym7o1JXuYdPkofm3yUE6f1sBw/hUSwd3j+t99AZOdD2/l1R/up2VlbUr+QuWHMTmY5pHfemDW/PseHtXiifsSwypb7H3+MK89vR/HEeINUVrGqXkuIuRSeX709Z/j+9ZrPPip3Wy8c63rSR956yIIN4WYjoWuBSlaI5TsQQLG+H7VHQ9v4dieM6SGMzWLYhnpS7F6cwe37lpTk/k9PGaCt9xYQgz3jfLPf/EUr3x/L/XNcVqWNxIIjR/hoZQiHA/RsryRUCTIM3/3Et/70nPk0tNL9x6PSgTtVCJjtUmzh02fwYd+437ymQKlwvQzjcfjav/Uhz9zj7dq95iXeGely6RHs3zvb57nr//0n/nOXz83b+p8D/YM883/6ylSQylaVzZNOTbeH/LR2tnE+aPdfPsvnyWbdK/pdSWDt7q7gUrGrl1V1m9rZxMf/Nz9DPeOuirw+UyB9EiOj3zhYeINUdfm9fBwE0/cXURE+MFXX+L8icuEYyF6zvTz5N++gONMre6F26RHsnznL58FFHVN8WnPo5SiaVmC0f4k3/vSc5RLliv2hc3VKKXjyOTz2ZLGZ7Ti0xurmnvTXev40G8+wEhfiszozH+QRgdS5FJ5PvbF97NiQ/uM5/PwqBWeuLtIIVuk78IQje11GKZOojXOUG+SbMpdN8ZUEBFe+JdXKbhYBrehrZ7ergHe+vEhV+bTtRD1gTsp2RPXmxMRys4oDcH7p+T333TXOh7/40cwTJ3+C5XSvFOlXLLoOz9IXWOMz/zZY3Ru7JjyHB4es4kn7i7iC5iYfoNCrtKdqJgvoRtazaJMquHEvrOcOniOhjZ3GxI0tid4/Zn99F90J1etMfQgPqOR4jgNU0QcinY3Mf9W4v6tU56/Y20rT/znj3DHQ5sZ7k3Sf2GIfLYwYWE2ESGbytN3YYjUUIZ7P7KTT/3JozQtWxx1eDwWN6oWnYeqYceOHbJ37945OXYtOXPkAj/8+58htoCm+NDn7mPDbZ1zYovjOPzDn38Xq2QRirrf7m6od5R12zt55Lff68p8lpOmO/1tsqVTKKWhqRCIYEvFnVIfvJOW8CNoU2yLJmKDpBGxUUonm1ac3HeRfS+9Q2o4g1KVcgWV8E9ABE3XcByhsa2OHQ9vYe22lRNuPnt4zBZKqX0ismPScZ64u096JEtyKEMsEZ7TYlLdp3v55n//IS0rqvNPTxXHdhjsGebf/cWnXUv1FxGKdh/Jwn4Kdi8KnZC5krh/+4RlB26cQ+we7NJhHPsUjnUJcPjlpq2D0pvR9NWUSusZGWhgdCBLMV9CaRr+oEl9c5yG1roFXS8mmy4gjkM4Fly0NcuXItWKuxfnXgOi9WGi9bNT12QiTh44V9O2b5UORHDhxGU23llde77JUEoRMFoJRD405deKCHb5KHbheRz7AqCDCoPWRKWh2C/HiZPDsveh8zpNLXFaV7wXw38XSs2dC80tRISf/WA/B145jghs2rmahz95J7rueWGXEt63vYi5eLKXULS25QNMn0HPmd6aHqMaxElRyn2DUuarOM4waMtQehtKi71L2KHyA6K0MJrejNI7EHTK+e9TTP/VlVX+wqbreA97f3qUxtY6mtrrOfLGaU4dvjDXZnnMMt7KfZFiWzaDl4ZoaK+v6XGCkQDdp/uu/Z0pFtl3sYc3ui6SKZZIhIPcu7qTLe0t+I3anG6OdYFi5u9ACii9o6pM1+tRKoTSQ4gzTCH9l5ihj2H4ptGycJ6QSebRNA3tykpdN3SSQ/Mj38Jj9vDEfZFSLlk4IjXPnjRMnXy2kq05kMny1df2kCwUSQSDJEJB8qUy3z5whNe7LvBbd91B2Oeu28OxzlPM/A0QQM2wFLPSEiAlyrlvg5QxA+MXJ5vPNHckQFWKmikFtm2zbNXibALtMT6eW2axIszaylNEcET4x7cOULJtlsVjBH0muqYR8fvpqIvTk0zzgyPHXD2uYw9TzHwFCKK0OOCAZBCnH7H7EGcAJMtUShso5UNpbZTz38MqHXbV3tmipSPBY791H76AiW7qPPLZe+hYM72Wjx4LF2/lvkgx/ZWv1nEETaudyFuWTSAc4NzQCP3pLMvqxi7Z2xKNcLinlw/eup760MzDMkWcygobG6WCSPkE4lyCdzVJVggCykTpK1D6MlCTR78oZYJqopz7V3SjEzVBGeL5ytrNy1m7efnkAz1qSrlkISKYPmPW3XyeuC9SdEOnsb2eQq5IqIY12fOZAp0bOzg3NDzhj4imFKDoSaZcEXe7tBe7fBREEPvKCluFYCw3lNiIdQaxulDmLSh98rIBSgshdpJS7gf4I5+dsb0eSwcR4dzxy+x9+QQXz/QBikg8yM77b2Hj7Z0EQrMTkeWJ+yKmY30bh18+XlNxLxctlq1tpacaz4fIlGo/jj+NRTn/w4rbxRlGqQioCUI+lQ4qCmIh5SPgpFHmhskPpLXilA/g2A+jzUFrRY+Fx08vH+ap776KeUKjs7GZ5vZ6lFIUciVe+sF+Drx2ik/8zgPEZiFU2vO5L2LWbe+cVh2VanFsBxQsX9fGikTdhKn8zhVhb4vNvIqiXT6FUz6KckZQKj6xsF+PMkDFELsLsbomH64UoGMV35iRvR5LA8uxefrF10kdTpOK54jVh6+5YgIhH60dCbKpPE/906uzUkzQE/dFTMe6VmINEXKZ2vQTTQ6mWX/bKmINEdY0JqgLBRnNj32sgUyWW1uaaAiHZnzccu5JcIYqq/GpujGVAhVFrFMg6cnHa43YpTcQKU3LVo+lg1iCcRio0+gIjx2dlGiK0XdpmJ6uwZrb44n7IkbTNHZ/eAfJwfSEq+rpYFs2xUKJne+vFPEyNI0ndm7Hdhx6U2nKduWOoVC2uJRMUhcM8NFtG2d8XMexcEo/BxWrCPV0UBqg45RPTT5UmYhYiD0wvWN5LBn6ukdoUXXcv2wzneHxe+oahs6JQxdrbo8n7oucW3etYfXmDob7kq7OO3h5hF3v30bbql+exO3xGH/4wHvYvXolyUKB7mSKkm3xoY0b+MK9dxILzNz3L+WDIHmUNsO5VKiy+pdqarwLjjNxOWIPj1KhDAq0SZLoTJ9BZhbKgHsbqoscTdN4+DP38k//55NkRrOuFPga7h2loa2eux+97abnEqEgj2zawIc2rsdyHAxNczUEzCkdwJU1iQIExBlF6ZO5inTE6gbfze/Xw+Mq/qBZVUpFuWQRrXO/SuuNeCv3JUC8McrH//CDlEsWyaEq/MzjICIMXR4hXBfiY3/wAXyB8UO6lFKYuu56bK9jd8EUS/6Oj444I9WNozb7Fh6Lh9aOBOFogEJ+/P0ZEcGybG7ZtrLm9njivkRoXdnEp/70wwRCfvouDE45iqZUKNN7foDWziYe/6NH566UsWRw7bRVBkg1t8fi3jE9Fi26oXPXg5sYGUxj22NHwwz1p2jvbKRtZUPN7fHcMkuIpmUJnvjfP8obzxzg1af3IZbQtDwxYROKfKZAaiSDYRi8/9fvZcs9t8xx6Vg3T9nqNpkVFkp5jbA9JmfrXWsYGUyz5+fHCQR9xOvDKE2RzxZJjeRoXlbHhz+7e1ayVT1xX2I4lsPoQApESA6nuXCim5aVTcQaIojtgFKVdaqmQIRoIsJDj+9m/R2ratLNaapoegeUDiIiM79AxEJpk9+BCIJmLJvZsTyWBEop7n90O2s2LuPAa6c48043ju3Q0BLnA4/vYv2W5fj8brkVJ8YT9yXGc//0MqcOdtG+upWOtW3k0nmG+5I88PE70U0du+xg+gxiiQiJtjqi1yVizAc0cyMUngVsZn76OqBN3t1JAUobP7TNw+N6lFIsX9PM8jXNlcYws1CddSw8cV9CpIYznDrYRdOyhmt1YELRINl0nsxojvs/duccWzg5mnkrmqrDkSyoGfj9r8T9K23ievfiZFFaXaUcsIfHFFFKzdniyNslWkIU8yU0pW4q8GX6DDIj2Tmyaoroy9F9WxDJzywxS3Kgt05aJVJkBN3/vik3APHwmGuqOmOVUh9QSp1QSp1WSv3ZBOM+rpQSpdSkzVs9Zp/65hj+oI9CrnjtMRGpVHZcIOVhlVIYoc+hqUCVCUhjIBYAmrFu4mFSQikDw7dtesfx8JhDJhV3VWlA+SXgg8BG4FNKqZvyyFUlnODfA2+6baSHOximwUOfuYfkYJqhyyMkh9L0nh9k+YZ21t3WOdfmVY1mrsQMPwGSQpwpFkYTGySLMjeBGj/LtdJEuw8j8KGqNl09POYb1fjcdwGnReQsgFLqW8BjwNEbxv0fwP8N/LGrFnq4yoY7VlP3n2O8/dpJMqNZ1mxbwfrbV8/aDr5bGKHHccpnKBd+DDSitCpqZEsRpIgyN03ekk+G0PWVGP57XLHXY2oU7DJFu4ymFAHdxNS87cGpUs0ntgy4vsrNJeBdO29KqduA5SLytFJqXHFXSn0e+DzAihUrpm6thyu0rGikZUXjXJsxI5RSmLE/waGAXXwd5fiu+M99764UKQKUrrhYgmi+XZNGyIiTBBRm+NMo5YnKbGE5Nucy/bw+eILz2YHKRuSVdpHb6ju5PbGatkDdvIrems9Uc+aO9Ule28lSlZ2mvwR+Y7KJROQrwFcAduzY4W6ZQo8lh6b5CcT+E8XM32CXjoCTQ5EGuXrKXjnFtDiacQtKbwQmrv0uzjDg4I/8HppeffhjIVvkxP6zmH6TDbevQjeqrDE/TbLZImfP9pNM5tA1jZbWOCtXNs5xgtn0uZQb4rvnXydl5QnqPlquE3HLsTk80sX+4bN0hpv56PI7iZi1a0CzWKhG3C8B1++2dQA91/0dBTYDP7vyZbQCTymlPiwie90y1MNjLJQWxh/5IqXcv2KXD6K0+spqRJwrHZiCTCboUOnuJE4vmtaML/IbU+689IOvvMj5Y92I4zD4yO3c95Gd03o/k5HPl3j558c5fPgijuOg6xoilV654bCf++7fwJYtyxfU6rYr0883ul4mpPtpC94cmmpoOk2BOCLCpdwQXz/7U55Y/QBRc+6T6uYz1Yj7HmCdUmoV0A08Dnz66pMikgSu3eMrpX4G/LEn7BNTKluUSpXNwIDfwKjxSm8xo7QgvvDnsEvbKee/jSMFlEqg1OSNQUTK4AwiOJj+hzGC70NV0UT73XMIl05dpmVFA/lMgUuneqf7ViYkny/xr996g/7+FI2N0ZtW6YVCmWeePkgqlWf37vULQuCHimm+2fULIkaQsDHx566UoikQY6iY4tvnX+Vzq9+LoXnXzXhMKu4iYimlvgg8R2UJ9Pci8o5S6r8Ce0XkqVobuRgQEbp7Rnj7eA8XLg4xNJK9zt+laGyIsGplAxtvWUZrc2xBXJjzCaUUhn87urkWq3QQu/gSjt19pbKvH6WClSYd4gClK2GUCpSB7r8Xw38nmt4y7WPf/t5N7HvpbZRS3PuRXW6+tWu88PzbDAykaWmJj/l8IGDS0hLnFy+fYNmyBKtWjd0NaD7x5uApBJlU2K+nwR+jOz/CuUw/62JtNbRuYaPc7tBTLTt27JC9e5fG4r7rwiA/eekdhoazGIZGOOwj4DevCbjjCIVimWyuhG3ZtLXW8fB7N7KsbeLsSY/xEbER+yK23YdjnUHsy4AFaCgtgWasQdPb0IyVqAlCIqs/ntB/cQjTb5IYR3xnQjKZ43/97Us0NcVuSkIba2xzc4zHP3W363a4Sd4q8T+O/5CELzLlFfhoKUtLIM4Tqx+oiW3zGaXUPhGZNJfICwWoIcWSxUsvH2f/ofPEon5amqNjrsg1TREK+ggFfYgIyWSOr//La9y9aw333r3Oc9lMA6V0lNGJZnSCv/ZlFZRSNY1AOnmiF4RJhR0gFgty4fwQo6M56upm3rO2VpxMd+OIMy3XStwMcT47wHAxQ8Lv5SGMxcLcWl8AFAplvvPkHg4ePk9rc5RIOFCVq0UpRSwWpLkpyutvneb7zxygXJ5ioo7HomNwKI3PV91aTCmF0hSZGjVGd4vBYhpdTW/hUqnZopEqTzNLeQngiXsNsG2HJ5/ez6WeEVqaY9OqCKfrGq0tcU6e6eOZnxx2vcG1x8JC0zSkyvrzAAo17f7hs0XJsdFmYqQIlozdFMPDE/easP/Qec6dH6C5aWw3TLUopWhtjvH2sW6OnbjsooUeC4221jjlUnV3cLbtIDjE4/PXJQMQ1H0zFmefFy0zLp7P3WVGRrO89PJxGhtmJuxXUUrRUB/mRy8cYeWKBsITdE3ymB45K8ml3FEGSxcpOwU0dCJGPcvDm2nwdcyLipDr1rfy/E/exrLsSfdgRkdz3HrrMiKR+Z3oszzUgDNNcbccG6UUjf6Yy1YtHjxxd5mDRy6CAtN0b0URCJgkU3mOHu9h5+2rXJt3qTNa6uNU+nX6CmcBhV8LoSkdEYeMNcyl/DFCeoy10TtZHtqENk3/sBsEgz527lrNa6+eorUtPu7CoVgsY1k2O3eunmULp05npJmoGSBvlwjqVdQGuo6RUobb6lcRmkII5VJj7pcki4hS2WLfofPU1+B2OBYL8Mbes+M23vWYGpfzp/jFwL8wVLxEzGgkbjYR0MP4tAB+PUTEqKfOrMS9Hxp5joMjz2FLeU5t3n3PejZuWsblnlFyudK7nnMcYWQky8hojsceu4OWVvfDMd1GVxrvadzASDEzpdfZ4mCJw+2J+f8DNpd4K3cX6R9IY5XtqlftIoLjjCBSBCrp8pqKoFTkps2wYMBH30CK0WSOhoQX+jUT+gtd7B1+irAex9Qmdl34tCCmGaA7fxSlFNvrfmXO3DS6rvHIo9tZubKRN944TV9vkoopCscR1q5t5u73rKO9feHkR2yrX8Xh0QsMFpI0Bib/QXLEoa8wyt2N62mpYvxSxhN3FxkYTFNNUItIEcu+TNnquiLsUClyVcmn1LQ6TGMVutb0biERxdBwxhP3GVB2CuwfeZqQHptU2K+ilCJuNHMx9zZN/pV0hG5qZzBr6LrGtu0r2LJ1Ob29o2SzRTRNo7ExMu83UMcioJs8vnI3/9L1Cr35ERr9sXHj3gt2iaFimjsSa3iwdauXxT0Jnri7SP9gGtM38ardtocolA6A2JUStCr6rucFcJwcxdIBNBXD77+90nXoyrPDC6Ud3jylN38ayykRNidvjH09SmkEtRhnMntYFrx1zoVF09SCWqFPRNQM8sSqB3i5/yj7h89SFpuw4cdUOg5QtMsUnTJRM8Cjy+7g9sRqtHmwyT3f8cTdRayyzUQJhJY9SLG0F0UQpY29ylJwJR0+gCNZCsU3CfjvRFMBlKYoW15C03QREc5k9hCYZmclvxYiWe5ntNxLvc+raeImQcPHr7Rv577mjZxIdfN28iJZq4iuFB2hBNvrV9EZbvIKhU0BT9xdxDB1HGdsv4zjZCmWDlSEXVXX9UhTYRzJUiweIOC/C3HE1SicpUbaGiRjjRAzpldQSymFrgx6cic8ca8RQcPH9sQqtie8qLCZ4t3buEhLU5SyNXY0S9k6D0jVwn4VTYVxnCSOMwxAoi48UzOXLCUnj0KbkUvFUCZ5O+miVR4etcETdxepJC7d/LhIGcvurqq++Jgok7LVBUp5m6kzwBF77L5iU0ChYYvljkEeHjXEc8u4SHNTFNPQKd8QDmnZ/YCDmuZvqVJBsvkhwiGHem/lPm0Mzc8UyrOMiS0WPn3hRaVMl9FkjtffOkMuV2LDulY23do+55vJHtXhibuL+EyDO7Z38ua+szQ3/jIKxnFSzOQmSQHptMY9D01ey9tjfKJGAqUUtljo02x8bUmRJt/SaO6e+f/bO/PguK7rTn/nLb1v2AmABMGdokSJm0RqsWRJlLXZkuLYimzLcTKaOLETT2ryT1KVqplUpmpqJutMJp4kHsdZPHFsR7ETRpZHlrXY1EKJFBeJlEiRIikSJPalgd77vXfnjwZligvQAF430I33VaGqG3379rnd7/3efeeee046zze//QrZbBGfz+Cdd3vJF4ps3dQ936Z5lIHnlnGZTRuXIQiF4sW37kXm8lXn8mCainVrPuySsW0bx5mfHauW4/DiyVP8zRv7efb4CQr2wo/iMbUAXaGNZGbpMy9dFEzagqtdtmxh8v7ZYSZSeVqao8RjQZoawry279R8m+VRJt7M3WUS8RB33b6eZ54/QnvbhXJ5BrP1BygFY0m4d2eWcChEIVfg2N4TvP7DAwz3jiIirNzYxdaPbWL5hqVVu2X+f+8e54WTJ4n5fBzu62c4k+GxG66vymfPha7w9ZxKH0ApZ8Y7TVPWKCsjWzC1xZHP5NJ0vI5Sl9Vt9Vi4eL9UBdh8fRerVrQwMDiBUgpNi4Ca+cxWKRgYgmvWweqVBXIpH9/6r9/j6a8/TyFXpK2rhZalzZw73sd3/uBfePbvX6zaTP6NnnMsiURIBIMsjXm87jIAACAASURBVMfYf74XpwZyzkeNJrpCGxm3BmeUIz9np/BpAbrDmyto3cKie3kTjQ1h+gbGGR5JMZbMcNuONfNtlkeZeDP3CqDrGj/34Gae3PUG758dpqW5FeQdFAopM1zDtmFwGFavhI9+JIlpLOepP3+Dkd4x2le0ftBOBBKtcWJOlP3PHSbeEmf7A1sqNbQPiAcDjGWz+IJB0oUCMb9/roEoVUFEuC5xF3knTX/uJHGjZdoZfMZK4uBwS/OjhIzFk2I2GPDx+C/czIE3z5DJFli9ooVVFx17Hgsbb+ZeIfx+k089vI2tm5YzMJgjl23DcaYvCaYUjE/A8Chs3wb33yPoeor00A2cO9FP01W2nGuaRnNnI3ueeoNiofLZCz993XWICL0TE+Rtm89tuqFmoih0Mdja+AmWh29g3BpivDiI5Xz4O1PKIW2NkSwO4NND3NbyWeK+tnmyeP6IhP185OY13HvXtZ6w1xjezL2C+H0G9951HetWt/Oj56GndxDTsAmFdPx+PkhV4DilRdNstjRjX9IGd9wmtLUKtj2MrjVz9FWFYepTCqjPbzKWK9Jz7DwrNi6v6Ng64zF++/aPMJrLEfcHCPlmtjmrUiilsJwJcvYg1uTFVNf8+PVmfFrig1m6LgbXJ3ayKrKNnszbnErvJ2NNCrwSFA6tgZWsjGyh0dc5r7ncPTxmgyfuVaC7q4lf+cKDnHo/zP63fkhvXwPDI/oHiSBFoLkR1q6GdWuE5qaS+8B2RkAc4tFfYXxoH2Zg+oIGSimyVSqMHDBN2s2FIepFe5zR/FsMZF7GciZA5AOf+gVXmCY+moI30hTYSsBoBiBsJFgXu4XV0RvJWONYqoAuBj4tRED39hR41C6euFcJEWFl9520t4eZSH8L29Kx7WZEDHw+0PWfzcgdJ4Ntj6DpMRKR38DQlxCKBrEKZeyMFPAFZ1bVppZxlMVQdg/nU8+icPBrCYLGlfO+OKrAYOYVBjK7aQ5upz28E0MLAqCLSdRsqqbpHh4VxRP3KhP034SpLyWbf4Vc/lUUFgoNy9ZBWSAKTYsRCT9CwLetFGkDXLNjLW/tfmfKvq2ihWHoLF3bUY2hzDsFe5xTyW+Rsc4S0FvRpsnbo4mPoNGGUjZD2dcZzx9jReJzhK5yMfDwqGU8cZ8HDKODqPEpwsEHKBTfwXZGUCqPJiEMowPTWI1csoNy2foOmjoaGBtIkmi9vAKNUoqhcyNsf3ALgUVQRLtgj3Ni7OsUnRRBfWZb4kV0QkY7BTvJ8dGvsybxBCFzcVwQPRYPXrTMPKJpIQL+rYSD9xAJfZxQ8C585vrLhB1A13U++ZsPYvpN+s8MUsiVFv+UUqTHM/SeHGD15hXc8vCN1R5G1XGUxankP1B0JgjozbOO0vHpcTRMTib/jqIzszqeHh4LHU/ca4iGtgSf/8+f5paHbiQzkWHg7BADZ4fwBX08+Ks7efjX78NcIFErlWQg+wrpYg9+rXnOffn0GJaT49zE0zPa1FSL2E6GgtVPwerHLiMs16O28dwyNUYkEebWR25i+4NbyExk0XWNUCxUMzHmc6Vgj9OXeo6g0eramAN6C6P5QzQXbyLi63alz4VE3jrLePYVUoU3PvT/iG8z0cAtBMzKhs26jVKK8dEMyZEUtuUgmhAM+2loieLzeZJ2gbK+CRG5D/ifgA58XSn13y55/beAfw9YwCDw75RS77tsa1mMZXP0p1L0jo8zni8AkAgEWBKN0B6LEvXXhz/aMA1ijdHpG9YZo/lDgDPt4ulMENHQxc9gdk9dibtSimTuRUbSTyFiYmotH7j8lLJJFd9kIr+PhtB9JII7F/QEwXEcek4OcmjPe5x+t49i0S7VTpi82VIAStHUFueGHStZu7GLUKQ+zvXZMq24i4gOfBW4B+gB9orILqXU2xc1OwBsU0plRORLwB8Av1AJg6+EoxTHBofYffI0J4ZH0CZjnA29tPHEsksHggI2tLZya3cXq5oaF/TB7HE5SikGMi/j09wvDO3TGknm36bopDBnWWN1oTGef5WR9C5Mvf2yi6GIjk9aUWIxkvkBIj4SwTvmydKpef94Hz/+/n6SwylMv0E0EcIwLt9UppQim87z3L8e4MV/O8jmW9dy884N+Pz176q8EuXM3G8CTiilTgKIyLeBh4EPxF0p9cJF7fcAj7tp5FQMpzM8+dYRTgwPEzZ9dMSiVxVtRylODI9wuK+fje1tPHLtNcQCgWqZ6jFHik4Sy0njq0B+lws7V3PWAKav9sXddjKTwr5kyrscEQOf3sFo5mmi/q3oC+jClssW2P30IQ7uOUksEaK1c+qLuogQigQIRQLYls0bu49x/HAPDzy2nY7lc1+fqTXKWVDtBM5e9Lxn8n9X4wngh1d6QUS+KCL7RGTf4OBg+VZehaMDg/zJT1/mbDJJZyxGQyg45WxcE6E5HKIzHuPowBB//JOXeX90bM52eFSHnD1Y8eRkWau3wp9QHdKFtwALTabf0KaJicImlT9YecPKJJPK8+TXf8Kbr5+irTNBODqzSZhu6LR2NGAVbb79F89z/HBPhSxduJQj7lc6n64YViAijwPbgD+80utKqa8ppbYppba1tMyuAv0Fjg0M8o29+4n4/bSEwzOMcxbaohFMQ+ev9uzlzJgn8LWA7WTmWiVvSgSdglMfxa9T+b1oUv6ajCExJvKvV9Ci8snninz/b3Yz1JekrbMBTZt9UF8kFiTeEGbXN1/m1LH6uHCXSznfWg+w7KLnS4HzlzYSkZ3A7wIPKaXy7ph3ZYYzGf5+/0EagnNLWBX1+wmaBn+79wDpQsFFCz0qQeUDFaWUlrMOsJ0JNMo/N0R8OGphxPq/9Mxb9PWM0Nx2+Wa92eAP+oglwjz1rVdJjWdd6bMWKEfc9wJrRGSFiPiAx4BdFzcQkc3AX1ES9gH3zfwZjlJ87623ASHkm3sOlVggQKZY5AfvHKv7OOdaRxdf2fnwZ4MSC2MB+ZzngogPRfmFW5RyEOY/J9GZE/0cePk4LUvcEfYLBMN+bMvhuX/Zv2jO82nFXSllAb8BPAO8A3xXKXVERH5fRB6abPaHQAT4JxE5KCK7rtLdnHlveIRjg0O0hN2rQN8WjbC35xy9Ewtj5uJxZfz63Fx506IgaCyp7GdUiaC5HluNl93eVklCvvUVtGh6lFI8v+sAkVgQrQLl/JpaYxw/3MO500Ou970QKSvOXSn1NPD0Jf/7Txc93umyXVflpVPvEzJNV8MYNRFMTef1s2d55NoNrvXr4S5+vQERA0cVXY1zh5KwKBQBo8IXkCoRC9xIMvc8SqlpzxWlFEpZRP3bq2Tdlek9M8xw/zitHYmK9C8i+PwGB189wdIV9fE7T0VNpR9I5QscHRikIRR0ve+mUIi9Z89hVakGqcfMEdFpCmyl4Iy43nfRGSdsLq1IDP10KKUYzr5FT+p58vaoK32aeith3yYK9vkp3RBKKQpOLyHftZi6+3cttuOU7QZ587WTmNMUpJkricYI777VQ3qi/n3vNbVXdyCVQkQuq8ruBoauYTuK4XSGtmh9+F3rkabgVgazr5Z8xNPUPi0XpRSWSrE0+NC8bGwbL57kxPh3EAxG8ofZ2PgVV+xoCX8ax5kga53A1FrR5MM7Nh1VoOgM4DeW0xL5jGtjzxctDp/s5dXDpxlKptFEWL+8jR3XLqer7coXT6UUp9/tI5pwz916JTRdQ4DB3iThqPuTxIVEjYl7GqeCiyEKGEynPXFfwAT0NpoCWxjJHXTNP15Qo4SMpcT961zpb6bYTmkWaWoRis6Ea/1qWoC22BMkMy+SzO+m6AyCuiDgCk38JAJ3kwjdhSbubObL5Ar83x+9wbnBMeLhIEsaoyilONEzyJFTvdxz4zpu3bjisgtJJpUjncrNOJ59NihgsHeM7rX1sb5yNWpK3NPFQkVm7RdQSlGw7Ir17zF3RISOyH2MF96laI9j6nPbrWo7eRxVoCv2SbQrpFquBgn/OlqD20gVz7Es4u7dgyZ+GsL3Eg99lGzxOJZdcmkZegNBc41ron6BXS8dpm94go7mn0W7iAhN8TCW7fCj14+xpCnG6s4P7xgdH82gaVKVOye/36T/nDvur4VMTYl7JcPgSv1z5S1bHgsKQwuxIv44J8a+Do5garNLoGY7efLOIN2xxwgabS5bWT6amKyIPVLhz/AT9l1X0c8YSqY5emaAJVdJaGfoGuGgj5cOnbxM3G3LoVonn6YJxXwZJStrnJpaUI35/RV1yyBCaIEUfPaYmrC5lNWJJ3CURdYemHHsct4eoaBG6Y49RkPg+gpZubg43Ttcqvk+xew7Hg5wum+EdO7DmwY1vdJTt5+hlKpIqOVCo6ZG2BaNVNQtg1K0Rjx/e60QNpexvvErxHxryNrnydsjKHX1aCelFAV7nIx1Dr/exLqGL3vC7iL5gjXt+XkhIKJ4ifszGK7wxO0iCgWLhub6P89ryi3TGinlkLEcB2MO+SauRM6yCPtMGoJelshawqfHWBH7LKniSQYzr5AsvIsgKBT6ZCy8oyxAoYCQ2cnS4MeJ+9fPm4+9XolHgtPeQVmWjaYJoUvS8MYbw+i6hm076BWeVTu2w5JlTRX9jIVATR3dfsPgpmWdvH62hyVRdwtVjGSy3Lt2tZfjfQEzUczSkxmhJzNCfy6J5dgEdJOloSaWBBN0RT/DUjLk7D6yxT4KThKlHEwtQsjsIKC34tO9PP4XKDh50tYYtrLQ0AjoEYJ6ZNbfz+rOZkxDp2jZmFfItw4wPJFh27pl+MwPS4+mabR3NTHcl6xoOOSFi09zm/tpoxcaNSXuANu7lvLK6TPYjoPu0uy9aNsIsKWzw5X+PNylLzvGS4PvcnislHlaFyGgmwiCrRRHx0vZ/nyawfbmVWxvWk1beO18mrxgSVtJzqTf4Wz2KGkriXaRZ1bhYGp+2gLddIc30uhrR5vBXoKA3+SuLat5es9RljRELiuokUxl8ZsGN1/XfcX337B9JU99a09FxT09kaOlPUFDS/1XMas5ce+Ixbilu4s9Z87SEXPn6tufSnP/ujUkFpBLRikHyz6DZZ3Hst7Dss+hVAHQ0LQ4prkSQ+/CNLrRZhktstApOjavDL7LC/1vY4hGayCGfgWxSVASg4JjsXvgKPuGT/Lw0m2si7V7s/RJ8naWI+MvcSY9mXRPjxE3Wi77fmxlcT5zkrOZY8TNFjY33E2Dr/xIoh3XdmM7iuffOI5SCp9p4DiKgm3TEAny2M4tNESvLN4rrunA5zcoFizMCtVCTU9k+egnNi2K40LmK0Patm3b1L59+2b13myxyP/Y/Sp5y5pzKoKBVJq2SJgv3XwTpn7lW8lq4jgZ8oX9ZHPP4TijKBRCEJEgInrJc6wKOCqN4KAQAr6tBAIfwdC76uagzdtFnjzzGkfHe1kSiGNo5f82GSvPSCHNziXXcXvr+rr5TmbLYK6HvSNPU3ByxIymsnf2ZqxxCirHNbEdrI3eOKNZfCqT58ipXvpGUpiGxtplLXS3N2FM40/ft/sYL/7bQdo6G1z/3VLjWQxT5xf/4701XUhbRN5QSm2brl1NjjBomjxx0xb+4tW9jKQzNM4iQ6RSiqF0mqjfzxe2bZ53YVdKUSgeIZX+RxyVQpNGdH3pZe1KsfhBNOKT77PJFw+RK7xOwL+dcPARNC1ccVvz2SK2bWMYOr6Au4ncbOXwz2f28u54P53BmZ/kIcOPTzN4tu8wfs1gR8sa12yrNfqyp9gzvIuAFiFuzixZVsiI4Vch3k6+Qs7OcH3ijrIFPhLys/3a7hnbu/nm1Rw9eIbkcIp4o3sRLbbtMJHM8Nlf31nTwj4TanaUrZEIX775Jv72jQOcS47TFo2UHUFTsG36J1J0NyT4/NZNxOe5jqpSeSbST5Iv7EGTJgx92fRvmkRER5c2lHLI5fdRKLxDLPLLmOYqV20s5IqcfLuHY/tPc+7kANl0HtEE5SjC0SCdK1tYt2UFKzZ0zvmWet/wSd4ZPzcrYb+AoeksCcT5Ye8hlkdaaA9WJtPgQmasMMhrw08R1GP4tNkd47oYJMxWTqYOEtQjrIvd6LKVl3yeoXP/o9v5hz9/lkwqRygy93PTcRQD50fZcfe1dHYvnlqqNemWuZi8ZfHCeyd58b1TKITGUJCAcbm4KKXIFi3Gslk0Ee5bv5Zbu7tcD6mcKY7KMZ76BsXiMXStc87JsBxnHKXGiUZ+Fb/vmjnbZ1s2B3Yf49UfHqSQtwgEfYSigQ8EXClFsWCRTeXIZYr4Qz4+8onNbLx5zazKo40W0vyvo8/Q4A/j0+Y+9xgtpImbIX51zV0zcivUOpZT5CeD3yFnpQm5UFDcVhYT1gh3tn6GhK/VBQun5tzpIf7p/7xIIOgjEpu969W2HQbOj7Jpxyru/rmtcyrZt1Ao1y1T8+J+gdFslv3nzvPy6TOkC4XJ3W4ymc8aHAUNwQC3rVjOpo52on7/ND1WHqXskrAXjqDpna65Nhwng1KjxGP/AdNYMet+xoYmePrvdnP+9CBNbTFM//S7d/O5IiP9SZava+f+z39kxpEPz/cd4aWBo7S5ONM+nxnll1fdQXek/nN4X+D4xH4OJ39KwnQvrULGGidkRPloq3sZJKei7+wI//rNl8lMZGlqjc94V+lEMkNmIseOnddy884NdSHssAjF/QJKKcbzeQZTaXJWKX9EyDRpiYSJ+HwLanEtm9tNKvNddM39hVDHSYJoNMR+G02b+ZrEyECS7/7ZMxTzFomW6IzsU0ox3D9OJBbk0a98jFiZvtOiY/NHb/+AiOl3ZdZ+geH8BKujS3h0+Q7X+lzI2Mrmmd6/xhAfpubeJEYpxbg1yO0tj9Lob3et36nIZQu8/KPDHHzlBLqhkWiMYJhXXx9TSpFKZsmk8ySaI9z/C9vp6KqvDUt1vaA6FSJCPBCYdz/6dFj2AKnM99G1JRW54GhaHMvuIZN9mkj4UzN6by6d55//94+xLYeG1pnf0osIzUvijA5O8L2/fI7P/tYD+ALTz/qH8hMUHQufywvCcTPEiYk+HOUsCtfMUL6HvJMhaLobIisi6GJyOn24auIeCPq4++EtXL99JYdfP8Wbr5/EsR0cR2H6dDRNQymwihZKlcS9vauRe35+G8vXtFUspLIWWLwjn2cymR8goiNSOfeQrrWTze8mELgNo8wqO0opfrrrDVLJNC0djXP6/IaWKP1nR9jzzJvc/vDWadsP5cZxZlDUuVwMTafo2CQLWRr8lY0kWggM58+jUZnor4AWoS93qqzyfW7SsiTBnQ9t5tZ7r2Oof5yR/nH6z49SyBXRdI14U4S29gSNrTFiDaEFdYc+X3jiPg/Yzij54iF0rbI7YkV0BJ1c/jUioYfLek/fmWHefOU4rUvdKTfX3B5n7/NHuHb7KpqWTO1HTxazFUvrLAgpK7coxH0ofxafVpkqQ7oYpO0seSdDQK/+d+nzm3R0NdHR1cR1zH49aTFQ//eoC5B8fj8grpWJmwpNayGXfwlH5cpqf3D3UXx+07XFJ93Q0XWNt149MW3bUmqvyoh7qe/FQcoawxBfRfoWEQSNnJ2uSP8e7uGJ+zxQKBxCk+qkDBAxUcrCtnunbZvLFDj6xiniLqdDTTRHePOVd7GKU1e5Cuk+nClS9s4JEVcXaRcyisq7TBbTxbJW8cS9yihlYdk9iFTzltbBsqYX9+G+MQDXU64apoFVtBkdHJ+yXXMgVpF8/RcuGI3++s/hDWCIWbmLJKUapLqXLnnB44l7lbGdYUAhUr10B0IQyzo5bbuR/iSOUylRUIz0J6ds0eKPAuK6MKWtPB2BBOYM8tPUMg2+NgqTRbfdplQMRRGaY+1aj8rjiXuVUSqPqnKhVhEDR6WmbZdJ5SoWKug4kM8WpmwTMvxsiHcwUnDXnztRzHFTs7vpGBYyTf5Oiipfkb4LTp6Y0YiheeUoFzqeuFed+fBVSlk1RivpphWZurbmBbY3r6ZgW66VXMvZRfy6ybrY4snV3+rvAtSM68qWQ86ZYFl47mktPCqPJ+5VRjCQKgu8wkYrI3FUJB6qWB1LESFYRhKoZaEmbmjoYjA3tQunHJRSDOcneLBzEwF98cw0o2YjLf5lZO0JV/t1lA0IS0PrXO3XozLUvbgnU1nO9o2SnsYlUC00vYlKzaquispi6F3TNmtsjVc0yqKxjNJmIsK9HTcQNgKMzcE9o5SiP5fkmngn1yemH3u9sT62g4KTnRRkd5iwhlkV2URQXxwL07VO3S55247Dj156h31HzqJppU0sd25fw44bVszr7jVNAmh6C8rJIlK5cmIXowDDuDw3/KU0LoljGBpW0cIw3Ts08rkigaCPeFN54Z9hw8/nV97G37z3E0byqRlHuThK0ZcdY3m4mZ9bduOi3K3Y7O9kVWQTJ9OHiJtzz+KYtVME9RjrY9tdsM6jGpQ1cxeR+0TkmIicEJHfucLrfhH5zuTrr4lIt9uGzpRDx87x2lvv09YUpa0pRmM8xLOvHONM7+h8m4bPWI9Sc3c7lMOF6AZDnz4XiM9vsvHWtYwOTr/4OhOSwym23HnNjEIsWwNxnlh9Jw2+MOczoxQcq6z3pa0857OjbGpczudW3Lqo3DGXck38ZhK+NsaLw3PqJ29nKDo5bmp6wNVEZB6VZdqzTUoxe18F7gc2AJ8RkQ2XNHsCGFVKrQb+FPjvbhs6Uw683UMiGkTTSrM2w9DxmTpHTkwf711p/P6bUBSr4ppxnGF85kY0rbzQtRtuWYtynGk3HJVLMV9E04Rrb5x5tEqzP8oTq+/knvaNjBez9GZGGS2kKTjWB9+dUoqsXWAoN0FvdhRNhM+vuI1Hlm7Dv4iFHcDU/Nzc9BBxXzNjxYEZu2iUUqStMQoqz60tn5xRLVWP+aece++bgBNKqZMAIvJt4GHg7YvaPAz83uTjJ4E/FxFR85VPmFJ0xqWfrhQfiP18YuhLMfQuHGcMkcpVCFJKocgSDNxe9nsa2+Lccv8mXvrBAZbMMVWqUoqhviQ7H91BtGF2m7ZMTee21nXc2LSSd8d7OZI8x9nMMENWajKgVNHoj3JdYhnXNyxjebh5UWR+LBe/HuLW5k9ydHwPxyf249MChPTotKkvCk6WtDVOk7+dLQ33EDXnlkTOo/qUI+6dwNmLnvcAlzrePmijlLJEJAk0AUNuGDkbtm7o4vvPHSIUMNF1jULRpmjZXLu6OqlKp0JECAU/zvjEVxGJVSzHjKOGMI1VmMbMZs1b79rAe0d6GDw/QvM0yb6uhlKKod5RVlzTyfW3rp1VHxfj1002NnSxsaGrVG/WsXBQGKIvms1Js8XUfGxM3E5HcA3HJl6jP3calGBqPkwtgEap8Lql8hScHApFyIixpWEnXeFr0Kq44c7DPcoR9ytNdS+dkZfTBhH5IvBFgK6uykYwbFzbweBYitcOnQZA14QH77iWZUvcyXY4V3zmOgKBW8jlX8fQO13vX6k8ShWIhD8z44uH6TN45It38r2/+DH9PSO0dCRmlEjMsR0Gz4+xdFUrH//lO1xPZyAii97lMhua/O3c4n+ElDXGYO4sw4XzjBX6sVQRQSNhttLk76TJ306jr8O7A6pxyhH3HuDiis1LgfNXadMjIgYQB0Yu7Ugp9TXga1CqxDQbg8tF04SdO9Zx8/XdTGTyJGJBAr6FIwgiQjj4EMXiMRxnGE1zr1rMhURhkfBjGPrsIiXC0SCf/vWP8cL393F4z3GiiRDhWHDKyBOlFKmxDOmJHJtvX89HPrGlrCIdHtUlYiSIRBKsYON8m+JRQcoR973AGhFZAZwDHgM+e0mbXcAXgFeBTwHPz6e//WLCIT/h0MJc4de0MLHol0mO/5lrAl8S9h6CwXsJ+G+dU1+BsJ/7PncL67Ys56V/O8BAzwiaphEI+wmEfGia4DiKXDpPNlNAKcWSriYe/KXb6Vo7/+4vD4/FzLTiPulD/w3gGUAHvqGUOiIivw/sU0rtAv4a+KaInKA0Y3+skkbXE4beSiL2myQn/hLb6kHT22edVMxxkjgqSSj0CUKBj7kS3y0irNywlBXXdNJ3Zpj3j56n50Q/g+dHsYo2hqnTuqyJZWva6F7fSUtnw6KMK/fwWGjUXYHsWsVRWTKZp8nmX0SIoGkNZfvKHZXFsYfQ9Uai4ccxzcWTJMvDY7GxaAtk1yqaBImEfx6/bxOZ7LMUrHcAQZMIImFEfua7VkqhVBalUijyaBIhHPo4gcBtaFKZ8moeHh61hSfuCwzTXEXcXIVtD5IvHKRQPI5lvw/Oz1IFCwpNb8VnbMFnXofPXPch8ffw8PDwxH2BousthIL3EAreMzlTT6FUEURDkyAiC3OR2MPDY2HgiXsNICJIlWquenh41AfeLgUPDw+POsQTdw8PD486xBN3Dw8PjzrEE3cPDw+POsQTdw8PD486xBN3Dw8Pjzpk3tIPiMgg8H4FP6KZecwnX2W8sdYvi2m83ljLY7lSqmW6RvMm7pVGRPaVk3+hHvDGWr8spvF6Y3UXzy3j4eHhUYd44u7h4eFRh9SzuH9tvg2oIt5Y65fFNF5vrC5Stz53Dw8Pj8VMPc/cPTw8PBYtNS3uInKfiBwTkRMi8jtXeN0vIt+ZfP01EemuvpXuUcZ4f0tE3haRN0XkORFZPh92usF0Y72o3adERIlIzUZZlDNWEXl08rc9IiLfqraNblLGcdwlIi+IyIHJY/mB+bDTDUTkGyIyICKHr/K6iMifTX4Xb4rIFtc+vJQrvPb+KNVzfQ9YCfiAQ8CGS9p8GfjLycePAd+Zb7srPN47gdDk4y/V6njLGetkuyjwU2APsG2+7a7g77oGOAA0TD5vnW+7KzzerwFfmny8ATg933bPYby3A1uAw1d5/QHgh4AAO4DX3PrsWp653wScUEqdVEoVgG8DD1/S5mHg7yYfPwncLbVbvXnaJUn0KgAAAqNJREFU8SqlXlBKZSaf7gGWVtlGtyjntwX4L8AfALlqGucy5Yz1V4CvKqVGAZRSA1W20U3KGa8CYpOP48D5KtrnKkqpnwIjUzR5GPh7VWIPkBCRdjc+u5bFvRM4e9Hznsn/XbGNUsoCkkBTVaxzn3LGezFPUJoR1CLTjlVENgPLlFJPVdOwClDO77oWWCsiL4vIHhG5r2rWuU854/094HER6QGeBr5SHdPmhZme12VTy5WYrjQDvzT0p5w2tULZYxGRx4FtwB0VtahyTDlWEdGAPwV+qVoGVZByfleDkmvmo5TuxnaLyHVKqbEK21YJyhnvZ4C/VUr9sYjcDHxzcrxO5c2rOhXTqFqeufcAyy56vpTLb98+aCMiBqVbvKlukRYy5YwXEdkJ/C7wkFIqXyXb3Ga6sUaB64AXReQ0JV/lrhpdVC33OP5XpVRRKXUKOEZJ7GuRcsb7BPBdAKXUq0CAUi6WeqSs83o21LK47wXWiMgKEfFRWjDddUmbXcAXJh9/CnheTa5i1CDTjnfSVfFXlIS9lv2yU45VKZVUSjUrpbqVUt2U1hceUkrtmx9z50Q5x/G/UFosR0SaKblpTlbVSvcoZ7xngLsBROQaSuI+WFUrq8cu4Bcno2Z2AEmlVK8rPc/3avIcV6IfAN6ltPr+u5P/+31KJzqUDop/Ak4ArwMr59vmCo/3x0A/cHDyb9d821ypsV7S9kVqNFqmzN9VgD8B3gbeAh6bb5srPN4NwMuUImkOAh+bb5vnMNZ/BHqBIqVZ+hPArwG/dtFv+9XJ7+ItN49jb4eqh4eHRx1Sy24ZDw8PD4+r4Im7h4eHRx3iibuHh4dHHeKJu4eHh0cd4om7h4eHRx3iibuHh4dHHeKJu4eHh0cd4om7h4eHRx3y/wHVZ7go5QIImAAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "N = 50\n", + "x = np.random.rand(N)\n", + "y = np.random.rand(N)\n", + "colors = np.random.rand(N)\n", + "sizes = (30 * np.random.rand(N))**2 # 0 to 15 point radii\n", + "plt.scatter(x, y, s=sizes, c=colors, alpha=0.5)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "### 8. Load csv file and show multiple chart types\n", + "Or use plt.figlegend() to show a legend outside the plot area" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " month avg_high avg_low record_high record_low avg_precipitation\n", + "0 Jan 58 42 74 22 2.95\n", + "1 Feb 61 45 78 26 3.02\n", + "2 Mar 65 48 84 25 2.34\n", + "3 Apr 67 50 92 28 1.02\n", + "4 May 71 53 98 35 0.48\n", + "5 Jun 75 56 107 41 0.11\n", + "6 Jul 77 58 105 44 0.00\n", + "7 Aug 77 59 102 43 0.03\n", + "8 Sep 77 57 103 40 0.17\n", + "9 Oct 73 54 96 34 0.81\n", + "10 Nov 64 48 84 30 1.70\n", + "11 Dec 58 42 73 21 2.56\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "df = pd.read_csv('Fremont_weather.txt')\n", + "print(df)\n", + "plt.bar(df['month'], df['record_high'], color='r')\n", + "plt.bar(df['month'], df['record_low'], color='c')\n", + "plt.plot(df['month'], df['avg_high'], color='k')\n", + "plt.plot(df['month'], df['avg_low'], color='b')\n", + "plt.legend()\n", + "plt.show() " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "### 9.1. Subplots, part 1\n", + "221 = top left subplot \n", + "222 = top right subplot \n", + "223 = bottom left subplot \n", + "224 = bottom right subplot " + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig = plt.figure()\n", + "fig.suptitle('My SubPlots')\n", + "fig.add_subplot(221)\n", + "plt.plot([np.log(n) for n in range(1,10)])\n", + "fig.add_subplot(222, facecolor='y')\n", + "fig.add_subplot(223)\n", + "fig.add_subplot(224) \n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "### 9.2. Subplots, part 2" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, plots = plt.subplots(2, sharex=True)\n", + "fig.suptitle('Sharing X axis')\n", + "x = range(0,200,5)\n", + "y = [n**0.8 for n in x]\n", + "plots[0].plot(x, y, color='r')\n", + "plots[1].scatter(x, y)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "### 10. Save figure to image file" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure(figsize=(4,3), dpi=100)\n", + "plt.plot([245, 170, 148, 239, 161, 196, 112, 258])\n", + "plt.axis([0, 7, 0, 300])\n", + "plt.title('Flight Data')\n", + "plt.xlabel('Speed')\n", + "plt.savefig('Flights.png')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Matplotlib/pyplot.py b/Matplotlib/pyplot.py new file mode 100644 index 00000000..736716b6 --- /dev/null +++ b/Matplotlib/pyplot.py @@ -0,0 +1,90 @@ +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt + +# 1. simple plot with 4 numbers +plt.plot([1, 3, 2, 4]) +plt.show() + +# 2. points have x and y values; add title and axis labels +plt.plot([1, 2, 3, 4], [1, 4, 9, 16]) +plt.title('Test Plot', fontsize=8, color='g') +plt.xlabel('number n') +plt.ylabel('n^2') +plt.show() + +# 3. change figure size. plot red dots; set axis scales x: 0-6 and y: 0-20 +plt.figure(figsize=(1,5)) # 1 inch wide x 5 inches tall +plt.plot([1, 2, 3, 4], [1, 4, 9, 16], 'ro') # red-o +plt.axis([0, 6, 0, 20]) # [xmin, xmax, ymin, ymax] +plt.annotate('square it', (3,6)) +plt.show() + +# 4. bar chart with four bars +plt.clf() # clear figure +x = np.arange(4) +y = [8.8, 5.2, 3.6, 5.9] +plt.xticks(x, ('Ankit', 'Hans', 'Joe', 'Flaco')) +plt.bar(x, y) +# plt.bar(x, y, color='y') +# plt.bar(x, y, color=['lime', 'r', 'k', 'tan']) +plt.show() + +# 5. two sets of 10 random dots plotted +d = {'Red O' : np.random.rand(10), + 'Grn X' : np.random.rand(10)} +df = pd.DataFrame(d) +df.plot(style=['ro','gx']) +plt.show() + +# 6. time series - six months of random floats +ts = pd.Series(np.random.randn(180), index=pd.date_range('1/1/2018', periods=180)) +df = pd.DataFrame(np.random.randn(180, 3), index=ts.index, columns=list('ABC')) +df.cumsum().plot() +plt.show() + +# 7. random dots in a scatter +N = 50 +x = np.random.rand(N) +y = np.random.rand(N) +colors = np.random.rand(N) +sizes = (30 * np.random.rand(N))**2 # 0 to 15 point radii +plt.scatter(x, y, s=sizes, c=colors, alpha=0.5) +plt.show() + +# 8. load csv file and show multiple chart types +df = pd.read_csv('Fremont_weather.txt') +print(df) +plt.bar(df['month'], df['record_high'], color='r') +plt.bar(df['month'], df['record_low'], color='c') +plt.plot(df['month'], df['avg_high'], color='k') +plt.plot(df['month'], df['avg_low'], color='b') +plt.legend() # or plt.figlegend for legend outside the plot area +plt.show() + +# 9. subplots +fig = plt.figure() +fig.suptitle('My SubPlots') +fig.add_subplot(221) #top left +plt.plot([np.log(n) for n in range(1,10)]) +fig.add_subplot(222, facecolor='y') #top right +fig.add_subplot(223) #bottom left +fig.add_subplot(224) #bottom right +plt.show() + +fig, plots = plt.subplots(2, sharex=True) +fig.suptitle('Sharing X axis') +x = range(0,200,5) +y = [n**0.8 for n in x] +plots[0].plot(x, y, color='r') +plots[1].scatter(x, y) + +# 10. save figure to image file +plt.figure(figsize=(4,3), dpi=100) +plt.plot([245, 170, 148, 239, 161, 196, 112, 258]) +plt.axis([0, 7, 0, 300]) +plt.title('Flight Data') +plt.xlabel('Speed') +# plt.savefig('Flights.png') +plt.show() + diff --git a/NLTK/NLTK.ipynb b/NLTK/NLTK.ipynb new file mode 100644 index 00000000..7c65f6a8 --- /dev/null +++ b/NLTK/NLTK.ipynb @@ -0,0 +1,665 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python NLTK Natural Language Tool Kit\n", + "## Topics covered in this video\n", + "- Exploring the NLTK corpus \n", + "- Dictionary definitions \n", + "- Punctuation and stop words \n", + "- Stemming and lemmatization \n", + "- Sentence and word tokenizers \n", + "- Parts of speech tagging \n", + "- word2vec \n", + "- Clustering and classifying\n", + "\n", + "### NLTK Setup\n", + "First you need to install the nltk library with 'pip install nltk' or some equivalent shell command. \n", + "Then you need to download the nltk corpus by running \n", + "```python \n", + "import nltk \n", + "nltk.download()```\n", + "This will open the NLTK downloader dialog window where you should just click Download All. The corpus is a large and varied body of sample documents that you'll need for this video, including dictionaries and word lists like stop words. You can uninstall it later if you have a shortage of disk space with *pip uninstall nltk*.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "260819\n", + "19317\n", + "['[', 'Moby', 'Dick', 'by', 'Herman', 'Melville', '1851', ']', 'ETYMOLOGY', '.']\n", + "['[', 'Sense', 'and', 'Sensibility', 'by', 'Jane', 'Austen', '1811', ']', 'CHAPTER']\n" + ] + } + ], + "source": [ + "import nltk\n", + "from nltk.book import *\n", + "\n", + "print(type(text1))\n", + "print(len(text1))\n", + "print(len(set(text1)))\n", + "print(text1[:10])\n", + "print(text2[:10])" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['austen-emma.txt', 'austen-persuasion.txt', 'austen-sense.txt', 'bible-kjv.txt', 'blake-poems.txt', 'bryant-stories.txt', 'burgess-busterbrown.txt', 'carroll-alice.txt', 'chesterton-ball.txt', 'chesterton-brown.txt', 'chesterton-thursday.txt', 'edgeworth-parents.txt', 'melville-moby_dick.txt', 'milton-paradise.txt', 'shakespeare-caesar.txt', 'shakespeare-hamlet.txt', 'shakespeare-macbeth.txt', 'whitman-leaves.txt']\n", + "37360\n", + "3106\n", + "['What', 'say', 'you', '?']\n", + "950\n" + ] + } + ], + "source": [ + "from nltk.corpus import gutenberg\n", + "print(gutenberg.fileids())\n", + "hamlet = gutenberg.words('shakespeare-hamlet.txt')\n", + "print(len(hamlet))\n", + "hamlet_sentences = gutenberg.sents('shakespeare-hamlet.txt')\n", + "print(len(hamlet_sentences))\n", + "print(hamlet_sentences[1024])\n", + "print(len(gutenberg.paras('shakespeare-hamlet.txt')))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Get the count of a word in a document, or the context of every occurence of a word in a document." + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "26\n", + "Displaying 7 of 7 matches:\n", + "r him ,\" said I , now flying into a passion again at this unaccountable farrago\n", + " employed in the celebration of the Passion of our Lord ; though in the Vision \n", + "ce all mortal interests to that one passion ; nevertheless it may have been tha\n", + "ing with the wildness of his ruling passion , yet were by no means incapable of\n", + "it , however promissory of life and passion in the end , it is above all things\n", + "o ' s lordly chest . So have I seen Passion and Vanity stamping the living magn\n", + " Guernseyman , flying into a sudden passion . \" Oh ! keep cool -- cool ? yes , \n", + "None\n", + "Displaying 5 of 5 matches:\n", + "one ,\" said Elinor , \" who has your passion for dead leaves .\" \" No ; my feelin\n", + "r daughters , without extending the passion to her ; and Elinor had the satisfa\n", + "r , if he was to be in the greatest passion !-- and Mr . Donavan thinks just th\n", + "edness I could have borne , but her passion -- her malice -- At all events it m\n", + "ling a sacrifice to an irresistible passion , as once she had fondly flattered \n", + "None\n" + ] + } + ], + "source": [ + "print(text1.count('horse'))\n", + "print(text1.concordance('passion'))\n", + "print(text2.concordance('passion'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**FreqDist and most_common** \n", + "We can use FreqDist to find the number of occurrences of each word in the text. \n", + "By getting len(vocab) we get the number of unique words in the text (including punctuation). \n", + "And we can get the most common words easily too." + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "19317\n", + "[(',', 18713), ('the', 13721), ('.', 6862), ('of', 6536), ('and', 6024), ('a', 4569), ('to', 4542), (';', 4072), ('in', 3916), ('that', 2982), (\"'\", 2684), ('-', 2552), ('his', 2459), ('it', 2209), ('I', 2124), ('s', 1739), ('is', 1695), ('he', 1661), ('with', 1659), ('was', 1632)]\n" + ] + } + ], + "source": [ + "vocab = nltk.FreqDist(text1)\n", + "print(len(vocab))\n", + "print(vocab.most_common(20))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here we got the 80 most common words, filtered only the ones with at least 3 characters, then sorted them descending by number of occurences. \n", + "A better way is to first remove all the *stop words* (see below), then get the FreqDist." + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('that', 2982), ('with', 1659), ('this', 1280), ('from', 1052), ('whale', 906), ('have', 760), ('there', 715), ('were', 680), ('which', 640), ('like', 624), ('their', 612), ('they', 586), ('some', 578), ('then', 571), ('when', 553), ('upon', 538), ('into', 520), ('ship', 507), ('more', 501), ('Ahab', 501), ('them', 471), ('what', 442), ('would', 421), ('been', 415), ('other', 412), ('over', 403)]\n" + ] + } + ], + "source": [ + "mc = sorted([w for w in vocab.most_common(80) if len(w[0]) > 3], key=lambda x: x[1], reverse=True)\n", + "print(mc)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### A dispersion plot shows you where in the document a word is used. You can pass in a list of words." + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "text1.dispersion_plot(['capture', 'whale', 'life', 'death', 'kill'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Dictionary definitions\n", + "Use wordnet synsets to get word definitions and examples of usage. \n", + "The [0] is required because synsets returns a list, with an entry for each POS." + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "unmitigated.a.01 - not diminished or moderated in intensity or severity; sometimes used as an intensifier\n", + "['unmitigated suffering', 'an unmitigated horror', 'an unmitigated lie']\n" + ] + } + ], + "source": [ + "from nltk.corpus import wordnet as wn\n", + "w = wn.synsets(\"unmitigated\")[0]\n", + "print(w.name(), '-', w.definition())\n", + "print(w.examples())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Punctuation and Stop Words\n", + "Text analysis is often faster and easier if you can remove useless words. \n", + "NLTK provides a list of these stop words so it's easy to filter them out of your text prior to processing. \n", + "Here, 15% of our text is punctuation, and 40% is stop words. So we shrink the text by more than half by stripping out punctuation and stop words." + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n", + "['i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', \"you're\", \"you've\", \"you'll\", \"you'd\", 'your', 'yours', 'yourself', 'yourselves', 'he', 'him', 'his', 'himself', 'she', \"she's\", 'her', 'hers', 'herself', 'it', \"it's\", 'its', 'itself', 'they', 'them', 'their', 'theirs', 'themselves', 'what', 'which', 'who', 'whom', 'this', 'that', \"that'll\", 'these', 'those', 'am', 'is', 'are', 'was', 'were', 'be', 'been', 'being', 'have', 'has', 'had', 'having', 'do', 'does', 'did', 'doing', 'a', 'an', 'the', 'and', 'but', 'if', 'or', 'because', 'as', 'until', 'while', 'of', 'at', 'by', 'for', 'with', 'about', 'against', 'between', 'into', 'through', 'during', 'before', 'after', 'above', 'below', 'to', 'from', 'up', 'down', 'in', 'out', 'on', 'off', 'over', 'under', 'again', 'further', 'then', 'once', 'here', 'there', 'when', 'where', 'why', 'how', 'all', 'any', 'both', 'each', 'few', 'more', 'most', 'other', 'some', 'such', 'no', 'nor', 'not', 'only', 'own', 'same', 'so', 'than', 'too', 'very', 's', 't', 'can', 'will', 'just', 'don', \"don't\", 'should', \"should've\", 'now', 'd', 'll', 'm', 'o', 're', 've', 'y', 'ain', 'aren', \"aren't\", 'couldn', \"couldn't\", 'didn', \"didn't\", 'doesn', \"doesn't\", 'hadn', \"hadn't\", 'hasn', \"hasn't\", 'haven', \"haven't\", 'isn', \"isn't\", 'ma', 'mightn', \"mightn't\", 'mustn', \"mustn't\", 'needn', \"needn't\", 'shan', \"shan't\", 'shouldn', \"shouldn't\", 'wasn', \"wasn't\", 'weren', \"weren't\", 'won', \"won't\", 'wouldn', \"wouldn't\"]\n", + "260819\n", + "221767\n", + "122226\n" + ] + } + ], + "source": [ + "from string import punctuation\n", + "print(punctuation)\n", + "without_punct = [w for w in text1 if w not in punctuation] # this is called a list comprehension\n", + "\n", + "from nltk.corpus import stopwords\n", + "sw = stopwords.words('english')\n", + "print(sw)\n", + "without_sw = [w for w in without_punct if w not in sw] \n", + "\n", + "print(len(text1))\n", + "print(len(without_punct))\n", + "print(len(without_sw))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Stemming and Lemmatization\n", + "These term normalization algorithms strip the word endings off to reduce the number of root words for easier matching. \n", + "This is useful for search term matching. [NLTK stemming docs](https://www.nltk.org/api/nltk.stem.html)" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "is is\n", + "are are\n", + "bought bought\n", + "buys buy\n", + "giving give\n", + "jumps jump\n", + "jumped jump\n", + "birds bird\n", + "do do\n", + "does doe\n", + "did did\n", + "doing do\n" + ] + } + ], + "source": [ + "from nltk.stem.porter import PorterStemmer\n", + "st = PorterStemmer()\n", + "words = ['is', 'are', 'bought', 'buys', 'giving', 'jumps', 'jumped', 'birds', 'do', 'does', 'did', 'doing']\n", + "for word in words:\n", + " print(word, st.stem(word))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**WordNet Lemmatizer** \n", + "The difference is that the result of stemming may not be an actual word, but lemmatization returns the root word. NLTK supports both. \n", + "You can also try the Lancaster or Snowball stemmers. The Snowball stemmer supports numerous languages: Arabic, Danish, Dutch, English, Finnish, French, German, Hungarian, Italian, Norwegian, Portuguese, Romanian, Russian, Spanish and Swedish." + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "is is\n", + "are are\n", + "bought bought\n", + "buys buy\n", + "giving giving\n", + "jumps jump\n", + "jumped jumped\n", + "birds bird\n", + "do do\n", + "does doe\n", + "did did\n", + "doing doing\n" + ] + } + ], + "source": [ + "from nltk.stem import WordNetLemmatizer\n", + "wnl = WordNetLemmatizer()\n", + "words = ['is', 'are', 'bought', 'buys', 'giving', 'jumps', 'jumped', 'birds', 'do', 'does', 'did', 'doing']\n", + "for word in words:\n", + " print(word, wnl.lemmatize(word))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Sentence and Word Tokenizers\n", + "Sentence tokenizer breaks text down into a list of sentences. It's pretty good at handling punctuation and decimal numbers. \n", + "[Word tokenizer](https://www.nltk.org/api/nltk.tokenize.html) breaks a string down into a list of words and punctuation. \n", + "It is also easy to get parts of speech using nltk.pos_tag. There are different tagsets, depending on how much detail you want. I like universal." + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['Hello.', 'I am Joe!', 'I like Python.', '263.5 is a big number.']\n", + "['The', 'quick', 'brown', 'fox', 'jumps', 'over', 'the', 'lazy', 'dog', '.']\n" + ] + } + ], + "source": [ + "from nltk.tokenize import sent_tokenize, word_tokenize\n", + "s = 'Hello. I am Joe! I like Python. 263.5 is a big number.' # 4 sentences\n", + "print(sent_tokenize(s))\n", + "\n", + "w = word_tokenize('The quick brown fox jumps over the lazy dog.')\n", + "print(w)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Parts of Speech Tagging\n", + "To break a block of text down into its parts of speech use pos_tag. \n", + "The default tagset uses 2 or 3 letter tokens that are hard for me to understand. [StackOverflow](https://stackoverflow.com/questions/15388831/what-are-all-possible-pos-tags-of-nltk) has a great decoder for the default POS tags. \n", + "The Universal tagset gives a more familiar looking tag (noun, verb, adj). \n", + "NLTK includes several other tagsets you can try." + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['The', 'quick', 'brown', 'fox', 'jumps', 'over', 'the', 'lazy', 'dog', '.']\n", + "[('The', 'DT'), ('quick', 'JJ'), ('brown', 'NN'), ('fox', 'NN'), ('jumps', 'VBZ'), ('over', 'IN'), ('the', 'DT'), ('lazy', 'JJ'), ('dog', 'NN'), ('.', '.')]\n", + "[('The', 'DET'), ('quick', 'ADJ'), ('brown', 'NOUN'), ('fox', 'NOUN'), ('jumps', 'VERB'), ('over', 'ADP'), ('the', 'DET'), ('lazy', 'ADJ'), ('dog', 'NOUN'), ('.', '.')]\n" + ] + } + ], + "source": [ + "w = word_tokenize('The quick brown fox jumps over the lazy dog.')\n", + "print(w)\n", + "print(nltk.pos_tag(w))\n", + "print(nltk.pos_tag(w, tagset='universal'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Word2Vec\n", + "[Word2Vec](https://radimrehurek.com/gensim/models/word2vec.html) uses neural networks to analyze words in a corpus by using the contexts of words. \n", + "It takes as its input a large corpus of text, and maps unique words to a vector space, such that \n", + "words that share common contexts in the corpus are located in close proximity to one another in the space. \n", + "Word2Vec does NOT look at word meanings, it only finds words that are used in combination with other words. So *frying* and *pan* may have a high similarity. \n", + "You can see here the context of one word (pain) for two different corpora. \n", + "This uses the popular gensim library, which is not part of NLTK." + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('person', 0.9992861747741699), ('favourable', 0.998925507068634), ('meaning', 0.9987690448760986), ('effect', 0.9987439513206482), ('comfortable', 0.998741626739502), ('delay', 0.9987210035324097)]\n", + "[('even', 0.9980006217956543), ('moment', 0.9979783296585083), ('hence', 0.9979231357574463), ('without', 0.9979217052459717), ('separate', 0.9979064464569092), ('Now', 0.9979038238525391)]\n" + ] + } + ], + "source": [ + "from gensim.models import Word2Vec\n", + "emma_vec = Word2Vec(gutenberg.sents('austen-emma.txt'))\n", + "leaves_vec = Word2Vec(gutenberg.sents('whitman-leaves.txt'))\n", + "print(emma_vec.wv.most_similar('pain', topn=6))\n", + "print(leaves_vec.wv.most_similar('pain', topn=6))" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "30103\n", + "[('mercy', 0.9284727573394775),\n", + " ('liveth', 0.9062315821647644),\n", + " ('truth', 0.8941866159439087),\n", + " ('grace', 0.8938426375389099),\n", + " ('glory', 0.8936725854873657),\n", + " ('salvation', 0.8859732747077942),\n", + " ('hosts', 0.8839103579521179),\n", + " ('confession', 0.8837960958480835)]\n", + "[('making', 0.9873884916305542),\n", + " ('abundant', 0.9802387952804565),\n", + " ('realm', 0.98007732629776),\n", + " ('powers', 0.9798883199691772),\n", + " ('twice', 0.9775580763816833)]\n" + ] + } + ], + "source": [ + "from gensim.models import Word2Vec\n", + "from nltk.corpus import stopwords\n", + "from string import punctuation\n", + "import pprint as pp\n", + "\n", + "bible_sents = gutenberg.sents('bible-kjv.txt')\n", + "sw = stopwords.words('english')\n", + "bible = [[w.lower() for w in s if w not in punctuation and w not in sw] for s in bible_sents]\n", + "print(len(bible))\n", + "\n", + "bible_vec = Word2Vec(bible)\n", + "pp.pprint(bible_vec.wv.most_similar('god', topn=8))\n", + "pp.pprint(bible_vec.wv.most_similar('creation', topn=5))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### k-Means Clustering\n", + "[Clustering](http://www.nltk.org/api/nltk.cluster.html) groups similar items together. \n", + "The K-means clusterer starts with k arbitrarily chosen means (or centroids) then assigns each vector to the cluster with the closest mean. It then recalculates the means of each cluster as the centroid of its vector members. This process repeats until the cluster memberships stabilize. [NLTK docs on this example](https://www.nltk.org/_modules/nltk/cluster/kmeans.html) \n", + "This example clusters int vectors, which you can think of as points on a plane. But you could also use clustering to cluster similar documents by vocabulary/topic." + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "k-means trial 0\n", + "iteration\n", + "iteration\n", + "Clustered: [array([2, 1]), array([1, 3]), array([4, 7]), array([6, 7])]\n", + "As: [0, 0, 1, 1]\n", + "Means: [array([1.5, 2. ]), array([5., 7.])]\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "from nltk.cluster import KMeansClusterer, euclidean_distance\n", + "\n", + "vectors = [np.array(f) for f in [[2, 1], [1, 3], [4, 7], [6, 7]]]\n", + "means = [[4, 3], [5, 5]]\n", + "\n", + "clusterer = KMeansClusterer(2, euclidean_distance, initial_means=means)\n", + "clusters = clusterer.cluster(vectors, True, trace=True)\n", + "\n", + "print('Clustered:', vectors)\n", + "print('As:', clusters)\n", + "print('Means:', clusterer.means())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**k-Means Clustering, Example-2** \n", + "In this example we cluster an array of 6 points into 2 clusters. \n", + "The initial centroids are randomly chosen by the clusterer, and it does 10 iterations to regroup the clusters and recalculate centroids. " + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Clustered: [array([3, 3]), array([1, 2]), array([4, 2]), array([4, 0]), array([2, 3]), array([3, 1])]\n", + "As: [0, 0, 1, 1, 0, 1]\n", + "Means: [array([2. , 2.66666667]), array([3.66666667, 1. ])]\n", + "classify([2 2]): 0\n" + ] + } + ], + "source": [ + "vectors = [np.array(f) for f in [[3, 3], [1, 2], [4, 2], [4, 0], [2, 3], [3, 1]]]\n", + "\n", + "# test k-means using 2 means, euclidean distance, and 10 trial clustering repetitions with random seeds\n", + "clusterer = KMeansClusterer(2, euclidean_distance, repeats=10)\n", + "clusters = clusterer.cluster(vectors, True)\n", + "centroids = clusterer.means()\n", + "print('Clustered:', vectors)\n", + "print('As:', clusters)\n", + "print('Means:', centroids)\n", + "\n", + "# classify a new vector\n", + "vector = np.array([2,2])\n", + "print('classify(%s):' % vector, end=' ')\n", + "print(clusterer.classify(vector))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Plot a Chart of the Clusters in Example-2** \n", + "Make a Scatter Plot of the two clusters using matplotlib.pyplot. \n", + "We plot all the points in cluster-0 blue, and all the points in cluster-1 red. Then we plot the two centroids in orange. \n", + "I used list comprehensions to create new lists for all the x0, y0, x1 and y1 values." + ] + }, + { + "cell_type": "code", + "execution_count": 104, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "x0 = np.array([x[0] for idx, x in enumerate(vectors) if clusters[idx]==0])\n", + "y0 = np.array([x[1] for idx, x in enumerate(vectors) if clusters[idx]==0])\n", + "plt.scatter(x0,y0, color='blue')\n", + "x1 = np.array([x[0] for idx, x in enumerate(vectors) if clusters[idx]==1])\n", + "y1 = np.array([x[1] for idx, x in enumerate(vectors) if clusters[idx]==1])\n", + "plt.scatter(x1,y1, color='red')\n", + "\n", + "xc = np.array([x[0] for x in centroids])\n", + "yc = np.array([x[1] for x in centroids])\n", + "plt.scatter(xc,yc, color='orange')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Numpy/Numpy commands.txt b/Numpy/Numpy commands.txt new file mode 100644 index 00000000..c76953ba --- /dev/null +++ b/Numpy/Numpy commands.txt @@ -0,0 +1,155 @@ +https://docs.scipy.org/doc/numpy-1.12.0/reference/ + +Numpy + install Numpy using pip + import numpy as np + ndarray - an N-dimensional array, which describes a collection of “items” of the same type + array(list) # constructor + asarray(a[, dtype, order]) # Convert the input to an array + Constants: + ndarray.shape tuple of array dimensions + ndarray.size number of elements in array + ndarray.itemsize size of one element + ndarray.dtype data type of elements + ndarray.flat 1D iterator over elements of array + Common Functions + np.tolist() + np.reshape(a, (3,2)) + np.swapaxes(axis1, axis2) + np.copy() + arange() + Statistics Functions: + np.sum(a, axis) + np.prod + np.min + np.max + np.mean + np.std standard deviation + np.var + np.sort(axis) + Other Functions: + String operations + logical operations - AND, OR, XOR, NOT, >, <, =, ... + trig functions + complex numbers (real + imaginary) + polynomials + 2D matrix operations + Fourier transforms +==================================================================================== +import numpy as np +x = [0,1,2,3,4,5] +a = np.array(x) + +index: a[2] + +slice: a[start:stop:step] + a[1:4:2] + a[3:] + a[:3] +a.shape +a.size +a.itemsize +a.dtype + +b = np.array([[1,2,3], [4,5,6]]) +b.swapaxes(0,1) + +a = np.arange(0,6) +a = np.arange(0,6).reshape(2,3) +======================================================================================== +import numpy as np + +pip install numpy +pip install numpy --upgrade + +import numpy as np + +a = np.array([2,3,4]) + +a = np.arange(1, 12, 2) # (from, to, step) + +a = np.linspace(1, 12, 6) # (first, last, num_elements) float data type + +a.reshape(3,2) +a = a.reshape(3,2) + +a.size + +a.shape + +a.dtype + +a.itemsize + +# this works: +b = np.array([(1.5,2,3), (4,5,6)]) + +# but this does not work: +b = np.array(1,2,3) # square brackets are required + +a < 4 # prints True/False + +a * 3 # multiplies each element by 3 +a *= 3 # saves result to a + +a = np.zeros((3,4)) + +a = np.ones((2,3)) + +a = np.array([2,3,4], dtype=np.int16) + +a = np.random.random((2,3)) + +np.set_printoptions(precision=2, suppress=True) # show 2 decimal places, suppress scientific notation + +a = np.random.randint(0,10,5) +a.sum() +a.min() +a.max() +a.mean() +a.var() # variance +a.std() # standard deviation + + +a.sum(axis=1) +a.min(axis=0) + +a.argmin() # index of min element +a.argmax() # index of max element +a.argsort() # returns array of indices that would put the array in sorted order +a.sort() # in place sort + +# indexing, slicing, iterating +a = np.arange(10)**2 +a[2] +a[2:5] + +for i in a: + print (i ** 2) +a[::-1] # reverses array + +for i in a.flat: + print (i) + + +a.transpose() + +a.ravel() # flattens to 1D + +# read in csv data file +data = np.loadtxt("data.txt", dtype=np.uint8, delimiter=",", skiprows=1 ) +# loadtxt does not handle missing values. to handle such exceptions use genfromtxt instead. + +data = np.loadtxt("data.txt", dtype=np.uint8, delimiter=",", skiprows=1, usecols=[0,1,2,3]) + +np.random.shuffle(a) + +a = np.random.random(5) + +np.random.choice(a) + +np.random.random_integers(5,10,2) # (low, high inclusive, size) + + + + diff --git a/Numpy/Numpy.pptx b/Numpy/Numpy.pptx new file mode 100644 index 00000000..329ca480 Binary files /dev/null and b/Numpy/Numpy.pptx differ diff --git a/Numpy/Python Numpy Intro.ipynb b/Numpy/Python Numpy Intro.ipynb new file mode 100644 index 00000000..637478b8 --- /dev/null +++ b/Numpy/Python Numpy Intro.ipynb @@ -0,0 +1,558 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python Numpy Intro\n", + "An introduction to the [Python Numpy](http://www.numpy.org/) numerical python library. \n", + "The core data structure behind Numpy is the n-dimensional [Numpy Array](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.html). It is 3x to 10x faster and more memory efficient than Python's lists because, similar to Java arrays, it uses contiguous blocks of memory, and all elements are the same data type so there is no type checking at runtime. The Numpy library also includes many built-in code-saving mathematical functions that can be performed on an entire array or any slice of an array with a single line of code (ie. no for loops). \n", + "Numpy n-dimensional arrays are also sometimes referred to as nd-arrays.\n", + "\n", + "**Install Numpy** using pip: pip install numpy\n", + "The convention for importing numpy is *import numpy as np*.\n", + "\n", + "import numpy as np\n", + "\n", + "### Creating a Numpy Array\n", + "There are MANY ways to instantiate a numpy array. I covered the most common ones below. [Docs here cover more constructors](https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.array-creation.html).\n", + "- Pass in a list to the array() constructor\n", + "- Use the arange function, similar to the range function but used for Numpy arrays. Uses arguments, (start, stop+1, step).\n", + "- Use linspace to create an array of n equally spaced values. Uses arguments (start, stop, number of items).\n", + "- Create an array empty, full of ones or zeros, or full of any fill value. Uses argument (shape) in the form of a tuple. \n", + "\n", + "You can pass in dtype as an optional argument for any of these. This is especially useful if you want to limit memory usage for a very large array of small integers because int8 and int16 use much less space than the default int32." + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[ 1 3 5 7 9 11]\n", + "[ 1 3 5 7 9 11]\n", + "[5. 5.25 5.5 5.75 6. 6.25 6.5 6.75 7. 7.25 7.5 7.75 8. ]\n", + "[[0. 0.]\n", + " [0. 0.]\n", + " [0. 0.]\n", + " [0. 0.]]\n", + "[[1 1 1]\n", + " [1 1 1]]\n", + "[88 88 88 88 88 88]\n", + "[25 30 35 40]\n", + "[[ 1 3 5]\n", + " [ 7 9 11]]\n", + "[[0 0 0]\n", + " [0 0 0]]\n" + ] + } + ], + "source": [ + "a = np.array([1,3,5,7,9,11])\n", + "print(a)\n", + "\n", + "a = np.arange(1, 12, 2) # (start, stop, step)\n", + "print(a)\n", + "\n", + "a = np.linspace(5, 8, 13) # (start, stop, number of items)\n", + "print(a)\n", + "\n", + "a = np.zeros((4, 2))\n", + "print(a)\n", + "\n", + "a = np.ones((2, 3), dtype=np.int16)\n", + "print(a)\n", + "\n", + "a = np.full((6,), 88)\n", + "print(a)\n", + "\n", + "a = np.fromstring('25 30 35 40', dtype=np.int, sep=' ')\n", + "print(a)\n", + "\n", + "a = np.array([[1,3,5],[7,9,11]])\n", + "print(a)\n", + "\n", + "b = np.zeros_like(a) # _like gives you a new array in the same shape as the argument.\n", + "print(b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Numpy Array Attributes\n", + "Get size (number of items), shape (dimensions), itemsize(bytes of memory for each item), and dtype (numpy data type). \n", + "See how many bytes of memory space the whole array uses from the product of size and itemsize. See [complete list of attributes and methods](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.html)." + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n", + "(2, 3)\n", + "2\n", + "4\n", + "int32\n", + "24\n" + ] + } + ], + "source": [ + "print(a.size)\n", + "print(a.shape)\n", + "print(a.ndim)\n", + "print(a.itemsize)\n", + "print(a.dtype)\n", + "print(a.nbytes) # same as a.size * a.itemsize" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Indexing and Slicing\n", + "Use square brackets to get any item of an array by index. Multi-dimensional arrays can use multiple square brackets.\n", + "\n", + "There are three arguments for slicing arrays, all are optional: [start:stop:step]. \n", + " If start is left blank it defaults to 0. If stop is left blank it defaults to the end of the array. Step defaults to 1." + ] + }, + { + "cell_type": "code", + "execution_count": 98, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[ 1 3 5]\n", + " [ 7 9 11]]\n", + "[ 7 9 11]\n", + "5\n", + "[]\n", + "[[1 3 5]]\n", + "[[ 7 9 11]]\n", + "[[3]\n", + " [9]]\n" + ] + } + ], + "source": [ + "print(a)\n", + "print(a[1])\n", + "print(a[0][2])\n", + "print(b[2:4])\n", + "\n", + "print(a[:1])\n", + "print(a[1:3:2])\n", + "print(a[:, 1:2]) # all elements on dimension 0, only element 1 on dimension 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Reshape, Swap Axes, Flatten\n", + "See full list of [array manipulation routines](https://docs.scipy.org/doc/numpy/reference/routines.array-manipulation.html)." + ] + }, + { + "cell_type": "code", + "execution_count": 99, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[-9 -8 -7]\n", + " [-6 -5 -4]]\n", + "[[-9 -6]\n", + " [-8 -5]\n", + " [-7 -4]]\n", + "[-9 -6 -8 -5 -7 -4]\n" + ] + } + ], + "source": [ + "c = np.arange(-9, -3,).reshape(2,3)\n", + "print(c)\n", + "\n", + "c = c.swapaxes(0,1)\n", + "print(c)\n", + "\n", + "c = c.flatten()\n", + "print(c)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Use dtype to Save Space\n", + "Default data types (int32 and float64) are memory hogs. If you don't need the higher precision you can save a lot of memory space and improve speed of operations by using smaller data types. For large data sets this makes a big difference." + ] + }, + { + "cell_type": "code", + "execution_count": 100, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "int32 \n", + "400\n", + "int8 \n", + "100\n" + ] + } + ], + "source": [ + "d = np.arange(0,100)\n", + "print(d.dtype, type(d[1]))\n", + "print(d.nbytes)\n", + "\n", + "d = np.arange(0,100, dtype='int8')\n", + "print(d.dtype, type(d[1]))\n", + "print(d.nbytes)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### UpCasting, Rounding, Print Formatting\n", + "Data type of all Items is upcast to the most precise element. " + ] + }, + { + "cell_type": "code", + "execution_count": 101, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "float64\n", + "[[1.57 2. 3. ]\n", + " [4. 5. 6. ]]\n", + "[[1.57 2. 3. ]\n", + " [4. 5. 6. ]]\n" + ] + } + ], + "source": [ + "e = np.array([(1.566666,2,3), (4,5,6)])\n", + "print(e.dtype)\n", + "\n", + "e = e.round(4)\n", + "print(e)\n", + "\n", + "np.set_printoptions(precision=2, suppress=True) # show 2 decimal places, suppress scientific notation\n", + "print(e)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Numpy Data Types Available\n", + "uint is unsigned int, for positive numbers." + ] + }, + { + "cell_type": "code", + "execution_count": 102, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'complex': [, ],\n", + " 'float': [,\n", + " ,\n", + " ],\n", + " 'int': [,\n", + " ,\n", + " ,\n", + " ,\n", + " ],\n", + " 'others': [,\n", + " ,\n", + " ,\n", + " ,\n", + " ],\n", + " 'uint': [,\n", + " ,\n", + " ,\n", + " ,\n", + " ]}\n" + ] + } + ], + "source": [ + "import pprint as pp\n", + "pp.pprint(np.sctypes)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Reading and Writing to Files\n", + "Can use [loadtxt](https://docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html#numpy.loadtxt), or [genfromtxt](https://docs.scipy.org/doc/numpy/reference/generated/numpy.genfromtxt.html#numpy.genfromtxt) to load data to load an entire file into an array at once. Genfromtxt is more fault tolerant. \n", + "Use [savetxt](https://docs.scipy.org/doc/numpy/reference/generated/numpy.savetxt.html#numpy.savetxt) to write an array to file." + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[9 3 8 7 6 1 0 4 2 5]\n", + " [1 7 4 9 2 6 8 3 5 0]\n", + " [4 8 3 9 5 7 2 6 0 1]\n", + " [1 7 4 2 5 9 6 8 0 3]\n", + " [0 7 5 2 8 6 3 4 1 9]\n", + " [5 9 1 4 7 0 3 6 8 2]]\n", + "int32\n" + ] + } + ], + "source": [ + "f = np.loadtxt('data.txt', skiprows=1, delimiter=',', dtype=np.int32)\n", + "print(f)\n", + "print(f.dtype)\n", + "\n", + "np.savetxt('data2.txt', f, delimiter=';', fmt='%d', header='a;b;c;d;e;f;g;h;i;j', comments='')" + ] + }, + { + "cell_type": "code", + "execution_count": 111, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[9 3 8 7 6 1 0 4 2 5]\n", + " [1 7 4 9 2 6 8 3 5 0]\n", + " [4 8 3 9 5 7 2 6 0 1]\n", + " [1 7 4 2 5 9 6 8 0 3]\n", + " [0 7 5 2 8 6 3 4 1 9]\n", + " [5 9 1 4 7 0 3 6 8 2]]\n" + ] + } + ], + "source": [ + "g = np.genfromtxt('data.txt', skip_header=1, delimiter=',', dtype=np.int32)\n", + "print(g)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Mathematical Functions\n", + "Numpy has an extensive list of [math and scientific functions](https://docs.scipy.org/doc/numpy/reference/routines.html). \n", + "The best part is that you don't have to iterate. You can apply an operation to the entire array or a slice of an array at once." + ] + }, + { + "cell_type": "code", + "execution_count": 105, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[ True False True True True False False False False True]\n", + " [False True False True False True True False True False]\n", + " [False True False True True True False True False False]\n", + " [False True False False True True True True False False]\n", + " [False True True False True True False False False True]\n", + " [ True True False False True False False True True False]]\n", + "[[80 8 63 48 35 0 -1 15 3 24]\n", + " [ 0 48 15 80 3 35 63 8 24 -1]\n", + " [15 63 8 80 24 48 3 35 -1 0]\n", + " [ 0 48 15 3 24 80 35 63 -1 8]\n", + " [-1 48 24 3 63 35 8 15 0 80]\n", + " [24 80 0 15 48 -1 8 35 63 3]]\n" + ] + } + ], + "source": [ + "print(g > 4)\n", + "print(g ** 2 - 1)" + ] + }, + { + "cell_type": "code", + "execution_count": 106, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "9\n", + "270\n", + "4.5\n", + "8.25\n", + "2.8722813232690143\n", + "[45 45 45 45 45 45]\n", + "[0 3 1 2 2 0 0 3 0 0]\n", + "6\n", + "0\n", + "[[6 5 8 1 7 9 4 3 2 0]\n", + " [9 0 4 7 2 8 5 1 6 3]\n", + " [8 9 6 2 0 4 7 5 1 3]\n", + " [8 0 3 9 2 4 6 1 7 5]\n", + " [0 8 3 6 7 2 5 1 4 9]\n", + " [5 2 9 6 3 0 7 4 8 1]]\n" + ] + } + ], + "source": [ + "print(g.min())\n", + "print(g.max())\n", + "print(g.sum())\n", + "print(g.mean())\n", + "print(g.var()) # variance\n", + "print(g.std()) # standard deviation\n", + "\n", + "print(g.sum(axis=1))\n", + "print(g.min(axis=0))\n", + "\n", + "print(g.argmin()) # index of min element\n", + "print(g.argmax()) # index of max element\n", + "print(g.argsort()) # returns array of indices that would put the array in sorted order" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Column Operations\n", + "Apply functions only to specific columns by slicing, or create a new array from the columns you want, then work on them. \n", + "But Beware that creating a new pointer to the same data can screw up your data if you're not careful." + ] + }, + { + "cell_type": "code", + "execution_count": 113, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[8]\n", + " [4]\n", + " [3]\n", + " [4]\n", + " [5]\n", + " [1]]\n", + "8\n", + "298.607881119482\n", + "[[ 9 3 8 70000 6 1 0 4 2 5]\n", + " [ 1 7 4 90000 2 6 8 3 5 0]\n", + " [ 4 8 3 90000 5 7 2 6 0 1]\n", + " [ 1 7 4 20000 5 9 6 8 0 3]\n", + " [ 0 7 5 20000 8 6 3 4 1 9]\n", + " [ 5 9 1 40000 7 0 3 6 8 2]]\n" + ] + } + ], + "source": [ + "print(g[:, 2:3])\n", + "print(g[:, 2:3].max())\n", + "\n", + "col3 = g[:, 3:4] # not a copy, just a pointer to a slice of g\n", + "print(col3.std())\n", + "\n", + "col3 *= 100 # Beware: this is applied to g data\n", + "print(g)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Numpy Random Functions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.set_printoptions(precision=5, suppress=True) # show 5 decimal places, suppress scientific notation\n", + "h = np.random.random(6)\n", + "print(h)\n", + "\n", + "h = np.random.randint(10, 99, 8) # (low, high inclusive, size)\n", + "print(h)\n", + "\n", + "np.random.shuffle(h) # in-place shuffle\n", + "print(h)\n", + "\n", + "print(np.random.choice(h))\n", + "\n", + "h.sort() # in-place sort\n", + "print(h)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Numpy/data.txt b/Numpy/data.txt new file mode 100644 index 00000000..d3e350d6 --- /dev/null +++ b/Numpy/data.txt @@ -0,0 +1,7 @@ +a,b,c,d,e,f,g,h,i,j +9,3,8,7,6,1,0,4,2,5 +1,7,4,9,2,6,8,3,5,0 +4,8,3,9,5,7,2,6,0,1 +1,7,4,2,5,9,6,8,0,3 +0,7,5,2,8,6,3,4,1,9 +5,9,1,4,7,0,3,6,8,2 diff --git a/Object Oriented Programming/Python OOP.pptx b/Object Oriented Programming/Python OOP.pptx new file mode 100644 index 00000000..5fcc108d Binary files /dev/null and b/Object Oriented Programming/Python OOP.pptx differ diff --git a/Object Oriented Programming/building our first class.py b/Object Oriented Programming/building our first class.py new file mode 100644 index 00000000..51411d5e --- /dev/null +++ b/Object Oriented Programming/building our first class.py @@ -0,0 +1,20 @@ +#Today we will learn how to create a class and other attributes of class +#Below is the method how classes are defined +class Student: + pass + +#Below is the method to create object , Here Varun and rohan are two objects of Class Student +Varun = Student() +larry = Student() + +# Now after creating objects we can use them to call variables +Varun.name = "Harry" +Varun.std = 12 +Varun.section = 1 +larry.std = 9 +larry.subjects = ["hindi", "physics"] +print(Varun.section, larry.subjects) + + + + diff --git a/Object Oriented Programming/classes.py b/Object Oriented Programming/classes.py new file mode 100644 index 00000000..b5585312 --- /dev/null +++ b/Object Oriented Programming/classes.py @@ -0,0 +1,70 @@ +# from shape_class import * + +class Shape: + def __init__(self, color=None): + self.color = color + + def get_color(self): + return self.color + + def __str__(self): + return self.get_color() + ' Shape' + +class Rectangle(Shape): + def __init__(self, color, length, width): + super().__init__(color) + self.length = length + self.width = width + + def get_area(self): + return self.length * self.width + + def get_perimeter(self): + return 2 * (self.length + self.width) + + def __str__(self): + return self.get_color() + ' ' + str(self.length) + 'x' + str(self.width) + ' ' + type(self).__name__ + +from math import pi +class Circle(Shape): + def __init__(self, color, radius): + super().__init__(color) + self.radius = radius + + def get_area(self): + return pi * self.radius ** 2 + + def get_perimeter(self): + return 2 * pi * self.radius + +def print_shape_data(self): + print('Shape: ', type(self).__name__) + print('Color: ', self.get_color()) + print('Area: ', self.get_area()) + print('Perimeter:', self.get_perimeter()) + +shape = Shape('red') +print('shape is', shape.get_color()) + +rect = Rectangle('blue', 6, 4) +print('rect is', rect.get_color(), ' with area:', rect.get_area(), ' and perimeter:', rect.get_perimeter()) + +circ = Circle('green', 5) +print('circ is', circ.get_color(), ' with area:', circ.get_area(), ' and perimeter:', circ.get_perimeter()) + +print('rect is a', type(rect).__name__) +print('circ is a', type(circ).__name__, '\n') + + +my_new_shape = Rectangle('yellow', 17, 9) +print_shape_data(my_new_shape) + +print(type(my_new_shape)) +print(my_new_shape) + + + + + + + diff --git a/Object Oriented Programming/shape_class.py b/Object Oriented Programming/shape_class.py new file mode 100644 index 00000000..1708e4dd --- /dev/null +++ b/Object Oriented Programming/shape_class.py @@ -0,0 +1,9 @@ +class Shape: + def __init__(self, color=None): + self.color = color + + def get_color(self): + return self.color + + def __str__(self): + return self.get_color() + ' Shape' diff --git a/Pandas/Admission_Predict_Ver1.1.csv b/Pandas/Admission_Predict_Ver1.1.csv new file mode 100644 index 00000000..ff4d3f2a --- /dev/null +++ b/Pandas/Admission_Predict_Ver1.1.csv @@ -0,0 +1,501 @@ +Serial No.,GRE Score,TOEFL Score,University Rating,SOP,LOR,CGPA,Research,Chance of Admit +1,337,118,4,4.5,4.5,9.65,1,0.92 +2,324,107,4,4,4.5,8.87,1,0.76 +3,316,104,3,3,3.5,8,1,0.72 +4,322,110,3,3.5,2.5,8.67,1,0.8 +5,314,103,2,2,3,8.21,0,0.65 +6,330,115,5,4.5,3,9.34,1,0.9 +7,321,109,3,3,4,8.2,1,0.75 +8,308,101,2,3,4,7.9,0,0.68 +9,302,102,1,2,1.5,8,0,0.5 +10,323,108,3,3.5,3,8.6,0,0.45 +11,325,106,3,3.5,4,8.4,1,0.52 +12,327,111,4,4,4.5,9,1,0.84 +13,328,112,4,4,4.5,9.1,1,0.78 +14,307,109,3,4,3,8,1,0.62 +15,311,104,3,3.5,2,8.2,1,0.61 +16,314,105,3,3.5,2.5,8.3,0,0.54 +17,317,107,3,4,3,8.7,0,0.66 +18,319,106,3,4,3,8,1,0.65 +19,318,110,3,4,3,8.8,0,0.63 +20,303,102,3,3.5,3,8.5,0,0.62 +21,312,107,3,3,2,7.9,1,0.64 +22,325,114,4,3,2,8.4,0,0.7 +23,328,116,5,5,5,9.5,1,0.94 +24,334,119,5,5,4.5,9.7,1,0.95 +25,336,119,5,4,3.5,9.8,1,0.97 +26,340,120,5,4.5,4.5,9.6,1,0.94 +27,322,109,5,4.5,3.5,8.8,0,0.76 +28,298,98,2,1.5,2.5,7.5,1,0.44 +29,295,93,1,2,2,7.2,0,0.46 +30,310,99,2,1.5,2,7.3,0,0.54 +31,300,97,2,3,3,8.1,1,0.65 +32,327,103,3,4,4,8.3,1,0.74 +33,338,118,4,3,4.5,9.4,1,0.91 +34,340,114,5,4,4,9.6,1,0.9 +35,331,112,5,4,5,9.8,1,0.94 +36,320,110,5,5,5,9.2,1,0.88 +37,299,106,2,4,4,8.4,0,0.64 +38,300,105,1,1,2,7.8,0,0.58 +39,304,105,1,3,1.5,7.5,0,0.52 +40,307,108,2,4,3.5,7.7,0,0.48 +41,308,110,3,3.5,3,8,1,0.46 +42,316,105,2,2.5,2.5,8.2,1,0.49 +43,313,107,2,2.5,2,8.5,1,0.53 +44,332,117,4,4.5,4,9.1,0,0.87 +45,326,113,5,4.5,4,9.4,1,0.91 +46,322,110,5,5,4,9.1,1,0.88 +47,329,114,5,4,5,9.3,1,0.86 +48,339,119,5,4.5,4,9.7,0,0.89 +49,321,110,3,3.5,5,8.85,1,0.82 +50,327,111,4,3,4,8.4,1,0.78 +51,313,98,3,2.5,4.5,8.3,1,0.76 +52,312,100,2,1.5,3.5,7.9,1,0.56 +53,334,116,4,4,3,8,1,0.78 +54,324,112,4,4,2.5,8.1,1,0.72 +55,322,110,3,3,3.5,8,0,0.7 +56,320,103,3,3,3,7.7,0,0.64 +57,316,102,3,2,3,7.4,0,0.64 +58,298,99,2,4,2,7.6,0,0.46 +59,300,99,1,3,2,6.8,1,0.36 +60,311,104,2,2,2,8.3,0,0.42 +61,309,100,2,3,3,8.1,0,0.48 +62,307,101,3,4,3,8.2,0,0.47 +63,304,105,2,3,3,8.2,1,0.54 +64,315,107,2,4,3,8.5,1,0.56 +65,325,111,3,3,3.5,8.7,0,0.52 +66,325,112,4,3.5,3.5,8.92,0,0.55 +67,327,114,3,3,3,9.02,0,0.61 +68,316,107,2,3.5,3.5,8.64,1,0.57 +69,318,109,3,3.5,4,9.22,1,0.68 +70,328,115,4,4.5,4,9.16,1,0.78 +71,332,118,5,5,5,9.64,1,0.94 +72,336,112,5,5,5,9.76,1,0.96 +73,321,111,5,5,5,9.45,1,0.93 +74,314,108,4,4.5,4,9.04,1,0.84 +75,314,106,3,3,5,8.9,0,0.74 +76,329,114,2,2,4,8.56,1,0.72 +77,327,112,3,3,3,8.72,1,0.74 +78,301,99,2,3,2,8.22,0,0.64 +79,296,95,2,3,2,7.54,1,0.44 +80,294,93,1,1.5,2,7.36,0,0.46 +81,312,105,3,2,3,8.02,1,0.5 +82,340,120,4,5,5,9.5,1,0.96 +83,320,110,5,5,4.5,9.22,1,0.92 +84,322,115,5,4,4.5,9.36,1,0.92 +85,340,115,5,4.5,4.5,9.45,1,0.94 +86,319,103,4,4.5,3.5,8.66,0,0.76 +87,315,106,3,4.5,3.5,8.42,0,0.72 +88,317,107,2,3.5,3,8.28,0,0.66 +89,314,108,3,4.5,3.5,8.14,0,0.64 +90,316,109,4,4.5,3.5,8.76,1,0.74 +91,318,106,2,4,4,7.92,1,0.64 +92,299,97,3,5,3.5,7.66,0,0.38 +93,298,98,2,4,3,8.03,0,0.34 +94,301,97,2,3,3,7.88,1,0.44 +95,303,99,3,2,2.5,7.66,0,0.36 +96,304,100,4,1.5,2.5,7.84,0,0.42 +97,306,100,2,3,3,8,0,0.48 +98,331,120,3,4,4,8.96,1,0.86 +99,332,119,4,5,4.5,9.24,1,0.9 +100,323,113,3,4,4,8.88,1,0.79 +101,322,107,3,3.5,3.5,8.46,1,0.71 +102,312,105,2,2.5,3,8.12,0,0.64 +103,314,106,2,4,3.5,8.25,0,0.62 +104,317,104,2,4.5,4,8.47,0,0.57 +105,326,112,3,3.5,3,9.05,1,0.74 +106,316,110,3,4,4.5,8.78,1,0.69 +107,329,111,4,4.5,4.5,9.18,1,0.87 +108,338,117,4,3.5,4.5,9.46,1,0.91 +109,331,116,5,5,5,9.38,1,0.93 +110,304,103,5,5,4,8.64,0,0.68 +111,305,108,5,3,3,8.48,0,0.61 +112,321,109,4,4,4,8.68,1,0.69 +113,301,107,3,3.5,3.5,8.34,1,0.62 +114,320,110,2,4,3.5,8.56,0,0.72 +115,311,105,3,3.5,3,8.45,1,0.59 +116,310,106,4,4.5,4.5,9.04,1,0.66 +117,299,102,3,4,3.5,8.62,0,0.56 +118,290,104,4,2,2.5,7.46,0,0.45 +119,296,99,2,3,3.5,7.28,0,0.47 +120,327,104,5,3,3.5,8.84,1,0.71 +121,335,117,5,5,5,9.56,1,0.94 +122,334,119,5,4.5,4.5,9.48,1,0.94 +123,310,106,4,1.5,2.5,8.36,0,0.57 +124,308,108,3,3.5,3.5,8.22,0,0.61 +125,301,106,4,2.5,3,8.47,0,0.57 +126,300,100,3,2,3,8.66,1,0.64 +127,323,113,3,4,3,9.32,1,0.85 +128,319,112,3,2.5,2,8.71,1,0.78 +129,326,112,3,3.5,3,9.1,1,0.84 +130,333,118,5,5,5,9.35,1,0.92 +131,339,114,5,4,4.5,9.76,1,0.96 +132,303,105,5,5,4.5,8.65,0,0.77 +133,309,105,5,3.5,3.5,8.56,0,0.71 +134,323,112,5,4,4.5,8.78,0,0.79 +135,333,113,5,4,4,9.28,1,0.89 +136,314,109,4,3.5,4,8.77,1,0.82 +137,312,103,3,5,4,8.45,0,0.76 +138,316,100,2,1.5,3,8.16,1,0.71 +139,326,116,2,4.5,3,9.08,1,0.8 +140,318,109,1,3.5,3.5,9.12,0,0.78 +141,329,110,2,4,3,9.15,1,0.84 +142,332,118,2,4.5,3.5,9.36,1,0.9 +143,331,115,5,4,3.5,9.44,1,0.92 +144,340,120,4,4.5,4,9.92,1,0.97 +145,325,112,2,3,3.5,8.96,1,0.8 +146,320,113,2,2,2.5,8.64,1,0.81 +147,315,105,3,2,2.5,8.48,0,0.75 +148,326,114,3,3,3,9.11,1,0.83 +149,339,116,4,4,3.5,9.8,1,0.96 +150,311,106,2,3.5,3,8.26,1,0.79 +151,334,114,4,4,4,9.43,1,0.93 +152,332,116,5,5,5,9.28,1,0.94 +153,321,112,5,5,5,9.06,1,0.86 +154,324,105,3,3,4,8.75,0,0.79 +155,326,108,3,3,3.5,8.89,0,0.8 +156,312,109,3,3,3,8.69,0,0.77 +157,315,105,3,2,2.5,8.34,0,0.7 +158,309,104,2,2,2.5,8.26,0,0.65 +159,306,106,2,2,2.5,8.14,0,0.61 +160,297,100,1,1.5,2,7.9,0,0.52 +161,315,103,1,1.5,2,7.86,0,0.57 +162,298,99,1,1.5,3,7.46,0,0.53 +163,318,109,3,3,3,8.5,0,0.67 +164,317,105,3,3.5,3,8.56,0,0.68 +165,329,111,4,4.5,4,9.01,1,0.81 +166,322,110,5,4.5,4,8.97,0,0.78 +167,302,102,3,3.5,5,8.33,0,0.65 +168,313,102,3,2,3,8.27,0,0.64 +169,293,97,2,2,4,7.8,1,0.64 +170,311,99,2,2.5,3,7.98,0,0.65 +171,312,101,2,2.5,3.5,8.04,1,0.68 +172,334,117,5,4,4.5,9.07,1,0.89 +173,322,110,4,4,5,9.13,1,0.86 +174,323,113,4,4,4.5,9.23,1,0.89 +175,321,111,4,4,4,8.97,1,0.87 +176,320,111,4,4.5,3.5,8.87,1,0.85 +177,329,119,4,4.5,4.5,9.16,1,0.9 +178,319,110,3,3.5,3.5,9.04,0,0.82 +179,309,108,3,2.5,3,8.12,0,0.72 +180,307,102,3,3,3,8.27,0,0.73 +181,300,104,3,3.5,3,8.16,0,0.71 +182,305,107,2,2.5,2.5,8.42,0,0.71 +183,299,100,2,3,3.5,7.88,0,0.68 +184,314,110,3,4,4,8.8,0,0.75 +185,316,106,2,2.5,4,8.32,0,0.72 +186,327,113,4,4.5,4.5,9.11,1,0.89 +187,317,107,3,3.5,3,8.68,1,0.84 +188,335,118,5,4.5,3.5,9.44,1,0.93 +189,331,115,5,4.5,3.5,9.36,1,0.93 +190,324,112,5,5,5,9.08,1,0.88 +191,324,111,5,4.5,4,9.16,1,0.9 +192,323,110,5,4,5,8.98,1,0.87 +193,322,114,5,4.5,4,8.94,1,0.86 +194,336,118,5,4.5,5,9.53,1,0.94 +195,316,109,3,3.5,3,8.76,0,0.77 +196,307,107,2,3,3.5,8.52,1,0.78 +197,306,105,2,3,2.5,8.26,0,0.73 +198,310,106,2,3.5,2.5,8.33,0,0.73 +199,311,104,3,4.5,4.5,8.43,0,0.7 +200,313,107,3,4,4.5,8.69,0,0.72 +201,317,103,3,2.5,3,8.54,1,0.73 +202,315,110,2,3.5,3,8.46,1,0.72 +203,340,120,5,4.5,4.5,9.91,1,0.97 +204,334,120,5,4,5,9.87,1,0.97 +205,298,105,3,3.5,4,8.54,0,0.69 +206,295,99,2,2.5,3,7.65,0,0.57 +207,315,99,2,3.5,3,7.89,0,0.63 +208,310,102,3,3.5,4,8.02,1,0.66 +209,305,106,2,3,3,8.16,0,0.64 +210,301,104,3,3.5,4,8.12,1,0.68 +211,325,108,4,4.5,4,9.06,1,0.79 +212,328,110,4,5,4,9.14,1,0.82 +213,338,120,4,5,5,9.66,1,0.95 +214,333,119,5,5,4.5,9.78,1,0.96 +215,331,117,4,4.5,5,9.42,1,0.94 +216,330,116,5,5,4.5,9.36,1,0.93 +217,322,112,4,4.5,4.5,9.26,1,0.91 +218,321,109,4,4,4,9.13,1,0.85 +219,324,110,4,3,3.5,8.97,1,0.84 +220,312,104,3,3.5,3.5,8.42,0,0.74 +221,313,103,3,4,4,8.75,0,0.76 +222,316,110,3,3.5,4,8.56,0,0.75 +223,324,113,4,4.5,4,8.79,0,0.76 +224,308,109,2,3,4,8.45,0,0.71 +225,305,105,2,3,2,8.23,0,0.67 +226,296,99,2,2.5,2.5,8.03,0,0.61 +227,306,110,2,3.5,4,8.45,0,0.63 +228,312,110,2,3.5,3,8.53,0,0.64 +229,318,112,3,4,3.5,8.67,0,0.71 +230,324,111,4,3,3,9.01,1,0.82 +231,313,104,3,4,4.5,8.65,0,0.73 +232,319,106,3,3.5,2.5,8.33,1,0.74 +233,312,107,2,2.5,3.5,8.27,0,0.69 +234,304,100,2,2.5,3.5,8.07,0,0.64 +235,330,113,5,5,4,9.31,1,0.91 +236,326,111,5,4.5,4,9.23,1,0.88 +237,325,112,4,4,4.5,9.17,1,0.85 +238,329,114,5,4.5,5,9.19,1,0.86 +239,310,104,3,2,3.5,8.37,0,0.7 +240,299,100,1,1.5,2,7.89,0,0.59 +241,296,101,1,2.5,3,7.68,0,0.6 +242,317,103,2,2.5,2,8.15,0,0.65 +243,324,115,3,3.5,3,8.76,1,0.7 +244,325,114,3,3.5,3,9.04,1,0.76 +245,314,107,2,2.5,4,8.56,0,0.63 +246,328,110,4,4,2.5,9.02,1,0.81 +247,316,105,3,3,3.5,8.73,0,0.72 +248,311,104,2,2.5,3.5,8.48,0,0.71 +249,324,110,3,3.5,4,8.87,1,0.8 +250,321,111,3,3.5,4,8.83,1,0.77 +251,320,104,3,3,2.5,8.57,1,0.74 +252,316,99,2,2.5,3,9,0,0.7 +253,318,100,2,2.5,3.5,8.54,1,0.71 +254,335,115,4,4.5,4.5,9.68,1,0.93 +255,321,114,4,4,5,9.12,0,0.85 +256,307,110,4,4,4.5,8.37,0,0.79 +257,309,99,3,4,4,8.56,0,0.76 +258,324,100,3,4,5,8.64,1,0.78 +259,326,102,4,5,5,8.76,1,0.77 +260,331,119,4,5,4.5,9.34,1,0.9 +261,327,108,5,5,3.5,9.13,1,0.87 +262,312,104,3,3.5,4,8.09,0,0.71 +263,308,103,2,2.5,4,8.36,1,0.7 +264,324,111,3,2.5,1.5,8.79,1,0.7 +265,325,110,2,3,2.5,8.76,1,0.75 +266,313,102,3,2.5,2.5,8.68,0,0.71 +267,312,105,2,2,2.5,8.45,0,0.72 +268,314,107,3,3,3.5,8.17,1,0.73 +269,327,113,4,4.5,5,9.14,0,0.83 +270,308,108,4,4.5,5,8.34,0,0.77 +271,306,105,2,2.5,3,8.22,1,0.72 +272,299,96,2,1.5,2,7.86,0,0.54 +273,294,95,1,1.5,1.5,7.64,0,0.49 +274,312,99,1,1,1.5,8.01,1,0.52 +275,315,100,1,2,2.5,7.95,0,0.58 +276,322,110,3,3.5,3,8.96,1,0.78 +277,329,113,5,5,4.5,9.45,1,0.89 +278,320,101,2,2.5,3,8.62,0,0.7 +279,308,103,2,3,3.5,8.49,0,0.66 +280,304,102,2,3,4,8.73,0,0.67 +281,311,102,3,4.5,4,8.64,1,0.68 +282,317,110,3,4,4.5,9.11,1,0.8 +283,312,106,3,4,3.5,8.79,1,0.81 +284,321,111,3,2.5,3,8.9,1,0.8 +285,340,112,4,5,4.5,9.66,1,0.94 +286,331,116,5,4,4,9.26,1,0.93 +287,336,118,5,4.5,4,9.19,1,0.92 +288,324,114,5,5,4.5,9.08,1,0.89 +289,314,104,4,5,5,9.02,0,0.82 +290,313,109,3,4,3.5,9,0,0.79 +291,307,105,2,2.5,3,7.65,0,0.58 +292,300,102,2,1.5,2,7.87,0,0.56 +293,302,99,2,1,2,7.97,0,0.56 +294,312,98,1,3.5,3,8.18,1,0.64 +295,316,101,2,2.5,2,8.32,1,0.61 +296,317,100,2,3,2.5,8.57,0,0.68 +297,310,107,3,3.5,3.5,8.67,0,0.76 +298,320,120,3,4,4.5,9.11,0,0.86 +299,330,114,3,4.5,4.5,9.24,1,0.9 +300,305,112,3,3,3.5,8.65,0,0.71 +301,309,106,2,2.5,2.5,8,0,0.62 +302,319,108,2,2.5,3,8.76,0,0.66 +303,322,105,2,3,3,8.45,1,0.65 +304,323,107,3,3.5,3.5,8.55,1,0.73 +305,313,106,2,2.5,2,8.43,0,0.62 +306,321,109,3,3.5,3.5,8.8,1,0.74 +307,323,110,3,4,3.5,9.1,1,0.79 +308,325,112,4,4,4,9,1,0.8 +309,312,108,3,3.5,3,8.53,0,0.69 +310,308,110,4,3.5,3,8.6,0,0.7 +311,320,104,3,3,3.5,8.74,1,0.76 +312,328,108,4,4.5,4,9.18,1,0.84 +313,311,107,4,4.5,4.5,9,1,0.78 +314,301,100,3,3.5,3,8.04,0,0.67 +315,305,105,2,3,4,8.13,0,0.66 +316,308,104,2,2.5,3,8.07,0,0.65 +317,298,101,2,1.5,2,7.86,0,0.54 +318,300,99,1,1,2.5,8.01,0,0.58 +319,324,111,3,2.5,2,8.8,1,0.79 +320,327,113,4,3.5,3,8.69,1,0.8 +321,317,106,3,4,3.5,8.5,1,0.75 +322,323,104,3,4,4,8.44,1,0.73 +323,314,107,2,2.5,4,8.27,0,0.72 +324,305,102,2,2,2.5,8.18,0,0.62 +325,315,104,3,3,2.5,8.33,0,0.67 +326,326,116,3,3.5,4,9.14,1,0.81 +327,299,100,3,2,2,8.02,0,0.63 +328,295,101,2,2.5,2,7.86,0,0.69 +329,324,112,4,4,3.5,8.77,1,0.8 +330,297,96,2,2.5,1.5,7.89,0,0.43 +331,327,113,3,3.5,3,8.66,1,0.8 +332,311,105,2,3,2,8.12,1,0.73 +333,308,106,3,3.5,2.5,8.21,1,0.75 +334,319,108,3,3,3.5,8.54,1,0.71 +335,312,107,4,4.5,4,8.65,1,0.73 +336,325,111,4,4,4.5,9.11,1,0.83 +337,319,110,3,3,2.5,8.79,0,0.72 +338,332,118,5,5,5,9.47,1,0.94 +339,323,108,5,4,4,8.74,1,0.81 +340,324,107,5,3.5,4,8.66,1,0.81 +341,312,107,3,3,3,8.46,1,0.75 +342,326,110,3,3.5,3.5,8.76,1,0.79 +343,308,106,3,3,3,8.24,0,0.58 +344,305,103,2,2.5,3.5,8.13,0,0.59 +345,295,96,2,1.5,2,7.34,0,0.47 +346,316,98,1,1.5,2,7.43,0,0.49 +347,304,97,2,1.5,2,7.64,0,0.47 +348,299,94,1,1,1,7.34,0,0.42 +349,302,99,1,2,2,7.25,0,0.57 +350,313,101,3,2.5,3,8.04,0,0.62 +351,318,107,3,3,3.5,8.27,1,0.74 +352,325,110,4,3.5,4,8.67,1,0.73 +353,303,100,2,3,3.5,8.06,1,0.64 +354,300,102,3,3.5,2.5,8.17,0,0.63 +355,297,98,2,2.5,3,7.67,0,0.59 +356,317,106,2,2,3.5,8.12,0,0.73 +357,327,109,3,3.5,4,8.77,1,0.79 +358,301,104,2,3.5,3.5,7.89,1,0.68 +359,314,105,2,2.5,2,7.64,0,0.7 +360,321,107,2,2,1.5,8.44,0,0.81 +361,322,110,3,4,5,8.64,1,0.85 +362,334,116,4,4,3.5,9.54,1,0.93 +363,338,115,5,4.5,5,9.23,1,0.91 +364,306,103,2,2.5,3,8.36,0,0.69 +365,313,102,3,3.5,4,8.9,1,0.77 +366,330,114,4,4.5,3,9.17,1,0.86 +367,320,104,3,3.5,4.5,8.34,1,0.74 +368,311,98,1,1,2.5,7.46,0,0.57 +369,298,92,1,2,2,7.88,0,0.51 +370,301,98,1,2,3,8.03,1,0.67 +371,310,103,2,2.5,2.5,8.24,0,0.72 +372,324,110,3,3.5,3,9.22,1,0.89 +373,336,119,4,4.5,4,9.62,1,0.95 +374,321,109,3,3,3,8.54,1,0.79 +375,315,105,2,2,2.5,7.65,0,0.39 +376,304,101,2,2,2.5,7.66,0,0.38 +377,297,96,2,2.5,2,7.43,0,0.34 +378,290,100,1,1.5,2,7.56,0,0.47 +379,303,98,1,2,2.5,7.65,0,0.56 +380,311,99,1,2.5,3,8.43,1,0.71 +381,322,104,3,3.5,4,8.84,1,0.78 +382,319,105,3,3,3.5,8.67,1,0.73 +383,324,110,4,4.5,4,9.15,1,0.82 +384,300,100,3,3,3.5,8.26,0,0.62 +385,340,113,4,5,5,9.74,1,0.96 +386,335,117,5,5,5,9.82,1,0.96 +387,302,101,2,2.5,3.5,7.96,0,0.46 +388,307,105,2,2,3.5,8.1,0,0.53 +389,296,97,2,1.5,2,7.8,0,0.49 +390,320,108,3,3.5,4,8.44,1,0.76 +391,314,102,2,2,2.5,8.24,0,0.64 +392,318,106,3,2,3,8.65,0,0.71 +393,326,112,4,4,3.5,9.12,1,0.84 +394,317,104,2,3,3,8.76,0,0.77 +395,329,111,4,4.5,4,9.23,1,0.89 +396,324,110,3,3.5,3.5,9.04,1,0.82 +397,325,107,3,3,3.5,9.11,1,0.84 +398,330,116,4,5,4.5,9.45,1,0.91 +399,312,103,3,3.5,4,8.78,0,0.67 +400,333,117,4,5,4,9.66,1,0.95 +401,304,100,2,3.5,3,8.22,0,0.63 +402,315,105,2,3,3,8.34,0,0.66 +403,324,109,3,3.5,3,8.94,1,0.78 +404,330,116,4,4,3.5,9.23,1,0.91 +405,311,101,3,2,2.5,7.64,1,0.62 +406,302,99,3,2.5,3,7.45,0,0.52 +407,322,103,4,3,2.5,8.02,1,0.61 +408,298,100,3,2.5,4,7.95,1,0.58 +409,297,101,3,2,4,7.67,1,0.57 +410,300,98,1,2,2.5,8.02,0,0.61 +411,301,96,1,3,4,7.56,0,0.54 +412,313,94,2,2.5,1.5,8.13,0,0.56 +413,314,102,4,2.5,2,7.88,1,0.59 +414,317,101,3,3,2,7.94,1,0.49 +415,321,110,4,3.5,4,8.35,1,0.72 +416,327,106,4,4,4.5,8.75,1,0.76 +417,315,104,3,4,2.5,8.1,0,0.65 +418,316,103,3,3.5,2,7.68,0,0.52 +419,309,111,2,2.5,4,8.03,0,0.6 +420,308,102,2,2,3.5,7.98,1,0.58 +421,299,100,3,2,3,7.42,0,0.42 +422,321,112,3,3,4.5,8.95,1,0.77 +423,322,112,4,3.5,2.5,9.02,1,0.73 +424,334,119,5,4.5,5,9.54,1,0.94 +425,325,114,5,4,5,9.46,1,0.91 +426,323,111,5,4,5,9.86,1,0.92 +427,312,106,3,3,5,8.57,0,0.71 +428,310,101,3,3.5,5,8.65,1,0.71 +429,316,103,2,2,4.5,8.74,0,0.69 +430,340,115,5,5,4.5,9.06,1,0.95 +431,311,104,3,4,3.5,8.13,1,0.74 +432,320,112,2,3.5,3.5,8.78,1,0.73 +433,324,112,4,4.5,4,9.22,1,0.86 +434,316,111,4,4,5,8.54,0,0.71 +435,306,103,3,3.5,3,8.21,0,0.64 +436,309,105,2,2.5,4,7.68,0,0.55 +437,310,110,1,1.5,4,7.23,1,0.58 +438,317,106,1,1.5,3.5,7.65,1,0.61 +439,318,110,1,2.5,3.5,8.54,1,0.67 +440,312,105,2,1.5,3,8.46,0,0.66 +441,305,104,2,2.5,1.5,7.79,0,0.53 +442,332,112,1,1.5,3,8.66,1,0.79 +443,331,116,4,4.5,4.5,9.44,1,0.92 +444,321,114,5,4.5,4.5,9.16,1,0.87 +445,324,113,5,4,5,9.25,1,0.92 +446,328,116,5,4.5,5,9.08,1,0.91 +447,327,118,4,5,5,9.67,1,0.93 +448,320,108,3,3.5,5,8.97,1,0.84 +449,312,109,2,2.5,4,9.02,0,0.8 +450,315,101,3,3.5,4.5,9.13,0,0.79 +451,320,112,4,3,4.5,8.86,1,0.82 +452,324,113,4,4.5,4.5,9.25,1,0.89 +453,328,116,4,5,3.5,9.6,1,0.93 +454,319,103,3,2.5,4,8.76,1,0.73 +455,310,105,2,3,3.5,8.01,0,0.71 +456,305,102,2,1.5,2.5,7.64,0,0.59 +457,299,100,2,2,2,7.88,0,0.51 +458,295,99,1,2,1.5,7.57,0,0.37 +459,312,100,1,3,3,8.53,1,0.69 +460,329,113,4,4,3.5,9.36,1,0.89 +461,319,105,4,4,4.5,8.66,1,0.77 +462,301,102,3,2.5,2,8.13,1,0.68 +463,307,105,4,3,3,7.94,0,0.62 +464,304,107,3,3.5,3,7.86,0,0.57 +465,298,97,2,2,3,7.21,0,0.45 +466,305,96,4,3,4.5,8.26,0,0.54 +467,314,99,4,3.5,4.5,8.73,1,0.71 +468,318,101,5,3.5,5,8.78,1,0.78 +469,323,110,4,4,5,8.88,1,0.81 +470,326,114,4,4,3.5,9.16,1,0.86 +471,320,110,5,4,4,9.27,1,0.87 +472,311,103,3,2,4,8.09,0,0.64 +473,327,116,4,4,4.5,9.48,1,0.9 +474,316,102,2,4,3.5,8.15,0,0.67 +475,308,105,4,3,2.5,7.95,1,0.67 +476,300,101,3,3.5,2.5,7.88,0,0.59 +477,304,104,3,2.5,2,8.12,0,0.62 +478,309,105,4,3.5,2,8.18,0,0.65 +479,318,103,3,4,4.5,8.49,1,0.71 +480,325,110,4,4.5,4,8.96,1,0.79 +481,321,102,3,3.5,4,9.01,1,0.8 +482,323,107,4,3,2.5,8.48,1,0.78 +483,328,113,4,4,2.5,8.77,1,0.83 +484,304,103,5,5,3,7.92,0,0.71 +485,317,106,3,3.5,3,7.89,1,0.73 +486,311,101,2,2.5,3.5,8.34,1,0.7 +487,319,102,3,2.5,2.5,8.37,0,0.68 +488,327,115,4,3.5,4,9.14,0,0.79 +489,322,112,3,3,4,8.62,1,0.76 +490,302,110,3,4,4.5,8.5,0,0.65 +491,307,105,2,2.5,4.5,8.12,1,0.67 +492,297,99,4,3,3.5,7.81,0,0.54 +493,298,101,4,2.5,4.5,7.69,1,0.53 +494,300,95,2,3,1.5,8.22,1,0.62 +495,301,99,3,2.5,2,8.45,1,0.68 +496,332,108,5,4.5,4,9.02,1,0.87 +497,337,117,5,5,5,9.87,1,0.96 +498,330,120,5,4.5,5,9.56,1,0.93 +499,312,103,4,4,5,8.43,0,0.73 +500,327,113,4,4.5,4.5,9.04,0,0.84 \ No newline at end of file diff --git a/Pandas/Fremont_weather.txt b/Pandas/Fremont_weather.txt new file mode 100644 index 00000000..e776cdc9 --- /dev/null +++ b/Pandas/Fremont_weather.txt @@ -0,0 +1,13 @@ +month,avg_high,avg_low,record_high,record_low,avg_precipitation +Jan,58,42,74,22,2.95 +Feb,61,45,78,26,3.02 +Mar,65,48,84,25,2.34 +Apr,67,50,92,28,1.02 +May,71,53,98,35,0.48 +Jun,75,56,107,41,0.11 +Jul,77,58,105,44,0.0 +Aug,77,59,102,43,0.03 +Sep,77,57,103,40,0.17 +Oct,73,54,96,34,0.81 +Nov,64,48,84,30,1.7 +Dec,58,42,73,21,2.56 \ No newline at end of file diff --git a/Pandas/Pandas - Change Column Names.ipynb b/Pandas/Pandas - Change Column Names.ipynb new file mode 100644 index 00000000..aa84e79c --- /dev/null +++ b/Pandas/Pandas - Change Column Names.ipynb @@ -0,0 +1,364 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Pandas - Change Column Names" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ABCDLabel
05.13.51.40.2Iris-setosa
14.93.01.40.2Iris-setosa
24.73.21.30.2Iris-setosa
34.63.11.50.2Iris-setosa
45.03.61.40.2Iris-setosa
..................
1456.73.05.22.3Iris-virginica
1466.32.55.01.9Iris-virginica
1476.53.05.22.0Iris-virginica
1486.23.45.42.3Iris-virginica
1495.93.05.11.8Iris-virginica
\n", + "

150 rows × 5 columns

\n", + "
" + ], + "text/plain": [ + " A B C D Label\n", + "0 5.1 3.5 1.4 0.2 Iris-setosa\n", + "1 4.9 3.0 1.4 0.2 Iris-setosa\n", + "2 4.7 3.2 1.3 0.2 Iris-setosa\n", + "3 4.6 3.1 1.5 0.2 Iris-setosa\n", + "4 5.0 3.6 1.4 0.2 Iris-setosa\n", + ".. ... ... ... ... ...\n", + "145 6.7 3.0 5.2 2.3 Iris-virginica\n", + "146 6.3 2.5 5.0 1.9 Iris-virginica\n", + "147 6.5 3.0 5.2 2.0 Iris-virginica\n", + "148 6.2 3.4 5.4 2.3 Iris-virginica\n", + "149 5.9 3.0 5.1 1.8 Iris-virginica\n", + "\n", + "[150 rows x 5 columns]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.read_csv('iris.data', names=['A','B','C','D','Label'])\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "axis=1 tells Pandas it's column names. \n", + "inplace=True tells Pandas to save the changes to our DataFrame." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
aabbCDLabel
05.13.51.40.2Iris-setosa
14.93.01.40.2Iris-setosa
24.73.21.30.2Iris-setosa
34.63.11.50.2Iris-setosa
45.03.61.40.2Iris-setosa
..................
1456.73.05.22.3Iris-virginica
1466.32.55.01.9Iris-virginica
1476.53.05.22.0Iris-virginica
1486.23.45.42.3Iris-virginica
1495.93.05.11.8Iris-virginica
\n", + "

150 rows × 5 columns

\n", + "
" + ], + "text/plain": [ + " aa bb C D Label\n", + "0 5.1 3.5 1.4 0.2 Iris-setosa\n", + "1 4.9 3.0 1.4 0.2 Iris-setosa\n", + "2 4.7 3.2 1.3 0.2 Iris-setosa\n", + "3 4.6 3.1 1.5 0.2 Iris-setosa\n", + "4 5.0 3.6 1.4 0.2 Iris-setosa\n", + ".. ... ... ... ... ...\n", + "145 6.7 3.0 5.2 2.3 Iris-virginica\n", + "146 6.3 2.5 5.0 1.9 Iris-virginica\n", + "147 6.5 3.0 5.2 2.0 Iris-virginica\n", + "148 6.2 3.4 5.4 2.3 Iris-virginica\n", + "149 5.9 3.0 5.1 1.8 Iris-virginica\n", + "\n", + "[150 rows x 5 columns]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.rename({'A':'aa', 'B':'bb'}, axis=1, inplace=True)\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Pandas/Pandas - Delete Columns from DataFrame.ipynb b/Pandas/Pandas - Delete Columns from DataFrame.ipynb new file mode 100644 index 00000000..28293203 --- /dev/null +++ b/Pandas/Pandas - Delete Columns from DataFrame.ipynb @@ -0,0 +1,757 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Pandas - Delete Columns from a DataFrame" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ABCDLabel
05.13.51.40.2Iris-setosa
14.93.01.40.2Iris-setosa
24.73.21.30.2Iris-setosa
34.63.11.50.2Iris-setosa
45.03.61.40.2Iris-setosa
..................
1456.73.05.22.3Iris-virginica
1466.32.55.01.9Iris-virginica
1476.53.05.22.0Iris-virginica
1486.23.45.42.3Iris-virginica
1495.93.05.11.8Iris-virginica
\n", + "

150 rows × 5 columns

\n", + "
" + ], + "text/plain": [ + " A B C D Label\n", + "0 5.1 3.5 1.4 0.2 Iris-setosa\n", + "1 4.9 3.0 1.4 0.2 Iris-setosa\n", + "2 4.7 3.2 1.3 0.2 Iris-setosa\n", + "3 4.6 3.1 1.5 0.2 Iris-setosa\n", + "4 5.0 3.6 1.4 0.2 Iris-setosa\n", + ".. ... ... ... ... ...\n", + "145 6.7 3.0 5.2 2.3 Iris-virginica\n", + "146 6.3 2.5 5.0 1.9 Iris-virginica\n", + "147 6.5 3.0 5.2 2.0 Iris-virginica\n", + "148 6.2 3.4 5.4 2.3 Iris-virginica\n", + "149 5.9 3.0 5.1 1.8 Iris-virginica\n", + "\n", + "[150 rows x 5 columns]" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.read_csv('iris.data', names=['A','B','C','D','Label'])\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1) to drop a single column\n, and saving it permanently ", + "df.drop('col_name', axis=1,inplace =True) \n", + "To save changes you must either set df = df.drop(), or add inplace=True." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ACDLabel
05.11.40.2Iris-setosa
14.91.40.2Iris-setosa
24.71.30.2Iris-setosa
34.61.50.2Iris-setosa
45.01.40.2Iris-setosa
...............
1456.75.22.3Iris-virginica
1466.35.01.9Iris-virginica
1476.55.22.0Iris-virginica
1486.25.42.3Iris-virginica
1495.95.11.8Iris-virginica
\n", + "

150 rows × 4 columns

\n", + "
" + ], + "text/plain": [ + " A C D Label\n", + "0 5.1 1.4 0.2 Iris-setosa\n", + "1 4.9 1.4 0.2 Iris-setosa\n", + "2 4.7 1.3 0.2 Iris-setosa\n", + "3 4.6 1.5 0.2 Iris-setosa\n", + "4 5.0 1.4 0.2 Iris-setosa\n", + ".. ... ... ... ...\n", + "145 6.7 5.2 2.3 Iris-virginica\n", + "146 6.3 5.0 1.9 Iris-virginica\n", + "147 6.5 5.2 2.0 Iris-virginica\n", + "148 6.2 5.4 2.3 Iris-virginica\n", + "149 5.9 5.1 1.8 Iris-virginica\n", + "\n", + "[150 rows x 4 columns]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.drop('B', axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ABCDLabel
05.13.51.40.2Iris-setosa
14.93.01.40.2Iris-setosa
24.73.21.30.2Iris-setosa
34.63.11.50.2Iris-setosa
45.03.61.40.2Iris-setosa
..................
1456.73.05.22.3Iris-virginica
1466.32.55.01.9Iris-virginica
1476.53.05.22.0Iris-virginica
1486.23.45.42.3Iris-virginica
1495.93.05.11.8Iris-virginica
\n", + "

150 rows × 5 columns

\n", + "
" + ], + "text/plain": [ + " A B C D Label\n", + "0 5.1 3.5 1.4 0.2 Iris-setosa\n", + "1 4.9 3.0 1.4 0.2 Iris-setosa\n", + "2 4.7 3.2 1.3 0.2 Iris-setosa\n", + "3 4.6 3.1 1.5 0.2 Iris-setosa\n", + "4 5.0 3.6 1.4 0.2 Iris-setosa\n", + ".. ... ... ... ... ...\n", + "145 6.7 3.0 5.2 2.3 Iris-virginica\n", + "146 6.3 2.5 5.0 1.9 Iris-virginica\n", + "147 6.5 3.0 5.2 2.0 Iris-virginica\n", + "148 6.2 3.4 5.4 2.3 Iris-virginica\n", + "149 5.9 3.0 5.1 1.8 Iris-virginica\n", + "\n", + "[150 rows x 5 columns]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2) to drop multiple axes by name\n", + "df.drop(['col_name1', 'col_name2'], axis=1, inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
BCD
03.51.40.2
13.01.40.2
23.21.30.2
33.11.50.2
43.61.40.2
............
1453.05.22.3
1462.55.01.9
1473.05.22.0
1483.45.42.3
1493.05.11.8
\n", + "

150 rows × 3 columns

\n", + "
" + ], + "text/plain": [ + " B C D\n", + "0 3.5 1.4 0.2\n", + "1 3.0 1.4 0.2\n", + "2 3.2 1.3 0.2\n", + "3 3.1 1.5 0.2\n", + "4 3.6 1.4 0.2\n", + ".. ... ... ...\n", + "145 3.0 5.2 2.3\n", + "146 2.5 5.0 1.9\n", + "147 3.0 5.2 2.0\n", + "148 3.4 5.4 2.3\n", + "149 3.0 5.1 1.8\n", + "\n", + "[150 rows x 3 columns]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.drop(['A','Label'], axis=1, inplace=True)\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3) to drop multiple axes by numerical column index\n", + "df.drop(df.columns[[idx1, idx2]], axis=1, inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
C
01.4
11.4
21.3
31.5
41.4
......
1455.2
1465.0
1475.2
1485.4
1495.1
\n", + "

150 rows × 1 columns

\n", + "
" + ], + "text/plain": [ + " C\n", + "0 1.4\n", + "1 1.4\n", + "2 1.3\n", + "3 1.5\n", + "4 1.4\n", + ".. ...\n", + "145 5.2\n", + "146 5.0\n", + "147 5.2\n", + "148 5.4\n", + "149 5.1\n", + "\n", + "[150 rows x 1 columns]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.drop(df.columns[[0, 2]], axis=1, inplace=True)\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Pandas/Pandas - Delete NaN Rows from DataFrame.ipynb b/Pandas/Pandas - Delete NaN Rows from DataFrame.ipynb new file mode 100644 index 00000000..79d4b0af --- /dev/null +++ b/Pandas/Pandas - Delete NaN Rows from DataFrame.ipynb @@ -0,0 +1,655 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Pandas - Delete NaN Rows from DataFrame" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[StackOverflow Thread](https://stackoverflow.com/questions/13413590/how-to-drop-rows-of-pandas-dataframe-whose-value-in-a-certain-column-is-nan)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
012
0-1.358720-0.4939670.258351
10.3383470.498426-0.050406
20.821865-0.376314-1.504425
3-0.5518760.6945950.540055
4-0.493108-0.5702550.160218
5-0.705264-1.9409840.321970
60.2571330.642613-0.416996
7-1.391762-1.689991-1.804575
81.459479-0.731590-0.061360
91.314401-1.666592-1.778455
10-0.353425-0.654705-0.155042
11-0.898696-0.7568020.539142
\n", + "
" + ], + "text/plain": [ + " 0 1 2\n", + "0 -1.358720 -0.493967 0.258351\n", + "1 0.338347 0.498426 -0.050406\n", + "2 0.821865 -0.376314 -1.504425\n", + "3 -0.551876 0.694595 0.540055\n", + "4 -0.493108 -0.570255 0.160218\n", + "5 -0.705264 -1.940984 0.321970\n", + "6 0.257133 0.642613 -0.416996\n", + "7 -1.391762 -1.689991 -1.804575\n", + "8 1.459479 -0.731590 -0.061360\n", + "9 1.314401 -1.666592 -1.778455\n", + "10 -0.353425 -0.654705 -0.155042\n", + "11 -0.898696 -0.756802 0.539142" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.DataFrame(np.random.randn(12,3))\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
012
0NaNNaNNaN
10.3383470.498426-0.050406
2NaN-0.376314-1.504425
3-0.551876NaN0.540055
4NaN-0.570255NaN
5-0.705264-1.9409840.321970
6NaNNaN-0.416996
7-1.391762-1.689991-1.804575
8NaN-0.731590NaN
91.314401NaN-1.778455
10NaN-0.654705-0.155042
11-0.898696-0.7568020.539142
\n", + "
" + ], + "text/plain": [ + " 0 1 2\n", + "0 NaN NaN NaN\n", + "1 0.338347 0.498426 -0.050406\n", + "2 NaN -0.376314 -1.504425\n", + "3 -0.551876 NaN 0.540055\n", + "4 NaN -0.570255 NaN\n", + "5 -0.705264 -1.940984 0.321970\n", + "6 NaN NaN -0.416996\n", + "7 -1.391762 -1.689991 -1.804575\n", + "8 NaN -0.731590 NaN\n", + "9 1.314401 NaN -1.778455\n", + "10 NaN -0.654705 -0.155042\n", + "11 -0.898696 -0.756802 0.539142" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.iloc[::2,0] = np.nan\n", + "df.iloc[::3,1] = np.nan\n", + "df.iloc[::4,2] = np.nan\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**- Drop all rows that have *any* NaN values**" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
012
10.3383470.498426-0.050406
5-0.705264-1.9409840.321970
7-1.391762-1.689991-1.804575
11-0.898696-0.7568020.539142
\n", + "
" + ], + "text/plain": [ + " 0 1 2\n", + "1 0.338347 0.498426 -0.050406\n", + "5 -0.705264 -1.940984 0.321970\n", + "7 -1.391762 -1.689991 -1.804575\n", + "11 -0.898696 -0.756802 0.539142" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.dropna()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**- drop only if *all* columns are NaN**" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
012
10.3383470.498426-0.050406
2NaN-0.376314-1.504425
3-0.551876NaN0.540055
4NaN-0.570255NaN
5-0.705264-1.9409840.321970
6NaNNaN-0.416996
7-1.391762-1.689991-1.804575
8NaN-0.731590NaN
91.314401NaN-1.778455
10NaN-0.654705-0.155042
11-0.898696-0.7568020.539142
\n", + "
" + ], + "text/plain": [ + " 0 1 2\n", + "1 0.338347 0.498426 -0.050406\n", + "2 NaN -0.376314 -1.504425\n", + "3 -0.551876 NaN 0.540055\n", + "4 NaN -0.570255 NaN\n", + "5 -0.705264 -1.940984 0.321970\n", + "6 NaN NaN -0.416996\n", + "7 -1.391762 -1.689991 -1.804575\n", + "8 NaN -0.731590 NaN\n", + "9 1.314401 NaN -1.778455\n", + "10 NaN -0.654705 -0.155042\n", + "11 -0.898696 -0.756802 0.539142" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.dropna(how='all')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**- Drop only if NaN in a specific column**" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
012
10.3383470.498426-0.050406
2NaN-0.376314-1.504425
3-0.551876NaN0.540055
5-0.705264-1.9409840.321970
6NaNNaN-0.416996
7-1.391762-1.689991-1.804575
91.314401NaN-1.778455
10NaN-0.654705-0.155042
11-0.898696-0.7568020.539142
\n", + "
" + ], + "text/plain": [ + " 0 1 2\n", + "1 0.338347 0.498426 -0.050406\n", + "2 NaN -0.376314 -1.504425\n", + "3 -0.551876 NaN 0.540055\n", + "5 -0.705264 -1.940984 0.321970\n", + "6 NaN NaN -0.416996\n", + "7 -1.391762 -1.689991 -1.804575\n", + "9 1.314401 NaN -1.778455\n", + "10 NaN -0.654705 -0.155042\n", + "11 -0.898696 -0.756802 0.539142" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.dropna(subset=[2])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Pandas/Pandas - Iterate Rows of a DataFrame.ipynb b/Pandas/Pandas - Iterate Rows of a DataFrame.ipynb new file mode 100644 index 00000000..e911a4be --- /dev/null +++ b/Pandas/Pandas - Iterate Rows of a DataFrame.ipynb @@ -0,0 +1,723 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Pandas - Iterate Rows of a DataFrame " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
01234
05.13.51.40.2Iris-setosa
14.93.01.40.2Iris-setosa
24.73.21.30.2Iris-setosa
34.63.11.50.2Iris-setosa
45.03.61.40.2Iris-setosa
..................
1456.73.05.22.3Iris-virginica
1466.32.55.01.9Iris-virginica
1476.53.05.22.0Iris-virginica
1486.23.45.42.3Iris-virginica
1495.93.05.11.8Iris-virginica
\n", + "

150 rows × 5 columns

\n", + "
" + ], + "text/plain": [ + " 0 1 2 3 4\n", + "0 5.1 3.5 1.4 0.2 Iris-setosa\n", + "1 4.9 3.0 1.4 0.2 Iris-setosa\n", + "2 4.7 3.2 1.3 0.2 Iris-setosa\n", + "3 4.6 3.1 1.5 0.2 Iris-setosa\n", + "4 5.0 3.6 1.4 0.2 Iris-setosa\n", + ".. ... ... ... ... ...\n", + "145 6.7 3.0 5.2 2.3 Iris-virginica\n", + "146 6.3 2.5 5.0 1.9 Iris-virginica\n", + "147 6.5 3.0 5.2 2.0 Iris-virginica\n", + "148 6.2 3.4 5.4 2.3 Iris-virginica\n", + "149 5.9 3.0 5.1 1.8 Iris-virginica\n", + "\n", + "[150 rows x 5 columns]" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.read_csv('iris.data', header=None)\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Get a List of one Column\n", + "Use a list comprehension." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1.4,\n", + " 1.4,\n", + " 1.3,\n", + " 1.5,\n", + " 1.4,\n", + " 1.7,\n", + " 1.4,\n", + " 1.5,\n", + " 1.4,\n", + " 1.5,\n", + " 1.5,\n", + " 1.6,\n", + " 1.4,\n", + " 1.1,\n", + " 1.2,\n", + " 1.5,\n", + " 1.3,\n", + " 1.4,\n", + " 1.7,\n", + " 1.5,\n", + " 1.7,\n", + " 1.5,\n", + " 1.0,\n", + " 1.7,\n", + " 1.9,\n", + " 1.6,\n", + " 1.6,\n", + " 1.5,\n", + " 1.4,\n", + " 1.6,\n", + " 1.6,\n", + " 1.5,\n", + " 1.5,\n", + " 1.4,\n", + " 1.5,\n", + " 1.2,\n", + " 1.3,\n", + " 1.5,\n", + " 1.3,\n", + " 1.5,\n", + " 1.3,\n", + " 1.3,\n", + " 1.3,\n", + " 1.6,\n", + " 1.9,\n", + " 1.4,\n", + " 1.6,\n", + " 1.4,\n", + " 1.5,\n", + " 1.4,\n", + " 4.7,\n", + " 4.5,\n", + " 4.9,\n", + " 4.0,\n", + " 4.6,\n", + " 4.5,\n", + " 4.7,\n", + " 3.3,\n", + " 4.6,\n", + " 3.9,\n", + " 3.5,\n", + " 4.2,\n", + " 4.0,\n", + " 4.7,\n", + " 3.6,\n", + " 4.4,\n", + " 4.5,\n", + " 4.1,\n", + " 4.5,\n", + " 3.9,\n", + " 4.8,\n", + " 4.0,\n", + " 4.9,\n", + " 4.7,\n", + " 4.3,\n", + " 4.4,\n", + " 4.8,\n", + " 5.0,\n", + " 4.5,\n", + " 3.5,\n", + " 3.8,\n", + " 3.7,\n", + " 3.9,\n", + " 5.1,\n", + " 4.5,\n", + " 4.5,\n", + " 4.7,\n", + " 4.4,\n", + " 4.1,\n", + " 4.0,\n", + " 4.4,\n", + " 4.6,\n", + " 4.0,\n", + " 3.3,\n", + " 4.2,\n", + " 4.2,\n", + " 4.2,\n", + " 4.3,\n", + " 3.0,\n", + " 4.1,\n", + " 6.0,\n", + " 5.1,\n", + " 5.9,\n", + " 5.6,\n", + " 5.8,\n", + " 6.6,\n", + " 4.5,\n", + " 6.3,\n", + " 5.8,\n", + " 6.1,\n", + " 5.1,\n", + " 5.3,\n", + " 5.5,\n", + " 5.0,\n", + " 5.1,\n", + " 5.3,\n", + " 5.5,\n", + " 6.7,\n", + " 6.9,\n", + " 5.0,\n", + " 5.7,\n", + " 4.9,\n", + " 6.7,\n", + " 4.9,\n", + " 5.7,\n", + " 6.0,\n", + " 4.8,\n", + " 4.9,\n", + " 5.6,\n", + " 5.8,\n", + " 6.1,\n", + " 6.4,\n", + " 5.6,\n", + " 5.1,\n", + " 5.6,\n", + " 6.1,\n", + " 5.6,\n", + " 5.5,\n", + " 4.8,\n", + " 5.4,\n", + " 5.6,\n", + " 5.1,\n", + " 5.1,\n", + " 5.9,\n", + " 5.7,\n", + " 5.2,\n", + " 5.0,\n", + " 5.2,\n", + " 5.4,\n", + " 5.1]" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "col2 = [x for x in df[2]]\n", + "col2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Iterate Rows with Index and each Row as a List\n", + "**DO NOT** try to change data in the df this way, but it is convenient for iterating. \n", + "Itertuples is supposed to be much faster than Iterrows for large datasets." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 5.1 3.5 1.4 0.2 Iris-setosa\n", + "1 4.9 3.0 1.4 0.2 Iris-setosa\n", + "2 4.7 3.2 1.3 0.2 Iris-setosa\n", + "3 4.6 3.1 1.5 0.2 Iris-setosa\n", + "4 5.0 3.6 1.4 0.2 Iris-setosa\n", + "5 5.4 3.9 1.7 0.4 Iris-setosa\n", + "6 4.6 3.4 1.4 0.3 Iris-setosa\n", + "7 5.0 3.4 1.5 0.2 Iris-setosa\n", + "8 4.4 2.9 1.4 0.2 Iris-setosa\n", + "9 4.9 3.1 1.5 0.1 Iris-setosa\n", + "10 5.4 3.7 1.5 0.2 Iris-setosa\n", + "11 4.8 3.4 1.6 0.2 Iris-setosa\n", + "12 4.8 3.0 1.4 0.1 Iris-setosa\n", + "13 4.3 3.0 1.1 0.1 Iris-setosa\n", + "14 5.8 4.0 1.2 0.2 Iris-setosa\n", + "15 5.7 4.4 1.5 0.4 Iris-setosa\n", + "16 5.4 3.9 1.3 0.4 Iris-setosa\n", + "17 5.1 3.5 1.4 0.3 Iris-setosa\n", + "18 5.7 3.8 1.7 0.3 Iris-setosa\n", + "19 5.1 3.8 1.5 0.3 Iris-setosa\n", + "20 5.4 3.4 1.7 0.2 Iris-setosa\n", + "21 5.1 3.7 1.5 0.4 Iris-setosa\n", + "22 4.6 3.6 1.0 0.2 Iris-setosa\n", + "23 5.1 3.3 1.7 0.5 Iris-setosa\n", + "24 4.8 3.4 1.9 0.2 Iris-setosa\n", + "25 5.0 3.0 1.6 0.2 Iris-setosa\n", + "26 5.0 3.4 1.6 0.4 Iris-setosa\n", + "27 5.2 3.5 1.5 0.2 Iris-setosa\n", + "28 5.2 3.4 1.4 0.2 Iris-setosa\n", + "29 4.7 3.2 1.6 0.2 Iris-setosa\n", + "30 4.8 3.1 1.6 0.2 Iris-setosa\n", + "31 5.4 3.4 1.5 0.4 Iris-setosa\n", + "32 5.2 4.1 1.5 0.1 Iris-setosa\n", + "33 5.5 4.2 1.4 0.2 Iris-setosa\n", + "34 4.9 3.1 1.5 0.1 Iris-setosa\n", + "35 5.0 3.2 1.2 0.2 Iris-setosa\n", + "36 5.5 3.5 1.3 0.2 Iris-setosa\n", + "37 4.9 3.1 1.5 0.1 Iris-setosa\n", + "38 4.4 3.0 1.3 0.2 Iris-setosa\n", + "39 5.1 3.4 1.5 0.2 Iris-setosa\n", + "40 5.0 3.5 1.3 0.3 Iris-setosa\n", + "41 4.5 2.3 1.3 0.3 Iris-setosa\n", + "42 4.4 3.2 1.3 0.2 Iris-setosa\n", + "43 5.0 3.5 1.6 0.6 Iris-setosa\n", + "44 5.1 3.8 1.9 0.4 Iris-setosa\n", + "45 4.8 3.0 1.4 0.3 Iris-setosa\n", + "46 5.1 3.8 1.6 0.2 Iris-setosa\n", + "47 4.6 3.2 1.4 0.2 Iris-setosa\n", + "48 5.3 3.7 1.5 0.2 Iris-setosa\n", + "49 5.0 3.3 1.4 0.2 Iris-setosa\n", + "50 7.0 3.2 4.7 1.4 Iris-versicolor\n", + "51 6.4 3.2 4.5 1.5 Iris-versicolor\n", + "52 6.9 3.1 4.9 1.5 Iris-versicolor\n", + "53 5.5 2.3 4.0 1.3 Iris-versicolor\n", + "54 6.5 2.8 4.6 1.5 Iris-versicolor\n", + "55 5.7 2.8 4.5 1.3 Iris-versicolor\n", + "56 6.3 3.3 4.7 1.6 Iris-versicolor\n", + "57 4.9 2.4 3.3 1.0 Iris-versicolor\n", + "58 6.6 2.9 4.6 1.3 Iris-versicolor\n", + "59 5.2 2.7 3.9 1.4 Iris-versicolor\n", + "60 5.0 2.0 3.5 1.0 Iris-versicolor\n", + "61 5.9 3.0 4.2 1.5 Iris-versicolor\n", + "62 6.0 2.2 4.0 1.0 Iris-versicolor\n", + "63 6.1 2.9 4.7 1.4 Iris-versicolor\n", + "64 5.6 2.9 3.6 1.3 Iris-versicolor\n", + "65 6.7 3.1 4.4 1.4 Iris-versicolor\n", + "66 5.6 3.0 4.5 1.5 Iris-versicolor\n", + "67 5.8 2.7 4.1 1.0 Iris-versicolor\n", + "68 6.2 2.2 4.5 1.5 Iris-versicolor\n", + "69 5.6 2.5 3.9 1.1 Iris-versicolor\n", + "70 5.9 3.2 4.8 1.8 Iris-versicolor\n", + "71 6.1 2.8 4.0 1.3 Iris-versicolor\n", + "72 6.3 2.5 4.9 1.5 Iris-versicolor\n", + "73 6.1 2.8 4.7 1.2 Iris-versicolor\n", + "74 6.4 2.9 4.3 1.3 Iris-versicolor\n", + "75 6.6 3.0 4.4 1.4 Iris-versicolor\n", + "76 6.8 2.8 4.8 1.4 Iris-versicolor\n", + "77 6.7 3.0 5.0 1.7 Iris-versicolor\n", + "78 6.0 2.9 4.5 1.5 Iris-versicolor\n", + "79 5.7 2.6 3.5 1.0 Iris-versicolor\n", + "80 5.5 2.4 3.8 1.1 Iris-versicolor\n", + "81 5.5 2.4 3.7 1.0 Iris-versicolor\n", + "82 5.8 2.7 3.9 1.2 Iris-versicolor\n", + "83 6.0 2.7 5.1 1.6 Iris-versicolor\n", + "84 5.4 3.0 4.5 1.5 Iris-versicolor\n", + "85 6.0 3.4 4.5 1.6 Iris-versicolor\n", + "86 6.7 3.1 4.7 1.5 Iris-versicolor\n", + "87 6.3 2.3 4.4 1.3 Iris-versicolor\n", + "88 5.6 3.0 4.1 1.3 Iris-versicolor\n", + "89 5.5 2.5 4.0 1.3 Iris-versicolor\n", + "90 5.5 2.6 4.4 1.2 Iris-versicolor\n", + "91 6.1 3.0 4.6 1.4 Iris-versicolor\n", + "92 5.8 2.6 4.0 1.2 Iris-versicolor\n", + "93 5.0 2.3 3.3 1.0 Iris-versicolor\n", + "94 5.6 2.7 4.2 1.3 Iris-versicolor\n", + "95 5.7 3.0 4.2 1.2 Iris-versicolor\n", + "96 5.7 2.9 4.2 1.3 Iris-versicolor\n", + "97 6.2 2.9 4.3 1.3 Iris-versicolor\n", + "98 5.1 2.5 3.0 1.1 Iris-versicolor\n", + "99 5.7 2.8 4.1 1.3 Iris-versicolor\n", + "100 6.3 3.3 6.0 2.5 Iris-virginica\n", + "101 5.8 2.7 5.1 1.9 Iris-virginica\n", + "102 7.1 3.0 5.9 2.1 Iris-virginica\n", + "103 6.3 2.9 5.6 1.8 Iris-virginica\n", + "104 6.5 3.0 5.8 2.2 Iris-virginica\n", + "105 7.6 3.0 6.6 2.1 Iris-virginica\n", + "106 4.9 2.5 4.5 1.7 Iris-virginica\n", + "107 7.3 2.9 6.3 1.8 Iris-virginica\n", + "108 6.7 2.5 5.8 1.8 Iris-virginica\n", + "109 7.2 3.6 6.1 2.5 Iris-virginica\n", + "110 6.5 3.2 5.1 2.0 Iris-virginica\n", + "111 6.4 2.7 5.3 1.9 Iris-virginica\n", + "112 6.8 3.0 5.5 2.1 Iris-virginica\n", + "113 5.7 2.5 5.0 2.0 Iris-virginica\n", + "114 5.8 2.8 5.1 2.4 Iris-virginica\n", + "115 6.4 3.2 5.3 2.3 Iris-virginica\n", + "116 6.5 3.0 5.5 1.8 Iris-virginica\n", + "117 7.7 3.8 6.7 2.2 Iris-virginica\n", + "118 7.7 2.6 6.9 2.3 Iris-virginica\n", + "119 6.0 2.2 5.0 1.5 Iris-virginica\n", + "120 6.9 3.2 5.7 2.3 Iris-virginica\n", + "121 5.6 2.8 4.9 2.0 Iris-virginica\n", + "122 7.7 2.8 6.7 2.0 Iris-virginica\n", + "123 6.3 2.7 4.9 1.8 Iris-virginica\n", + "124 6.7 3.3 5.7 2.1 Iris-virginica\n", + "125 7.2 3.2 6.0 1.8 Iris-virginica\n", + "126 6.2 2.8 4.8 1.8 Iris-virginica\n", + "127 6.1 3.0 4.9 1.8 Iris-virginica\n", + "128 6.4 2.8 5.6 2.1 Iris-virginica\n", + "129 7.2 3.0 5.8 1.6 Iris-virginica\n", + "130 7.4 2.8 6.1 1.9 Iris-virginica\n", + "131 7.9 3.8 6.4 2.0 Iris-virginica\n", + "132 6.4 2.8 5.6 2.2 Iris-virginica\n", + "133 6.3 2.8 5.1 1.5 Iris-virginica\n", + "134 6.1 2.6 5.6 1.4 Iris-virginica\n", + "135 7.7 3.0 6.1 2.3 Iris-virginica\n", + "136 6.3 3.4 5.6 2.4 Iris-virginica\n", + "137 6.4 3.1 5.5 1.8 Iris-virginica\n", + "138 6.0 3.0 4.8 1.8 Iris-virginica\n", + "139 6.9 3.1 5.4 2.1 Iris-virginica\n", + "140 6.7 3.1 5.6 2.4 Iris-virginica\n", + "141 6.9 3.1 5.1 2.3 Iris-virginica\n", + "142 5.8 2.7 5.1 1.9 Iris-virginica\n", + "143 6.8 3.2 5.9 2.3 Iris-virginica\n", + "144 6.7 3.3 5.7 2.5 Iris-virginica\n", + "145 6.7 3.0 5.2 2.3 Iris-virginica\n", + "146 6.3 2.5 5.0 1.9 Iris-virginica\n", + "147 6.5 3.0 5.2 2.0 Iris-virginica\n", + "148 6.2 3.4 5.4 2.3 Iris-virginica\n", + "149 5.9 3.0 5.1 1.8 Iris-virginica\n" + ] + } + ], + "source": [ + "for i, row in df.iterrows():\n", + " print(i, row[0], row[1], row[2], row[3], row[4])" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 5.1 3.5 1.4 0.2 Iris-setosa\n", + "1 4.9 3.0 1.4 0.2 Iris-setosa\n", + "2 4.7 3.2 1.3 0.2 Iris-setosa\n", + "3 4.6 3.1 1.5 0.2 Iris-setosa\n", + "4 5.0 3.6 1.4 0.2 Iris-setosa\n", + "5 5.4 3.9 1.7 0.4 Iris-setosa\n", + "6 4.6 3.4 1.4 0.3 Iris-setosa\n", + "7 5.0 3.4 1.5 0.2 Iris-setosa\n", + "8 4.4 2.9 1.4 0.2 Iris-setosa\n", + "9 4.9 3.1 1.5 0.1 Iris-setosa\n", + "10 5.4 3.7 1.5 0.2 Iris-setosa\n", + "11 4.8 3.4 1.6 0.2 Iris-setosa\n", + "12 4.8 3.0 1.4 0.1 Iris-setosa\n", + "13 4.3 3.0 1.1 0.1 Iris-setosa\n", + "14 5.8 4.0 1.2 0.2 Iris-setosa\n", + "15 5.7 4.4 1.5 0.4 Iris-setosa\n", + "16 5.4 3.9 1.3 0.4 Iris-setosa\n", + "17 5.1 3.5 1.4 0.3 Iris-setosa\n", + "18 5.7 3.8 1.7 0.3 Iris-setosa\n", + "19 5.1 3.8 1.5 0.3 Iris-setosa\n", + "20 5.4 3.4 1.7 0.2 Iris-setosa\n", + "21 5.1 3.7 1.5 0.4 Iris-setosa\n", + "22 4.6 3.6 1.0 0.2 Iris-setosa\n", + "23 5.1 3.3 1.7 0.5 Iris-setosa\n", + "24 4.8 3.4 1.9 0.2 Iris-setosa\n", + "25 5.0 3.0 1.6 0.2 Iris-setosa\n", + "26 5.0 3.4 1.6 0.4 Iris-setosa\n", + "27 5.2 3.5 1.5 0.2 Iris-setosa\n", + "28 5.2 3.4 1.4 0.2 Iris-setosa\n", + "29 4.7 3.2 1.6 0.2 Iris-setosa\n", + "30 4.8 3.1 1.6 0.2 Iris-setosa\n", + "31 5.4 3.4 1.5 0.4 Iris-setosa\n", + "32 5.2 4.1 1.5 0.1 Iris-setosa\n", + "33 5.5 4.2 1.4 0.2 Iris-setosa\n", + "34 4.9 3.1 1.5 0.1 Iris-setosa\n", + "35 5.0 3.2 1.2 0.2 Iris-setosa\n", + "36 5.5 3.5 1.3 0.2 Iris-setosa\n", + "37 4.9 3.1 1.5 0.1 Iris-setosa\n", + "38 4.4 3.0 1.3 0.2 Iris-setosa\n", + "39 5.1 3.4 1.5 0.2 Iris-setosa\n", + "40 5.0 3.5 1.3 0.3 Iris-setosa\n", + "41 4.5 2.3 1.3 0.3 Iris-setosa\n", + "42 4.4 3.2 1.3 0.2 Iris-setosa\n", + "43 5.0 3.5 1.6 0.6 Iris-setosa\n", + "44 5.1 3.8 1.9 0.4 Iris-setosa\n", + "45 4.8 3.0 1.4 0.3 Iris-setosa\n", + "46 5.1 3.8 1.6 0.2 Iris-setosa\n", + "47 4.6 3.2 1.4 0.2 Iris-setosa\n", + "48 5.3 3.7 1.5 0.2 Iris-setosa\n", + "49 5.0 3.3 1.4 0.2 Iris-setosa\n", + "50 7.0 3.2 4.7 1.4 Iris-versicolor\n", + "51 6.4 3.2 4.5 1.5 Iris-versicolor\n", + "52 6.9 3.1 4.9 1.5 Iris-versicolor\n", + "53 5.5 2.3 4.0 1.3 Iris-versicolor\n", + "54 6.5 2.8 4.6 1.5 Iris-versicolor\n", + "55 5.7 2.8 4.5 1.3 Iris-versicolor\n", + "56 6.3 3.3 4.7 1.6 Iris-versicolor\n", + "57 4.9 2.4 3.3 1.0 Iris-versicolor\n", + "58 6.6 2.9 4.6 1.3 Iris-versicolor\n", + "59 5.2 2.7 3.9 1.4 Iris-versicolor\n", + "60 5.0 2.0 3.5 1.0 Iris-versicolor\n", + "61 5.9 3.0 4.2 1.5 Iris-versicolor\n", + "62 6.0 2.2 4.0 1.0 Iris-versicolor\n", + "63 6.1 2.9 4.7 1.4 Iris-versicolor\n", + "64 5.6 2.9 3.6 1.3 Iris-versicolor\n", + "65 6.7 3.1 4.4 1.4 Iris-versicolor\n", + "66 5.6 3.0 4.5 1.5 Iris-versicolor\n", + "67 5.8 2.7 4.1 1.0 Iris-versicolor\n", + "68 6.2 2.2 4.5 1.5 Iris-versicolor\n", + "69 5.6 2.5 3.9 1.1 Iris-versicolor\n", + "70 5.9 3.2 4.8 1.8 Iris-versicolor\n", + "71 6.1 2.8 4.0 1.3 Iris-versicolor\n", + "72 6.3 2.5 4.9 1.5 Iris-versicolor\n", + "73 6.1 2.8 4.7 1.2 Iris-versicolor\n", + "74 6.4 2.9 4.3 1.3 Iris-versicolor\n", + "75 6.6 3.0 4.4 1.4 Iris-versicolor\n", + "76 6.8 2.8 4.8 1.4 Iris-versicolor\n", + "77 6.7 3.0 5.0 1.7 Iris-versicolor\n", + "78 6.0 2.9 4.5 1.5 Iris-versicolor\n", + "79 5.7 2.6 3.5 1.0 Iris-versicolor\n", + "80 5.5 2.4 3.8 1.1 Iris-versicolor\n", + "81 5.5 2.4 3.7 1.0 Iris-versicolor\n", + "82 5.8 2.7 3.9 1.2 Iris-versicolor\n", + "83 6.0 2.7 5.1 1.6 Iris-versicolor\n", + "84 5.4 3.0 4.5 1.5 Iris-versicolor\n", + "85 6.0 3.4 4.5 1.6 Iris-versicolor\n", + "86 6.7 3.1 4.7 1.5 Iris-versicolor\n", + "87 6.3 2.3 4.4 1.3 Iris-versicolor\n", + "88 5.6 3.0 4.1 1.3 Iris-versicolor\n", + "89 5.5 2.5 4.0 1.3 Iris-versicolor\n", + "90 5.5 2.6 4.4 1.2 Iris-versicolor\n", + "91 6.1 3.0 4.6 1.4 Iris-versicolor\n", + "92 5.8 2.6 4.0 1.2 Iris-versicolor\n", + "93 5.0 2.3 3.3 1.0 Iris-versicolor\n", + "94 5.6 2.7 4.2 1.3 Iris-versicolor\n", + "95 5.7 3.0 4.2 1.2 Iris-versicolor\n", + "96 5.7 2.9 4.2 1.3 Iris-versicolor\n", + "97 6.2 2.9 4.3 1.3 Iris-versicolor\n", + "98 5.1 2.5 3.0 1.1 Iris-versicolor\n", + "99 5.7 2.8 4.1 1.3 Iris-versicolor\n", + "100 6.3 3.3 6.0 2.5 Iris-virginica\n", + "101 5.8 2.7 5.1 1.9 Iris-virginica\n", + "102 7.1 3.0 5.9 2.1 Iris-virginica\n", + "103 6.3 2.9 5.6 1.8 Iris-virginica\n", + "104 6.5 3.0 5.8 2.2 Iris-virginica\n", + "105 7.6 3.0 6.6 2.1 Iris-virginica\n", + "106 4.9 2.5 4.5 1.7 Iris-virginica\n", + "107 7.3 2.9 6.3 1.8 Iris-virginica\n", + "108 6.7 2.5 5.8 1.8 Iris-virginica\n", + "109 7.2 3.6 6.1 2.5 Iris-virginica\n", + "110 6.5 3.2 5.1 2.0 Iris-virginica\n", + "111 6.4 2.7 5.3 1.9 Iris-virginica\n", + "112 6.8 3.0 5.5 2.1 Iris-virginica\n", + "113 5.7 2.5 5.0 2.0 Iris-virginica\n", + "114 5.8 2.8 5.1 2.4 Iris-virginica\n", + "115 6.4 3.2 5.3 2.3 Iris-virginica\n", + "116 6.5 3.0 5.5 1.8 Iris-virginica\n", + "117 7.7 3.8 6.7 2.2 Iris-virginica\n", + "118 7.7 2.6 6.9 2.3 Iris-virginica\n", + "119 6.0 2.2 5.0 1.5 Iris-virginica\n", + "120 6.9 3.2 5.7 2.3 Iris-virginica\n", + "121 5.6 2.8 4.9 2.0 Iris-virginica\n", + "122 7.7 2.8 6.7 2.0 Iris-virginica\n", + "123 6.3 2.7 4.9 1.8 Iris-virginica\n", + "124 6.7 3.3 5.7 2.1 Iris-virginica\n", + "125 7.2 3.2 6.0 1.8 Iris-virginica\n", + "126 6.2 2.8 4.8 1.8 Iris-virginica\n", + "127 6.1 3.0 4.9 1.8 Iris-virginica\n", + "128 6.4 2.8 5.6 2.1 Iris-virginica\n", + "129 7.2 3.0 5.8 1.6 Iris-virginica\n", + "130 7.4 2.8 6.1 1.9 Iris-virginica\n", + "131 7.9 3.8 6.4 2.0 Iris-virginica\n", + "132 6.4 2.8 5.6 2.2 Iris-virginica\n", + "133 6.3 2.8 5.1 1.5 Iris-virginica\n", + "134 6.1 2.6 5.6 1.4 Iris-virginica\n", + "135 7.7 3.0 6.1 2.3 Iris-virginica\n", + "136 6.3 3.4 5.6 2.4 Iris-virginica\n", + "137 6.4 3.1 5.5 1.8 Iris-virginica\n", + "138 6.0 3.0 4.8 1.8 Iris-virginica\n", + "139 6.9 3.1 5.4 2.1 Iris-virginica\n", + "140 6.7 3.1 5.6 2.4 Iris-virginica\n", + "141 6.9 3.1 5.1 2.3 Iris-virginica\n", + "142 5.8 2.7 5.1 1.9 Iris-virginica\n", + "143 6.8 3.2 5.9 2.3 Iris-virginica\n", + "144 6.7 3.3 5.7 2.5 Iris-virginica\n", + "145 6.7 3.0 5.2 2.3 Iris-virginica\n", + "146 6.3 2.5 5.0 1.9 Iris-virginica\n", + "147 6.5 3.0 5.2 2.0 Iris-virginica\n", + "148 6.2 3.4 5.4 2.3 Iris-virginica\n", + "149 5.9 3.0 5.1 1.8 Iris-virginica\n" + ] + } + ], + "source": [ + "for row in df.itertuples(name=None): \n", + " print(row[0], row[1], row[2], row[3], row[4], row[5])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Pandas/Pandas Reorder Columns in DataFrame.ipynb b/Pandas/Pandas Reorder Columns in DataFrame.ipynb new file mode 100644 index 00000000..0f030051 --- /dev/null +++ b/Pandas/Pandas Reorder Columns in DataFrame.ipynb @@ -0,0 +1,420 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Pandas - Reorder Columns\n", + "Swap two columns, or change the order of columns" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ABCDLabel
05.13.51.40.2Iris-setosa
14.93.01.40.2Iris-setosa
24.73.21.30.2Iris-setosa
34.63.11.50.2Iris-setosa
45.03.61.40.2Iris-setosa
..................
1456.73.05.22.3Iris-virginica
1466.32.55.01.9Iris-virginica
1476.53.05.22.0Iris-virginica
1486.23.45.42.3Iris-virginica
1495.93.05.11.8Iris-virginica
\n", + "

150 rows × 5 columns

\n", + "
" + ], + "text/plain": [ + " A B C D Label\n", + "0 5.1 3.5 1.4 0.2 Iris-setosa\n", + "1 4.9 3.0 1.4 0.2 Iris-setosa\n", + "2 4.7 3.2 1.3 0.2 Iris-setosa\n", + "3 4.6 3.1 1.5 0.2 Iris-setosa\n", + "4 5.0 3.6 1.4 0.2 Iris-setosa\n", + ".. ... ... ... ... ...\n", + "145 6.7 3.0 5.2 2.3 Iris-virginica\n", + "146 6.3 2.5 5.0 1.9 Iris-virginica\n", + "147 6.5 3.0 5.2 2.0 Iris-virginica\n", + "148 6.2 3.4 5.4 2.3 Iris-virginica\n", + "149 5.9 3.0 5.1 1.8 Iris-virginica\n", + "\n", + "[150 rows x 5 columns]" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.read_csv('iris.data', names=['A','B','C','D','Label'])\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1) get a list of the column names." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['A', 'B', 'C', 'D', 'Label']" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "titles = list(df.columns)\n", + "titles" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2) Swap or move whatever columns you want in the list." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['A', 'C', 'B', 'D', 'Label']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "titles[1], titles[2] = titles[2], titles[1]\n", + "titles" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3) Reassign the columns in the DataFrame." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ACBDLabel
05.11.43.50.2Iris-setosa
14.91.43.00.2Iris-setosa
24.71.33.20.2Iris-setosa
34.61.53.10.2Iris-setosa
45.01.43.60.2Iris-setosa
..................
1456.75.23.02.3Iris-virginica
1466.35.02.51.9Iris-virginica
1476.55.23.02.0Iris-virginica
1486.25.43.42.3Iris-virginica
1495.95.13.01.8Iris-virginica
\n", + "

150 rows × 5 columns

\n", + "
" + ], + "text/plain": [ + " A C B D Label\n", + "0 5.1 1.4 3.5 0.2 Iris-setosa\n", + "1 4.9 1.4 3.0 0.2 Iris-setosa\n", + "2 4.7 1.3 3.2 0.2 Iris-setosa\n", + "3 4.6 1.5 3.1 0.2 Iris-setosa\n", + "4 5.0 1.4 3.6 0.2 Iris-setosa\n", + ".. ... ... ... ... ...\n", + "145 6.7 5.2 3.0 2.3 Iris-virginica\n", + "146 6.3 5.0 2.5 1.9 Iris-virginica\n", + "147 6.5 5.2 3.0 2.0 Iris-virginica\n", + "148 6.2 5.4 3.4 2.3 Iris-virginica\n", + "149 5.9 5.1 3.0 1.8 Iris-virginica\n", + "\n", + "[150 rows x 5 columns]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = df[titles]\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Pandas/Pandas and Matplotlib Tackle Graduate Admissions Data.ipynb b/Pandas/Pandas and Matplotlib Tackle Graduate Admissions Data.ipynb new file mode 100644 index 00000000..414ccaf5 --- /dev/null +++ b/Pandas/Pandas and Matplotlib Tackle Graduate Admissions Data.ipynb @@ -0,0 +1,620 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Pandas and Matplotlib Tackle Graduate Admissions Data\n", + "Source: Kaggle, https://www.kaggle.com/mohansacharya/graduate-admissions/ \n", + " Mohan S Acharya, Asfia Armaan, Aneeta S Antony : A Comparison of Regression Models for Prediction of Graduate Admissions, IEEE International Conference on Computational Intelligence in Data Science 2019 \n", + " \n", + "### 1. Load in Data\n", + "Import numpy, pandas and matplotlib libraries, and load data into a Pandas dataframe. \n", + "Print data shape and summary info of data." + ] + }, + { + "cell_type": "code", + "execution_count": 98, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(500, 9)\n", + "\n", + "RangeIndex: 500 entries, 0 to 499\n", + "Data columns (total 9 columns):\n", + "Serial No. 500 non-null int64\n", + "GRE Score 500 non-null int64\n", + "TOEFL Score 500 non-null int64\n", + "University Rating 500 non-null int64\n", + "SOP 500 non-null float64\n", + "LOR 500 non-null float64\n", + "CGPA 500 non-null float64\n", + "Research 500 non-null int64\n", + "Chance of Admit 500 non-null float64\n", + "dtypes: float64(4), int64(5)\n", + "memory usage: 35.2 KB\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "\n", + "df = pd.read_csv('Admission_Predict_Ver1.1.csv')\n", + "print(df.shape)\n", + "df.info()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Clean up Columns\n", + "Delete the first column (serial num) since Pandas already assigns an id to each row. \n", + "Rename the columns to simpler names. Print first 5 rows." + ] + }, + { + "cell_type": "code", + "execution_count": 99, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
gretoeflratingsoplorgparesearchchance
033711844.54.59.6510.92
132410744.04.58.8710.76
231610433.03.58.0010.72
332211033.52.58.6710.80
431410322.03.08.2100.65
\n", + "
" + ], + "text/plain": [ + " gre toefl rating sop lor gpa research chance\n", + "0 337 118 4 4.5 4.5 9.65 1 0.92\n", + "1 324 107 4 4.0 4.5 8.87 1 0.76\n", + "2 316 104 3 3.0 3.5 8.00 1 0.72\n", + "3 322 110 3 3.5 2.5 8.67 1 0.80\n", + "4 314 103 2 2.0 3.0 8.21 0 0.65" + ] + }, + "execution_count": 99, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = df.drop(['Serial No.'], axis=1)\n", + "new_names = {'GRE Score':'gre', 'TOEFL Score':'toefl', 'University Rating':'rating', 'SOP':'sop', 'LOR':'lor', 'CGPA':'gpa', 'Research':'research', 'Chance of Admit ':'chance'}\n", + "df.rename(columns=new_names, inplace=True)\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Scope out Data\n", + "Show boxplots to see high-level distribution of main columns. \n", + "Use pandas.describe() to see high-level distribution of data." + ] + }, + { + "cell_type": "code", + "execution_count": 100, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
gretoeflratingsoplorgparesearchchance
count500.000000500.000000500.000000500.000000500.00000500.000000500.000000500.00000
mean316.472000107.1920003.1140003.3740003.484008.5764400.5600000.72174
std11.2951486.0818681.1435120.9910040.925450.6048130.4968840.14114
min290.00000092.0000001.0000001.0000001.000006.8000000.0000000.34000
25%308.000000103.0000002.0000002.5000003.000008.1275000.0000000.63000
50%317.000000107.0000003.0000003.5000003.500008.5600001.0000000.72000
75%325.000000112.0000004.0000004.0000004.000009.0400001.0000000.82000
max340.000000120.0000005.0000005.0000005.000009.9200001.0000000.97000
\n", + "
" + ], + "text/plain": [ + " gre toefl rating sop lor gpa \\\n", + "count 500.000000 500.000000 500.000000 500.000000 500.00000 500.000000 \n", + "mean 316.472000 107.192000 3.114000 3.374000 3.48400 8.576440 \n", + "std 11.295148 6.081868 1.143512 0.991004 0.92545 0.604813 \n", + "min 290.000000 92.000000 1.000000 1.000000 1.00000 6.800000 \n", + "25% 308.000000 103.000000 2.000000 2.500000 3.00000 8.127500 \n", + "50% 317.000000 107.000000 3.000000 3.500000 3.50000 8.560000 \n", + "75% 325.000000 112.000000 4.000000 4.000000 4.00000 9.040000 \n", + "max 340.000000 120.000000 5.000000 5.000000 5.00000 9.920000 \n", + "\n", + " research chance \n", + "count 500.000000 500.00000 \n", + "mean 0.560000 0.72174 \n", + "std 0.496884 0.14114 \n", + "min 0.000000 0.34000 \n", + "25% 0.000000 0.63000 \n", + "50% 1.000000 0.72000 \n", + "75% 1.000000 0.82000 \n", + "max 1.000000 0.97000 " + ] + }, + "execution_count": 100, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "plt.figure(1, figsize=(14,4))\n", + "for i in range(1,6):\n", + " plt.subplot(1,5,i)\n", + " plt.boxplot(df[df.columns[i]])\n", + " plt.title(df.columns[i])\n", + "plt.show()\n", + "df.describe()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4. Detailed Data Distribution\n", + "Plot histograms for main columns to show detailed distribution of data" + ] + }, + { + "cell_type": "code", + "execution_count": 101, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "df[['gre','toefl','rating','gpa','research','chance']].hist(figsize=(14, 9),bins=16,linewidth='1',edgecolor='k',grid=False)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5. Show Correlation with Chance of Acceptance\n", + "Calculate correlation between each data column and Chance of Acceptance. \n", + "Here we can see GPA, GRE score and TOEFL score are the most important features because they have the best correlation with acceptance. \n", + "Research appears to be the least important feature." + ] + }, + { + "cell_type": "code", + "execution_count": 107, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "gre 0.810351\n", + "toefl 0.792228\n", + "rating 0.690132\n", + "sop 0.684137\n", + "lor 0.645365\n", + "gpa 0.882413\n", + "research 0.545871\n", + "chance 1.000000\n", + "Name: chance, dtype: float64\n" + ] + } + ], + "source": [ + "correlation = df.corr()['chance']\n", + "plt.bar(df.columns, correlation, color='gray')\n", + "plt.show()\n", + "print(correlation)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 6. Plot Relations between GRE & TOEFL, and GPA & GRE\n", + "We can see a strong correlation between TOEFL and GRE scores -- people scoring high on one probably scored high on the other. \n", + "And we see a strong correlation between GPA and GRE -- people with a high GPA probably scored high on the GRE." + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "df.plot(kind='scatter', x='gre', y='toefl', color='green')\n", + "plt.xlabel(\"GRE\")\n", + "plt.ylabel(\"TOEFL\")\n", + "plt.show()\n", + "\n", + "df.plot(kind='scatter', x='gpa', y='gre', color='red')\n", + "plt.xlabel(\"GPA\")\n", + "plt.ylabel(\"GRE\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7. Plot relations between Chance and other Features" + ] + }, + { + "cell_type": "code", + "execution_count": 104, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYkAAAEKCAYAAADn+anLAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4xLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvDW2N/gAAIABJREFUeJztnX+cXGV97z/f3WQD2QST7G4Xan7aDXmZQhLJSom6KValXi8vUEly9dZGW5XW1tra2qJtX8KL+8NqorbIbStarkUrNsUWKRcLAqVga1o2NASIBVYCJAU2yybRJGBCdr/3j5ldZp55zpzvnHnOmXNmP+/Xixe7Z57zzPd5ZnaenHPe5zOiqiCEEEJ8dLS6AEIIIfmFiwQhhJBIuEgQQgiJhIsEIYSQSLhIEEIIiYSLBCGEkEi4SBBCCImEiwQhhJBIuEgQQgiJZFarC2iG3t5eXb58eavLIISQQrFr167nVbXP0rbQi8Ty5csxPDzc6jIIIaRQiMhT1rY83UQIISQSLhKEEEIi4SJBCCEkEi4ShBBCIuEiQQghJJLUFgkRuV5EDorIwxXbtonIf4jIHhH5OxFZUPHYJ0RkREQeFZGfT6suQsjMYGT0KG4a3o+R0aMtq2H82Ak8uP8Ixo+diNxmaQMAw/vG8bk7HsXwvvHsBgBA0vpmOhHZCOAYgBtU9ZzytosA3K2qp0Tk0wCgqleIyGoANwI4H8BPArgTwNmqOlHvOQYHB5UKLCHE5ZM3P4Qbdj49/fvWDUtx9aXnZlrDt3b/J6745h7M7ujAS5OT+Mxla6BA1bYt6xdjx64Dddt85rI12DG8H98deXlxGBrowVc/cEHi2kRkl6oOmtqm+fWlIrIcwK1Ti4Tz2DsAbFLVXxCRTwCAqn6q/NjtAK5S1e/V65+LBCHEZWT0KN78+Xtrtt/50Y0Y6J+fSQ3jx07g9Z++Gz9+aXJ625xZHQAUJ05Ff+b62szuACq6meamX7kAgyt6EtXXyCLRymsSvwzg2+WfXwlgf8VjB8rbahCRy0VkWESGx8bGUi6REFI0du8/0tD2NDhw+EXM7qj+eO3sEHRK/Y9cfxvxtr338eebKdFMSxYJEfkDAKcA/NXUJk8z73Krqtep6qCqDvb1me4qJ4TMINYtWdDQ9jRYvPB0vDRZ/c//iUnFhHoOCWLb+I88Nq7sbaZEM5kvEiLyXgAXA/gFfflc1wEASyqaLQbwTNa1EUKKz0D/fGzdsLRq29YNSzM71QQAPfPm4DOXrcFpszswf84snDa7A9s2rcG2TWurtm3dsDS2zWe3rMPQQPVppaGBnsSnmhol02sSIvJWAJ8D8LOqOlbR7qcBfB0vX7i+C8BKXrgmhCRlZPQodu8/gnVLFmS6QFQyfuwEDhx+EYsXno6eeXO82yxtgJLddO/jz2Pjyt6mF4hGrkmkFvAnIjcCuBBAr4gcAHAlgE8AmAPgOyICADtV9VdV9RER2QFgL0qnoX49boEghJB6DPTPT7Q4hPyA7pk3Z7qPKQ4fP4nHR4+iu6sTPfPm1PwexYq+eZg9qxOLF57e8JiaIdUjibThkQQhJCQ+bTWkfuqquWf3d+Ox0ePTv2/dsBTrly2KVWc/c9kaXLLO6/aYyI0CmzZcJAghofBpqyH10yg116WrU3By4uXPZZ8We9rsDvzzFT9X98ijHkVRYAkhJDf4tNWQ+qlVwS2fip/Gp8XO7ujAgcMvNlxDEgr9pUOEEBIKn7YaUj+1Krju2Z2JSa2p46XJycyuTfBIghBC4NdWQ+qnPjV3VX931e9bNyzF9s1rY7XYz1y2JvGppkbhNQlCCKkgbf3UVXN9qq5Vi01KLhRYQggpIj5t1dVPrQuJbwE48sJJPH3oBSzvmQvAr+r6avBtywIuEoQQUgdXi90yuBg7hg9EarLX3D2CoYEerOjtrkmifWLseE27ZtJcs4CnmwghJAKfFusSpclaaSbNNSlUYAkhJAB+LdZB/JqslazSXJPCRYIQQiLwa7EOTZ6NySrNNSlcJAghJAKfFusmt0Zpsr4k2lamuSaF1yQIISQGS3Kr1W4KqdMmhQosIYQ4WO8z8LWz6KeDK2qPCnx664K5XVi6aC4WzO2KfL48xJxPwUWCENL2+NJdfSmqlnbWvny4KbBvGOjB8FOHq/oafvJQjTp79aXnJhx58/B0EyGkrfFprL4UVUs7a18+LCmwbgLsFHd+dGPQIwoqsIQQUsansfpSVC3trH35sKTAugmwjeybFlwkCCFtjU9j9aWoWtpZ+/JhSYGNOrNjTZBNAy4ShJC2xqex+lJULe2sffnwpcAODfRU9bV981qvOtvKi9e8JkEImRE0Yzcl7cuHay61wm7i15cSQgiJhBeuCSGZMX7sBB7cfwTjx0401MayX15wax3eN47P3fEohveNR7YBgJsf2I8P/OX9uPmB/dPbRkaP4qbh/RgZPWp+vlbCIwlCSGKS3legQOJ7DbLGrX/potPx2Ojx6ceHBnqwaXBJzXj+92178dyPTk63O+uMLrxl9Zmx90A0cx+GFZ5uIoSkTtL7CubMEgCCE6cav9cgayxR4UDt/Q2NxIdX3gPRzH0YjcDTTYSQ1El6X0GndKCzQ+rulxdMUeEeJhv4t3flPRDN3IeRFlwkCCGJSHpfwYROYsL5FLXea5A1pqhwDx0NfMVE5T0QzdyHkRZcJAghiUh6X8G2TWuxbVOyew2yxlf/qv7uqjZDAz3YvnltTXz4WWd0VbU764yu2HsgmrkPIy1SuyYhItcDuBjAQVU9p7xtM4CrALwawPmqOlzevhzA9wE8Wt59p6r+atxz8JoEIa0n6X0FzdxrkDVurb64b994bn5gP2596DlcfO6ZePt5SwDY7oFIe27yEhX+FQDXArihYtvDAN4J4Iue9j9Q1XUp1kNIoSnyh6ovatsSv51XVvTNw+xZnVWngQ4fP4nHR4+iu6tzelznvHIBTk2W/j/Fwu4urOyfj4Xd0VHheZqb1BYJVb23fIRQue37QHSIFSHETxZaZKi6iqS3WnDHuGX9YuzYdSA23huKmm3rly2K7Stvc5WqAlteJG6dOt1Usf0eAB9zTjc9AuAxAD8C8Ieqel9c/zzdRGYCWWmRIeoqkt5qwaLAzpnVUTXeenR1Aicnoh/Paq6KqMA+C2Cpqr4GwG8D+LqInOFrKCKXi8iwiAyPjY1lWiQhrSCPWiRQfL3VQlIFNgqJ+cjN41zlYpFQ1ROqOl7+eReAHwA4O6Ltdao6qKqDfX19WZZJSEvIoxYJFF9vtZBUgY1CUb+vPM5VLhYJEekTkc7yz68CsBLAE62tipB8kEctMqquIumtFnxj3LphqTPmNV611bdt++Z1dfvK41ylqcDeCOBCAL0ARgFcCeAQgC8A6ANwBMBuVf15EbkMwNUATgGYAHClqv593HPwmgSZSeTVbiq63mrBHY813tu3zdJX2uRCgVXVd0c89Heett8E8M20aiEkinb/MMuir7T11qT3Ybj3KDTzfRI+vdVloH9+zX0Pru4K1M6Nb67y9L5M8z4JQnJNXrVSH0nTVpOOJy9zk3TclQmsd37/IK685RGcmNDY8fj6cvXWNwz0YPipw4n6ssxhXuZ+CqbAkhlJXrVSH0nTVpOOJy9zk3TcswQ4FfOx5huPry833bWZvixzyBRYQnJCXrVSH0nTVpOOJy9zk3Tcln/2+sbj68ty46+1L8sc5mXuK+EiQWYkedVKfSRNW006nrzMTdJxW/IcfOPx9WU502LtyzKHeZn7SrhIkBlJXrVSH0nTVpOOJy9zk3Tcn/tvtQmsrzitM3Y8vr62b15bo7IODfQk6ssyh3mZ+0p4TYLMaPJkkcSR1PJJ8/myIA92k6uyNtNXqDE3Qy4UWEKKQJ7SNuOw1JqX8bgfcpb7BaJw9VPrfm8/b8l0PDdgn5tv73kG39rzLC5dcxbe87oVAGr1Vp8Sm/c016RwkSCE1NCMhunuO7hsIb47Mj79uC8NNar/T978UKx+GjJ1du1V/4Af/riUwHf/k4ex7Y5H8eBVb61bUyPjsUAFNiA83URIeJrRMC2pqUBtGqqv/5HRo3jz5++t28+cWR0AFCcqnNekyujX/mUf/vCWvTXb/+clq6ePKKJqcpNg864fU4ElhCSmGQ3TmprqpqH6+t+9/0hsP50dgk4Jo4x+a8+zsdujanKNqqLrx5VwkSCEVNGMhmlNTXXTUH39r1uyAHFMTComNIwyeumas2K3R9Xkno8pun5cCRcJQkgVzWiYvn2HBnqq2vjSUH39D/TPj9VPt21ag22b1gZRRt/zuhV4xWmdVdtecVrn9KmmqJq2blgaLPmWCmxgeE2CkPRoRsMMaTdZ9NOQyujX/mVfjd0UV1PoGqjAEhJBXtz8omD5ALVGWFuw9u8qokdeOImnD72A5T1zp/uypp9a9FPL3FjH857XrYhcHKawpLs2U1ee4CJBckPe1L+846qYQwM9uN/RQ90E060blgKKmm1XX3puVd++18Knmlr6P/OMrulE1mvuHsHQQA+++oELasZjef2t+qmvLssY005p9dUfqq604OkmkgvykjxaFCx6qKuZ1uPOj26sOm3ivhY+1dTVPhvhpl+5AIMrXr5WYXn9o8bsJrVGJbfGjTHtlNao+kPU1ShUYEnhyKP6l2cseqirmVr7870WPtW0Ge59/Pmq3y2vf6R+6iS1RiW3xo0x7ZTWqPpD1JUmPN1EckEe1b88Y9FDXc3U2p/vtZiYVNhCuG1sXNlb9bvl9Y/UT52zIVFnR+LGmHZKa1T9IepKEx5JkFyQR/Uvz1j00O2b13l1Td+2yguovtfCp5pu27TG1L+byDo00FN1qinqOd3XP0o/3b55rTPu2uRWyxjTTmmNqj9EXWnCaxIkV9Buaow07Saramrpf3jfOO59/HlsXNlbs0DEPWfcmBupK8nzhdwv7bqsUIElLSfpmzzt1MwiL0K+2l0V0zd/rkIatc3F+lr4dFB324q+eZg9q7PqtEnSuG3f8/lwx2hVTy2Lo1XftSi9PvKUHstFggQnbwpf3uuyYFVS0xyPtQZ325bBxdgxfKDh/ZrpK6k6a63L7T8Pr09a8HQTCUpeVda81mXBr6QKAAmSPJq8Bp8WW1uXi3U/W1/x82BNbvXXEJ8ya52bPL3fqMCSlpFHhQ/Ib10WvEqqdKCzo1r1THM8Vi3WV5eLdT9TX4Z5sCa3emswpMxa56Yo7zcXnm4iQcmjwgfkty4LXiVVJwGt/kBLczxWLdZXl4t1P1NfhnmwJrd6a/DU6vZvnZuivN9ceCRBgpJHhS/PdVnwK6lrgyWPJq/Bp8XW1rV1w9JE+9n6ip8Ha3Krv4b4lFnr3BTl/eaS2jUJEbkewMUADqrqOeVtmwFcBeDVAM5X1eGK9p8A8H4AEwA+oqq3xz0Hr0nkl7xaRHmty0La6acha3C3Jd2vmb5crOps0v7z8PpYycs1ia8AeKuz7WEA7wRQdRVJRFYDeBeAny7v86ci0gkShPFjJ/Dg/iMYP3Yis+fsmTcHa5csyOwPwzrGpHWNjB7FTcP7MTJ6NPI5rTVY2vnaTKWfHj5+MnI8d+19Dlfc9CDu2vtcQ88HAMP7xvG5Ox7F8L7xyDa++fPVtfvpw/j6vz6F3U8fBgDsGzuGu74/in1jx+rud99jB/GFux/HfY8djHxO334+LOO29pX0fZP130EapGo3ichyALdOHUlUbL8HwMemjiTKRxFQ1U+Vf78dwFWq+r16/fNIIp4ia59W0h6jRZ/csn4xduw6EFuDpVZfG0uq6UWfvwePjR6f/n1Vfzd+7Y0rTXPzni/vxHdHXl4copJaLXOz84nxqjpOnyV4scLyGRrowYre7pr97njkuem0WKB0p/b3fv8tsc9nUVkHly2sGl9UGq6vr7STYVtBI0cSeVkkrgWwU1W/Vv79LwB8W1Vvqtc/F4n6FFn7tJL2GK36pIuvBkutvjaWVNO79j6H99+wq6bN7A7BS5P1NczhfePY9MWdNfu6Sa0uliTaZvnjLWvw9vOW1H2+WpW1Vj+14vaVdjJsq8jL6aZG8CkM3ldYRC4XkWERGR4bG0u5rGJTZO3TStpjtOqTLr4aLLX62lhSTe/YO+pto86fka8uN5E1brvv+dPi1odePm1mVlmbSKx1+0o7GbYI5GWROABgScXviwE842uoqtep6qCqDvb19WVSXFEpsvZpJe0xWvVJF18Nllp9bSypphet7ve2EcRrsm4ia9x23/OnxcXnnhn7fDUq66SWdNYEuH2lnQxbBPKySNwC4F0iMkdEVgBYCeDfWlxT4Smy9mkl7TFa9UlXzfTVYKnV18aSavqm1WdiVX93VZtV/d347JZ4DXNwRQ+GBqpPK/mSWq1z49Zx+qzqhWpooMe7n5sWe9YZXdOnmuo9n0VbdccXlYabRCtu97+zNBXYGwFcCKAXwCiAKwEcAvAFAH0AjgDYrao/X27/BwB+GcApAL+lqt+Oew5ek7CRVw0vJGmP0aJPJg2ss7axBNTdtfc53LF3FBet7sebVp9pfj4A5qRWF19dbh2+vn373fzAftz60HO4+NwzqxaIuOez6KfWNNxWJMNmTW4uXKcNFwmSBmn/sSe9FyBkrUkXPesHrbsopD2eIn1A5wFGhROSkLRVRktaaEid1kdSpden4fo00ifGjk/rptfcPYJV/d146tCLqY2naPpp0eCRBCFl0lYZrWmhLkl1Wh9RGmlXJ3ByIrr2uMcbIeR4iqif5oEiKrCEtJy0VUZrWqhLUp3WR7RGWr+GuMcbIeR42l0/zQM83URImbRVRmtaqEtSndZHtEZaXxmNe7wRQo6n3fXTPMAjCULKpK0yWtNCQ+m0PqI00u2b19WtYfvmdd79fNtc3XRVf3dq42l3/TQP8JoEIQ60m2g3tTu0m2Y4/EOz4/uAs34JfdL7HXz9h/rie+trONA/v+ZeC0sNC7u7sLJ/PhZ2v3zjm6+vFX3zMHtWZ93TPta5cfHdc2HZz3KfCamFi0SbQY3Qjk8FdZNVo0ia5hrytXDbbRlcjB3D8eps0vG5qm4zdVn7cqlMq73m7pGm0mqtr/VMh6eb2ghqhHaiVNDKZNUokqa5hnwtfO1ckr6GVlU3aV1zZgkAaThtNXRareW1bleowM5QqBHaiVJBLcmmSdNcQ74WvnYuSV9Dq6qbtK5O6UBnR3Wek6XW0Gm1WaTYtgNcJNoIaoR2olRQS7Jp0jTXkK+Fr51L0tcwStV1k1WT1jWhk2X1t7FaQ6fVZpFi2w5wkWgjqBHaiVJBLacfkqa5hnwtfO0s6qwFq6qbtK5tm9YmSlsNnVY7U081NQqvSbQhtJvsNGO8JLWbQvXtaxfyNbSous3UlbTWkGm1MxUqsDOcpDplKA0zipAfmKH+4H36ZsgPtMPHT+Lx0aPo7upMZW7d/n3P5/tQtYzR15fvPWJRUn37JZ2bBXO7sHTRXCyY2xXfuALfa03i4SJBMiGkDupLIw2lM1rVT4vCmVS7tM6V2//Z/d14bPR41fO5iaxDAz3YNLgkdjyvXbYQ95X3q1d71koqVdbsiTzdJCJfQJ1QGVX9SFpFWeHppmIQUgeNSiMNoTP61c9aXdOigybVLq1zFdW/ha7ODpycaCyJ1ld71koqVdZwhFJghwHsqvMfISZC6qBRaaQhdEav+unRNS06aFLt0jpXzY23ejGwJNH6njNrJZUqa2uod7rpzar6iyLym6r6J5lVRNqOkDpoVBppCJ3Rq37qJKDVi4QvudUdT1Lt0jpXzY1XUFm/JYnW95wbV/bimrtHatqlpaRSZW0N9f75sF5ElgH4ZRFZKCKLKv/LqkBSfELqoFFppCFON/jVz1pd06KDJtUurXPl639Vf3fN8/mU0e2b48fj7uerPWsllSpra6h3TeIjAD4E4FUA/hOlf35Moar6qvTLqw+vSRSLPNpN1udLajwlrdM6V27/lkRW63istWetpFJlbZ4gCqyqXgPgGhH5M1X9ULDqyIwgacKnD8t+ISOz940dm/7Qq1e7285Xgy811ULaOrJPP3W3WWsfXFF79GB5PZLODVXWbDHdTCcibwCwUlX/r4j0ApivqvtSry4GHknkk7QTZV0N8g0DPRh+6nDDz+fTKSuVUQCRSmel+gmUTvU8dejFIEmnVtz6V/V349E6CuzUeFb0dteMG4ogcwqkm5BLwtDIkUTsIiEiVwIYBLBKVc8WkZ8E8Deq+vrmS20OLhL5I+1EWYv6aXm+RhRSV+mMUj8rSZp0aqUZBTYJ1trTTMgl4QidAvsOAJcAOA4AqvoMAB7rES9pJ8padEfL8zWiTbpKZ5ziCSRPOrWStfZprT3NhFzSGiyLxEktHW4oAIhId0x7MoNJO1HWojtanq8RbdJVOuMUTyB50qmVrLVPa+1pJuSS1mBZJHaIyBcBLBCRDwK4E8CX0i2LFJW0E2V9GuTQQE/DzxelU1qUTp/6uaq/O0jSqZVmFFjfuEPMKZBuQi5pDdYL128BcBFKGuztqvodwz7XA7gYwEFVPae8bRGAvwawHMCTALao6mERuRDAtwBMXQz/W1W9Ou45eE0iv6SdKOtaSSHtJqvS6bYLGQyYtH7reHztQs0pkG5CLmmeNFJg9wCYehUfNO7zFQDXArihYtvHAdylqn8kIh8v/35F+bH7VPViY9+Foeh/CCGjqC0evrV/V4P0KZ2Wvnw65Yq+eZg9qzP29IfbzleDT6e13LeQ9N6QIy+cxNOHXsDynrl1a/eN21VSfRpuyHsU0tZ8SRgsdtMWANsA3IPSkcQQgN9V1ZtiOxdZDuDWiiOJRwFcqKrPishZAO5R1VXlI4mPNbpI5P1IouiaX80X2q9fjB27DsSOx5Kk6ksZXb9sUaL58qmsSfuyvmZuu8FlC6tU0yj9VIGabW4qq2+efcm3rrZ65hldeO5HJ2Ofz6f0WsZtTWAt+vt+JhBagX0QwFtU9WD59z4Ad6rqWkMhy1G9SBxR1QUVjx9W1YXlReKbAA4AeAalBeORuP7zvEgUXfOzfKG9bzzWJFUfc2Z1NKyMRqmgXZ2CkxPRKa0+rK+ZZW4aYXYHUK8rdyzN4iq9lnFbE1iL/r6fKYRWYDumFogy48b9GuEBAMvKC88XANwc1VBELheRYREZHhsbC1xGOIqu+Vm+0N43HmuSqg+3RTMqq0jj+qn1NbPMTWPUnxt3LM3iKryWcVsTWIv+vie1WN7p3xaR20XkfSLyPgD/D8BtCZ9vtHyaCeX/HwQAVf2Rqh4r/3wbgNnlO7trUNXrVHVQVQf7+voSlpE+Rdf8LF9o7xtPVJKqq4P6cFs0o7K6R8hJU2etY2yO+nMT+iuGXYXXMm5rAmvR3/ekFssioQC+CGANgLUArmvi+W4B8N7yz+9FyWiCiJwp5X8uicj55brGvT0UhKJrfpYvtPeNx5qk6ksZTaKMRqms2zfXT2m1jtk6Rt94fPqpb9tnt6yrO8/bN681aatnnVGdgRT1fK6xZRm3NYG16O97UovlmsQDqnqes22Pqq6J2e9GABcC6AUwCuBKlE4j7QCwFMDTADar6iER+TBKibOnALwI4LdV9V/iis/zNYkpZqrdlDRlNKTKGjJ11tLOqp+GtJvcbdbnSzpuq91U9Pd9uxNEgRWRDwH4NQCvEpE9FQ/NB/DPcR2r6rsjHnqTp+21KOmybUczml/aH3IWLF9ob9nPh0/DtPbvjjFpX83Mldu/Tz/1JaT6FFtXn7XOw1Pjx3H/k4ewcO5sDPTP9/a9YG4Xli6aiwVzXz7SuGvvc7hj7yguWt2PN60+0zsea6ptyMRfLi75o973SbwCwEIAn0LpfoYpjqrqoQxqi6UIRxJJSaoR5lU/DFlXqL4sqq61bzcVthHV1Ke3umqpTz/d+cQ4HqtIfT3rjC4cfvFUbN/ufqv6u3H7Ry9MNDchk27z+t5tR4IqsHmmXReJpBphXvXDkHWF6suq6lr6jkqFtaimUXprpVqaNPG1qxM4OWFr+xdb108fUVjnZs6sDgCKE6caU4195PW9266EVmBJxiTVCPOqH4asK1RfVlXX0ndUKqxFNY3SWyvV0qSJr9LAn/cde0enf7bOTWeHoFPy9bqS8HCRyCFJNcK86och6wrVl1XVtfQdlQprUU2jjuQr1dKkia8Ku6Z70er+6Z+tczMxqZjQfL2uJDxcJHJIUo0wr/phyLpC9WVVdS19+1JhrapplN5aeRE+Sj91U1/POqPL6Xudab9V/d3Tp5oamZttm9Zg26bGVWMfeX3vEl6TyDV5sJtCErKuUH2FTG5tRjW1qKW+Nq6lZO3bZzclnZs8vq6kPmmkwJIWkFQjzEO6ZkgtMmQNFqx1uouCTzW11uCqpb4Pdp9+uqynG69dvgjLeqK/C8yn5q5buhC980+rezrHl2Drm5uQr2se3rukGh5JkOCkrTJa+g/VJgpXeXUTWKOSaC0aqS9R1teXq7cODfTg/qcOV7XZMbw/NnXWN26r0kuKCRVY0jLSVhkt/YdqE0WU8uriptpaNVIfrs5q0Vuj0mXd7e64rUovKS5UYEnLSFtltPQfqk0UUcqriyu3WjVSf18ddX/37xSVHltf87UqvWRmwEWCBCVtldHSf6g2UUQpry7usYFVI/X3NVn3d/9OUUcn9TVfq9JLZgZcJEhQ0lYZLf2HahOFT3l1E1h9qbZWjdSXKLt987pYvXVooKeqzWe3rDOlzrrjtiq9ZGbAaxIkFdJWGS39h2oThWs3WZNoQybkuu18bSyps5bxkfaBCixJDeuHakiV0feBaUksdZNVrXUmjR33Kao+fHW5uqk11dZ9Tl8bXzKs5fXxJdhao8JdeP9DceEiQcy0IqXTl37qJqQmTVa1Pp9PP61US6+5ewSr+rvx1KEXY3VXX11PjB2v6suqm6at+VrmxjKnTHctNjzdREy0IqUzKv20MiE1abJqI8/nqqxR/VfvU6u7NpLKGqebpq35ulhei6R1kuyhAkuC04qUzqj008rtSZNVG3nc7c3yzyqf7tpIKmucbpq25utieS2S1knyDU83EROtSOmMSj+t3J40WbWRx93eou4+qGRCJwGCtc6ZAAARbElEQVStbtlIKmucbpq25utieS2S1knyDY8kiIlWpHRGpZ9Wnt5ImqzayPO52ur2zWtrFNFV/d2xumtUKmsS3TRtzdc6N3FzynTX4sNrEqQhWmGpWIyapMmq1uezqKVW3dXXf1LdNG3N14V2U3tABbaF5PGPoZl4Z7ddM2qr25e1Bp8OaqnLp6QmrcHXv6uIWhNSfeNxE2RDLnohdWTLa+HbxnTX4sJFIiB5VP2sX2jvqzPkeNy+tgwuxo7hA4n6Tqp+uuPesn4xduw6EESdbQZXLX3DQA+GnTRXX10+NTfr91sz7y9SDHi6KRB5VP38X2hv+/L6kOPx9eVi7Tup+mlJW41SVOM0z2aIUkur6/Irt+72rN9vzby/SGuhAtsC8qj6eb/Q3vjl9SHH4+vLxdp3UvXTkrYapajGaZ7NYOk7Sul1t2f9fmvm/UWKA083BSKPqp/3C+0nFXEpoFH7hvySexdr30nVT9+4XaIU1TjNsxksfUcd7bvbs36/NfP+IsWBRxKByKPq56vJ+uX1Icfj62vrhqWJ+k6qfvrG7dYQpaimdaoJ8KulbpprlNK7fXP865gmzby/SHHgNYnAtLvdFLKOZvpOqn5aakhqETWDJc01afBg2jTz/iKtITcKrIhcD+BiAAdV9ZzytkUA/hrAcgBPAtiiqoeldIL1TwC8DcALAN6nqg+kWV8apJ1+mmZNlrRVH9YPCbcva12WvqxzZanBp85mfW+DD59+akm6bQVUXtuHtK9JfAXAtQBuqNj2cQB3qeoficjHy79fAeC/AFhZ/u9nAPxZ+f8zkqSJmxZCpqamrUBadFdrcqulBuvchExudfv3KbC+2tN8j1jJo/ZNwpL66SYRWQ7g1oojiUcBXKiqz4rIWQDuUdVVIvLF8s83uu2i+s7j6aYQJE3ctBClLVamlVqfL20F0qK7Rs2Vq7NaamgkUdZHkuTWqLmvxFd7mu8RK3nUvomNvCuw/VMf/OX//0R5+ysB7K9od6C8rQoRuVxEhkVkeGxsLPViW0HSxE0LFh3V+nxpK5AW3TU6ubXxGhpJlPWRJLnVgq/2NN8jVvKofZPw5Mlu8v011vwTTlWvU9VBVR3s6+vLoKzsSZq4acGio1qfL0qBnND01Fm3r+jk1sZraCRR1keS5FYLvtrTfI9YyaP2TcLTikVitHyaCeX/HyxvPwBgSUW7xQCeybi2XJA0cdNClLYYKuEzpAJp0V2j5mr75nUN19BIomyo5Fbf3LsKrK/2NN8jVvKofZPwtOKaxDYA4xUXrhep6u+JyH8F8GGU7KafAXCNqp5fr+92vSYxRZoqZkj1M20F0tJXSD20FcmtFgXWOu6soe5aPPKkwN4I4EIAvSJyAMCVAP4IwA4ReT+ApwFsLje/DaUFYgQlBfaX0qytUVrhqPuUxyQ0k7Zqwac7+tRMt45mPuDcfX3aalJ916rFruibh9mzOqdPrzSTKOv272uT9YdxM+Mh7UOqi4SqvjvioTd52iqAX0+znqSEVCyzphUpnZb5Gly2cFohnWrj0zctyujQQA/uNyijlr6tabiWRNm0U23TTKyl2kqm4B3XMUSphq66mEf1z69cCgBJrXarkurD1TeTKqlJdVdrGq4lUTbtVNs0E2uptrY/eVdgC0W0YllNHtU/r6IqHejsSC891KqkWvZNqqQm1V2tabiWRNm0U23TTKyl2koqYQpsDNGKZTV5VP+8iqpOAlr9QRuydquSatk3qZKaVHe1puFaEmXTTrVNM7GWaiuphEcSMUSphu6X3OdR/fMrl2tTrd2qpLoKqU/ftCqpFmXUxapvJk2UTTvVNs3EWqqtpBJekzCS1wROC61I6bTMl9VuCqmMWvq2tstDqm3WmjRpDxq5JsFFghBCZhi8cN0g48dO4MH9RzB+7ESrS2mYtGvPw9z4arDUFapN6H3zMKcWilInSZcZf+G6yD542rXnYW6S3ueR9N6DkPc2hNwva4pSJ0mfGX26qcg+eNq152FukkaRJ733IOS9DSH3y5qi1EmSw9NNRorsg6ddex7mJmkUedJ7D0Le2xByv6wpSp0kG2b06aYi++Bp156HubHeo2C5ryBJm0bqCnlvRqspSp0kG2b0kUSRffC0a8/D3CSNIk9670HIextC7pc1RamTZMOMviYxRZF98LRrz8PcJL3PI1SbRupKc7+sKUqdpHFyExVeFEJGHefhDyvtD8es8b0+ltcsVBsr7RatXZQ6SbpwkQhI1tpgmnpoK8ZTJNy52TK4GDuGk0WFE5JneLopEFlrg0ljwJuJyKYGWcI3Ny6cK5JnqMC2gKy1waQx4M1EZFODLOGbGxfOFWkXeLopEFlrg0ljwJuJyKYGWcI3Ny6cK9Iu8EgiEFlrg0ljwJuJyKYGWcI3N0mjwgnJO7wmEZg8fFl9SLupSBZU1oSMCickS6jANkjIP+40tUFfnUn1UCtpjmd43zjuffx5bFzZi8EVPfE75Ax3bqiMknZkxi8SRdE8Q9aZhzG/58s78d2RcQDANXePYGigB1/9wAWZ1kAIiWdGX5MYP3YCV3xzD3780iSOnjiFH780id/75p7c5eeHrDMPYx7eNz69QExx38g4hveNR+xBCGkVM3qRKIrmGbLOPIz53sefb2g7IaR1zOhFoiiaZ8g68zDmjSt7G9pOCGkdM3qRKIrmGbLOPIx5cEUPhgaqL1QPDfQU8uI1Ie1OSxRYEflNAB8EIAC+pKp/LCJXlbeNlZv9vqreVq+fmZYCG7LOPIy56HYTIUWlEQU280VCRM4B8A0A5wM4CeAfAHwIwC8AOKaq26195fE+iayZCVHhWTMTx0xmFnm/T+LVAHaq6gsAICL/BOAdLaij8KStsuZBlc2amThmQurRimsSDwPYKCI9IjIXwNsALCk/9mER2SMi14vIwhbUVhjSVlnzoMpmzUwcMyFxZL5IqOr3AXwawHdQOtX0IIBTAP4MwE8BWAfgWQCf9e0vIpeLyLCIDI+NjfmazAjSVlnzoMpmzUwcMyFxtMRuUtW/UNXzVHUjgEMAHlfVUVWdUNVJAF9C6ZqFb9/rVHVQVQf7+vqyLDtXpK2y5kGVzZqZOGZC4mjJIiEiP1H+/1IA7wRwo4icVdHkHSidliIRpK2y5kGVzZqZOGZC4miVAnsfgB4ALwH4bVW9S0S+itKpJgXwJIBfUdVn6/VDu4l2UxrMxDGTmUXe7Sao6pBn2y+2opY8Y/mwSjt5NA/Jpll/aOdhzITkhRmfAptXqGKW4DwQ0lpmdCxHXqGKWYLzQEjr4SKRQ6hiluA8ENJ6uEjkEKqYJTgPhLQeLhI5hCpmCc4DIa2nJQpsKNpdgaWKWYLzQEhYcq/AEhuhVMyR0aPYvf8I1i1ZgIH++QEqyxYqqYS0Di4Sbc4nb34IN+x8evr3rRuW4upLz21hRYSQIsFrEm3MyOjRqgUCAG743tMYGT3aoooIIUWDi0Qbs3v/kYa2E0KICxeJNmbdkgUNbSeEEBcuEm3MQP98bN2wtGrb1g1LC3nxmhDSGnjhus25+tJzsfWC5YW2mwghrYOLxAxgoH9+qosD72MgpH3hIkGagimthLQ3vCZBEsOUVkLaHy4SJDFMaSWk/eEiQRLDlFZC2h8uEiQxTGklpP3hhWvSFJeseyVeP9BLu4mQNoWLBGkaprQS0r7wdBMhhJBIuEgQQgiJhIsEIYSQSLhIEEIIiYSLBCGEkEhEVVtdQ2JEZAzAU62uIyG9AJ5vdREJKXLtQLHrZ+2to8j1u7UvU9U+y46FXiSKjIgMq+pgq+tIQpFrB4pdP2tvHUWuv5naebqJEEJIJFwkCCGERMJFonVc1+oCmqDItQPFrp+1t44i15+4dl6TIIQQEgmPJAghhETCRSJlROStIvKoiIyIyMfrtNskIioiubEn4moXkfeJyJiI7C7/94FW1OnDMu8iskVE9orIIyLy9axrrIdh7j9fMe+PiciRVtTpw1D7UhH5RxH5dxHZIyJva0WdPgy1LxORu8p13yMii1tRpw8RuV5EDorIwxGPi4hcUx7bHhE5z9SxqvK/lP4D0AngBwBeBaALwIMAVnvazQdwL4CdAAZbXbe1dgDvA3Btq2tNWPtKAP8OYGH5959odd2Nvm8q2v8GgOtbXXcDc38dgA+Vf14N4MlW191A7X8D4L3ln38OwFdbXXdFbRsBnAfg4YjH3wbg2wAEwAUA/tXSL48k0uV8ACOq+oSqngTwDQCXetr9DwCfAfDjLIuLwVp7HrHU/kEA/0dVDwOAqh7MuMZ6NDr37wZwYyaVxWOpXQGcUf75FQCeybC+elhqXw3grvLP/+h5vGWo6r0ADtVpcimAG7TETgALROSsuH65SKTLKwHsr/j9QHnbNCLyGgBLVPXWLAszEFt7mcvKh643iciSbEqLxVL72QDOFpF/FpGdIvLWzKqLxzr3EJFlAFYAuDuDuixYar8KwHtE5ACA21A6EsoDltofBHBZ+ed3AJgvIj0Z1BYC8/uqEi4S6SKebdM6mYh0APg8gN/JrCI7dWsv8/cAlqvqGgB3AvjL1KuyYal9FkqnnC5E6V/iXxaRBSnXZcVS/xTvAnCTqk6kWE8jWGp/N4CvqOpilE6BfLX8t9BqLLV/DMDPisi/A/hZAP8J4FTahQWikffVNHl4YdqZAwAq/3W9GNWH1vMBnAPgHhF5EqXzhLfk5OJ1XO1Q1XFVPVH+9UsA1mdUWxyxtZfbfEtVX1LVfQAeRWnRyAOW+qd4F/Jzqgmw1f5+ADsAQFW/B+A0lLKFWo3lPf+Mqr5TVV8D4A/K236YXYlN0cj7ahouEulyP4CVIrJCRLpQ+oO+ZepBVf2hqvaq6nJVXY7ShetLVHW4NeVWUbd2AHDOZ14C4PsZ1leP2NoB3AzgjQAgIr0onX56ItMqo7HUDxFZBWAhgO9lXF89LLU/DeBNACAir0ZpkRjLtEo/lvd8b8VRzycAXJ9xjc1wC4CtZcvpAgA/VNVn43bid1yniKqeEpEPA7gdJXPielV9RESuBjCsqjV/+HnBWPtHROQSlA63D6FkO7UcY+23A7hIRPYCmADwu6o63rqqX6aB9827AXxDy+pKHjDW/jsAviQiH0XpdMf78jAGY+0XAviUiChKRuKvt6xgBxG5EaX6esvXe64EMBsAVPXPUbr+8zYAIwBeAPBLpn5z8NoQQgjJKTzdRAghJBIuEoQQQiLhIkEIISQSLhKEEEIi4SJBCCEkEi4ShHgQkTNF5Bsi8oNyUuxtInK5iOQtPoWQVOEiQYiDiAiAvwNwj6r+lKquBvD7APpbWxkh2cNFgpBa3gjgpfINSAAAVd0N4D4A88phhv8hIn9VXlAgIp8UkftF5GERua5i+z0i8mkR+bfy9z4Mlbd3ish2EXmoHJD4G+Xt60Xkn0Rkl4jcbknpJCRNuEgQUss5AHZFPPYaAL+FUmT0qwC8vrz9WlV9raqeA+B0ABdX7DNLVc8v73dledvlKKW3vqYckPhXIjIbwBcAbFLV9ShFPvyvcMMipHEYy0FIY/ybqh4AABHZDWA5gO8CeKOI/B6AuQAWAXgEpZRcAPjb8v93ldsDwJsB/LmqngIAVT0kIuegtEB9p3wg0gkgNluHkDThIkFILY8A2BTx2ImKnycAzBKR0wD8KUrfKrhfRK5CKbTO3WcCL//NCWpjmgXAI6q6oYnaCQkKTzcRUsvdAOaIyAenNojIa1H6/gAfUwvC8yIyD9ELTCV3APhVEZlV7n8RSnHlfSKyobxttoj8dMIxEBIELhKEOJQTSd8B4C1lBfYRlL5NzZu9r6pHUPo+jYdQiiC/3/A0X0YpMnuPiDwI4L+XvzJzE4BPl7ftBvC6JodDSFMwBZYQQkgkPJIghBASCRcJQgghkXCRIIQQEgkXCUIIIZFwkSCEEBIJFwlCCCGRcJEghBASCRcJQgghkfx/Pv9qtPCzyrgAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAEKCAYAAAD9xUlFAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4xLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvDW2N/gAAIABJREFUeJzt3X90XOV5J/DvM9LoR2XZFrIqa5GEncrxqRcLBSsEQeU6hHBoyrHJSqbJHo5CTihpGtqEJK3b7ilJvdvNYhPYk9IGyI8TwCmpa1KbsNmDgwnrgOOEsSPboASsIIJELCGPJZCILMuaZ/+Y8fXcO+/MvPPjzozM93OOjnXfee9zn/e9d+aZuVeeK6oKIiIiAAgUOwEiIiodLApERORgUSAiIgeLAhEROVgUiIjIwaJAREQOFgUiInKwKBARkYNFgYiIHOXFTiBTy5Yt0xUrVhQ7DSKiBeXQoUMnVbUhXb8FVxRWrFiBUChU7DSIiBYUEfm1TT+ePiIiIgeLAhEROVgUiIjIwaJAREQOFgUiInL4WhRE5FUROSYi/SKS8CdDEvVVERkUkaMicrmf+RARUWqF+KTwflXtUNVOw2N/BGBV7Oc2AF8rQD55F56exZHhSYSnZ4udCi0QuRwzfh5vptiDY1PYFRrG4NhU3reX7/je/E3jCQ2Fcc/elxAaCqfMwdtm0wcAdh8exq0PPY/dh4cBADsODGHz/Qew48CQ02ffwCi27DqCfQOjTpupXzGIn7fjFJFXAXSq6skkjz8A4BlVfTS2/BKADap6IlnMzs5OLaX/p7Cn/3VseewogoEA5iIRbOtpx8aOi4udFpWwXI4ZP483U+zQq6fw8MHXnD59Xa3YumltXrYHAHfuPpa3+N78b1rXjJ2HRlzj2RkaxrOD54tBd1s9Vi6rScgBClfb6sYavDT2dso+fV2t2PviKEbfOpM0xyVVZWhcUoWX42KtbqzB6Jun8ebpeVe/I1+6Pqt5SEZEDiV5c+7u53NRGAIwAUABPKCqD3oefwLA/1LVZ2PL+wBsUdWkr/qlVBTC07O4+q6ncXou4rRVBQN4bss1qF9UWcTMqFTlcsz4ebyZYleUCc7MJ74+PHXHerQ11ua0PSD6Lvvae/fnJb4pf6+KsgDOzCd/vNT8j41rcPNVK/MWz7Yo+H366GpVvRzR00SfFpH1nsfFsE7CUSgit4lISERC4+PjfuSZlZGJGQQD7ikMBgIYmZgpUkZU6nI5Zvw83kyxRUxPT6B/eDLn7aWKk018U/6J/HsD7Ic9R5OeMPGVr0VBVX8T+/cNAP8B4ApPlxEALXHLzQB+Y4jzoKp2qmpnQ0Par+4omOa6asxF3O885iIRNNdVFykjKnW5HDN+Hm+m2MnOInS0LM15e6niZBPflH8ic5ErVZvam4qyXd+KgojUiEjtud8BXAfgBU+3xwH0xf4K6UoAb6a6nlBq6hdVYltPO6qCAdRWlqMqGMC2nnaeOqKkcjlm/DzeTLHv3nxZ9Nx5nL6u1rycOgKAtsbavMU35d/X1eoZTzu62+pd63W31Rtz8LatbqxJ26evqxVNiytS5rmkqiwh1urGGiypKkvol89TR5nw7ZqCiLwL0U8HQPSL9/5VVf9RRP4MAFT1fol+Pr0PwPUAfgvg46muJwCldU3hnPD0LEYmZtBcV82CQFZyOWb8PN5MsQfHptA/PImOlqV5Kwjx8hnfm79pPKGhMPYfP4n1q5ahc2V90hy8bTZ9gOhfHz1xbBQ3rF2OGy9vwY4DQ9hz9AQ2tTc5L/T7Bkaxd2AM161pxAfWLAcAY798KokLzX4oxaJARFTqSuVCMxERLSAsCkRE5GBRICIiB4sCERE5WBSIiMjBokBERA4WBSIicrAoEBGRg0WBiIgcLApERORgUSAiIgeLAhEROVgUiIjIwaJAREQOFgUiInKwKBARkcP3oiAiZSLycxF5wvDYLSIyLiL9sZ9b/c6HFqbw9CyODE8iPD1b8nnkq08usWzbvEJDYdyz9yWEhsIp1/P2Gxybwq7QMAbHpnLOy2Z7yfrtGxjFll1HsG9g1Lhsux4QvYParQ89j92Hh5P2MeXl7bfjwBA2338AOw4MpczBxDSvfvP9zmsi8jkAnQAWq+oNnsduAdCpqrfbxuOd19559vS/ji2PHUUwEMBcJIJtPe3Y2HFxSeaRrz65xFLAqs0b6+ZvHMSzg+df3Lrb6tHb2ZKw3s7QsKvf8sUVGH3rjLPc19WKdZdclFVeN3U2Y2doJOX2kuV134+O4+Wxt51+QQHm4l7eVjfW4M/fvyrteqsba/DmzJxrTAEAEbhjNdRWJeQ1NnXaFctrSVUZtt641mr/37n7GB4++JprXrduWps0djolcTtOEWkG8BCAfwTwORYFylR4ehZX3/U0Ts+df0pWBQN4bss1Bb0ftk0e+eqTS6zKcgEgmD0b3xYAoJg9q0ljhYbC6H3gYMK4K8oCODMfiVsWnJlP/5pRUQacmT+/bM4rsc0rGADmDA9728sFOGvxUuZdL1l8P5UHgPghm/b/4NgUrr13f8K6T92xPuv7WJfK7Tj/N4C/hrvIevWIyFER2SUiLaYOInKbiIREJDQ+Pu5LolSaRiZmEAy4D9NgIICRiZmSyyNffXKJVSYBlAXE3RYQlEnqWPuPn4SZplhKTmCRl6EtMVCSxz3ttnl5+xW4HkS36UnCtP/7hyeN6yZrzyffioKI3ADgDVU9lKLb9wGsUNV2AE8h+qkigao+qKqdqtrZ0NDgQ7ZUqprrqjEXcT915yIRNNdVl1we+eqTS6x5jWDe86ozH1HMa+pY61ctg5mkWEpOYZGXoS0xUJLHPe22eXn7FeMvbbx10LT/O1qWGtdN1p5Pfs7J1QA2isirAL4L4BoR2RHfQVXDqnruSsvXAazzMR9agOoXVWJbTzuqggHUVpajKhjAtp72gp46ss0jX31yibW99zJs7/W2tWN772UpY3WurEd3W70rh+62ety92R3r7s2XJfRrWlzhWu7rasXdmzss8kps6+tqdS1/5aYOY15fuckd/54/6cDqxhpXv6DnxXd1Y03Cel+5KXG91Y01CWPyvlCubqwx5uWN5bWkqgz3eHIw7f+2xlr0dbW62vq6WrM+dZQJ3y80A4CIbADwBcM1hSZVPRH7/cMAtqjqlali8ZrCO1N4ehYjEzNorqsueEHINI989ckllm2bV2gojP3HT2L9qmXoXFmfdD1vv8GxKfQPT6KjZanzwpVtXjbbSxZr38Ao9g6M4bo1jfjAmuUJy7brAdG/Pnri2ChuWLscN17eYuxjysvbb8eBIew5egKb2ptw81UrM9r/pnnNVklcaI5LZgNiRUFEtgIIqerjIvJlABsBnAVwCsCnVPWXqWKxKBARZa6kikI+sSgQEWWuVP76iIiIFhAWBSIicrAoEBGRg0WBiIgcLApERORgUSAiIgeLAhEROVgUiIjIwaJAREQOFgUiInKwKBARkYNFgYiIHCwKRETkYFEgIiIHiwIRETl8LwoiUiYiPxeRJwyPVYrIv4nIoIj8VERW+J0PERElV4hPCp8B8Iskj30CwISqtgG4F8BdBcgHQPR2eEeGJxGenk3feQEyjc+2rRQMjk1hV2gYg2NTRdueaW68/UJDYdyz9yWEhsIp17OZZ9sxe7dpysHUZorvbds3MIotu45g38Boyty98XcfHsatDz2P3YeHU+Zgim8zD6ZYpm1620zrmZjy8uZhysu0nnebts8xm/1TCL7eeU1EmgE8BOAfAXzOcI/mJwF8SVV/IiLlAEYBNGiKpPJx57U9/a9jy2NHEQwEMBeJYFtPOzZ2XJxTzFJiGp8CVm2lMA937j6Ghw++5iz3dbVi66a1Bd3euksuSpib0KunXP2aFlfgxFtnnOXutnr0drZkNc+2Y775Gwfx7OD5F7glVWV48/S8KwcFXH262+qxcllNQnwoXG3eWKsba/Dn71+VkPvO0LArflCAubhnbNPiCvze79Ym5DA2dRovj73tiv/kHRvSzsMr428nxDr+xhRG4+a+aXEFFHC1efPqbqvHI7cm3gL+unufScjrfSvrXXm8u7HG1aevqxUHXwknrNdQW+XKdXVjDX59aibtc8w0bu/+yfV5UBK34xSRXQC+DKAWsXs0ex5/AcD1qjoSW/4VgPep6slkMXMtCuHpWVx919M4PRdx2qqCATy35Zqi3hA+X0zjqywXAILZs/FtAQCK2bPn938pzMPg2BSuvXd/QvtTd6zP+cblmWyvokxwZl7jloEz8wndEgQDQNzUG+feO8+2Yw4NhdH7wEGLUeVP4jwEcGY+kmKNzHyzbx0+sGY5gOTzkE+7PnklOlfWO8v7BkbxiYcP+brNeKbnWCbjzuV5UPTbcYrIDQDeUNVUMy6GtoQqJSK3iUhIRELj4+M55TUyEa3a8YKBAEYmZnKKWypM4yuTAMoC7qkuCwjKpPTmoX94MqN2v7Yn4p4vsX6qeObZMPfeebYd8/7jSd8r+SbxPWN+30TuHRhzfvdrH8fzzmH89gvB9BzLZNyFmCM/rylcDWCjiLwK4LsArhGRHZ4+IwBaACB2+mgJgFPeQKr6oKp2qmpnQ0NDTkk111VjLuJ+pzMXiaC5rjqnuKXCNL55jWA+4n4yz0cU81p689DRsjSjdr+25/0ErbB9d+yZZ8Pce+fZdszrVy2zzCF/JOFtm+l9XPauW9Po/O7XPo7nncP47ReC6TmWybgLMUe+FQVV/VtVbVbVFQA+AuBpVb3Z0+1xAB+L/d4b6+Pf+SwA9Ysqsa2nHVXBAGory1EVDGBbT/sFceoIMI9ve+9l2N7rbWvH9t7LSm4e2hpro+dT4/R1tfpy6ijV9u7e7J6buzd3JPRrWlzhWu5uq8dXbupIO/feebYdc+fKenS31bvallSVJeTg7dPdVm+M723zxlrdWGOYh/aE+EFPnWhaXGHMYXVjTUL8c6eOgOTzYIrlnfumxRUJbd68utvqXaeOAOADa5Yb8/Lm4e3T19VqXM+b6+rGmrTPsWTjLuTzIJ6v1xScjYhsQOyagohsBRBS1cdFpArAIwDeg+gnhI+o6iupYuXjQjMQPfc+MjGD5rrqor8Q+sE0Ptu2UjA4NoX+4Ul0tCwtyBPBtD3T3Hj7hYbC2H/8JNavWua84GQ7z7Zj9m7TlIOpzRTf27ZvYBR7B8Zw3ZpG5wXblLs3/u7Dw3ji2ChuWLscN17ekjQHU3ybeTDFMm3T22Zaz8SUlzcPU16m9bzbtH2O2eyfXJTEhWY/5KsoEBG9kxT9QjMRES08LApERORgUSAiIgeLAhEROVgUiIjIwaJAREQOFgUiInKwKBARkYNFgYiIHCwKRETkYFEgIiIHiwIRETlYFIiIyMGiQEREDhYFIiJysCgQEZHDt6IgIlUi8jMROSIiL4rIPxj63CIi4yLSH/u51a98LnTh6VkcGZ5EeHrWuFwIg2NT2BUaxuDYVNI+prxscrWJbdvP1MfUtm9gFFt2HcG+gVGnLTQUxj17X0JoKJxRLG+bKbZtrB0HhrD5/gPYcWDIug8QvSvZrQ89j92Hh5PG944vWZs3lim2zfaSzYWXKYd8sjkGi/GcKgbf7rwmIgKgRlWnRSQI4FkAn1HVg3F9bgHQqaq328blndcS7el/HVseO4pgIIC5SAQ3rWvGzkMjzvK2nnZs7LjY1xzu3H0MDx98zVnu62rF1k1rU+a5racdCiS0eXO1iW3bz9QHioS2g6+E8fLY207b6sYaNNRW4dnB8y9KTYsrcOKtM2ljeduWVJXhzdPzrtjvW1lvldeen7/uWjcowFzcU9jUZ0lVGaoryjAal2vT4gp8cM1yV/zliytcfbrb6qGAa8zdbfU4/saUq59X0+IKKJB2e8nm+ck7Nrji3fyNgwk5PHLrlUm3nynTcek9Bm36lLqSuh2niPwOokXhU6r607j2W8CikJPw9CyuvutpnJ6LJO1TFQzguS3X+HYP5sGxKVx77/6E9qfuWO+637E3z8pyASCYPXu+zZurTWzbfsn6UGn5Zt861/2Oex84mNBn1yevTHnPZVum49J7DNr0WQhK4nacIlImIv0A3gDww/iCEKdHRI6KyC4RaUkS5zYRCYlIaHx83M+UF5yRiRkEA6l3YzAQwMjEjG859A9Ppm035VkmAZQFxNXmzdUmtm2/ZH2otOwdGHN+33/8pLFPsvZMmY5L7zFo0+dC4mtRUNV5Ve0A0AzgChG51NPl+wBWqGo7gKcAPJQkzoOq2qmqnQ0NDX6mvOA011VjLpL8UwIAzEUiaK6r9i2HjpaladtNec5rBPMR9ydVb642sW37JetDpeW6NY3O7+tXLTP2SdaeKdNx6T0GbfpcSAry10eqOgngGQDXe9rDqnruqs3XAawrRD4XkvpFldjW046qYAC1leWoCgbQ19XqWt7W0+7rx9y2xtroOfA4fV2trtM7pjy3916G7b3tKXO1iW3bL1kfU9vqxhpX2+rGGnS3uU9XNC2usIrlbVtSVZYQ2zYv77pB9wctY58lVWUJuTYtrkiI7+3T3VafMObutvqEfl5Niyustpdsns+dOgKAzpXmHPJx6ggwH5feY9Cmz4XEzwvNDQDmVHVSRKoB7AVwl6o+EdenSVVPxH7/MIAtqpryChKvKZiFp2cxMjGD5rpq1C+qTFguhMGxKfQPT6KjZWnCi3ayPJO1ZRPbtp+pj6lt38Ao9g6M4bo1ja5z3PuPn8T6VcvQubLeOpa3zRTbNtaOA0PYc/QENrU34earVlr1AaJ/DfTEsVHcsHY5bry8xRjfOz7TmE2xTLFttpdsnr1MOeSTzTFYjOdUPhX9QrOItCN6OqgM0U8kO1V1q4hsBRBS1cdF5MsANgI4C+AUoheif5kqLosCEVHmil4U/MKiQESUuZL46yMiIlpYWBSIiMjBokBERA4WBSIicrAoEBGRg0WBiIgcLApERORgUSAiIgeLAhEROVgUiIjIwaJAREQOFgUiInKwKBARkcOqKIjIu0Tk+yJyUkTeEJE9IvIuv5MjIqLCsv2k8K8AdgJYDuA/Afh3AI/6lRQRERWHbVEQVX1EVc/GfnYASHkjBhGpEpGficgREXlRRP7B0KdSRP5NRAZF5KcisiLzIRARUb7YFoUficjfiMgKEblERP4awP8RkYtE5KIk68wCuEZVLwPQAeB6EfHeavMTACZUtQ3AvQDuymYQfglPz+LI8CTC07PpOxfQ4NgUdoWGMTg2ldF6pvGYYmU7bpu89g2MYsuuI9g3MJpRbJNs8wwNhXHP3pcQGgqnbDPZfXgYtz70PHYfHgZgHrMplnc9Ux/b/bPjwBA2338AOw4MWW8PMM+9d13b8disZ3ucevvZzkOhlerrQb5Z3XlNRIZSPKyqmvL6goj8DoBnEb3d5k/j2p8E8CVV/YmIlAMYBdCgKZIq1J3X9vS/ji2PHUUwEMBcJIJtPe3Y2HGx79tN587dx/Dwwdec5b6uVmzdtDbteqbxhF49lRBr3SUXZTVum7yuu/cZvDz2trO8urEGT96xIW1s2/HY5HnzNw7i2cHzL27dbfVQIKHtkVsTbxV+5f/8IUbfOuMsV5cLZs6eP1T7ulrxyvjbCbGOvzHlWi8owFzcEd7dVo/ezhar/bPn56/jzdPzTlsAQATuWN7tNS2uQG11MGHuG2qrXLkuX1zhWi/ZeLzz1bS4Aic860FhdZx6j5vutno8/+uJtPNgc8znU6m+HmSiJG7HKSJlAA4BaAPwz6q6xfP4CwCuV9WR2PKvALxPVU8mi1mIohCensXVdz2N03Pnn25VwQCe23JNUW/YPTg2hWvv3Z/Q/tQd61PezN40nsryAGbPRhL6etttxm2T176BUXzi4UMJfb7Zty7pzdozGY9NnqGhMHofOGi1jV2fvNJ1g/jdh4fx2Z1HM8ozExVlAZyZT79/FjLvcZrsuIlXUQacmU9sT3fM51Opvh5kKq+34xSRoIj8pYjsiv3cLiLBdOup6ryqdgBoBnCFiFzqDW1azbD920QkJCKh8fFxm5RzMjIxg2DAPTXBQAAjEzO+bzuV/uHJjNrPMY0nGe8OsRm3TV57B8aMfZK1p5Lt/tl/POl7jbR9nziW++mu1BbWvdKz4T1O0h23ACBJXqJs1s2XUn098IvtNYWvAVgH4F9iP+tibVZUdRLAMwCu9zw0AqAFAGKnj5YAOGVY/0FV7VTVzoaGBtvNZq25rhpzEfe7tLlIBM111b5vO5WOlqUZtZ9jGk8y3pcmm3Hb5HXdmkZjn2TtqWS7f9avWma9DW/fG9Zm9mkmc6b3RxcW73GS7rgFAIX5uLVZN19K9fXAL7ZF4b2q+jFVfTr283EA7021gog0iMjS2O/VAK4F8EtPt8cBfCz2ey+Ap1NdTyiU+kWV2NbTjqpgALWV5agKBrCtp73oHxXbGmuj52vj9HW1pv0YbRrP9t52Y6ztvZmP2yavD6xZjtWNNa4+qxtrMj51lGw8Nnl2rqxHd1u9q627zdwWf+oIAG68vAVNiytcbdXl7hfyvq5WYyzvekHP6393Wz3u3my3f5ZUlbnavE9g0/aaFlcY596bq3e9ZOOxWc/mODUdN91t9a55uHtzR1bHfD6V6uuBX2wvNB8GsFlVfxVbfheAXap6eYp12gE8BKAM0WN3p6puFZGtAEKq+riIVAF4BMB7EP2E8BFVfSVVLoW60AxEzyWOTMygua66pA6AwbEp9A9PoqNlaUZPDtN4TLGyHbdNXvsGRrF3YAzXrWnMqiCkG4+N0FAY+4+fxPpVy5wXf1Obye7Dw3ji2ChuWLscN17eYhyzKZZ3PVMf2/2z48AQ9hw9gU3tTbj5qpVW2wPMc+9d13Y8NuvZHqfefrbzUGil+npgK68XmkXkGgDfBnDuBXsFgI+r6o9yyDErhSwKREQXCtuiUG4Zrx7ApYgWg00ArgLwZtbZERFRSbK9pvD3qvoWgMUAPgjgfmRwoZmIiBYG26Jw7i+F/xjA/aq6B0BFiv5ERLQA2RaF10XkAQA3AfiBiFRmsC4RES0Qti/sNwF4EtH/fTwJ4CIAf+VbVkREVBRWF5pV9bcAvhe3fALACb+SIiKi4uApICIicrAoEBGRg0WBiIgcLApERORgUSAiIgeLAhEROVgUiIjIwaJAREQOFgUiInKwKBARkcO3oiAiLSLyIxH5hYi8KCKfMfTZICJvikh/7OdOv/IhIqL0/PykcBbA51X19wFcCeDTIrLG0O/HqtoR+9nqYz4u4elZHBmeRHh6tlCbzEq2eeYyvnxtMzQUxj17X0JoKJzx9rxtg2NT2BUaxuDYlNPH1Gbaprefab19A6PYsusI9g2MpszLu65pezbrmbZnirXjwBA2338AOw4MOW27Dw/j1oeex+7Dw8blZGO0Ybvvvf1sxkwLg9XtOPOyIZE9AO5T1R/GtW0A8AVVvcE2Tj5ux7mn/3VseewogoEA5iIRbOtpx8aOi3OK6Yds88xlfPnaZutF1Xh57G3n8e62ejxy65VW21PA1fbeS+rw48HzL5R9Xa2AAg8ffM3V9sr423g2rl93Wz1WLqtx9Xt3Y40rr76uVhx8JexqW91Ygz9//6qEvEKvnnLFalpcgRNvnXFtr7ezJe16S6rK8Obpedf2GmqrEnI/OjLp6rekqgzVFWUYjdumV9PiCnxwzfKEudm6aW3Sdc6x3ffefjeta8bOQyMpx2ybA/knr/dozkMyKwDsB3Bp7A5u59o3AHgMwAiA3yBaIF5MFSvXohCensXVdz2N03MRp60qGMBzW64pqZtxZ5tnLuPL5zZNdn3ySufG78nWqywPAFDMni3Mm5VkygWIT6GyPIDZs6nHBwAVZYIz8xq3DJyZT7FCgTx1x/qUN7y33fc2+9o7B7Y5kL9si4LvF5pFZBGiL/yfjS8IMYcBXKKqlwH4JwC7k8S4TURCIhIaHx/PKZ+RiRkEA+5hBwMBjEzM5BQ337LNM5fx5XObJvuPn0y7XllAUCbF//uHfJUkKZG/5egfnkz5uO2+t9nXIpJVDlQafD1iRSSIaEH4jqp+z/u4qr6lqtOx338AICgiywz9HlTVTlXtbGhoyCmn5rpqzEXc73LmIhE011XnFDffss0zl/Hlc5sm61e5d61pvfmIYl7Tx/Kb+WUtc4rijwUAOlqWpnzcdt/b7OtkZx/S5UClwc+/PhIA3wTwC1W9J0mf5bF+EJErYvmkviqZo/pFldjW046qYAC1leWoCgawrae9pE4dAdnnmcv48rnN1Y01rj7dbfWuU0fJ1tve247tvZe52rrb3Ov1dbVGryt42rz9utvqE/p58+rrak1oW91Yg3v+pCMhL2+spsXu25R3t9Xj7s3u3O/e3JGw3pKqsoTtmXL39ltSVZawTa+mxRXGuUl32sZ235v69XW1esZ8WVY5UGnw7ZqCiPwBgB8DOAY4b5f+DkArAKjq/SJyO4BPIfqXSjMAPqeqB1LFzceFZiB6bnRkYgbNddUlVxDiZZtnLuPL1zZDQ2HsP34S61ctSygI6bbnbRscm0L/8CQ6WpY6Ly6mNtM2vf1M6+0bGMXegTFct6YRH1izPGle3nVN27NZz7Q9U6wdB4aw5+gJbGpvws1XrQQQ/WujJ46N4oa1y3Hj5S0Jy8nmJpt9aNvPZsxUXCV1oTmf8lUUiIjeSUrmQjMRES0cLApERORgUSAiIgeLAhEROVgUiIjIwaJAREQOFgUiInKwKBARkYNFgYiIHCwKRETkYFEgIiIHiwIRETlYFIiIyMGiQEREDhYFIiJysCgQEZHDz9txtojIj0TkFyLyooh8xtBHROSrIjIoIkdF5HK/8slGeHoWR4YnEZ6ezajN1MfG4NgUdoWGMTg2lXGu3nWzzcE2L5tcc8nBu262OZjYxjLlv+PAEDbffwA7DgxllIPNXJj62ORlm3u2eeVTLsc4FUa5j7HPAvi8qh4WkVoAh0Tkh6o6ENfnjwCsiv28D8DXYv8W3Z7+17HlsaMIBgKYi0SwracdCqRtu6mzGTtDI64+GzsuTru9O3cfw8MHX3OW+7pasXXTWqtcvet2t9Xj+V9PZJyDbV5QpM3RoccaAAAPyUlEQVTVNH+2OXjX7bykDs8Onr91t20OuYxn3SUXJeT/97uP4c3T8wCA51+dwD98fwBzcTcuTJaDzVyY+oRePZU2r/deUocfe+bGlLtp7nPZR9nI5RinwinY7ThFZA+A+1T1h3FtDwB4RlUfjS2/BGCDqp5IFqcQt+MMT8/i6ruexum5iNNWWS4ABLNn49sCABSzZ5PPYVUwgOe2XJPyfreDY1O49t79Ce1P3bE+7b1tk62baQ7Zxj4nPlfT/NnmYFrXVrr5ymQ8FWWCM/Pn92u5ACl2c9IcbObCfLwFXMdauvZUfUxzn8s+ykYuxzjlR0ndjlNEVgB4D4Cfeh66GMBw3PJIrM27/m0iEhKR0Pj4uF9pnk9iYgbBgHtqyiSAsoC42wKCMkk9hcFAACMTMyn79A9PZtSeaR+bHLKNbeprmj/bHEzrZpNDNo/HE3Hv64jleyfvNmzmIpMxS/ouCX1Mc5/LPspGLsc4FZbvRUFEFgF4DMBnVfUt78OGVRKefqr6oKp2qmpnQ0ODH2m6NNdVYy7ifjc2rxHMe14Z5iOKeU39rm0uEkFzXXXKPh0tSzNqz7SPTQ7Zxjb1Nc2fbQ6mdbPJIZvH43k/QQdsXo0N27CZi0zGbFObvH1Mc5/LPspGLsc4FZavRUFEgogWhO+o6vcMXUYAtMQtNwP4jZ852ahfVIltPe2oCgZQW1mOqmAA23svw/Zeb1s7tvde5mrr62p1LW/raU/7cbytsTZ6bjtOX1er1cdq07rdbfUZ55BJXulyNc2fbQ6mdbvb6jPOIdfx3L3ZvV/v+ZMOLKkqc/ULegqFKQebuTAfb+3GvLzHoGluvH1Mc5/LPspGLsc4FZZv1xQk+vn7IQCnVPWzSfr8MYDbAXwI0QvMX1XVK1LFLcQ1hXPC07MYmZhBc1216/xvujZTHxuDY1PoH55ER8vSjJ8s3nWzzcE2L5tcc8nBu262OeQyHlP+Ow4MYc/RE9jU3oSbr1ppnYPNXJj62ORlm3u2eeVTLsc45cb2moKfReEPAPwYwDEA5z6n/h2AVgBQ1ftjheM+ANcD+C2Aj6tqylf8QhYFIqILhW1R8O1PUlX1WaS5LqbRivRpv3IgIqLM8H80ExGRg0WBiIgcLApERORgUSAiIgeLAhEROVgUiIjIwaJAREQOFgUiInKwKBARkYNFgYiIHCwKRETkYFEgIiIHiwIRETlYFIiIyMGiQEREDt+Kgoh8S0TeEJEXkjy+QUTeFJH+2M+dfuVCRER2/Pyk8G1E76iWyo9VtSP2s9XHXBaE8PQsjgxPIjw9m3M/U5/QUBj37H0JoaFwyvi2/dJtM5ccBsemsCs0jMGxKeNysvimfunyzLeFHj8bpZgTZcfPO6/tF5EVfsW/0Ozpfx1bHjuKYCCAuUgE23rasbHj4qz6mfrsDA3j2cHoC/FXnx5Ed1s9Hrn1yoT4N3/joFW/dHndtK4ZOw+NZJXDnbuP4eGDrznL726swctjbzvLfV2tWHfJRQljDL16yrVeX1crtm5am9U8Z2uhx79QcqLs+XaPZgCIFYUnVPVSw2MbADwGYATAbwB8QVVfTBfzQrxHc3h6Flff9TROz0WctqpgAM9tucZ1M3WbfqY+wQAQt+jY9ckr0bmy3lkODYXR+8DBtP1s8veyzWFwbArX3rs/aZxzKssDmD17PmBFmeDMfOKx/NQd6103s7eZ52wt9PgXSk5kZnuP5mJeaD4M4BJVvQzAPwHYnayjiNwmIiERCY2PjxcswUIZmZhBMODeFcFAACMTMxn3M/VJdqvs/cdPplxO1556m94U7HLoH55MHedcuITw5vjx8WznOVsLPX42SjEnyk3RioKqvqWq07HffwAgKCLLkvR9UFU7VbWzoaGhoHkWQnNdNeYi7rfRc5EImuuqM+5n6gOYPw2uX7Us5XK69tTb9KZgl0NHy9LUcc6FSwhvjh8fz3aes7XQ42ejFHOi3BStKIjIcom9vRORK2K5ZHZl8wJRv6gS23raURUMoLayHFXBALb1tCd8/LbpZ+rzlZs60N3mPv3T3VafcEqoc2W9VT+b/Pu6WrPKoa2xFn1dra621Y01ruW+rlZs73Vv7+7NlyWs19fV6pw6SpanaZ6ztdDjXyg5UW58u6YgIo8C2ABgGYAxAF8EEAQAVb1fRG4H8CkAZwHMAPicqh5IF/dCvKZwTnh6FiMTM2iuq075pLLpZ+oTGgpj//GTWL9qWcoXett+6baZSw6DY1PoH55ER8tStDXWJiwnG6Opn83c5NNCj5+NUsyJ3GyvKfh6odkPF3JRICLyy0K40ExERCWGRYGIiBwsCkRE5GBRICIiB4sCERE5WBSIiMjBokBERA4WBSIicrAoEBGRg0WBiIgcLApERORgUSAiIgeLAhEROVgUiIjIwaJAREQOFgUiInL4VhRE5Fsi8oaIvJDkcRGRr4rIoIgcFZHL/cploQhPz+LI8CTC07PFTiUr+czfG8sUe3BsCrtCwxgcm8p5e0QUVe5j7G8DuA/Aw0ke/yMAq2I/7wPwtdi/70h7+l/HlseOIhgIYC4SwbaedmzsuLjYaVnLZ/7eWDeta8bOQyOu2KFXT+Hhg6856/R1tWLrprX5Gg7RO5avt+MUkRUAnlDVSw2PPQDgGVV9NLb8EoANqnoiVcwL8Xac4elZXH3X0zg9F3HaqoIBPLflmgVxv9t85m+K5VVZHsDs2cTHn7pjfdL7MhO90y2E23FeDGA4bnkk1pZARG4TkZCIhMbHxwuSXCGNTMwgGHDvimAggJGJmSJllJl85m+KZat/eDKr9YjovGIWBTG0GT+2qOqDqtqpqp0NDQ0+p1V4zXXVmIu43/nORSJorqsuUkaZyWf+pli2OlqWZrUeEZ1XzKIwAqAlbrkZwG+KlEtR1S+qxLaedlQFA6itLEdVMIBtPe0L4tQRkN/8TbH6ulpdy9t729HX1epar6+rlaeOiPKgmNcU/hjA7QA+hOgF5q+q6hXpYl6I1xTOCU/PYmRiBs111QumIMTLZ/7eWKbYg2NT6B+eREfLUhYEojRsryn49tdHIvIogA0AlonICIAvAggCgKreD+AHiBaEQQC/BfBxv3JZKOoXVS7IYnBOPvP3xjLFbmusZTEgyjPfioKqfjTN4wrg035tn4iIMsf/0UxERA4WBSIicrAoEBGRg0WBiIgcLApEROTw9f8p+EFExgH8uth5ZGkZgJPFTiJLCzl3YGHnz9yLZyHn7839ElVN+5UQC64oLGQiErL5zyOlaCHnDizs/Jl78Szk/LPNnaePiIjIwaJAREQOFoXCerDYCeRgIecOLOz8mXvxLOT8s8qd1xSIiMjBTwpERORgUfCBiFwvIi+JyKCI/E2Kfr0ioiJSMn/dkC53EblFRMZFpD/2c2sx8jSxmXcRuUlEBkTkRRH510LnmIrF3N8bN+8vi0jJ3GrOIvdWEfmRiPxcRI6KyIeKkaeJRe6XiMi+WN7PiEhzMfI0EZFvicgbIvJCksdFRL4aG9tREbk8bVBV5U8efwCUAfgVgHcBqABwBMAaQ79aAPsBHATQWey8bXMHcAuA+4qda5a5rwLwcwB1seXfLXbemR43cf3/AsC3ip13BnP/IIBPxX5fA+DVYuedQe7/DuBjsd+vAfBIsfOOy209gMsBvJDk8Q8B+L+I3unySgA/TReTnxTy7woAg6r6iqqeAfBdAJsM/f47gG0AThcyuTRscy9FNrn/KYB/VtUJAFDVNwqcYyqZzv1HATxakMzSs8ldASyO/b4EpXOXRZvc1wDYF/v9R4bHi0ZV9wM4laLLJgAPa9RBAEtFpClVTBaF/LsYwHDc8kiszSEi7wHQoqpPFDIxC2lzj+mJfRTdJSIthseLwSb3dwN4t4g8JyIHReT6gmWXnu3cQ0QuAbASwNMFyMuGTe5fAnBz7IZbP0D0k04psMn9CICe2O8fBlArIvUFyC0frI+rc1gU8k8Mbc6feIlIAMC9AD5fsIzspcw95vsAVqhqO4CnADzke1Z2bHIvR/QU0gZE32l/Q0SW+pyXLZv8z/kIgF2qOu9jPpmwyf2jAL6tqs2IntJ4JPZcKDab3L8A4A9F5OcA/hDA6wDO+p1YnmRyXAFgUfDDCID4d8/NcH9UrgVwKYBnRORVRM/zPV4iF5vT5Q5VDavqbGzx6wDWFSi3dNLmHuuzR1XnVHUIwEuIFolSYJP/OR9B6Zw6Auxy/wSAnQCgqj8BUIXod/MUm80x/xtV/S+q+h4A/y3W9mbhUsxJJscVABYFPzwPYJWIrBSRCkSfwI+fe1BV31TVZaq6QlVXIHqheaOqhoqTrkvK3AHAcz5yI4BfFDC/VNLmDmA3gPcDgIgsQ/R00isFzTI5m/whIqsB1AH4SYHzS8Um99cAfAAAROT3ES0K4wXN0szmmF8W96nmbwF8q8A55uJxAH2xv0K6EsCbqnoi1Qq+3aP5nUpVz4rI7QCeRPQvG76lqi+KyFYAIVVNeKKXCsvc/1JENiL68fkUon+NVHSWuT8J4DoRGQAwD+CvVDVcvKzPy+C4+SiA72rsT0tKgWXunwfwdRG5A9HTF7eUwhgsc98A4Msiooj+xWDJ3FteRB5FNL9lses1XwQQBABVvR/R6zcfAjAI4LcAPp42ZgnsFyIiKhE8fURERA4WBSIicrAoEBGRg0WBiIgcLApERORgUSACICLLReS7IvKr2Leo/kBEbhORUvsqEiJfsSjQO56ICID/APCMqv6eqq4B8HcAGoubGVHhsSgQRf+X81zsP/sAAFS1H8CPASyKffHfL0XkO7ECAhG5U0SeF5EXROTBuPZnROQuEflZ7J4H3bH2MhG5W0SOxb5M8C9i7etE5P+JyCEReTLdN1gS+Y1FgSj6XVSHkjz2HgCfRfTrk98F4OpY+32q+l5VvRRANYAb4tYpV9UrYut9MdZ2G6LfbPqe2JcJfkdEggD+CUCvqq5D9OsT/jF/wyLKHL/mgii1n6nqCACISD+AFQCeBfB+EflrAL8D4CIALyL6DbIA8L3Yv4di/QHgWgD3q+pZAFDVUyJyKaIF6YexDxplAFJ+Lw2R31gUiKIv6L1JHpuN+30eQLmIVAH4F0TvmDcsIl9C9AvevOvM4/xzTJD4lcUC4EVV7cohd6K84ukjoujNaipF5E/PNYjIexH97nyTcwXgpIgsQvKCEm8vgD8TkfJY/IsQ/eruBhHpirUFReQ/ZzkGorxgUaB3vNi3dX4YwAdjf5L6IqJ3CjN+77yqTiJ6L4ljiH4d9/MWm/kGol8ffVREjgD4r7HbP/YCuCvW1g/gqhyHQ5QTfksqERE5+EmBiIgcLApERORgUSAiIgeLAhEROVgUiIjIwaJAREQOFgUiInKwKBARkeP/AyyhiMGsMMqaAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "for i in range(1,7):\n", + " df.plot(kind='scatter', x='chance', y=df.columns[i]) \n", + " plt.xlabel(\"Chance\")\n", + " plt.ylabel(df.columns[i])\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Pandas/Pandas.pptx b/Pandas/Pandas.pptx new file mode 100644 index 00000000..0812a218 Binary files /dev/null and b/Pandas/Pandas.pptx differ diff --git a/Pandas/Python Pandas Input-Output.ipynb b/Pandas/Python Pandas Input-Output.ipynb new file mode 100644 index 00000000..4fc3f862 --- /dev/null +++ b/Pandas/Python Pandas Input-Output.ipynb @@ -0,0 +1,762 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python Pandas I/O\n", + "### Creating DataFrames, Reading and Writing to CSV & JSON files \n", + "[Documentation](https://pandas.pydata.org/docs/index.html)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import random" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Creating DataFrames from Lists and Dicts\n", + "▶ New DataFrame from a **List** \n", + "Pandas automatically assigns numerical row indexes." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
0
00.027684
10.174996
20.743153
30.628041
40.658552
\n", + "
" + ], + "text/plain": [ + " 0\n", + "0 0.027684\n", + "1 0.174996\n", + "2 0.743153\n", + "3 0.628041\n", + "4 0.658552" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data1 = [random.random() for i in range(10000)]\n", + "df = pd.DataFrame(data1)\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "▶ New DataFrame from a **2D List** \n", + "Column names default to integers. Each subList is a row." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
01
0A28
1B78
2C85
3D65
4E98
\n", + "
" + ], + "text/plain": [ + " 0 1\n", + "0 A 28\n", + "1 B 78\n", + "2 C 85\n", + "3 D 65\n", + "4 E 98" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data2 = [[i, random.randint(10,99)] for i in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ']\n", + "df = pd.DataFrame(data2)\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "▶ New DataFrame from a **Dictionary** \n", + "Dict Keys become column names" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ModelPriceSize
0T571.4257 inches
1T611.4861 inches
2T641.7364 inches
3T651.9565 inches
\n", + "
" + ], + "text/plain": [ + " Model Price Size\n", + "0 T57 1.42 57 inches\n", + "1 T61 1.48 61 inches\n", + "2 T64 1.73 64 inches\n", + "3 T65 1.95 65 inches" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data3 = {\n", + " 'Model':['T57','T61','T64','T65'],\n", + " 'Price':[1.42,1.48,1.73,1.95],\n", + " 'Size':['57 inches','61 inches','64 inches','65 inches']}\n", + "df = pd.DataFrame(data3)\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Change previous example to use Model number as index. " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
PriceSize
T571.4257 inches
T611.4861 inches
T641.7364 inches
T651.9565 inches
\n", + "
" + ], + "text/plain": [ + " Price Size\n", + "T57 1.42 57 inches\n", + "T61 1.48 61 inches\n", + "T64 1.73 64 inches\n", + "T65 1.95 65 inches" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.DataFrame(\n", + " {'Price':data3['Price'],'Size':data3['Size']}, \n", + " index=data3['Model'])\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "▶ New DataFrame from a List of Dictionaries \n", + "Note, missing Length is populated with NaN (not a number)." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
HtLenWt
06345.02.6
129NaN1.7
23771.04.2
\n", + "
" + ], + "text/plain": [ + " Ht Len Wt\n", + "0 63 45.0 2.6\n", + "1 29 NaN 1.7\n", + "2 37 71.0 4.2" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data4 = [\n", + " {'Ht':63, 'Len':45, 'Wt':2.6}, \n", + " {'Ht':29, 'Wt':1.7},\n", + " {'Ht':37, 'Len':71, 'Wt':4.2}]\n", + "df = pd.DataFrame(data4)\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Reading & Writing DataFrames to CSV Files\n", + "[Documentation](https://pandas.pydata.org/docs/user_guide/io.html#csv-text-files) of numerous optional parameters. \n", + "\n", + "▶ Write DataFrame to CSV file " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.DataFrame(data4)\n", + "df.to_csv('outfile.csv', index=False) #, sep=';')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "▶ Read CSV file into DataFrame \n", + "Missing numerical data are given value NaN by default." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
HtLenWt
06345.02.6
129NaN1.7
23771.04.2
\n", + "
" + ], + "text/plain": [ + " Ht Len Wt\n", + "0 63 45.0 2.6\n", + "1 29 NaN 1.7\n", + "2 37 71.0 4.2" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.read_csv('outfile.csv')\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "▶ Convert DataFrame to_string" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "' Ht Len Wt\\n0 63 45.0 2.6\\n1 29 NaN 1.7\\n2 37 71.0 4.2'" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.DataFrame(data4)\n", + "d4str = df.to_string()\n", + "d4str" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Reading & Writing DataFrames to JSON files\n", + "[Documentation](https://pandas.pydata.org/docs/user_guide/io.html#csv-text-files) of numerous optional parameters. \n", + "\n", + "▶ Convert DataFrame to **JSON** string \n", + "No argument - json by columns is default, {column -> {index -> value}}" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'{\"Ht\":{\"0\":63,\"1\":29,\"2\":37},\"Len\":{\"0\":45.0,\"1\":null,\"2\":71.0},\"Wt\":{\"0\":2.6,\"1\":1.7,\"2\":4.2}}'" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data4_json = df.to_json()\n", + "data4_json" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Use orient='index' to structure the json by rows, {index -> {column -> value}}. \n", + "You can also strip out the row indices by using orient='records'." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'{\"0\":{\"Ht\":63,\"Len\":45.0,\"Wt\":2.6},\"1\":{\"Ht\":29,\"Len\":null,\"Wt\":1.7},\"2\":{\"Ht\":37,\"Len\":71.0,\"Wt\":4.2}}'" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data4_json = df.to_json(orient='index')\n", + "data4_json" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "▶ Write to a text file in JSON format." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "data4_json = df.to_json('outjson.txt')\n", + "data4_json" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "▶ Read same JSON data back in to a DataFrame." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
HtLenWt
06345.02.6
129NaN1.7
23771.04.2
\n", + "
" + ], + "text/plain": [ + " Ht Len Wt\n", + "0 63 45.0 2.6\n", + "1 29 NaN 1.7\n", + "2 37 71.0 4.2" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data4 = pd.read_json('outjson.txt')\n", + "data4" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Pandas/Python Pandas Time Series Data.ipynb b/Pandas/Python Pandas Time Series Data.ipynb new file mode 100644 index 00000000..3db1b4b4 --- /dev/null +++ b/Pandas/Python Pandas Time Series Data.ipynb @@ -0,0 +1,856 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python Pandas Time Series Data\n", + "[Documentation](https://pandas.pydata.org/docs/user_guide/timeseries.html)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import datetime\n", + "import random" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Data Formats Supported\n", + "Pandas datetime64 can interpret strings, Python datetime, and Numpy datetime64 objects. \n", + "Also note, a list of pd.datetime64 objects are automatically converted to a DatetimeIndex." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "DatetimeIndex(['2020-06-01', '2020-06-02', '2020-06-03', '2020-06-04',\n", + " '2020-06-05'],\n", + " dtype='datetime64[ns]', freq=None)" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a1 = pd.to_datetime([\n", + " '6/1/2020', \n", + " '6-2-2020',\n", + " datetime.datetime(2020, 6, 3),\n", + " np.datetime64('2020-06-04'),\n", + " np.datetime64('2020-06-05')])\n", + "a1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Pass in a format argument for custom formatted dates (case matters)." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "DatetimeIndex(['2020-06-14', '2020-06-15'], dtype='datetime64[ns]', freq=None)" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a2 = pd.to_datetime(['2020/14/06', '2020/15/06'], format='%Y/%d/%m')\n", + "a2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Hours and Minutes too? No problem." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "DatetimeIndex(['2020-08-06 14:05:00', '2020-09-06 06:45:00'], dtype='datetime64[ns]', freq=None)" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a3 = pd.to_datetime(\n", + " ['2020/6/8 14.05', '2020/6/9 06.45'], format='%Y/%d/%m %H.%M')\n", + "a3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Creating a datetime sequence with fixed intervals\n", + "freq parameters: \n", + " D=days, W=weeks, M=months, B=business days, BW=bus weeks, BM=bus months" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "DatetimeIndex(['2020-06-01', '2020-06-02', '2020-06-03', '2020-06-04',\n", + " '2020-06-05', '2020-06-06', '2020-06-07', '2020-06-08',\n", + " '2020-06-09', '2020-06-10', '2020-06-11', '2020-06-12',\n", + " '2020-06-13', '2020-06-14', '2020-06-15', '2020-06-16',\n", + " '2020-06-17', '2020-06-18', '2020-06-19', '2020-06-20',\n", + " '2020-06-21', '2020-06-22', '2020-06-23', '2020-06-24',\n", + " '2020-06-25', '2020-06-26', '2020-06-27', '2020-06-28',\n", + " '2020-06-29', '2020-06-30'],\n", + " dtype='datetime64[ns]', freq='D')\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
M
2020-06-070.970080
2020-06-140.809867
2020-06-180.917428
2020-06-200.945739
2020-06-260.815245
\n", + "
" + ], + "text/plain": [ + " M\n", + "2020-06-07 0.970080\n", + "2020-06-14 0.809867\n", + "2020-06-18 0.917428\n", + "2020-06-20 0.945739\n", + "2020-06-26 0.815245" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b1 = [random.random() for i in range(30)]\n", + "b2 = pd.date_range('2020-06-01', periods=30, freq='1d')\n", + "print(b2)\n", + "df = pd.DataFrame({'M':b1}, index=b2)\n", + "#df.loc['2020-06-18':]\n", + "df[df['M'] > 0.8]" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
0
2020-07-120.581691
2020-07-190.611492
2020-07-260.933940
\n", + "
" + ], + "text/plain": [ + " 0\n", + "2020-07-12 0.581691\n", + "2020-07-19 0.611492\n", + "2020-07-26 0.933940" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b3 = np.random.rand(52)\n", + "b4 = pd.date_range('2020-06-01', periods=52, freq='W')\n", + "df = pd.DataFrame(b3, index=b4)\n", + "df['2020-07-10':'2020-07-28']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Alternative to periods, you can give start and stop dates." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "DatetimeIndex(['2020-06-30', '2020-07-31', '2020-08-31', '2020-09-30',\n", + " '2020-10-31', '2020-11-30', '2020-12-31'],\n", + " dtype='datetime64[ns]', freq='M')" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b3 = pd.date_range('2020-06-30', '2020-12-31', freq='M')\n", + "b3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Dates Index to/from CSV file\n", + "Create DataFrame with Dates as Index, Write it to a CSV file, then Read in the CSV data and put the dates as Index" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
alphabeta
2020-05-2910.4026
2020-05-308.9226
2020-05-315.0912
2020-06-013.8727
2020-06-023.9324
2020-06-034.7916
2020-06-049.1216
\n", + "
" + ], + "text/plain": [ + " alpha beta\n", + "2020-05-29 10.40 26\n", + "2020-05-30 8.92 26\n", + "2020-05-31 5.09 12\n", + "2020-06-01 3.87 27\n", + "2020-06-02 3.93 24\n", + "2020-06-03 4.79 16\n", + "2020-06-04 9.12 16" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "d1 = np.round(6 + 4 * np.random.randn(7), decimals=2)\n", + "d2 = np.random.randint(12, 30, size=7)\n", + "d3 = pd.Series(pd.date_range('2020-05-29', periods=7, freq='1d'))\n", + "df = pd.DataFrame({'alpha':d1, 'beta':d2}, index=d3)\n", + "\n", + "df.to_csv('file01.csv')\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
alphabeta
2020-05-2910.4026
2020-05-308.9226
2020-05-315.0912
\n", + "
" + ], + "text/plain": [ + " alpha beta\n", + "2020-05-29 10.40 26\n", + "2020-05-30 8.92 26\n", + "2020-05-31 5.09 12" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.read_csv('file01.csv', index_col=0)\n", + "print(type(df.index[2]))\n", + "df.index = pd.to_datetime(df.index, format='%Y/%m/%d')\n", + "print(type(df.index[2]))\n", + "df[:'2020/05/31']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Constructing Dates from Multiple Columns\n", + "You have Month, Day and Year in separate fields, and need to combine them into a single Datetime field." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2017 12 7 0.970109923902562\n" + ] + } + ], + "source": [ + "yyyy = [random.randint(1995,2020) for i in range(100)]\n", + "mm = [random.randint(1,12) for i in range(100)]\n", + "dd = [random.randint(1,28) for i in range(100)]\n", + "data = [random.random() for i in range(100)]\n", + "print(yyyy[5], mm[5], dd[5], data[5])" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
01
02016-10-180.282307
12007-09-090.004984
22016-12-120.652762
32017-04-140.199284
42013-03-230.163154
\n", + "
" + ], + "text/plain": [ + " 0 1\n", + "0 2016-10-18 0.282307\n", + "1 2007-09-09 0.004984\n", + "2 2016-12-12 0.652762\n", + "3 2017-04-14 0.199284\n", + "4 2013-03-23 0.163154" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df1 = pd.DataFrame({'year': yyyy,'month': mm, 'day': dd})\n", + "df1 = pd.to_datetime(df1) \n", + "df2 = pd.Series(data)\n", + "df = pd.concat([df1, df2], axis=1)\n", + "df[:5]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Pivot (Transpose) Rows & Columns\n", + "You normally want dates as the row index, not the column headers. \n", + "Flip the rows and columns using T." + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
0
2016-10-18 00:00:000.282307
2007-09-09 00:00:000.004984
2016-12-12 00:00:000.652762
2017-04-14 00:00:000.199284
2013-03-23 00:00:000.163154
\n", + "
" + ], + "text/plain": [ + " 0\n", + "2016-10-18 00:00:00 0.282307\n", + "2007-09-09 00:00:00 0.004984\n", + "2016-12-12 00:00:00 0.652762\n", + "2017-04-14 00:00:00 0.199284\n", + "2013-03-23 00:00:00 0.163154" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.read_csv('pivot.csv')\n", + "df = df.T\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Date Arithmetic" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Thursday'" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "appointment = pd.Timestamp('2020-06-04')\n", + "appointment.day_name()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Uh oh! my appointment is delayed 2 days. \n", + "Here are 3 different ways to add 2 days to the date." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Saturday'" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "appointment = pd.Timestamp('2020-06-04')\n", + "appointment += pd.Timedelta('2 days')\n", + "appointment.day_name()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Saturday'" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "appointment = pd.Timestamp('2020-06-04')\n", + "appointment += pd.Timedelta(days=2)\n", + "appointment.day_name()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Date offsets: Day, Hour, Minute, Second, Milli, Micro, Nano " + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Saturday'" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "appointment = pd.Timestamp('2020-06-04')\n", + "appointment += pd.offsets.Day(2)\n", + "appointment.day_name()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "NO, it's delayed 2 business days. " + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Monday'" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "appointment = pd.Timestamp('2020-06-04')\n", + "appointment += pd.offsets.BDay(2)\n", + "appointment.day_name()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Pandas/file01.csv b/Pandas/file01.csv new file mode 100644 index 00000000..229e74ef --- /dev/null +++ b/Pandas/file01.csv @@ -0,0 +1,8 @@ +,alpha,beta +2020-05-29,8.78,24 +2020-05-30,13.0,25 +2020-05-31,0.44,25 +2020-06-01,1.94,28 +2020-06-02,5.4,20 +2020-06-03,5.68,21 +2020-06-04,2.64,16 diff --git a/Pandas/iris.data b/Pandas/iris.data new file mode 100644 index 00000000..5c4316cd --- /dev/null +++ b/Pandas/iris.data @@ -0,0 +1,151 @@ +5.1,3.5,1.4,0.2,Iris-setosa +4.9,3.0,1.4,0.2,Iris-setosa +4.7,3.2,1.3,0.2,Iris-setosa +4.6,3.1,1.5,0.2,Iris-setosa +5.0,3.6,1.4,0.2,Iris-setosa +5.4,3.9,1.7,0.4,Iris-setosa +4.6,3.4,1.4,0.3,Iris-setosa +5.0,3.4,1.5,0.2,Iris-setosa +4.4,2.9,1.4,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +5.4,3.7,1.5,0.2,Iris-setosa +4.8,3.4,1.6,0.2,Iris-setosa +4.8,3.0,1.4,0.1,Iris-setosa +4.3,3.0,1.1,0.1,Iris-setosa +5.8,4.0,1.2,0.2,Iris-setosa +5.7,4.4,1.5,0.4,Iris-setosa +5.4,3.9,1.3,0.4,Iris-setosa +5.1,3.5,1.4,0.3,Iris-setosa +5.7,3.8,1.7,0.3,Iris-setosa +5.1,3.8,1.5,0.3,Iris-setosa +5.4,3.4,1.7,0.2,Iris-setosa +5.1,3.7,1.5,0.4,Iris-setosa +4.6,3.6,1.0,0.2,Iris-setosa +5.1,3.3,1.7,0.5,Iris-setosa +4.8,3.4,1.9,0.2,Iris-setosa +5.0,3.0,1.6,0.2,Iris-setosa +5.0,3.4,1.6,0.4,Iris-setosa +5.2,3.5,1.5,0.2,Iris-setosa +5.2,3.4,1.4,0.2,Iris-setosa +4.7,3.2,1.6,0.2,Iris-setosa +4.8,3.1,1.6,0.2,Iris-setosa +5.4,3.4,1.5,0.4,Iris-setosa +5.2,4.1,1.5,0.1,Iris-setosa +5.5,4.2,1.4,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +5.0,3.2,1.2,0.2,Iris-setosa +5.5,3.5,1.3,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +4.4,3.0,1.3,0.2,Iris-setosa +5.1,3.4,1.5,0.2,Iris-setosa +5.0,3.5,1.3,0.3,Iris-setosa +4.5,2.3,1.3,0.3,Iris-setosa +4.4,3.2,1.3,0.2,Iris-setosa +5.0,3.5,1.6,0.6,Iris-setosa +5.1,3.8,1.9,0.4,Iris-setosa +4.8,3.0,1.4,0.3,Iris-setosa +5.1,3.8,1.6,0.2,Iris-setosa +4.6,3.2,1.4,0.2,Iris-setosa +5.3,3.7,1.5,0.2,Iris-setosa +5.0,3.3,1.4,0.2,Iris-setosa +7.0,3.2,4.7,1.4,Iris-versicolor +6.4,3.2,4.5,1.5,Iris-versicolor +6.9,3.1,4.9,1.5,Iris-versicolor +5.5,2.3,4.0,1.3,Iris-versicolor +6.5,2.8,4.6,1.5,Iris-versicolor +5.7,2.8,4.5,1.3,Iris-versicolor +6.3,3.3,4.7,1.6,Iris-versicolor +4.9,2.4,3.3,1.0,Iris-versicolor +6.6,2.9,4.6,1.3,Iris-versicolor +5.2,2.7,3.9,1.4,Iris-versicolor +5.0,2.0,3.5,1.0,Iris-versicolor +5.9,3.0,4.2,1.5,Iris-versicolor +6.0,2.2,4.0,1.0,Iris-versicolor +6.1,2.9,4.7,1.4,Iris-versicolor +5.6,2.9,3.6,1.3,Iris-versicolor +6.7,3.1,4.4,1.4,Iris-versicolor +5.6,3.0,4.5,1.5,Iris-versicolor +5.8,2.7,4.1,1.0,Iris-versicolor +6.2,2.2,4.5,1.5,Iris-versicolor +5.6,2.5,3.9,1.1,Iris-versicolor +5.9,3.2,4.8,1.8,Iris-versicolor +6.1,2.8,4.0,1.3,Iris-versicolor +6.3,2.5,4.9,1.5,Iris-versicolor +6.1,2.8,4.7,1.2,Iris-versicolor +6.4,2.9,4.3,1.3,Iris-versicolor +6.6,3.0,4.4,1.4,Iris-versicolor +6.8,2.8,4.8,1.4,Iris-versicolor +6.7,3.0,5.0,1.7,Iris-versicolor +6.0,2.9,4.5,1.5,Iris-versicolor +5.7,2.6,3.5,1.0,Iris-versicolor +5.5,2.4,3.8,1.1,Iris-versicolor +5.5,2.4,3.7,1.0,Iris-versicolor +5.8,2.7,3.9,1.2,Iris-versicolor +6.0,2.7,5.1,1.6,Iris-versicolor +5.4,3.0,4.5,1.5,Iris-versicolor +6.0,3.4,4.5,1.6,Iris-versicolor +6.7,3.1,4.7,1.5,Iris-versicolor +6.3,2.3,4.4,1.3,Iris-versicolor +5.6,3.0,4.1,1.3,Iris-versicolor +5.5,2.5,4.0,1.3,Iris-versicolor +5.5,2.6,4.4,1.2,Iris-versicolor +6.1,3.0,4.6,1.4,Iris-versicolor +5.8,2.6,4.0,1.2,Iris-versicolor +5.0,2.3,3.3,1.0,Iris-versicolor +5.6,2.7,4.2,1.3,Iris-versicolor +5.7,3.0,4.2,1.2,Iris-versicolor +5.7,2.9,4.2,1.3,Iris-versicolor +6.2,2.9,4.3,1.3,Iris-versicolor +5.1,2.5,3.0,1.1,Iris-versicolor +5.7,2.8,4.1,1.3,Iris-versicolor +6.3,3.3,6.0,2.5,Iris-virginica +5.8,2.7,5.1,1.9,Iris-virginica +7.1,3.0,5.9,2.1,Iris-virginica +6.3,2.9,5.6,1.8,Iris-virginica +6.5,3.0,5.8,2.2,Iris-virginica +7.6,3.0,6.6,2.1,Iris-virginica +4.9,2.5,4.5,1.7,Iris-virginica +7.3,2.9,6.3,1.8,Iris-virginica +6.7,2.5,5.8,1.8,Iris-virginica +7.2,3.6,6.1,2.5,Iris-virginica +6.5,3.2,5.1,2.0,Iris-virginica +6.4,2.7,5.3,1.9,Iris-virginica +6.8,3.0,5.5,2.1,Iris-virginica +5.7,2.5,5.0,2.0,Iris-virginica +5.8,2.8,5.1,2.4,Iris-virginica +6.4,3.2,5.3,2.3,Iris-virginica +6.5,3.0,5.5,1.8,Iris-virginica +7.7,3.8,6.7,2.2,Iris-virginica +7.7,2.6,6.9,2.3,Iris-virginica +6.0,2.2,5.0,1.5,Iris-virginica +6.9,3.2,5.7,2.3,Iris-virginica +5.6,2.8,4.9,2.0,Iris-virginica +7.7,2.8,6.7,2.0,Iris-virginica +6.3,2.7,4.9,1.8,Iris-virginica +6.7,3.3,5.7,2.1,Iris-virginica +7.2,3.2,6.0,1.8,Iris-virginica +6.2,2.8,4.8,1.8,Iris-virginica +6.1,3.0,4.9,1.8,Iris-virginica +6.4,2.8,5.6,2.1,Iris-virginica +7.2,3.0,5.8,1.6,Iris-virginica +7.4,2.8,6.1,1.9,Iris-virginica +7.9,3.8,6.4,2.0,Iris-virginica +6.4,2.8,5.6,2.2,Iris-virginica +6.3,2.8,5.1,1.5,Iris-virginica +6.1,2.6,5.6,1.4,Iris-virginica +7.7,3.0,6.1,2.3,Iris-virginica +6.3,3.4,5.6,2.4,Iris-virginica +6.4,3.1,5.5,1.8,Iris-virginica +6.0,3.0,4.8,1.8,Iris-virginica +6.9,3.1,5.4,2.1,Iris-virginica +6.7,3.1,5.6,2.4,Iris-virginica +6.9,3.1,5.1,2.3,Iris-virginica +5.8,2.7,5.1,1.9,Iris-virginica +6.8,3.2,5.9,2.3,Iris-virginica +6.7,3.3,5.7,2.5,Iris-virginica +6.7,3.0,5.2,2.3,Iris-virginica +6.3,2.5,5.0,1.9,Iris-virginica +6.5,3.0,5.2,2.0,Iris-virginica +6.2,3.4,5.4,2.3,Iris-virginica +5.9,3.0,5.1,1.8,Iris-virginica + diff --git a/Pandas/outfile.csv b/Pandas/outfile.csv new file mode 100644 index 00000000..ba5d7289 --- /dev/null +++ b/Pandas/outfile.csv @@ -0,0 +1,4 @@ +Ht,Len,Wt +63,45.0,2.6 +29,,1.7 +37,71.0,4.2 diff --git a/Pandas/outjson.txt b/Pandas/outjson.txt new file mode 100644 index 00000000..0967acb0 --- /dev/null +++ b/Pandas/outjson.txt @@ -0,0 +1 @@ +{"0":{"Ht":63,"Len":45.0,"Wt":2.6},"1":{"Ht":29,"Len":null,"Wt":1.7},"2":{"Ht":37,"Len":71.0,"Wt":4.2}} \ No newline at end of file diff --git a/Pandas/pandas_weather.py b/Pandas/pandas_weather.py new file mode 100644 index 00000000..39c4f2c4 --- /dev/null +++ b/Pandas/pandas_weather.py @@ -0,0 +1,123 @@ +import numpy as np +import pandas as pd + +def header(msg): + print('-' * 50) + print('[ ' + msg + ' ]') + +# 1. load hard-coded data into a dataframe +header("1. load hard-coded data into a df") +df = pd.DataFrame( + [['Jan',58,42,74,22,2.95], + ['Feb',61,45,78,26,3.02], + ['Mar',65,48,84,25,2.34], + ['Apr',67,50,92,28,1.02], + ['May',71,53,98,35,0.48], + ['Jun',75,56,107,41,0.11], + ['Jul',77,58,105,44,0.0], + ['Aug',77,59,102,43,0.03], + ['Sep',77,57,103,40,0.17], + ['Oct',73,54,96,34,0.81], + ['Nov',64,48,84,30,1.7], + ['Dec',58,42,73,21,2.56]], + index = [0,1,2,3,4,5,6,7,8,9,10,11], + columns = ['month','avg_high','avg_low','record_high','record_low','avg_precipitation']) +print(df) + +# 2. read text file into a dataframe +header("2. read text file into a df") +filename = 'Fremont_weather.txt' +df = pd.read_csv(filename) +print(df) + +# 3. print first 5 or last 3 rows of df +header("3. df.head()") +print(df.head()) +header("3. df.tail(3)") +print(df.tail(3)) + +# 4. get data types, index, columns, values +header("4. df.dtypes") +print(df.dtypes) + +header("4. df.index") +print(df.index) + +header("4. df.columns") +print(df.columns) + +header("4. df.values") +print(df.values) + +# 5. statistical summary of each column +header("5. df.describe()") +print(df.describe()) + +# 6. sort records by any column +header("6. df.sort_values('record_high', ascending=False)") +print (df.sort_values('record_high', ascending=False)) + +# 7. slicing records +header("7. slicing -- df.avg_low") +print(df.avg_low) # index with single column + +header("7. slicing -- df['avg_low']") +print(df['avg_low']) + +header("7. slicing -- df[2:4]") # index with single column +print(df[2:4]) # rows 2 to 3 + +header("7. slicing -- df[['avg_low','avg_high']]") +print(df[['avg_low','avg_high']]) + +header("7. slicing -- df.loc[:,['avg_low','avg_high']]") +print(df.loc[:,['avg_low','avg_high']]) # multiple columns: df.loc[from_row:to_row,['column1','column2']] + +header("7. slicing scalar value -- df.loc[9,['avg_precipitation']]") +print(df.loc[9,['avg_precipitation']]) + +header("7. df.iloc[3:5,[0,3]]") # index location can receive range or list of indices +print(df.iloc[3:5,[0,3]]) + +# 8. filtering +header("8. df[df.avg_precipitation > 1.0]") # filter on column values +print(df[df.avg_precipitation > 1.0]) + +header("8. df[df['month'].isin['Jun','Jul','Aug']]") +print(df[df['month'].isin(['Jun','Jul','Aug'])]) + +# 9. assignment -- very similar to slicing +header("9. df.loc[9,['avg_precipitation']] = 101.3") +df.loc[9,['avg_precipitation']] = 101.3 +print(df.iloc[9:11]) + +header("9. df.loc[9,['avg_precipitation']] = np.nan") +df.loc[9,['avg_precipitation']] = np.nan +print(df.iloc[9:11]) + +header("9. df.loc[:,'avg_low'] = np.array([5] * len(df))") +df.loc[:,'avg_low'] = np.array([5] * len(df)) +print(df.head()) + +header("9. df['avg_day'] = (df.avg_low + df.avg_high) / 2") +df['avg_day'] = (df.avg_low + df.avg_high) / 2 +print(df.head()) + +# 10. renaming columns +header("10. df.rename(columns = {'avg_precipitation':'avg_rain'}, inplace=True)") +df.rename(columns = {'avg_precipitation':'avg_rain'}, inplace=True) # rename 1 column +print(df.head()) + +header("10. df.columns = ['month','av_hi','av_lo','rec_hi','rec_lo','av_rain','av_day']") +df.columns = ['month','av_hi','av_lo','rec_hi','rec_lo','av_rain','av_day'] +print(df.head()) + +# 11. iterate a df +header("11. iterate rows of df with a for loop") +for index, row in df.iterrows(): + print (index, row["month"], row["avg_high"]) + +# 12. write to csv file +df.to_csv('foo.csv') + + diff --git a/Pandas/pivot.csv b/Pandas/pivot.csv new file mode 100644 index 00000000..0c603dc6 --- /dev/null +++ b/Pandas/pivot.csv @@ -0,0 +1,2 @@ +2016-10-18 00:00:00,2007-09-09 00:00:00,2016-12-12 00:00:00,2017-04-14 00:00:00,2013-03-23 00:00:00,2017-12-07 00:00:00,2008-06-05 00:00:00,2004-12-06 00:00:00,1995-11-05 00:00:00,1996-09-12 00:00:00,2001-05-23 00:00:00,1997-07-08 00:00:00,1995-05-01 00:00:00,2008-11-06 00:00:00,2020-12-07 00:00:00,1998-02-03 00:00:00,1996-12-20 00:00:00,1998-04-25 00:00:00,2019-03-09 00:00:00,2019-08-25 00:00:00,2015-12-01 00:00:00,2004-04-08 00:00:00,2015-04-19 00:00:00,2013-12-23 00:00:00,2008-07-17 00:00:00,2016-02-16 00:00:00,2004-05-08 00:00:00,2000-10-26 00:00:00,1999-04-27 00:00:00,2014-06-23 00:00:00,2014-04-02 00:00:00,1999-06-05 00:00:00,1998-10-20 00:00:00,2013-01-24 00:00:00,2006-07-27 00:00:00,2002-08-20 00:00:00,2013-11-07 00:00:00,2006-07-01 00:00:00,2004-11-23 00:00:00,2008-09-07 00:00:00,1996-08-19 00:00:00,2016-01-27 00:00:00,2002-09-26 00:00:00,1996-09-09 00:00:00,1998-10-09 00:00:00,2000-07-19 00:00:00,2008-11-19 00:00:00,2014-03-11 00:00:00,1996-07-15 00:00:00,2000-02-05 00:00:00,1998-06-24 00:00:00,1998-01-23 00:00:00,1998-05-06 00:00:00,2003-08-05 00:00:00,2013-08-02 00:00:00,1996-03-07 00:00:00,1995-03-25 00:00:00,2012-10-06 00:00:00,2004-07-27 00:00:00,1999-08-05 00:00:00,2009-06-04 00:00:00,2007-07-27 00:00:00,2002-07-03 00:00:00,2011-06-07 00:00:00,2012-08-19 00:00:00,2018-03-22 00:00:00,1996-09-02 00:00:00,2008-09-02 00:00:00,2006-09-14 00:00:00,2007-07-11 00:00:00,2009-07-16 00:00:00,2016-06-24 00:00:00,2008-10-07 00:00:00,1997-06-13 00:00:00,2017-02-17 00:00:00,2009-05-09 00:00:00,1995-12-28 00:00:00,2014-05-25 00:00:00,1996-03-24 00:00:00,1996-11-12 00:00:00,2011-07-12 00:00:00,2009-11-24 00:00:00,2003-02-05 00:00:00,2010-07-06 00:00:00,1996-12-13 00:00:00,2014-10-11 00:00:00,2008-03-26 00:00:00,2019-07-07 00:00:00,2015-12-13 00:00:00,1997-08-21 00:00:00,2016-10-05 00:00:00,2016-10-08 00:00:00,2005-03-27 00:00:00,2011-03-08 00:00:00,2015-03-14 00:00:00,2001-10-11 00:00:00,1996-07-03 00:00:00,2006-10-22 00:00:00,2004-03-22 00:00:00,1998-12-07 00:00:00 +0.2823066951673592,0.004983503360937558,0.6527617484109105,0.19928401502972315,0.16315370812362973,0.970109923902562,0.28902358319246113,0.3869769040495181,0.036043163595530725,0.8466446865018183,0.3029305402508473,0.9333588096128297,0.1519465926874476,0.9927748105073949,0.4651284520015794,0.14707391568333994,0.08982833065821505,0.5883453931565746,0.3494752580177175,0.10167526699057972,0.07941368601234156,0.9358293552727159,0.10740538848773118,0.4506715669567083,0.8387140420947164,0.5746907600075374,0.758976559783973,0.3110498538520595,0.9993881318470451,0.26265671090461906,0.6470895524293089,0.49971727121051435,0.8195258715074762,0.3630891873905159,0.11926782337362651,0.555536083920244,0.8190498637543558,0.40175480684114895,0.7158884358768607,0.3076511179082977,0.06309063694263983,0.5979927629277495,0.7614082398079934,0.34115186547855936,0.5709798851222291,0.9855403495879589,0.7253074001190444,0.4685492447308346,0.03796109649032342,0.16599775387020776,0.7730834960205076,0.04807532952934723,0.9967131145813193,0.7619403019670993,0.4326634641827285,0.43819600412852544,0.8915384234633204,0.7388190145903542,0.1504441063873443,0.11645793742178479,0.8849805306825719,0.8209440808963199,0.03756126787686931,0.2921962688201817,0.637006806437786,0.21496659424673736,0.0673283796900469,0.2679415763216668,0.845924613974428,0.35520559789032924,0.9358371834432343,0.12177533426329734,0.7385219285657647,0.09006868872192064,0.21716948989174056,0.212482450203213,0.26463884587482933,0.4639594087198322,0.473534405458537,0.31034018086435244,0.4868968278642336,0.7276362315420386,0.5856335537301501,0.3848357918705628,0.5045424488044008,0.3669372132755703,0.5223717711718852,0.07330274927032765,0.12129741612938838,0.4463446916302444,0.06560636427124344,0.5628053006445556,0.6800242556861632,0.13053686078804783,0.9666542996125932,0.21805040691134103,0.920335829229451,0.5715463228495896,0.2984664705574499,0.28766845010273867 diff --git a/Primes.py b/Primes.py index 196644d3..3bbf14eb 100644 --- a/Primes.py +++ b/Primes.py @@ -2,7 +2,7 @@ max = int(input("Find primes up to what number? : ")) primeList = [] - +#for loop for checking each number for x in range(2, max + 1): isPrime = True index = 0 @@ -43,4 +43,4 @@ x += 1 -print(primeList) \ No newline at end of file +print(primeList) diff --git a/Python Bisect.ipynb b/Python Bisect.ipynb new file mode 100644 index 00000000..1390432d --- /dev/null +++ b/Python Bisect.ipynb @@ -0,0 +1,267 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python Bisect Module\n", + "Used to find the insertion point for adding an item to a sorted list. \n", + "Advantage: it's fast. Runs in O(log n). \n", + "[Documentation](https://docs.python.org/3/library/bisect.html)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import bisect" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### bisect_left\n", + "Finds the insertion point for an item in a sorted list, or the spot just left of any matches. \n", + "Works for list of ints, list of floats, list of strings." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n", + "3\n", + "2\n" + ] + } + ], + "source": [ + "a = [24, 33, 41, 41, 45, 50, 53, 59, 62, 66, 70]\n", + "i = bisect.bisect_left(a, 41)\n", + "print(i)\n", + "\n", + "b = [1.3, 2.2, 3.4, 4.6, 5.5, 6.9, 7.2, 8.4]\n", + "j = bisect.bisect_left(b, 4.1)\n", + "print(j)\n", + "\n", + "c = ['aaa', 'bbb', 'ccc', 'ddd']\n", + "k = bisect.bisect_left(c, 'bug')\n", + "print(k)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If list is unsorted, results are unpredictable, but it still tries." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n" + ] + } + ], + "source": [ + "a = [33, 24, 41, 41, 45, 50, 53, 59, 66, 62, 70]\n", + "i = bisect.bisect_left(a, 30)\n", + "print(i)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### insort_left\n", + "This inserts an item into the list in the correct position." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[24, 33, 41, 41, 44, 45, 50, 53, 59, 62, 66, 70]\n" + ] + } + ], + "source": [ + "d = [24, 33, 41, 41, 45, 50, 53, 59, 62, 66, 70]\n", + "bisect.insort_left(d, 44)\n", + "print(d)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### bisect_right\n", + "Just like bisect_left, but for matches it returns the spot just to the right of matches." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4\n", + "2\n", + "3\n" + ] + } + ], + "source": [ + "a = [24, 33, 41, 41, 45, 50, 53, 59, 62, 66, 70]\n", + "i = bisect.bisect_right(a, 41)\n", + "print(i)\n", + "\n", + "b = [1.3, 2.2, 3.4, 4.6, 5.5, 6.9, 7.2, 8.4]\n", + "j = bisect.bisect_right(b, 2.2)\n", + "print(j)\n", + "\n", + "c = ['A', 'big', 'dog', 'runs', 'slowly']\n", + "k = bisect.bisect_right(c, 'dog')\n", + "print(k)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### insort_right\n", + "Just like insort_left, but for matches it inserts to the right of the match." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[24, 33, 41, 41, 45, 46, 50, 53, 59, 62, 66, 70]\n" + ] + } + ], + "source": [ + "d = [24, 33, 41, 41, 45, 50, 53, 59, 62, 66, 70]\n", + "bisect.insort_right(d, 46)\n", + "print(d)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### A fast Find function for a Sorted List\n", + "Find leftmost value greater than x in sorted list a" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n" + ] + } + ], + "source": [ + "def find_next(a, x):\n", + " i = bisect.bisect_right(a, x)\n", + " if i < len(a):\n", + " return a[i]\n", + " return False\n", + "\n", + "print(find_next([10, 15, 20, 25, 30], 33))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### A simple get_grade function\n", + "get_grade uses a list of cutoffs to split grades into 5 ranges, then uses the bisect index to return the corresponding grade. " + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['F', 'A', 'C', 'C', 'B', 'A', 'A']\n" + ] + } + ], + "source": [ + "def get_grade(score, cutoffs=[60, 70, 80, 90], grades='FDCBA'):\n", + " i = bisect.bisect_right(cutoffs, score)\n", + " return grades[i]\n", + "\n", + "grades = [get_grade(score) for score in [52, 99, 77, 70, 89, 90, 100]]\n", + "print(grades)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Python Generators.ipynb b/Python Generators.ipynb new file mode 100644 index 00000000..1a68f384 --- /dev/null +++ b/Python Generators.ipynb @@ -0,0 +1,224 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python Generators\n", + "[documentation](https://docs.python.org/3/howto/functional.html#generators) \n", + "[Another really good tutorial](https://realpython.com/introduction-to-python-generators/#using-generators)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "*yield* keyword makes a function into a generator. Python keeps the call stack for the generator function open and saves the state. When you invoke the next() function it will return execution to the same point it left off in the generator function." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Simple generator function \n", + "The while loop continues indefinitely. The function increments x then returns x with each iteration." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "def my_generator(x=1):\n", + " while True:\n", + " yield x\n", + " x += 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using the generator with a for loop\n", + "Here, gene is a my_generator function. \n", + "The for loop iterates through gene indefinitely. \n", + "Behind the scenes, the for loop is calling the generator's \\__next__ function. \n", + "Big advantages over Lists: \n", + "- Generator can provide an infinite seqence. \n", + "- Generator doesn't load values into memory. " + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 " + ] + }, + { + "ename": "KeyboardInterrupt", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mgene\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mend\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m' '\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msleep\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0.5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mKeyboardInterrupt\u001b[0m: " + ] + } + ], + "source": [ + "import time\n", + "gene = my_generator()\n", + "print(type(gene))\n", + "\n", + "for i in gene:\n", + " print(i, end=' ')\n", + " time.sleep(0.5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using the generator with explicit next( ) calls\n", + "*range* limits this for loop to 10 iterations. \n", + "Each iteration of the for loop it calls the generator using *next(gene)*." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "2 3 4 5 6 7 8 9 10 11 " + ] + } + ], + "source": [ + "gene = my_generator()\n", + "print(gene.__next__())\n", + "for i in range(10):\n", + " print(next(gene), end=' ')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Generators from Generator Expressions\n", + "Similar to List Comprehensions, but uses ( ) rather than [ ]. \n", + "Create with a single line of code. \n", + "Only use 120 bytes of memory." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "120\n", + "\n", + "0\n", + "3\n" + ] + } + ], + "source": [ + "gene = (x for x in range(999999))\n", + "\n", + "import sys\n", + "print(sys.getsizeof(gene))\n", + "print(type(gene))\n", + "\n", + "print(next(gene))\n", + "next(gene)\n", + "next(gene)\n", + "print(next(gene))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Generator to Read File\n", + "Saves memory, and avoids memory overflow for very large files, because it only *loads one line into memory at a time*." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Rolling Stones\n", + "\n", + "Lady Gaga\n", + "Jackson Browne\n", + "Maroon 5\n", + "Arijit Singh\n", + "Elton John\n", + "John Mayer\n" + ] + } + ], + "source": [ + "def read_file(fn = 'bands.txt'):\n", + " for line in open(fn):\n", + " yield line\n", + " \n", + "band = read_file()\n", + "print(next(band))\n", + "for i in range(6):\n", + " print(next(band), end='')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Python List Iteration.ipynb b/Python List Iteration.ipynb new file mode 100644 index 00000000..7361caaf --- /dev/null +++ b/Python List Iteration.ipynb @@ -0,0 +1,197 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python List Iteration\n", + "A variety of ways to iterate Lists, including for loop, while loop, enumerate." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "The standard for loop works well if it is used inside the loop you only need the item and not its index." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a\n", + "b\n", + "c\n", + "d\n", + "e\n" + ] + } + ], + "source": [ + "letters = ['a', 'b', 'c', 'd', 'e']\n", + "\n", + "for letter in letters:\n", + " print(letter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "If you need the index inside the loop you can use range(len(list)). \n", + "Then you can always get the list item if needed by using the index." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "letters 0 = a\n", + "letters 1 = b\n", + "letters 2 = c\n", + "letters 3 = d\n", + "letters 4 = e\n" + ] + } + ], + "source": [ + "for index in range(len(letters)):\n", + " print('letters', index, '=', letters[index])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "Best option if you need both index and item inside the loop is to use Python's **enumerate** function. \n", + "Enumerate works in both Python 2.x and 3.x" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "letters 0 = a\n", + "letters 1 = b\n", + "letters 2 = c\n", + "letters 3 = d\n", + "letters 4 = e\n" + ] + } + ], + "source": [ + "for index, item in enumerate(letters):\n", + " print('letters', index, '=', item)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Enumerate actually returns an iterable enumerate object, \n", + "which is a sequence of tuples of (index, item)." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(0, 'a')\n", + "(1, 'b')\n", + "\n" + ] + } + ], + "source": [ + "enum_obj = enumerate(letters)\n", + "print(next(enum_obj))\n", + "print(next(enum_obj))\n", + "print(type(enum_obj))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "Probably the clumsiest way to iterate a list in Python -- the **while loop**. \n", + "Requires index initialization before list, and incrementation inside loop." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "letters 0 = a\n", + "letters 1 = b\n", + "letters 2 = c\n", + "letters 3 = d\n", + "letters 4 = e\n" + ] + } + ], + "source": [ + "index = 0\n", + "while index < len(letters): \n", + " print('letters', index, '=', letters[index]) \n", + " index += 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Python Random Numbers Module.ipynb b/Python Random Numbers Module.ipynb new file mode 100644 index 00000000..db837a8c --- /dev/null +++ b/Python Random Numbers Module.ipynb @@ -0,0 +1,450 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python Random Numbers Module\n", + "[Official Documentation](https://docs.python.org/3/library/random.html)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import random" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### randint\n", + "Gives you a random integer between from and to values, inclusive." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2 2 3 1 1 2 0 2 3 2 0 0 2 2 0 3 3 2 1 2 3 0 2 2 2 " + ] + } + ], + "source": [ + "for i in range (25):\n", + " print(random.randint(0, 3), end=' ')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### randrange\n", + "Works similar to the range function -- gives you a random number between from and to-1, with optional step. \n", + "From defaults to 0 if only 1 argument is given. \n", + "Step defaults to 1 if only 2 arguments are given." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "25\n", + "3 6 6 6 6 3 3 3 0 0 6 6 3 0 6 0 3 0 6 6 6 6 3 3 6 " + ] + } + ], + "source": [ + "print(random.randrange(100))\n", + "\n", + "for i in range (25):\n", + " print(random.randrange(0, 9, 3), end=' ')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### choice\n", + "Returns one randomly chosen item from a sequence (list, tuple or string). Works for lists/tuples of integers, floats, strings or other objects. " + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "9\n", + "Roby\n", + "Darby\n", + "Washington\n", + "Hampton\n" + ] + } + ], + "source": [ + "print(random.choice([3, 5, 7, 9, 11]))\n", + "\n", + "names = ['Roby', 'Matthews', 'Washington', 'Darby', 'Hampton']\n", + "for i in range(4):\n", + " print(random.choice(names))" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-\n", + "a c e b b a e d c c " + ] + } + ], + "source": [ + "print(random.choice('bunch-of-letters'))\n", + "\n", + "material = 'brocade'\n", + "for i in range(10):\n", + " print(random.choice(material), end=' ')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### choices\n", + "Just like choice, but returns a list of n random choices, with replacement, so each pick is from the full sequence." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[9, 5, 3, 6, 5, 6, 5, 3, 1, 5, 10, 1, 4, 4, 10]\n", + "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n" + ] + } + ], + "source": [ + "numbers = [n+1 for n in range(10)]\n", + "my_picks = random.choices(numbers, k=15)\n", + "print(my_picks)\n", + "print(numbers)" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['Darby', 'Hampton']\n" + ] + } + ], + "source": [ + "names = ['Roby', 'Matthews', 'Washington', 'Darby', 'Hampton']\n", + "print(random.choices(names, k=2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also add weights if you want some items to have a better chance of being picked. Here, 1 is 4x more likely than 4 to be picked." + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2, 1, 3, 4, 1, 1, 1, 3, 2, 2, 2, 4, 2, 1, 1, 3, 2, 3, 1, 3]\n" + ] + } + ], + "source": [ + "numbers = [1,2,3,4]\n", + "my_picks = random.choices(numbers, weights=[4,3,2,1], k=20)\n", + "print(my_picks)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Use random.choices to generate random passwords \n", + "First we pick a list of 8 random numbers between a and z on the ascii table, then we convert the numbers to ascii letters, then join them into a string." + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[100, 109, 104, 100, 103, 102, 118, 121]\n", + "dmhdgfvy\n" + ] + } + ], + "source": [ + "picks = random.choices(range(ord('a'),ord('z')), k=8)\n", + "print(picks)\n", + "picks = [chr(i) for i in picks]\n", + "print(''.join(picks))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here's a random password generator that uses all upper and lower case letters and numbers." + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Z81Hw3uk\n" + ] + } + ], + "source": [ + "import string\n", + "all_chars = string.ascii_lowercase + string.ascii_uppercase + string.digits\n", + "pw = ''.join(random.choices(all_chars, k=8))\n", + "print(pw)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### sample\n", + "Just like choices, but without replacement. \n", + "Useful for picking lottery winners or bingo numbers. \n", + "Returned list is in the order they were picked." + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['green', 'pink']\n" + ] + } + ], + "source": [ + "colors = ['red', 'blue', 'green', 'aqua', 'pink', 'black']\n", + "picks = random.sample(colors, k=2)\n", + "print(picks)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using the range function as an argument will not give you any duplicate picks." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[18, 38, 20, 50, 1]\n" + ] + } + ], + "source": [ + "picks = random.sample(range(1,51), k=5)\n", + "print(picks)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### shuffle\n", + "Shuffle any sequence into random order. \n", + "This is an in-place shuffle, and it doesn't return anything." + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 4, 5, 6, 7, 8]\n", + "None\n", + "[2, 6, 8, 1, 4, 7, 5, 3]\n" + ] + } + ], + "source": [ + "numbers = [1, 2, 3, 4, 5, 6, 7, 8]\n", + "print(numbers)\n", + "print(random.shuffle(numbers))\n", + "\n", + "random.shuffle(numbers)\n", + "print(numbers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### random.random()\n", + "Random floating point values between 0.0 and 1.0." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.8424897774160051\n", + "0.9016594664191279\n", + "0.5162849368345925\n", + "0.021852081927422384\n", + "0.5740618908246983\n", + "0.6539291129848911\n" + ] + } + ], + "source": [ + "print(random.random())\n", + "\n", + "for i in range(5):\n", + " print(random.random())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### uniform (from, to)\n", + "Random float between a range of values" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.5032833557221568\n", + "10.31258224982709\n", + "9.431820659293221\n", + "10.4390639618008\n", + "9.6906814789157\n", + "10.559354593909362\n" + ] + } + ], + "source": [ + "print(random.uniform(2.1, 4.3))\n", + "\n", + "for i in range(5):\n", + " print(random.uniform(9.4, 10.7))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Python Set Comprehensions.ipynb b/Python Set Comprehensions.ipynb new file mode 100644 index 00000000..475521cb --- /dev/null +++ b/Python Set Comprehensions.ipynb @@ -0,0 +1,331 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python Set Comprehensions\n", + "Note that Python sets are not ordered, and duplicates are automatically removed. \n", + "Otherwise, comprehensions work just like with lists. \n", + "General syntax is: new_set = {expression for item in iterable if condition}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Simple Comprehension using Range" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}\n" + ] + } + ], + "source": [ + "ints = {i for i in range(10)}\n", + "print(ints)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Comprehension using Range with a Condition filter\n", + "Only take even values from range" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{0, 2, 4, 6, 8}\n" + ] + } + ], + "source": [ + "evens = {i for i in range(10) if i%2 == 0}\n", + "print(evens)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Apply math function to values in range\n", + "Here, square each value" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{0, 1, 64, 4, 36, 9, 16, 49, 81, 25}\n" + ] + } + ], + "source": [ + "squares = {i*i for i in range(10)}\n", + "print(squares)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that Python eliminates duplicates from sets" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{0, 1, 4, 9, 16, 25}\n" + ] + } + ], + "source": [ + "sqrs = {i*i for i in range(-5, 5)}\n", + "print(sqrs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Set Comprehension on a List" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{4, 9, 169, 49, 121, 25}\n" + ] + } + ], + "source": [ + "primes = [2, 2, 2, 3, 3, 5, 5, 5, 7, 11, 11, 13, 13, 13, 13]\n", + "primes_squared = {p*p for p in primes}\n", + "print(primes_squared)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### More Complex Expressions: quadratic transformation\n", + "Any expression is allowed. More complex expressions can be put in parentheses. \n", + "Here, quadratic equation: \n", + "2x^2 + 5x + 10" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{43, 143, 307, 85, 28, 413}\n" + ] + } + ], + "source": [ + "transformed = {(2*x*x + 5*x + 10) for x in primes}\n", + "print(transformed)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Flatten List and eliminate duplicates\n", + "Syntax: {leaf for branch in tree for leaf in branch}" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{1, 2, 3, 98, 76}\n" + ] + } + ], + "source": [ + "nums = [[1,3],[2,3],[3,98],[76,1]]\n", + "flat_set = {a for b in nums for a in b}\n", + "print(flat_set)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Eliminate Dups from a List\n", + "We can easily eliminate differences in capitalization, while removing duplicates." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'Albert', 'Ella', 'George', 'Salil'}\n" + ] + } + ], + "source": [ + "names = ['salil', 'ALBERT', 'Ella', 'george', 'Salil', 'George', 'ELLA', 'Albert']\n", + "names_set = {n.capitalize() for n in names}\n", + "print(names_set)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And it's easy to convert this back to a list." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['Albert', 'Ella', 'George', 'Salil']\n" + ] + } + ], + "source": [ + "names_set = list({n.capitalize() for n in names})\n", + "print(names_set)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Get Car Make from list of Make & Model\n", + "We're getting the first word from each string." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'Toyota', 'Tesla', 'Chevy'}\n" + ] + } + ], + "source": [ + "cars = ['Toyota Prius', 'Chevy Bolt', 'Tesla Model 3', 'Tesla Model Y']\n", + "makes = {(c.split()[0]) for c in cars}\n", + "print(makes)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Get Initials from Names\n", + "Take first and last initials" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'CB', 'NF', 'HP'}\n" + ] + } + ], + "source": [ + "names = ['Clint Barton', 'Tony', 'Nick Fury', 'Hank Pym']\n", + "inits = {(n.split()[0][0] + n.split()[1][0]) for n in names if len(n.split())==2}\n", + "print(inits)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Python in 90 minutes/Python in 90 minutes.pptx b/Python in 90 minutes/Python in 90 minutes.pptx new file mode 100644 index 00000000..7640e394 Binary files /dev/null and b/Python in 90 minutes/Python in 90 minutes.pptx differ diff --git a/Python in 90 minutes/Python in 90 minutes.py b/Python in 90 minutes/Python in 90 minutes.py new file mode 100644 index 00000000..17d08eb5 --- /dev/null +++ b/Python in 90 minutes/Python in 90 minutes.py @@ -0,0 +1,596 @@ +# INTRODUCTION TO PYTHON +# ------------------------------------------------ +# to print, put text inside single or double quotes, inside parentheses. +print('Hello World') + +# VARIABLES +# ------------------------------------------------ +# variables are used for temporary storage of data that may change +# a single equals sign is the assignment operator +age = 26 +first_name = 'Shivika' +gpa = 3.99 + +# here we can see three different types of data stored in variables: an integer, a string, and a float. +# You do not have to declare the data type stored in each variable. Python does that for you. +# You can see what type of data is in a variable using the type() function +print(type(age)) +print(type(first_name)) +print(type(gpa)) + +# variables are "dynamically typed" -- Python checks the type at runtime +age = 26.2 +print(type(age)) +print(age, type(age)) + +# variable naming tips: +# naming can have letters, numbers and underscore, but cannot start with a digit +# some Python reserved words cannot be used +# use descriptive variable names +# Case Matters +# constants in all caps: PI = 3.14159 +# every Python variable is a pointer to the data stored somewhere in memory +# get memory location of a variable using id() function +print(id(age)) + +# to swap variable values: +x = 5 +y = 10 +x, y = y, x +print('x =', x, 'y =', y) + +# BOOLEAN VALUES - True or False +# ------------------------------------------------ +# These all evaluate to False: 0, 0.0, [], "", None +# These are all True: any non-zero number, any non-empty string, list or set +print(bool(1)) # True +print(bool('dog')) +print(bool(10.78)) +print(bool(0 or 1)) + +print(bool(0)) # False +print(bool('')) +print(bool(0 and 1)) + +# MATH FUNCTIONS +# ------------------------------------------------ +# built-in arithmetic functions are: add, subtract, multiply, divide, power, integer division, and modulus (AKA: mod or remainder) +# + Addition +# - Subtraction +# * Multiplication +# / Division +# // Integer Division +# % Modulus (division remainder) +# ** Power +x = 5 + 7 +print(x, type(x)) +x = 5 - 7 +print(x, type(x)) +x = 7 / 4 +print(x, type(x)) +x = 7 // 4 +print(x, type(x)) +x = 7 % 4 +print(x) +x = 4 ** 3 +print(x) + +# x += 5 is the same as saying x = x + 5 +x = 2 +x = x + 5 +print(x) + +x = 2 +x += 5 +print(x) + +# Order of Operations +# 1. ( ) +# 2. ** +# 3. * / // % +# 4. + - +# Example: 1 + 5 ** (3 // 2) - 6 % 4 => 4 +x = 1 + 5 ** (3 // 2) - 6 % 4 +print(x) + +# CONSOLE INPUT +# ------------------------------------------------ +# Get user input from the keyboard at the command prompt +name = input('What is your name? ') +print("Hello,", name) +age = eval(input('How old are you? ')) +print('Age =', age, type(age)) + +# With what we know so far we can write a program to get user input and compute the area of a triangle. +base = eval(input('Enter the base: ')) +height = eval(input('Enter the height: ')) +area = base * height / 2 +print ('Area = ', area) + +# COMMENTS +# ------------------------------------------------ +# Hash tag for single line comment +''' +Three sets of quotes +for multi-line comments +''' +""" double quotes work too """ + +# IF-ELIF-ELSE STATEMENTS +# ------------------------------------------------ +# requires a boolean expression +x = 69 +print(x > 50) +print(x == 50) +print(x != 50) + +my_age = 19 +print(my_age > 21) +if my_age >= 21: + print("Old enough.") +else: + print("Not old enough.") + print("Maybe next year.") + +score = 72 +if score > 90: + print('Grade: A') +elif score > 80: + print('Grade: B') +elif score > 70: + print('Grade: C') +elif score > 60: + print('Grade: D') +else: + print('Grade: F') + +# can have multiple conditions in an if, using and/or +my_age = 19 +grade = 'C' +if my_age > 18 and grade == 'A': + print('I can go to the party!') + +# nested if statements -- both conditions must be True +my_age = 19 +grade = 'C' +if my_age > 18: + if grade == 'A': + print('I can go to the party!') + +# if ternary +x = 10 +y = 20 +# action/ if condition true/ else condfition false +z = x + y if x > y else y - x +print(z) +# result 10 + + +# STRINGS +# ------------------------------------------------ +# a string is a sequence of characters (ie. text) +s = 'Howdy' +print(s) +print(len(s)) +print(s[3]) +print(s[1:3]) +t = ' dude! ' +s += t +print(s + '|') +print(s.strip() + '|') +s = s.rstrip('! ') +print(s) + +s = 'Howdy dude!' +print(s.lower()) +print(s.upper()[:5]) +print(s.title()) +print(s.replace('Howdy', 'Greetings')) +print(s) +print(s.count('d')) +print(s.find('w')) +print('dud' in s) +print('X' not in s) +print(s.startswith('How')) +print(s.endswith('cat')) +print(s > 'Honk') +print(s.isalpha()) +print(s[0:4].isalpha()) +print(s.isnumeric()) + +print(s.split()) +print('5,7,9'.split(',')) +print('73.294'.split('.')) + +print(s[0], '\t', s[1], '\t', s[2]) +print(s[:s.find(' ')] + '\n' + s[s.find(' ')+1:]) + +# LOOPS -- FOR, WHILE +# ------------------------------------------------ +# used to iterate through the items of a string or list +# indention is important. +# every statement indented from for will be executed each iteration +s = 'Raj' +for letter in s: + print(letter) +for letter in s: + print(letter, end='') +print() + +# if inside a for loop. indention is important. +for pig in s: + if pig != 'a': + print(pig, end='') +print() +for i in range(len(s)): + print(i, end='') +print() +for i in range(len(s)): + print(s[i]) +for i in range(len(s)-1, -1, -1): + print(s[i]) +print(s[::-1]) + +# while loops are an alternative to for loops +# they check a boolean each iteration, and exit the loop when the bool is False +x = 2 +while x < 5: + print('ha') + x += 1 + +# DATA STRUCTURES +# ------------------------------------------------ +# These functions all work on String, List, and Tuple + +# Indexing -- access any item in the sequence using its index +x = 'frog' +print (x[3]) # prints 'g' + +x = ['pig', 'cow', 'horse'] +print (x[1]) # prints 'cow' + +# Slicing -- slice out substrings, sublists, subtuples using indexes +# [start : end+1 : step] +x = 'computer' +print(x[1:4]) # items 1 to 3, 'omp' +print(x[1:6:2]) # items 1, 3, 5, 'opt' +print(x[3:]) # items 3 to end, 'puter' +print(x[:5]) # items 0 to 4, 'compu' +print(x[-1]) # last item, 'r' +print(x[-3:]) # last 3 items, 'ter' +print(x[:-2]) # all except last 2 items, 'comput' + +# Adding / Concatenating -- combine 2 sequences of the same type using + +x = 'horse' + 'shoe' +print (x) # prints 'horseshoe' + +x = ['pig', 'cow'] + ['horse'] +print (x) # prints ['pig', 'cow', 'horse'] + +# Multiplying -- multiply a sequence using * +x = 'bug' * 3 +print (x) # prints 'bugbugbug' + +x = [8, 5] * 3 +print (x) # prints [8, 5, 8, 5, 8, 5] + +# Checking Membership -- test whether an item is in or not in a sequence +x = 'bug' +print ('u' in x) # prints True + +x = ['pig', 'cow', 'horse'] +print ('cow' not in x) # prints False + +# Iterating -- iterate through the items in a sequence +x = [7, 8, 3] +for item in x: + print (item * 2) # prints 14, 16, 6 + +x = [7, 8, 3] +for index, item in enumerate(x): + print (index, item) # prints 0 7, 1 8, 2 3 + +# Length -- count the number of items in a sequence +x = 'bug' +print (len(x)) # prints 3 + +x = ['pig', 'cow', 'horse'] +print (len(x)) # prints 3 + +# Minimum -- find the minimum item in a sequence lexicographically +# alpha or numeric types, but cannot mix types +x = 'bug' +print (min(x)) # prints 'b' + +x = ['pig', 'cow', 'horse'] +print (min(x)) # prints 'cow' + +# Maximum -- find the maximum item in a sequence +# alpha or numeric types, but cannot mix types +x = 'bug' +print (max(x)) # prints 'u' + +x = ['pig', 'cow', 'horse'] +print (max(x)) # prints 'pig' + +# Sum -- find the sum of items in a sequence +# entire sequence must be numeric type +x = [5, 7, 'bug'] +print (sum(x)) # error! + +x = [2, 5, 8, 12] +print (sum(x)) # prints 27 +print (sum(x[-2:])) # prints 20 + +# Sorting -- returns a new list of items in sorted order +# sorted does not change the original list +x = 'bug' +print (sorted(x)) # prints ['b', 'g', 'u'] + +x = ['pig', 'cow', 'horse'] +print (sorted(x)) # prints ['cow', 'horse', 'pig'] + +# count (item) +# Returns count of an item +x = 'hippo' +print (x.count('p')) # prints 2 + +x = ['pig', 'cow', 'horse', 'cow'] +print (x.count('cow')) # prints 2 + +# index (item) +# Returns the index of the first occurrence of an item +x = 'hippo' +print (x.index('p')) # prints 2 + +x = ['pig', 'cow', 'horse', 'cow'] +print (x.index('cow')) # prints 1 + +# Unpacking - unpack the n items of a sequence into n variables +x = ['pig', 'cow', 'horse'] +a, b, c = x # now a is 'pig', b is 'cow', c is 'horse' + +# LISTS +# ------------------------------------------------ +# constructors – creating a new list +x = list((1, 2, 3)) # note double parens +x = ['a', 25, 'dog', 8.43] +x = list(tuple1) + +# list creation using comprehensions +x = [m for m in range(8)] +# resulting list: [0, 1, 2, 3, 4, 5, 6, 7] +x = [z**2 for z in range(10) if z>4] +# resulting list: [25, 36, 49, 64, 81] + +# Delete -- delete a list or an item from a list +x = [5, 3, 8, 6] +del(x[1]) # [5, 8, 6] +del(x) # deletes list x + +# Append -- append an item to a list +x = [5, 3, 8, 6] +x.append(7) # [5, 3, 8, 6, 7] + +# Extend -- append an sequence to a list +x = [5, 3, 8, 6] +y = [12, 13] +x.extend(y) # [5, 3, 8, 6, 7, 12, 13] + +# Insert -- insert an item at given index. x.insert(index, item) +x = [5, 3, 8, 6] +x.insert(1, 7) # [5, 7, 3, 8, 6] +x.insert(1,['a','m']) # [5, ['a', 'm'], 7, 3, 8, 6] + +# Pop -- pops last item off the list, and returns item +x = [5, 3, 8, 6] +x.pop() # [5, 3, 8]. and returns the 6 +print(x.pop()) # [5, 3]. and prints 8 + +# Remove -- remove first instance of an item +x = [5, 3, 8, 6, 3] +x.remove(3) # [5, 8, 6, 3] + +# Reverse -- reverse the order of the list +x = [5, 3, 8, 6] +x.reverse() # [6, 8, 3, 5] + +# Sort -- sort the list in place +# sorted(x) returns a new sorted list without changing the original list x. +# x.sort() puts the items of x in sorted order (sorts in place). +x = [5, 3, 8, 6] +x.sort() # [3, 5, 6, 8] + +# Clear -- delete all items from the list +x = [5, 3, 8, 6] +x.clear() # [] + +# TUPLES +# ------------------------------------------------ +# constructors – creating a new tuple +x = () # no-item tuple +x = (1,2,3) +x = 1, 2, 3 # parenthesis are optional +x = 2, # single-item tuple +list1 = [5, 7, 7] +x = tuple(list1) # tuple from list + +# Tuples are Immutable, but member objects may be mutable +x = (1, 2, 3) +del(x[1]) # error! +x[1] = 8 # error! + +x = ([1,2], 3) # 2-item tuple: list and int +del(x[0][1]) # ([1], 3) + +# SETS +# ------------------------------------------------ +# constructors – creating a new set +x = {3,5,3,5} # {5, 3} +x = set() # empty set +list1 = [5, 7, 7] +x = set(list1) # new set from list. strips duplicates, {5, 7} + +# Set Comprehension +x = {3*x for x in range(10) if x>5} +# resulting set: {18, 21, 24, 27} but in random order + +# DICTIONARIES +# ------------------------------------------------ +# constructors – creating a new dict +x = {'pork':25.3, 'beef':33.8, 'chicken':22.7} +x = dict([('pork', 25.3),('beef', 33.8),('chicken', 22.7)]) +x = dict(pork=25.3, beef=33.8, chicken=22.7) + +# Accessing keys and values in a dict +x.keys() # returns list of keys in x +x.values() # returns list of values in x +x.items() # returns list of key-value tuple pairs in x + +item in x.values() # tests membership in x, returns boolean + +# Iterating a Dict +for key in x: # iterate keys + print(key, x[key]) # print all key/value pairs + +for k, v in x.items(): # iterate key/value pairs + print(k, v) # print all key/value pairs + +# FUNCTIONS +# ------------------------------------------------ +# use the def keyword to create a function +# give the function a name, followed by parentheses and a colon +# you can pass in 0 or more variables. here we pass in num. +# you can return 0 or more variables. here we return the cube of num +# indention is important. +def cuber(num): + num_cubed = num * num * num + return num_cubed + +# to call the function, and pass in 5: +cuber(5) + +# but if you want to assign the return value (125) to a variable, +x = 5 +x_cubed = cuber(x) +print(x, x_cubed) + +# you can set default values for parameters +def cuber(num = 2): + num_cubed = num * num * num + return num_cubed + +print(cuber()) # uses the default 2 +print(cuber(3)) # 3 overrides the default + +# you can pass in multiple values, and return multiple values +# but order is important +def solve_triangle(base, height, side1, side2, side3): + area = base * height / 2 + perimeter = side1 + side2 + side3 + return area, perimeter + +area, perim = solve_triangle(3, 4, 5, 3, 4) # b=3, h=4, s1=5, s2=3, s3=4 +print('Area:', area, ' Perimeter:', perim) + +# above are all called "positional arguments", and order matters +# you can also pass in "keyword arguments" when calling a function +a, p = solve_triangle(side1=5, side2=3, side3=4, height=4, base=3) +print(a, p) + +# or use a combination of both, but positional arguments must come first +a, p = solve_triangle(3, 4, side3=4, side2=3, side1=5) +print(a, p) + +# CLASSES & OBJECTS +# ------------------------------------------------ +# Use classes to model real-world things. +# Keep related data (variables) and actions (functions) in one block of code. +class Circle: + # Circle constructor -- __init__ method creates a new Circle object + def __init__(self, r = 1): + self.radius = r + + def getPerimeter(self): + return 2 * self.radius * 3.14 + + def getArea(self): + return self.radius ** 2 * 3.14 +# all methods have the self parameter, which is Python's reference to the object that invoked the method + +# this calls the __init__ method, which creates the new Circle +circle1 = Circle(3) +# you can access the circle's attributes and methods using the dot operator +print("Radius =", circle1.radius) +print("Perimeter =", circle1.getPerimeter()) + +# IMPORTS +# ------------------------------------------------ +# Python has many many classes already written that you can use +# To access methods and data from another class you must import it +import math +print(math.pi) + +import random +print(random.randint(1,5)) + +# shorter version, using as to abbreviate module name +import math as m +print(m.pi) + +import random as rd +print(rd.randint(1,5)) + +# import just one or two functions or constants rather than a whole module +# easier for coding, but need to beware names don't conflict +from math import pi +print(pi) + +from random import randint, shuffle +print(randint(1,5)) +x = ['a', 'b', 'c'] +shuffle(x) +print(x) + +# can rename an imported function if you want +x = ['a', 'b', 'c'] +from random import shuffle as sf +sf(x) +print(x) + +# can also import whole module using * +from random import * +print(randint(1,5)) + +# FILE READ & WRITE +# ------------------------------------------------ +filename = 'city_data.txt' + +# this opens a file handle called fin, iterates the lines of the file, and prints each line +with open(filename) as fin: + for line in fin: + print(line) + +# we can grab words from a line by using split, which turns each line into a list called row +with open(filename) as fin: + fin.readline() + for line in fin: + row = line.split(',') + print('Country:', row[1], ' City:', row[2]) + +# use the w parameter to write to an output file +with open('Cities.txt', 'w') as fout: + with open(filename) as fin: + fin.readline() + for line in fin: + row = line.split(',') + fout.write(row[2] + '\n') + + + + + + + + + diff --git a/Python in 90 minutes/city_data.txt b/Python in 90 minutes/city_data.txt new file mode 100644 index 00000000..5ed0a476 --- /dev/null +++ b/Python in 90 minutes/city_data.txt @@ -0,0 +1,5 @@ +Country Code,Country Name,City Name,City Population +08,US,San Jose,70 +09,Canada,Vancouver,30 +08,US,San Francisco,90 +07,China,Beijing,40 \ No newline at end of file diff --git a/Queues implementaion.py b/Queues implementaion.py new file mode 100644 index 00000000..63170c8c --- /dev/null +++ b/Queues implementaion.py @@ -0,0 +1,64 @@ + +# implemented by Linked list +class Node(object): + def __init__(self, item = None): + self.item = item + self.next = None + self.previous = None + + +class Queue(object): + def __init__(self): + self.length = 0 + self.head = None + self.tail = None + + def enqueue(self, x): + newNode = Node(x) + if self.head == None: + self.head = self.tail = newNode + else: + self.tail.next = newNode + newNode.previous = self.tail + self.tail = newNode + self.length += 1 + + + def dequeue (self): + item = self.head.item + self.head = self.head.next + self.length -= 1 + if self.length == 0: + self.last = None + return item + + +################################################# + +# implemented by array +class Queue: + def __init__(self): + self.items = [] + + def is_empty(self): + return self.items == [] + + def enqueue(self, data): + self.items.append(data) + + def dequeue(self): + return self.items.pop(0) + + def display(self): + ar = [] + for i in self.items: + ar.append(i) + return ar +que = Queue() +que.enqueue('google') +que.enqueue('youtube') +que.enqueue('udemy') +que.enqueue('udacity') +que.dequeue() +que.dequeue() +print(que.display()) diff --git a/README.md b/README.md index c5403ef5..939de1ed 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,19 @@ -# Python +#This is a open source project. +# Python 3 These files are mainly intended to accompany my series of YouTube tutorial videos here, https://www.youtube.com/user/joejamesusa -and is mainly intended for educational purposes. -You are invited to subscribe to my video channel, and to download and use any code in -this Python repository without restrictions, according to the MIT License. +and are mainly intended for educational purposes. +You are invited to subscribe to my video channel-Joe James, and to download and use any code in +this Python repository, according to the MIT License. Feel free to post any comments on my YouTube channel. +I am very happy to see you there on my you tube channel. excited!!!!!!!!! +## Subscribe to my channel for more tutorial videos. -Joe James -Fremont, California -Copyright (C) 2015-2017, Joe James +This source code is easy to understand and reliable for self study and you will learn them easily, try to practice more coding by making algorithms yourself and you can become a better Python programmer, and remember "Try to learn something about everything and everything about something". + +Thank you for reviewing my repositories and keep practicing. +Joe James. +Fremont, CA. +Copyright (C) 2015-2021, Joe James + +## Happy coding guys!😀 diff --git a/Sorting Algorithms/Heapsort.py b/Sorting Algorithms/Heapsort.py new file mode 100644 index 00000000..9a2e2c14 --- /dev/null +++ b/Sorting Algorithms/Heapsort.py @@ -0,0 +1,33 @@ +# heapify +def heapify(arr, n, i): + largest = i # largest value + l = 2 * i + 1 # left + r = 2 * i + 2 # right + # if left child exists + if l < n and arr[i] < arr[l]: + largest = l + # if right child exits + if r < n and arr[largest] < arr[r]: + largest = r + # root + if largest != i: + arr[i],arr[largest] = arr[largest],arr[i] # swap + # root. + heapify(arr, n, largest) +# sort +def heapSort(arr): + n = len(arr) + # maxheap + for i in range(n, -1, -1): + heapify(arr, n, i) + # element extraction + for i in range(n-1, 0, -1): + arr[i], arr[0] = arr[0], arr[i] # swap + heapify(arr, i, 0) +# main +arr = [2,5,3,8,6,5,4,7] +heapSort(arr) +n = len(arr) +print ("Sorted array is") +for i in range(n): + print (arr[i],end=" ") diff --git a/Sorting Algorithms/Python QuickSort.ipynb b/Sorting Algorithms/Python QuickSort.ipynb new file mode 100644 index 00000000..5f925c81 --- /dev/null +++ b/Sorting Algorithms/Python QuickSort.ipynb @@ -0,0 +1,140 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python QuickSort Algorithm" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5, 9, 1, 2, 4, 8, 6, 3, 7]\n", + "[1, 2, 3, 4, 5, 6, 7, 8, 9]\n" + ] + } + ], + "source": [ + "#---------------------------------------\n", + "# Quick Sort\n", + "#---------------------------------------\n", + "def quick_sort(A):\n", + " quick_sort2(A, 0, len(A)-1)\n", + " \n", + "def quick_sort2(A, low, hi):\n", + " if hi-low < 1 and low < hi:\n", + " quick_selection(A, low, hi)\n", + " elif low < hi:\n", + " p = partition(A, low, hi)\n", + " quick_sort2(A, low, p - 1)\n", + " quick_sort2(A, p + 1, hi)\n", + " \n", + "def get_pivot(A, low, hi):\n", + " mid = (hi + low) // 2\n", + " s = sorted([A[low], A[mid], A[hi]])\n", + " if s[1] == A[low]:\n", + " return low\n", + " elif s[1] == A[mid]:\n", + " return mid\n", + " return hi\n", + " \n", + "def partition(A, low, hi):\n", + " pivotIndex = get_pivot(A, low, hi)\n", + " pivotValue = A[pivotIndex]\n", + " A[pivotIndex], A[low] = A[low], A[pivotIndex]\n", + " border = low\n", + "\n", + " for i in range(low, hi+1):\n", + " if A[i] < pivotValue:\n", + " border += 1\n", + " A[i], A[border] = A[border], A[i]\n", + " A[low], A[border] = A[border], A[low]\n", + "\n", + " return (border)\n", + " \n", + "def quick_selection(x, first, last):\n", + " for i in range (first, last):\n", + " minIndex = i\n", + " for j in range (i+1, last+1):\n", + " if x[j] < x[minIndex]:\n", + " minIndex = j\n", + " if minIndex != i:\n", + " x[i], x[minIndex] = x[minIndex], x[i]\n", + " \n", + "A = [5,9,1,2,4,8,6,3,7]\n", + "print(A)\n", + "quick_sort(A)\n", + "print(A)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Nice simple version written by Mr. UncleChu in comments\n", + "Slick code, but does not sort in place, so uses a lot more memory. Do not use for large lists or you'll get stackoverflow." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5, 9, 1, 2, 4, 8, 6, 3, 7]\n", + "[1, 2, 3, 4, 5, 6, 7, 8, 9]\n" + ] + } + ], + "source": [ + "def quick_sort_chu(a_list):\n", + " if len(a_list) < 2: return a_list\n", + " lesser = quick_sort([x for x in a_list[1:] if x <= a_list[0]])\n", + " bigger = quick_sort([x for x in a_list[1:] if x > a_list[0]])\n", + " return sum([lesser, [a_list[0]], bigger], [])\n", + "A = [5,9,1,2,4,8,6,3,7]\n", + "print(A)\n", + "B = quick_sort_chu(A)\n", + "print(B)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Sorting Algorithms/Radix_Sort.ipynb b/Sorting Algorithms/Radix_Sort.ipynb new file mode 100644 index 00000000..0b701528 --- /dev/null +++ b/Sorting Algorithms/Radix_Sort.ipynb @@ -0,0 +1,121 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Radix Sort\n", + "(c) 2020, Joe James" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# get number of digits in largest item\n", + "def __get_num_digits(A):\n", + " m = 0\n", + " for item in A:\n", + " m = max(m, item)\n", + " return len(str(m))" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# flatten into a 1D List\n", + "from functools import reduce\n", + "def __flatten(A):\n", + " return reduce(lambda x, y: x + y, A)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Changed from YouTube video:\n", + "It's much cleaner to put the _get_num_digits call inside the radix function rather than in main as shown in the video. That way you only need to pass a List to the radix function. Thanks to Brother Lui for this suggestion." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "def radix(A):\n", + " num_digits = __get_num_digits(A)\n", + " for digit in range(0, num_digits):\n", + " B = [[] for i in range(10)]\n", + " for item in A:\n", + " # num is the bucket number that the item will be put into\n", + " num = item // 10 ** (digit) % 10\n", + " B[num].append(item)\n", + " A = __flatten(B)\n", + " return A" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 45, 53, 55, 213, 288, 289]\n", + "[0, 1, 2, 3, 4, 5] [999994, 999995, 999996, 999997, 999998, 999999]\n" + ] + } + ], + "source": [ + "def main():\n", + " A = [55, 45, 3, 289, 213, 1, 288, 53, 2]\n", + " A = radix(A)\n", + " print(A)\n", + " \n", + " B = [i for i in range(1000000)]\n", + " from random import shuffle\n", + " shuffle(B)\n", + " B = radix(B)\n", + " print(B[:6], B[-6:])\n", + "\n", + "main()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/SortingAlgorithms.py b/Sorting Algorithms/SortingAlgorithms similarity index 96% rename from SortingAlgorithms.py rename to Sorting Algorithms/SortingAlgorithms index 8d6f81c6..0379471d 100644 --- a/SortingAlgorithms.py +++ b/Sorting Algorithms/SortingAlgorithms @@ -1,394 +1,394 @@ -import random -import time -import copy -size1 = 100 -size2 = 10000 -size3 = 1000000 -span = 1000000 -threshold = 20 - -#--------------------------------------- -# Insertion Sort -#--------------------------------------- -# not optimized, equiv to while version below, but uses for loop -def insertion_sort1(A): - for i in range(1, len(A)): - for j in range(i-1, -1, -1): - if A[j] > A[j+1]: - A[j], A[j+1] = A[j+1], A[j] - else: - break - -# not optimized, equiv to break version, but uses while loop -def insertion_sort2(A): - for i in range(1, len(A)): - j = i-1 - while A[j] > A[j+1] and j >= 0: - A[j], A[j+1] = A[j+1], A[j] - j -= 1 - -# optimized - shifts instead of swapping -def insertion_sort3(A): - for i in range(1, len(A)): - curNum = A[i] - k = 0 - for j in range(i-1, -2, -1): - k = j - if A[j] > curNum: - A[j+1] = A[j] - else: - break - A[k+1] = curNum - -#--------------------------------------- -# Selection Sort -#--------------------------------------- -def selection_sort(A): - for i in range (0, len(A) - 1): - minIndex = i - for j in range (i+1, len(A)): - if A[j] < A[minIndex]: - minIndex = j - if minIndex != i: - A[i], A[minIndex] = A[minIndex], A[i] - -#--------------------------------------- -# Bubble Sort -#--------------------------------------- -# not optimized -def bubble_sort1(A): - for i in range (0, len(A) - 1): - for j in range (0, len(A) - i - 1): - if A[j] > A[j+1]: - A[j], A[j+1] = A[j+1], A[j] - -# optimized to exit if no swaps occur -def bubble_sort2(A): - for i in range (0, len(A) - 1): - done = True - for j in range (0, len(A) - i - 1): - if A[j] > A[j+1]: - A[j], A[j+1] = A[j+1], A[j] - done = False - if done: - return - -#--------------------------------------- -# Merge Sort -#--------------------------------------- -def merge_sort(A): - merge_sort2(A, 0, len(A)-1) - -def merge_sort2(A, first, last): - if last-first < threshold and first < last: - quick_selection(A, first, last) - elif first < last: - middle = (first + last)//2 - merge_sort2(A, first, middle) - merge_sort2(A, middle+1, last) - merge(A, first, middle, last) - -def merge(A, first, middle, last): - L = A[first:middle] - R = A[middle:last+1] - L.append(999999999) - R.append(999999999) - i = j = 0 - - for k in range (first, last+1): - if L[i] <= R[j]: - A[k] = L[i] - i += 1 - else: - A[k] = R[j] - j += 1 -#--------------------------------------- -# Quick Sort -#--------------------------------------- -def quick_sort(A): - quick_sort2(A, 0, len(A)-1) - -def quick_sort2(A, low, hi): - if hi-low < threshold and low < hi: - quick_selection(A, low, hi) - elif low < hi: - p = partition(A, low, hi) - quick_sort2(A, low, p - 1) - quick_sort2(A, p + 1, hi) - -def get_pivot(A, low, hi): - mid = (hi + low) // 2 - s = sorted([A[low], A[mid], A[hi]]) - if s[1] == A[low]: - return low - elif s[1] == A[mid]: - return mid - return hi - -def partition(A, low, hi): - pivotIndex = get_pivot(A, low, hi) - pivotValue = A[pivotIndex] - A[pivotIndex], A[low] = A[low], A[pivotIndex] - border = low - - for i in range(low, hi+1): - if A[i] < pivotValue: - border += 1 - A[i], A[border] = A[border], A[i] - A[low], A[border] = A[border], A[low] - - return (border) - -def quick_selection(x, first, last): - for i in range (first, last): - minIndex = i - for j in range (i+1, last+1): - if x[j] < x[minIndex]: - minIndex = j - if minIndex != i: - x[i], x[minIndex] = x[minIndex], x[i] - -#--------------RANDOM ORDER---------------------- -#------------------------------------------------ -# size = 100 -#------------------------------------------------ -print("\nRandom Order\n---------------------------------") -w = [random.randint(0, span) for a in range(0, size1)] -t1 = time.clock() -insertion_sort3(w) -print("Insertion Sort(size=", str(size1),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, span) for a in range(0, size1)] -t1 = time.clock() -selection_sort(w) -print("Selection Sort(size=", str(size1),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, span) for a in range(0, size1)] -t1 = time.clock() -bubble_sort2(w) -print("Bubble Sort(size=", str(size1),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, span) for a in range(0, size1)] -t1 = time.clock() -merge_sort(w) -print("Merge Sort(size=", str(size1),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, span) for a in range(0, size1)] -t1 = time.clock() -quick_sort(w) -print("Quick Sort(size=", str(size1),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, span) for a in range(0, size1)] -t1 = time.clock() -w.sort() -print("Tim Sort(size=", str(size1),"): ", (time.clock()-t1) * 1000) -#------------------------------------------------ -# size = 10,000 -#------------------------------------------------ -w = [random.randint(0, span) for a in range(0, size2)] -t1 = time.clock() -insertion_sort3(w) -print("Insertion Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, span) for a in range(0, size2)] -t1 = time.clock() -selection_sort(w) -print("Selection Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, span) for a in range(0, size2)] -t1 = time.clock() -bubble_sort2(w) -print("Bubble Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, span) for a in range(0, size2)] -t1 = time.clock() -merge_sort(w) -print("Merge Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, span) for a in range(0, size2)] -t1 = time.clock() -quick_sort(w) -print("Quick Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, span) for a in range(0, size2)] -t1 = time.clock() -w.sort() -print("Tim Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) -#------------------------------------------------ -# size = 1,000,000 -#------------------------------------------------ -w = [random.randint(0, span) for a in range(0, size3)] -t1 = time.clock() -merge_sort(w) -print("Merge Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, span) for a in range(0, size3)] -t1 = time.clock() -quick_sort(w) -print("Quick Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, span) for a in range(0, size3)] -t1 = time.clock() -w.sort() -print("Tim Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) - -# ----------------ALREADY SORTED----------------- -#------------------------------------------------ -# size = 10,000 -#------------------------------------------------ -print("\nAlready Sorted\n---------------------------------") - -w = [a for a in range(0, size2)] -t1 = time.clock() -insertion_sort3(w) -print("Insertion Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -t1 = time.clock() -selection_sort(w) -print("Selection Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -t1 = time.clock() -bubble_sort2(w) -print("Bubble Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -t1 = time.clock() -merge_sort(w) -print("Merge Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -t1 = time.clock() -quick_sort(w) -print("Quick Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -t1 = time.clock() -w.sort() -print("Tim Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) -#------------------------------------------------ -# size = 1,000,000 -#------------------------------------------------ -w = [a for a in range(0, size3)] -t1 = time.clock() -merge_sort(w) -print("Merge Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) - -t1 = time.clock() -quick_sort(w) -print("Quick Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) - -t1 = time.clock() -w.sort() -print("Tim Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) - -# ----------------REVERSE SORTED----------------- -#------------------------------------------------ -# size = 10,000 -#------------------------------------------------ -print("\nReverse Sorted\n---------------------------------") - -w = [a for a in range(0, size2)] -w.reverse() -t1 = time.clock() -insertion_sort3(w) -print("Insertion Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -w = [a for a in range(0, size2)] -w.reverse() -t1 = time.clock() -selection_sort(w) -print("Selection Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -w = [a for a in range(0, size2)] -w.reverse() -t1 = time.clock() -bubble_sort2(w) -print("Bubble Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -w = [a for a in range(0, size2)] -w.reverse() -t1 = time.clock() -merge_sort(w) -print("Merge Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -w = [a for a in range(0, size2)] -w.reverse() -t1 = time.clock() -quick_sort(w) -print("Quick Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -w = [a for a in range(0, size2)] -w.reverse() -t1 = time.clock() -w.sort() -print("Tim Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) -#------------------------------------------------ -# size = 1,000,000 -#------------------------------------------------ -w = [a for a in range(0, size3)] -w.reverse() -t1 = time.clock() -merge_sort(w) -print("Merge Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) - -w = [a for a in range(0, size3)] -w.reverse() -t1 = time.clock() -quick_sort(w) -print("Quick Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) - -w = [a for a in range(0, size3)] -w.reverse() -t1 = time.clock() -w.sort() -print("Tim Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) - -#--------------RANDOM ORDER, MANY DUPLICATES------------------ -#------------------------------------------------ -# size = 10,000 -#------------------------------------------------ -print("\nRandom Order, Many Duplicates\n---------------------------------") - -w = [random.randint(0, size2//10) for a in range(0, size2)] -t1 = time.clock() -insertion_sort3(w) -print("Insertion Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, size2//10) for a in range(0, size2)] -t1 = time.clock() -selection_sort(w) -print("Selection Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0,size2//10) for a in range(0, size2)] -t1 = time.clock() -bubble_sort2(w) -print("Bubble Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, size2//10) for a in range(0, size2)] -t1 = time.clock() -merge_sort(w) -print("Merge Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, size2//10) for a in range(0, size2)] -t1 = time.clock() -quick_sort(w) -print("Quick Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, size2//10) for a in range(0, size2)] -t1 = time.clock() -w.sort() -print("Tim Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) -#------------------------------------------------ -# size = 1,000,000 -#------------------------------------------------ -w = [random.randint(0, size2//10) for a in range(0, size3)] -t1 = time.clock() -merge_sort(w) -print("Merge Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, size2//10) for a in range(0, size3)] -t1 = time.clock() -#quick_sort(w) -#print("Quick Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) - -w = [random.randint(0, size2//10) for a in range(0, size3)] -t1 = time.clock() -w.sort() +import random +import time +import copy +size1 = 100 +size2 = 10000 +size3 = 1000000 +span = 1000000 +threshold = 20 + +#--------------------------------------- +# Insertion Sort +#--------------------------------------- +# not optimized, equiv to while version below, but uses for loop +def insertion_sort1(A): + for i in range(1, len(A)): + for j in range(i-1, -1, -1): + if A[j] > A[j+1]: + A[j], A[j+1] = A[j+1], A[j] + else: + break + +# not optimized, equiv to break version, but uses while loop +def insertion_sort2(A): + for i in range(1, len(A)): + j = i-1 + while A[j] > A[j+1] and j >= 0: + A[j], A[j+1] = A[j+1], A[j] + j -= 1 + +# optimized - shifts instead of swapping +def insertion_sort3(A): + for i in range(1, len(A)): + curNum = A[i] + k = 0 + for j in range(i-1, -2, -1): + k = j + if A[j] > curNum: + A[j+1] = A[j] + else: + break + A[k+1] = curNum + +#--------------------------------------- +# Selection Sort +#--------------------------------------- +def selection_sort(A): + for i in range (0, len(A) - 1): + minIndex = i + for j in range (i+1, len(A)): + if A[j] < A[minIndex]: + minIndex = j + if minIndex != i: + A[i], A[minIndex] = A[minIndex], A[i] + +#--------------------------------------- +# Bubble Sort +#--------------------------------------- +# not optimized +def bubble_sort1(A): + for i in range (0, len(A) - 1): + for j in range (0, len(A) - i - 1): + if A[j] > A[j+1]: + A[j], A[j+1] = A[j+1], A[j] + +# optimized to exit if no swaps occur +def bubble_sort2(A): + for i in range (0, len(A) - 1): + done = True + for j in range (0, len(A) - i - 1): + if A[j] > A[j+1]: + A[j], A[j+1] = A[j+1], A[j] + done = False + if done: + return + +#--------------------------------------- +# Merge Sort +#--------------------------------------- +def merge_sort(A): + merge_sort2(A, 0, len(A)-1) + +def merge_sort2(A, first, last): + if last-first < threshold and first < last: + quick_selection(A, first, last) + elif first < last: + middle = (first + last)//2 + merge_sort2(A, first, middle) + merge_sort2(A, middle+1, last) + merge(A, first, middle, last) + +def merge(A, first, middle, last): + L = A[first:middle] + R = A[middle:last+1] + L.append(999999999) + R.append(999999999) + i = j = 0 + + for k in range (first, last+1): + if L[i] <= R[j]: + A[k] = L[i] + i += 1 + else: + A[k] = R[j] + j += 1 +#--------------------------------------- +# Quick Sort +#--------------------------------------- +def quick_sort(A): + quick_sort2(A, 0, len(A)-1) + +def quick_sort2(A, low, hi): + if hi-low < threshold and low < hi: + quick_selection(A, low, hi) + elif low < hi: + p = partition(A, low, hi) + quick_sort2(A, low, p - 1) + quick_sort2(A, p + 1, hi) + +def get_pivot(A, low, hi): + mid = (hi + low) // 2 + s = sorted([A[low], A[mid], A[hi]]) + if s[1] == A[low]: + return low + elif s[1] == A[mid]: + return mid + return hi + +def partition(A, low, hi): + pivotIndex = get_pivot(A, low, hi) + pivotValue = A[pivotIndex] + A[pivotIndex], A[low] = A[low], A[pivotIndex] + border = low + + for i in range(low, hi+1): + if A[i] < pivotValue: + border += 1 + A[i], A[border] = A[border], A[i] + A[low], A[border] = A[border], A[low] + + return (border) + +def quick_selection(x, first, last): + for i in range (first, last): + minIndex = i + for j in range (i+1, last+1): + if x[j] < x[minIndex]: + minIndex = j + if minIndex != i: + x[i], x[minIndex] = x[minIndex], x[i] + +#--------------RANDOM ORDER---------------------- +#------------------------------------------------ +# size = 100 +#------------------------------------------------ +print("\nRandom Order\n---------------------------------") +w = [random.randint(0, span) for a in range(0, size1)] +t1 = time.clock() +insertion_sort3(w) +print("Insertion Sort(size=", str(size1),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, span) for a in range(0, size1)] +t1 = time.clock() +selection_sort(w) +print("Selection Sort(size=", str(size1),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, span) for a in range(0, size1)] +t1 = time.clock() +bubble_sort2(w) +print("Bubble Sort(size=", str(size1),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, span) for a in range(0, size1)] +t1 = time.clock() +merge_sort(w) +print("Merge Sort(size=", str(size1),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, span) for a in range(0, size1)] +t1 = time.clock() +quick_sort(w) +print("Quick Sort(size=", str(size1),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, span) for a in range(0, size1)] +t1 = time.clock() +w.sort() +print("Tim Sort(size=", str(size1),"): ", (time.clock()-t1) * 1000) +#------------------------------------------------ +# size = 10,000 +#------------------------------------------------ +w = [random.randint(0, span) for a in range(0, size2)] +t1 = time.clock() +insertion_sort3(w) +print("Insertion Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, span) for a in range(0, size2)] +t1 = time.clock() +selection_sort(w) +print("Selection Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, span) for a in range(0, size2)] +t1 = time.clock() +bubble_sort2(w) +print("Bubble Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, span) for a in range(0, size2)] +t1 = time.clock() +merge_sort(w) +print("Merge Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, span) for a in range(0, size2)] +t1 = time.clock() +quick_sort(w) +print("Quick Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, span) for a in range(0, size2)] +t1 = time.clock() +w.sort() +print("Tim Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) +#------------------------------------------------ +# size = 1,000,000 +#------------------------------------------------ +w = [random.randint(0, span) for a in range(0, size3)] +t1 = time.clock() +merge_sort(w) +print("Merge Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, span) for a in range(0, size3)] +t1 = time.clock() +quick_sort(w) +print("Quick Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, span) for a in range(0, size3)] +t1 = time.clock() +w.sort() +print("Tim Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) + +# ----------------ALREADY SORTED----------------- +#------------------------------------------------ +# size = 10,000 +#------------------------------------------------ +print("\nAlready Sorted\n---------------------------------") + +w = [a for a in range(0, size2)] +t1 = time.clock() +insertion_sort3(w) +print("Insertion Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +t1 = time.clock() +selection_sort(w) +print("Selection Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +t1 = time.clock() +bubble_sort2(w) +print("Bubble Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +t1 = time.clock() +merge_sort(w) +print("Merge Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +t1 = time.clock() +quick_sort(w) +print("Quick Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +t1 = time.clock() +w.sort() +print("Tim Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) +#------------------------------------------------ +# size = 1,000,000 +#------------------------------------------------ +w = [a for a in range(0, size3)] +t1 = time.clock() +merge_sort(w) +print("Merge Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) + +t1 = time.clock() +quick_sort(w) +print("Quick Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) + +t1 = time.clock() +w.sort() +print("Tim Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) + +# ----------------REVERSE SORTED----------------- +#------------------------------------------------ +# size = 10,000 +#------------------------------------------------ +print("\nReverse Sorted\n---------------------------------") + +w = [a for a in range(0, size2)] +w.reverse() +t1 = time.clock() +insertion_sort3(w) +print("Insertion Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +w = [a for a in range(0, size2)] +w.reverse() +t1 = time.clock() +selection_sort(w) +print("Selection Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +w = [a for a in range(0, size2)] +w.reverse() +t1 = time.clock() +bubble_sort2(w) +print("Bubble Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +w = [a for a in range(0, size2)] +w.reverse() +t1 = time.clock() +merge_sort(w) +print("Merge Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +w = [a for a in range(0, size2)] +w.reverse() +t1 = time.clock() +quick_sort(w) +print("Quick Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +w = [a for a in range(0, size2)] +w.reverse() +t1 = time.clock() +w.sort() +print("Tim Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) +#------------------------------------------------ +# size = 1,000,000 +#------------------------------------------------ +w = [a for a in range(0, size3)] +w.reverse() +t1 = time.clock() +merge_sort(w) +print("Merge Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) + +w = [a for a in range(0, size3)] +w.reverse() +t1 = time.clock() +quick_sort(w) +print("Quick Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) + +w = [a for a in range(0, size3)] +w.reverse() +t1 = time.clock() +w.sort() +print("Tim Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) + +#--------------RANDOM ORDER, MANY DUPLICATES------------------ +#------------------------------------------------ +# size = 10,000 +#------------------------------------------------ +print("\nRandom Order, Many Duplicates\n---------------------------------") + +w = [random.randint(0, size2//10) for a in range(0, size2)] +t1 = time.clock() +insertion_sort3(w) +print("Insertion Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, size2//10) for a in range(0, size2)] +t1 = time.clock() +selection_sort(w) +print("Selection Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0,size2//10) for a in range(0, size2)] +t1 = time.clock() +bubble_sort2(w) +print("Bubble Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, size2//10) for a in range(0, size2)] +t1 = time.clock() +merge_sort(w) +print("Merge Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, size2//10) for a in range(0, size2)] +t1 = time.clock() +quick_sort(w) +print("Quick Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, size2//10) for a in range(0, size2)] +t1 = time.clock() +w.sort() +print("Tim Sort(size=", str(size2),"): ", (time.clock()-t1) * 1000) +#------------------------------------------------ +# size = 1,000,000 +#------------------------------------------------ +w = [random.randint(0, size2//10) for a in range(0, size3)] +t1 = time.clock() +merge_sort(w) +print("Merge Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, size2//10) for a in range(0, size3)] +t1 = time.clock() +#quick_sort(w) +#print("Quick Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) + +w = [random.randint(0, size2//10) for a in range(0, size3)] +t1 = time.clock() +w.sort() print("Tim Sort(size=", str(size3),"): ", (time.clock()-t1) * 1000) \ No newline at end of file diff --git a/Sorting Algorithms/bubble_sort.py b/Sorting Algorithms/bubble_sort.py new file mode 100644 index 00000000..c24853c9 --- /dev/null +++ b/Sorting Algorithms/bubble_sort.py @@ -0,0 +1,25 @@ +#--------------------------------------- +# Bubble Sort +#--------------------------------------- +# not optimized +def bubble_sort1(A): + for i in range (0, len(A) - 1): + for j in range (0, len(A) - i - 1): + if A[j] > A[j+1]: + A[j], A[j+1] = A[j+1], A[j] + +# optimized to exit if no swaps occur +def bubble_sort2(A): + for i in range (0, len(A) - 1): + done = True + for j in range (0, len(A) - i - 1): + if A[j] > A[j+1]: + A[j], A[j+1] = A[j+1], A[j] + done = False + if done: + return + +A = [5,9,1,2,4,8,6,3,7] +print(A) +bubble_sort1(A) +print(A) \ No newline at end of file diff --git a/Sorting Algorithms/insertion_sort.py b/Sorting Algorithms/insertion_sort.py new file mode 100644 index 00000000..ee911f2a --- /dev/null +++ b/Sorting Algorithms/insertion_sort.py @@ -0,0 +1,37 @@ +#--------------------------------------- +# Insertion Sort +#--------------------------------------- +# not optimized, equiv to while version below, but uses for loop +def insertion_sort1(A): + for i in range(1, len(A)): + for j in range(i-1, -1, -1): + if A[j] > A[j+1]: + A[j], A[j+1] = A[j+1], A[j] + else: + break + +# not optimized, equiv to break version, but uses while loop +def insertion_sort2(A): + for i in range(1, len(A)): + j = i-1 + while A[j] > A[j+1] and j >= 0: + A[j], A[j+1] = A[j+1], A[j] + j -= 1 + +# optimized - shifts instead of swapping +def insertion_sort3(A): + for i in range(1, len(A)): + curNum = A[i] + k = 0 + for j in range(i-1, -2, -1): + k = j + if A[j] > curNum: + A[j+1] = A[j] + else: + break + A[k+1] = curNum + +A = [5,9,1,2,4,8,6,3,7] +print(A) +insertion_sort1(A) +print(A) \ No newline at end of file diff --git a/Mergesort.py b/Sorting Algorithms/merge_sort.py similarity index 79% rename from Mergesort.py rename to Sorting Algorithms/merge_sort.py index ea55cfc4..73d3ab31 100644 --- a/Mergesort.py +++ b/Sorting Algorithms/merge_sort.py @@ -1,31 +1,34 @@ -import sys - -def merge_sort(A): - merge_sort2(A, 0, len(A)-1) - -def merge_sort2(A, first, last): - if first < last: - middle = (first + last)//2 - merge_sort2(A, first, middle) - merge_sort2(A, middle+1, last) - merge(A, first, middle, last) - -def merge(A, first, middle, last): - L = A[first:middle+1] - R = A[middle+1:last+1] - L.append(sys.maxsize) - R.append(sys.maxsize) - i = j = 0 - - for k in range (first, last+1): - if L[i] <= R[j]: - A[k] = L[i] - i += 1 - else: - A[k] = R[j] - j += 1 - -A = [5,9,1,2,4,8,6,3,7] -print(A) -merge_sort(A) -print(A) \ No newline at end of file +#--------------------------------------- +# Merge Sort +#--------------------------------------- +import sys + +def merge_sort(A): + merge_sort2(A, 0, len(A)-1) + +def merge_sort2(A, first, last): + if first < last: + middle = (first + last)//2 + merge_sort2(A, first, middle) + merge_sort2(A, middle+1, last) + merge(A, first, middle, last) + +def merge(A, first, middle, last): + L = A[first:middle+1] + R = A[middle+1:last+1] + L.append(sys.maxsize) + R.append(sys.maxsize) + i = j = 0 + + for k in range (first, last+1): + if L[i] <= R[j]: + A[k] = L[i] + i += 1 + else: + A[k] = R[j] + j += 1 + +A = [5,9,1,2,4,8,6,3,7] +print(A) +merge_sort(A) +print(A) diff --git a/Sorting Algorithms/quick_sort.py b/Sorting Algorithms/quick_sort.py new file mode 100644 index 00000000..9731a8ee --- /dev/null +++ b/Sorting Algorithms/quick_sort.py @@ -0,0 +1,50 @@ +#--------------------------------------- +# Quick Sort +#--------------------------------------- +def quick_sort(A): + quick_sort2(A, 0, len(A)-1) + +def quick_sort2(A, low, hi): + if hi-low < threshold and low < hi: + quick_selection(A, low, hi) + elif low < hi: + p = partition(A, low, hi) + quick_sort2(A, low, p - 1) + quick_sort2(A, p + 1, hi) + +def get_pivot(A, low, hi): + mid = (hi + low) // 2 + s = sorted([A[low], A[mid], A[hi]]) + if s[1] == A[low]: + return low + elif s[1] == A[mid]: + return mid + return hi + +def partition(A, low, hi): + pivotIndex = get_pivot(A, low, hi) + pivotValue = A[pivotIndex] + A[pivotIndex], A[low] = A[low], A[pivotIndex] + border = low + + for i in range(low, hi+1): + if A[i] < pivotValue: + border += 1 + A[i], A[border] = A[border], A[i] + A[low], A[border] = A[border], A[low] + + return (border) + +def quick_selection(x, first, last): + for i in range (first, last): + minIndex = i + for j in range (i+1, last+1): + if x[j] < x[minIndex]: + minIndex = j + if minIndex != i: + x[i], x[minIndex] = x[minIndex], x[i] + +A = [5,9,1,2,4,8,6,3,7] +print(A) +quick_sort(A) +print(A) \ No newline at end of file diff --git a/Sorting Algorithms/selection_sort.py b/Sorting Algorithms/selection_sort.py new file mode 100644 index 00000000..f3209f46 --- /dev/null +++ b/Sorting Algorithms/selection_sort.py @@ -0,0 +1,16 @@ +#--------------------------------------- +# Selection Sort +#--------------------------------------- +def selection_sort(A): + for i in range (0, len(A) - 1): + minIndex = i + for j in range (i+1, len(A)): + if A[j] < A[minIndex]: + minIndex = j + if minIndex != i: + A[i], A[minIndex] = A[minIndex], A[i] + +A = [5,9,1,2,4,8,6,3,7] +print(A) +selection_sort(A) +print(A) \ No newline at end of file diff --git a/Stacks, Queues & Heaps.ipynb b/Stacks, Queues & Heaps.ipynb new file mode 100644 index 00000000..a54ede21 --- /dev/null +++ b/Stacks, Queues & Heaps.ipynb @@ -0,0 +1,346 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Stacks, Queues & Heaps\n", + "© Joe James, 2019.\n", + "\n", + "### Stack using Python List\n", + "Stack is a LIFO data structure -- last-in, first-out. \n", + "Use append() to push an item onto the stack. \n", + "Use pop() to remove an item." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[4, 7, 12, 19]\n" + ] + } + ], + "source": [ + "my_stack = list()\n", + "my_stack.append(4)\n", + "my_stack.append(7)\n", + "my_stack.append(12)\n", + "my_stack.append(19)\n", + "print(my_stack)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "19\n", + "12\n", + "[4, 7]\n" + ] + } + ], + "source": [ + "print(my_stack.pop())\n", + "print(my_stack.pop())\n", + "print(my_stack)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Stack using List with a Wrapper Class\n", + "We create a Stack class and a full set of Stack methods. \n", + "But the underlying data structure is really a Python List. \n", + "For pop and peek methods we first check whether the stack is empty, to avoid exceptions." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "class Stack():\n", + " def __init__(self):\n", + " self.stack = list()\n", + " def push(self, item):\n", + " self.stack.append(item)\n", + " def pop(self):\n", + " if len(self.stack) > 0:\n", + " return self.stack.pop()\n", + " else:\n", + " return None\n", + " def peek(self):\n", + " if len(self.stack) > 0:\n", + " return self.stack[len(self.stack)-1]\n", + " else:\n", + " return None\n", + " def __str__(self):\n", + " return str(self.stack)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Test Code for Stack Wrapper Class" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 3]\n", + "3\n", + "1\n", + "1\n", + "None\n" + ] + } + ], + "source": [ + "my_stack = Stack()\n", + "my_stack.push(1)\n", + "my_stack.push(3)\n", + "print(my_stack)\n", + "print(my_stack.pop())\n", + "print(my_stack.peek())\n", + "print(my_stack.pop())\n", + "print(my_stack.pop())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "### Queue using Python Deque\n", + "Queue is a FIFO data structure -- first-in, first-out. \n", + "Deque is a double-ended queue, but we can use it for our queue. \n", + "We use append() to enqueue an item, and popleft() to dequeue an item. \n", + "See [Python docs](https://docs.python.org/3/library/collections.html#collections.deque) for deque." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "deque([5, 10])\n", + "5\n" + ] + } + ], + "source": [ + "from collections import deque\n", + "my_queue = deque()\n", + "my_queue.append(5)\n", + "my_queue.append(10)\n", + "print(my_queue)\n", + "print(my_queue.popleft())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Fun exercise:\n", + "Write a wrapper class for the Queue class, similar to what we did for Stack, but using Python deque. \n", + "Try adding enqueue, dequeue, and get_size methods." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Python Single-ended Queue Wrapper Class using Deque\n", + "We rename the append method to enqueue, and popleft to dequeue. \n", + "We also add peek and get_size operations." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "from collections import deque\n", + "class Queue():\n", + " def __init__(self):\n", + " self.queue = deque()\n", + " self.size = 0\n", + " def enqueue(self, item):\n", + " self.queue.append(item)\n", + " self.size += 1\n", + " def dequeue(self, item):\n", + " if self.size > 0:\n", + " self.size -= 1\n", + " return self.queue.popleft()\n", + " else: \n", + " return None\n", + " def peek(self):\n", + " if self.size > 0:\n", + " ret_val = self.queue.popleft()\n", + " queue.appendleft(ret_val)\n", + " return ret_val\n", + " else:\n", + " return None\n", + " def get_size(self):\n", + " return self.size" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Python MaxHeap\n", + "A MaxHeap always bubbles the highest value to the top, so it can be removed instantly. \n", + "Public functions: push, peek, pop \n", + "Private functions: __swap, __floatUp, __bubbleDown, __str__." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "class MaxHeap:\n", + " def __init__(self, items=[]):\n", + " super().__init__()\n", + " self.heap = [0]\n", + " for item in items:\n", + " self.heap.append(item)\n", + " self.__floatUp(len(self.heap) - 1)\n", + "\n", + " def push(self, data):\n", + " self.heap.append(data)\n", + " self.__floatUp(len(self.heap) - 1)\n", + "\n", + " def peek(self):\n", + " if self.heap[1]:\n", + " return self.heap[1]\n", + " else:\n", + " return False\n", + " \n", + " def pop(self):\n", + " if len(self.heap) > 2:\n", + " self.__swap(1, len(self.heap) - 1)\n", + " max = self.heap.pop()\n", + " self.__bubbleDown(1)\n", + " elif len(self.heap) == 2:\n", + " max = self.heap.pop()\n", + " else: \n", + " max = False\n", + " return max\n", + "\n", + " def __swap(self, i, j):\n", + " self.heap[i], self.heap[j] = self.heap[j], self.heap[i]\n", + "\n", + " def __floatUp(self, index):\n", + " parent = index//2\n", + " if index <= 1:\n", + " return\n", + " elif self.heap[index] > self.heap[parent]:\n", + " self.__swap(index, parent)\n", + " self.__floatUp(parent)\n", + "\n", + " def __bubbleDown(self, index):\n", + " left = index * 2\n", + " right = index * 2 + 1\n", + " largest = index\n", + " if len(self.heap) > left and self.heap[largest] < self.heap[left]:\n", + " largest = left\n", + " if len(self.heap) > right and self.heap[largest] < self.heap[right]:\n", + " largest = right\n", + " if largest != index:\n", + " self.__swap(index, largest)\n", + " self.__bubbleDown(largest)\n", + " \n", + " def __str__(self):\n", + " return str(self.heap)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### MaxHeap Test Code" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, 95, 10, 21, 3]\n", + "95\n", + "21\n" + ] + } + ], + "source": [ + "m = MaxHeap([95, 3, 21])\n", + "m.push(10)\n", + "print(m)\n", + "print(m.pop())\n", + "print(m.peek())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/String Formatting.ipynb b/String Formatting.ipynb new file mode 100644 index 00000000..82546e12 --- /dev/null +++ b/String Formatting.ipynb @@ -0,0 +1,444 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python String format()\n", + "[Official docs](https://docs.python.org/3/library/string.html#format-string-syntax) \n", + "[more documentation](https://pyformat.info)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Replace with String - positional" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "My name is Alex.\n", + "My name is Alex Marshall.\n" + ] + } + ], + "source": [ + "first_name = 'Alex'\n", + "last_name = 'Marshall'\n", + "print('My name is {}.'.format(first_name))\n", + "print('My name is {} {}.'.format(first_name, last_name))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Replace with String using Index\n", + "Using indexes can be useful when order varies." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "My name is Alex Marshall.\n", + "My name is Marshall, Alex. First name Alex\n" + ] + } + ], + "source": [ + "print('My name is {0} {1}.'.format(first_name, last_name))\n", + "print('My name is {1}, {0}. First name {0}'.format(first_name, last_name))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Alignment: Align Left, Right, Middle\n", + "{:<} align Left (default is align left, so this is optional) \n", + "{:>n} align Right with n padding spaces \n", + "{:^n} align Middle with n padding spaces" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of cases: 5\n", + "Number of cases: 16\n", + "Number of cases: 294\n", + "Number of cases: 5\n", + "Number of cases: 16\n", + "Number of cases: 294\n" + ] + } + ], + "source": [ + "# align left - these both do the same thing\n", + "cases = [5, 16, 294]\n", + "for case in cases:\n", + " print('Number of cases: {}'.format(case))\n", + "for case in cases:\n", + " print('Number of cases: {:<}'.format(case))" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of cases: 5\n", + "Number of cases: 16\n", + "Number of cases: 294\n" + ] + } + ], + "source": [ + "# align right with 5 total spaces\n", + "for case in cases:\n", + " print('Number of cases:{:>5}'.format(case))" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of cases: 5 \n", + "Number of cases: 16 \n", + "Number of cases: 294 \n" + ] + } + ], + "source": [ + "# align center with 5 total spaces\n", + "for case in cases:\n", + " print('Number of cases:{:^5}'.format(case))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Integers & Floats\n", + "{:d} Integer variable \n", + "{:5d} Integer with padding of 5 \n", + "{:f} Floating point variable " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Length is 26.\n", + "Length is 26.\n", + "In dog years, I'm 8 .\n" + ] + } + ], + "source": [ + "length = 26\n", + "print('Length is {:d}.'.format(length))\n", + "\n", + "# align right, padding=6, integer\n", + "print('Length is {:>6d}.'.format(length))\n", + "\n", + "# named variable, align center, padding=4, integer\n", + "print(\"In dog years, I'm {age:^5d}.\".format(age=8))" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Distance to moon is 238,900 miles.\n" + ] + } + ], + "source": [ + "# integer with commas\n", + "print('Distance to moon is {:,d} miles.'.format(238900))" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Radius is 4.780000 inches.\n", + "Radius is 4.8 inches.\n", + "Radius is 0004.8 inches.\n", + "Radius is 4.78000 inches.\n" + ] + } + ], + "source": [ + "radius = 4.78\n", + "print('Radius is {:f} inches.'.format(radius))\n", + "\n", + "# round to 1 decimal place, float\n", + "print('Radius is {:.1f} inches.'.format(radius))\n", + "\n", + "# padding=6 (pads with leading 0's), round to 1 decimal\n", + "print('Radius is {:06.1f} inches.'.format(radius))\n", + "\n", + "# padding=5 decimal places\n", + "print('Radius is {:.5f} inches.'.format(radius))" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "A is +15. B is -9. C is 33.\n", + "A is +15. B is -9. B is -9.\n" + ] + } + ], + "source": [ + "# positive & negative signs\n", + "a, b, c = 15, -9, 33\n", + "print('A is {:+d}. B is {:+d}. C is {:-d}.'.format(a, b, c))\n", + "\n", + "# {+3d} shows pos or neg sign, padding=3. \n", + "# {: d} prints neg or a leading space if positive.\n", + "print('A is {:+3d}. B is {:+4d}. B is {: d}.'.format(a, b, b))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Named Placeholders\n", + "You can pass in named variables as keyword args, or as an unpacked dict. \n", + "And it's easy to pass in a list." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Mekael is a Carpenter.\n" + ] + } + ], + "source": [ + "print(\"{name} is a {job}.\".format(name='Mekael', job='Carpenter'))" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "ename": "KeyError", + "evalue": "'name'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mjob\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'Carpenter'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;31m# THIS DOES NOT WORK!\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"{name} is a {job}.\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mjob\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mKeyError\u001b[0m: 'name'" + ] + } + ], + "source": [ + "name = 'Mekael'\n", + "job = 'Carpenter'\n", + "# THIS DOES NOT WORK!\n", + "print(\"{name} is a {job}.\".format(name, job))" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Mekael is a Carpenter.\n" + ] + } + ], + "source": [ + "# This works great\n", + "print(\"{n} is a {j}.\".format(n=name, j=job))" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Mekael is a Carpenter.\n" + ] + } + ], + "source": [ + "# Or use a dictionary, and ** unpacks the dictionary.\n", + "jobs = {'name':'Mekael', 'job':'Carpenter'}\n", + "print(\"{name} is a {job}.\".format(**jobs))" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Score 2 is 96\n" + ] + } + ], + "source": [ + "# passing in a list is clean and easy\n", + "scores = [78, 96, 83, 86]\n", + "print('Score 2 is {s[1]}'.format(s = scores))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Scientific Notation\n", + "Use {:e}, or upper case E." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "My big number is 8.745770e+02\n", + "A bigger number is 6.022141E+23\n" + ] + } + ], + "source": [ + "print('My big number is {:e}'.format(874.577))\n", + "print('A bigger number is {:E}'.format(602214090000000000000000))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Binary & Hexadecimal\n", + "{:b} converts decimal to binary\n", + "{:x} converts decimal to hex. Or use upper case X for capitals." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The binary equivalent of 79 is 1001111\n", + "The Hexadecimal equivalent of 183 is B7\n" + ] + } + ], + "source": [ + "print('The binary equivalent of 79 is {:b}'.format(79))\n", + "print('The Hexadecimal equivalent of 183 is {:X}'.format(183))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Strings/Using Python Strings.ipynb b/Strings/Using Python Strings.ipynb new file mode 100644 index 00000000..19643b9c --- /dev/null +++ b/Strings/Using Python Strings.ipynb @@ -0,0 +1,518 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Using Strings in Python 3\n", + "[Python String docs](https://docs.python.org/3/library/string.html)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Creating Strings\n", + "Enclose a string in single or double quotes, or in triple single quotes. \n", + "And you can embed single quotes within double quotes, or double quotes within single quotes. " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tony Stark is Ironman.\n", + "Her book is called \"The Magician\".\n", + "Captain Rogers kicks butt.\n" + ] + } + ], + "source": [ + "s = 'Tony Stark is'\n", + "t = \"Ironman.\"\n", + "print(s, t)\n", + "u = 'Her book is called \"The Magician\".'\n", + "print(u)\n", + "v = '''Captain Rogers kicks butt.'''\n", + "print(v)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Type, Len, Split, Join\n", + "Get the number of characters in a string using len. \n", + "To get the number of words you have to split the string into a list. Split uses a space as its default, or you can split on any substring you like. \n", + "To reverse a split, use join(str)." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "13\n" + ] + } + ], + "source": [ + "print(type(s))\n", + "print(len(s))" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['Tony', 'Stark', 'is']\n", + "3\n", + "['Her book is c', 'lled \"The M', 'gici', 'n\".']\n", + "['you', 'are', 'so', 'pretty']\n", + "Just do it.\n" + ] + } + ], + "source": [ + "print(s.split())\n", + "print(len(s.split()))\n", + "print(u.split('a'))\n", + "print('you,are,so,pretty'.split(','))\n", + "print(' '.join(['Just', 'do', 'it.']))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Check if a substring is contained in a string\n", + "Use *in* or *not in*. \n", + "Startswith and Endswith are also useful boolean checks." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "False\n", + "True\n", + "True\n", + "True\n" + ] + } + ], + "source": [ + "print('dog' in s)\n", + "print('k' in t)\n", + "print('k' not in t)\n", + "print(s.startswith('Tony'))\n", + "print(s.endswith('is'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Replace all substrings\n", + "Second example iterates through a dictionary and replaces all instances of text numbers with numerals." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Captain America kicks butt.\n" + ] + } + ], + "source": [ + "v = v.replace('Rogers', 'America')\n", + "print(v)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Anton has 3 cars. Javier has 4.\n" + ] + } + ], + "source": [ + "z = 'Anton has three cars. Javier has four.'\n", + "numbers = {'one':'1', 'two':'2', 'three':'3', 'four':'4', 'five':'5'}\n", + "for k,v in numbers.items():\n", + " z = z.replace(k,v)\n", + "print(z)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Change case" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tony stark is\n", + "IRONMAN.\n", + "Her Book Is Called \"The Magician\".\n", + "Hulk rules!\n" + ] + } + ], + "source": [ + "print(s.lower())\n", + "print(t.upper())\n", + "print(u.title())\n", + "print('hulk rules!'.capitalize())" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "False\n", + "True\n", + "True\n" + ] + } + ], + "source": [ + "print('david'.islower())\n", + "print('hulk'.isupper())\n", + "print('Hulk'.istitle())\n", + "print('covid19'.isalnum())" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "False\n", + "True\n", + "False\n" + ] + } + ], + "source": [ + "print('Thor'.isalpha())\n", + "print('3.14'.isnumeric())\n", + "print('314'.isdigit())\n", + "print('3.14'.isdecimal())" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0123456789\n", + "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n", + "abcdefghijklmnopqrstuvwxyz\n", + "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" + ] + } + ], + "source": [ + "import string\n", + "print(string.digits)\n", + "print(string.punctuation)\n", + "print(string.ascii_lowercase)\n", + "print(string.ascii_uppercase)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Strip leading or trailing characters\n", + "This is often used to strip blank spaces or newlines, but can be used for much more." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Natasha is a spy.\n", + "Natasha is a spy \n", + "\n", + "\n", + " Natasha is a spy\n", + "Natasha is a spy. She has red hair.\n", + "She has red \n" + ] + } + ], + "source": [ + "w = '\\n Natasha is a spy \\n'\n", + "x = '\\nShe has red hair\\n'\n", + "\n", + "print(w.strip() + '.')\n", + "print(w.lstrip())\n", + "print(w.rstrip())\n", + "print(w.strip() + '. ' + x.strip() + '.')\n", + "print(x.strip().rstrip('arih'))" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "What do you want\n" + ] + } + ], + "source": [ + "y = 'What do you want?!!&?'\n", + "print(y.rstrip(string.punctuation))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Find, and Count substrings\n", + "Search from the left with find, or from the right with rfind. \n", + "The return value is the start index of the first match of the substring." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n", + "5\n", + "What do you want?!!&?\n" + ] + } + ], + "source": [ + "print(y.find('a'))\n", + "print(y.rfind('do'))\n", + "print(y)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Natasha is a spy\n", + "4\n" + ] + } + ], + "source": [ + "print(w.strip())\n", + "print(w.count('a'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Strings are immutable\n", + "Any change to a string results in a new string being written to a new block of memory. " + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4565794160\n", + "4565793776\n" + ] + } + ], + "source": [ + "m = 'Black widow'\n", + "print(id(m))\n", + "m = m + 's'\n", + "print(id(m))" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tony Stark is Ironman.\n", + "Tony Stark is Ironman.\n" + ] + } + ], + "source": [ + "print(s, t)\n", + "z = s + ' ' + t\n", + "print(z)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Slicing Substrings\n", + "string[from:to+1:step]\n", + "Only 1 parameter: it is used as an index. \n", + "From defaults to beginning. \n", + "To defaults to end. \n", + "Step defaults to 1." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "567\n" + ] + } + ], + "source": [ + "z = '0123456789'\n", + "print(z[1])\n", + "print(z[5:8])" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "012\n", + "789\n", + "89\n", + "24\n" + ] + } + ], + "source": [ + "print(z[:3])\n", + "print(z[7:])\n", + "print(z[-2:])\n", + "print(z[2:5:2])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Strings/bands.txt b/Strings/bands.txt new file mode 100644 index 00000000..7148cf12 --- /dev/null +++ b/Strings/bands.txt @@ -0,0 +1,38 @@ +Rolling Stones +Lady Gaga +Jackson Browne +Maroon 5 +Arijit Singh +Elton John +John Mayer +CCR +Eagles +Pink +Aerosmith +Adele +Taylor Swift +Faye Wong +UB40 +ColdPlay +Boston +4 Non Blondes +The Cars +Cheap Trick +Def Leppard +Ed Sheeran +Dire Straits +Train +Tom Petty +One Direction +Jimmy Buffett +Mumford & Sons +Phil Collins +Rod Stewart +The Script +Elvis +U2 +Simon & Garfunkel +Michael Buble +Abba +The Jackson 5 +R.E.M. \ No newline at end of file diff --git a/Tensorflow_Keras/TensorFlow Tutorial with MNIST Dataset.ipynb b/Tensorflow_Keras/TensorFlow Tutorial with MNIST Dataset.ipynb new file mode 100644 index 00000000..49cb48ed --- /dev/null +++ b/Tensorflow_Keras/TensorFlow Tutorial with MNIST Dataset.ipynb @@ -0,0 +1,337 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# TensorFlow Tutorial with MNIST Dataset\n", + "**About the MNIST dataset**. \n", + "MNIST is the equivalent *Hello World* of image analysis.\n", + "It consists of hand written numbers, 0-9, in 28x28 pixel squares. \n", + "Each gray-scale pixel contains an integer 0-255 to indicate darkness, with 0 white and 255 black. \n", + "There are about 60,000 training records, and about 10,000 test records. \n", + "In other words, the images of numbers have already been transformed into arrays of ints to make them easier to use for ML projects. You can find more info on the dataset [here](http://yann.lecun.com/exdb/mnist/). You can also download it from [here](https://s3.amazonaws.com/img-datasets/mnist.pkl.gz).\n", + "## 1. Load Data into a Numpy Array \n", + "I downloaded the data file onto my desktop and loaded it locally. \n", + "You can also load it directly from the cloud as follows: \n", + "```mnist = tf.keras.datasets.mnist \n", + "(x_train, y_train), (x_test, y_test) = mnist.load_data() \n", + "``` \n", + "**After the load:** \n", + "x_train contains 60k arrays of 28x28. \n", + "The y_train vector contains the corresponding labels for these. \n", + "x_test contains 10k arrays of 28x28. \n", + "The y_test vector contains the corresponding labels for these." + ] + }, + { + "cell_type": "code", + "execution_count": 218, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 47040000 (60000, 28, 28)\n", + " 60000 (60000,)\n", + " 7840000 (10000, 28, 28)\n", + " 10000 (10000,)\n", + "8 2\n" + ] + } + ], + "source": [ + "import pickle\n", + "import numpy as np\n", + "\n", + "with open('/Users/joejames/desktop/mnist.pkl', 'rb') as f:\n", + " (x_train, y_train), (x_test, y_test) = pickle.load(f, encoding='latin1')\n", + " \n", + "print(type(x_train), x_train.size, x_train.shape)\n", + "print(type(y_train), y_train.size, y_train.shape)\n", + "print(type(x_test), x_test.size, x_test.shape)\n", + "print(type(y_test), y_test.size, y_test.shape)\n", + "print(y_train[55], y_test[583])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Use Matplotlib to visualize one record. \n", + "I set the colormap to Greys. There are a bunch of other colormap choices if you like bright visualizations. Try magma or any of the other colormap choice in the [docs](https://matplotlib.org/tutorials/colors/colormaps.html)." + ] + }, + { + "cell_type": "code", + "execution_count": 217, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 217, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.cm as cm\n", + "import matplotlib.pyplot as plt\n", + "\n", + "plt.imshow(x_train[55].reshape(28, 28), cmap=cm.Greys)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Plot a bunch of records to see sample data \n", + "Basically, use the same Matplotlib commands above in a for loop to show 18 records from the train set in a subplot figure. We also make the figsize a bit bigger and remove the tick marks for readability." + ] + }, + { + "cell_type": "code", + "execution_count": 213, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 213, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAgsAAAEdCAYAAACCOCTVAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAAIABJREFUeJzt3Xu81VP+x/H3mS6SJLoQ4bhEJSSJqYxIaRQJFVNyp1zLNX4mUkY0aZLcScgkRoZhcilSIYoowkzkNrocl8g9zu8Pj8/a69veZ5199jn7/nr+0+exzt77rL5nn33W97PW+qyS8vJyAQAAVOR32e4AAADIbQwWAABAEIMFAAAQxGABAAAEMVgAAABBDBYAAEAQgwUAABDEYAEAAAQxWAAAAEEMFgAAQFDtqjy4SZMm5aWlpWnqSn5buXKlysrKSlJ5Ltc1bPHixWXl5eVNq/o8rmsY1zU9uK7pwXVNj2Sva5UGC6WlpVq0aFHqvSpgHTp0SPm5XNewkpKSD1N5Htc1jOuaHlzX9OC6pkey15VpCAAAEMRgAQAABDFYAAAAQQwWAABAEIMFAAAQxGABAAAEMVgAAABBVaqzgOLz8ccfS5ImTpzo2iZMmCBJGj58uGs7//zzJUnbb799BnsHAMgEMgsAACCIwQIAAAjKm2mIX3/9VZL0448/Bh83depUF3/77beSpLffftu1/e1vf5MkXX755a7tpptucvGmm24qSRo/frxrGzp0aKrdzkuffvqpi/fZZx9J0ldffeXaSkp+OwLDrqUUu+5r167NRBeLzvLly1186KGHunjJkiWSpKZNq1wyv+jccccdLh4yZIik2OeKJL377rsu3m233TLXMRQt+3v2888/u7b58+dLin4On3jiiZKk2rWz9yebzAIAAAjKemZh3bp1kqRffvnFtb3xxhuSpKefftq12Z3t7bffXuXv4Z84duGFF0qS7rrrLte2xRZbuPjAAw+UJB1yyCFV/j757MMPY2eJdO3a1cVffvmlpFg2QYpdr0022cS1rVmzRpL0/vvvu7Ydd9zRxbVq1arZDteg//znPy62/2/Hjh2z1Z2EFi5c6OJu3bplsSf5Z/bs2ZKkCy64wLX97nfx90n+exyoSX5m1s9az5kzR1L09zsRyzKMHDkyDb1LDpkFAAAQxGABAAAEZWUa4pNPPnFxu3btJMXSvzXJUo3+lIMtYDz11FNdW7NmzVzcoEEDSYW9YMxfTGPTDz179nRtVluhIvYzu+aaa1xbly5dJEktW7Z0bf6UkX+9c42lqSXpnXfekZQ70xDl5eWSolMl7733Xra6k5fsev3www9Z7knuWrlypSTpnnvucW2zZs1y8auvvhr3nGnTpkmK1lZ55plnJEknnXSSa/OngYuBv8jb6tP4dWq+//57F9vv90477eTaGjduLElavHixa7vtttskRRfbZ/pvFJkFAAAQxGABAAAEZWUawtIskrT11ltLSm0aokePHnGv+cgjj7g2W63vr+6HdPHFF7vYrzGRrLlz50qK1bGQpL59+0qKXv/XX3891S5m1I033uhi/z2VC9avXy9Juvbaa12bldaWCnu6rDr82ipXXXVV3Nfbt28vKbrjarPNNkt7v3LJggULXNy/f39J0urVq12bpcgl6eijj5YUnaIcNGhQ3Gvac/xU/OTJk2uox7nHn9oaM2aMJOmWW25xbbbbryJ77rmnpNhnqiRt2LBBUuxvoxT7ufivxzQEAADIKVnJLNgiQym2oObhhx92bb///e8lScccc0zcc20hnST985//dHHdunUlSatWrXJt/qISxO4K7r//ftfm3z0YyxJIsZ+BfxdhC5pat27t2i699FJJ0Z9jotfORX6Nj1xjlQZ9/nVH1H//+19J0uGHH+7avvjii7jHjR07VlK0xkoh8ytV2mLGXr16uTbLYB111FGuze6UpdjCZf935ZRTTpEkTZ8+Pe77derUqQZ6nfv87Iy9pyrTpk0bF7/wwguSpIYNG7q2zz//vIZ6V7PILAAAgCAGCwAAICjr5Z73228/SdJee+3l2mxK4ZJLLnFt119/vSRp9OjRcY/zbbPNNi72F4UVq2QPhRo4cKBr8w/csYVifttxxx0nSapfv75r23bbbSVFy+jed999Lh4xYoSk6J7sbPvf//4nKXqNck2iFHr37t2z0JP8cOedd0pKXCvEFulJ0sEHH5yxPuWC5557zsWHHXZY3NcHDBggSbr77rtdm1/O3dghR1Li6QerqeBPZRYyvy5FInYgmX98gF+fxp9+MH7p/VxCZgEAAARlPbNgEo1it9xyy7g2f5ubHfokcQjMxsrKyiRJ1113nWuz7an+lhyrHOZXBvMzNlat0f6tiu+++87F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rLy8vGlVn8d1DeO6pgfXNT24rumR7HWt0mChtLRUixYtSr1XBaxDhw4pP5frGlZSUvJhKs/juoZxXdOD65oeXNf0SPa6Mg0BAACCGCwAAIAgBgsAACCIwQIAAAhisAAAAIIYLAAAgCAGCwAAIKhKdRayafTo0ZKkkSNHuraOHTu6+Omnn5YkbbHFFpntGICC069fP0lSeXm5a3v44Yez1Z20WL16tYufeuopSdLYsWNd2yGHHOJi/7PWDBw4UJJUq1atdHUROYTMAgAACGKwAAAAgnJ6GuKrr75y8Y033ihJ+t3vYuObxYsXu/ijjz6SJO25554Z6l3+Kisrc/GGDRskSa+88opr69Onj4v9652Mk08+2cW33Xabi4stVfnLL79IklasWOHahg0b5uInn3wy431C2DXXXOPiJ554QpI0fPjwbHUnbf71r39Jkv70pz+5tm+++SbuccuXL3fx5MmT475uUxOtWrWq6S4iB5FZAAAAQTmdWahfv76LjzzySEnSPffck6Xe5KdVq1a5+N5775Uk3X777a7t119/lRTLzEjRbEJJSdUO0vR/PltuuaWLx4wZI0naZJNNqvR6+erHH3+UFL3ratGihYvXr18vSWrQoEFmO4aI8ePHu9jPLNStW1eS1KtXr4z3Kd26desmKfreS5RZqEznzp0lSXPnznVtbdu2rWbvkKvILAAAgCAGCwAAICinpyEsFShJO+20UxZ7kr9GjBjh4vvvvz+j33vChAkuHjJkiCRpl112yWgfcsknn3zi4nXr1kliGiLb5s+f7+KffvrJxUcccYQkqVOnThnvU7ptuummkqILkI8//nhJ0rfffuvadt55Zxe///77ca/zxRdfSJIef/xx18Y0RHrZ54YUfb/OmDFDUmy612f1MCTpr3/9a8rfm8wCAAAIYrAAAACCcnoa4ocffnDx66+/nsWe5C9Lp0qJpyG23XZbSdJFF13k2myHhJS4zsK8efMkSTNnzqyxfhYDv3QwUvOf//xHUrTs+9133+1iS7FXxt7DL774omtr06aNi/0ptELlfzbsvffekqLXo0mTJi5ONA1hbIoRNevtt9928fTp0yVF6118+eWXLg7tWps9e3aN9IfMAgAACMrpzMLPP//sYn+UlcjLL78sSdphhx1cG4dKSX379nWxLUjyWeagKgvtzjzzTElS69atXZtf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hg2ubcWKFRnvEwAgM8gsAACAIAYLAAAgiGkIBI0aNUqSdOutt7q2tWvXSpIGDx6clT4BADKLzAIAAAgiswBJ0rfffuvifv36ufipp56SJJWUxOpN7b///pKkyZMnZ6h3AIBsIrMAAACCGCwAAICgGp2G+OmnnyRJzz33nGvbdNNNJUkLFixwbevWrXPxpEmTJEl9+/Z1bS1atEjq+2233XYu7tOnjyRphx12qGq3i5rVT7joootc29NPPx33uClTprh4v/32kxT72eI35eXlLj7nnHMkSdOmTXNtH330kYsbNmyYuY4BCTz//PMunjkxxI5yAAAOVklEQVRzpiTp5Zdfdm2vv/563HP++Mc/uvjBBx+UJNWrVy9NPYSxv609e/Z0bX5tmzfeeEOS1KhRo7T1gcwCAAAIqtHMwsSJEyVJl156aZWf+8ADD1Trew8fPlxS9ECn008/XZJ0zDHHuLZ0jrzy0ddffy1Juv/++4OP809ta9WqVTq7lLf8ipZPPPGEpNj1laQXX3zRxf4dApBu3333nYst6zV16lTXttVWW0mKZg523313Fz/66KOSpMcff9y1derUSZL02muvpaHHxeGbb76J/OvbbLPNXLx48WJJ0WzQ3nvv7eJMZHnJLAAAgCAGCwAAIKhGpyH8RXAhzZo1c/GBBx6Y1HNat24tSVq+fLlrW7NmjYvnzZsnSXrllVdcm8X77ruva2vXrl1S36+Q+YdCWdrRX5znW7hwoaTo9A4Sq1OnjovtevmLGj/99NOM96nY2HTmDz/84NqWLl0qSbrxxhvjHr/PPvu4eNGiRWnuXfb06tXLxW+//bYkady4ca5t6NChkipOZ1vV1pYtW7q2N998U1K0uuuQIUNqqMf567PPPnOxvedWrlyZ8LE2vZDoIL7x48e72N7D/ue0/7P49ddfU+9wksgsAACAIAYLAAAgqEanIebPny8pmnpNVPegbt26Lm7QoEHK3+/HH3908R577CFJev/99+Me99BDD7mYaQjp73//u4st/TVo0CDXdtNNN7l48803z1zHCsjFF18sSXrkkUdc27Jly7LVnYLx3nvvSYql0qVYSXJJuvPOOyUlnlbzS5YbS6VLUvv27V1cKCv833rrLUnSCy+84NpsyuGCCy5I+nWaNm0qSRozZoxrO++88yRJN9xwg2tjGiJaU+j6668PPtZq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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "images = x_train[0:18]\n", + "fig, axes = plt.subplots(3, 6, figsize=[9,5])\n", + "\n", + "for i, ax in enumerate(axes.flat):\n", + " ax.imshow(x_train[i].reshape(28, 28), cmap=cm.Greys)\n", + " ax.set_xticks([])\n", + " ax.set_yticks([])\n", + "plt.show" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. Show distribution of training data labels \n", + "The training data is about evenly distributed across all nine digits. " + ] + }, + { + "cell_type": "code", + "execution_count": 214, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5923 6742 5958 6131 5842 5421 5918 6265 5851 5949]\n" + ] + } + ], + "source": [ + "counts = np.bincount(y_train)\n", + "nums = np.arange(len(counts))\n", + "plt.bar(nums, counts)\n", + "plt.show()\n", + "print(counts)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Apply Keras/TensorFlow neural network \n", + "Use tensorflow to train the model with 60k training records, compile the model, and classify 10k test records with 98% accuracy. \n", + "**Create the model** \n", + "Build the keras model by stacking layers into the network. Our model here has four layers:\n", + "- Flatten reshapes the data into a 1-dimensional array\n", + "- [Dense](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Dense) tells the model to use output arrays of shape (*, 512) and sets rectified linear [activation function](https://keras.io/activations/). \n", + "- [Dropout](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Dropout) applies dropout to the input to help avoid overfitting.\n", + "- The next Dense line condenses the ouput into probabilities for each of the 10 digits.\n", + "\n", + "**Compile the model** \n", + "- [Adam](https://keras.io/optimizers/) is an optimization algorithm that uses stochastic gradient descent to update network weights.\n", + "- Sparse categorical crossentropy is a [loss function](https://keras.io/losses/) that is required to compile the model. The loss function measures how accurate the model is during training. We want to minimize this function to steer the model in the right direction.\n", + "- A metric is a function that is used to judge the performance of your model. We're using accuracy of our predictions as compared to y_test as our metric. \n", + "Lastly, we fit our training data into the model, with several training repetitions (epochs), then evaluate our test data. \n", + "\n", + "Our final result is about 98% accuracy in classifying 10k digits in the test set. You can try tweaking this model with different settings to get a better score. An easy tweak is increasing the epochs, which improves accuracy at the expense of time. Follow the links to the Keras layer docs above and try different options for Dense output, activation functions, optimization algorithms and loss functions." + ] + }, + { + "cell_type": "code", + "execution_count": 215, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/4\n", + "60000/60000 [==============================] - 5s 89us/sample - loss: 0.2581 - acc: 0.9244\n", + "Epoch 2/4\n", + "60000/60000 [==============================] - 5s 83us/sample - loss: 0.1180 - acc: 0.9644\n", + "Epoch 3/4\n", + "60000/60000 [==============================] - 5s 81us/sample - loss: 0.0867 - acc: 0.9736\n", + "Epoch 4/4\n", + "60000/60000 [==============================] - 5s 82us/sample - loss: 0.0697 - acc: 0.9785\n", + "10000/10000 [==============================] - 1s 59us/sample - loss: 0.0662 - acc: 0.9791\n" + ] + }, + { + "data": { + "text/plain": [ + "[0.0662360069771763, 0.9791]" + ] + }, + "execution_count": 215, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import tensorflow as tf\n", + "# Disable some deprecated error messages\n", + "tf.logging.set_verbosity(tf.logging.ERROR)\n", + "\n", + "# Normalize the data to a 0.0 to 1.0 scale for faster processing\n", + "x_train, x_test = x_train / 255.0, x_test / 255.0\n", + "\n", + "model = tf.keras.models.Sequential([\n", + " tf.keras.layers.Flatten(input_shape=(28, 28)),\n", + " tf.keras.layers.Dense(256, activation=tf.nn.relu),\n", + " tf.keras.layers.Dropout(0.25),\n", + " tf.keras.layers.Dense(10, activation=tf.nn.softmax)\n", + "])\n", + " \n", + "model.compile(optimizer='adam',\n", + " loss='sparse_categorical_crossentropy',\n", + " metrics=['accuracy'])\n", + "\n", + "model.fit(x_train, y_train, epochs=4)\n", + "model.evaluate(x_test, y_test)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. Generate predictions for test set \n", + "Our predictions are in the form of a list of 10 floats, with probabilities for each value. We can get the prediction by picking the index of the list item with the highest probability. And we can visualize that item to verify our prediction." + ] + }, + { + "cell_type": "code", + "execution_count": 216, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5.5930052e-09 1.6970777e-15 2.4897268e-10 2.3935108e-14 7.2053798e-09\n", + " 4.4642620e-10 1.0000000e+00 8.1785776e-12 2.4993282e-10 2.6947859e-13]\n", + "6\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 216, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "predictions = model.predict(x_test)\n", + "print(predictions[88])\n", + "print(np.argmax(predictions[88]))\n", + "plt.imshow(x_test[88].reshape(28, 28), cmap=cm.Greys)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/2-3_tree.py b/Trees/2-3_tree.py similarity index 96% rename from 2-3_tree.py rename to Trees/2-3_tree.py index f78fae13..9dc3bf5b 100644 --- a/2-3_tree.py +++ b/Trees/2-3_tree.py @@ -1,144 +1,144 @@ -# 2-3 Tree -# balanced tree data structure with up to 2 data items per node - -class Node: - def __init__(self, data, par = None): - #print ("Node __init__: " + str(data)) - self.data = list([data]) - self.parent = par - self.child = list() - - def __str__(self): - if self.parent: - return str(self.parent.data) + ' : ' + str(self.data) - return 'Root : ' + str(self.data) - - def __lt__(self, node): - return self.data[0] < node.data[0] - - def _isLeaf(self): - return len(self.child) == 0 - - # merge new_node sub-tree into self node - def _add(self, new_node): - # print ("Node _add: " + str(new_node.data) + ' to ' + str(self.data)) - for child in new_node.child: - child.parent = self - self.data.extend(new_node.data) - self.data.sort() - self.child.extend(new_node.child) - if len(self.child) > 1: - self.child.sort() - if len(self.data) > 2: - self._split() - - # find correct node to insert new node into tree - def _insert(self, new_node): - # print ('Node _insert: ' + str(new_node.data) + ' into ' + str(self.data)) - - # leaf node - add data to leaf and rebalance tree - if self._isLeaf(): - self._add(new_node) - - # not leaf - find correct child to descend, and do recursive insert - elif new_node.data[0] > self.data[-1]: - self.child[-1]._insert(new_node) - else: - for i in range(0, len(self.data)): - if new_node.data[0] < self.data[i]: - self.child[i]._insert(new_node) - break - - # 3 items in node, split into new sub-tree and add to parent - def _split(self): - # print("Node _split: " + str(self.data)) - left_child = Node(self.data[0], self) - right_child = Node(self.data[2], self) - if self.child: - self.child[0].parent = left_child - self.child[1].parent = left_child - self.child[2].parent = right_child - self.child[3].parent = right_child - left_child.child = [self.child[0], self.child[1]] - right_child.child = [self.child[2], self.child[3]] - - self.child = [left_child] - self.child.append(right_child) - self.data = [self.data[1]] - - # now have new sub-tree, self. need to add self to its parent node - if self.parent: - if self in self.parent.child: - self.parent.child.remove(self) - self.parent._add(self) - else: - left_child.parent = self - right_child.parent = self - - # find an item in the tree; return item, or False if not found - def _find(self, item): - # print ("Find " + str(item)) - if item in self.data: - return item - elif self._isLeaf(): - return False - elif item > self.data[-1]: - return self.child[-1]._find(item) - else: - for i in range(len(self.data)): - if item < self.data[i]: - return self.child[i]._find(item) - - def _remove(self, item): - pass - - # print preorder traversal - def _preorder(self): - print (self) - for child in self.child: - child._preorder() - -class Tree: - def __init__(self): - print("Tree __init__") - self.root = None - - def insert(self, item): - print("Tree insert: " + str(item)) - if self.root is None: - self.root = Node(item) - else: - self.root._insert(Node(item)) - while self.root.parent: - self.root = self.root.parent - return True - - def find(self, item): - return self.root._find(item) - - def remove(self, item): - self.root.remove(item) - - def printTop2Tiers(self): - print ('----Top 2 Tiers----') - print (str(self.root.data)) - for child in self.root.child: - print (str(child.data), end=' ') - print(' ') - - def preorder(self): - print ('----Preorder----') - self.root._preorder() - -tree = Tree() - -lst = [13, 7, 24, 15, 4, 29, 20, 16, 19, 1, 5, 22, 17] -for item in lst: - tree.insert(item) -tree.printTop2Tiers() - -# for i in range (25): - # tree.insert(i) - # tree.printTop2Tiers() -# tree.preorder() -# print (tree.find(16)) +# 2-3 Tree +# balanced tree data structure with up to 2 data items per node + +class Node: + def __init__(self, data, par = None): + #print ("Node __init__: " + str(data)) + self.data = list([data]) + self.parent = par + self.child = list() + + def __str__(self): + if self.parent: + return str(self.parent.data) + ' : ' + str(self.data) + return 'Root : ' + str(self.data) + + def __lt__(self, node): + return self.data[0] < node.data[0] + + def _isLeaf(self): + return len(self.child) == 0 + + # merge new_node sub-tree into self node + def _add(self, new_node): + # print ("Node _add: " + str(new_node.data) + ' to ' + str(self.data)) + for child in new_node.child: + child.parent = self + self.data.extend(new_node.data) + self.data.sort() + self.child.extend(new_node.child) + if len(self.child) > 1: + self.child.sort() + if len(self.data) > 2: + self._split() + + # find correct node to insert new node into tree + def _insert(self, new_node): + # print ('Node _insert: ' + str(new_node.data) + ' into ' + str(self.data)) + + # leaf node - add data to leaf and rebalance tree + if self._isLeaf(): + self._add(new_node) + + # not leaf - find correct child to descend, and do recursive insert + elif new_node.data[0] > self.data[-1]: + self.child[-1]._insert(new_node) + else: + for i in range(0, len(self.data)): + if new_node.data[0] < self.data[i]: + self.child[i]._insert(new_node) + break + + # 3 items in node, split into new sub-tree and add to parent + def _split(self): + # print("Node _split: " + str(self.data)) + left_child = Node(self.data[0], self) + right_child = Node(self.data[2], self) + if self.child: + self.child[0].parent = left_child + self.child[1].parent = left_child + self.child[2].parent = right_child + self.child[3].parent = right_child + left_child.child = [self.child[0], self.child[1]] + right_child.child = [self.child[2], self.child[3]] + + self.child = [left_child] + self.child.append(right_child) + self.data = [self.data[1]] + + # now have new sub-tree, self. need to add self to its parent node + if self.parent: + if self in self.parent.child: + self.parent.child.remove(self) + self.parent._add(self) + else: + left_child.parent = self + right_child.parent = self + + # find an item in the tree; return item, or False if not found + def _find(self, item): + # print ("Find " + str(item)) + if item in self.data: + return item + elif self._isLeaf(): + return False + elif item > self.data[-1]: + return self.child[-1]._find(item) + else: + for i in range(len(self.data)): + if item < self.data[i]: + return self.child[i]._find(item) + + def _remove(self, item): + pass + + # print preorder traversal + def _preorder(self): + print (self) + for child in self.child: + child._preorder() + +class Tree: + def __init__(self): + print("Tree __init__") + self.root = None + + def insert(self, item): + print("Tree insert: " + str(item)) + if self.root is None: + self.root = Node(item) + else: + self.root._insert(Node(item)) + while self.root.parent: + self.root = self.root.parent + return True + + def find(self, item): + return self.root._find(item) + + def remove(self, item): + self.root.remove(item) + + def printTop2Tiers(self): + print ('----Top 2 Tiers----') + print (str(self.root.data)) + for child in self.root.child: + print (str(child.data), end=' ') + print(' ') + + def preorder(self): + print ('----Preorder----') + self.root._preorder() + +tree = Tree() + +lst = [13, 7, 24, 15, 4, 29, 20, 16, 19, 1, 5, 22, 17] +for item in lst: + tree.insert(item) +tree.printTop2Tiers() + +# for i in range (25): + # tree.insert(i) + # tree.printTop2Tiers() +# tree.preorder() +# print (tree.find(16)) diff --git a/Trees/BST_Height_Size.pptx b/Trees/BST_Height_Size.pptx new file mode 100644 index 00000000..572bb448 Binary files /dev/null and b/Trees/BST_Height_Size.pptx differ diff --git a/BinarySearchTree.py b/Trees/BinarySearchTree.py similarity index 95% rename from BinarySearchTree.py rename to Trees/BinarySearchTree.py index 40d6ee8f..c1e34b82 100644 --- a/BinarySearchTree.py +++ b/Trees/BinarySearchTree.py @@ -1,214 +1,214 @@ -# Binary Search Tree in Python - -class Node: - def __init__(self, val): - self.value = val - self.leftChild = None - self.rightChild = None - - def insert(self, data): - if self.value == data: - return False - - elif self.value > data: - if self.leftChild: - return self.leftChild.insert(data) - else: - self.leftChild = Node(data) - return True - - else: - if self.rightChild: - return self.rightChild.insert(data) - else: - self.rightChild = Node(data) - return True - - def find(self, data): - if(self.value == data): - return True - elif self.value > data: - if self.leftChild: - return self.leftChild.find(data) - else: - return False - else: - if self.rightChild: - return self.rightChild.find(data) - else: - return False - - def getHeight(self): - if self.leftChild and self.rightChild: - return 1 + max(self.leftChild.getHeight(), self.rightChild.getHeight()) - elif self.leftChild: - return 1 + self.leftChild.getHeight() - elif self.rightChild: - return 1 + self.rightChild.getHeight() - else: - return 1 - - def preorder(self): - if self: - print (str(self.value)) - if self.leftChild: - self.leftChild.preorder() - if self.rightChild: - self.rightChild.preorder() - - def postorder(self): - if self: - if self.leftChild: - self.leftChild.postorder() - if self.rightChild: - self.rightChild.postorder() - print (str(self.value)) - - def inorder(self): - if self: - if self.leftChild: - self.leftChild.inorder() - print (str(self.value)) - if self.rightChild: - self.rightChild.inorder() - -class Tree: - def __init__(self): - self.root = None - - def insert(self, data): - if self.root: - return self.root.insert(data) - else: - self.root = Node(data) - return True - - def find(self, data): - if self.root: - return self.root.find(data) - else: - return False - - def getHeight(self): - if self.root: - return self.root.getHeight() - else: - return -1 - - def remove(self, data): - # empty tree - if self.root is None: - return False - - # data is in root node - elif self.root.value == data: - if self.root.leftChild is None and self.root.rightChild is None: - self.root = None - elif self.root.leftChild and self.root.rightChild is None: - self.root = self.root.leftChild - elif self.root.leftChild is None and self.root.rightChild: - self.root = self.root.rightChild - elif self.root.leftChild and self.root.rightChild: - delNodeParent = self.root - delNode = self.root.rightChild - while delNode.leftChild: - delNodeParent = delNode - delNode = delNode.leftChild - - self.root.value = delNode.value - if delNode.rightChild: - if delNodeParent.value > delNode.value: - delNodeParent.leftChild = delNode.rightChild - elif delNodeParent.value < delNode.value: - delNodeParent.rightChild = delNode.rightChild - else: - if delNode.value < delNodeParent.value: - delNodeParent.leftChild = None - else: - delNodeParent.rightChild = None - - return True - - parent = None - node = self.root - - # find node to remove - while node and node.value != data: - parent = node - if data < node.value: - node = node.leftChild - elif data > node.value: - node = node.rightChild - - # case 1: data not found - if node is None or node.value != data: - return False - - # case 2: remove-node has no children - elif node.leftChild is None and node.rightChild is None: - if data < parent.value: - parent.leftChild = None - else: - parent.rightChild = None - return True - - # case 3: remove-node has left child only - elif node.leftChild and node.rightChild is None: - if data < parent.value: - parent.leftChild = node.leftChild - else: - parent.rightChild = node.leftChild - return True - - # case 4: remove-node has right child only - elif node.leftChild is None and node.rightChild: - if data < parent.value: - parent.leftChild = node.rightChild - else: - parent.rightChild = node.rightChild - return True - - # case 5: remove-node has left and right children - else: - delNodeParent = node - delNode = node.rightChild - while delNode.leftChild: - delNodeParent = delNode - delNode = delNode.leftChild - - node.value = delNode.value - if delNode.rightChild: - if delNodeParent.value > delNode.value: - delNodeParent.leftChild = delNode.rightChild - elif delNodeParent.value < delNode.value: - delNodeParent.rightChild = delNode.rightChild - else: - if delNode.value < delNodeParent.value: - delNodeParent.leftChild = None - else: - delNodeParent.rightChild = None - - def preorder(self): - if self.root is not None: - print("PreOrder") - self.root.preorder() - - def postorder(self): - if self.root is not None: - print("PostOrder") - self.root.postorder() - - def inorder(self): - if self.root is not None: - print("InOrder") - self.root.inorder() - -bst = Tree() -print(bst.insert(10)) -#print(bst.insert(5)) -bst.preorder() -print(bst.getHeight()) -#bst.postorder() -#bst.inorder() -print(bst.remove(10)) +# Binary Search Tree in Python + +class Node: + def __init__(self, val): + self.value = val + self.leftChild = None + self.rightChild = None + + def insert(self, data): + if self.value == data: + return False + + elif self.value > data: + if self.leftChild: + return self.leftChild.insert(data) + else: + self.leftChild = Node(data) + return True + + else: + if self.rightChild: + return self.rightChild.insert(data) + else: + self.rightChild = Node(data) + return True + + def find(self, data): + if(self.value == data): + return True + elif self.value > data: + if self.leftChild: + return self.leftChild.find(data) + else: + return False + else: + if self.rightChild: + return self.rightChild.find(data) + else: + return False + + def getHeight(self): + if self.leftChild and self.rightChild: + return 1 + max(self.leftChild.getHeight(), self.rightChild.getHeight()) + elif self.leftChild: + return 1 + self.leftChild.getHeight() + elif self.rightChild: + return 1 + self.rightChild.getHeight() + else: + return 1 + + def preorder(self): + if self: + print (str(self.value)) + if self.leftChild: + self.leftChild.preorder() + if self.rightChild: + self.rightChild.preorder() + + def postorder(self): + if self: + if self.leftChild: + self.leftChild.postorder() + if self.rightChild: + self.rightChild.postorder() + print (str(self.value)) + + def inorder(self): + if self: + if self.leftChild: + self.leftChild.inorder() + print (str(self.value)) + if self.rightChild: + self.rightChild.inorder() + +class Tree: + def __init__(self): + self.root = None + + def insert(self, data): + if self.root: + return self.root.insert(data) + else: + self.root = Node(data) + return True + + def find(self, data): + if self.root: + return self.root.find(data) + else: + return False + + def getHeight(self): + if self.root: + return self.root.getHeight() + else: + return -1 + + def remove(self, data): + # empty tree + if self.root is None: + return False + + # data is in root node + elif self.root.value == data: + if self.root.leftChild is None and self.root.rightChild is None: + self.root = None + elif self.root.leftChild and self.root.rightChild is None: + self.root = self.root.leftChild + elif self.root.leftChild is None and self.root.rightChild: + self.root = self.root.rightChild + elif self.root.leftChild and self.root.rightChild: + delNodeParent = self.root + delNode = self.root.rightChild + while delNode.leftChild: + delNodeParent = delNode + delNode = delNode.leftChild + + self.root.value = delNode.value + if delNode.rightChild: + if delNodeParent.value > delNode.value: + delNodeParent.leftChild = delNode.rightChild + elif delNodeParent.value < delNode.value: + delNodeParent.rightChild = delNode.rightChild + else: + if delNode.value < delNodeParent.value: + delNodeParent.leftChild = None + else: + delNodeParent.rightChild = None + + return True + + parent = None + node = self.root + + # find node to remove + while node and node.value != data: + parent = node + if data < node.value: + node = node.leftChild + elif data > node.value: + node = node.rightChild + + # case 1: data not found + if node is None or node.value != data: + return False + + # case 2: remove-node has no children + elif node.leftChild is None and node.rightChild is None: + if data < parent.value: + parent.leftChild = None + else: + parent.rightChild = None + return True + + # case 3: remove-node has left child only + elif node.leftChild and node.rightChild is None: + if data < parent.value: + parent.leftChild = node.leftChild + else: + parent.rightChild = node.leftChild + return True + + # case 4: remove-node has right child only + elif node.leftChild is None and node.rightChild: + if data < parent.value: + parent.leftChild = node.rightChild + else: + parent.rightChild = node.rightChild + return True + + # case 5: remove-node has left and right children + else: + delNodeParent = node + delNode = node.rightChild + while delNode.leftChild: + delNodeParent = delNode + delNode = delNode.leftChild + + node.value = delNode.value + if delNode.rightChild: + if delNodeParent.value > delNode.value: + delNodeParent.leftChild = delNode.rightChild + elif delNodeParent.value < delNode.value: + delNodeParent.rightChild = delNode.rightChild + else: + if delNode.value < delNodeParent.value: + delNodeParent.leftChild = None + else: + delNodeParent.rightChild = None + + def preorder(self): + if self.root is not None: + print("PreOrder") + self.root.preorder() + + def postorder(self): + if self.root is not None: + print("PostOrder") + self.root.postorder() + + def inorder(self): + if self.root is not None: + print("InOrder") + self.root.inorder() + +bst = Tree() +print(bst.insert(10)) +#print(bst.insert(5)) +bst.preorder() +print(bst.getHeight()) +#bst.postorder() +#bst.inorder() +print(bst.remove(10)) bst.preorder() \ No newline at end of file diff --git a/Trees/bst.py b/Trees/bst.py new file mode 100644 index 00000000..f45b2f4f --- /dev/null +++ b/Trees/bst.py @@ -0,0 +1,236 @@ +# Binary Search Tree in Python + +class Node: + def __init__(self, val): + self.value = val + self.leftChild = None + self.rightChild = None + + def insert(self, data): + if self.value == data: + return False + + elif self.value > data: + if self.leftChild: + return self.leftChild.insert(data) + else: + self.leftChild = Node(data) + return True + + else: + if self.rightChild: + return self.rightChild.insert(data) + else: + self.rightChild = Node(data) + return True + + def find(self, data): + if(self.value == data): + return True + elif self.value > data: + if self.leftChild: + return self.leftChild.find(data) + else: + return False + else: + if self.rightChild: + return self.rightChild.find(data) + else: + return False + + def getSize(self): + if self.leftChild and self.rightChild: + return 1 + self.leftChild.getSize() + self.rightChild.getSize() + elif self.leftChild: + return 1 + self.leftChild.getSize() + elif self.rightChild: + return 1 + self.rightChild.getSize() + else: + return 1 + + def getHeight(self): + if self.leftChild and self.rightChild: + return 1 + max(self.leftChild.getHeight(), self.rightChild.getHeight()) + elif self.leftChild: + return 1 + self.leftChild.getHeight() + elif self.rightChild: + return 1 + self.rightChild.getHeight() + else: + return 1 + + def preorder(self): + if self: + print (str(self.value)) + if self.leftChild: + self.leftChild.preorder() + if self.rightChild: + self.rightChild.preorder() + + def postorder(self): + if self: + if self.leftChild: + self.leftChild.postorder() + if self.rightChild: + self.rightChild.postorder() + print (str(self.value)) + + def inorder(self): + if self: + if self.leftChild: + self.leftChild.inorder() + print (str(self.value)) + if self.rightChild: + self.rightChild.inorder() + +class Tree: + def __init__(self): + self.root = None + + def insert(self, data): + if self.root: + return self.root.insert(data) + else: + self.root = Node(data) + return True + + def find(self, data): + if self.root: + return self.root.find(data) + else: + return False + + def getHeight(self): + if self.root: + return self.root.getHeight() + else: + return 0 + + def getSize(self): + if self.root: + return self.root.getSize() + else: + return 0 + + def remove(self, data): + # empty tree + if self.root is None: + return False + + # data is in root node + elif self.root.value == data: + if self.root.leftChild is None and self.root.rightChild is None: + self.root = None + elif self.root.leftChild and self.root.rightChild is None: + self.root = self.root.leftChild + elif self.root.leftChild is None and self.root.rightChild: + self.root = self.root.rightChild + elif self.root.leftChild and self.root.rightChild: + delNodeParent = self.root + delNode = self.root.rightChild + while delNode.leftChild: + delNodeParent = delNode + delNode = delNode.leftChild + + if delNode.rightChild: + if delNodeParent.value > delNode.value: + delNodeParent.leftChild = delNode.rightChild + elif delNodeParent.value < delNode.value: + delNodeParent.rightChild = delNode.rightChild + else: + if delNode.value < delNodeParent.value: + delNodeParent.leftChild = None + else: + delNodeParent.rightChild = None + self.root.value = delNode.value + + return True + + parent = None + node = self.root + + # find node to remove + while node and node.value != data: + parent = node + if data < node.value: + node = node.leftChild + elif data > node.value: + node = node.rightChild + + # case 1: data not found + if node is None or node.value != data: + return False + + # case 2: remove-node has no children + elif node.leftChild is None and node.rightChild is None: + if data < parent.value: + parent.leftChild = None + else: + parent.rightChild = None + return True + + # case 3: remove-node has left child only + elif node.leftChild and node.rightChild is None: + if data < parent.value: + parent.leftChild = node.leftChild + else: + parent.rightChild = node.leftChild + return True + + # case 4: remove-node has right child only + elif node.leftChild is None and node.rightChild: + if data < parent.value: + parent.leftChild = node.rightChild + else: + parent.rightChild = node.rightChild + return True + + # case 5: remove-node has left and right children + else: + delNodeParent = node + delNode = node.rightChild + while delNode.leftChild: + delNodeParent = delNode + delNode = delNode.leftChild + + node.value = delNode.value + if delNode.rightChild: + if delNodeParent.value > delNode.value: + delNodeParent.leftChild = delNode.rightChild + elif delNodeParent.value < delNode.value: + delNodeParent.rightChild = delNode.rightChild + else: + if delNode.value < delNodeParent.value: + delNodeParent.leftChild = None + else: + delNodeParent.rightChild = None + + def preorder(self): + if self.root is not None: + print("PreOrder") + self.root.preorder() + + def postorder(self): + if self.root is not None: + print("PostOrder") + self.root.postorder() + + def inorder(self): + if self.root is not None: + print("InOrder") + self.root.inorder() + +def main(): + bst = Tree() + print(bst.insert(10)) + print(bst.insert(5)) + bst.insert(2) + bst.insert(7) + bst.preorder() + print('Height = ', bst.getHeight()) + print('Size = ', bst.getSize()) + #bst.postorder() + #bst.inorder() + print(bst.remove(10)) + bst.preorder() + +main() diff --git a/Unpacking Variables.ipynb b/Unpacking Variables.ipynb new file mode 100644 index 00000000..3b1f8d31 --- /dev/null +++ b/Unpacking Variables.ipynb @@ -0,0 +1,360 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Packing & Unpacking Variables" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Assign variables\n", + "In Python you can assign multiple variables at a time using commas." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "2\n", + "3\n" + ] + } + ], + "source": [ + "a, b, c = 1, 2, 3\n", + "print(a)\n", + "print(b)\n", + "print(c)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Swap a pair of Variables in Python\n", + "x,y = y,x" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x=12, y=5\n" + ] + } + ], + "source": [ + "x = 5; y = 12\n", + "x, y = y, x\n", + "print('x=' + str(x) + ', y=' + str(y))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Swap a trio of Variables in Python\n", + "Yes, this trick works for 3 variables too." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "88 99 77\n" + ] + } + ], + "source": [ + "x, y, z = 77, 88, 99\n", + "z, x, y = x, y, z\n", + "print(x, y, z)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Split String into multiple variables\n", + "But be careful because the number of variables must match the number of substrings from the split." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4\n", + "5\n", + "6\n" + ] + } + ], + "source": [ + "a, b, c = '4 5 6'.split()\n", + "print(a)\n", + "print(b)\n", + "print(c)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Splitting a List into variables is magically easy" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "8\n", + "9\n", + "10\n" + ] + } + ], + "source": [ + "my_list = [8, 9, 10]\n", + "a, b, c = my_list\n", + "print(a)\n", + "print(b)\n", + "print(c)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Split Tuple into variables" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "25 26 27\n" + ] + } + ], + "source": [ + "tup = (25,26,27)\n", + "x, y, z = tup\n", + "print(x, y, z)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### This gives you a Tuple, not a List" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(8, 9, 10)\n", + "\n" + ] + } + ], + "source": [ + "var = a, b, c\n", + "print(var)\n", + "print(type(var))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### *args for Functions\n", + "Used for passing a non-keyworded, variable-length argument list to a function. \n", + "Received as a Tuple." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('Forest', 'Hill', 'High')\n", + "\n" + ] + } + ], + "source": [ + "def pack_it(*args):\n", + " print(args)\n", + " print(type(args))\n", + " \n", + "x = 'Forest'; y = 'Hill'; z = 'High'\n", + "pack_it(x, y, z)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This unpacks the List before sending it, so it can be received by the function as separate variables." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cullen\n", + "McDonough\n" + ] + } + ], + "source": [ + "def unpack_it(x, y):\n", + " print(x)\n", + " print(y)\n", + " \n", + "args = ['Cullen', 'McDonough']\n", + "unpack_it(*args)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### **kwargs for Functions\n", + "Used for passing keyworded, variable-length argument dictionary to functions. \n", + "This works, but it's kinda annoying because some normal Python dictionaries fail. \n", + "func (1:'Edsel', 2:'Betamax') does not work." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'a': 'Edsel', 'b': 'Betamax', 'c': 'mGaetz'}\n", + "Edsel\n", + "\n" + ] + } + ], + "source": [ + "def func(**losers):\n", + " print(losers)\n", + " print(losers['a'])\n", + " print(type(losers))\n", + " \n", + "func(a='Edsel', b='Betamax', c='mGaetz')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This works, but it's kinda annoying because you have to use strings for the keys, so some normal Python dictionaries will give you an error. {1:'Edsel', 2:'Betamax'} fails." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Edsel\n" + ] + } + ], + "source": [ + "def func(a, b, c):\n", + " print(a)\n", + "\n", + "losers = {'a':'Edsel', 'b':'Betamax', 'c':'mGaetz'}\n", + "func(**losers)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Web Data Mining/Python BeautifulSoup Web Scraping Tutorial.ipynb b/Web Data Mining/Python BeautifulSoup Web Scraping Tutorial.ipynb new file mode 100644 index 00000000..f7d55aa9 --- /dev/null +++ b/Web Data Mining/Python BeautifulSoup Web Scraping Tutorial.ipynb @@ -0,0 +1,514 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python BeautifulSoup Web Scraping Tutorial\n", + "Learn to scrape data from the web using the Python BeautifulSoup bs4 library. \n", + "BeautifulSoup makes it easy to parse useful data out of an HTML page. \n", + "First install the bs4 library on your system by running at the command line, \n", + "*pip install beautifulsoup4* or *easy_install beautifulsoup4* (or bs4) \n", + "See [BeautifulSoup official documentation](https://www.crummy.com/software/BeautifulSoup/bs4/doc/) for the complete set of functions.\n", + "\n", + "### Import requests so we can fetch the html content of the webpage\n", + "You can see our example page has about 28k characters." + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "28556\n" + ] + } + ], + "source": [ + "import requests\n", + "r = requests.get('https://www.usclimatedata.com/climate/united-states/us')\n", + "print(len(r.text))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Import BeautifulSoup, and convert your HTML into a bs4 object\n", + "Now we can access specific HTML tags on the page using dot, just like a JSON object." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Climate United States - normals and averages\n", + "Climate United States - normals and averages\n" + ] + } + ], + "source": [ + "from bs4 import BeautifulSoup\n", + "soup = BeautifulSoup(r.text)\n", + "print(soup.title)\n", + "print(soup.title.string)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Drill into the bs4 object to access page contents\n", + "soup.p will give you the contents of the first paragraph tag on the page. \n", + "soup.a gives you anchors / links on the page. \n", + "Get contents of an attribute inside an HTML tag using square brackets and perentheses. \n", + "Use .parent to get the parent object, and .next_sibling to get the next peer object. \n", + "**Use your browser's *inspect element* feature to find the tag for the data you want.**" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "

You are here: United States

\n", + "You are here: United States\n", + "\n", + "\"US\n", + "\n", + "US Climate Data on Facebook\n", + "\n", + "\n" + ] + } + ], + "source": [ + "print(soup.p)\n", + "print(soup.p.text)\n", + "print(soup.a)\n", + "print(soup.a['title'])\n", + "print()\n", + "print(soup.p.parent)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Prettify() is handy for formatted printing \n", + "but note this works only on bs4 objects, not on strings, dicts or lists. For those you need to import pprint." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "
\n", + "\n" + ] + } + ], + "source": [ + "print(soup.p.parent.prettify())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### We need all the state links on this page\n", + "First we find_all anchor tags, and print out the href attribute, which is the actual link url. \n", + "But we see the result includes some links we don't want, so we need to filter those out." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "https://www.facebook.com/yourweatherservice/n", + "https://twitter.com/usclimatedata/n", + "http://www.usclimatedata.com/n", + "/climate/united-states/us\n", + "#summary\n", + "/climate/united-states/us\n", + "#\n", + "#\n", + "/climate/alabama/united-states/3170\n", + "/climate/kentucky/united-states/3187\n", + "/climate/north-dakota/united-states/3204\n", + "/climate/alaska/united-states/3171\n", + "/climate/louisiana/united-states/3188\n", + "/climate/ohio/united-states/3205\n", + "/climate/arizona/united-states/3172\n", + "/climate/maine/united-states/3189\n", + "/climate/oklahoma/united-states/3206\n", + "/climate/arkansas/united-states/3173\n", + "/climate/maryland/united-states/1872\n", + "/climate/oregon/united-states/3207\n", + "/climate/california/united-states/3174\n", + "/climate/massachusetts/united-states/3191\n", + "/climate/pennsylvania/united-states/3208\n", + "/climate/colorado/united-states/3175\n", + "/climate/michigan/united-states/3192\n", + "/climate/rhode-island/united-states/3209\n", + "/climate/connecticut/united-states/3176\n", + "/climate/minnesota/united-states/3193\n", + "/climate/south-carolina/united-states/3210\n", + "/climate/delaware/united-states/3177\n", + "/climate/mississippi/united-states/3194\n", + "/climate/south-dakota/united-states/3211\n", + "/climate/district-of-columbia/united-states/3178\n", + "/climate/missouri/united-states/3195\n", + "/climate/tennessee/united-states/3212\n", + "/climate/florida/united-states/3179\n", + "/climate/montana/united-states/919\n", + "/climate/texas/united-states/3213\n", + "/climate/georgia/united-states/3180\n", + "/climate/nebraska/united-states/3197\n", + "/climate/utah/united-states/3214\n", + "/climate/hawaii/united-states/3181\n", + "/climate/nevada/united-states/3198\n", + "/climate/vermont/united-states/3215\n", + "/climate/idaho/united-states/3182\n", + "/climate/new-hampshire/united-states/3199\n", + "/climate/virginia/united-states/3216\n", + "/climate/illinois/united-states/3183\n", + "/climate/new-jersey/united-states/3200\n", + "/climate/washington/united-states/3217\n", + "/climate/indiana/united-states/3184\n", + "/climate/new-mexico/united-states/3201\n", + "/climate/west-virginia/united-states/3218\n", + "/climate/iowa/united-states/3185\n", + "/climate/new-york/united-states/3202\n", + "/climate/wisconsin/united-states/3219\n", + "/climate/kansas/united-states/3186\n", + "/climate/north-carolina/united-states/3203\n", + "/climate/wyoming/united-states/3220\n", + "https://www.yourweatherservice.com/n", + "https://www.climatedata.eu/n", + "https://www.weernetwerk.nl/n", + "/about-us.php\n", + "/disclaimer.php\n", + "/cookies.php\n" + ] + } + ], + "source": [ + "for link in soup.find_all('a'):\n", + " print(link.get('href'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Filter urls using string functions\n", + "We just add an *if* to check conditions, then add the good ones to a list. \n", + "In the end we get 51 state links, including Washington DC." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "51\n" + ] + } + ], + "source": [ + "base_url = 'https://www.usclimatedata.com/'\n", + "state_links = []\n", + "for link in soup.find_all('a'):\n", + " url = link.get('href')\n", + " if url and '/climate/' in url and '/climate/united-states/us' not in url:\n", + " state_links.append(url)\n", + "print(len(state_links))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Test getting the data for one state\n", + "then print the title for that page." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Climate Ohio - temperature, rainfall and average\n" + ] + } + ], + "source": [ + "r = requests.get(base_url + state_links[5])\n", + "soup = BeautifulSoup(r.text)\n", + "print(soup.title.string)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The data we need is in *tr* tags\n", + "But look, there are 58 tr tags on the page, and we only want 2 of them - the *Average high* rows." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "58\n" + ] + } + ], + "source": [ + "rows = soup.find_all('tr')\n", + "print(len(rows))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Filter rows, and add temp data to a list\n", + "We use a list comprehension to filter the rows. \n", + "Then we have only 2 rows left. \n", + "We iterate through those 2 rows, and add all the temps from data cells (td) into a list." + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n", + "['36', '40', '52', '63', '73', '82', '85', '84', '77', '65', '52', '41']\n" + ] + } + ], + "source": [ + "rows = [row for row in rows if 'Average high' in str(row)]\n", + "print(len(rows))\n", + "\n", + "high_temps = []\n", + "for row in rows:\n", + " tds = row.find_all('td')\n", + " for i in range(1,7):\n", + " high_temps.append(tds[i].text)\n", + "print(high_temps)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Get the name of the State\n", + "First attempt we just split the title string into a list, and grab the second word. \n", + "But that doesn't work for 2-word states like New York and North Carolina. \n", + "So instead we slice the string from first blank to the hyphen. " + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Wyoming\n", + "Wyoming\n" + ] + } + ], + "source": [ + "state = soup.title.string.split()[1]\n", + "print(state)\n", + "s = soup.title.string\n", + "state = s[s.find(' '):s.find('-')].strip()\n", + "print(state)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Add state name and temp list to the data dictionary\n", + "For a single state, this is what our scraped data looks like. \n", + "In this example we only got monthly highs by state, but you could drill into cities, and could get lows and precipitation. " + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'Ohio': ['36', '40', '52', '63', '73', '82', '85', '84', '77', '65', '52', '41']}\n" + ] + } + ], + "source": [ + "data = {}\n", + "data[state] = high_temps\n", + "print(data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Put it all together and iterate 51 states\n", + "We loop through our 51-state list, and get high temp data for each state, and add it to the data dict. \n", + "This combines all our work above into a single for loop. \n", + "The result is a dict with 51 states and a list of monthly highs for each." + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'Alabama': ['57', '62', '70', '77', '84', '90', '92', '92', '87', '78', '69', '60'], 'Kentucky': ['40', '45', '55', '66', '75', '83', '87', '86', '79', '68', '55', '44'], 'North Dakota': ['23', '28', '40', '57', '68', '77', '85', '83', '72', '58', '40', '26'], 'Alaska': ['23', '27', '34', '44', '56', '63', '65', '64', '55', '40', '28', '25'], 'Louisiana': ['62', '65', '72', '78', '85', '89', '91', '91', '87', '80', '72', '64'], 'Ohio': ['36', '40', '52', '63', '73', '82', '85', '84', '77', '65', '52', '41'], 'Arizona': ['67', '71', '77', '85', '95', '104', '106', '104', '100', '89', '76', '66'], 'Maine': ['28', '32', '40', '53', '65', '74', '79', '78', '70', '57', '45', '33'], 'Oklahoma': ['50', '55', '63', '72', '80', '88', '94', '93', '85', '73', '62', '51'], 'Arkansas': ['51', '55', '64', '73', '81', '89', '92', '93', '86', '75', '63', '52'], 'Maryland': ['42', '46', '54', '65', '75', '85', '89', '87', '80', '68', '58', '46'], 'Oregon': ['48', '52', '56', '61', '68', '74', '82', '82', '77', '64', '53', '46'], 'California': ['54', '60', '65', '71', '80', '87', '92', '91', '87', '78', '64', '54'], 'Massachusetts': ['36', '39', '45', '56', '66', '76', '81', '80', '72', '61', '51', '41'], 'Pennsylvania': ['40', '44', '53', '64', '74', '83', '87', '85', '78', '67', '56', '45'], 'Colorado': ['45', '46', '54', '61', '72', '82', '90', '88', '79', '66', '52', '45'], 'Michigan': ['30', '33', '44', '58', '69', '78', '82', '80', '73', '60', '47', '34'], 'Rhode Island': ['37', '40', '48', '59', '68', '78', '83', '81', '74', '63', '53', '42'], 'Connecticut': ['37', '40', '47', '58', '68', '77', '82', '81', '74', '63', '53', '42'], 'Minnesota': ['26', '31', '43', '58', '71', '80', '85', '82', '73', '59', '42', '29'], 'South Carolina': ['56', '60', '68', '76', '84', '90', '93', '91', '85', '76', '67', '58'], 'Delaware': ['43', '47', '55', '66', '75', '83', '87', '85', '79', '69', '58', '47'], 'Mississippi': ['56', '60', '69', '76', '83', '89', '92', '92', '87', '77', '67', '58'], 'South Dakota': ['22', '27', '39', '57', '69', '78', '84', '82', '72', '58', '39', '25'], 'District of Columbia': ['42', '44', '53', '64', '75', '83', '87', '84', '78', '67', '55', '45'], 'Missouri': ['40', '45', '56', '67', '75', '83', '88', '88', '80', '69', '56', '43'], 'Tennessee': ['50', '55', '64', '73', '81', '89', '92', '91', '85', '74', '63', '52'], 'Florida': ['64', '67', '74', '80', '87', '91', '92', '92', '88', '81', '73', '65'], 'Montana': ['33', '39', '48', '58', '67', '76', '86', '85', '73', '59', '43', '32'], 'Texas': ['62', '65', '72', '80', '87', '92', '96', '97', '91', '82', '71', '63'], 'Georgia': ['52', '57', '64', '72', '81', '86', '90', '88', '82', '73', '64', '54'], 'Nebraska': ['32', '37', '50', '63', '73', '84', '88', '86', '77', '64', '48', '36'], 'Utah': ['38', '44', '53', '61', '71', '82', '90', '89', '78', '65', '50', '40'], 'Hawaii': ['80', '80', '81', '83', '85', '87', '88', '89', '89', '87', '84', '81'], 'Nevada': ['45', '50', '57', '63', '71', '81', '90', '88', '80', '68', '54', '45'], 'Vermont': ['27', '31', '40', '55', '67', '76', '81', '79', '70', '57', '46', '33'], 'Idaho': ['38', '45', '55', '62', '72', '81', '91', '90', '79', '65', '48', '38'], 'New Hampshire': ['31', '35', '44', '57', '69', '77', '82', '81', '73', '60', '48', '36'], 'Virginia': ['47', '51', '60', '70', '78', '86', '90', '88', '81', '71', '61', '51'], 'Illinois': ['32', '36', '46', '59', '70', '81', '84', '82', '75', '63', '48', '36'], 'New Jersey': ['39', '42', '51', '62', '72', '82', '86', '84', '77', '65', '55', '44'], 'Washington': ['47', '50', '54', '58', '65', '70', '76', '76', '71', '60', '51', '46'], 'Indiana': ['35', '40', '51', '63', '73', '82', '85', '83', '77', '65', '52', '39'], 'New Mexico': ['44', '48', '56', '65', '74', '83', '86', '83', '78', '67', '53', '43'], 'West Virginia': ['42', '47', '56', '68', '75', '82', '85', '84', '78', '68', '57', '46'], 'Iowa': ['31', '36', '49', '62', '72', '82', '86', '84', '76', '63', '48', '34'], 'New York': ['39', '42', '50', '60', '71', '79', '85', '83', '76', '65', '54', '44'], 'Wisconsin': ['29', '33', '42', '54', '65', '75', '80', '78', '71', '59', '46', '33'], 'Kansas': ['40', '45', '56', '67', '76', '85', '89', '89', '80', '68', '55', '42'], 'North Carolina': ['51', '55', '63', '72', '79', '86', '89', '87', '81', '72', '62', '53'], 'Wyoming': ['40', '40', '47', '55', '65', '75', '83', '81', '72', '59', '47', '38']}\n" + ] + } + ], + "source": [ + "data = {}\n", + "for state_link in state_links:\n", + " url = base_url + state_link\n", + " r = requests.get(base_url + state_link)\n", + " soup = BeautifulSoup(r.text)\n", + " rows = soup.find_all('tr')\n", + " rows = [row for row in rows if 'Average high' in str(row)]\n", + " high_temps = []\n", + " for row in rows:\n", + " tds = row.find_all('td')\n", + " for i in range(1,7):\n", + " high_temps.append(tds[i].text)\n", + " s = soup.title.string\n", + " state = s[s.find(' '):s.find('-')].strip()\n", + " data[state] = high_temps\n", + "print(data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Save to CSV file\n", + "Lastly, we might want to write all this data to a CSV file. \n", + "Here's a quick easy way to do that." + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [], + "source": [ + "import csv\n", + "\n", + "with open('high_temps.csv','w') as f:\n", + " w = csv.writer(f)\n", + " w.writerows(data.items())" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Web Data Mining/Python Requests.ipynb b/Web Data Mining/Python Requests.ipynb new file mode 100644 index 00000000..66f27fed --- /dev/null +++ b/Web Data Mining/Python Requests.ipynb @@ -0,0 +1,419 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python Requests\n", + "(c) 2019, Joe James.\n", + "MIT License.\n", + "\n", + "Tutorial on using the [Requests](http://docs.python-requests.org/en/master/user/quickstart/) library to access HTTP requests, GET, POST, PUT, DELETE, HEAD, OPTIONS. \n", + "This notebook also covers how to use the Python [JSON](https://docs.python.org/3/library/json.html) library to parse values out of a GET response. \n", + "If you don't have the requests library installed you can run 'pip install requests' or some equivalent command for your system in the console window. " + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "import json" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": {}, + "outputs": [], + "source": [ + "r = requests.get('https://api.github.com/events')\n", + "r = requests.post('https://httpbin.org/post', data = {'name':'Joe'})\n", + "r = requests.put('https://httpbin.org/put', data = {'name':'Joe'})\n", + "r = requests.delete('https://httpbin.org/delete')\n", + "r = requests.head('https://httpbin.org/get')\n", + "r = requests.options('https://httpbin.org/get')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### GET Requests - Passing Parameters in URLs\n", + "A URL that returns an HTTP response in JSON format is called an API endpoint. \n", + "Here's an example, https://httpbin.org/get \n", + "\n", + "With GET requests we can add parameters onto the URL to retrieve specific data. \n", + "We define the params as a dictionary, and add params=payload to the Request. \n", + "The Requests library builds the whole URL for us." + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "https://httpbin.org/get?key1=value1&key2=value2\n" + ] + } + ], + "source": [ + "payload = {'key1': 'value1', 'key2': 'value2'}\n", + "r = requests.get('https://httpbin.org/get', params=payload)\n", + "print(r.url)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Passing a List as a parameter** \n", + "Still use key:value pairs, with the list as the value. \n", + "You can see here all the different attributes included in an HTTP Request response." + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "URL: https://httpbin.org/get?key1=value1&key2=value2&key2=value3\n", + "ENCODING: None\n", + "STATUS_CODE: 200\n", + "HEADERS: {'Access-Control-Allow-Credentials': 'true', 'Access-Control-Allow-Origin': '*', 'Content-Encoding': 'gzip', 'Content-Type': 'application/json', 'Date': 'Tue, 26 Feb 2019 18:13:35 GMT', 'Server': 'nginx', 'Content-Length': '229', 'Connection': 'keep-alive'}\n", + "TEXT: {\n", + " \"args\": {\n", + " \"key1\": \"value1\", \n", + " \"key2\": [\n", + " \"value2\", \n", + " \"value3\"\n", + " ]\n", + " }, \n", + " \"headers\": {\n", + " \"Accept\": \"*/*\", \n", + " \"Accept-Encoding\": \"gzip, deflate\", \n", + " \"Host\": \"httpbin.org\", \n", + " \"User-Agent\": \"python-requests/2.21.0\"\n", + " }, \n", + " \"origin\": \"99.99.39.153, 99.99.39.153\", \n", + " \"url\": \"https://httpbin.org/get?key1=value1&key2=value2&key2=value3\"\n", + "}\n", + "\n", + "CONTENT: b'{\\n \"args\": {\\n \"key1\": \"value1\", \\n \"key2\": [\\n \"value2\", \\n \"value3\"\\n ]\\n }, \\n \"headers\": {\\n \"Accept\": \"*/*\", \\n \"Accept-Encoding\": \"gzip, deflate\", \\n \"Host\": \"httpbin.org\", \\n \"User-Agent\": \"python-requests/2.21.0\"\\n }, \\n \"origin\": \"99.99.39.153, 99.99.39.153\", \\n \"url\": \"https://httpbin.org/get?key1=value1&key2=value2&key2=value3\"\\n}\\n'\n", + "JSON: >\n" + ] + } + ], + "source": [ + "payload = {'key1': 'value1', 'key2': ['value2', 'value3']}\n", + "r = requests.get('https://httpbin.org/get', params=payload)\n", + "print('URL: ', r.url)\n", + "print('ENCODING: ', r.encoding)\n", + "print('STATUS_CODE: ', r.status_code)\n", + "print('HEADERS: ', r.headers)\n", + "print('TEXT: ', r.text)\n", + "print('CONTENT: ', r.content)\n", + "print('JSON: ', r.json)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### POST Requests\n", + "We can add parameters to a POST request in Dictionary format, but we use data=payload. \n", + "POST requests are used to upload new records to the server. \n", + "POST would typically be used to get data from a web form and submit it to the server. " + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"args\": {}, \n", + " \"data\": \"\", \n", + " \"files\": {}, \n", + " \"form\": {\n", + " \"key1\": \"value1\", \n", + " \"key2\": \"value2\"\n", + " }, \n", + " \"headers\": {\n", + " \"Accept\": \"*/*\", \n", + " \"Accept-Encoding\": \"gzip, deflate\", \n", + " \"Content-Length\": \"23\", \n", + " \"Content-Type\": \"application/x-www-form-urlencoded\", \n", + " \"Host\": \"httpbin.org\", \n", + " \"User-Agent\": \"python-requests/2.21.0\"\n", + " }, \n", + " \"json\": null, \n", + " \"origin\": \"99.99.39.153, 99.99.39.153\", \n", + " \"url\": \"https://httpbin.org/post/"\n", + "}\n", + "\n" + ] + } + ], + "source": [ + "r = requests.post('https://httpbin.org/post', data = {'name':'Joe'})\n", + "\n", + "payload = {'key1': 'value1', 'key2': 'value2'}\n", + "r = requests.post(\"https://httpbin.org/post/", data=payload)\n", + "print(r.text)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using Requests to GET Currency Exchange Data\n", + "Here's a handy endpoint where we can GET foreign currency exchange rates in JSON format, https://api.exchangeratesapi.io/latest" + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\"rates\":{\"MXN\":21.7145,\"AUD\":1.5897,\"HKD\":8.9178,\"RON\":4.7626,\"HRK\":7.4275,\"CHF\":1.1371,\"IDR\":15917.9,\"CAD\":1.5024,\"USD\":1.1361,\"ZAR\":15.752,\"JPY\":125.93,\"BRL\":4.2574,\"HUF\":317.06,\"CZK\":25.663,\"NOK\":9.7725,\"INR\":80.853,\"PLN\":4.3282,\"ISK\":136.1,\"PHP\":59.144,\"SEK\":10.5858,\"ILS\":4.1148,\"GBP\":0.86055,\"SGD\":1.5332,\"CNY\":7.6077,\"TRY\":6.0254,\"MYR\":4.6157,\"RUB\":74.6158,\"NZD\":1.652,\"KRW\":1270.0,\"THB\":35.583,\"BGN\":1.9558,\"DKK\":7.4616},\"base\":\"EUR\",\"date\":\"2019-02-26\"}\n" + ] + } + ], + "source": [ + "url = 'https://api.exchangeratesapi.io/latest'\n", + "r = requests.get(url)\n", + "print(r.text)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**It looks like the default is base:EUR, but we want exchange rates for USD, so we can pass in a parameter for base. \n", + "We can also put in any date we want.**" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\"rates\":{\"MXN\":18.8315549401,\"AUD\":1.2571475116,\"HKD\":7.823572534,\"RON\":3.7694876599,\"HRK\":6.0552252179,\"CHF\":0.9610654069,\"IDR\":13307.03754989,\"CAD\":1.2432190274,\"USD\":1.0,\"JPY\":110.621487334,\"BRL\":3.1959762157,\"PHP\":50.2997474953,\"CZK\":20.7957970188,\"NOK\":7.8771686894,\"INR\":63.5175531482,\"PLN\":3.3954549157,\"MYR\":3.9560153132,\"ZAR\":12.302191089,\"ILS\":3.399609025,\"GBP\":0.7252830496,\"SGD\":1.3214140262,\"HUF\":251.6086991936,\"EUR\":0.8145312373,\"CNY\":6.4380548994,\"TRY\":3.7828459721,\"SEK\":8.0096929217,\"RUB\":56.4333306182,\"NZD\":1.3706931661,\"KRW\":1063.5660177568,\"THB\":31.9247373137,\"BGN\":1.5930601939,\"DKK\":6.0679319052},\"base\":\"USD\",\"date\":\"2018-01-15\"}\n" + ] + } + ], + "source": [ + "url = 'https://api.exchangeratesapi.io/2018-01-15'\n", + "r = requests.get(url, params={'base':'USD'})\n", + "print(r.text)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Decoding JSON data\n", + "Now we have the rates in JSON format. We need to convert that to usable data. \n", + "The JSON library basically has two functions: \n", + "- json.loads( ) converts a text string into Python dict/list objects. \n", + "- json.dumps( ) converts dict/list objects into a string. \n", + "\n", + "We need to decode the JSON data into a dictionary, then get the rate for GBP, convert it to a float, and do a conversion." + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'MXN': 18.8315549401, 'AUD': 1.2571475116, 'HKD': 7.823572534, 'RON': 3.7694876599, 'HRK': 6.0552252179, 'CHF': 0.9610654069, 'IDR': 13307.03754989, 'CAD': 1.2432190274, 'USD': 1.0, 'JPY': 110.621487334, 'BRL': 3.1959762157, 'PHP': 50.2997474953, 'CZK': 20.7957970188, 'NOK': 7.8771686894, 'INR': 63.5175531482, 'PLN': 3.3954549157, 'MYR': 3.9560153132, 'ZAR': 12.302191089, 'ILS': 3.399609025, 'GBP': 0.7252830496, 'SGD': 1.3214140262, 'HUF': 251.6086991936, 'EUR': 0.8145312373, 'CNY': 6.4380548994, 'TRY': 3.7828459721, 'SEK': 8.0096929217, 'RUB': 56.4333306182, 'NZD': 1.3706931661, 'KRW': 1063.5660177568, 'THB': 31.9247373137, 'BGN': 1.5930601939, 'DKK': 6.0679319052}\n", + "0.7252830496\n", + "200USD = 145.05660992 GBP\n" + ] + } + ], + "source": [ + "rates_json = json.loads(r.text)['rates']\n", + "print(rates_json)\n", + "print(rates_json['GBP'])\n", + "gbp = float(rates_json['GBP'])\n", + "print('200USD = ', str(gbp * 200), 'GBP')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using Requests to GET Song Data\n", + "Every API has documentation on how to use it. \n", + "You can find the docs for this Song Data API [here.](https://documenter.getpostman.com/view/3719697/RzfarXB4)" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[{\"id\":12,\"name\":\"Beatles\",\"year_started\":1960,\"year_quit\":1970,\"text\":\"Beatles\"},{\"id\":14,\"name\":\"Dario G\",\"year_started\":1997,\"year_quit\":null,\"text\":\"Dario G\"},{\"id\":16,\"name\":\"Fleetwood Mac\",\"year_started\":1967,\"year_quit\":null,\"text\":\"Fleetwood Mac\"},{\"id\":17,\"name\":\"Blink 182\",\"year_started\":1992,\"year_quit\":null,\"text\":\"Blink 182\"},{\"id\":18,\"name\":\"Bloc Party\",\"year_started\":2002,\"year_quit\":null,\"text\":\"Bloc Party\"},{\"id\":19,\"name\":\"The Temper Trap\",\"year_started\":2005,\"year_quit\":null,\"text\":\"The Temper Trap\"},{\"id\":20,\"name\":\"MGMT\",\"year_started\":2002,\"year_quit\":null,\"text\":\"MGMT\"},{\"id\":21,\"name\":\"Coldplay\",\"year_started\":1996,\"year_quit\":null,\"text\":\"Coldplay\"},{\"id\":22,\"name\":\"\n" + ] + } + ], + "source": [ + "url = 'https://musicdemons.com/api/v1/artist'\n", + "r = requests.get(url)\n", + "print(r.text[:700])" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\"id\":21,\"name\":\"Coldplay\",\"year_started\":1996,\"year_quit\":null,\"text\":\"Coldplay\"}\n" + ] + } + ], + "source": [ + "url = 'https://musicdemons.com/api/v1/artist/21'\n", + "r = requests.get(url)\n", + "print(r.text)" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\"id\":21,\"name\":\"Coldplay\",\"year_started\":1996,\"year_quit\":null,\"text\":\"Coldplay\",\"songs\":[{\"id\":1,\"title\":\"Something Just Like This\",\"released\":\"02\\/22\\/2017\",\"text\":\"Something Just Like This\",\"youtube_id\":\"FM7MFYoylVs\",\"pivot\":{\"artist_id\":21,\"song_id\":1},\"subject\":{\"id\":226,\"subjectable_id\":1,\"subjectable_type\":\"App\\\\Entities\\\\MusicDemons\\\\Song\"}},{\"id\":11,\"title\":\"Hymn For The Weekend\",\"released\":\"01\\/25\\/2016\",\"text\":\"Hymn For The Weekend\",\"youtube_id\":\"YykjpeuMNEk\",\"pivot\":{\"artist_id\":21,\"song_id\":11},\"subject\":{\"id\":233,\"subjectable_id\":11,\"subjectable_type\":\"App\\\\Entities\\\\MusicDemons\\\\Song\"}},{\"id\":78,\"title\":\"Sky Full Of Stars\",\"released\":\"05\\/02\\/2014\",\"text\":\"Sky Full Of Stars\",\n" + ] + } + ], + "source": [ + "url = 'https://musicdemons.com/api/v1/artist/21'\n", + "headers = {'with': 'songs,members'}\n", + "r = requests.get(url, headers=headers)\n", + "print(r.text[:700])" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Coldplay\n", + "Something Just Like This\n", + "Hymn For The Weekend\n", + "Sky Full Of Stars\n", + "Fix You\n", + "Brothers & Sisters\n", + "Shiver\n", + "The Scientist\n", + "Yellow\n", + "Trouble\n", + "Every Teardrop Is a Waterfall\n", + "Life in Technicolor ii\n", + "Adventure Of A Lifetime\n", + "Magic\n", + "The Hardest Part\n", + "Viva la Vida\n", + "1.36\n", + "42\n", + "A Head Full of Dreams\n", + "A Hopeful Transmission\n", + "A Message\n", + "A Rush of Blood to the Head\n", + "Princess of China\n" + ] + } + ], + "source": [ + "import json\n", + "text_json = json.loads(r.text)\n", + "print(text_json['name'])\n", + "for song in text_json['songs']:\n", + " print(song['title'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tips on breaking down JSON \n", + "To get data out of a JSON object, which is a combination of lists and dictionaries, \n", + "just remember for lists you need a numerical index, and for key-value pairs you need a text index. \n", + "So if the object looks like this, {\"cars\":[\"id\":1,\"model\":\"Camry\"... you can access the model of the first car with text['cars'][0]['model']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/addition of two number b/addition of two number new file mode 100644 index 00000000..d31335e3 --- /dev/null +++ b/addition of two number @@ -0,0 +1,9 @@ +# Store input numbers +num1 = input('Enter first number: ') +num2 = input('Enter second number: ') + +# Add two numbers +sum = float(num1) + float(num2) + +# Display the sum +print('The sum of {0} and {1} is {2}'.format(num1, num2, sum)) diff --git a/deep_copy.ipynb b/deep_copy.ipynb new file mode 100644 index 00000000..a11d7052 --- /dev/null +++ b/deep_copy.ipynb @@ -0,0 +1,248 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python: how to Copy and Deep Copy Python Lists \n", + "(c) Joe James 2023" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Assignment is not a Copy\n", + "listA = listB does not create a copy. Changes to one list will be reflected in the other.\n", + "listA and listB both reference the exact same list." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2, 44, 6, [1, 3]]\n", + "140554034568968\n", + "140554034568968\n" + ] + } + ], + "source": [ + "listA = [2, 4, 6, [1, 3]]\n", + "listB = listA\n", + "listB[1] = 44\n", + "print(listA)\n", + "print(id(listA))\n", + "print(id(listB))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Shallow copy using the list() constructor\n", + "Shallow copy only works for 1D lists of native data types. \n", + "Sublists, dicts, and other objects will retain the same referece to those objects." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2, 4, 6, [55, 3]]\n" + ] + } + ], + "source": [ + "listA = [2, 4, 6, [1, 3]]\n", + "listB = list(listA)\n", + "listB[1] = 44\n", + "listB[3][0] = 55\n", + "print(listA)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Other ways to make a Shallow copy\n", + "List comprehensions, list.copy(), or copy.copy() can also be used to make *shallow* copies" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2, 4, 6, [55, 3]]\n" + ] + } + ], + "source": [ + "listA = [2, 4, 6, [1, 3]]\n", + "listB = [x for x in listA]\n", + "listB[1] = 44\n", + "listB[3][0] = 55\n", + "print(listA)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2, 4, 6, [55, 3]]\n" + ] + } + ], + "source": [ + "listA = [2, 4, 6, [1, 3]]\n", + "listB = listA.copy()\n", + "listB[1] = 44\n", + "listB[3][0] = 55\n", + "print(listA)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2, 4, 6, [55, 3]]\n" + ] + } + ], + "source": [ + "import copy\n", + "listA = [2, 4, 6, [1, 3]]\n", + "listB = copy.copy(listA)\n", + "listB[1] = 44\n", + "listB[3][0] = 55\n", + "print(listA)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### How to Deep Copy a Python List\n", + "use copy.deepcopy()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2, 4, 6, [1, 3]]\n" + ] + } + ], + "source": [ + "import copy\n", + "listA = [2, 4, 6, [1, 3]]\n", + "listB = copy.deepcopy(listA)\n", + "listB[1] = 44\n", + "listB[3][0] = 55\n", + "print(listA)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Deepcopy with Objects" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "140554035637216 140554035637104\n", + "140554035637216 140554035637216\n", + "140554035637216 140554035637048\n" + ] + } + ], + "source": [ + "class Pony():\n", + " def __init__(self, n):\n", + " self.name = n\n", + " \n", + "# copy.copy on an object gives you 2 unique objects (with same attributes)\n", + "pony1 = Pony('Pinto')\n", + "pony2 = copy.copy(pony1)\n", + "print(id(pony1), id(pony2))\n", + "\n", + "# copy.copy on a list of objects gives you 2 unique lists containing the exact same objects \n", + "# (ie. new list is a shallow copy)\n", + "m = [pony1, pony2]\n", + "n = copy.copy (m)\n", + "print(id(m[0]), id(n[0]))\n", + "\n", + "# use copy.deepcopy to deep copy a list of objects\n", + "n = copy.deepcopy (m)\n", + "print(id(m[0]), id(n[0]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/dict_comprehensions.py b/dict_comprehensions.py new file mode 100644 index 00000000..890c7221 --- /dev/null +++ b/dict_comprehensions.py @@ -0,0 +1,54 @@ +# Python Dictionary Comprehensions +# (c) Joe James 2023 + +# 1. math function to compute values using list +dict1 = {x: 2*x for x in [0, 2, 4, 6]} +print ('1. ', dict1) + +# 2. math function to compute values using range +dict2 = {x: x**2 for x in range(0, 7, 2)} +print ('2. ', dict2) + +# 3. from chars in a string +dict3 = {x: ord(x) for x in 'Kumar'} +print ('3. ', dict3) + +# 4. given lists of keys & values +x = ['Aditii', 'Brandon', 'Clumley', 'Magomed', 'Rishi'] +y = [1, 2, 3, 13, 18] +dict4 = {i: j for (i,j) in zip(x,y)} +print ('4. ', dict4) + +# 5. from chars in a string +x = "python" +dict5 = {i: 3*i.upper() for i in x} +print('5. ', dict5) + +# 6. list comprehension for the value +x = [2, 4, 6, 8] +y = [5, 10, 15, 20] +dict6 = {i: [i + 2*j for j in y] for i in x} +print('6. ', dict6) + +#7. using items +x = {'A':10, 'B':20, 'C':30} +dict7 = {i: j*2 for (i,j) in x.items()} +print('7. ', dict7) + +# 8. conditional comprehension +dict8 = {i: i**3 for i in range(10) if i%2 == 0} +print('8. ', dict8) + +# 9. if-else conditional comprehension +x = {'A':10, 'B':20, 'C':30} +dict9 = {i: (j if j < 15 else j+100) for (i,j) in x.items()} +print('9. ', dict9) + +# 10. transformation from an existing dict +x = {'A':10, 'B':20, 'C':30} +dict10 = {i: x[i]+1 for i in x} +print('10. ', dict10) + + + + diff --git a/exception-handling.py b/exception-handling.py new file mode 100644 index 00000000..57ddf118 --- /dev/null +++ b/exception-handling.py @@ -0,0 +1,66 @@ +# something more about try except +# basic syntax +''' +try: + code1 + +except: + some code that will execute if code 1 fails or raise some error + +else: + this code is executed only if try was succesful i.e no error in code1 + +finally: + + this code will execute in every situation if try fails or not +''' + +filename = 'exception_data.txt' +# Outer try block catches file name or file doesn't exist errors. +try: + with open(filename) as fin: + for line in fin: + # print(line) + items = line.split(',') + total = 0 + + # Inner try bock catches integer conversion errors. + try: + for item in items: + num = int(item) + total += num + print('Total = ' + str(total)) + except: + print('Error converting to integer. ', items) +except: + print('Error opening file. ' + filename) + +finally: + print('This is our optional finally block. Code here will execute no matter what.') + + +# Second example: name Error type in except block; call function from try block. +def this_fails(): + x = 1/0 +try: + this_fails() +except ZeroDivisionError as err: + print('Handling run-time error:', err) + + +def divide_me(n): + x = 1/n + +i = int(input('enter a number ')) +try: + divide_me(i) + +except Exception as e: + print(e) # this will print the error msg but don't kill the execution of program + +else: + print('Your Code Run Successfully') # this will execute if divide_me(i) run sucessfully without an error + +finally: + print('thanks') # this will execute in every condition + diff --git a/exception_data.txt b/exception_data.txt new file mode 100644 index 00000000..bea828db --- /dev/null +++ b/exception_data.txt @@ -0,0 +1,5 @@ +5,7,28,35,42 +2.9,15,4,80,36 +16,25,7,11,19 +18,15,19,x,10 +27,39,12,21,122 \ No newline at end of file diff --git a/factorial.py b/factorial.py new file mode 100644 index 00000000..8e4a65ea --- /dev/null +++ b/factorial.py @@ -0,0 +1,19 @@ +def get_recursive_factorial(n): + if n < 0: + return -1 + elif n < 2: + return 1 + else: + return n * get_recursive_factorial(n-1) + +def get_iterative_factorial(n): + if n < 0: + return -1 + else: + fact = 1 + for i in range(1, n+1): + fact *= i + return fact +print("input should be an integer") +print(get_recursive_factorial(6)) +print(get_iterative_factorial(6)) diff --git a/flatten_list.py b/flatten_list.py new file mode 100644 index 00000000..3f3c57df --- /dev/null +++ b/flatten_list.py @@ -0,0 +1,27 @@ +# Python Flatten Nested Lists +# (c) Joe James 2023 + +# list comprehension method +def flatten1 (myList): + return [i for j in myList for i in j] + +# recursive method +def flatten2 (myList): + flatList = [] + for item in myList: + if isinstance(item, list): + flatList.extend(flatten2(item)) + else: + flatList.append(item) + return flatList + +list1 = [[0], [1, 2], [3, [4, 5]], [6], [7]] +list2 = [0, [1, 2], [3, [4, 5]], [6], 7] + +print("flatten1(list1): ", flatten1(list1)) # works, but only flattens 1 layer of sublists +# print(flatten1(list2)) # error - can't work with list of ints and sublists of ints + +print("flatten2(list1): ", flatten2(list1)) +print("flatten2(list2): ", flatten2(list2)) + + diff --git a/graph_adjacency-list.py b/graph_adjacency-list.py index fec2f958..ebc3f47c 100644 --- a/graph_adjacency-list.py +++ b/graph_adjacency-list.py @@ -4,9 +4,9 @@ def __init__(self, n): self.name = n self.neighbors = list() - def add_neighbor(self, v): + def add_neighbor(self, v, weight): if v not in self.neighbors: - self.neighbors.append(v) + self.neighbors.append((v, weight)) self.neighbors.sort() class Graph: @@ -19,11 +19,11 @@ def add_vertex(self, vertex): else: return False - def add_edge(self, u, v): + def add_edge(self, u, v, weight=0): if u in self.vertices and v in self.vertices: # my YouTube video shows a silly for loop here, but this is a much faster way to do it - self.vertices[u].add_neighbor(v) - self.vertices[v].add_neighbor(u) + self.vertices[u].add_neighbor(v, weight) + self.vertices[v].add_neighbor(u, weight) return True else: return False diff --git a/graph_adjacency-matrix.py b/graph_adjacency-matrix.py index b6d05589..3f315001 100644 --- a/graph_adjacency-matrix.py +++ b/graph_adjacency-matrix.py @@ -1,4 +1,5 @@ # implementation of an undirected graph using Adjacency Matrix, with weighted or unweighted edges +# its definitely work class Vertex: def __init__(self, n): self.name = n @@ -46,4 +47,4 @@ def print_graph(self): for edge in edges: g.add_edge(edge[:1], edge[1:]) -g.print_graph() \ No newline at end of file +g.print_graph() diff --git a/lcm.py b/lcm.py index 8d584ab7..a308141e 100644 --- a/lcm.py +++ b/lcm.py @@ -1,4 +1,4 @@ -# computes Lowest Common Multiple LCM / Least Common Denominator LCD +# computes Lowest Common Multiple (LCM) / Least Common Denominator (LCD) # useful for adding and subtracting fractions # 2 numbers @@ -21,4 +21,4 @@ def lcm3(nums): print(str(lcm(7, 12))) nums = [3, 2, 16] -print(str(lcm3(nums))) \ No newline at end of file +print(str(lcm3(nums))) diff --git a/list_comprehensions.py b/list_comprehensions.py new file mode 100644 index 00000000..6e003514 --- /dev/null +++ b/list_comprehensions.py @@ -0,0 +1,42 @@ +# list comprehensions +# basic format: new_list = [transform sequence [filter] ] +import random + +under_10 = [x for x in range(10)] +print('under_10: ' + str(under_10)) + +squares = [x**2 for x in under_10] +print('squares: ' + str(squares)) + +odds = [x for x in range(10) if x%2 == 1] +print('odds: ' + str(odds)) + +ten_x = [x * 10 for x in range(10)] +print('ten_x: ' + str(ten_x)) + +# get all numbers from a string +s = 'I love 2 go t0 the store 7 times a w3ek.' +nums = [x for x in s if x.isnumeric()] +print('nums: ' + ''.join(nums)) + +# get index of a list item +names = ['Cosmo', 'Pedro', 'Anu', 'Ray'] +idx = [k for k, v in enumerate(names) if v == 'Anu'] +print('index = ' + str(idx[0])) + +# delete an item from a list +letters = [x for x in 'ABCDEF'] +random.shuffle(letters) +letrs = [a for a in letters if a != 'C'] +print(letters, letrs) + +# if-else condition in a comprehension (must come before iteration) +nums = [5, 3, 10, 18, 6, 7] +new_list = [x if x%2 == 0 else 10*x for x in nums] +print('new list: ' + str(new_list)) + +# nested loop iteration for 2D list +a = [[1,2],[3,4]] +new_list = [x for b in a for x in b] +print(new_list) + diff --git a/match statements.ipynb b/match statements.ipynb new file mode 100644 index 00000000..a8fc422d --- /dev/null +++ b/match statements.ipynb @@ -0,0 +1,327 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python 10 - Structural Pattern Matching\n", + "### match statements \n", + "Very similar to switch/case statements in C, Java, and Javascript. \n", + "Can be used in lieu of if/elif/else blocks. \n", + "[documentation](https://www.python.org/dev/peps/pep-0622/)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Can use integer for match variable..." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "large\n" + ] + } + ], + "source": [ + "var = 3\n", + "\n", + "match var:\n", + " case 1:\n", + " print('small')\n", + " case 2:\n", + " print('medium')\n", + " case 3:\n", + " print('large')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### ...or floating point..." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "large\n" + ] + } + ], + "source": [ + "var = 1.5\n", + "\n", + "match var:\n", + " case 1.3:\n", + " print('small')\n", + " case 1.4:\n", + " print('medium')\n", + " case 1.5:\n", + " print('large')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### ...or Tuple...\n", + "Note here we also use a variable to receive *any* value." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "on x-axis\n" + ] + } + ], + "source": [ + "var = (8,0)\n", + "\n", + "match var:\n", + " case (0,x):\n", + " print('on y-axis')\n", + " case (x,0):\n", + " print('on x-axis')\n", + " case (x,y):\n", + " print('not on axis')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### ...or String" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "small\n" + ] + } + ], + "source": [ + "var = \"S\"\n", + "\n", + "match var:\n", + " case \"S\":\n", + " print('small')\n", + " case \"Med\":\n", + " print('medium')\n", + " case \"Lg\":\n", + " print('large')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### The Default case _ \n", + "The default case, using underscore, is optional. " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "large\n" + ] + } + ], + "source": [ + "var = 4\n", + "\n", + "match var:\n", + " case 1:\n", + " print('small')\n", + " case 2:\n", + " print('medium')\n", + " case _:\n", + " print('large')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Conditionals in case \n", + "*or* conditions (using bar) are supported in case statements." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "small\n" + ] + } + ], + "source": [ + "var = 2\n", + "\n", + "match var:\n", + " case 2 | 3:\n", + " print('small')\n", + " case 4 | 5 | 6:\n", + " print('medium')\n", + " case _:\n", + " print('large')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### No breaks needed\n", + "*if* statements are supported, but must follow syntax, case var if (inequality expression). \n", + "\n", + "Note that you do not need break statements. The match block will automatically end execution after one case is executed." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "A\n", + "F\n" + ] + } + ], + "source": [ + "def print_grade(score):\n", + " match score:\n", + " # case score > 90 this does not work!\n", + " case score if score >= 90:\n", + " print('A')\n", + " case score if score >= 80:\n", + " print('B')\n", + " case score if score >= 70:\n", + " print('C')\n", + " case score if score >= 60:\n", + " print('D')\n", + " case _:\n", + " print('F')\n", + " \n", + "print_grade(94)\n", + "print_grade(48)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Python Objects \n", + "Match statements can also use Python objects and instance variables. \n", + "In the final case here we could have used _ default case, but instead used x so that we could use the value of x in our print statement." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "medium\n", + "Size XL is not recognized.\n" + ] + } + ], + "source": [ + "class T_shirt:\n", + " def __init__(self, s):\n", + " self.size = s\n", + "\n", + " def order(self):\n", + " match self.size:\n", + " case 'S' | 'Sm':\n", + " print('small')\n", + " case 'M' | 'Med':\n", + " print('medium')\n", + " case 'L' | 'Lg':\n", + " print('large')\n", + " case x:\n", + " print(f'Size {x} is not recognized.')\n", + " \n", + "shirt1 = T_shirt('Med')\n", + "shirt1.order()\n", + "\n", + "shirt2 = T_shirt('XL')\n", + "shirt2.order()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/python oriented programming b/python oriented programming new file mode 100644 index 00000000..8e3a4499 --- /dev/null +++ b/python oriented programming @@ -0,0 +1,34 @@ +class Mobile: + def make_call(self): + print("i am making a call") + def play_game(self): + print("i am playing games") + +m1=Mobile() + +m1.make_call() + +m1.play_game() + +class Mobile: + def set_color(self,color): + self.color=color + def set_cost(self,cost): + self.cost=cost + def show_color(self): + print("black") + def show_price(self): + print("5000") + def make_call(self): + print("i am making a call") + def play_game(self): + print("i am playing games") + + + +m2=Mobile() + +m2.show_price() + +m2.show_color() + diff --git a/remove_from_list.py b/remove_from_list.py new file mode 100644 index 00000000..9619664f --- /dev/null +++ b/remove_from_list.py @@ -0,0 +1,48 @@ +# Python: del vs pop vs remove from a list +# (c) Joe James 2023 + +def get_dogs(): + return ['Fido', 'Rover', 'Spot', 'Duke', 'Chip', 'Spot'] + +dogs = get_dogs() +print(dogs) + +# Use pop() to remove last item or an item by index and get the returned value. +print('1. pop last item from list:') +myDog = dogs.pop() +print(myDog, dogs) + +dogs = get_dogs() +print('2. pop item with index 1:') +myDog = dogs.pop(1) +print(myDog, dogs) + +# Use remove() to delete an item by value. (raises ValueError if value not found) +dogs = get_dogs() +print('3. remove first Spot from list:') +dogs.remove('Spot') +print(dogs) + +# Use del to remove an item or range of items by index. Or delete entire list. +dogs = get_dogs() +print('4. del item with index 3:') +del(dogs[3]) +print(dogs) + +dogs = get_dogs() +print('5. del items [1:3] from list:') +del(dogs[1:3]) +print(dogs) + +dogs = get_dogs() +print('6. del entire list:') +del(dogs) +print(dogs) + + + + + + + + diff --git a/turtle_graphics.py b/turtle_graphics.py new file mode 100644 index 00000000..da671ef3 --- /dev/null +++ b/turtle_graphics.py @@ -0,0 +1,35 @@ +import turtle as tt +from random import randint, sample + +def draw(): + size = randint(40, 300) + angles = (144, 150, 157.5, 160, 165) + angle = sample(angles, 1)[0] + + colors = [ + ('#922B21', '#E6B0AA'), ('#76448A', '#D2B4DE'), ('#1F618D', '#AED6F1'), ('#515A5A', '#EAEDED'), + ('#148F77', '#D1F2EB'), ('#B7950B', '#F7DC6F'), ('#F39C12', '#FDEBD0'), ('#BA4A00', '#F6DDCC')] + color = sample(colors, 1)[0] + tt.color(color[0], color[1]) + + x_pos = randint(-200,200) + y_pos = randint(-200,200) + tt.pu() + tt.setpos(x_pos, y_pos) + start_position = tt.pos() + tt.pd() + + tt.begin_fill() + while True: + tt.forward(size) + tt.left(angle) + if abs(tt.pos() - start_position) < 1: + break + tt.end_fill() + +tt.circle(100) +for i in range(3): + tt.pensize(i%3) + draw() + +tt.done() \ No newline at end of file