Data Analytics Using Python - Sem-6 - IT
Data Analytics Using Python - Sem-6 - IT
ON
B.Tech (CSE/IT)
SEMESTER-VI
2
3
Table of Contents
Module-1 ................................................................................................................................................ 7
INTRODUCTION TO PYTHON ........................................................................................................ 7
1.1 Brief history of python ...................................................................................................................... 7
1.2 Data types in Python ......................................................................................................................... 9
1.2.1 Python Numbers......................................................................................................................... 9
1.3 Python List ...................................................................................................................................... 10
1.4 Python Tuple ................................................................................................................................... 11
1.5 Python Set ....................................................................................................................................... 11
1.6 Python Strings ................................................................................................................................. 11
1.7 Python Dictionary ........................................................................................................................... 12
1.8 Python Variables ............................................................................................................................. 12
1.8.1 Assigning a value to a Variable in Python ............................................................................... 13
1.9 Constants ......................................................................................................................................... 14
1.10 Literals .......................................................................................................................................... 14
1.10.1 Numeric Literals .................................................................................................................... 14
1.10.2 String literals .......................................................................................................................... 15
1.10.3 Boolean literals ...................................................................................................................... 16
1.11 Python Keywords .......................................................................................................................... 17
1.12 Rules and Naming Convention for Variables and Constants ........................................................ 17
1.13 Operators ....................................................................................................................................... 18
1.9. Precedence and Associativity of Operators in Python ................................................................... 23
1.10 File Handling in Python ................................................................................................................ 24
1.11 Control Statements ........................................................................................................................ 26
Module-2 .............................................................................................................................................. 28
FUNCTIONS AND DATA STRUCTURES IN PYTHON .............................................................. 28
2.1 Functions- Basics of functions ........................................................................................................ 28
2.2 Recursive Functions ........................................................................................................................ 29
2.3 First Class functions in Python or Functions as Objects ................................................................. 30
2.4 Lists in Python ................................................................................................................................ 31
2.5 Lists – Methods to process lists ...................................................................................................... 35
2.6 Copy in Python (Deep Copy and Shallow Copy) ........................................................................... 40
2.7 Using List as Stack and Queues in Python ..................................................................................... 44
4
2.8 Nested lists ...................................................................................................................................... 45
2.9 List as Matrix .................................................................................................................................. 45
2.10 Tuples in Python ........................................................................................................................... 47
2.11 Nested Tuples................................................................................................................................ 51
2.12 Dictionary ..................................................................................................................................... 52
2.13 Ordered Dictionary in Python ....................................................................................................... 58
2.14 Iterate over a dictionary in Python ................................................................................................ 61
2.15 Conversion of list and strings into dictionary ............................................................................... 63
2.16 Sets and Frozen sets in Python...................................................................................................... 66
2.17 Lambda function in python ........................................................................................................... 69
2.18 Filter() in python ........................................................................................................................... 70
2.19 reduce() in Python ......................................................................................................................... 71
2.20 Map() function .............................................................................................................................. 73
2.21 Iterators in Python ......................................................................................................................... 73
2.22 List Comprehension ...................................................................................................................... 77
Module-3 .............................................................................................................................................. 79
OBJECTS IN PYTHON ..................................................................................................................... 79
3.1 Classes and Instance attributes........................................................................................................ 79
3.2 Inheritance....................................................................................................................................... 80
3.3 Different forms of Inheritance ........................................................................................................ 81
3.4 Method Resolution Order (MRO) ................................................................................................... 82
3.5 Magic methods ................................................................................................................................ 84
3.6 Operator Overloading in Python ..................................................................................................... 87
3.7 Meta Classes ................................................................................................................................... 89
3.8 Abstract and Inner classes ............................................................................................................... 91
3.9 Exception Handling ........................................................................................................................ 94
3.10 Modular Programs and Packages .................................................................................................. 96
Module-4 ............................................................................................................................................ 100
Numerical Analysis in python .......................................................................................................... 100
4.1 Introduction to NumPy ................................................................................................................. 100
4.2 NumPy - Ndarray Object .............................................................................................................. 100
4.3 NumPy Numerical types ............................................................................................................... 107
4.3.1 Data type Object (dtype) in NumPy Python .......................................................................... 107
4.3.2 Character Codes ..................................................................................................................... 109
5
4.3.3 One Dimensional Indexing using index arrays ...................................................................... 109
4.4 Creating a Two-dimensional Array............................................................................................... 112
4.5 Stacking Arrays using numpy.stack() in Python ........................................................................... 113
4.6 Splitting NumPy arrays ................................................................................................................. 114
4.7 NumPy - Array Attributes ............................................................................................................. 115
4.8 Converting 1-d and 2-d Arrays ..................................................................................................... 118
4.9 Creating Array views and copies .................................................................................................. 119
4.10 Indexing Numpy arrays with Booleans ....................................................................................... 123
4.11 Broadcasting numPy arrays ........................................................................................................ 124
Module-5 ............................................................................................................................................ 128
DATA MANIPULATION AND VISUALIZATION IN PYTHON.......................................... 128
5.1 Data Frames in Panda ................................................................................................................... 128
5.2 Creating Data frames from .csv and excel files ............................................................................ 128
5.3 Creating DataFrame from dict of ndarray/lists ............................................................................. 129
5.4 Dataframes Aggregation and concatenation ................................................................................. 130
5.5 Plotting using matplotlib & panda ................................................................................................ 133
6
Module-1
INTRODUCTION TO PYTHON
It was that time when working on Python started. Soon after that, Guido Van Rossum began
doing its application based work in December of 1989 by at Centrum Wiskunde &
Informatica (CWI) which is situated in Netherland. It was started firstly as a hobby project
because he was looking for an interesting project to keep him occupied during Christmas.
The programming language which Python is said to have succeeded is ABC Programming
Language, which had the interfacing with the Amoeba Operating System and had the feature
of exception handling. He had already helped to create ABC earlier in his career and he had
seen some issues with ABC but liked most of the features. He had taken the syntax of ABC,
and some of its good features. It came with a lot of complaints too, so he fixed those issues
completely and had created a good scripting language which had removed all the flaws.
The inspiration for the name came from BBC’s TV Show – ‘Monty Python’s Flying Circus’,
as he was a big fan of the TV show and also he wanted a short, unique and slightly
mysterious name for his invention and hence he named it Python!
The language was finally released in 1991. When it was released, it used a lot fewer codes to
express the concepts, when we compare it with Java, C++ & C. Its design philosophy was
quite good too. Its main objective is to provide code readability and advanced developer
productivity. When it was released it had more than enough capability to provide classes with
inheritance, several core data types exception handling and functions.
Following are the illustrations of different versions of Python along with the timeline.
7
8
1.2 Data types in Python
Every value in Python has a datatype. Since everything is an object in Python programming,
data types are actually classes and variables are instance (object) of these classes.
There are various data types in Python. Some of the important types are listed below.
a=5
print(a, "is of type", type(a))
a = 2.0
print(a, "is of type", type(a))
9
a = 1+2j
print(a, "is complex number?", isinstance(1+2j,complex))
A floating point number is accurate up to 15 decimal places. Integer and floating points are
separated by decimal points. 1 is integer, 1.0 is floating point number.
Complex numbers are written in the form, x + yj, where x is the real part and y is the
imaginary part. Here are some examples.
>>> a = 1234567890123456789
>>> a
1234567890123456789
>>> b = 0.1234567890123456789
>>> b
0.12345678901234568
>>> c = 1+2j
>>> c
(1+2j)
Notice that the float variable b got truncated.
Declaring a list is pretty straight forward. Items separated by commas are enclosed within
brackets [ ].
a = [5,10,15,20,25,30,35,40]
# a[2] = 15
print("a[2] = ", a[2])
>>> a = [1,2,3]
>>> a[2]=4
>>> a
10
[1, 2, 4]
Tuples are used to write-protect data and are usually faster than list as it cannot change
dynamically. It is defined within parentheses () where items are separated by commas.
We can use the slicing operator [] to extract items but we cannot change its value.
t = (5,'program', 1+3j)
# t[1] = 'program'
print("t[1] = ", t[1])
# Generates error
# Tuples are immutable
t[0] = 10
a = {5,2,3,1,4}
# printing set variable
print("a = ", a)
Like list and tuple, slicing operator [ ] can be used with string. Strings are immutable.
11
s = 'Hello world!'
# s[4] = 'o'
print("s[4] = ", s[4])
# s[6:11] = 'world'
print("s[6:11] = ", s[6:11])
# Generates error
# Strings are immutable in Python
s[5] ='d'
It is generally used when we have a huge amount of data. Dictionaries are optimized for
retrieving data. We must know the key to retrieve the value.
In Python, dictionaries are defined within braces {} with each item being a pair in the
form key:value. Key and value can be of any type.
1. >>> d = {1:'value','key':2}
2. >>> type(d)
3. <class 'dict'>
We use key to retrieve the respective value. But not the other way around.
d = {1:'value','key':2}
print(type(d))
# Generates error
print("d[2] = ", d[2]);
A variable is a named location used to store data in the memory. It is helpful to think
of variables as a container that holds data which can be changed later throughout
programming. For example,
1. number = 10
12
Here, we have created a named number. We have assigned value 10 to the variable.
You can think variable as a bag to store books in it and those books can be replaced at any
time.
1. number = 10
2. number = 1.1
Initially, the value of number was 10. Later it's changed to 1.1.
Note: In Python, we don't assign values to the variables, whereas Python gives the reference
of the object (value) to the variable.
website = "apple.com"
print(website)
When you run the program, the output will be:
apple.com
In the above program, we assigned a value apple.com to the variable website. Then we print
the value assigned to website i.e. apple.com
website = "apple.com"
print(website)
print(website)
apple.com
programiz.com
In the above program, we have assigned apple.com to the website variable initially. Then, it's
value is changed to programiz.com.
a, b, c = 5, 3.2, "Hello"
print (a)
print (b)
print (c)
13
If we want to assign the same value to multiple variables at once, we can do this as
x = y = z = "same"
print (x)
print (y)
print (z)
1.9 Constants
A constant is a type of variable whose value cannot be changed. It is helpful to think of
constants as containers that hold information which cannot be changed later.
Non technically, you can think of constant as a bag to store some books and those books
cannot be replaced once placed inside the bag.
Create a constant.py
PI = 3.14
GRAVITY = 9.8
Create a main.py
import constant
print(constant.PI)
print(constant.GRAVITY)
When you run the program, the output will be:
3.14
9.8
1.10 Literals
Literal is a raw data given in a variable or constant. In Python, there are various types of
literals they are as follows:
14
Numeric Literals are immutable (unchangeable). Numeric literals can belong to 3 different
numerical types Integer, Float, and Complex.
#Float Literal
float_1 = 10.5
float_2 = 1.5e2
#Complex Literal
x = 3.14j
print(a, b, c, d)
print(float_1, float_2)
print(x, x.imag, x.real)
We assigned integer literals into different variables. Here, a is binary literal, b is a decimal
literal, c is an octal literal and d is a hexadecimal literal.
When we print the variables, all the literals are converted into decimal values.
10.5 and 1.5e2 are floating-point literals. 1.5e2 is expressed with exponential and is
equivalent to 1.5 * 102.
We assigned a complex literal i.e 3.14j in variable x. Then we use imaginary literal (x.imag)
and real literal (x.real) to create imaginary and real part of complex number.
A string literal is a sequence of characters surrounded by quotes. We can use single, double
or triple quotes for a string. And, a character literal is a single character surrounded by single
or double quotes.
15
print(strings)
print(char)
print(multiline_str)
print(unicode)
print(raw_str)
This is Python
C
This is a multiline string with more than one line code.
Ünicöde
raw \n string
In the above program, This is Python is a string literal and C is a character literal. The value
with triple-quote """ assigned in the multiline_str is multi-line string literal. The
u"\u00dcnic\u00f6de" is a unicode literal which supports characters other than English and
r"raw \n string" is a raw string literal.
x = (1 == True)
y = (1 == False)
a = True + 4
b = False + 10
print("x is", x)
print("y is", y)
print("a:", a)
print("b:", b)
Similarly, we can use the True and False in numeric expressions as the value. The value of a
is 5 because we add True which has value of 1 with 4. Similarly, b is 10 because we add the
False having value of 0 with 10.
16
1.11 Python Keywords
We cannot use a keyword as a variable name, function name or any other identifier. They are
used to define the syntax and structure of the Python language.
In Python, keywords are case sensitive.There are 33 keywords in Python 3.7. This number
can vary slightly in the course of time.All the keywords except True, False and None are in
lowercase and they must be written as it is. The list of all the keywords is given below.
2. Create a name that makes sense. For example, vowel makes more sense than v.
3. If you want to create a variable name having two words, use underscore to separate them.
For example:
my_name
current_salary
17
4. Use capital letters possible to declare a constant. For example:
PI
G
MASS
SPEED_OF_LIGHT
TEMP
1.13 Operators
Operators are the constructs which can manipulate the value of operands.
Consider the expression 4 + 5 = 9. Here, 4 and 5 are called operands and + is called operator.
Arithmetic Operators
Comparison (Relational) Operators
Assignment Operators
Logical Operators
Bitwise Operators
Membership Operators
Identity Operators
Let us have a look on all operators one by one.
# Addition of numbers
add = a + b
# Subtraction of numbers
sub = a - b
# Multiplication of number
18
mul = a * b
# Division(float) of number
div1 = a / b
# Division(floor) of number
div2 = a // b
# print results
print(add)
print(sub)
print(mul)
print(div1)
print(div2)
print(mod)
Output:
13
5
36
2.25
2
1
2. Comparison Operators
These operators compare the values on either sides of them and decide the relation among
them. They are also called Relational operators.
Assume variable a holds 10 and variable b holds 20, then −
19
3. Assignment Operators
Assume variable a holds 10 and variable b holds 20, then −
20
4. Bitwise Operators
Bitwise operator works on bits and performs bit by bit operation. Assume if a = 60; and b =
13; Now in the binary format their values will be 0011 1100 and 0000 1101 respectively.
Following table lists out the bitwise operators supported by Python language with an example
each in those, we use the above two variables (a and b) as operands −
a = 0011 1100
b = 0000 1101
-----------------
~a = 1100 0011
21
5. Logical Operators
There are following logical operators supported by Python language. Assume variable a holds
10 and variable b holds 20 then
6. Membership Operators
Python’s membership operators test for membership in a sequence, such as strings, lists, or
tuples. There are two membership operators as explained below –
22
7. Identity Operators
Identity operators compare the memory locations of two objects. There are two Identity
operators explained below –
The combination of values, variables, operators and function calls is termed as an expression.
Python interpreter can evaluate a valid expression.
>>> 5 - 7
-2
Here 5 - 7 is an expression. There can be more than one operator in an expression.
To evaluate these type of expressions there is a rule of precedence in Python. It guides the
order in which operation are carried out.For example, multiplication has higher precedence
than subtraction.
But we can change this order using parentheses () as it has higher precedence. Parentheses ()
has higher precendence.
# Output: 12
(10 - 4) * 2
The operator precedence in Python are listed in the following table. It is in descending order,
upper group has higher precedence than the lower ones.
23
1.10 File Handling in Python
Python too supports file handling and allows users to handle files i.e., to read and write files,
along with many other file handling options, to operate on files. The concept of file handling
has stretched over various other languages, but the implementation is either complicated or
lengthy, but alike other concepts of Python, this concept here is also easy and short. Python
treats file differently as text or binary and this is important. Each line of code includes a
sequence of characters and they form text file. Each line of a file is terminated with a special
character, called the EOL or End of Line characters like comma {,} or newline character. It
ends the current line and tells the interpreter a new one has begun. Let’s start with Reading
and Writing files.
24
We use open () function in Python to open a file in read or write mode. As explained above,
open ( ) will return a file object. To return a file object we use open() function along with two
arguments, that accepts file name and the mode, whether to read or write. So, the syntax
being: open(filename, mode). There are three kinds of mode, that Python provides and how
files can be opened:
“ r “, for reading.
“ w “, for writing.
“ a “, for appending.
One must keep in mind that the mode argument is not mandatory. If not passed, then Python
will assume it to be “ r ” by default. Let’s look at this program and try to analyze how the
read mode works:
There is more than one way to read a file in Python. If you need to extract a string that
contains all characters in the file then we can use file.read(). The full code would work like
this:
# Python code to illustrate read() mode
file = open("file.text", "r")
print file.read()
Another way to read a file is to call a certain number of characters like in the following code
the interpreter will read the first five characters of stored data and return it as a string:
# Python code to illustrate read() mode character wise
file = open("file.txt", "r")
print file.read(5)
Creating a file using write() mode
Let’s see how to create a file and how write mode works:
To manipulate the file, write the following in your Python environment:
# Python code to create a file
file = open('geek.txt','w')
file.write("This is the write command")
file.write("It allows us to write in a particular file")
file.close()
25
The close() command terminates all the resources in use and frees the system of this
particular program.
Working of append() mode
Let’s see how the append mode works:
Continue
Break
Pass
1) Continue Statement:
When the program encounters continue statement, it will skip the statements which are
present after the continue statement inside the loop and proceed with the next iterations.
Syntax:
continue
Example:
if (char == ‘y’):
continue;
print(“Current character: “, char)
Output:
Current character: P
Current character: t
Current character: h
Current character: o
Current character: n
In the above example during the second iteration if the condition evaluates to true, then it will
execute the continue statement. So whatever statements are present below, for loop will be
skipped, hence letter ‘y’ is not printed.
2) Break Statement:
26
The break statement is used to terminate the loop containing it, the control of the program
will come out of that loop.
Syntax:
for char in ‘Python’:
if (char == ‘h’):
break;
print(“Current character: “, char)
Output:
Current character: P
Current character: y
Current character: t
3) Pass Statement:
Pass statement is python is a null operation, which is used when the statement is required
syntactically.
Syntax:
pass
Example:
Output:
Current character: P
Current character: y
Current character: t
Current character: h
Current character: o
Current character: n
27
Module-2
A function is a block of code which only runs when it is called.You can pass data, known as
parameters, into a function. A function can return data as a result.
Creating a Function
In Python a function is defined using the def keyword:
Example
def my_function():
print("Hello from a function")
Calling a Function
To call a function, use the function name followed by parenthesis:
Example
def my_function():
print("Hello from a function")
my_function()
Parameters
Information can be passed to functions as parameter. Parameters are specified after the
function name, inside the parentheses. You can add as many parameters as you want, just
separate them with a comma.
The following example has a function with one parameter (fname). When the function is
called, we pass along a first name, which is used inside the function to print the full name:
Example
def my_function(fname):
print(fname + " Refsnes")
my_function("Emil")
my_function("Tobias")
my_function("Linus")
You can send any data types of parameter to a function (string, number, list, dictionary etc.),
and it will be treated as the same data type inside the function.
E.g. if you send a List as a parameter, it will still be a List when it reaches the function:
28
Example
def my_function(food):
for x in food:
print(x)
Return Values
To let a function return a value, use the return statement:
Example
def my_function(x):
return 5 * x
print(my_function(3))
print(my_function(5))
print(my_function(9))
The developer should be very careful with recursion as it can be quite easy to slip into writing
a function which never terminates, or one that uses excess amounts of memory or processor
power. However, when written correctly recursion can be a very efficient and
mathematically-elegant approach to programming.
In this example, tri_recursion() is a function that we have defined to call itself ("recurse").
We use the k variable as the data, which decrements (-1) every time we recurse. The
recursion ends when the condition is not greater than 0 (i.e. when it is 0).
To a new developer it can take some time to work out how exactly this works, best way to
find out is by testing and modifying it.
Example
Recursion Example
def tri_recursion(k):
if(k>0):
result = k+tri_recursion(k-1)
print(result)
else:
result = 0
return result
29
tri_recursion(6)
First class objects in a language are handled uniformly throughout. They may be stored in
data structures, passed as arguments, or used in control structures. A programming language
is said to support first-class functions if it treats functions as first-class objects. Python
supports the concept of First Class functions.
1. Functions are objects: Python functions are first class objects. In the example below, we
are assigning function to a variable. This assignment doesn’t call the function. It takes the
function object referenced by shout and creates a second name pointing to it, yell.
def shout(text):
return text.upper()
print shout('Hello')
yell = shout
print yell('Hello')
Output
HELLO
HELLO
2. Functions can be passed as arguments to other functions: Because functions are objects
we can pass them as arguments to other functions. Functions that can accept other functions
as arguments are also called higher-order functions. In the example below, we have created a
function greet which takes a function as an argument.
def whisper(text):
return text.lower()
30
def greet(func):
# storing the function in a variable
greeting = func("Hi, I am created by a function passed as an argument.")
print greeting
greet(shout)
greet(whisper)
Output
3. Functions can return another function: Because functions are objects we can return a
function from another function. In the below example, the create_adder function returns
adder function.
def create_adder(x):
def adder(y):
return x+y
return adder
add_15 = create_adder(15)
print add_15(10)
Output
25
Lists are just like the arrays, declared in other languages. Lists need not be homogeneous
always which makes it a most powerful tool in Python. A single list may contain Data Types
like Integers, Strings, as well as Objects. Lists are mutable, and hence, they can be altered
even after their creation.
List in Python are ordered and have a definite count. The elements in a list are indexed
according to a definite sequence and the indexing of a list is done with 0 being the first index.
Each element in the list has its definite place in the list, which allows duplicating of elements
in the list, with each element having its own distinct place and credibility.
Lists in Python can be created by just placing the sequence inside the square brackets[].
Unlike Sets, list doesn’t need a built-in function for creation of list.
31
# Python program to demonstrate a Creation of List
# Creating a List
List = []
print("Intial blank List: ")
print(List)
Multi-Dimensional List:
[['Geeks', 'For'], ['Geeks']]
32
# Creating a List with
# mixed type of values
# (Having numbers and strings)
List = [1, 2, 'Geeks', 4, 'For', 6, 'Geeks']
print("\nList with the use of Mixed Values: ")
print(List)
Output:
# Creating a List
List = []
print("Initial blank List: ")
print(List)
33
print(List)
Output:
# Creating a List
List = [1,2,3,4]
print("Initial List: ")
print(List)
# Addition of Element at
# specific Position
# (using Insert Method)
List.insert(3, 12)
List.insert(0, 'Geeks')
print("\nList after performing Insert Operation: ")
print(List)
Output:
Initial List:
[1, 2, 3, 4]
Other than append() and insert() methods, there’s one more method for Addition of elements,
extend(), this method is used to add multiple elements at the same time at the end of the list.
34
# Creating a List
List = [1,2,3,4]
print("Initial List: ")
print(List)
# Addition of multiple elements to the List at the end (using Extend Method)
Initial List:
[1, 2, 3, 4]
1. “in” operator :- This operator is used to check if an element is present in the list or not.
Returns true if element is present in list else returns false.
2. “not in” operator :- This operator is used to check if an element is not present in the list
or not. Returns true if element is not present in list else returns false.
# Python code to demonstrate the working of "in" and "not in" initializing list
lis = [1, 4, 3, 2, 5]
Output:
35
4. min() :- This function returns the minimum element of list.
# Python code to demonstrate the working of len(), min() and max() initializing list 1
lis = [2, 1, 3, 5, 4]
6. “+” operator :- This operator is used to concatenate two lists into a single list.
7. “*” operator :- This operator is used to multiply the list “n” times and return the single
list.
# Python code to demonstrate the working of "+" and "*" initializing list 1
lis = [1, 2, 3]
# initializing list 2
lis1 = [4, 5, 6]
print ("\r")
36
# priting combined lists
print ("list after combining is : ", end="")
for i in range(0,len(lis3)):
print (lis3[i], end=" ")
Output:
list after concatenation is : 1 2 3 4 5 6
list after combining is : 1 2 3 1 2 3 1 2 3
8. index(ele, beg, end) :- This function returns the index of first occurrence of element after
beg and before end.
# Python code to demonstrate the working of index() and count() initializing list 1
lis = [2, 1, 3, 5, 4, 3]
Negative indexing
In Python, negative sequence indexes represent positions from the end of the array. Instead of
having to compute the offset as in List[len(List)-3], it is enough to just write List[-3].
Negative indexing means beginning from the end, -1 refers to the last item, -2 refers to the
second last item etc.
37
Geeks
For
Note – Remove method in List will only remove the first occurrence of the searched element.
# Creating a List
List = [1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12]
print("Intial List: ")
print(List)
Intial List:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
Slicing of a List
In Python List, there are multiple ways to print the whole List with all the elements, but to
print a specific range of elements from the list, we use Slice operation. Slice operation is
performed on Lists with the use of colon(:). To print elements from beginning to a range use
[:Index], to print elements from end use [:-Index], to print elements from specific Index till
the end use [Index:], to print elements within a range, use [Start Index:End Index] and to print
38
whole List with the use of slicing operation, use [:]. Further, to print whole List in reverse
order, use [::-1].
Note – To print elements of List from rear end, use Negative Indexes.
# Creating a List
List = ['G','E','E','K','S','F',
'O','R','G','E','E','K','S']
print("Intial List: ")
print(List)
Sliced_List = List[3:8]
print("\nSlicing elements in a range 3-8: ")
print(Sliced_List)
Sliced_List = List[5:]
print("\nElements sliced from 5th "
"element till the end: ")
print(Sliced_List)
Sliced_List = List[:]
print("\nPrinting all elements using slice operation: ")
print(Sliced_List)
Output:
Intial List:
['G', 'E', 'E', 'K', 'S', 'F', 'O', 'R', 'G', 'E', 'E', 'K', 'S']
39
2.6 Copy in Python (Deep Copy and Shallow Copy)
In Python, Assignment statements do not copy objects, they create bindings between a target
and an object. When we use = operator user thinks that this creates a new object; well, it
doesn’t. It only creates a new variable that shares the reference of the original object.
Sometimes a user wants to work with mutable objects, in order to do that user looks for a way
to create “real copies” or “clones” of these objects. Or, sometimes a user wants copies that
user can modify without automatically modifying the original at the same time, in order to do
that we create copies of objects.
A copy is sometimes needed so one can change one copy without changing the other. In
Python, there are two ways to create copies :
Deep copy
Shallow copy
In order to implement these copy, we use copy module. We use copy module for shallow and
deep copy operations. For Example
import copy
# initializing list 1
40
Deep copy is a process in which the copying process occurs recursively. It means first
constructing a new collection object and then recursively populating it with copies of the
child objects found in the original. In case of deep copy, a copy of object is copied in other
object. It means that any changes made to a copy of object do not reflect in the original
object. In python, this is implemented using “deepcopy()” function.
import copy
# initializing list 1
li2 = copy.deepcopy(li1)
print("\r")
li2[2][0] = 7
# Change is reflected in l2
41
print ("The new list of elements after deep copying ")
for i in range(0,len( li1)):
print (li2[i],end=" ")
print("\r")
Output:
In the above example, the change made in the list did not effect in other lists, indicating the
list is deep copied.
A shallow copy means constructing a new collection object and then populating it with
references to the child objects found in the original. The copying process does not recurse and
therefore won’t create copies of the child objects themselves. In case of shallow copy, a
reference of object is copied in other object. It means that any changes made to a copy of
object do reflect in the original object. In python, this is implemented using “copy()”
function.
42
# importing "copy" for copy operations
import copy
# initializing list 1
li1 = [1, 2, [3,5], 4]
print("\r")
li2[2][0] = 7
Output:
In the above example, the change made in the list did effect in other list, indicating the list is
shallow copied.
Important Points:
The difference between shallow and deep copying is only relevant for compound objects
(objects that contain other objects, like lists or class instances):
A shallow copy constructs a new compound object and then (to the extent possible)
inserts references into it to the objects found in the original.
A deep copy constructs a new compound object and then, recursively, inserts copies
into it of the objects found in the original.
43
2.7 Using List as Stack and Queues in Python
Stack
Stack works on the principle of “Last-in, first-out”. Also, the inbuilt functions in Python
make the code short and simple. To add an item to the top of the list, i.e., to push an item, we
use append() function and to pop out an element we use pop() function. These functions
work quiet efficiently and fast in end operations.
Let’s look at an example and try to understand the working of push() and pop() function:
Example:
# Python code to demonstrate Implementing stack using list
stack = ["Amar", "Akbar", "Anthony"]
stack.append("Ram")
stack.append("Iqbal")
print(stack)
print(stack.pop())
print(stack)
print(stack.pop())
print(stack)
Output :
Queue
Implementing Queue is a bit different. Queue works on the principle of “First-in, first-out”.
Time plays an important factor here. We saw that during the implementation of stack we used
append() and pop() function which was efficient and fast because we inserted and popped
elements from the end of the list, but in queue when insertion and pops are made from the
beginning of the list, it is slow. This occurs due to the properties of list, which is fast at the
end operations but slow at the beginning operations, as all other elements have to be shifted
one by one. So, we prefer the use of collections.deque over list, which was specially designed
to have fast appends and pops from both the front and back end.
#Python code to demonstrate Implementing Queue using deque and list from collections
import deque
queue = deque(["Ram", "Tarun", "Asif", "John"])
print(queue)
queue.append("Akbar")
print(queue)
queue.append("Birbal")
44
print(queue)
print(queue.popleft())
print(queue.popleft())
print(queue)
Output:
A list can even have another list as an item. This is called nested list.
# nested list
# Nested indexing
print(n_list[0][1])
# Output: a
print(n_list[1][3])
# Output: 5
A matrix is a two-dimensional data structure where numbers are arranged into rows and
columns. For example:
45
This matrix is a 3x4 (pronounced "three by four") matrix because it has 3 rows and 4
columns.
Python Matrix
Python doesn't have a built-in type for matrices. However, we can treat list of a list as a
matrix. For example:
A = [[1, 4, 5],
[-5, 8, 9]]
We can treat this list of a list as a matrix having 2 rows and 3 columns.
A = [[1, 4, 5, 12],
[-5, 8, 9, 0],
[-6, 7, 11, 19]]
print("A =", A)
print("A[1] =", A[1]) # 2nd row
print("A[1][2] =", A[1][2]) # 3rd element of 2nd row
print("A[0][-1] =", A[0][-1]) # Last element of 1st Row
column = []; # empty list
for row in A:
column.append(row[2])
print("3rd column =", column)
When we run the program, the output will be:
46
3rd column = [5, 9, 11]
# 3x3 matrix
X = [[12,7,3],
[4 ,5,6],
[7 ,8,9]]
# 3x4 matrix
Y = [[5,8,1,2],
[6,7,3,0],
[4,5,9,1]]
# result is 3x4
result = [[0,0,0,0],
[0,0,0,0],
[0,0,0,0]]
# iterate through rows of X
for i in range(len(X)):
# iterate through columns of Y
for j in range(len(Y[0])):
# iterate through rows of Y
for k in range(len(Y)):
result[i][j] += X[i][k] * Y[k][j]
for r in result:
print(r)
# An empty tuple
empty_tuple = ()
print (empty_tuple)
Output:
()
47
tup = 'python', 'geeks'
print(tup)
('python', 'geeks')
('python', 'geeks')
Note: In case your generating a tuple with a single element, make sure to add a comma
after the element.
Concatenation of Tuples
tuple1 = (0, 1, 2, 3)
tuple2 = ('python', 'geek')
Nesting of Tuples
tuple1 = (0, 1, 2, 3)
tuple2 = ('python', 'geek')
tuple3 = (tuple1, tuple2)
print(tuple3)
Output :
tuple3 = ( 0, 1)
del tuple3
print(tuple3)
Error:
48
File "d92694727db1dc9118a5250bf04dafbd.py", line 6, in <module>
print(tuple3)
NameError: name 'tuple3' is not defined
Output:
(0, 1)
list1 = [0, 1, 2]
print(tuple(list1))
print(tuple('python')) # string 'python'
Output
(0, 1, 2)
('p', 'y', 't', 'h', 'o', 'n')
Takes a single parameter which may be a list,string,set or even a dictionary( only keys are
taken as elements) and converts them to a tuple.# Code for deleting a tuple
tuple3 = ( 0, 1)
del tuple3
print(tuple3)
Error:
Output:
(0, 1)
49
Finding Length of a Tuple
list1 = [0, 1, 2]
print(tuple(list1))
print(tuple('python')) # string 'python'
Output
(0, 1, 2)
('p', 'y', 't', 'h', 'o', 'n')
Takes a single parameter which may be a list,string,set or even a dictionary( only keys are
taken as elements) and converts them to a tuple.
Tuples in a loop
tup = ('geek',)
n = 5 #Number of time loop runs
for i in range(int(n)):
tup = (tup,)
print(tup)
Output :
(('geek',),)
((('geek',),),)
(((('geek',),),),)
((((('geek',),),),),)
(((((('geek',),),),),),)
50
# cmp() returns 0 if matched, 1 when not tuple1
# is longer and -1 when tuple1 is shoter
print('Not the same')
else:
print('Same')
print ('Maximum element in tuples 1,2: ' +
str(max(tuple1)) + ',' +
str(max(tuple2)))
print ('Minimum element in tuples 1,2: ' +
str(min(tuple1)) + ',' + str(min(tuple2)))
Output
Note: max() and min() checks the based on ASCII values. If there are two strings in a
tuple, then the first different character in the strings are checked.
Tuples are unchangeable, so you cannot remove items from it, but you can delete the tuple
completely:
Example
The del keyword can delete the tuple completely:
Nested tuples are accessed using nested indexing, as shown in the example below.
# nested index
print(n_tuple[0][3]) # 's'
print(n_tuple[1][1]) #4
However, there are certain advantages of implementing a tuple over a list. Below listed are
some of the main advantages:
51
We generally use tuple for heterogeneous (different) datatypes and list for homogeneous
(similar) datatypes.
Since tuples are immutable, iterating through tuple is faster than with list. So there is a slight
performance boost.
Tuples that contain immutable elements can be used as a key for a dictionary. With lists, this
is not possible.
If you have data that doesn't change, implementing it as tuple will guarantee that it remains
write-protected.
2.12 Dictionary
A dictionary is a collection which is unordered, changeable and indexed. In Python
dictionaries are written with curly brackets, and they have keys and values.
Example
Create and print a dictionary:
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
print(thisdict)
Accessing Items
You can access the items of a dictionary by referring to its key name, inside square brackets:
Example
Get the value of the "model" key:
x = thisdict["model"]
There is also a method called get() that will give you the same result:
Example
Get the value of the "model" key:
x = thisdict.get("model")
Change Values
You can change the value of a specific item by referring to its key name:
Example
Change the "year" to 2018:
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
52
thisdict["year"] = 2018
You can loop through a dictionary by using a for loop.When looping through a dictionary, the
return value are the keys of the dictionary, but there are methods to return the values as well.
Example
Print all key names in the dictionary, one by one:
for x in thisdict:
print(x)
Example
Print all values in the dictionary, one by one:
for x in thisdict:
print(thisdict[x])
Example
You can also use the values() function to return values of a dictionary:
for x in thisdict.values():
print(x)
Example
Loop through both keys and values, by using the items() function:
for x, y in thisdict.items():
print(x, y)
Example
Check if "model" is present in the dictionary:
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
if "model" in thisdict:
print("Yes, 'model' is one of the keys in the thisdict dictionary")
Dictionary Length
To determine how many items (key-value pairs) a dictionary has, use the len() method.
Example
Print the number of items in the dictionary:
53
print(len(thisdict))
Adding Items
Adding an item to the dictionary is done by using a new index key and assigning a value to it:
Example
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
thisdict["color"] = "red"
print(thisdict)
Removing Items
There are several methods to remove items from a dictionary:
Example
The pop() method removes the item with the specified key name:
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
thisdict.pop("model")
print(thisdict)
Example
The popitem() method removes the last inserted item (in versions before 3.7, a random item
is removed instead):
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
thisdict.popitem()
print(thisdict)
Example
The del keyword removes the item with the specified key name:
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
del thisdict["model"]
print(thisdict)
54
Example
The del keyword can also delete the dictionary completely:
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
del thisdict
print(thisdict) #this will cause an error because "thisdict" no longer exists.
Example
The clear() keyword empties the dictionary:
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
thisdict.clear()
print(thisdict)
Copy a Dictionary
You cannot copy a dictionary simply by typing dict2 = dict1, because: dict2 will only be a
reference to dict1, and changes made in dict1 will automatically also be made in dict2.
There are ways to make a copy, one way is to use the built-in Dictionary method copy().
Example
Make a copy of a dictionary with the copy() method:
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
mydict = thisdict.copy()
print(mydict)
Another way to make a copy is to use the built-in method dict().
Example
Make a copy of a dictionary with the dict() method:
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
mydict = dict(thisdict)
print(mydict)
55
POP items from dictionary
The pop() method removes the specified item from the dictionary.The value of the removed
item is the return value of the pop() method, see example below.
Syntax
dictionary.pop(keyname, defaultvalue)
Syntax
dictionary.clear()
Example
car = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
car.clear()
print(car)
The keys() method returns a view object. The view object contains the keys of the dictionary,
as a list.
The view object will reflect any changes done to the dictionary, see example below.
Syntax
dictionary.keys()
Example
car = {
"brand": "Ford",
56
"model": "Mustang",
"year": 1964
}
x = car.keys()
print(x)
Note: When an item is added in the dictionary, the view object also gets updated:
Example
car = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
x = car.keys()
car["color"] = "white"
print(x)
Syntax
dictionary.update(iterable)
car.update({"color": "White"})
print(car)
The fromkeys() method returns a dictionary with the specified keys and values.
Syntax
dict.fromkeys(keys, value)
57
y=0
thisdict = dict.fromkeys(x, y)
print(thisdict)
Output:
['key1': 0, 'key2': 0, 'key3': 0]
The get() method returns the value of the item with the specified key.
Syntax
dictionary.get(keyname, value)
car = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
x = car.get("model")
print(x)
Output:
Mustang
An OrderedDict is a dictionary subclass that remembers the order that keys were first
inserted. The only difference between dict() and OrderedDict() is that:
OrderedDict preserves the order in which the keys are inserted. A regular dict doesn’t track
the insertion order, and iterating it gives the values in an arbitrary order. By contrast, the
order the items are inserted is remembered by OrderedDict.
print("This is a Dict:\n")
d = {}
d['a'] = 1
d['b'] = 2
d['c'] = 3
d['d'] = 4
58
for key, value in d.items():
print(key, value)
This is a Dict:
('a', 1)
('c', 3)
('b', 2)
('d', 4)
Important Points:
Key value Change: If the value of a certain key is changed, the position of the key remains
unchanged in OrderedDict.
# A Python program to demonstrate working of key
# value change in OrderedDict
from collections import OrderedDict
print("Before:\n")
od = OrderedDict()
od['a'] = 1
od['b'] = 2
od['c'] = 3
od['d'] = 4
for key, value in od.items():
print(key, value)
print("\nAfter:\n")
od['c'] = 5
for key, value in od.items():
print(key, value)
Output:
Before:
59
('a', 1)
('b', 2)
('c', 3)
('d', 4)
After:
('a', 1)
('b', 2)
('c', 5)
('d', 4)
Deletion and Re-Inserting: Deleting and re-inserting the same key will push it to the back as
OrderedDict however maintains the order of insertion.
print("Before deleting:\n")
od = OrderedDict()
od['a'] = 1
od['b'] = 2
od['c'] = 3
od['d'] = 4
print("\nAfter deleting:\n")
od.pop('c')
for key, value in od.items():
print(key, value)
print("\nAfter re-inserting:\n")
od['c'] = 3
for key, value in od.items():
print(key, value)
Output:
Before deleting:
('a', 1)
('b', 2)
('c', 3)
('d', 4)
After deleting:
('a', 1)
60
('b', 2)
('d', 4)
After re-inserting:
('a', 1)
('b', 2)
('d', 4)
('c', 3)
The order of states in the below code will change every time because the dictionary doesn’t
store keys in a particular order.
statesAndCapitals = {
'Gujarat' : 'Gandhinagar',
'Maharashtra' : 'Mumbai',
'Rajasthan' : 'Jaipur',
'Bihar' : 'Patna'
}
Rajasthan
Bihar
Maharashtra
Gujarat
61
In order to maintain the order of keys and values in a dictionary, use OrderedDict.
statesAndCapitals = OrderedDict([
('Gujarat', 'Gandhinagar'),
('Maharashtra', 'Mumbai'),
('Rajasthan', 'Jaipur'),
('Bihar', 'Patna')
])
Gujarat
Maharashtra
Rajasthan
Bihar
Above dictionary is an OrderedDict as the keys and values are stored in the order in which
they were defined in the dictionary. Hence the above method should be used when we want
to maintain the order of (key, value) stored in the dictionary.
Again, in this case, the order in which the capitals are printed in the below code will change
every time because the dictionary doesn’t store them in a particular order.
filter_none
edit
play_arrow
brightness_4
# Python3 code to iterate through all values in a dictionary
statesAndCapitals = {
'Gujarat' : 'Gandhinagar',
'Maharashtra' : 'Mumbai',
'Rajasthan' : 'Jaipur',
'Bihar' : 'Patna'
}
62
# Iterating over values
for capital in statesAndCapitals.values():
print(capital)
Output:
List Of given capitals:
Gandhinagar
Jaipur
Mumbai
Patna
statesAndCapitals = {
'Gujarat' : 'Gandhinagar',
'Maharashtra' : 'Mumbai',
'Rajasthan' : 'Jaipur',
'Bihar' : 'Patna'
}
Bihar : Patna
Gujarat : Gandhinagar
Rajasthan : Jaipur
Maharashtra : Mumbai
63
Method #1 : dict comprehension
To convert a list to dictionary, we can use list comprehension and make a key:value pair of
consecutive elements. Finally, typecase the list to dict type.
def Convert(lst):
res_dct = {lst[i]: lst[i + 1] for i in range(0, len(lst), 2)}
return res_dct
# Driver code
lst = ['a', 1, 'b', 2, 'c', 3]
print(Convert(lst))
Output:
{'a': 1, 'b': 2, 'c': 3}
First create an iterator, and intialise it to variable ‘it’. Then use zip method, to zip keys and
values together. Finally typecast it to dict type.
def Convert(a):
it = iter(lst)
res_dct = dict(zip(it, it))
return res_dct
# Driver code
lst = ['a', 1, 'b', 2, 'c', 3]
print(Convert(lst))
Output:
{'c': 3, 'b': 2, 'a': 1}
str = "key1=value1;key2=value2;key3=value3"
for k, v in d.items():
print(k, v)
Output
key1 value1
key2 value2
key3 value3
64
Python program to create a dictionary from a string
Dictionary in python is a very useful data structure and at many times we see problems
regarding converting a string to a dictionary.
So, let us discuss how we can tackle this problem.
# Initializing String
string = "{'A':13, 'B':14, 'C':15}"
# Initializing String
string = "A - 13, B - 14, C - 15"
print(Dict)
print(Dict['A'])
print(Dict['C'])
Output:
{'C': '15', 'A': '13', 'B': '14'}
13
15
65
2.16 Sets and Frozen sets in Python
A set is an unordered collection of items. Every element is unique (no duplicates) and must
be immutable (which cannot be changed).However, the set itself is mutable. We can add or
remove items from it. Sets can be used to perform mathematical set operations like union,
intersection, symmetric difference etc.
It can have any number of items and they may be of different types (integer, float, tuple,
string etc.). But a set cannot have a mutable element, like list, set or dictionary, as its element.
# set of integers
my_set = {1, 2, 3}
print(my_set)
Example
Loop through the set, and print the values:
for x in thisset:
print(x)
Add Items
To add one item to a set use the add() method.To add more than one item to a set use the
update() method.
Example
Add an item to a set, using the add() method:
66
Example
Get the number of items in a set:
Output: 3
Remove Item
To remove an item in a set, use the remove(), or the discard() method.
Example
Remove "banana" by using the remove() method:
Note: If the item to remove does not exist, remove() will raise an error.
Note: If the item to remove does not exist, discard() will NOT raise an error.
You can use the union() method that returns a new set containing all items from both sets, or
the update() method that inserts all the items from one set into another:
Example
The union() method returns a new set with all items from both sets:
set3 = set1.union(set2)
print(set3)
67
Example
The update() method inserts the items in set2 into set1:
set1.update(set2)
print(set1)
Note: Both union() and update() will exclude any duplicate items.
Example
z = x.intersection(y)
print(z)
Output: apple
Frozen sets
The frozenset() method returns an immutable frozenset object initialized with elements from
the given iterable.
Frozen set is just an immutable version of a Python set object. While elements of a set can be
modified at any time, elements of frozen set remain the same after creation.
Due to this, frozen sets can be used as key in Dictionary or as element of another set. But like
sets, it is not ordered (the elements can be set at any index).
frozenset([iterable])
frozenset() Parameters
The frozenset() method optionally takes a single parameter:
iterable (Optional) - the iterable which contains elements to initialize the frozenset with.
Iterable can be set, dictionary, tuple, etc.
68
If no parameters are passed, it returns an empty frozenset.
fSet = frozenset(vowels)
print('The frozen set is:', fSet)
print('The empty frozen set is:', frozenset())
In Python, anonymous function means that a function is without a name. As we already know
that def keyword is used to define the normal functions and the Lambda keyword is used to
create anonymous functions. It has the following syntax:
This function can have any number of arguments but only one expression, which is evaluated
and returned. One is free to use lambda functions wherever function objects are required. You
need to keep in your knowledge that lambda functions are syntactically restricted to a single
expression.
It has various uses in particular fields of programming besides other types of expressions in
functions.
Let’s look at this example and try to understand the difference between a normal def defined
function and lambda function. This is a program that returns the cube of a given value:
# Python code to illustrate cube of a number showing difference between def() and lambda().
69
def cube(y):
return y*y*y;
g = lambda x: x*x*x
print(g(7))
print(cube(5))
Output:
343
125
Without using Lambda: Here, both of them returns the cube of a given number. But, while
using def, we needed to define a function with a name cube and needed to pass a value to it.
After execution, we also needed to return the result from where the function was called using
the return keyword.
Using Lambda: Lambda definition does not include a “return” statement, it always contains
an expression which is returned. We can also put a lambda definition anywhere a function is
expected, and we don’t have to assign it to a variable at all. This is the simplicity of lambda
functions.
syntax:
filter(function, sequence)
Parameters:
function: function that tests if each element of a
sequence true or not.
sequence: sequence which needs to be filtered, it can
be sets, lists, tuples, or containers of any iterators.
Returns:
returns an iterator that is already filtered.
70
# sequence
Output:
Application:It is normally used with Lambda functions to separate list, tuple, or sets.
[1, 3, 5, 13]
[0, 2, 8]
The reduce(fun,seq) function is used to apply a particular function passed in its argument to
all of the list elements mentioned in the sequence passed along.This function is defined in
“functools” module.
Working :
At first step, first two elements of sequence are picked and the result is obtained.
Next step is to apply the same function to the previously attained result and the
number just succeeding the second element and the result is again stored.
This process continues till no more elements are left in the container.
The final returned result is returned and printed on console.
71
# python code to demonstrate working of reduce() by importing functools for reduce()
import functools
# initializing list
lis = [ 1 , 3, 5, 6, 2, ]
Output:
reduce() vs accumulate()
Both reduce() and accumulate() can be used to calculate the summation of a sequence
elements. But there are differences in the implementation aspects in both of these.
# initializing list
lis = [ 1, 3, 4, 10, 4 ]
72
print (functools.reduce(lambda x,y:x+y,lis))
Output:
The summation of list using accumulate is :[1, 4, 8, 18, 22]
The summation of list using reduce is :22
map() function returns a list of the results after applying the given function to each item of a
given iterable (list, tuple etc.)
Syntax :
map(fun, iter)
Parameters :
fun : It is a function to which map passes each element of given iterable.
iter : It is a iterable which is to be mapped.
NOTE : You can pass one or more iterable to the map() function.
Returns :
NOTE : The returned value from map() (map object) then can be passed to functions like
list() (to create a list), set() (to create a set) .
CODE 1
# Return double of n
def addition(n):
return n + n
{2, 4, 6, 8}
73
implement following methods. In fact, any object that wants to be an iterator must implement
following methods.
1. __iter__ method that is called on initialization of an iterator. This should return an object
that has a next or __next__ (in Python 3) method.
2. next ( __next__ in Python 3) The iterator next method should return the next value for the
iterable. When an iterator is used with a ‘for in’ loop, the for loop implicitly calls next() on
the iterator object. This method should raise a StopIteration to signal the end of the iteration.
Below is a simple Python program that creates iterator type that iterates from 10 to given
limit. For example, if limit is 15, then it prints 10 11 12 13 14 15. And if limit is 5, then it
prints nothing.
# A simple Python program to demonstrate working of iterators using an example type that
iterates from 10 to given value
# Cosntructor
def __init__(self, limit):
self.limit = limit
# Prints nothing
for i in Test(5):
print(i)
74
Output :
10
11
12
13
14
15
# A generator function that yields 1 for first time, 2 second time and 3 third time
def simpleGeneratorFun():
yield 1
yield 2
yield 3
Generator-Object: Generator functions return a generator object. Generator objects are used
either by calling the next method on the generator object or using the generator object in a
“for in” loop (as shown in the above program).
# A generator function
def simpleGeneratorFun():
yield 1
yield 2
yield 3
# x is a generator object
x = simpleGeneratorFun()
75
# Iterating over the generator object using next
print(x.next()); # In Python 3, __next__()
print(x.next());
print(x.next());
Output :
1
2
3
So a generator function returns an generator object that is iterable, i.e., can be used as an
Iterators .As another example, below is a generator for Fibonacci Numbers.
def fib(limit):
Output :
0
1
1
2
3
76
Using for in loop
0
1
1
2
3
List comprehension is an elegant way to define and create list in python. We can create lists
just like mathematical statements and in one line only. The syntax of list comprehension is
easier to grasp.
A list comprehension generally consist of these parts :
Output expression,
input sequence,
a variable representing member of input sequence and
an optional predicate part.
For example :
77
# below list contains power of 2 from 1 to 8
power_of_2 = [2 ** x for x in range(1, 9)]
print power_of_2
print("\nExtracted digits")
numbers = [x for x in string if x.isdigit()]
print numbers
print("\nMultiplication Table")
for i in table:
print i
Output:
Extracted digits
['1', '1', '1', '2', '2']
Multiplication Table
[5, 1, 5]
[5, 2, 10]
[5, 3, 15]
[5, 4, 20]
[5, 5, 25]
[5, 6, 30]
[5, 7, 35]
[5, 8, 40]
[5, 9, 45]
[5, 10, 50]
78
Module-3
OBJECTS IN PYTHON
Class attributes
Class attributes belong to the class itself they will be shared by all the instances. Such
attributes are defined in the class body parts usually at the top, for legibility.
class sampleclass:
count = 0 # class attribute
def increase(self):
sampleclass.count += 1
print sampleclass.count
Output:
1
2
2
Instance Attributes
Unlike class attributes, instance attributes are not shared by objects. Every object has its own
copy of the instance attribute (In case of class attributes all object refer to single copy).
79
class emp:
def __init__(self):
self.name = 'xyz'
self.salary = 4000
def show(self):
print self.name
print self.salary
e1 = emp()
print "Dictionary form :", vars(e1)
print dir(e1)
Output :
3.2 Inheritance
Inheritance is the capability of one class to derive or inherit the properties from some another
class. The benefits of inheritance are:
class Person(object):
# Constructor
def __init__(self, name):
self.name = name
# To get name
def getName(self):
return self.name
80
# To check if this person is employee
def isEmployee(self):
return False
# Driver code
Output:
Geek1 False
Geek2 True
1. Single inheritance: When a child class inherits from only one parent class, it is called as
single inheritance. We saw an example above.
2. Multiple inheritance: When a child class inherits from multiple parent classes, it is called
as multiple inheritance.
Unlike Java and like C++, Python supports multiple inheritance. We specify all parent classes
as comma separated list in bracket.When a child class inherits from multiple parent classes, it
is called as multiple inheritance.
Unlike Java and like C++, Python supports multiple inheritance. We specify all parent classes
as comma separated list in bracket.
class Base1(object):
def __init__(self):
self.str1 = "Geek1"
print "Base1"
class Base2(object):
def __init__(self):
self.str2 = "Geek2"
print "Base2"
81
class Derived(Base1, Base2):
def __init__(self):
def printStrs(self):
print(self.str1, self.str2)
ob = Derived()
ob.printStrs()
Output:
Base1
Base2
Derived
('Geek1', 'Geek2')
Output :
Base1
Base2
Derived
Geek1 True E101
It denotes the way a programming language resolves a method or attribute. Python supports
classes inheriting from other classes. The class being inherited is called the Parent or
Superclass, while the class that inherits is called the Child or Subclass. In python, method
resolution order defines the order in which the base classes are searched when executing a
method. First, the method or attribute is searched within a class and then it follows the order
we specified while inheriting. This order is also called Linearization of a class and set of rules
are called MRO(Method Resolution Order). While inheriting from another class, the
interpreter needs a way to resolve the methods that are being called via an instance. Thus we
need the method resolution order. For Example
class A:
def rk(self):
print(" In class A")
class B(A):
def rk(self):
82
print(" In class B")
r = B()
r.rk()
Output:
In class B
In the above example the methods that are invoked is from class B but not from class A, and
this is due to Method Resolution Order(MRO).
The order that follows in the above code is- class B - > class A
In multiple inheritances, the methods are executed based on the order specified while
inheriting the classes. For the languages that support single inheritance, method resolution
order is not interesting, but the languages that support multiple inheritance method resolution
order plays a very crucial role. Let’s look over another example to deeply understand the
method resolution order:
class A:
def rk(self):
print(" In class A")
class B(A):
def rk(self):
print(" In class B")
class C(A):
def rk(self):
print("In class C")
# classes ordering
class D(B, C):
pass
r = D()
r.rk()
Output:
In class B
In the above example we use multiple inheritances and it is also called Diamond
inheritance or Deadly Diamond of Death and it looks as follows:
83
Python follows a depth-first lookup order and hence ends up calling the method from class A.
By following the method resolution order, the lookup order as follows.
Class D -> Class B -> Class C -> Class A
Python follows depth-first order to resolve the methods and attributes. So in the above
example, it executes the method in class B.
Magic methods in Python are the special methods which add "magic" to your class. Magic
methods are not meant to be invoked directly by you, but the invocation happens internally
from the class on a certain action. For example, when you add two numbers using the +
operator, internally, the __add__() method will be called.
Built-in classes in Python define many magic methods. Use the dir() function to see the
number of magic methods inherited by a class. For example, the following lists all the
attributes and methods defined in the int class.
>>> dir(int)
As you can see above, the int class includes various magic methods surrounded by double
underscores. For example, the __add__ method is a magic method which gets called when we
add two numbers using the + operator. Consider the following example.
>>> num=10
>>> num + 5
15
>>> num.__add__(5)
15
As you can see, when you do num+10, the + operator calls the __add__(10) method. You can
also call num.__add__(5) directly which will give the same result. However, as mentioned
before, magic methods are not meant to be called directly, but internally, through some other
methods or actions.
Magic methods are most frequently used to define overloaded behaviours of predefined
operators in Python. For instance, arithmetic operators by default operate upon numeric
operands. This means that numeric objects must be used along with operators like +, -, *, /,
84
etc. The + operator is also defined as a concatenation operator in string, list and tuple classes.
We can say that the + operator is overloaded.
In order to make the overloaded behaviour available in your own custom class, the
corresponding magic method should be overridden. For example, in order to use the +
operator with objects of a user-defined class, it should include the __add__() method.
Let's see how to implement and use some of the important magic methods.
1. __new__() method
Languages such as Java and C# use the new operator to create a new instance of a class. In
Python the __new__() magic method is implicitly called before the __init__() method. The
__new__() method returns a new object, which is then initialized by __init__().
Example: __new__()
class employee:
def __new__(cls):
print ("__new__ magic method is called")
inst = object.__new__(cls)
return inst
def __init__(self):
print ("__init__ magic method is called")
self.name='Satya'
The above example will produce the following output when you create an instance of the
Employee class.
>>> e1=employee()
__new__ magic method is called
__init__ magic method is called
Thus, the __new__() method is called before the __init__() method.
2. __str__() method
>>> num=12
>>> str(num)
'12'
>>> #This is equivalent to
>>> int.__str__(num)
'12'
Let us now override the __str__() method in the employee class to return a string
representation of its object.
Example:
class employee:
def __init__(self):
85
self.name='Swati'
self.salary=10000
def __str__(self):
return 'name='+self.name+' salary=$'+str(self.salary)
See how the str() function internally calls the __str__() method defined in the employee class.
This is why it is called a magic method!
>>> e1=employee()
>>> print(e1)
name=Swati salary=$10000
3. __add__() method
In following example, a class named distance is defined with two instance attributes - ft and
inch. The addition of these two distance objects is desired to be performed using the
overloading + operator.
To achieve this, the magic method __add__() is overridden, which performs the addition of
the ft and inch attributes of the two objects. The __str__() method returns the object's string
representation.
Example: __add__()
class distance:
def __init__(self, x=None,y=None):
self.ft=x
self.inch=y
def __add__(self,x):
temp=distance()
temp.ft=self.ft+x.ft
temp.inch=self.inch+x.inch
if temp.inch>=12:
temp.ft+=1
temp.inch-=12
return temp
def __str__(self):
return 'ft:'+str(self.ft)+' in: '+str(self.inch)
Run the above Python script to verify the overloaded operation of the + operator.
>>> d1=distance(3,10)
>>> d2=distance(4,4)
>>> print("d1= {} d2={}".format(d1, d2))
d1= ft:3 in: 10 d2=ft:4 in: 4
>>>d3=d1+d2
>>>print(d3)
ft:8 in: 2
4. __ge__() method
The following method is added in the distance class to overload the >= operator.
Example: __ge__()
class distance:
def __init__(self, x=None,y=None):
86
self.ft=x
self.inch=y
def __ge__(self, x):
val1=self.ft*12+self.inch
val2=x.ft*12+x.inch
if val1>=val2:
return True
else:
return False
This method gets invoked when the >= operator is used and returns True or False.
Accordingly, the appropriate message can be displayed
>>>d1=distance(2,1)
>>>d2=distance(4,10)
>>>d1>=d2
False
print(1 + 2)
Output:
3
GeeksFor
12
GeeksGeeksGeeksGeeks
87
because compiler don’t know how to add two objects. So we define a method for an operator
and that process is called operator overloading. We can overload all existing operators but we
can’t create a new operator. To perform operator overloading, Python provides some special
function or magic function that is automatically invoked when it is associated with that
particular operator. For example, when we use + operator, the magic method __add__ is
automatically invoked in which the operation for + operator is defined.
Code 1:
class A:
def __init__(self, a):
self.a = a
print(ob1 + ob2)
print(ob3 + ob4)
Output :
3
GeeksFor
class A:
def __init__(self, a):
self.a = a
def __gt__(self, other):
if(self.a>other.a):
return True
88
else:
return False
ob1 = A(2)
ob2 = A(3)
if(ob1>ob2):
print("ob1 is greater than ob2")
else:
print("ob2 is greater than ob1")
Output :
ob2 is greater than ob1
class A:
def __init__(self, a):
self.a = a
def __lt__(self, other):
if(self.a<other.a):
return "ob1 is lessthan ob2"
else:
return "ob2 is less than ob1"
def __eq__(self, other):
if(self.a == other.a):
return "Both are equal"
else:
return "Not equal"
ob1 = A(2)
ob2 = A(3)
print(ob1 < ob2)
ob3 = A(4)
ob4 = A(4)
print(ob1 == ob2)
Output :
ob1 is lessthan ob2
Not equal
In Python everything have some type associated with it. For example if we have a variable
having integer value then it’s type is int. You can get type of anything using type() function.
num = 23
print("Type of num is:", type(num))
89
lst = [1, 2, 4]
print("Type of lst is:", type(lst))
name = "Atul"
print("Type of name is:", type(name))
Output:
class Student:
pass
stu_obj = Student()
Output:
A Class is also an object, and just like any other object it’s a instance of something called
Metaclass. A special class type creates these Class object. The type class is default metaclass
which is responsible for making classes. For example in above example if we try to find out
the type of Student class, it comes out to be a type.
class Student:
pass
Output:
90
# Defining class methods
test.foo = lambda self: print('Hello')
# creating object
myobj = test()
print(myobj.x)
myobj.foo()
Output:
45
Hello
This whole meta thing can be summarized as – Metaclass create Classes and Classes creates
objects. Metaclass is responsible for generation of classes, so we can write our own custom
metaclasses to modify the way classes are generated by performing extra actions or injecting
code.
We create a class (Human) with one inner class (Head). An instance is created that calls a
method in the inner class:
class Human:
def __init__(self):
self.name = 'Guido'
self.head = self.Head()
class Head:
def talk(self):
return 'talking...'
if __name__ == '__main__':
guido = Human()
print guido.name
print guido.head.talk()
Output:
Guido
talking...
91
In the program above we have the inner class Head() which has its own method. An inner
class can have both methods and variables. In this example the constructor of the class
Human (init) creates a new head object.
Abstract Classes
An abstract class can be considered as a blueprint for other classes, allows you to create a set
of methods that must be created within any child classes built from your abstract class. A
class which contains one or abstract methods is called an abstract class. An abstract method is
a method that has declaration but not has any implementation. Abstract classes are not able to
instantiated and it needs subclasses to provide implementations for those abstract methods
which are defined in abstract classes. While we are designing large functional units we use an
abstract class. When we want to provide a common implemented functionality for all
implementations of a component, we use an abstract class. Abstract classes allow partially to
implement classes when it completely implements all methods in a class, then it is called
interface.
Abstract classes allow you to provide default functionality for the subclasses. Compared to
interfaces abstract classes can have an implementation. By defining an abstract base class,
you can define a common Application Program Interface(API) for a set of subclasses. This
capability is especially useful in situations where a third-party is going to provide
implementations, such as with plugins in an application, but can also help you when working
on a large team or with a large code-base where keeping all classes in your head at the same
time is difficult or not possible.
In python by default, it is not able to provide abstract classes, but python comes up with a
module which provides the base for defining Abstract Base classes (ABC) and that module
name is ABC. ABC works by marking methods of the base class as abstract and then
registering concrete classes as implementations of the abstract base. A method becomes an
abstract by decorated it with a keyword @abstractmethod. For Example –
Code 1:
class Polygon(ABC):
# abstract method
def noofsides(self):
pass
class Triangle(Polygon):
92
def noofsides(self):
print("I have 3 sides")
class Pentagon(Polygon):
class Hexagon(Polygon):
class Quadrilateral(Polygon):
# Driver code
R = Triangle()
R.noofsides()
K = Quadrilateral()
K.noofsides()
R = Pentagon()
R.noofsides()
K = Hexagon()
K.noofsides()
Output:
I have 3 sides
I have 4 sides
I have 5 sides
I have 6 sides
Code 2:
def move(self):
pass
93
class Human(Animal):
def move(self):
print("I can walk and run")
class Snake(Animal):
def move(self):
print("I can crawl")
class Dog(Animal):
def move(self):
print("I can bark")
class Lion(Animal):
def move(self):
print("I can roar")
# Driver code
R = Human()
R.move()
K = Snake()
K.move()
R = Dog()
R.move()
K = Lion()
K.move()
Output:
Exception is the base class for all the exceptions in python. You can check the exception
hierarchy here. Let us try to access the array element whose index is out of bound and handle
the corresponding exception.
94
a = [1, 2, 3]
try:
print "Second element = %d" %(a[1])
except IndexError:
print "An error occurred"
Output:
Second element = 2
An error occurred
A try statement can have more than one except clause, to specify handlers for different
exceptions. Please note that at most one handler will be executed.
Output:
Value of b =
Error Occurred and Handled
The output above is so because as soon as python tries to access the value of b, NameError
occurs.
Else Clause:
In python, you can also use else clause on try-except block which must be present after all the
except clauses. The code enters the else block only if the try clause does not raise an
exception.
# Program to depict else clause with try-except Function which returns a/b
95
def AbyB(a , b):
try:
c = ((a+b) / (a-b))
except ZeroDivisionError:
print "a/b result in 0"
else:
print c
-5.0
a/b result in 0
Raising Exception:
The raise statement allows the programmer to force a specific exception to occur. The sole
argument in raise indicates the exception to be raised. This must be either an exception
instance or an exception class (a class that derives from Exception).
try:
raise NameError("Hi there") # Raise Error
except NameError:
print "An exception"
raise # To determine whether the exception was raised or not
The output of the above code will simply line printed as “An exception” but a Runtime error
will also occur in the last due to raise statement in the last line. So, the output on your
command line will look like
96
Modules in Python are simply Python files with a .py extension. The name of the module will
be the name of the file. A Python module can have a set of functions, classes or variables
defined and implemented.
Let's create a module. We save the following code in the file fibonacci.py:
def fib(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fib(n-1) + fib(n-2)
def ifib(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b
return a
We can import this module in the interactive python shell and call the functions by prefixing
them with "fibonacci.":
Usually, modules contain functions, but there can be statements in them as well. These
statements can be used to initialize the module. They are only executed when the module is
imported.
A module has a private symbol table, which is used as the global symbol table by all
functions defined in the module. This is a way to prevent that a global variable of a module
accidentally clashes with a user's global variable with the same name. Global variables of a
module can be accessed with the same notation as functions, i.e. modname.name
A module can import other modules. It is customary to place all import statements at the
beginning of a module or a script.
Importing Names from a Module Directly
Names from a module can directly be imported into the importing module's symbol table:
Output:
1 1 2 3 5 8 13 21 34 55 89 144 233 377
This does not introduce the module name from which the imports are taken in the local
symbol table. It's possible but not recommended to import all names defined in a module,
except those beginning with an underscore "_":
97
>>> from fibonacci import *
>>> fib(500)
Output:
Packeges in python
Suppose you have developed a very large application that includes many modules. As the
number of modules grows, it becomes difficult to keep track of them all if they are dumped
into one location. This is particularly so if they have similar names or functionality. You
might wish for a means of grouping and organizing them.
Packages allow for a hierarchical structuring of the module namespace using dot notation. In
the same way that modules help avoid collisions between global variable names, packages
help avoid collisions between module names.
Creating a package is quite straightforward, since it makes use of the operating system’s
inherent hierarchical file structure. Consider the following arrangement:
Here, there is a directory named pkg that contains two modules, mod1.py and mod2.py. The
contents of the modules are:
mod1.py
def foo():
print('[mod1] foo()')
class Foo:
pass
mod2.py
def bar():
print('[mod2] bar()')
class Bar:
pass
Given this structure, if the pkg directory resides in a location where it can be found (in one of
the directories contained in sys.path), you can refer to the two modules with dot notation
(pkg.mod1, pkg.mod2) and import them with the syntax you are already familiar with:
98
from <module_name> import <name(s)>
>>> from pkg.mod1 import foo
>>> foo()
99
Module-4
Using NumPy, a developer can perform the following operations −Mathematical and logical
operations on arrays. Fourier transforms and routines for shape manipulation.Operations
related to linear algebra. NumPy has in-built functions for linear algebra and random number
generation.
NumPy is often used along with packages like SciPy (Scientific Python) and Mat−plotlib
(plotting library). This combination is widely used as a replacement for MatLab, a popular
platform for technical computing. However, Python alternative to MatLab is now seen as a
more modern and complete programming language. It is open source, which is an added
advantage of NumPy.
The most important object defined in NumPy is an N-dimensional array type called ndarray.
It describes the collection of items of the same type. Items in the collection can be accessed
using a zero-based index.Every item in an ndarray takes the same size of block in the
memory. Each element in ndarray is an object of data-type object (called dtype). Any item
extracted from ndarray object (by slicing) is represented by a Python object of one of array
scalar types. The following diagram shows a relationship between ndarray, data type object
(dtype) and array scalar type –
100
An instance of ndarray class can be constructed by different array creation routines
described later in the tutorial. The basic ndarray is created using an array function in NumPy
as follows −
numpy.array
It creates an ndarray from any object exposing array interface, or from any method that
returns an array.
numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
The above constructor takes the following parameters –
101
Example 1
import numpy as np
a = np.array([1,2,3])
print a
The output is as follows −
[1, 2, 3]
Example 2
import numpy as np
a = np.array([[1, 2], [3, 4]])
print a
The output is as follows −
[[1, 2]
[3, 4]]
Example 3
# minimum dimensions
import numpy as np
a = np.array([1, 2, 3,4,5], ndmin = 2)
print a
The output is as follows −
[[1, 2, 3, 4, 5]]
Example 4
# dtype parameter
import numpy as np
a = np.array([1, 2, 3], dtype = complex)
print a
The output is as follows −
102
The memory block holds the elements in a row-major order (C style) or a column-major
order (FORTRAN or MatLab style).
It is a table of elements (usually numbers), all of the same type, indexed by a tuple of positive
integers. In NumPy dimensions are called axes. The number of axes is rank. NumPy’s array
class is called ndarray. It is also known by the alias array.
Example :
[[ 1, 2, 3],
[ 4, 2, 5]]
Here,
rank = 2 (as it is 2-dimensional or it has 2 axes)
first dimension(axis) length = 2, second dimension has length = 3
overall shape can be expressed as: (2, 3)
Array is of type:
No. of dimensions: 2
Shape of array: (2, 3)
Size of array: 6
Array stores elements of type: int64
103
For example, you can create an array from a regular Python list or tuple using the array
function. The type of the resulting array is deduced from the type of the elements in the
sequences. Often, the elements of an array are originally unknown, but its size is known.
Hence, NumPy offers several functions to create arrays with initial placeholder content.
These minimize the necessity of growing arrays, an expensive operation.
To create sequences of numbers, NumPy provides a function analogous to range that returns
arrays instead of lists.
arange: returns evenly spaced values within a given interval. step size is specified.
linspace: returns evenly spaced values within a given interval. num no. of elements are
returned.
Reshaping array: We can use reshape method to reshape an array. Consider an array with
shape (a1, a2, a3, …, aN). We can reshape and convert it into another array with shape (b1,
b2, b3, …, bM). The only required condition is:
a1 x a2 x a3 … x aN = b1 x b2 x b3 … x bM . (i.e original size of array remains unchanged.)
Flatten array: We can use flatten method to get a copy of array collapsed into one
dimension. It accepts order argument. Default value is ‘C’ (for row-major order). Use ‘F’ for
column major order.
104
print ("\nA sequential array with steps of 5:\n", f)
newarr = arr.reshape(2, 2, 3)
# Flatten array
arr = np.array([[1, 2, 3], [4, 5, 6]])
flarr = arr.flatten()
Output :
A random array:
[[ 0.46829566 0.67079389]
[ 0.09079849 0.95410464]]
105
A sequential array with 10 values between 0 and 5:
[ 0. 0.55555556 1.11111111 1.66666667 2.22222222 2.77777778
3.33333333 3.88888889 4.44444444 5. ]
Original array:
[[1 2 3 4]
[5 2 4 2]
[1 2 0 1]]
Reshaped array:
[[[1 2 3]
[4 5 2]]
[[4 2 1]
[2 0 1]]]
Original array:
[[1 2 3]
[4 5 6]]
Fattened array:
[1 2 3 4 5 6]
Array Indexing: Knowing the basics of array indexing is important for analysing and
manipulating the array object. NumPy offers many ways to do array indexing.
Slicing: Just like lists in python, NumPy arrays can be sliced. As arrays can be
multidimensional, you need to specify a slice for each dimension of the array.
Integer array indexing: In this method, lists are passed for indexing for each dimension.
One to one mapping of corresponding elements is done to construct a new arbitrary array.
Boolean array indexing: This method is used when we want to pick elements from array
which satisfy some condition.
import numpy as np
# An exemplar array
# Slicing array
temp = arr[:2, ::2]
print ("Array with first 2 rows and alternate"
106
"columns(0 and 2):\n", temp)
Output :
Every ndarray has an associated data type (dtype) object. This data type object (dtype)
informs us about the layout of the array. This means it gives us information about :
Constructing a data type (dtype) object : Data type object is an instance of numpy.dtype
class and it can be created using numpy.dtype.
Parameters:
obj: Object to be converted to a data type object.
align : bool, optional
Add padding to the fields to match what a C compiler would output for a similar C-struct.
107
copy : bool, optional
Make a new copy of the data-type object. If False, the result may just be a reference to a
built-in data-type object.
int16
# Python Program to create a data type object containing a 32 bit big-endian integer
import numpy as np
print("Size is:",dt.itemsize)
a = np.array([1])
Output:
type is:
dtype is: int32
108
4.3.2 Character Codes
Each built-in data-type has a character code (the updated Numeric typecodes), that uniquely
identifies it.
Example
>>> dt = np.dtype('b') # byte, native byte order
>>> dt = np.dtype('>H') # big-endian unsigned short
>>> dt = np.dtype('<f') # little-endian single-precision float
>>> dt = np.dtype('d') # double-precision floating-point number
The first character specifies the kind of data and the remaining characters specify the number
of bytes per item, except for Unicode, where it is interpreted as the number of characters. The
item size must correspond to an existing type, or an error will be raised. The supported kinds
are
'?' boolean
'b' (signed) byte
'B' unsigned byte
'i' (signed) integer
'u' unsigned integer
'f' floating-point
'c' complex-floating point
'm' timedelta
'M' datetime
'O' (Python) objects
'S', 'a' zero-terminated bytes (not recommended)
'U' Unicode string
'V' raw data (void)
Indexing can be done in numpy by using an array as an index. In case of slice, a view or
shallow copy of the array is returned but in index array a copy of the original array is
returned. Numpy arrays can be indexed with other arrays or any other sequence with the
exception of tuples. The last element is indexed by -1 second last by -2 and so on.
Example-1
import numpy as np
Output :
109
A sequential array with a negative step:
[10 8 6 4 2]
Example-2
import numpy as np
Output :
Elements are:
[2 4 7]
Basic Slicing and indexing: Consider the syntax x[obj] where x is the array and obj is the
index. Slice object is the index in case of basic slicing. Basic slicing occurs when obj is:
# a[start:stop:step]
print("\n a[-8:17:1] = ",a[-8:17:1])
Array is:
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]
110
Ellipsis can also be used along with basic slicing. Ellipsis (…) is the number of : objects
needed to make a selection tuple of the same length as the dimensions of the array.
# A 3 dimensional array.
b = np.array([[[1, 2, 3],[4, 5, 6]],
[[7, 8, 9],[10, 11, 12]]])
Output :
[[ 2 5]
[ 8 11]]
Advanced indexing returns a copy of data rather than a view of it. Advanced indexing is of
two types integer and Boolean.
Purely integer indexing: When integers are used for indexing. Each element of first
dimension is paired with the element of the second dimension. So the index of the elements
in this case are (0,0),(1,0),(2,1) and the corresponding elements are selected.
Output :
[1 3 6]
Boolean Indexing: This indexing has some boolean expression as the index. Those elements
are returned which satisfy that Boolean expression. It is used for filtering the desired element
values.
111
Output :
[80 100]
import numpy as np
Output :
[1600 6400])
# You may wish to select those elements whose sum of row is a multiple of 10.
import numpy as np
array = np.arange(20).reshape(4,5)
array
python
Output:
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])
First, 20 integers will be created and then it will convert the array into a two-dimensional
array with 4 rows and 5 columns. Let's check the dimensionality of this array.
array.shape
python
Output:
112
(4, 5)
Since we get two values, this is a two-dimensional array. To access an element in a two-
dimensional array, you need to specify an index for both the row and the column.
array[3][4]
python
Output:
19
numpy.stack() function is used to join a sequence of same dimension arrays along a new
axis.The axis parameter specifies the index of the new axis in the dimensions of the result.
For example, if axis=0 it will be the first dimension and if axis=-1 it will be the last
dimension.
# input array
in_arr1 = geek.array([ 1, 2, 3] )
print ("1st Input array : \n", in_arr1)
in_arr2 = geek.array([ 4, 5, 6] )
print ("2nd Input array : \n", in_arr2)
Output:
1st Input array :
[1 2 3]
113
[[1 2 3]
[4 5 6]]
numpy.split
numpy.split(ary, indices_or_sections, axis=0)[source]
Parameters:
ary : ndarray
If indices_or_sections is a 1-D array of sorted integers, the entries indicate where along axis
the array is split. For example, [2, 3] would, for axis=0, result in
ary[:2]
ary[2:3]
ary[3:]
If an index exceeds the dimension of the array along axis, an empty sub-array is returned
correspondingly.
Returns:
sub-arrays : list of ndarrays
A list of sub-arrays.
Raises:
ValueError
If indices_or_sections is given as an integer, but a split does not result in equal division.
Example:
>>> x = np.arange(9.0)
>>> np.split(x, 3)
114
[array([0., 1., 2.]), array([3., 4., 5.]), array([6., 7., 8.])]
>>> x = np.arange(8.0)
>>> np.split(x, [3, 5, 6, 10])
ndarray.shape
This array attribute returns a tuple consisting of array dimensions. It can also be used to
resize the array.
Example 1
import numpy as np
a = np.array([[1,2,3],[4,5,6]])
print a.shape
The output is as follows −
(2, 3)
Example 2
a = np.array([[1,2,3],[4,5,6]])
a.shape = (3,2)
print a
The output is as follows −
[[1, 2]
[3, 4]
[5, 6]]
Example 3
import numpy as np
a = np.array([[1,2,3],[4,5,6]])
b = a.reshape(3,2)
115
print b
The output is as follows −
[[1, 2]
[3, 4]
[5, 6]]
ndarray.ndim
This array attribute returns the number of array dimensions.
Example 1
[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
Example 2
# now reshape it
b = a.reshape(2,4,3)
print b
# b is having three dimensions
The output is as follows −
[[[ 0, 1, 2]
[ 3, 4, 5]
[ 6, 7, 8]
[ 9, 10, 11]]
[[12, 13, 14]
[15, 16, 17]
[18, 19, 20]
[21, 22, 23]]]
numpy.itemsize
This array attribute returns the length of each element of array in bytes.
Example 1
116
print x.itemsize
The output is as follows −
Example 2
4
numpy.flags
The ndarray object has the following attributes. Its current values are returned by this
function.
This array is a copy of some other array. When this array is deallocated, the base array will be
updated with the contents of this array
Example
The following example shows the current values of flags.
117
import numpy as np
x = np.array([1,2,3,4,5])
print x.flags
C_CONTIGUOUS : True
F_CONTIGUOUS : True
OWNDATA : True
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False
We can use numpy ndarray tolist() function to convert the array to a list. If the array is multi-
dimensional, a nested list is returned. For one-dimensional array, a list with the array
elements is returned. The tolist() function doesn’t accept any argument. It’s a simple way to
convert an array to a list representation.
Output:
import numpy as np
# 2d array to list
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(f'NumPy Array:\n{arr}')
list1 = arr.tolist()
print(f'List: {list1}')
Output:
NumPy Array:
[[1 2 3]
118
[4 5 6]]
While executing the functions, some of them return a copy of the input array, while some
return the view. When the contents are physically stored in another location, it is called Copy.
If on the other hand, a different view of the same memory content is provided, we call it as
View.
No Copy
Simple assignments do not make the copy of array object. Instead, it uses the same id() of the
original array to access it. The id() returns a universal identifier of Python object, similar to
the pointer in C.
Furthermore, any changes in either gets reflected in the other. For example, the changing
shape of one will change the shape of the other too.
Example
import numpy as np
a = np.arange(6)
119
139747815479536
a is assigned to b:
[0 1 2 3 4 5]
b has same id():
139747815479536
Change shape of b:
[[0 1]
[2 3]
[4 5]]
Example
import numpy as np
# To begin with, a is 3X2 array
a = np.arange(6).reshape(3,2)
120
Array a:
[[0 1]
[2 3]
[4 5]]
Create view of a:
[[0 1]
[2 3]
[4 5]]
Shape of b:
[[0 1 2]
[3 4 5]]
Shape of a:
[[0 1]
[2 3]
[4 5]]
Example
import numpy as np
a = np.array([[10,10], [2,3], [4,5]])
Create a slice:
[[10 10]
[ 2 3]
[ 4 5]]
121
Deep Copy
The ndarray.copy() function creates a deep copy. It is a complete copy of the array and its
data, and doesn’t share with the original array.
Example
import numpy as np
a = np.array([[10,10], [2,3], [4,5]])
Array a is:
[[10 10]
[ 2 3]
[ 4 5]]
Can we write b is a
False
122
[ 4 5]]
a remains unchanged:
[[10 10]
[ 2 3]
[ 4 5]]
import numpy as np
A = np.array([4, 7, 3, 4, 2, 8])
print(A == 4)
print(A < 5)
[ True False True True True False]
B = np.array([[42,56,89,65],
[99,88,42,12],
[55,42,17,18]])
print(B>=42)
[[ True True True True]
[ True True True False]
[ True True False False]]
import numpy as np
A = np.array([
[12, 13, 14, 12, 16, 14, 11, 10, 9],
[11, 14, 12, 15, 15, 16, 10, 12, 11],
[10, 12, 12, 15, 14, 16, 10, 12, 12],
[ 9, 11, 16, 15, 14, 16, 15, 12, 10],
[12, 11, 16, 14, 10, 12, 16, 12, 13],
[10, 15, 16, 14, 14, 14, 16, 15, 12],
[13, 17, 14, 10, 14, 11, 14, 15, 10],
[10, 16, 12, 14, 11, 12, 14, 18, 11],
123
[10, 19, 12, 14, 11, 12, 14, 18, 10],
[14, 22, 17, 19, 16, 17, 18, 17, 13],
[10, 16, 12, 14, 11, 12, 14, 18, 11],
[10, 16, 12, 14, 11, 12, 14, 18, 11],
[10, 19, 12, 14, 11, 12, 14, 18, 10],
[14, 22, 12, 14, 11, 12, 14, 17, 13],
[10, 16, 12, 14, 11, 12, 14, 18, 11]])
B = A < 15
B.astype(np.int)
Output::
array([[1, 1, 1, 1, 0, 1, 1, 1, 1],
[1, 1, 1, 0, 0, 0, 1, 1, 1],
[1, 1, 1, 0, 1, 0, 1, 1, 1],
[1, 1, 0, 0, 1, 0, 0, 1, 1],
[1, 1, 0, 1, 1, 1, 0, 1, 1],
[1, 0, 0, 1, 1, 1, 0, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0, 1]])
The term broadcasting refers to how numpy treats arrays with different Dimension during
arithmetic operations which lead to certain constraints, the smaller array is broadcast across
the larger array so that they have compatible shapes.
Broadcasting provides a means of vectorizing array operations so that looping occurs in C
instead of Python as we know that Numpy implemented in C. It does this without making
needless copies of data and which leads to efficient algorithm implementations. There are
cases where broadcasting is a bad idea because it leads to inefficient use of memory that slow
down the computation.
Example –
import numpy as np
A = np.array([5, 7, 3, 1])
B = np.array([90, 50, 0, 30])
124
Example to get deeper understanding –
Let’s assume that we have a large data set, each datum is a list of parameters. In Numpy we
have a 2-D array, where each row is a datum and the number of rows is the size of the data
set. Suppose we want to apply some sort of scaling to all these data every parameter gets its
own scaling factor or say Every parameter is multiplied by some factor.
Just to have some clear understanding, let’s count calories in foods using a macro-nutrient
breakdown. Roughly put, the caloric parts of food are made of fats (9 calories per gram),
protein (4 cpg) and carbs (4 cpg). So if we list some foods (our data), and for each food list its
macro-nutrient breakdown (parameters), we can then multiply each nutrient by its caloric
value (apply scaling) to compute the caloric breakdown of every food item.
With this transformation, we can now compute all kinds of useful information. For example,
what is the total number of calories present in some food or, given a breakdown of my dinner
know how much calories did I get from protein and so on.
macros = array([
[0.8, 2.9, 3.9],
[52.4, 23.6, 36.5],
[55.2, 31.7, 23.9],
[14.4, 11, 4.9]
])
# Create a new array filled with zeros, of the same shape as macros.
result = zeros_like(macros)
result
output:
Algorithm:
Inputs: Array A with m dimensions and array B with n dimensions
p = max(m, n)
if m < p:
125
left-pad A's shape with 1s until it also has p dimensions
else if n < p:
left-pad B's shape with 1s until it also has p dimensions
result_dims = new list with p elements
Broadcasting Rules:
If the arrays don't have the same rank then prepend the shape of the lower rank array
with 1s until both shapes have the same length.
The two arrays are compatible in a dimension if they have the same size in the
dimension or if one of the arrays has size 1 in that dimension.
The arrays can be broadcast together iff they are compatible with all dimensions.
After broadcasting, each array behaves as if it had shape equal to the element-wise
maximum of shapes of the two input arrays.
In any dimension where one array had size 1 and the other array had size greater than
1, the first array behaves as if it were copied along that dimension.
import numpy as np
a = np.array([17, 11, 19]) # 1x3 Dimension array
print(a)
b=3
print(b)
[17 11 19]
3
[20 14 22]
import numpy as np
126
A = np.array([[11, 22, 33], [10, 20, 30]])
print(A)
b=4
print(b)
C=A+b
print(C)
Output:
[[11 22 33]
[10 20 30]]
4
[[15 26 37]
[14 24 34]]
127
Module-5
Pandas provide a unique method to retrieve rows from a Data frame. DataFrame.loc[] method
is used to retrieve rows from Pandas DataFrame. Rows can also be selected by passing
integer location to an iloc[] function.
128
Note: We’ll be using nba.csv file in below examples.
Output:
As shown in the output image, two series were returned since there was only one parameter
both of the times.
To create DataFrame from dict of narray/list, all the narray must be of same length. If index
is passed then the length index should be equal to the length of arrays. If no index is passed,
then by default, index will be range(n) where n is the array length.
import pandas as pd
129
# intialise data of lists.
data = {'Name':['Tom', 'nick', 'krish', 'jack'],
'Age':[20, 21, 19, 18]}
# Create DataFrame
df = pd.DataFrame(data)
Python is a great language for doing data analysis, primarily because of the fantastic
ecosystem of data-centric Python packages. Pandas is one of those packages and makes
importing and analyzing data much easier.
Dataframe.aggregate() function is used to apply some aggregation across one or more
column. Aggregate using callable, string, dict, or list of string/callables. Most frequently used
aggregations are:
sum: Return the sum of the values for the requested axis
min: Return the minimum of the values for the requested axis
max: Return the maximum of the values for the requested axis
Parameters:
func : callable, string, dictionary, or list of string/callables. Function to use for aggregating
the data. If a function, must either work when passed a DataFrame or when passed to
DataFrame.apply. For a DataFrame, can pass a dict, if the keys are DataFrame column
names.
axis : (default 0) {0 or ‘index’, 1 or ‘columns’} 0 or ‘index’: apply function to each column. 1
or ‘columns’: apply function to each row.
130
Example #1: Aggregate ‘sum’ and ‘min’ function across all the columns in data frame.
df.aggregate(['sum', 'min'])
Output:
For each column which are having numeric values, minimum and sum of all values has been
found. For dataframe df , we have four such columns Number, Age, Weight, Salary.
import numpy as np
import pandas as pd
concat() function does all of the heavy lifting of performing concatenation operations along
an axis while performing optional set logic (union or intersection) of the indexes (if any) on
the other axes.
# Python program to concatenate dataframes using Panda
132
5.5 Plotting using matplotlib & panda
# x axis values
x = [1,2,3]
# corresponding y axis values
y = [2,4,1]
133
the code seems self explanatory. Following steps were followed:
Define the x-axis and corresponding y-axis values as lists.
Plot them on canvas using .plot() function.
Give a name to x-axis and y-axis using .xlabel() and .ylabel() functions.
Give a title to your plot using .title() function.
Finally, to view your plot, we use .show() function.
# line 1 points
x1 = [1,2,3]
y1 = [2,4,1]
# plotting the line 1 points
plt.plot(x1, y1, label = "line 1")
# line 2 points
x2 = [1,2,3]
y2 = [4,1,3]
# plotting the line 2 points
plt.plot(x2, y2, label = "line 2")
134
plt.legend()
Output:
Plot of different data: Using more than one list of data in a plot.
# importing libraries
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randn(1000, 4),
index = ts.index, columns = list('ABCD'))
df = df.cumsum()
plt.figure()
df.plot()
plt.show()
Output:
135
136