[Book] Introduction to Python_ With Applications in Optimization, Image and Video Processing, And Machine Learning
[Book] Introduction to Python_ With Applications in Optimization, Image and Video Processing, And Machine Learning
The book is written to be accessible and useful to those with no prior experience of Py-
thon, but those who are somewhat more adept will also benefit from the more advanced
material that comes later in the book.
Features
• Covers introductory and advanced material. Advanced material includes lists, diction-
aries, tuples, arrays, plotting using Matplotlib, object-oriented programming
• Suitable as a textbook for advanced undergraduates or postgraduates, or as a reference
for researchers and professionals
• Solutions manual, code, and additional examples are available for download.
Chapman & Hall/CRC
The Python Series
About the Series
Python has been ranked as the most popular programming language, and it is widely used
in education and industry. This book series will offer a wide range of books on Python
for students and professionals. Titles in the series will help users learn the language at an
introductory and advanced level, and explore its many applications in data science, AI, and
machine learning. Series titles can also be supplemented with Jupyter notebooks.
Python Packages
Tomas Beuzen and Tiffany-Anne Timbers
David Báez-López
David Alfredo Báez Villegas
Designed cover image: ShutterStock Images
Reasonable efforts have been made to publish reliable data and information, but the author and publisher
cannot assume responsibility for the validity of all materials or the consequences of their use. The authors
and publishers have attempted to trace the copyright holders of all material reproduced in this publica-
tion and apologize to copyright holders if permission to publish in this form has not been obtained. If
any copyright material has not been acknowledged please write and let us know so we may rectify in any
future reprint.
Except as permitted under U.S. Copyright Law, no part of this book may be reprinted, reproduced, trans-
mitted, or utilized in any form by any electronic, mechanical, or other means, now known or hereafter
invented, including photocopying, microfilming, and recording, or in any information storage or retrieval
system, without written permission from the publishers.
For permission to photocopy or use material electronically from this work, access www.copyright.com
or contact the Copyright Clearance Center, Inc. (CCC), 222 Rosewood Drive, Danvers, MA 01923, 978-
750-8400. For works that are not available on CCC please contact [email protected]
Trademark notice: Product or corporate names may be trademarks or registered trademarks and are used
only for identification and explanation without intent to infringe.
DOI: 10.1201/9781003222118
Publisher’s note: This book has been prepared from camera-ready copy provided by the authors.
Dedicated to Laura and Gary, my children, and to
Alina, my granddaughter.
The future is yours.
Preface xiii
Author Biographies xv
1 Introduction to Python 1
1.1 What is the Python Programming Language . . . . . . . . 1
1.2 The Python Programming Language . . . . . . . . . . . . . 1
1.2.1 Downloading Python . . . . . . . . . . . . . . . . . 2
1.2.2 The Python’s Integrated Development and Learning
Environment . . . . . . . . . . . . . . . . . . . . . . 2
1.3 Book Organization . . . . . . . . . . . . . . . . . . . . . . . 3
1.4 Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.5 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.5.1 Types of Variables . . . . . . . . . . . . . . . . . . . 5
1.5.2 Variable Assignment . . . . . . . . . . . . . . . . . . 6
1.5.3 Basic Operations . . . . . . . . . . . . . . . . . . . . 7
1.6 Input and Output in Python . . . . . . . . . . . . . . . . . 7
1.6.1 Escape Sequences . . . . . . . . . . . . . . . . . . . 9
1.7 Programs in Python . . . . . . . . . . . . . . . . . . . . . . 10
1.8 Comments in a Program . . . . . . . . . . . . . . . . . . . . 11
1.8.1 Operations with Integer and Floating-point Numbers 13
1.9 Functions in Python . . . . . . . . . . . . . . . . . . . . . . 13
1.10 Modules and Libraries . . . . . . . . . . . . . . . . . . . . . 14
1.11 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.11.1 Arithmetic Operators . . . . . . . . . . . . . . . . . 16
1.11.2 Relational Operators . . . . . . . . . . . . . . . . . 16
1.11.3 Logical Operators . . . . . . . . . . . . . . . . . . . 17
1.11.4 Assignment Operators . . . . . . . . . . . . . . . . . 18
1.12 Alphanumeric Variables . . . . . . . . . . . . . . . . . . . . 19
1.13 Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.14 Dictionaries . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.15 Tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
1.16 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
1.17 Python Instructions for Chapter 1 . . . . . . . . . . . . . . 26
1.18 Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.19 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
vii
viii Contents
4 Arrays 88
4.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
4.2 Introduction to Arrays . . . . . . . . . . . . . . . . . . . . . 88
4.3 Vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
4.3.1 Access to Vectors . . . . . . . . . . . . . . . . . . . 93
4.3.2 Vectors by Comprehension . . . . . . . . . . . . . . 93
4.3.3 The Instruction append . . . . . . . . . . . . . . . . 94
4.4 Examples with Vectors in Python . . . . . . . . . . . . . . . 94
4.4.1 Vector Sorting . . . . . . . . . . . . . . . . . . . . . 102
4.5 Matrices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
4.6 Arrays in Python . . . . . . . . . . . . . . . . . . . . . . . . 105
4.6.1 Array Generation by Indexing . . . . . . . . . . . . 106
4.6.2 Array Generation by Comprehension . . . . . . . . 108
4.7 Matrix Operations using Linear Algebra with numpy . . . . 110
4.7.1 Sum, Difference, and Multiplication of Matrices . . 110
4.7.2 Sum of Matrices . . . . . . . . . . . . . . . . . . . . 110
4.7.3 Product of a Matrix by a Matrix . . . . . . . . . . . 111
4.7.4 Product of Matrices in Python . . . . . . . . . . . . 113
4.7.4.1 Matrix Multiplication Using np.dot . . . . 113
4.7.4.2 Matrix Multiplication Using np.matrix . . 113
4.8 Special Matrices . . . . . . . . . . . . . . . . . . . . . . . . 116
4.8.1 The Identity Matrix . . . . . . . . . . . . . . . . . . 116
4.8.2 The Transpose Matrix . . . . . . . . . . . . . . . . . 116
4.8.3 Transpose by Comprehension . . . . . . . . . . . . . 118
4.9 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
4.10 Arrays in Pandas . . . . . . . . . . . . . . . . . . . . . . . . 125
4.10.1 Data Frames . . . . . . . . . . . . . . . . . . . . . . 129
4.10.2 Generation of Data Frames . . . . . . . . . . . . . . 132
4.10.3 Functions for Series and Data Frames . . . . . . . . 133
4.11 Python Instructions for Chapter 4 . . . . . . . . . . . . . . 136
4.12 Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
4.13 Selected Bibliography . . . . . . . . . . . . . . . . . . . . . 137
4.14 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
5 Functions 142
5.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
5.2 Subprograms . . . . . . . . . . . . . . . . . . . . . . . . . . 142
5.3 Functions in Python . . . . . . . . . . . . . . . . . . . . . . 143
5.4 Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
5.5 Anonymous Functions or lambda Functions . . . . . . . . . 149
5.6 Pass by Reference . . . . . . . . . . . . . . . . . . . . . . . 150
5.7 Local and Global Variables . . . . . . . . . . . . . . . . . . 151
5.8 Keyword and Default Arguments . . . . . . . . . . . . . . . 152
5.9 Variable-length Arguments . . . . . . . . . . . . . . . . . . 154
5.10 Additional Examples . . . . . . . . . . . . . . . . . . . . . . 155
x Contents
9 Optimization 258
9.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . 258
9.2 Optimization Concepts . . . . . . . . . . . . . . . . . . . . . 258
9.2.1 Parameters, Variables, and Functions . . . . . . . . 259
9.3 General Format of the Optimization Process . . . . . . . . 260
9.4 Optimization with Python . . . . . . . . . . . . . . . . . . . 261
9.5 The minimize Function . . . . . . . . . . . . . . . . . . . . 262
9.6 Linear Programming . . . . . . . . . . . . . . . . . . . . . . 271
9.7 Quadratic Programming . . . . . . . . . . . . . . . . . . . . 280
9.8 Python Instructions for Chapter 9 . . . . . . . . . . . . . . 283
9.9 Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
9.10 Selected Bibliography . . . . . . . . . . . . . . . . . . . . . 284
Index 431
Preface
xiii
xiv Preface
David Báez-López
David Alfredo Báez Villegas
xv
Chapter 1
Introduction to Python
DOI: 10.1201/9781003222118-1 1
2 Python with Optimization, ...
1.4 Algorithms
An algorithm is a way to solve a problem. Examples of algorithms in everyday
life can be found in cooking recipes, instructions to drive to a place, how
to assemble pre-built furniture, fixing a computer by a technician, etc. In
all of these examples, there is a sequence of steps to successfully complete
the required assignment. The last step in the design of the algorithm is the
4 Python with Optimization, ...
testing step to insure that the algorithm behaves as expected. A more accurate
definition of an algorithm is:
1.5 Variables
Variables are data that can take on different values depending upon the algo-
rithm. Variables must have a name to identify them. The name is a string of
alphanumeric characters which must start with a letter. The name may have
numbers and underscores, either capital or lower-case letters. Also, the name
is unique; that is, no other variable can have the same name. In Python, a cap-
ital letter is different from a lower-case one; thus, the variable A1 is different
from a1.
In every programming language, there are reserved words called keywords
and cannot be used as variable names. Python 3 has 33 keywords. To display
them in the IDLE type:
Names of variables must start with a letter and can only have
letters, numbers, and underscores.
12345.987
A variable is an integer one if it does not have a fractional part; that is,
it only has an integer part. For example, a = 6, speed = 45, depth = -3 are
integer variables.
An alphanumeric variable or text variable is a string of alphanumeric
characters which may include letters, numbers, and any other character. These
variables are called strings and are enclosed in single or double quotes such
as “elephant”, ‘silver_coin’, ‘year 2025’. The last string includes a blank
space which is counted as a character.
A boolean variable is a variable that can only take the values True or
False. They are used whenever a decision is taken. Boolean variables are
named after George Boole, a British mathematician who invented what is
now called Boole’s algebra.
The type of the variable is assigned when the variable is defined. Thus,
the expression a = 3 defines an integer variable, b = -3.24 defines a floating-
point variable, c = True defines a boolean variable, and d = “animal” defines
a string.
Python is a dynamic-type language. This means that a variable of a cer-
tain type can be redefined in a program with another type. For example,
the variable d = “animal” can be redefined in the program as d = -0.32, a
floating-point variable, and later on redefined as d = True, a boolean variable.
To find out what is the type of a variable the type instruction is used. For
example, if variables a, b, c, and d are given by:
>>> a = 2
>>> b = 5.6
>>> c = True
>>> d = ‘ENIAC’
6 Python with Optimization, ...
>>> type(a)
<class ‘int’>
>>> type(b)
<class ‘float’>
>>> type(c)
<class ‘bool’>
>>> type(d)
<class ‘str’>
>>> float(a)
1.0
>>> bool(a)
True
>>> str(a)
‘1’
a1 = 4
a2 = 8
In this way, a1 has the value 4 and a2 has the value 8. It is said that the value
4 is assigned to a1 and the value 8 is assigned to a2. This process is called an
assignment. If now the following is done:
a1 = a2
Now a1 is assigned the value of a2; thus, the new value of a1 is 8. The old
value of 4 is lost. The value of a2 has been assigned to a1.
Introduction to Python 7
>>> a = 3
>>> b = 5
>>> a + b
gives a result:
If a new variable is defined, the result is not automatically displayed. The user
must write the variable name at the Python prompt, as:
>>> c = a + b
>>> c
x = input( )
x = float(x)
These two instructions can be combined in a single row by assigning the type
to the string read with the input instructions. For example:
x = float(input( ))
The argument of the input instruction can have a text between double or
single quotation marks to indicate users what data is being read, as in:
8 Python with Optimization, ...
TABLE 1.1: Format options
Symbol Output type Example
d,i Signed integer -123
u Unsigned integer 123
f Floating-point 123.45
e Scientific notation 1.2345 e+002
g Shortest representation between f and e 123.45
c Character ‘a’
s String “program”
This indicates that the variable g is a floating-point one and its value is g =
9.8.
For the output of data, the instruction print can be used. To display the
value of g above, it can be done with:
print(g)
A format can be added inside the instruction print. The format options
are shown in Table 1.1. A formatting instruction can be added inside a print
instruction as in this example for the gravity as:
that displays:
The use of a print instruction provides a line feed. If there are two con-
secutive print instructions, the second print instruction is displayed in the
next line. For example,
produces:
Introduction to Python 9
a = 4
b = -7
print(f‘The value of a is: {a}. The value of b is: {b}’)
1 2 3
1
2
3
ax + b = c
that can be solved as
c−b
x=
a
This solution can be programmed1 as:
x = (c - b)/a
print(“The solution of the first-degree equation is x = ”, x)
To create this script, in the menu bar in the Python IDLE select
as shown in Figure 1.2. This opens a new window where the program can be
written. Before executing the script, it must be saved to a convenient location
with the name: Solution_first_degree_equation.py. To run this program,
in the menu bar of the program window, select Run → Run Module as shown
in Figure 1.3. The result is:
the code starting with a hash character. Finally, there are multiple lines of
code. These lines of code start with three single or double quotation marks to
open the lines of code. Triple single or double quotation marks must close the
comment block. For the solution of the first-degree equation, comments may
be implemented as:
>>> a = 3.4
>>> b = 2
>>> x = a + b
>>> print(x)
5.4
import math
a = 3
b = math.sqrt(a)
Introduction to Python 15
In this case each and everyone of the functions available in the module
are imported. This makes the program larger.
2. Instead of importing the whole module, import only the square root
function. This is done with:
import numpy as np
b = np.sqrt(a)
The option to display 92 lines is printed in the IDLE. Clicking on the option
displays all the functions available in the library numpy.
16 Python with Optimization, ...
TABLE 1.4: Arithmetic operators
Operation Operator Example Precedence
Addition + a + b 3
Subtraction - a - b 3
Multiplication * a*b 2
Division / a/b 2
Integer division // a//b 2
Power ax pow pow(a, x) 1
1.11 Operators
Operators indicate the type of operations that can be performed on the vari-
ables. There exist four types of operators:
1. Arithmetic.
2. Relational.
3. Logic.
4. Assignment.
a < b → True
a > b → False
a == b → False
a != b → True
It can readily be seen that the these statements can only have a Boolean
result, namely, either True or False.
>>> a and b
True
>>> a and c
False
>>> a or c
True
>>> a|c
True
18 Python with Optimization, ...
TABLE 1.7: Assignment operators
Python Operator
a = b =
a = a + 1 a += 1
a = a − 1 a −= 1
a = a + b a += b
a = a − b a −= b
a = a ∗ b a ∗= b
a = a / b a /= b
a = a % b a %= b
>>> a ∧ b
False
>>> a ∧ c
True
a & b | c
has the result True because a&b = False and False|c is True, but
a&(b|c)
is False because first (b|c) is computed and the result is True, but a&True is
False. Thus, using parenthesis alters the order and evaluation and the result.
a += 1 → a = 6
a -= 1 → a = 4
a += b → a = 8
Introduction to Python 19
a -= b → a = 2
a ∗= b → a = 15
a /= b → a = 1.66667
a %= b → a = 2
The result is 11 because the blank space is also counted. Strings can be con-
catenated, or added, with the symbol +. For example, given the strings a =
‘cats’, b = ‘dogs’, c = ‘ ’, d = ‘and’, they can be added as:
>>> a + c + d + c + b
cats and dogs
>>> len(a + c + d + c + b)
13
The blank string is used for separation of the strings. The length of the string
is 13 because the two blank spaces are also counted.
Each character in a string has a position. The numbering of the position
may start from the left and in that case, the left-most character is in the
position 0, the next element to the right is in position 1, and so on. The last
element in a string with length n is in position n-1. If the position numbering
starts from the right, then the right-most element is in position -1, the next
element to the left is in position -2, and so on. The left-most element is in
position -n. The numbering of a string is depicted in Figure 1.4.
20 Python with Optimization, ...
1.13 Lists
Sometimes it is necessary to work with a set of data. In Python, a list is such
a set. A list of elements is enclosed in brackets and the elements of the list
can be of several types, for example, some elements can be integer ones, but
other elements can be floating-point elements, strings, or even lists. Elements
in a list must be separated by a comma. A list must have a finite number of
elements. As an example, a list of the first ten natural numbers is:
Another example is a list of friends with their age; thus, the list elements can
be strings and integer numbers:
>>> friends = [‘Pete’, 16, ‘Rose’, 15, ‘John’, 21, “Louis”, 19]
The number of elements of a list can be found with the function len() as was
the case for strings. Further, lists can be concatenated and multiplied by an
integer. For example,
>>> name*3
[‘Tony’, 17, ‘Tony’, 17, ‘Tony’, 17]
Introduction to Python 21
The instruction len is used to find out the number of the list name as:
>>> len(name)
2
because there are only two elements in the list name. But if it is desired to
find the number of elements in the first element of the list name, the result is:
>>> len(name[0])
4
1.14 Dictionaries
Dictionaries are lists whose elements are pairs of variables. Each pair is com-
posed of a key and a value. The key and its value are separated by a colon.
The pairs are separated by commas. For example,
To print the value of a pair only the key is needed. To print the value of key
a in dictionary1 use:
The length of a dictionary is obtained with the instruction len. For exam-
ple, consider the following dictionary whose length is going to be found:
The answer is 2 because in the dictionary mat there are 2 pairs. Note that in
the dictionary mat the values are lists.
The list friends from the previous section can be better written as a
dictionary. This can be done with:
friends = {‘Pete’: 16, ‘Rose’: 15, ‘John’: 21, ‘Louis’: 19, ‘Tony’:
17}
1.15 Tuples
A tuple is an ordered collection of elements. Tuples may or may not be enclosed
in parentheses. The elements of a tuple can be strings, integers, floating-point,
lists, dictionaries, or any combination of elements. The length of a tuple can be
found with the function len( ). For example, the tuple animals = (“cats”,
“dogs”, “birds”), the length can be found with:
1.16 Examples
This section presents three examples of small programs or scripts in Python.
The first example uses tuples to swap variables, the second example computes
simple and compound interest and the last example implements temperature
conversion. The scripts have to be written in a new file and run as described
in Section 1.7.
>>> temp = x
>>> x = y
Finally, store the temporary variable which has the value of x into y:
>>> y = temp
The final result is that the values of the variables x and y have been swapped.
There is another way to do the swapping using tuples and the whole swapping
is done with:
For example, given the tuple (-7, 23), the values are swapped with:
“ ‘Temperature conversion
This script converts between different temperature scales ”’
# START
# END
To compute the power the function pow is used and it is available at the library
math that must be imported. The script is:
Introduction to Python 25
“ ‘Interest calculation.
This is Example 1.8. This program obtains the simple
and compound interest. ”’
# Simple interest:
simple_interest = principal*n*interest_rate
compound_interest = principal*pow(1 + interest_rate, n) - 1
# Display results:
print(“Simple interest: %0.2f” % simple_interest)
1.18 Conclusions
In this chapter the basic Python concepts such as variables, scripts, modules
or libraries, among many others, have been presented. Some examples show
how easy is to have a running program in Python. The Python IDLE has been
used but everything can be used in other platforms such as Jupyter or Spyder.
Introduction to Python 27
1.19 Exercises
1.1 What is displayed for the script presented below? Try to find the result
without running the script in the IDLE.
n = 4; k = 2
print(n)
print(-n)
print(n–)
print(n + k)
print(k)
print(n, k)
print(“ ”)
print(“n %3.2g” % n)
print(“n * n = %3.2g” % n*n)
print(n*n)
print(‘n’)
1.2 Indicate the output in the following segments of code:
a) x = 3
x = x + 2
print(x)
b) y = - 5.3
y = y*7.0
print(y)
c) x = 8; y = 3)
x = x%y
print(x)
1.3 Find the results for the following segments of code:
a) x = 3
x = x + 2
print(x)
b) y = - 5.3
y = y*7.0
print(y)
c) x = 8; y = 3
x = x % y;
print(x)
28 Python with Optimization, ...
1.4 The function getsizeof( ) from the library sys is used to obtain the
size of a variable. Using getsizeof( ) obtain the size of the variable “a” for
a) a = 2.0
b) a = 2
c) a = 20000
d) a = ‘2’
e) a = True
x = 42.0
y = 42.3 e-14
a = 42.3 e-14
b = −57.8
m = +87
n = +249
print(m*n)
print(x)
print(y)
print(a)
print(b)
a) x = 90.34
print(x)
b) z = 2
y = 7;
x = y + 2*z
print(“The result is: %5.2g” % x)
x = 8; y = 5
a = 1; b = 2
c) x = 1 & (a <= 2 | y = x)
Introduction to Python 29
a = 2; b = 3
x = 8.3; y = -4.6; z = 2.3
print (“a*b = %5.2f” % a*b )
print(“a/b = % 5.2f” % a/b )
print(“x/y = % 5.2f” % x/y )
print(“a*z = %5.2f” % a*z )
c = ‘8’
r = 3
print(c*r)
x = 7; y = 3
a. x % y
b. x = x + y
c. x += y
d. x =+ y
e. x *= y
f. x =* y
g. x %= y
1.11 Write a script to read the data: 7.0, 2.0, 8.3, 3.0, 5.6, 4.0 and
compute:
a. The maximum value.
b. The minimum value.
c. The addition.
d. The mean.
Chapter 2
Conditionals and Loops
2.1 Introduction
In real life, very often it is necessary to take a decision about what is the
next step in a given situation. The decision usually is taken depending upon
certain conditions in the situation. In the Python programming language, this
decision-making process also takes place, and the condition or conditions in
the process have to be evaluated. The decision-making instructions are known
as conditionals and they are studied in the first part of the chapter. The
second part of the chapter studies the instructions to repeat a process. These
instructions are called loops and they appear in iterative processes such as
those in numerical analysis, physics and finance, to name a few areas.
The chapter starts with the definition of a conditional in Python. Then, the
extension to nested conditionals is presented. Several examples show the use
of conditionals. Loops are introduced next. The two types of loops, for loops
and while loops are defined. Finally, examples using loops and conditionals
are presented.
2.2 Conditionals
Conditionals arise when an operation execution depends upon the true value
of a logic expression. For example, to take the square root of a number can only
be done if the number is positive. Thus, a conditional has to be implemented
to check that the number is positive.
The conditions in Python use the key word if in the following format:
if (logic expression):
Instructions
Next instructions
DOI: 10.1201/9781003222118-2 30
Conditionals and Loops 31
they must have the same indentation. The indented instructions are part of
the if statement and they are executed if the logic expression is True. Oth-
erwise, if the logic expression is False, the Next instructions are executed.
The logic expression can be inside parenthesis but this is not compulsory and
they may be omitted.
check = False
if (b != 0):
check = True
if (check):
c = a/b
print(“Result:”, c)
When the variable check is True, then it executes c = a/b and prints the
result. Otherwise, when a check is False it does not do anything.
The complete script is:
check = False
if (b != 0):
check = True
# End of conditional.
# Starts conditional.
if (check):
c = a/b
print(“Result:”, c)
The logic expression may use any of the relational operators shown in
Table 2.1. It can be seen that the equality comparison uses a double-equal
sign. Thus, a == b is comparing if a is equal to b. If the equality holds then
the logic expression is True. Otherwise, it is False. It is worth mentioning
that a = b is an assignment meaning that the value of b is assigned to a; thus,
it is not a comparison.
For example, consider the following example of correct and incorrect logic
expressions:
Composite logic expressions may also use the logic connectives from Table 2.2.
Some examples are:
a = 1; b = 2; c = 3
if( a < b ): True logic expression
if( a < b or c > 0): True logic expression
if( b > 1 and c == 4): False logic expression
• Read in a and b
• Check if a = 0
• Solve for x = b/a
• Display x
if (a != 0):
x =− b/a
print (“Result:”, x)
# End of the conditional.
# END
When this script is executed for the equation 2x + 3 = 0 the coefficient values
are a = 2, b = 3 and the value for x is −1.5. For the equation 0x + 3 = 0
the coefficient values are a = 0 and b = 3. In this case, the program does not
give any answer because the conditional is not true and the solution is not
obtained.
if(logic expression):
instructions 1
else:
instructions 2
This statement works as before in the first part; that is, the instructions 1
below the if conditional are executed if the logic expression is true, but
in the second part, the instructions 2 corresponding to else are executed
when the logic expression is false. Note that there is a semicolon after the
key word else.
The first-order equation script can be modified to print out a message as:
if (a != 0):
x = − b/a
print (“Result:”, x)
else:
print (“The equation cannot be solved because a = 0”)
# End of the conditional.
# END
Note that the else instruction MUST be aligned with the if instruction.
if (logic expression A) :
instructions 1.
elif: logic expression B:
instructions 2.
else:
instructions 3.
following instructions....
ax2 + bx + c = 0
√
−b ± b2 − 4ac
x1,2 = (2.1)
2a
The discriminant of this equation is given by
d = b2 − 4ac (2.2)
Depending upon the value of this discriminant there are three possible solu-
tions as follows:
1. Check if d > 0
• The solutions are real and different and given by equation (2.1).
2. Check if d == 0
• The solutions are real and equal and given by:
−b
x 1 = x2 =
2a
3. Check if d < 0
• The solutions are complex conjugate and they are given by:
√
−b ± i 4ac − b2
x1,2 =
2a
√
where i is the imaginary number i = −1.
Conditionals and Loops 37
To display the +- sign in Pyhton the unicode code \u00b1 is used as shown
below. The implementation in a Python script is as follows:
# START:
# END
a=3
b=0
c = a/b
print(b)
try:
c = a/b
print(c)
except ZeroDivisionError:
print(“Zero division error”)
else:
print(“Succesful division”)
The key words are try, except, and else. The key words try and else are
followed by a semicolon. The original code is placed after the try key word.
The error message is placed after the except key word. A semicolon is placed
after the error message. The else is optional and can be used to display a
success message. In the previous code, the else statement can be omitted.
It is not necessary to know the name of the error, just to know that there
might be the possibility of a run-time error. Another way to write the excep-
tion is as follows:
a=3
b=0
try:
c = a/b
print(c)
except:
print(“Zero division error”)
number = 3.1416
string = “Letter”
result = number + string
print(result)
number = 3.1416
string = “Letter”
try:
result = number + string
print(result)
except:
print(“Types are different”)
2.6 Loops
In some algorithms, it is necessary to repeat a set of instructions several times.
Instead of repeating the code, loops can be used. Loops are statements that
repeat a set of instructions a given number of times. There are two types of
loops: the while loop and the for loop. In the while loop, a set of instructions
is repeated a number of times depending upon a logic expression. In the
for loop, the set of instructions is repeated a given number of times. In this
case, there is no logic expression involved.
In the while loop, the logic expression is checked just before the loop
begins. In this way, it might be possible that the instructions inside the while
loop are never executed if the condition is not met. In the for loop there is
not a logic expression to be satisfied and the set of instructions inside the
loop is repeated a fixed number of times. The combination of both the while
and for loops together with the conditions of the previous chapter gives the
designer tools to implement powerful and yet, simple and elegant algorithms.
It can be seen that if the logic expression is false then the while loop may
not be executed because the first thing that has to be done is to check if the
logic expression is true.
The instructions inside the while loop must be indented. In addition,
there must be present a variable called the index that must be initialized
before the while loop and may change its value inside the loop to modify the
logic expression.
It could be the case that the logic expression is always false and, there-
fore, the while loop NEVER executes.
sum = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10
In the while loop the logic expression involves the index, so when it
reaches the value of eleven the logic condition becomes false. Thus the logic
expression is:
k < N + 1
The sum is incremented by the index, which takes the values from 1 to N. This
is done with:
sum = sum + k
The result after running the script for N = 10 is 55 as expected. The variable
where the sum is made is known as the accumulator.
6. The while loop ends when a divisor for N√is found or when the search
ends because the divisor is greater than N.
7. Once the while loop is finished, the result is displayed with a print
instruction.
As can be seen the comparison is made with the Boolean variable is_prime.
for counter_values:
Instructions
set of instructions is indented after the semicolon. The instructions inside the
loop ends when the indentation is ended. Another way to express values for
the counter_values is in a list as in
Instructions
sum = 55.
Conditionals and Loops 47
range(a, b, c)
This function creates a list that starts in a, it ends before b, and c is the
increment. The list generated is:
In every case, the last value in the list is NOT b. The last two examples show
decrement. The value of the increment cannot be 0.
# START
# END
as the external loop and the loops inside this loop are known as the nested
loops. The structure of the nested loops is:
loop_1
Instructions_1.
# End of loop_3.
# End of loop_2.
# End of loop_1.
It can be seen that loop_2 is nested inside loop_1 and that loop_3 is nested
inside loop_2. Each nested loop must be completely inside another loop.
Name 1 2 3 4 5 6
Gary 8.7 9 7.8 8.1 8.2 9.5
Laura 9.6 10 10 9.4 9.7 9.3
Alina 9.5 6.4 8.9 8.9 9.9 10
For each student, the algorithm must read the name of the student, and
the grades, and calculate the average. The steps to follow are:
1. Read the name of the student. To count the number of students use a
counter.
2. Read the grades, add them up, and take the average. Use a grade counter
to count the number of grades that have been read.
array = [ ]
GeneralAverage = 0
# Average calculation.
average = sum/6.0
# Add the average to the list:
list.append(average)
# Update GeneralAverage:
GeneralAverage += average
The variables x and z have four values, and y has six values. Three loops have
to be used for the computation. Any combination of for and while loops can
be used. For the values for x a for loop is used, and a while loop for the y
and z values.
The values for x can be written as the list x = [0, 2, 4, 6] and the y
and z values as the lists y = [-3, -2, -1, 1, 2, 3] and z = [2, 5, 8,
11]. They can also be written as:
The algorithm needs to have the three loops nested. Thus, for the first value
for x, say x0 = 0, and for the first value for y, say y0 = -3, compute the
function for every value of (x0, y0, z). Then, use the following value for y
as y1 = -1 and compute for every value (x0, y1, z). Continue in this way
until the function is computed for all the values of (x0, y, z). Then, for the
next value of x1, repeat the previous process until the function is computed
for every value of (x1, y, z). Continue until every value of x is used.
The script with the nested loops is:
# increment z:
z=z + 3
# increment y
y=y + 2
print()
After running the script, a long listing for the values of the function
f (x, y, z) = x + y + z is produced. The last four lines are displayed here:
x = 6 y = 3 z = 2 f = 11
x = 6 y = 3 z = 5 f = 14
x = 6 y = 3 z = 8 f = 17
x = 6 y = 3 z = 11 f = 20
Conditionals and Loops 53
3. Evaluate
1 N
Nk+1 = Nk +
2 Nk
4. A for loop is used. The loop is terminated when the difference between
consecutive values of Nk is less than 1 × 10−6 . That is
5. After the criteria is satisfied, display the result and the error.
6. Evaluate and display the square root with the function sqrt from the
module math. Display the difference between both results.
# Initial value.
Nk = 1.0
Trying the value N = 2702.5 the result after 10 iterations is (the last iteration
is shown):
It can be seen that the error between the function sqrt and Babylonian
method is very small.
Value of x = 10
Value of sum = 10.0
Value of x = 40
Value of sum = 50.0
Value of x = 70
Value of sum = 120.0
56 Python with Optimization, ...
It can be seen that only three integers less than 100 are divisible by 2 and by
5 simultaneously.
n! = 1 × 2 × 3 × 4 · · · × n − 1 × n
As an example, the factorial of 5 is given by:
Now, if the factorial of another number larger than 5 is needed, this previous
result can be used. In the case that it is needed to obtain the factorial of 20,
this can be done by multiplying the factorial of 19 times 20. The factorial of
19 can be obtained by multiplying the factorial of 18 times 19, and so on. By
definition, the factorial of 0 and the factorial of 1 are both equal to 1. The
following script obtains the factorial for any integer number:
Executing this script for n = 5 gives the expected result. The factorial for
another integer can be obtained too. For instance, for n = 10 the result is
3628800. In Chapter 7 the factorial function is revisited when the concept of
recursivity is presented. There is a factorial function in the math library and
in the numpy math library. Then the factorial can also be computed as
The following Python script obtains ten random numbers between 10 and 20:
58 Python with Optimization, ...
[18, 16, 14, 18, 13, 21, 15, 15, 11, 16]
The results vary from computer to computer and from run to run due to the
pseudorandom nature of the function randint.
Other functions to obtain random numbers are available in numpy which
includes the random library. To get integer random numbers the function
numpy.random.randint can be used. As an example, five random numbers
between 1 and 23 can be obtained with
where 1 is the lowest number, 23 is the greatest number and five random
numbers are going to be displayed in an numpy array, in this case, a one-
dimensional array.
To obtain random floating numbers between 0 and 1, the function available
is numpy.random.rand. For example to obtain random numbers in a 3×4 array
use
>>> numpy.random.rand(3, 4)
array([[0.42680396, 0.1773794 , 0.9608085 , 0.70378251],
[0.18838926, 0.82229386, 0.28981669, 0.33885616],
[0.21026074, 0.34366188, 0.6523904 , 0.45511047]])
>>> numpy.random.randn(3, 4)
array([[-0.44262916, -0.04642462, -1.37445931, 1.56985599],
[-0.08164265, -0.29936052, -0.00566557, -0.60739981],
[-1.49277666, 1.81893915, -0.16286686, -0.53728375]])
2.14 Conclusions
In this chapter conditionals and loops have been covered. The use of these in-
structions allows changing the sequence of a program depending upon either
the values of the variables or the computations needed. The conditionals can
be implemented with if closedup, if-else, and elif instructions. The loops
can be implemented with for and while loops. By means of examples, these
2.15 Exercises
1. What has to be done to an assignment in Python located immediately
after an if instruction to indicate that the assignment must be executed
only when the condition is true?
(a) >=
(b) !=
(c) <
(d) =
(e) ==
3. When there are multiple lines in an if block, how is the end of the block
indicated?
(a) The same indentation must be applied to the lines in the block.
(b) Use braces to indicate the block corresponding to the if instruc-
tion.
(c) Capitalize the first word not belonging to the if block.
4. What is the Python reserved word used when the logical test fails?
(a) switch
(b) else
(c) otherwise
(d) break
Conditionals and Loops 61
(a) Large
FINISHED
(b) Small
FINISHED
(c) Medium
FINISHED
(a) x = 2
(b) x = -2
(c) This code will never display ‘Something else’ regardless of the
value of x. .
(d) x = -2.0
62 Python with Optimization, ...
a < b
a < c & b > c
a < c & x
b == a | a < c
(a) 5
(b) 1.00
(c) 10
(d) 15
Conditionals and Loops 63
(a) friend
(b) friends
(c) Huey
(d) Dewey
(e) Louie
(a) -1
(b) 3
(c) 23
(d) 9
To check how fast is the convergence, display the result in the 5th, 10th
and 15th iteration.
2.16 Bibliography
1. https://docs.python.org/3/library/exceptions.html#bltin-exceptions
2. M. Matsumoto y T. Nishimura, Mersenne twister: a 623-dimensionally
equidistributed uniform pseudo-random number generator, ACM Trans. Mod-
eling and Computer Simulation, vol. 8, No. 1, pp. 3-30.
Chapter 3
Data Structures: Strings, Lists,
Tuples, and Dictionaries
3.1 Introduction
A brief introduction to some data structures is given. The structures cov-
ered are strings, lists, dictionaries, and tuples. In this chapter, some functions
that are applied to data structures are presented. Examples are used for this
purpose.
3.2 Strings
Strings are data structures with alphanumeric elements. The elements of a
string can be a single character, numbers, or a sequence of characters. The
elements of a string are enclosed in quotation marks. Examples of strings are:
In each one of the examples shown, the strings have a name and a certain
number of characters. The string “a101” has 15 characters including the blank
spaces, “car” has 6 characters, and “animal” has five. A string has to be
delimited by either single or double quotes.
Each character has a position in the string. The leftmost character has
position 0, the next one is position 1, and so on. Another way to indicate
the position is the following: the right most character is in position -1, the
following character to the left is in position -2, and so on. Thus, in string
“car”, the character “T’ is in position 0, the character o is in position 1, etc.
At the same time, the last “o” in “Torino” is in position -1, the “n” is in
position -2, and it can be seen that the “T” is in position -6.
The position of a character in a string is an integer number known as the
index.
DOI: 10.1201/9781003222118-3 65
66 Python with Optimization, ...
planets = “Mars_Jupiter_Saturn”
has 19 characters numbered from 0 to 18. The slice for “Jupiter” is obtained
as planets[5:12], and the slice for Mars is planets[0:4]. This is obtained
as:
>>> planets[5:12]
‘Jupiter’
>>> planets[0:4]
‘Mars’
>>> planets[13:30]
‘Saturn’
In this last slice, Python only prints the slice from character 13 to character
18 because the remaining characters do not exist.
For a string a, the operator a[: k] takes the slice that starts at the 0
Data Structures: Strings, Lists, Tuples, and Dictionaries 67
position and ends at the (k - 1)-eth position, whereas the operator a[k:]
is a slice consisting of the characters from the k-th position to the last one.
Two operations on strings are available, they are the sum of strings, also
called concatenation, and multiplication by an integer.
>>> new = a + b
“The dogis white”
There is not a blank space between the two strings because they only were
concatenated. A blank space can be added to correct as:
>>> new = a + “ ” + b
“The dog is white”
Next, the three strings are concatenated and blank spaces are added between
strings and a final period is also added:
>>> print(2*factor)
The result is 35, counting the blank spaces as parts of the phrase:
string_name.split(argument)
The argument in the split parenthesis means that the string_name is sepa-
rated in that argument. If there is no argument then the string is separated
into the blank spaces.
First, it is desired to separate the phrase in the blank spaces; thus, the argu-
ment of the split function is blank:
>>> Sagan.split( )
>>> Sagan.split(‘te’)
It can be seen that the string separator ‘te’ does not appear in the result.
city = ‘puebla’
but since strings are immutable, Python will give an error message:
a = “animals”
b = “flowers”
c = “nations”
>>> a.capitalize()
‘Animals’
Place ‘p’ before and after the string the substring indicated to have a total
of 20 characters:
>>> a.center(20,‘p’)
‘pppppppanimalspppppp’
How many ‘n’ there are between the characters in positions 0 and 6:
>>> c.count(‘n’, 0, 6)
2
>>> a.endswith(‘ls’)
True
>>> a.isalnum( )
True
>>> a.isnumeric( )
False
>>> min(c)
‘a’
>>> max(c)
‘t’
Fill with zeros at the beginning of the string for a total of 10 characters:
>>> c.zfill(10)
‘000nations’
Join with a given string a list of strings. In the example, the list
# [‘dog’, ‘cat’, ‘bird’] is called the iterable:
The answer is False because the character “u” is not in the variable ‘school’.
However, the character U produces:
if ‘e’ in phrase:
print(‘Player’ )
Player
because the character “e” is found in the string “May the best team win”.
The string player is displayed only once because the first time the “e” appears
in the string the condition is terminated. In the case that it is desired to print
the string “Player” each time that character “e” appears in the phrase, a for
loop can be used as:
Player
Player
Player
because the character ‘e’ appears three times in the string phrase.
74 Python with Optimization, ...
3.5 Lists
A list is a set of variables of the same or different type. A list has to be enclosed
by square brackets and the variables, called elements, have to be separated by
commas. Examples of lists are:
c = [27, ]
The first list is a list of strings and the fourth list has strings and numbers.
The last list is defined by a single element. It may include a comma but
this is not necessary.
Each element of a list has associated an index to indicate its position in
the list. The leftmost element has an index = 0, the next one to the right has
an index 1, and so on. Another way to enumerate the index is starting with
the rightmost element that is assigned index -1, the next one to the left has
index = -2, and so on.
>>> len(countries)
4
>>> len(countries[0])
Data Structures: Strings, Lists, Tuples, and Dictionaries 75
because now the element 0 in the list of countries is the string “Mexico”
that has 6 characters.
a slice from the element 1 to the element 3 is a list from the second to the
fourth elements, is:
and it can be seen that element with index = 4 is not included in the result.
3.5.2 Mutability
Lists are mutable. This means that the elements can either be changed,
deleted, or have new elements added.
The desired element changed its value because lists are mutable.
substring.join([list of strings])
76 Python with Optimization, ...
>>> substring.join(list)
To obtain:
substring = “”
It produces:
>>> substring.join(list)
‘catsdogsmice’
>>> max(b)
1858
3.6 Tuples
A tuple is a data structure consisting of elements that can be of different
types. Tuples are IMMUTABLE which means that the elements of a tuple
cannot be changed. Tuples may be enclosed between parentheses but that is
not compulsory. Examples of tuples are:
(-39, 23)
That is, the values in a and b have been swapped. This can be done with any
number of elements in the tuple, for example:
>>> a, b, c = c, a, b
>>> print(‘ a = ’, a, ‘\n b = ’, b,‘\n c = ’, c)
to obtain
a = car
b = 23
c = -39
Data Structures: Strings, Lists, Tuples, and Dictionaries 79
TABLE 3.2: Functions on tuples.
Funtion Description
tuple(list) Converts a list to tuple.
len(tuple) Length of a tuple.
max(tuple) Returns the element with the maximum value.
min(tuple) Returns the element with the minimum value.
3.7 Dictionaries
A dictionary is a data structure consisting of pairs of data. Each pair has a
first element called the key and a second element called the value. Both the
80 Python with Optimization, ...
key and the value can be of any type. Dictionaries are delimited by braces.
The format of a dictionary is:
a = { “key1”:value1,“key2”:value2,...,“keyM”:valueM }
Dictionaries are not immutable; that is, the elements of a dictionary can be
changed.
Pairs in dictionaries are referenced by the key; thus the pairs may appear
in different order with respect to the way they were referenced. For example,
>>> print(grades)
{ ‘Bob’ : 7.8, ‘Xavier’ : 10, ‘Hugo’ : 9, ‘Sarah’ : 9.2 }
Given that dictionaries are mutable, it is possible to change a grade, for ex-
ample, to change Bob’s grade from 7.8 to 8.9:
>>> print(grades)
{ ‘Bob’ : 8.9, ‘Xavier’ : 10, ‘Hugo’ : 9, ‘Sarah’ : 9.2 }
3.8 Sets
Sets are unordered collections of objects which do not allow repetition of the
elements of the set. Any duplicate element is ignored. Sets support mathemat-
ical operations like union, intersection, difference, and symmetric difference.
A collection of elements is a set if its enclosed by curly brackets. Examples of
sets are:
# Clears a set:
>>> fruits2 = fruits.clear( )
fruits2 = set( )
# Copy a set:
>>> fruits2.copy(fruits)
fruits2 = { ‘watermelon’, ‘cherry’, ‘orange’, ‘apple’}
>>> a.add(99)
The result is
Thus, most of the functions or methods in Table 3.4 cannot be used because
of the immutability property of frozen sets.
3.10 Conclusions
In this chapter strings, lists, tuples and dictionaries were defined as well
as some properties related to these data structures. The exercises presented
showed the different operations and functions on them. The examples at the
end of the chapter provide a complement to learn to use these data structures.
3.11 Exercises
1. Concatenate the string “Continent” with the string “American” to ob-
tain the string: “American Continent”. There must be a blank space
between the two words.
2. Develop an algorithm and its corresponding Python script for a game
where the program asks the user’s name. After a name is given the
program generates a random integer between 1 and 20. The game should
be in the following way (suppose that the generated number is 16):
[] correct
]] not correct
[[]] correct
[][] correct
[[][]] correct
[[]]]] not correct
6. The value of a word is the sum of the values assigned to a letter. If the
value for each letter is as follows: a = 1, b = 2, c = 3, etc., design an
algorithm and the corresponding Python script to compute the value of
a received word. Use a dictionary to assign the value for each letter as:
7. What is the result in the following loop applied to the Galileo’s phrase:
text = “The alphabet of the Universe is the Mathematics.”
for k in text.split():
print(k)
for k in text.split(‘t’):
print(k)
9. Add the strings “23” and “58” and convert the resulting string to a
floating point number.
10. Write a Python script to read four words, compute the string length and
display the words and the length indicated by asterisks. For example:
memory ******
mouse *****
computer ********
dots ****
13. Write a script to code a word to its equivalent in the International Civil
Aviation Organization (ICAO) phonetic code. The ICAO code must be
stored in a dictionary in the following way:
code = {‘A’ : ‘Alfa’, ‘B’ : ‘Bravo’, ‘C’ : ‘Charlie’, ‘D’ : ‘Delta’, ‘E’ : ‘Echo’,
‘F’ : ‘Foxtrot’, ‘G’ : ‘Golf’, ‘H’ : ‘Hotel’, ‘I’ : ‘India’, ‘J’ : ‘Juliett’, ‘K’
: ‘Kilo’, ‘L’ : ‘Lima’, ‘M’ : ‘Mike’, ‘N’ : ‘November’, ‘O’ : ‘Oscar’, ‘P’ :
‘Papa’, ‘Q’ : ‘Quebec’, ‘R’ : ‘Romeo’, ‘S’ : ‘Sierra’, ‘T’ : ‘Tango’, ‘U’ :
‘Uniform’, ‘V’ : ‘Victor’, ‘W’ : ‘Whisky’, ‘X’ : ‘Xray’, ‘Y’ : ‘Yankee’, ‘Z’
: ‘Zulu’ }
14. One application of sets is to get rid of duplicates. Use a for loop to
generate a random set of integer numbers between 1 and 10. Run the
loop for 100 loops.
Chapter 4
Arrays
4.1 Introduction
An array is a collection of objects. These objects usually are of the same type,
but this is not always the case. Arrays are used in a great deal of applica-
tions, for example, to store and handle bank accounts, census information,
inventories, sports statistics, and payrolls, to name a few.
The most common arrays are vectors and matrices. In Python, arrays are
represented by lists. In this way, a list represents a vector, a list of lists repre-
sents a two-dimensional array, and so on. In this chapter, the module numpy is
frequently used because it has a great deal of functions that are adequate to
handle arrays. Pandas is a package that handles arrays with functions similar
to the ones used with Numpy but that has found many applications in data
science and machine learning.
DOI: 10.1201/9781003222118-4 88
Arrays 89
An array must have a name and a size; that is, the number of elements.
Although the number of elements may be known beforehand, this is not always
the case, as it will be seen in the chapter.
4.3 Vectors
The simplest array is a vector represented by a list. Thus, a list may be thought
of as a vector. The following lists are vectors:
In the vector speeds the elements are integer numbers, in the vector trees
the elements are strings, but in the vector geometric_figures the elements
are strings and integer numbers. Thus, the elements in a vector or in a list
can be of heterogeneous type.
An array can also be created with numpy. Importing numpy as np, the
vector speeds is generated with:
import numpy as np
speeds2 = np.array([ 55, 60, 75, 80])
Looking for the type of both speeds and speeds2, it is seen that:
>>> type(speeds)
<class ‘list’>
>>> type(speeds2)
<class ‘numpy.ndarray’>
ndarray means that the array is multidimensional. In an array, the type of the
elements must be the same. Numbers and strings cannot be mixed. If some
elements are numbers and other elements are strings, numpy converts every
element to a string, as in the vector a90 given by:
It can be seen that numpy has converted the numbers 1 and 2 to strings. In
the dtype the sign <U11 means that the maximum size of each string is 11.
To return an array to a list use the instruction:
90 Python with Optimization, ...
TABLE 4.1: Grades.
Index Id_number Grade
0 301834 9.3
1 301846 9.9
2 301847 8.6
3 301889 10.0
4 301996 9.6
5 301998 8.9
6 302020 10.0
7 302028 9.1
8 302067 10.0
9 302135 10.0
name_of_the_array.tolist()
For example, for the array speeds2 = np.array([55, 60, 75, 80]), it be-
comes a list with:
import numpy as np
grades = np.array([9.9, 8.6, 10.0, 9.6, 8.9, 10.0, 9.1, 10.0])
Arrays 91
CAUTION
Vectors defined with numpy are not lists and thus, the
functions for lists cannot be applied to numpy arrays.
It can readily be seen that the student with id 302020 has a grade of
10.0 whereas the student with id number 301834 has a grade 9.9. In the first
student, the index is 6 and in the second one the index is 0.
Each element of the vector is called an element or a component. Each
component of a vector is referenced by its index. For example, id_number[1]
indicates the student with the No. 301846 and grades[2] indicate 8.6.
A for loop can be used to print out the id numbers and the grades. The
function range can be substituted by the equivalent function in numpy which
is arange as:
301834 9.3
301846 9.9
301847 8.6
301889 10.0
301996 9.6
301998 8.9
302020 10.0
302028 9.1
302067 10.0
In this for loop the index is student and it takes the values from 0 to 8 for
a total of 9 id numbers and 9 grades.
The sum is now divided by the number of grades. The value of the index i is
the number of grades. Thus:
average = sum/i
# The average is displayed:
print(‘The grade average is: %0.2f’ %average)
average = sum/i
# The average is displayed:
print(‘The grade average is: %0.2f’ %average)
The result for the grade average for this vector of grades is:
There are two functions in numpy that compute the average, they are
np.average and np.mean. For the vector in this example:
mean 9.5125
average 9.5125
grades[5] = 9.1
print(grades[11])
[0, 1, 4, 9, 16]
In the case of numpy arrays, the use of the instruction append is different and
it is used as:
[-3 5 8 27 99]
0.5338963331348068
a = random.randint(23, 32)
25
import random
x = [ ]
A for loop is used to generate the N random numbers and the function append
is used to append them to the vector x:
import random
x = [ ]
# The number of random numbers N is read:
N = int(input(“Enter the number of random numbers: ”))
x = [None]*N
for k in range(N):
x [k] = random.randint(min, max)
print(x[k])
33
46
39
40
36
47
The random numbers can change depending on the computer used and the
time of the execution.
random number generated with random, and it is known that it is less than
unity by a factor given by the maximum and minimum of the range as:
This results in a floating random number in the range between min and max.
This is the only change that has to be done in Example 4.3. The final program
is:
A run is:
4.2 and is repeated here. The equations that define these three functions for
a vector X[i] are for the average or mean value:
n−1
1
X= X[i]
n i=0
For the variance, also known as dispersion, it is a measure that the dispersion
of the data points around its center of gravity given by the mean value. A
large variance is an indication that many data points are distant from the
mean value. On the other hand, a small value for the variance is an indication
that the data points are clustered around the mean value. The variance is
represented by σ 2 with:
n−1
1 2
σ 2 = Variance = X[i] − X
n i=0
Finally, the standard deviation σ is defined by the square root of the variance.
The variance and the standard deviation have the same meaning, but the
standard deviation has the same units as the elements of the vector. The
standard deviation σ is given by:
√
σ = standard deviation = Variance
For a given vector X of length N the average, variance and standard deviation
can be computed. For the average:
average = sum/i
The variance requires the mean value. The following script computes the vari-
ance. First, the sum for the variance is initialized as:
variance = 0.0
The sum is done with a for loop and the variance is obtained by dividing the
sum by N:
for i in range(N):
sum = sum + (X[i] - average)**2
variance = sum/N
Arrays 101
sigma = sqrt(variance)
Finally, the average, variance, and standard deviation are printed out:
average = sum/i
# Standard deviation:
sigma = sqrt(variance)
for i in range(N):
vector[i] = randint(min, max)
print(“Original vector”)
print(vector)
print(“Sorted vector”)
print(sorted_vector)
A run is:
4.5 Matrices
Matrices are data structures that frequently appear in mathematics. They can
represent system models such as the coefficients of a system of simultaneous
linear equations, the pixels in an image, and a neural network, to name a few
applications. An example of the use of matrices is in the handling of sales in
a department store. Here, a vector may represent the sales in a month, but
for the whole year, it is more convenient to use a matrix instead of 12 vectors.
Another example is when forces act on a structure.
A matrix is a multidimensional array that can be used to store data. A
two-dimensional array is composed of rows and columns as the following array:
⎡ ⎤
a0,0 a0,1 ... a0,n−1
⎢ a1,0 a1,1 ... a1,n−1 ⎥
⎢ ⎥
A=⎢ . ⎥
⎣ .. ⎦
am−1,0 am−1,1 ... am−1,n−1
Arrays 105
ap,q
or simply
apq
Example 4.8 Examples of two-dimensional arrays
Consider the matrices A, B, y C given by:
⎡ ⎤ ⎡ ⎤ ⎡ ⎤
“a” “b” 77.3 3.1416 1 2 3
A = ⎣ “c” “d” ⎦ , B = ⎣10.01 −201.3⎦ , C =⎣9 18 −5⎦
“e” “f ” 66.6 27.021 16 4 7
The list is A and has three elements. The first list [1, -2.3, 0] is the first
element (element 0) of list A. The following list [ 9.6, -1.5, 4 ] is the
element 1 of list A. Finally, the list [ 5.7, -6.3, 3.1 ] is the element 2 of
list A. Each one of these lists has three elements.
106 Python with Optimization, ...
The array A can be printed with print(A) which produces the list as shown
above. If it is desired to print out the matrix as a table, two nested for loops
can be used. The first for loop prints a row and the second one prints the
following row:
1 -2.3 0
9.6 -1.5 4
5.7 -6.3 3.1
An escape sequence for a tab given by ‘\t’ has been added in the last print
for a better presentation.
A = [ ]
2. With a for loop generate the list corresponding to the rows. The length
of these lists is the number of columns m:
for i in range(m):
A.append([ ]) # A row is generated.
for j in range(n):
A[i].append(None) # Generates each one of the elements.
The matrix can be displayed with a pair of nested for loops as:
A = [ ]
for i in range(m):
A.append([ ])
for j in range(n):
A[i].append([None])
for k in range(m):
print( ) # New row.
for j in range(n):
print(A[k][j], “\t”)
[ ] [ ] [ ] [ ]
[ ] [ ] [ ] [ ]
[ ] [ ] [ ] [ ]
[ ] [ ] [ ] [ ]
In this definition, the rows are identical but the goal is to generate the array
with the desired size. For example, a 6×5 array with 0’s can be generated
with:
[[-7, 8, 5, 6, 9], [-10, 6, -6, -2, -3], [-7, -6, 10, -5, 1],
[1, -4, 6, 10, 3], [-10, -6, 4, 3, 4], [0, 8, 8, 9, 1]]
This matrix is randomly generated and the results change for each run.
Arrays 109
⎡ ⎤
−1 0 −10
⎢3 −4 0.5 ⎥
matrix = ⎢
⎣6
⎥
−23 8 ⎦
7 3 9
matrix = [[-1, 0, -10], [3, 4, 0.5], [6, -23, 8], [7, 3, 9]]
[ -1, 0, -10 ]
[ 3, 4, 0.5 ]
[ 6, -23, 2 ]
[ 7, 3, 9 ]
-1, 0, -10,
3, 4, 0.5,
6, -23, 8,
7, 3, 9,
110 Python with Optimization, ...
TABLE 4.2: Operations for numpy arrays
Operator Function
array.tolist() converts an array to list
array(list) converts a list to array
dot(v1, v2) dot product of vectors v1, v2
vdot(v1, v2) dot product of vectors v1, v2
inner(v1, v2) dot product of vectors v1, v2
linalg.eig(A) eigenvectors of matrix A
linalg.matrix_power(A,n) An power
linalg.norm(v, N) norm N of a vector
linalg.det(A) determinant of A
linalg.trace(A) trace of A
linalg.inv(A) inverse of A
linalg.solve(A, b) solve system of linear equations
linalg.transpose(A) transpose of A
[[ 6 8]
[11 11]]
⎡ ⎤
a0,0 a0,1 ... a0,m−1
⎢ a1,0 a1,1 ... a1,m−1 ⎥
⎢ ⎥
A=⎢ .. ⎥
⎣ . ⎦
an−1,0 an−1,1 ... an−1,m−1
⎡ ⎤
b0,0 b0,1 ... b0,k−1
⎢ b1,0 b1,1 ... b1,k−1 ⎥
⎢ ⎥
B=⎢ .. ⎥
⎣ . ⎦
bm−1,0 bm−1,1 ... bm−1,k−1
m−1
cij = ail blj = ai0 b0j + ai1 b1j + · · · + ai,m−1 bm−1,j
l=0
i = 0, 1, 2, . . . , n − 1 j = 0, 1, 2, . . . , k − 1 (4.1)
This is equivalent to say that the element cij is obtained by multiplying the
elements of the row i of matrix A by the corresponding elements of column
j of matrix B and adding the products. The only requirement is to multiply
112 Python with Optimization, ...
two matrices is that the number of columns of the first matrix is equal
to the number of rows of the second matrix.
⎡ ⎤
−7 −8
1 2 3
A= , B=⎣ 9 10 ⎦
4 5 6
4 −11
The order of A is 2×3 and the order of B is 3×2. Then, the product AB can be
obtained to be a matrix of order 2×2. Also, the product BA can be obtained
as a matrix of order 3×3. These products can be done with:
⎡ ⎤
−7 −8
1 2 3 ⎣
AB = 9 10 ⎦
4 5 6
4 −11
1 ∗ (−7) + 2 ∗ 9 + 3 ∗ 4 1 ∗ (−8) + 2 ∗ 10 + 3 ∗ (−11)
=
4 ∗ (−7) + 5 ∗ 9 + 6 ∗ 4 4 ∗ (−8) + 5 ∗ 10 + 6 ∗ (−11)
23 −21
=
41 −48
⎡ ⎤
−7 −8
1 2 3
BA = ⎣ 9 10 ⎦
4 5 6
4 −11
⎡ ⎤
(−7) ∗ 1 + (−8) ∗ 4 (−7) ∗ 2 + (−8) ∗ 5 (−7) ∗ 3 + (−8) ∗ 6
= ⎣ 9(1) + 10 ∗ 4 9 ∗ 2 + 10 ∗ 5 9 ∗ 3 + 10 ∗ 6 ⎦
4 ∗ 1 + (−11) ∗ 4 4 ∗ 2 + (−11) ∗ 5 4 ∗ 3 + (−11) ∗ 6
⎡ ⎤
−39 −54 −69
= ⎣ 49 58 87 ⎦
−40 −47 −54
The result is now a 3×2 matrix which is the same result as before:
import numpy as np
from random import *
a = np.matrix(a)
c = a*b
# Display the result of matrix multiplication with *.
print(‘Conversion of array a to matrix: c = a*b: \n c = ’, c)
a =
[[9 5 9 1]
[1 4 2 8]
[1 6 0 4]]
b =
[[0 4]
[1 5]
[0 8]
[9 5]]
c =
[[ 14 138]
[ 76 80]
[ 42 54]]
c =
[[ 14 138]
[ 76 80]
[ 42 54]]
The results will vary for each run because the matrices a, b, and c are created
with a random generator.
116 Python with Optimization, ...
import numpy as np
A = np.eye(4) # Order 4 identity matrix.
print(A)
[[1. 0. 0. 0. 0.]
[0. 1. 0. 0. 0.]
[0. 0. 1. 0. 0.]
[0. 0. 0. 1. 0.]
[0. 0. 0. 0. 1.]]
Another way to express the transpose of A is by using its elements aij as:
At = np.transpose(A)
For numpy arrays, the transpose may also be obtained with array.T. Thus,
for the array A above, the transpose can be found with np.array(A).T.
At =
[[ -1. 3. 6. 7.]
[ 0. 4. -23 3.]
[ -10. 0.5. 8. 9.]
At2 =
[[ -1. 3. 6. 7.]
[ 0. 4. -23 3.]
[ -10. 0.5. 8. 9.]
[[-1, 8, 6, 2], [4, 3, 9, 7], [10, -2, 5, 0], [5, -3, -1, 1]]
Arrays 119
4.9 Examples
In this section, two examples using matrices are presented. The first one is a
throw of a dice and an array is used to store the throws. The second example
solves a set of simultaneous linear differential equations using the eigenvalues
and eigenvectors of the system matrix.
import random
120 Python with Optimization, ...
2. The list is initialized as an empty array and the minimum and maximum
values of the throws are given:
throws = [ ]
min = 1
max = 6
for k in range(3):
print(throws[k])
5. The variable for the sum is initialized and the sum is computed:
6. The sixth column (column No. 5 throws[5] has the sum of the die
throws for each friend.
7. To count the number of 6’s for each friend, initialize the count to 0 and
use a for loop.
for t in range(5):
if throws[r][t] == 6: # Each throw is compared to 6.
count[r] += 1 # Increment the count for each 6.
8. Display the throws for each friend and the sum of points.
The number of throws with a six and the sum are displayed. There are
three cases for the number of 6’s. None at all, a single 6, and several 6’s.
Also, the friends vector with names is initialized:
throws = [ ]
min = 1
max = 6
[4, 2, 4, 2, 1]
[6, 3, 4, 2, 3]
[5, 4, 4, 6, 3]
dx
= −4x + y + z
dt
dy
= x + 5y − z
dt
dz
= y − 3z
dt
dX
= AX
dt
where
⎡ ⎤ ⎡ ⎤
−4 1 1 x
A=⎣ 1 5 −1⎦ and X = ⎣y ⎦
0 1 −3 z
The solution for this matrix differential equation is given in terms of the
eigenvalues λ1 , λ2 , and λ3 and the eigenvectors V1 , V2 , and V3 of matrix A
as:
X = C 1 V1 e λ 1 t + C 2 V 2 e λ 2 t + C 3 V3 e λ 3 t
The eigenvectors are given by
⎡ ⎤ ⎡ ⎤ ⎡ ⎤
v11 v21 v31
V1 = ⎣v12 ⎦ , V2 = ⎣v22 ⎦ , V3 = ⎣v32 ⎦
v13 v23 v33
import numpy as np
eigenvalues, eigenvectors = np.linalg.eig(A)
print(eigenvalues)
print(eigenvectors)
For the system matrix A above, the eigenvalues are given by:
[ 5. -4. -3.]
The eigenvectors are the columns of the array. Thus, the eigenvectors are given
by:
V0 = eigenvectors[:, 0]
Arrays 125
V1 = eigenvectors[:, 1]
V2 = eigenvectors[:, 2]
V2 = [0.707106781, 0, 0.707106781]
⎡ ⎤ ⎡ ⎤
−0.12309149 0.99014754
X = C1 ⎣−0.98473193⎦ e5t + C2 ⎣−0.09901475⎦ e−4t
−0.12309149 0.09901475
⎡ ⎤
0.707106781
+C3 ⎣ 0 ⎦ e−3t
0.707106781
import pandas as pd
The result is
0 a
1 b
2 1
3 2
dtype: object
The Pandas series is displayed and also shows the type of the result as an
object. The first column corresponds to the index and the second one to the
series values. Now consider the series b and the result given by
0 7
1 8
2 9
3 0
4 1
5 2
dtype: int64
which indicates that the elements in the series have the type int64; that is,
signed integers with a 64-bit lenght. The type of a Pandas series can be
changed using the method astype. For example, to change the type of se-
ries b to a floating point series and to a string series use
>>> c = pd.astype(float)
>>> d = pd.astype(str)
>>> c
>>> d
0 7.0
1 8.0
2 9.0
3 0.0
4 1.0
5 2.0
dtype: float64
Arrays 127
0 7
1 8
2 9
3 0
4 1
5 2
dtype: object
An index in the series can be found with index in series where the
result is a boolean, for example,
>>> 2 in b
True
>>> 7 in b
False
1 8
5 2
3 0
0 7
2 9
4 1
month 1
day 2
year 2024
dtype: int64
128 Python with Optimization, ...
month 1
day 2
year 2024
Name: Birth, dtype: int64
An index can be searched within a series with the method in. For example
Now consider changing the indexes to ‘year’, ‘quantity’, and ‘weight’. This
can be done with
year 2024.0
quantity NaN
weight NaN
Name: Birth, dtype: float64
The new indexes correspond to a value NaN which means Not-a-Number be-
cause there is no value assigned there. The index column may also have a
name with the method index.name. For example,
Several
month 1
day 2
year 2024
dtype: int64
Arrays 129
>>> df = pd.DataFrame(data)
>>> df
>>> df.columns
A column can be displayed with the name. For example, to display the column
corresponding to the codes
>>> df[‘Code’]
0 US
1 CA
2 MX
3 BR
4 AR
5 CO
Name: Code, dtype: object
130 Python with Optimization, ...
>>> df.Code
>>> df.head()
>>> df.head(3)
>>> df.loc[2]
Countries Mexico
Code MX
Size 1.96
Name: 2, dtype: object
>>> df.loc[[2]]
To add a capital city for Colombia add a new column with the name Capital
as
The result is False for every country but Colombia because it was declared
a capital city for this country. Another way to add a column is by declaring
the new column with a function, for example, in data frame df add a column
with half the population. This new column is called Half and it is added with
It can be seen that the column corresponding to Capital has been deleted or
dropped. To delete a row just write the column index; for example, to delete
the row corresponding to Canada use
>>> df.drop(1)
>>> df
132 Python with Optimization, ...
where sep refers to the separator in the data. To find out the path use
>>> import os
>>> os.getcwd()
If a table A is in text format the separator may be a tab \n. The table can be
read with
df = pd.read_csv(‘countriesOfTheWorld.csv’)
In this file, now converted to a Pandas data frame, there is a heading which
contains a number of characteristics besides the country name. The listing
ends with file information which in this case is a data frame with 227 rows
and 20 columns. Due to width limitations, only a few columns and a few rows
are displayed by Python. If the heading is of interest, it can be printed out
with
print(df.head(0))
which produces
0 4
1 8
2 9
2 10
1 3
dtype: int64
To compute the sine function of a Pandas series, the numpy function sin can
be used as
0 0.841471
1 0.909297
2 0.141120
0 -0.756802
dtype: float64
Further information about a series or data frame can be obtained with the
method describe as
>>> a.describe()
count 9.000000
mean 3.222222
std 5.651942
min -7.000000
25% -1.000000
50% 4.000000
75% 8.000000
max 10.000000
dtype: float64
In the case of data frames, the use of the method describe produces the same
results for each column as shown for the following data frame
0 1
count 2.000000 2.00000
mean 2.000000 3.50000
std 1.414214 2.12132
min 1.000000 2.00000
25% 1.500000 2.75000
50% 2.000000 3.50000
75% 2.500000 4.25000
max 3.000000 5.00000
>>> aa.info()
<class ‘pandas.core.frame.DataFrame’>
RangeIndex: 2 entries, 0 to 1
Data columns (total 2 columns):
Arrays 135
The methods loc and iloc fetch information from a series or data frame.
They work as:
To show how they work consider the data frame with indexes given by literals
and not by numbers. The data frame is defined by an array 6×4 with column
indexes with the letters a, b, c, d, e, and f. The row indexes are w, x, y, and
z. The data frame is
>>> df = pd.DataFrame(np.arange(24).reshape(6,4), \
index=list(‘abcdef’), columns=[‘w’, ‘x’, ‘y’, ‘z’)
>>> df
w x y z
a 0 1 2 3
b 4 5 6 7
c 8 9 10 11
d 12 13 14 15
e 16 17 18 19
f 20 21 22 23
The function loc retrieves by indicating the indexes. For example, to retrieve
the element in row d and column y, use
>>> df.loc[‘d’]
d 12 13 14 15
w x y z
a 0 1 2 3
b 4 5 6 7
c 8 9 10 11
The method iloc is similar to loc but it requires to give the indexes as
integers. For example, to display the rows from row a, which is row 1, to row
d, which is row 3, use df.iloc[1: 4] as
>>> df.iloc[1: 4]
b 4 5 6 7
c 8 9 10 11
d 12 13 14 15
To obtain a slice of the data frame use both row and column indexes as in
>>> df.iloc[1:4,1:3]
b 5 6
c 9 10
d 13 14
4.12 Conclusions
Vectors, matrices, and arrays find applications in many areas of science, math-
ematics, finance, engineering, and in general everyday life. This chapter has
introduced the use of arrays with Python. A section describes the use of Pan-
das to handle arrays. Several examples have presented how to use Python,
numpy and Pandas functions.
4.14 Exercises
1. Given the lists a = [1, 4, -2, 9], b = [-9, 0, 4, 7, -8]. Com-
pute a + b, a - b and 3*a.
138 Python with Optimization, ...
2. For the vector a = [23, 27, 02, 58, 19, -18, -1, 32, 92]. Find:
(a) a[3]
(b) a[3:5]
(c) a[:2]
(d) a[0:2]
Write a program to compute the magnitude for the vector x = [2, -4,
6, -3, -9].
4. The infinite norm x ∞ of a vector is defined by the largest magnitude
element. For the vector in the previous exercise, the infinite norm is
equal to 9. Write a program that obtains the infinite norm of a vector.
x · y = x1 · y1 + x2 · y2 + ... + xn · yn
Write a script to obtain the dot product of two vectors and compare the
result using the np.dot function.
7. The scalar product is also defined as the product of the vector magni-
tudes times the cosine of the angle between them. In this:
X · Y = |X| · |Y |cos(θ)
Figure 4.1 shows the angle for two vectors. Now, find the angle for vectors
X = [3, 4, 5], X = [-2, -1, 6].
8. Generate a random vector of size 10 with integral elements and sort it.
Display both vectors.
Write a program that must read data for 10 players. The program must
select those players that
⎡ ⎤
4 8 2
A = ⎣2 −2 −1⎦
6 7 3
⎡ ⎤
−1 10 4
B = ⎣ 12 0 −8⎦
−26 20 24
⎡ ⎤
−1 10 4
C = ⎣ 12 0 −8⎦
−26 −20 24
13. For the matrices in the previous exercise compute AB y CA. Explain
the results.
14. Compute the product A ∗ b.
⎡ ⎤
2 1 0
A=⎣9 −4 11 ⎦
16 5 −8
⎡ ⎤
10
b = ⎣−3⎦
17
15. Find the transpose of A for the previous exercise.
16. The game of memory, also called concentration game, consists of placing
pairs of cards upside down and arranged in matrix form. The players take
turns to choose two cards. If the cards are equal the cards are assigned
to that player. If the cards are not equal they are placed upside down
again. The game ends when all pairs are uncovered. Use a 5×2 matrix
of cards.
17. Improve the memory game to allow three levels: rookie with a 2×5 ma-
trix, intermediate with a 4×4, and pro with 4×6 matrix.
18. A diagonal matrix has non-zero elements in the main diagonal and has
0 otherwise; that is, it is of the form:
⎡ ⎤
d0,0 0 0 ... 0
⎢ 0 d1,1 0 ... 0 ⎥
⎢ ⎥
⎢ ⎥
D=⎢ 0 0 d2,2 ... 0 ⎥
⎢ .. ⎥
⎣ . ⎦
0 0 0 ... dn−1,n−1
Propose an algorithm that generates a diagonal matrix with random
integers.
Arrays 141
19. A triangular matrix has 0s either above or below the main diagonal.
If the triangular matrix has all the elements below the main diagonal
equal to zero the matrix is called upper triangular. Similarly, the matrix
is called lower triangular if the elements above the main diagonal are
equal to zero. An upper triangular matrix is of the form:
⎡ ⎤
a0,0 a0,1 a0,2 ... a0,n−1
⎢ 0 a1,1 a1,2 ... a1,n−1 ⎥
⎢ ⎥
⎢ ⎥
U =⎢ 0 0 a2,2 ... a2,n−1 ⎥
⎢ .. ⎥
⎣ . ⎦
0 0 0 ... am−1,n−1
20. The trace of an array is given by the sum of the elements of the main
diagonal. The elements of the main diagonal have equal indices; that is,
they are of the form.
A[k][k]
n-1
A= A[k][k]
k=0
5.1 Introduction
So far in the book, small scripts o programs have been developed. In real life, a
program can have thousands of lines of code. In such scripts, it might be pos-
sible to repeat code in different parts. By grouping that code in subprograms,
and when needed just call these subprograms, a great deal of coding could be
saved, making the program shorter and easier to understand and debug. In
other cases, the script is too long and it may be partitioned into smaller sub-
programs to make it easier to understand and maintain. In a larger program,
often referred to as the main program, a subprogram is called by the main
program. In this chapter, techniques to develop subprograms are described.
Several examples using subprograms are presented in the chapter. Also pre-
sented is the concept of recursion which is the case when a subprogram is used
by itself.
5.2 Subprograms
A subprogram is a part of a larger program or script. They may also have
inputs and outputs. A subprogram is usually called a function. Examples of
functions available in Python are the trigonometric functions, the square root,
the functions available in numpy, math, etc.
There are two types of subprograms, namely, procedures and functions.
Procedures are subprograms that have inputs but that do not provide an out-
put. Rather they execute some tasks, for example, print out data. Functions
instead receive input data and provide output data to be used in other func-
tions or in the main program. Some programmers and authors refer to pro-
cedures and functions as simply functions. In object-oriented programming,
functions are called methods and they belong to a class. Thus, they may be
referred to as either functions or methods.
def function_name(parameters):
body of the function
return output_data
The keyword def indicates that a function is defined in the following instruc-
tions which form the body of the function. In the case of procedures, there
is not a return statement. This is used to return to the main program the
variables of interest. As an example, if a function is to obtain the sum of the
first N integers, that function can be:
def adder(N):
sum = N*(N+1)/2
return sum
The function adder receives from the main program the value of N, and the
function returns the sum. This is received by the main program for whatever
is needed.
Functions must be defined before using them in another function or in
the main program. If this is not done an error is produced. There are some
guidelines that must be followed to write functions:
• The name of the function is unique and it cannot be used by any other
function or variable.
• The variables between the parenthesis after the function name are called
arguments or parameters. The number is usually fixed, but in some cases
is variable (see section 5.9).
• The body of the function must be indented. The first row is not indented
after the body of the function is not part of the function.
144 Python with Optimization, ...
def prime(number):
# Given a positive integer, determine if it is a prime.
prime(number)
The function must be placed before it is called. The script including the
main program and the function is
calculate the square root of the discriminant takes as input the coefficients
of the second-order equation and returns the square root of the discriminant.
This function is:
# Main program
import math
# Enter coefficients.
a = float(input(“Enter the coefficient for x**2: ”))
b = float(input(“Enter the coefficient for x: ”))
c = input(“Enter the independent term coefficient: ”)
def read_coeff( ):
# This function reads the coefficients of a second degree
equation.
The function read_coeff does not receive arguments but it must include the
empty parentheses. It returns to the main program the three coefficients in a
list. The coefficients are passed then from the main program to the function
discriminant_root.
The second function computes the roots x1 and x2:
x1 = (-b + d)/2/a
x2 = (-b - d)/2/a
# Main program
import math
# Read the coefficients:
[a, b, c] = read_coeffs( )
A run for the equation first calls the function read_coeff to obtain the coeffi-
cients, then calls the function to compute the square root of the discriminant,
and finally computes the roots. If the discriminant is zero, then the square
root cannot be computed and the program marks an error. For the equation:
2x2 + 3x − 2 = 0
The roots obtained are:
x1 = -2 and x2 = 0.5.
In the final complete script, the functions must be placed before they are
called. In this example then the function read_coeff is the first one followed
by the functions discriminant_root and compute. Finally, the main program
is the last one in the final script.
5.4 Recursion
Functions defined so far are executed in the order they are called. In some
other cases, it is convenient to use a technique known as recursion. In this
technique, a function calls itself; that is, within the function, there is a call to
itself. Such functions are called recursive functions.
As with any technique, there are advantages and disadvantages in using
recursion. Some advantages are:
def factorial_Rec(n):
fact = 1 # Initialize factorial variable to unity.
if (n > 1):
fact = n*factorial_Rec(n - 1) # Factorial is computed
# recursively.
else:
fact = 1
return fact # Returns the variable fact.
fact = n*factorial_Rec(n - 1)
A run with n = 6 is
>>> factorial_Rec(6)
720
For example, for the discriminant function, the lambda form expression is:
import math
d = lambda a1, b1, c1: math.sqrt(b1**2 - 4*a1*c1)
print(‘The square root of the discriminant is:’, d(1,9, 20))
a = 23
print(‘Outside the function a = ’, a)
def test(a):
a = 27
print(‘Inside the function: a = ’, a)
print(‘Outside the function: a = ’, a)
The result is
The first print occurs outside the function and the value of a is 23, then the
function, is called and the variable a is defined and printed and the result
is 27. Finally, the last print is outside the function and the value is 23. The
reference to the variable a outside the function is different from the variable
a inside the function. For the main program, there is no change in the value
of a.
In the case of a list is the same unless the list is somewhat modified by,
for example, adding or deleting elements. For example,
Functions 151
a = [23, 32]
print(‘Outside the function a = ’, a)
def test(a):
print(‘Inside the function: a = ’, a)
a.append(54)
print(‘Inside the function: a = ’, a)
test(a)
print(‘Outside the function: a = ’, a)
The result is
The value is modified inside the function but here is referenced to the list
defined before calling the function and thus it is the same list but modified.
In the last print instruction, the list is already modified.
global name_of_variable
a = 24
print(‘Outside the function: a = ’, a)
def test():
global a
print(‘Inside the function: a = ’, a)
a = 54
print(‘Inside the function: a = ’, a)
152 Python with Optimization, ...
def test2():
global a
print(‘Inside the function test2: a = ’, a)
a = 71
test()
test2()
print(‘Outside the function: a = ’, a)
The variable a is defined as global in the functions test and test2. The
values are modified in the functions and this is seen in the main program
where the last print produces the last value modified in the function test2.
the arguments var1 and var2 always have the same position and when the
function is called, the first value is assigned to var1 and the second value is
assigned to var2. When the function is called as in:
x = function(3, -8)
The values assigned to var1 and var2 are 3 and -8, respectively.
When keyword arguments are used, the call to the function identifies the
arguments by the name, regardless of the position in the function call. For the
example above, the call can be made with a keyword argument if it is made
as either:
or as:
Another variation for keyword arguments is when not all of the variables
are associated with a name. In that case, the position may be important. For
example:
x = function(var2 = -8, 3)
b1 = 5
The result is
# Values of a and b:
a = 6
b = 4
The result of the first call to the function is the addition 6 + 4 because add =
1. In the second call add is not present and the result is the subtraction 6 - 4:
10
2
Functions 155
import random
x = random.random( )
This generates a random number between 0 and 1. Another function for ran-
dom numbers is:
x = random.randint(a, b)
which generates a random integer number between a and b. For example, the
following script generates random integers between 10 and 76:
import random
for k in range(10):
x = random.random( )*(76 - 10) + 10
print(x)
and to obtain 10 integers between 10 and 76, a for loop is used as:
import random
for i in range(10):
x = random.randint(10, 76)
print(x)
For this example, the number has to be between 1 and 6. The script is:
def throw_die( )
from random import randint
number = randint(1, 6)
print( ‘The number is: ’, number)
This function is run as:
>>> throw_die( )
The number is: 5
>>> throw_die()
The number is: 2
The number obtained is always between 1 and 6.
156 Python with Optimization, ...
def fibonacci(m):
# The first two elements:
list_fibo = [0, 1]
# Elements from 3 to m + 1:
for k in range(2, m + 1)
list_fibo.append(f[k - 2] + f[k - 1])
This function produces the first m elements in the Fibonacci series. This func-
tion does not have a return because the print instruction is in the function.
This type of functions are often known as procedures. A run for m = 10 is:
>>> fibonacci(10)
[ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ]
• The second function receives the digits and returns the sum.
• The third function receives the digits and returns their product.
• The fourth and last function compares both results and displays the
result.
The algorithm to obtain the digits is to divide the number by 10 and the im-
portant part is the residue which gives the digits. The residue can be obtained
with the function modulus. For example, for the number 239, dividing by 10
the residue is 9 which is the least significant digit, or the rightmost digit of
Functions 157
the number. This number corresponds to the units. The quotient is 23 which
is divided by 10 again to obtain the residue 3 which is the next digit to the
left. This digit corresponds to the tens and the quotient is 2. This is the last
digit corresponding to the hundreds. This digit is called the most significant
digit. Now that the three digits are obtained the sum is 14 and the product
is 54 and the number 239 does not meet the requirements.
A function that extracts the digits from a given integer number is:
return digits
After finding the digits the next task is to find the sum and the product of
them. To find the sum a for loop is used. The argument for the function is
the list containing the digits. The function to add the digits is:
def addition(list_digits):
# Initialize the sum to 0:
add = 0
# Start the for loop to add the digits:
for k in range(len(list_digits)):
add = add + list_digit[k]
return add
158 Python with Optimization, ...
The function to obtain the product of the digits uses another for loop and it
is:
def multiply(list_digits):
# Initialize the product:
product = 1
# Start the for loop to find the product of the digits:
for k in range(len(list_digits)):
product = product*list_digit[k]
return product
The last function is to compare the product and the sum. If they are equal
then print a message of success. The function is:
def find_digits(number):
# Start the process with a while loop:
# Define an index
digits = [ ]
index = number
while index >= 10
quotient, residue = divmod(index, 10)
index = quotient
digits.append(residue)
digits.append(index)
digits.reverse()
return digits
def addition(list_digits):
add = 0
for k in range(len(list_digits)):
add = add + list_digit[k]
return add
def multiply(list_digits):
product = 1
for k in range(len(list_digits)):
product = product*list_digit[k]
return product
# Main program
# Read in the number
for number in range(0, 1000):
digits = find_digits(number)
add = addition(digits)
product = multiply(digits)
compare(number, add, product)
For the first 1000 integers, the following numbers satisfy the condition: 22,
123, 132, 213, 231.
def read_vertices(i):
# This function reads the vertices coordinates.
# Define the list:
p=[ ]
To compute the distance between two vertex the Euclidean distance formula
is used. For two point P1 = (x1 , y1 ) and P2 = (x2 , y2 ) the distance is given
by:
distance = (x21 − x22 ) + (y12 − y22 )
The coordinates received are a list of strings; thus, they have to be converted
to float type. The function is:
The perimeter is given by the sum of the sides computed with the function
dist and the area is given by the equations:
S = perimeter/2
Area = S(S − L1 )(S − L3 )(S − L3 )
where L1 , L2 , and L3 are the lengths of the triangle sides and S is an inter-
mediate variable. Then the function to calculate the perimeter and the area
is:
5.12 Conclusions
Functions are implementations of subalgorithms. They allow programmers to
partition and simplify a large program which otherwise might be too cum-
bersome to implement. Functions may also be used to contain code that is
repeated several times in a large program. The chapter contains a number of
examples that allow the reader to become proficient in the use of functions.
5.13 Exercises
1. Consider the following Python script. Show and explain the results that
the script produces at each stage:
def mistery(n) :
t = 0
for i in range (1, 4):
m = n * i
Functions 163
print(n, “ X ”, i, “ are ”, m)
t = t + m
return(t)
# Main program.
num = int(input(“Number ”)
print(“The result is: ”, mistery(num))
2. It is desired to write an algorithm to generate multiplication tables. The
script should have a function that reads the integer n which indicates
the desired table. Another function must obtain the corresponding table.
Finally, a last function must print out the table. The table must be
obtained from n×1 up to n×10.
6. Goldback’s conjecture states that any even number is formed by the sum
of two prime numbers. Write a Python script to check the conjecture. It
must comply with the following:
7. The table to find the income tax is shown below. Implement an algo-
rithm that a person must pay. The Python script must consist of a
function that receives the income. Another function must evaluate the
tax amount, and a third function must display both amounts, the income
and the tax amounts.
For example, if a person has a yearly income of 234,000, the tax that
must be paid is:
a = year%19
b = year%4
c = year%7
d = (19 ∗ a + 24)%30
e = (2 ∗ b + 4 ∗ c + 6 ∗ d + 5)%7
(b) The required date is obtained with: march 22 + d + e
Design an algorithm that evaluates this date. The algorithm must read
the year and it must print out the date for Easter Sunday. Given the
fact that the date can correspond to April, consider this fact to print
out the correct date.
Chapter 6
Object-Oriented Programming
6.1 Introduction
This chapter is a brief introduction to Object-Oriented Programming (OOP)
as it is implemented in Python. Although this way of programming is more
associated with languages such as C++ and Java, among others, it has also
been incorporated into Python; thus making it a multiparadigm program-
ming language. A great deal of textbooks have been dedicated to the teaching
of OOP; thus this section only presents the main characteristics of OOP in
Python and gives the specifics to start programming using this paradigm. The
chapter begins by defining the elements of OOP and continues with examples
of how to program in Python emphasizing the OOP.
• object
• attribute
• method
• class and instance
• encapsulation
• inheritance
• polymorphism
behavior will be produced for the type of object that is invoking it. When this
occurs during “runtime”, this feature is called late assignment (late binding)
or dynamic allocation.
class Countries:
#Class methods:
#Constructor
def __init__(self, country, capital):
self.country = country
self.capital = capital
The class is stored in the file classCountries.py. In this class, the attributes
are country and capital. The methods are __init__, which is the construc-
tor where the attributes are defined and initialized, and output which prints
out the result. The word self refers to the object created in the instantiation.
Thus, when the methods appear self.country and self.capital, they refer
to the attributes country and capital of the object or instance of the class.
An example run is as follows:
The objects are a, b, and c and they are instances of the class Countries.
The information for any instance can be printed out with:
>>> a.output()
The capital of France is Paris
168 Python with Optimization, ...
class MyFraction1:
# This class obtains the ratio of two numbers.
#Class methods
# Constructor
def __init__(self, numerator, denominator):
self.numerator = numerator
if denominator == 0:
print(‘The denominator must be different from 0.’)
else:
self.denominator = denominator
If this class is now used to obtain the fraction, we have to create the object
invoking an instance of the class MyFraction1 as follows:
>>> a = MyFraction1(2, 3)
>>> a.result()
result = 0.6666666666666666
>>> a.numerator = 1
To avoid this modification of the attributes from outside the class, encap-
sulation can be used. To modify the contents, methods called setters can be
added to set the values of the numerator and denominator. This is done with
the following methods:
class MyFraction2:
# This class obtains the ratio of two numbers.
# It includes setters.
#Class methods
# Constructor
def __init__(self, numerator, denominator):
self.numerator = numerator
if denominator == 0:
print(‘The denominator must be different from 0.’)
else:
self.denominator = denominator
# Setters
def setNumerator(self, numerator):
self.numerator = numerator
def setDenominator(self, denominator):
if denominator == 0:
print(‘The denominator must be different from 0.’)
else:
self.denominator = denominator
>>> a = MyFraction2(2, 3)
>>> a.setNumerator(7)
>>> a.denominator = 21
>>> a.result()
0.3333333333333333
0.25
Object b is another instance of the class MyFraction2 and the values of its
properties are different and independent of those belonging to object a.
The getters are methods to retrieve an attribute. Getters for this class can
be as simple as:
# Getters
def getNumerator(self):
return self.numerator
def getDenominator(self):
return self.denominator
Once the getters are inserted into the class MyFraction2 they can be used as:
>>> a.getDenominator()
>>> a.getNumerator()
and the result is the numerator and denominator for the values defined for
the object a.
The class MyFraction2 can be improved by printing out the result as a frac-
tion as, for example, 2/3. This can be done by adding an additional print
instruction in the method DisplayResult as
7/21 → 1/3
This method can be added to the class as a static method simply adding the
decorator @staticmethod on top of the method. A static method is a method
bounded to the class and not to the objects. It can modify a class attribute or
parameter. This method can be called each time an attribute is read. Thus,
it has to be called from the constructor and from the setter. The new class is
renamed MyFraction3 as:
class MyFraction3:
# This class obtains the ratio of two numbers.
# It displays the fraction using the GCD.
#Class methods
# Constructor
def __init__(self, numerator, denominator):
self.numerator = numerator
if denominator == 0:
print(‘The denominator must be different from 0.’)
else:
self.denominator = denominator
(self.numerator, self.denominator) = \
MyFraction3.reduce(self.numerator, self.denominator)
# Setters
def setNumerator(self, numerator):
self.numerator = numerator
(self.numerator, self.denominator) = \
MyFraction3.reduce(self.numerator, self.denominator)
def getDenominator(self):
return self.denominator
@staticmethod
def reduce(num, denom):
import numpy as np
6.3.4 Encapsulation
Encapsulation is a fundamental concept in OOP. Encapsulation of a class is
the packing of data and methods that restrict or protect them from access by
external methods. Such encapsulated methods or attributes are called private.
To accomplish this in Python, a protected name attribute or method has to
be prefixed by a single underscore. For example, in the class MyFraction, the
numerator can be made private just by prefixing it with an underscore, as in:
class MyFraction4:
# This class obtains the ratio of two numbers.
# It displays the fraction using the GCD.
#Class methods
# Constructor
def __init__(self, numerator, denominator):
self._numerator = numerator
if denominator == 0:
print(‘The denominator must be different from 0.’)
else:
self.denominator = denominator
(self._numerator, self.denominator) = \
MyFraction4.reduce(self._numerator, self.denominator)
# Setters
def setNumerator(self, numerator):
self._numerator = numerator
(self._numerator, self.denominator) = \
MyFraction4.reduce(self._numerator, self.denominator)
@staticmethod
def reduce(num, denom):
import numpy as np
>>> b = MyFraction4(2, 3)
>>> b.result()
result = 0.6666666666666666
Fraction = 2 / 3
>>> b.numerator(8)
Traceback (most recent call last):
File “<pyshell#56>”, line 1, in <module>
b.numerator(8)
AttributeError: ‘MyFraction4’ object has no attribute ‘numerator’
176 Python with Optimization, ...
>>> b.setNumerator(8)
>>> b.result()
result = 2.6666666666666665
Fraction = 8 / 3
6.3.5 Inheritance
The properties of classes can be inherited from existing classes. Thus, the
class that inherits is called a subclass or a child class. A top-level class is
sometimes called a superclass or a parent class. Each subclass can alter the
properties which were inherited and add also their own. A subclass inherits
all data and behavior of the parent class. It can also add more attributes and
more methods of its own.
In the last definition of the class of the example, the class MyFraction is
a superclass for any subclass defined from it.
class Reciprocal(MyFraction):
super().__init__(num, denom)
Finally, the method from the parent class used in the subclass is the method
result which is prefixed with the word self, and is included in the construc-
tor as
self.result()
Object-Oriented Programming 177
class Reciprocal(MyFraction):
class MyFraction5:
# This class obtains the ratio of two numbers.
# It displays the fraction using the GCD.
# Class methods
# Constructor
def __init__(self, numerator, denominator):
self._numerator = numerator
if denominator == 0:
print(‘The denominator must be different from 0.’)
else:
self.denominator = denominator
(self._numerator, self.denominator) = \
MyFraction5.reduce(self._numerator, self.denominator)
# Setters
def setNumerator(self, numerator):
self._numerator = numerator
(self._numerator, self.denominator) = \
MyFraction5.reduce(self._numerator, self.denominator)
@staticmethod
def reduce(num, denom):
import numpy as np
class Reciprocal(MyFraction5):
>>> c = Reciprocal(2,3)
result = 1.5
Fraction = 3 / 2
6.3.6 Overloading
Overloading is the mechanism that allows a method to accept different types
of arguments and to have an already existing name. When trying to add two
objects a and b
Object-Oriented Programming 179
>>> a = MyFraction5(3, 7)
>>> b = MyFraction5(2, 5)
>>> a + b
Traceback (most recent call last):
File “<pyshell#98>”, line 1, in <module>
a + b
TypeError: unsupported operand type(s) for +: ‘MyFraction5’
and ‘MyFraction5’
Python reports an error because the addition of this type of object has not
been defined. Recall that for the basic arithmetic operations of addition (+),
subtraction (-), multiplication (*) and division (/), Python establishes the
equivalence with the following methods: add, sub, mul and truediv, for the
addition, subtraction, multiplication, and division, respectively. The addition
of two fractions is given by
where num and denom represent the numerator and denominator of each frac-
tion. The method __add__ is overloaded as
The parameters for the addition of two fractions are the objects previously
defined.
The resulting fraction is sent to the method reduce to simplify the fraction:
The resulting numerator and denominator are sent to the method result to
display the resulting fraction:
self.result()
180 Python with Optimization, ...
In the same way, a method can be implemented for the subtraction of the two
fractions by rewriting the plus sign in the numerator sub, which will change
the fraction:
class MyFraction6:
# This class obtains the ratio of two numbers.
# It displays the fraction using the GCD.
# Class methods
# Constructor
def __init__(self, numerator, denominator):
self._numerator = numerator
if denominator == 0:
print(‘The denominator must be different from 0.’)
else:
self.denominator = denominator
(self._numerator, self.denominator) = \
MyFraction6.reduce(self._numerator, self.denominator)
# Setters
def setNumerator(self, numerator):
self._numerator = numerator
(self._numerator, self.denominator) = \
MyFraction6.reduce(self._numerator, self.denominator)
def setDenominator(self, denominator):
if denominator == 0:
print(‘The denominator must be different from 0.’)
else:
self.denominator = denominator
(self._numerator, self.denominator) = \
MyFraction6.reduce(self._numerator, self.denominator)
@staticmethod
def reduce(num, denom):
import numpy as np
# Evaluate greatest common divisor:
mygcd = np.gcd(np.abs(num), np.abs(denom))
# Numbers are reduced:
return (num/mygcd, denom/mygcd)
class Reciprocal(MyFraction6):
>>> a + b
result = 0.39285714285714285
Fraction = 11 / 28
Thus, it is observed that the result is correct. Testing for the subtraction:
>>> a - b
result = -0.10714285714285714
Fraction = -3 / 28
as expected.
6.4 Example
In this section, an example of classes is shown that illustrates the main features
of Python for applying the object-oriented paradigm.
Let us begin with the declaration of the class called Bank_Account whose
basic structure is shown in the following Script:
class Bank_Account:
# It creates and manages bank accounts.
Class methods
The first method is the constructor that must bear the same name as the class
which will create the account and assign a value to the opening balance. Each
object account will then be an object or an instance of the class BankAccount.
The constructor must read the account name and the value to be assigned to
the opening balance. An appropriate constructor is:
# Constructor
def __init__(self, balance):
self.balance = balance):
A method to print the account balance is given the name output and is defined
by
def output(self):
print(“This account has $ ”, self.balance)
# Constructor
def __init__(self, balance):
self.balance = balance):
self.output()
Now the methods to deposit and withdraw are written. In the first case, it is
an addition of the amount received to the previous balance, and in the second
case, it is subtracted. Also for consideration is the case where the withdrawal is
greater than the balance. In both methods, the account represents an instance
of the class BankAccount to modify and the amount represents the amount to
add or subtract from the balance of the account. For the deposit, the method
to define is:
class Bank_Account:
# It creates and manages bank accounts.
Class methods
# Constructor
def __init__(self, balance):
self.balance = balance):
self.output()
def output(self):
print(‘This account has $ ’, self.balance)
>>> Peter.deposit(8)
This account has $20.00
>>> Peter.withdrawal(14);
This account has $6.00
>>> Peter.withdrawal(8)
Not enough funds in the account.
6.6 Conclusions
In this chapter, an introduction to using Python to write programs using the
paradigm of Object-Oriented Programming was given. Only the most basic
definitions have been explored since the topic is quite large and is beyond the
aims of this book and chapter. The interested reader can consult the references
for a greater knowledge of the subject. However, with this chapter, it is already
possible to create classes of OOP in Python.
6.7 Exercises
1. It is known that the Earth’s gravity is 6 times larger than the Moon’s
gravity. Write a class to convert the weight on Earth to that on the
Moon.
186 Python with Optimization, ...
2. Write a class for the conversion from Celsius degrees to Fahrenheit and
vice versa.
3. Write the methods for multiplication and division for the class
MyFraction6.
4. Write a class with the name Cards. Assume that there are 52 cards in
the deck. Each hand has five cards given to three players. Use random
methods to give the hands and to find out which player is the winner.
5. Write a class to make the four basic operations with complex numbers.
6. Given a list of integer numbers, write a class to perform the following
functions on the list:
[3] A. Downey, Think Python: How to Think Like a Computer Scientist, 2nd
Ed., O’Reilly Media, 2016.
Chapter 7
Reading and Writing to Files
7.1 Introduction
So far, input data has been entered through the keyboard and the output has
been displayed on the screen. Data can also be stored in a file so it can be read
from this file and the output written either to the same file or to a different
one. In this chapter, the different ways to read from and write data to a file
are presented. Data is stored in files as bits (binary digits) that can have the
value of 0’s and 1’s. Bits are grouped in bytes, which are collections of eight
bits. There are mainly two types of files, namely, text files and data files. Text
files consist of sequences of alphanumeric and other special symbols and they
are human readable. Examples of text files are word documents. On the other
hand, binary files such as executable files, images, videos, and compressed
files, among others, are not human readable. In this chapter, it is shown how
to store data in both, text and binary files.
The variable mode has the following options shown in Table 7.1.
handle.write( ‘phrase’ )
where phrase is the information that is desired to write. After finishing the
writing process, the file has to be closed with:
handle.close( )
The kind of animals are: cats, dogs, birds. To write each name in a newline
an escape “\n” is inserted between the names. The instruction to write is
then:
Reading and Writing to Files 189
handle.write(“cats \n”)
handle.write(“dogs \n”)
handle.write(“birds \n”)
handle.close( )
After running and opening the file animals.txt with a text editor
animals.txt the contents can be seen. The instruction write DOES NOT
generate a newline automatically and, therefore, an escape sequence is in-
cluded.
The writelines instruction is used to write all the lines in the file (in this
example only a single line is available):
handle.writelines([“cats \n”, “dogs \n”, “birds \n”])
handle.close( )
190 Python with Optimization, ...
handle.write( “ phrase” )
The first line ends with a semicolon and the following lines have to be indented,
as it was the case for conditions and loops. When the with block ends the file
is closed.
The file is closed when the with statement ends. The country names appear
in a column in the file teams.txt. In the script the explicit continuation line
“\” is used to join the two lines that form the list of countries.
Brazil 5
Germany 4
Italy 4
Argentina 2
France 2
Uruguay 2
England 1
Spain 1
The instruction write can also be used to store numeric data with a for-
mat. For example, for the variable a = 3.2316 the instruction is:
file.write(“%s” %a)
The data is defined as pennant = 3 and the name of the team and the numer-
ical data can be written as
handle.close( )
In this case, the team name, a tab, and the number of pennants are written
to the file.
The techniques presented so far can be used to create an array of data. In
the following example, it is shown how to create this array or table.
The table has five rows and three columns. For Python this is an array or
matrix and the name given is dataTable:
The script to write this table to the file Table.dat starts with the creation of
the file Table.dat:
Two nested loops are used to write each row, column by column, each and
every element to the file Table.dat:
The instruction write can only have strings as arguments. Therefore, each
element in the table has to be converted to a string with str(column). It is
convenient to add as a separator a couple of tabs ‘\t’. The resulting string is
named string1 and formed and written to the file with
This finishes the nested for loop. Continuing with the for loop for rows, it is
necessary to add an end of line with the escape sequence ‘\n’
handle.write(“\n”)
handle.close( )
handle.close( )
When the file Table.dat is open with the WordPad, the contents are:
Then, the data is read according to the data format. This is shown with several
cases.
10.4
23.7
-34.8
496.17
17.28
-23.54
The first step is to open the file for reading. The handle is now my_file:
Next, the actual data is read each row at a time, each row contains a string
that has to be converted to an integer. To sum up the integers, first initialize
the sum to zero, then add up each number as is read. A count of the integers
Reading and Writing to Files 195
read is needed to take the average. The sum is 130 and the total number of
elements is 6. Thus, the average is 21.6666666666. The last step is to close the
file. First, the sum and the number of elements read are initialized to 0 .
sum = 0
count = 0
Then, the elements are read with a for loop:
The elements read from a file are strings and they have to be converted to
floating-point numbers and then added to the sum. The counter count that
counts the number of rows read has to be incremented by 1:
Finally, the loop is exited and the sum is divided by count to obtain the
average which is also printed with two decimal digits:
average = sum/count
print(‘The average of the sum is %0.2f’ %average)
my_file.close( )
Jan 13.8
Feb 15.2
Mar 17.4
Apr 21.4
May 24.7
Jun 27.3
Jul 27.9
Aug 27.9
Sep 26.3
Oct 23.7
Nov 17.1
Dec 15
It is desired to read the data from the file and display it. The information can
be represented as a dictionary. The month corresponds to the key and the
temperature to the value. After opening the file, each row is read and the
key and value are separated with row.split. A for loop is used. The Python
script starts by opening the file for reading:
sumT = 0
for row in f:
f.read(row)
data = row.split( )
The first part is the month and the second one is the temperature:
month = data[0]
temperature = data[-1]
Reading and Writing to Files 197
The temperature just read is converted to a floating number and added to the
accumulated sum:
sumT += float(temperature)
averageT = sumT/12
print(‘The average temperature is ’, averageT)
f.close( )
handle.readline(n)
The parameter n indicates how many characters in the line are read. If n is
not given, the entire line is read.
198 Python with Optimization, ...
The result is
a = Brazi
b = l 5
c = Germany 4
The first readline instruction only reads the first 5 characters in the first row.
The second readline reads the remaining characters in the first row including
the end of the line and the escape sequence “\n” which leaves an empty row.
The third readline reads also the complete line because the third row only
has seven characters. There is an empty row because of the escape sequence
in the row.
1. Import the library csv to be able to open the files with the extension
csv. The instruction is:
import csv
200 Python with Optimization, ...
3. Initialize the list where each row of the data is to be stored. The list is
given the name DataList:
DataList = [ ]
4. With a for loop the rows are read. Each row is added to the list using
the instruction append:
handle.close( )
Reading and Writing to Files 201
6. Note that the data is a list of lists; that is, a table. To display this table,
the instruction pprint whose meaning is pretty print, is used. The
instruction pprint is available in the library pprint and thus it has to
be imported before using it. The set of instructions is:
import pprint
pprint.pprint(DataList)
Now the sum of the quantities for each year is done. In the file, the first row
is row No. 0, and it has the names of the products. For rows 1 to 6, the first
column is the year; thus, the quantities for each product are in columns 1 to
4, and rows 1 to 6. The addition is to be written to a list that is initialized to
0. Then, the steps are:
1. Initialize the row with the averages to 0 and the first element of row as
‘Averages’. This is done with:
row = [0.0]*len(DataList[0])
row[0] = ‘Averages’
2. The sum of the columns is made with two nested for loops. The first for
loop selects a column and the nested for loop adds the elements in the
202 Python with Optimization, ...
column. Before the nested for loop the sum is initialized to 0. Before
adding, the numbers have to be converted to floating point numbers.
Recall that after read in the data from the Excel file, they are strings.
3. Create and open the file ‘yearlyAverage.csv’ for writing the data.
handle2 = open(‘yearlyAverage.csv’, ‘w’)
4. Write the elements of the first row, DataList[0], which contains the
names of the products. Each product name is separated by a comma. A
for loop is used as:
6. The average values are stored in the list row. The numerical values have
to be converted to strings in order to be written to the Excel file. Also
a comma has to be added. A for loop is used as:
for k in range(len(row)):
handle2.write(str(row[k]))
handle2.write(‘,’)
handle2.close()
Reading and Writing to Files 203
for k in range(len(row)):
handle2.write(str(row[k]))
handle2.write(‘,’)
handle2.close()
The results are shown in Figure 7.2.
204 Python with Optimization, ...
TABLE 7.2: Modes to handle binary files
Mode Description
‘rb’ Opens the file for read only.
If the file does not exist, an error is indicated.
‘wb’ Creates and opens the file to write.
If the file exists, it deletes the existing data.
‘ab’ Opens the file to write. If the file exists, it appends
the new data at the end of the existing data.
‘rb+’ Opens the file to read and write. If the file
does not exist, an error message is displayed.
‘wb+’ Creates and opens the file to write and read.
If the file exists, the existing data is deleted.
‘ab+’ Opens the file to read, write, and append. If the file
does not exist, an error message is displayed.
pickle.dump(data, handle)
B = 27
C = ‘Python’
The data for the array could be either a list of lists or a numpy array. This
data is entered as:
First, the pickle module is imported the file binary3.dat is created and
opened for writing binary data :
import pickle
id_binary = open(‘binary3.dat’, ‘wb’)
To write the data in binary format the instruction dump from the library
pickle is used. The data is an array, a list, an integer number, and a string.
The data for the array could be either a list of lists or a numpy array.
pickle.dump(A, id_binary)
pickle.dump(b, id_binary)
pickle.dump(B, id_binary)
pickle.dump(C, id_binary)
id_binary.close()
# File is closed.
id_binary.close()
208 Python with Optimization, ...
Figure 7.4 shows the data stored in binary format and open with Windows
WordPad. This is because the data is written in binary format and not in
ASCII code. To read the data, first the file is opened:
To read the data in binary format the pickle.load instruction is used. Thus,
the module pickle has to be imported. Data must be read in the same order
and with the same format that it was written. The first few lines in the file
must be:
id_bin.close()
Reading and Writing to Files 209
7.8 Conclusions
This chapter has covered the way to store and retrieve data in a file. The
data file may be created using another programming language. The different
techniques are presented by using several examples. In addition, the way to
retrieve and store data in Excel files is also covered.
210 Python with Optimization, ...
TABLE 7.3: Python instructions in Chapter 7
Instruction Description
close It closes a file.
csv.reader It reads csv files.
csv.writer It writes csv files.
import csv It imports the library csv.
import pprint It imports the library pprint.
open It opens a file for reading or writing.
pprint It prints tables.
with It opens files and closes them when it finishes.
write It writes in a file.
writerow It writes a whole row in a file.
writelines It writes several rows to a file.
7.9 Exercises
1. Generate a list of ten integer random numbers between 1 and 100. Then,
store them in a file with the name randomIntegers.dat. When finished,
open the file with a word processor to check the data stored.
2. Create a file with the names of South American countries and their
capital cities. The data must be previously stored in a dictionary. Then
read the dictionary and store the data in a file countries.dat. Check
your result in a word processor.
8.1 Introduction
An important characteristic of any program is its ability for data visualization.
This allows to see how data is behaving. For example, the behavior of the
stock market can be better appreciated with a plot. Plotting trigonometric
functions allows users to see that they are periodic functions. Programs written
in Python can take advantage of data visualization thanks to John D. Hunter
(1968-2012) who designed the module or library matplotlib. This module
is freely available and produces very high-quality two and three-dimensional
plots. Instructions for downloading matplotlib are available in the Appendix
A. The examples presented in this chapter cover many of the typical plots
used in academia and industry. For more examples, the reader can consult the
matplotlib page: https://matplotlib.org/stable/gallery/index.html.
import numpy as np
x = np.linspace(-2*np.pi, 2*np.pi, 100)
The list starts at the initial value of −2π, ends at the final value +2π and has
100 points. The sin(x) function is imported from numpy and the y values are
generated with a process called vectorization which consists of parallel com-
puting methods used to perform repetitive instructions into a single vector.
Thus, for example, given a vector x, the sine function for each of the elements
of vector x can be stored in vector y and computed as
y = np.sin(x)
y = np.sin(x)
The functions needed to obtain a plot are plot(x, y) where x and y are
the independent and dependent lists, respectively. Additionally, to display the
plot the function show has to be included after the plot instruction. Then, to
obtain the plot we have to write:
The resulting plot is shown in Figure 8.1. In this plot the sine wave is called
the trace. This plot is produced with 100 points for x and the number of points
determines its definition. Sometimes, it may be desirable to have more points
and thus obtain a higher definition plot.
The previous plot can be improved by adding a title, a grid, ticks, a
label, and a legend.
The limits for the x-axis go from -7 to +7 and for the y-axis from -1.5 to +1.5
as
xlim(-7, 7)
ylim(-1.5, 1.5)
grid()
For a legend located at the upper left side, it is required to have an instruction
label inside the plot function as
Figure 8.2 shows the resulting plot which is a better one as compared to Figure
8.1.
y1 = sin(x)
y2 = exp(x)
y3 = x**2
216 Python with Optimization, ...
These functions have to be imported before they can be used. The plotting is
done with
plt.grid()
plt.show()
The plot produced is shown in Figure 8.3. In this plot each trace is drawn in a
different color, the first color corresponding to y1 is blue, the second function
y2 is red, and the last one is green. A similar plot can be obtained by replac-
ing the instruction plt.plot(x, y1, x, y2, x, y3) with three instructions
plot as
plt.plot(x, y1)
plt.plot(x, y2)
plt.plot(x, y3)
218 Python with Optimization, ...
TABLE 8.1: Color palette for
the trace
Symbol Color
b blue
g green
r red
c cyan
m magenta
y yellow
k black
w white
The result is similar to Figure 8.3 but with different colors for the traces.
Alternatively, the word color and the equal sign can be omitted.
A trace marker and a trace style can be also added. The options are shown
in Tables 8.2 and 8.3.
220 Python with Optimization, ...
TABLE 8.3: Trace style
Symbol Description
- solid line
– discontinuous line
-. dash and point
: points
make the figure aesthetically more pleasant to look at. Some basic parameters
for the plot are available in the function set_theme in the package seaborn.
This function contains several parameters that make plots more appealing to
see, for example, to give a color to the background, to include a grid, among
other parameters. An example illustrates this.
The rest of the script remains the same, except for the grid function which
is not needed. The final script is:
sns.set_theme()
r= x2 + y 2 (8.1)
y
θ = tan−1 (8.2)
x
Example 8.7 A polar plot
For the function in polar coordinates
r = 1 + cos(4θ)
the plot for 0 < θ < 2π can be generated with
The polar plot is shown in Figure 8.7. There it can be seen the values for θ
from 0 to 2π and the values for r from 0 to 2.00. Now it is desired to plot the
polar function
r = sin(4θ)
that can be plotted with:
The polar plot produced is shown in Figure 8.8. There it can be seen the
values for r go from −1 to +1. But it is known that r should be greater than
1. A negative value for r indicates that θ increases by π radians. Then, the
value has to be corrected by adding π radians to the angle for those values
where r < 0. Then, before plotting the following for loop is added:
Plotting in Python 227
The resulting plot is shown in Figure 8.9. It can be seen that the values for r
are positive.
explode = [0, 0.1, 0, 0.3]. Finally, the angle for the first slice separation
can be specified as startangle = value in degrees
FIGURE 8.10: Pie chart for a = [8, 44, 16, 32, 20].
The pie chart produced is shown in Figure 8.10. It can be seen that the slice
for bananas stars at 90◦ , there is a shadow, the fruit names are displayed,
the percentages are displayed with two decimal digits, and the second slice
corresponding to pears is exploded.
where N is the number of data samples in each bin, bins is the total number
of bins, and patches is an object that gives access to the properties of each
bin.
The colors of the bins may be changed and the color selected depending upon
the bin size. To do this first determine the fraction of data corresponding to
each bin with
fracs = N/N.max()
The resulting plot is shown in Figure 8.11. There it can be seen that the
central bins are colored yellow and the outer bins are purple.
Another way to generate histogram plots is with seaborn. The function
displot plots histograms and can smooth the histogram plot with the kernel
density distribution (kde). The following script plots the normal distribution:
232 Python with Optimization, ...
The x-values are generated with linspace and then the y-values are generated
by vectorizing as:
The stem plot is generated with linefmt = ‘:’ and markerfmt = ‘x’. Finally,
the plot is displayed with A show():
The resulting plot is shown in Figure 8.14. There it can be seen that the
vertical lines are dotted and the marker is a cross.
where x, y are the coordinates, s is the size, c specify the color, marker is
the shape, alpha with a value between either 0 for a transparent or 1 for an
opaque marker, and parameters specify other parameters for the data points.
The parameters just mentioned are given for each point in the plot and thus,
they can be numpy arrays. An example is now shown.
N = 20
x = np.random.rand(N)
y = np.random.rand(N)
236 Python with Optimization, ...
N = 20
x = np.random.rand(N)
y = np.random.rand(N)
The resulting plot is shown in Figure 8.15. Now, more parameters can be
included; for example, if the line for the scatter plot is replaced by:
colors = np.arange(N)
alpha = 0.7
s1 = abs(np.random.rand(N))
plt.scatter(x, y, s = s1, c = colors, alpha = 0.7, marker = ‘x’)
Plotting in Python 237
The result is shown in Figure 8.16 where the different colors, opacity, and size
of the markers can be noted.
Then, generating the x-values with linspace and the functions sin(x) and
cos(x) are evaluated by vectorizing:
figure(5)
plot(x, y, label = ‘sine’)
legend(loc = ‘upper left’)
figure(10)
plot(x, z, label = ‘cosine’)
legend(loc = ‘upper right’)
show()
figure(10)
plot(x, z, label = ‘cosine’)
legend(loc = ‘upper right’)
The resulting plot is shown in Figure 8.17. It can be seen that there are two
windows with names Figure 5 and Figure 10.
8.6.2 Subplots
A difference from the previous way to plot two or more figures is the use of
subplots. In this case, two or more plots are fitted in a single figure window
and the instruction subplot, imported from matplotlib.pyplot, is used. The
subfigures are placed using an array style, for example, if there are four plots
they can be placed in two rows, two plots by row. Then, it is said that the
arrangement is 2 by 2 and a third number gives the position of the subplot in
the arrangement. For the subplot(2, 2, 3), the plot is placed in the second
row on the left. The subplot(2, 2, 2) places the plot in the first row to the
right which corresponds to the second position. The format for the instruction
subplot is:
subplot(m, n, k)
where m and n are the number of rows and columns, respectively, and k is the
position in the array from left to right and from top to bottom.
The subplots are indicated and the functions are plotted with a legend and a
grid:
show()
Plotting in Python 241
axes(projection = ‘3d’)
Plotting in Python 243
z=r
x = r ∗ sin(θ)
y = r ∗ cos(θ)
X = arange(-5, 5, 0.25)
Y = arange(-5, 5, 0.25)
X, Y = meshgrid(X, Y)
244 Python with Optimization, ...
The arange and meshgrid instructions must be imported from numpy. The
meshgrid instruction creates the values for the points X, Y where the desired
function is going to be evaluated. For this example, the function to be plotted
is
f ( X, Y) = sin(X2 + Y2 )
The Python instruction is
Z = np.sin(np.sqrt(X**2 + Y**2))
ax.plot_surface(X, Y, Z)
The plot can be colored with a color map using the instruction cmap inside the
plot_surface instruction. A list of the options available for the color map
is available at https://matplotlib.org/stable/tutorials/colors/colormaps.html.
For this example, the color map ‘gist_rainbow’ is used. In addition, to im-
prove the image sampling the parameter antialiased is set to False. The
instruction plot_surface is then:
Plotting in Python 245
There are two parameters that improve the final plot. They are the step size in
each direction. The parameters are rstride and cstride. The default value is
10, but an improvement in the plot can be achieved by setting them to a lower
value, for example, setting both of them to unity. Then the plot_surface
instruction is
The resulting three-dimensional plot is shown in Figure 8.20. The plot can
have added a color bar before displaying the plot, the instruction to plot the
color bar is
The surface plot now with the color bar added is shown in Figure 8.21.
The surface plot can be observed from different points of view by simply
placing the pointer over the plot, pressing the left button and dragging the
246 Python with Optimization, ...
pointer. This allows the observation of the plot from where it is desired to be
seen.
quiver([x, y], u, v)
−y
Bx =
x2 + y 2
x
By = 2
x + y2
In the following file, these equations are evaluated and the field is as shown
in Figure 8.23.
FIGURE 8.23: Quiver plot for the magnetic field around a wire. The current
goes out of the page.
# Axes limits
dx = (xmax - xmin)/(NX - 1.)
dy = (ymax - ymin)/(NY - 1.)
axis([xmin - dx, xmax + dx, ymin - dy, ymax + dy])
title(‘Magnetic field due to a current on a wire.’)
xlabel(‘x (cm)’)
ylabel(‘y (cm)’)
The magnetic field is shown in Figure 8.23. It can be seen that the magnetic
field decreases in magnitude as the distance from the wire, which is located
in the center of the plot, increases. Also, since the current through the wire is
pointing outwards, the vector field follows the right-hand rule.
for values of X, Y in the range −3π and 3π, a surface plot can be obtained
with
import numpy as np
# import matplotlib.ticker as ticker
import matplotlib.pyplot as plt
# Define the surface:
delta = 0.25
edge1 = np.pi*6
x = np.arange(-edge1, edge1, delta)
y = np.arange(-edge1, edge1, delta)
X, Y = np.meshgrid(x, y)
Z = np.sin(X/3) + np.cos(Y/4)
The surface plot is shown in Figure 8.24. The surface was plotted with a color
map ‘binary’ where the lowest values are very clear and the highest values
are darker. Now, a contour plot for this surface plot is obtained by replacing
the instructions
Plotting in Python 251
import numpy as np
import matplotlib.pyplot as plt
The contour plot is shown in Figure 8.25. The light gray lines correspond to
lower values of the function and the darker levels correspond to high values.
The clabel instruction adds values to the contours.
The next plot adds a contour plot to the surface plot. The instructions
that have to be added to the surface plot script are (after the surface plot
instruction and before the show() instruction):
import numpy as np
import matplotlib.pyplot as plt
# Define the surface
delta = 0.25
edge1 = np.pi*6
x = np.arange(-edge1, edge1, delta)
y = np.arange(-edge1, edge1, delta)
X, Y = np.meshgrid(x, y)
Z = np.sin(X/3) + np.cos(Y/4)
The surface plot with a contour is shown in Figure 8.26. In this case the
contour plot does not display values for each contour.
254 Python with Optimization, ...
8.9 Conclusions
This chapter has presented the different ways to visualize data in Python. This
is one of the most important characteristics of this programming language.
Different types of plots were described and examples were given. The libraries
used were matplotlib, pyplot, seaborn, and azw. For more information on
the pyplot parameters please go the the pyplot web site [1].
8.10 Exercises
1. Plot the points y = [2, -2, 3, 8, 9, 0, 1] using the method plot.
2. Plot the points given by the dictionary {1:1, 2:1, 3:5, 4:9, 5:-10}.
The keys are the x-coordinates and the values are the y-coordinates.
3. Plot the trigonometric function cos(x) from −2π a +2π. Use linspace
with 100 points.
4. Repeat the previous exercise using only 10 points. Compare the results.
256 Python with Optimization, ...
12. Obtain the pie plot for the list [23, 45, 17, 15].
13. Obtain the stem plot for the list [0.3, 4.2, -1, 0, 7.8 ].
14. Obtain a 3D parametric plot for the equations
z=1
x = r ∗ sin(θ)
y = r ∗ cos(θ)
19. Obtain a quiver plot for the electric field with the coordinates:
cos θ sin θ
E= ,
x2 + y 2 x2 + y 2
9.1 Introduction
In solving problems that involve mathematical equations, it is very common
for the problem to have either too many variables, implicitly defined variables,
or an equation that describes the problem. These are some of the few cases
where the use of optimization techniques is required. These techniques are
based on search algorithms which allow reaching one or several solutions to a
problem that is analytically impossible or very difficult to solve. The applica-
tion of optimization techniques is very broad and covers problems in all areas
of science. Python can incorporate a package that includes functions for per-
forming optimization for a large number of functions. The user has the task of
finding the most appropriate way to solve a given problem. This chapter is a
brief introduction to some of the functions for optimization in SciPy, so that
users can apply them in solving their problems. Several examples illustrate
how to solve these problems using Python and SciPy. SciPy is a package that
must be installed using pip as described in the Appendix.
Area = AB
The volume is called the target function or goal function which in this case
is to be maximized. The area that remains constant is called the restriction
function, which in this example is an equality constraint. The variable x is
the design variable.
• Design parameters. These are those constant amounts which are com-
pared with each design and that do not change during the optimization
process. They are denoted with P = [p1 , p2 , ..., pn ].
• Inequality constraints. They are the constraints that must satisfy the
problem. They are more difficult to satisfy than the equality constraints.
They are denoted by the matrix equation Ax ≤ b.
• Equality constraints. They are similar to the inequality constraints
but are easier to fulfill. They are denoted by the matrix equation Aeq x =
beq .
• Lateral constraints. They are used to specify the range of the design
variables. They correspond to the lower and upper bounds of the design
variables x.
• Initial conditions. They are the values of the design variables that are
at the beginning of the optimization.
Subject to
h1 (x1 , x2 , . . . , xn ) = 0
h2 (x1 , x2 , . . . , xn ) = 0
..
.
hm (x1 , x2 , . . . , xn ) = 0
Subject to
H1 (x1 , x2 , . . . , xn ) < 0
H2 (x1 , x2 , . . . , xn ) < 0
..
.
Hk (x1 , x2 , . . . , xn ) < 0
The user’s task is to set the optimization problem in terms of this format.
They can be used to find optimal solutions, perform equilibrium analysis, bal-
ance multiple design alternatives, and incorporate methods for the optimiza-
tion of algorithms and models. The methods used are within the following
techniques:
By means of examples, the chapter shows how to use some of these func-
tions to solve optimization problems.
• args (tuple, optional) extra arguments of the objective function and its
derivatives (jac, hes),
Some of these parameters are optional and may be omitted. This section
provides examples of how some of the optimization functions described in
the previous section can be used. The first optimization example uses the
minimize function to optimize the volume of the box from Example 9.1. There
is only a single variable and, therefore, it is a univariate function.
where x0 is the initial condition and options is the set of options for the
minimization process. For this example, the objective function is
ab = [24, 9]
def volume(x, ab):
return -(4*x**3-2*(ab[0] + ab[1])*x**2 + ab[0]*ab[1]*x)
# The sign of the function is changed to
# a minus sign to minimize.
“ ‘Script Example_9_2a.py
Obtaining the maximum volume for a box that is built
using a rectangular cardboard.”’
# Objective function:
def volume(x, ab):
return -(4*x**3-2*(ab[0] + ab[1])*x**2 + ab[0]*ab[1]*x)
# The sign of the function is changed
# to a minus sign to minimize.
# Optimization begins:
res = minimize(volume, x0, args = ab, method = ‘nelder-mead’, \
options = {‘xatol’:1e-8,‘disp’: True})
Iterations: 31
Function evaluations: 62
Optimum value for x: 2.0000
Optimum volume: 200.0
The first four lines are produced by the disp = True from options. The
last two lines are due to the print instructions. The optimization process
performed 31 iterations and 62 function evaluations.
In the minimization there were no derivatives computed. An improvement
in the minimization, process can be achieved if a method that uses the Jaco-
bian is used. In the case of an univariate function, the Jacobian is the first
derivative. The method is the Broyden-Fletcher-Goldfarb-Shanno or simply
BFGS. The derivative of the objective function is:
dV olume
= −(12x2 − 4(a + b)x + ab)
dx
“ ‘Script Example_9_2b.py
Obtaining the maximum volume for a box that is built
using a rectangular cardboard.
The method BFGS is used.”’
x0 = 1 # initial value.
# Values for a and b
ab = [24, 9]
266 Python with Optimization, ...
# Objective function:
def volume(x, ab):
return -(4*x**3-2*(ab[0] + ab[1])*x**2 + ab[0]*ab[1]*x)
# The sign of the function is changed to a
# minus sign to minimize.
# Jacobian.
def jac0(x, ab):
return -(12*x**2-4*(ab[0] + ab[1])*x + ab[0]*ab[1])
# Optimization begins:
res = minimize(volume, x0, args = ab, method = ‘BFGS’, \
jac = jac0, options = { ‘disp’: True})
The result is the same but the BFGS algorithm is faster by a factor of almost 8.
The graph of volume versus x in Figure 9.2 shows that the volume is maximum
when x = 2, as shown by the optimization process.
dV olume
= −24x − 4(a + b)
dx
“ ‘Script Example_9_2c.py
Obtaining the maximum volume for a box that is built
using a rectangular cardboard.
The method BFGS is used.”’
# initial value.
x0 = 1
# Jacobian.
def jac0(x, ab):
return -(12*x**2-4*(ab[0] + ab[1])*x + ab[0]*ab[1])
# Hessian.
def hes(x, ab):
return -(24*x - 4*(ab[0] + ab[1]))
268 Python with Optimization, ...
The results are similar to the previous script. But in some other functions,
especially in multivariate functions, the results may be much better.
f (x) = −(2xy + 2x − x2 − 2y 2 )
subject to the constraints:
x3 − y = 0
y − (x − 1)4 − 2 ≤ 0
and bounds
0.5 ≤ x ≤ 1.5
1.5 ≤ y ≤ 2.5
def f(x):
return -(2*x[0]*x[1] + 2*x[0] - x[0]**2 - 2*x[1]**2)
Optimization 269
def jc(x):
return [-(2*x[1] + 2 - 2*x[0]), - (2*x[0] - 4*x[1])]
x3 − y = 0
def consf(x):
return np.array([x[0]**3 - x[1]])
with Jacobian
[3x2 , −1]
which is implemented by
def jac(x):
return np.array([3.0*(x[0]**2.0), -1.0])
y − (x − 1)4 − 2 ≤ 0
which is implemented by
def funIn(x):
return np.array([x[1] - (x[0]-1)**4 - 2])
The functions defined above only have an instruction for the definition of
them; therefore, a lambda function may be used, as:
The function minimize is used with the bounds and initial value. First, the
constraints are not used, and then they are included:
# Script Example_9_3.py
import numpy as np
from scipy.optimize import minimize
import scipy.optimize as opt
# Objective function
def f(x):
return -(2*x[0]*x[1] + 2*x[0] - x[0]**2 - 2*x[1]**2)
# Constraints
cons = ({‘type’: ‘eq’,
‘fun’ : lambda x: np.array([x[0]**3 - x[1]]),
‘jac’ : lambda x: np.array([3.0*(x[0]**2.0), -1.0]),
{‘type’: ‘ineq’,
‘fun’ : lambda x: np.array([x[1] - (x[0]-1)**4 - 2])})
fun: -1.9999999999996365
x: [2.000e+00 1.000e+00]
nit: 5
jac: [ 1.252e-06 -1.416e-06]
hess_inv: [[9.983e-01 5.011e-01]
[5.011e-01 4.994e-01 ]]
nfev: 18
njev: 6
c 1 x1 + c 2 x2 + · · · + cn xn = z (9.1)
Subject to the constraints:
⎧
⎪
⎪ a11 x1 + a12 x2 + · · · + a1n xn ≤ b1
⎪
⎪
⎪
⎪ a x + a22 x2 + · · · + a2n xn ≤ b2
⎨ 21 1
..
. (9.2)
⎪
⎪
⎪
⎪ am1 x1 + am2 x2 + · · · + amn xn ≤ bm
⎪
⎪
⎩
x 1 , x2 , · · · , x n ≥0
272 Python with Optimization, ...
The variables
x1 , x2 , · · · , xn
are called decision variables. The set of decision variables that satisfy the
constraints is called a feasible point. The set of every possible feasible point is
called the feasible region. In the constraint equations, some of the inequalities
can be equalities; thus, there is a set of inequality constraints and a set of
equality constraints.
SciPy includes a function to perform linear programming. The function is
linprog with the following format:
f = 40x + 60y
Optimization 273
subject to constraints
⎡ ⎤ ⎡ ⎤
2 1 70
⎣1 x
1⎦ ≤ ⎣40⎦
y
1 3 90
x ≥ 0, y ≥ 0
The parameters are
f = [-40, -60]
A_ub = [[2, 1, [1, 1], [1, 3]]
b_ub = [70, 40, 90]
bnds = [(0, None), (0, None)]
print(res)
# bounds:
bnds = [(0, 100), (0, 100)]
# linprog method
res = linprog(f, A_ub, b_ub, bounds = bnds)
print(res)
274 Python with Optimization, ...
The optimal values for x are x0 = 15, x1 = 25. The optimal value for the
objective function is 2100. The optimization process made 3 iterations given
by nit.
This same problem can be solved with CVXOPT using the solvers.lp
method. The only requirement is to convert the objective function, the matrix
A_ub and the vector b_ub to numpy arrays and cvxopt matrices with floating-
point elements. They can be converted to floating-point with the option, tc
= ‘d’. The library cvxopt and its methods solvers and matrix have to be
imported. Then, the final script using the library CVXOPT is:
# solvers.qp method
res = solvers.lp(f, A_ub, b_ub)
Optimization 275
There is another package for linear programming with the name pulp. There
are some instructions that allows users to create new variables, and new prob-
lems, combine variables, use a solver, display the status of the solution, to get
the values of the variables. Consider the linear programming example from
above. To solve that problem with pulp first import the pulp library
import pulp
x1 = pulp.LpVariable(‘x1’, lowBound = 0)
x2 = pulp.LpVariable(‘x2’, lowBound = 0)
linearProblem += x1 + x2 <= 40
linearProblem += x1 + 3*x2 <= 90
solution = linearProblem.solve()
print(str(pulp.LpStatus[solution]) + \
“ ; max value = ” + str(pulp.value(linearProblem.objective))
print(“x1_opt =” + str(pulp.value(x1)))
print(“x2_opt =” + str(pulp.value(x2)))
which are the same values obtained with the other two packages. The complete
script is
# File Example_9_4c.py
# Solves the linear programming with pulp.
# Import pulp
import pulp
(x + 3)2 + (y + 5)2 = L2
This equation corresponds to a circle centered at (-3, -5) and radius L. This
would be the target function and, therefore, this function should be minimized.
278 Python with Optimization, ...
For the constraints, the small triangles abc and cde are considered. These
triangles are similar and they are related by:
x 3
=
5 y
which it is equivalent to:
xy = 15
# Objective function:
def ladder(x):
return (x + 3)**2 + (5 + 15/x)**2
# File Example_9_5.py
# Obtains the values of x, and the problem about the ladder.
# Objective function:
def ladder(x):
return (x + 3)**2 + (5 + 15/x)**2
This file provides the values of x to optimize the problem and additionally
calculates the length of the ladder. At the end, the curve of the objective
function is plotted. The result of the minimization gives:
L = 11.1941
The graph for the function ladder is shown in Figure 9.4. Here, it can clearly
be seen that the value of x minimizes the objective function and is consistent
with the value resulting from the optimization.
There are many ways to solve this example. This is only a solution but the
reader is invited to try an other optimization algorithm.
280 Python with Optimization, ...
FIGURE 9.4: Plot of the objective function with the minimum value displayed.
Cx = c
x≥ 0
y≥ 0
x, y ≥ 0
x + 3y ≥ 15
2x + 5y ≤ 100
3x + 4y ≤ 80
The quadratic form can be written in the standard form shown above as:
1 1 0 x x
x y + 3 4
2 0 0 y y
⎡⎤ ⎡ ⎤
−1 0 0
⎢ 0 −1⎥ ⎢ 0 ⎥
x 1 0 3 ⎢ ⎥ ⎢ ⎥
x = ,A = ,p = , B = ⎢−1 −3⎥ , b = ⎢
⎢ ⎥
⎢−15⎥
⎥
y 0 0 4 ⎣2 ⎦ ⎣
5 100 ⎦
3 4 80
These matrices and vectors in Python, converted to numpy arrays and CVXOPT
matrices are (numpy and cvxopt have to be imported previously):
solution = solvers.qp(A, p, B, b)
The solver displays information about the process but the important informa-
tion is the value of the objective function and the parameters x and y. These
are displayed with:
x = solution[‘x’]
ObjFun = solution[‘primal objective’]
print(‘The values of x and y are: ’)
print(‘The value of x is: ’, x[0])
print(‘The value of y is: ’, x[1])
print(‘The value of the objective function is: ’, ObjFun)
Thus, it can be seen that the values for x and y are 0 and 5, respectively. The
value of the objective function is the value of the quadratic form which in this
case is 20.0.
9.9 Conclusions
A brief introduction to the topic of optimization using Python and two of
the optimization packages available, SciPy and CVXOPT, have been presented.
Optimization using linear and quadratic programming as well as minimization
with and without constraints has been implemented. Several examples have
shown how the optimization process is done.
10.1 Introduction
A black and white image is a two-dimensional representation of three-
dimensional information in color. For processing, an image is partitioned into
a number of elements called pixels. This word comes from the combination of
the English words PICture ELement. The standard size of images in modern
devices is in the range of megapixels. In Figure 10.1, it is shown how an im-
age is represented. From this figure it can be seen that there are 8×8 = 64
pixels. A natural way of representing an image is then by a matrix or array
where each pixel position is associated with the values n and m of the matrix
elements. The value of the element m, n of the matrix is then the value of the
gray level of the corresponding pixel.
The way to number the pixels is exactly equal to the representation of
matrices as shown in Figure 10.2. Thus, the 0,0 pixel is a white pixel and
pixel 3,4 is a black pixel. Each pixel has an intensity level. For monochrome
images, the levels of intensity are gray levels. Depending on how many bits
are handled for this representation, it will be the number of gray levels that
can be represented. The image of Figure 10.2 is a chessboard that only has
two levels and therefore can be represented by a single bit. For example, if
that bit is 0 then it is black and if the pixel is 1 it is white, and vice versa.
For gray level images to be represented adequately, at least 256 gray levels
are needed which requires that each pixel is represented with 8-bit words. An
8-bit word is called a byte. In the case of color images, there are three color
components; then, 24 bits, or three bytes, are required for each color pixel.1
OpenCV is a software package especially designed for image and video
processing. It was initially developed by Intel and since August 2012 support
for OpenCV was taken by the non-profit foundation OpenCV.org which pro-
vides a developer and user site. It is written in C++ and has an interface for
Python. This chapter provides an introduction to image and video processing
using OpenCV and presents a set of instructions that allow users to begin to
do image and video processing. There are many more instructions available
in the OpenCV documentation site https://docs.opencv.org. Instructions
for installing OpenCV in different platforms are available in the Appendix.
OpenCV allows the processing of images in different formats, such as bmp,
eps, tif, pcx, gif, png, etc. and even in a free format. To test our scripts
in Python using OpenCV, an image known as Lena is used. This image is
usually used as a reference by researchers. This image of Lena is shown in
Figure 10.3. The original image is chromatic, in a bmp format and has a size
of 512×512×3.
1 Image files that are discussed in this chapter can be found in the web page of the book.
Image Processing with OpenCV 287
TABLE 10.1: Flags for imread.
Flag Action Value
Nothing It reads the unchanged image. -1
IMREAD_UNCHANGED It reads the unchanged image. -1
cv.IMREAD_GRAYSCALE It converts the image to a single
channel grayscale image. 0
cv.IMREAD_COLOR It converts the image to a 3
channel BGR color image. 1
import cv2
This step is needed to have access to all the functions available for image and
video processing. The name cv2 is the alias for OpenCV. The instruction to
read an image is
where image specifies the path and the name for the image file. The flags
are shown in Table 10.1. The image is read into an image file with the name
file_name. To display this image the instruction imshow is used. The format
is
cv2.imshow(“window_name”, file_name)
where window_name is the name in the window which displays the image.
An instruction cv2.waitKey(0) can be added to have the image windows
open until the key Enter is pressed and the pointer is on the image. Then,
the instruction cv2.destroyAllWindows() closes the windows. It is possible
to write a number inside the parenthesis, for example, cv2.waitKey(5000)
where the number is the time in milliseconds that the image window remains
open.
Now the image lena.jpg is in the OpenCV image file Lena as a color image.
To display the image, the instructions are:
where window name is the name of the window displayed and image is the
image name. The instruction waitKey(0) mantains the window open until
any key is pressed. Then, all image windows are closed by the instruction
destroyAllWindows(). The following script is used to read and display the
image Lena:
The method waitKey(0) is waiting for an input indefinitely. The image dis-
played closes when the pointer is placed upon the image and any key is pressed.
If another number different from 0 is entered, it indicates the number of mil-
liseconds that the image is displayed. The method destroyAllWindows() then
closes every open window.
The image Lena can be saved to a different format such as jpg or png, for
example. The instruction is imwrite(fileName, image). For this example,
to save the image Lena in format png, imwrite is used as
cv2.imwrite(‘images/lena.png’, Lena)
Now, after closing the image window, the folder images contains the images
lena.jpg and lena.png. In the case of jpg and png images, the instruction
imwrite can use additional parameters like the quality of the image saved.
Image Processing with OpenCV 289
2 https://docs.opencv.org/master/d8/d6a/group__imgcodecs__flags.html#ga292d
81be8d76901bff7988d18d2b42ac
290 Python with Optimization, ...
a = lena.shape
print(a)
(512, 512, 3)
These numbers mean that the image is represented by an array that has 512
rows, 512 columns, and has three layers corresponding to the three colors
BGR. A portion of an image can be cropped using the fact that images are
represented as matrices and taking into account that the first argument refers
to the height as:
image[y1:y1 + h, x1:x1 + k]
(x1, y1), (x1 + k-1, y1), (x1, y1 + h-1), (x1 + k-1, y1 + h-1)
Image Processing with OpenCV 291
or layer, which means that the first layer is the red layer, the second one is
the green layer, and the last one is the blue layer. However, in OpenCV the
layers are arranged as BGR. That is, the color layers are inverted. When an
image is opened with OpenCV as in the examples above, images are displayed
in the correct form. However, when an image is displayed with matplotlib,
then the colors are changed because the color formats are different.
The conversion from RGB image format to another one can be done when
the image is read using imread. For example, to read the image as a gray
format image use:
cv2.imread(“image”, cv2.RGB2GRAY)
If the image has already been read, then the instruction is cvtColor as:
Another color conversion is changing from RGB to HSV format. HSV stands
for hue, saturation, and chroma. This color space is used in a number of
applications. The instruction is:
cv2.imshow(‘Lena’, Lena)
cv2.imshow(‘Lena H’, h)
cv2.imshow(‘Lena s’, s)
cv2.imshow(‘Lena V’, v)
cv2.waitKey(0)
cv2.destroyAllWindows()
Image Processing with OpenCV 293
The variable correct is a boolean variable which with a True value indicates
that the frames are being captured correctly. The variable frame contains the
frames and to read them a while loop is used as follows:
while True:
correct, frame = capture.read()
cv2.imshow(‘Frame’, frame)
The imshow instruction is used to display the frames as they are captured.
To exit the while loop the instruction waitKey is used together with any key
pressed, for example the letter q to quit the capture. A condition if is used
as:
capture.release()
cv2.destroyAllWindows()
The complete file to capture video from the computer web cam is
294 Python with Optimization, ...
A video can also be captured specifying the path and the video file name.
fourcc = cv.VideoWriter_fourcc(*‘XVID’)
out = cv.VideoWriter(‘output.avi’, fourcc, 20.0, (640, 480))
Image Processing with OpenCV 295
These instructions should be placed inside the while loop. The complete file
is:
import cv2 as cv
cap = cv.VideoCapture(0)
# Import OpenCV
import cv2
where
• in is the original image.
• out is the resulting image.
298 Python with Optimization, ...
import cv2 as cv
import matplotlib.pyplot as plt
# THRESH_BINARY is applied:
ret,th1 = cv.threshold(img,80,255,cv.THRESH_BINARY)
cv2.imshow(‘img’, img)
cv2.imshow(‘Bitwise complemented image’, imgComp)
cv2.waitKey(0)
cv2.destroyAllWindows()
10.5 Histogram
A histogram is a representation of an image. It can be used to analyze images
and objects and video information. Histograms can be used to represent the
color distribution of an object, an edge gradient, or a distribution of probabil-
ities to determine the location of an object. Basically, histograms are collected
counts of data organized in predefined bins. What is of interest is the number
of pixels that fall within a bin range. OpenCV has the method to obtain the
histogram. This method is:
img = cv2.imread(‘images/cows.png’, 0)
hist = cv2.calcHist([img], [0], None, [128], (0, 256))
cv2.imshow(‘img’, img)
a = plt.figure(2)
plt.stem(hist)
plt.show()
cv2.waitKey(0)
cv2.destroyAllWindows()
The histogram is shown in Figure 10.10b. In the case of color images, the
calcHist method has to be repeated three times by only changing the layer
number to 0, 1, or 2.
result = equalizeHist(image)
Example 10.6 Histogram equalization
As an example, the image corn.png shown in Figure 10.11a, does not have a
good contrast. The following script equalizes the image and saves the result in
302 Python with Optimization, ...
a = plt.figure(2)
plt.stem(hist)
a = plt.figure(3)
plt.stem(resulting_hist)
plt.show()
cv2.waitKey(0)
cv2.destroyAllWindows()
import cv2
import numpy as np
The image to be created is a white color square created with ones in every
pixel and multiplied by 255 to make it a white square as
Now, a green straight line that starts at the pixel located at (50, 20) and ends
at the pixel located at (200, 100), the color has a component green and no
components red and blue and the thickness is 3.
A circle is added with a center at (400, 300), a radius equal to 50 and color
components red and blue so the color tuple is (255, 0, 255) and the thickness
is 5. The instruction is
cv2.circle(image, (400, 300), 30, (255, 0, 255), 5)
A rectangle is added with the upper left vertex at (100, 50) and the lower
right vertex at (300, 500). The color is blue so the tuple for the color is (255,
0, 0) and the thickness is 2. The instruction is then
A text “OpenCV” is written on the image with the lower left coordinate at (0,
400). The font is FONT_ITALIC, thickness is equal to 2, and color given by
(255, 0, 255) which corresponds to a purple color. The instruction is
Finally, an ellipse is printed with center at (100, 200), axes size = 70 and
200; thus, the parameter is (70, 200), the startAngle and endAngle are both
equal to 0, the color is (55, 100, 100), and the thickness is 2. The ellipse is:
cv2.imshow(‘Drawing’, image)
cv2.waitKey(0)
cv2.destroyAllWindows()
The contours can be found with the OpenCV method findContours which
has the format
FIGURE 10.13: Contours for image with geometric figures, a) original figures
and b) contours.
import cv2
import numpy as np
image = cv2.imread(‘figura10_shapes.png’)
imgGray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
_, th = cv2.threshold(imgGray, 150,255, cv2.THRESH_BINARY)
cv2.imshow(‘Original’, image)
cv2.imshow(‘Contours’, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
import cv2
import numpy as np
image = cv2.imread(‘figura10_shapes.png’)
imgGray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
_, th = cv2.threshold(imgGray, 150,255, cv2.THRESH_BINARY)
cv2.imshow(‘Example’, image)
cv2.imshow(‘th’, th)
cv2.imshow(‘img’, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
M
−1 N
−1
F (u, v) = f (x, y)e−j2π(ux/M +vy/N ) (10.1)
x=0 y=0
M −1 N −1
1
f (x, y) = F (u, v)ej2π(ux/M +vy/N ) (10.2)
M N u=0 v=0
for x = 0, 1, 2, . . . , M − 1 and y = 0, 1, 2, . . . , N − 1.
img = cv2.imread(‘images/cuadro.png’, 0)
img_float32 = np.float32(img)
plt.subplot(121)
plt.imshow(img, cmap = ‘gray’)
plt.title(‘Input Image’)
plt.xticks([])
plt.yticks([])
plt.subplot(122)
plt.imshow(magn, cmap = ‘gray’)
plt.title(‘Magnitude Spectrum’)
plt.xticks([])
plt.yticks([])
The image and the magnitude of the DFT are shown in Figure 10.14. To
evaluate the inverse DFT (IDFT), first shift again to restore the DFT and
then compute the IDFT as
f_ishift = np.fft.ifftshift(dft_shift)
img_back = cv2.idft(f_ishift)
Image Processing with OpenCV 311
As can be seen from Figure 10.15 there are two regions of interest, the white
and the black regions are regions where there are no changes in frequency and
they correspond to low frequencies, however, there are sharp changes at the
edges of the black rectangle which correspond to high frequencies.
import cv2
import numpy as np
from matplotlib import pyplot as plt
312 Python with Optimization, ...
image = cv2.imread(“square.png”)
Nu = 512
Nv = 512
image = cv2.resize(image, (Nu, Nv))
original = np.fft.fft2(imagGrayF)
center = np.fft.fftshift(original)
The log scale of the absolute value of the Fourier transform is computed and
displayed:
plt.subplot(152)
plt.imshow(np.log(1 + np.abs(center)), “gray”)
plt.title(“Spectrum”)
The spectrum is shown in Figure 10.17a. The design of the high-pass filter is
done with an ideal filter. This filter passes the high frequencies, those frequen-
cies far from the origin, and blocks or rejects the low-frequency signals close to
Image Processing with OpenCV 313
the center of the frequency spectrum. The design of the filter requires a matrix
of ones (1’s) with the size of the image. The number of rows and columns is
computed and the center is established. With a for loop, the points inside
the filter reject band are made 0 (zero). The filter function is in the variable
base. These operations are performed in a method or function as:
filteredSignal = center*HighPass
The filteredSignal variable is the DFT of the result which is plotted with:
plt.subplot(154)
plt.imshow(np.log(1 + np.abs(filteredSignal)),“gray”)
plt.title(“Spectrum of result”)
The filtered signal is shown in Figure 10.17b. The figure shows the absence of
low-frequency components. Finally, the inverse Fourier transform is computed
and the filtered image is displayed as Figure 10.17c.
314 Python with Optimization, ...
filteredSignal = np.fft.ifftshift(filteredSignal)
inverseFilteredSignal = np.fft.ifft2(filteredSignal)
plt.subplot(155)
plt.imshow(np.log(1 + np.abs(inverseFilteredSignal)), “gray”)
plt.title("Processed image")
plt.show()
Figure 10.17c shows the resulting filtered image. It can be seen that only the
region of high-frequency content, namely the edges, is preserved. The complete
script is
return base
original = np.fft.fft2(imagGrayF)
center = np.fft.fftshift(original)
plt.subplot(154)
plt.imshow(np.log(1 + np.abs(filtered_Signal)), “gray”)
plt.title(“Spectrum of result”)
The filtered signal shows that only in the region where there is abrupt
change, that corresponds to high frequencies, is kept. In the regions where
there is no change; that is, where there are only black or only white, that
316 Python with Optimization, ...
1
T (u, v) = (10.3)
1 + D(u, v)/D0]2n
where D(u, v) is the distance from the origin which is implemented with the
method distance from above. A method that implements the low-pass But-
terworth function is:
filter = np.ones(imgShape[:2])
The result of the filtering with these changes produces Figure 10.18. It can be
seen that the Butterworth filter reduces the Gibbs effect.
Image Processing with OpenCV 317
import cv2
from skimage.util import random_noise
Logo = cv2.imread(“PythonLogo.png”, 0 )
cv2.imshow(“PythonLogo”, Logo)
image = random_noise(Logo, mode = ‘s&p’,seed=None, clip=True)
cv2.imshow(“PythonLogo2”, image)
cv2.waitKey(0)
cv2.destroyAllWindows()
10.9.1 Denoising
There are several methods for denoising, the attempt to remove noise from an
image. The methods that are used in this section are: filter2D, blur, and
gaussianBlur. The method filter2D has the format
where source is the noisy image, depth is the type of the image, for example,
int, uint8, float, etc. Use -1 to have the same type in the processed image, and
the kernel is a matrix for the filtering that may be a 3×3, 5×5, 7×7, etc, but
always an odd number of rows and columns.
import cv2
from skimage.util import random_noise
import numpy as np
Then the image Lena is imported and salt and pepper noise is added. The
noisy image is displayed in Figure 10.20
Lena = cv2.imread(‘lenaC.jpg’, 0)
cv2.imshow(‘lena’, Lena)
image = random_noise(Lena, mode = ‘s&p’,seed = None, clip = True)
cv2.imshow(‘Noisy image’, image)
The kernel is defined and the filter2D is applied. The filtered image is displayed
and shown in Figure 10.20b.
The next method that is applied is the blur method. This is implemented with
which is displayed in Figure 10.20c. The last method is the Gaussian blur
implemented and displayed in Figure 10.20d with
FIGURE 10.20: a) Image with salt and pepper noise, b) Image filtered with
filter2D, c) Image blurred, d) Image processed with Gaussian blur.
import cv2
from skimage.util import random_noise
import numpy as np
# The image Lena is read and salt and pepper noise is added.
Lena = cv2.imread(‘lenaC.jpg’, 0)
cv2.imshow(‘lena’, Lena)
image = random_noise(Lena, mode = ‘s&p’,seed=None,clip=True)
cv2.imshow(‘Noisy image’, image)
cv2.waitKey(0)
cv2.destroyAllWindows()
The reflection set B̂ is then the set of points in B whose coordinates (x, y)
are replaced by (−x, −y). The translation of a set B by a point z = (x, y) is
322 Python with Optimization, ...
defined as
A B = {z|Bz ⊆ A} (10.6)
This means that for every point in the image, the reflection of the structuring
element fits completely in the resulting image. As an example consider the
image and structuring element in Figure 10.22. The result is an image that
looks smaller; that is, it has been eroded. As an example, the erosion process
is shown in Figure 10.23. In Figures 10.23a and c the structuring element
does not fit completely in the image and thus those pixels are eroded from
the image as shown in Figures 10.23b and d. In Figure 10.24a, b, and c, the
structuring element does fit inside the image and these pixels are preserved in
the erosioned image which is shown in Figure 10.24d.
A ⊕ B = {z|B̂z ∩ A = ∅} (10.7)
In this case the structuring element does not have to fit inside the original
image. The result is an image that dilates according to the structuring element.
Figure 10.25a shows a pixel where the structuring element dilates the image
as shown in Figure 10.25b. Figures 10.25c and d show another pixel and the
resulting dilated image is shown in Figure 10.26.
The morphological operations are best used with gray level images and
then a method for edge detection is used for demonstration. An example
shows the technique.
import cv2
import numpy as np
The edges of the image are obtained with an alternative method known as the
Canny detector named after his author [1]. The Canny method requires the
source image and two threshold values, minimum and maximum, which in this
example are chosen as 150 and 200. The processed image is then displayed:
The dilation is implemented with the OpenCV method dilate whose format is
The source image is LennaCanny, the kernel is a square kernel of size 3; that
is, a matrix of ones of dimension 3×3 with integer type, and the number of
iterations is 1.
# Dilation
kernel = np.ones((3,3), np.uint8)
LenaDilation =cv2.dilate(LenaCanny, kernel,iterations = 1)
cv2.imshow(‘Lena dilated’, LenaDilation)
326 Python with Optimization, ...
The erosion is implemented with the method erode which has the same pa-
rameters as the method dilate
# Erosion
LenaErosion = cv2.erode(LenaDilation, kernel,iterations = 1)
cv2.imshow(‘Lena eroded’, LenaErosion)
Finally, the last two instructions are to display and close the images,
cv2.waitKey(0)
cv2.destroyAllWindows()
# Dilation
kernel = np.ones((3,3), np.uint8)
LenaDilation =cv2.dilate(LenaCanny, kernel,iterations = 1)
cv2.imshow(‘Lena dilated’, LenaDilation)
The results for the Canny edge detection, the dilation, and the erosion are
shown in Figure 10.27.
10.12 Conclusions
OpenCV provides a great deal of methods and functions to perform operations
on images and videos. In this chapter only a few of those methods have been
presented. It is the author’s expectation that it will motivate readers to explore
and use OpenCV for image and video processing.
to search for a function that can predict the price of such a house. A possibility,
among many others, might be a straight line. The equation of a straight line
is
y(x, b, w) = b + wx (11.1)
where b and w are called the parameters of y(x, b, w). The parameter b cor-
responds to the y-intercept and the parameter w is the slope of the straight
line. The straight-line function then approximates the values of
ŷ (i) = f (x(i) , b, w)
(11.2)
= b + wx(i)
where ŷ (i) denotes the predicted values. The set of values (x(i) , y (i) ) is called
the training set. It is assumed that there are m training sets. The example
just described is known as a regression problem. The term regression refers
to the fact that a real-valued output, namely the price, is being predicted.
More formally, in supervised learning, a data set, called a training set, is used
to learn how to predict house prices. Then, the features are used to predict
the house prices ŷ (i) . Figure 11.2 presents the training data together with two
possible straight lines corresponding to two hypothesis functions produced by
two sets of parameters {b and w}. The question is: What is the best line to fit
the training data? To answer this question, a cost function to measure the
error has to be defined. Usually, a squared difference is used in the definition
of the cost function. The idea is to sum up the squared differences between the
real target value and the predicted by the function in equation 11.2, sum up
the errors and minimize it. As an example, consider the training set consisting
332 Python with Optimization, ...
FIGURE 11.3: Errors for a five-point training data. The straight line is the
function given by Eq. 11.1.
of five features and five targets shown in Figure 11.3. The squared error sum
is given by
4 4
d2i = [f (x(i) , b, w) − y (i) ]2 (11.3)
i=0 i=0
called the cost function and is defined in the following equation as:
M −1
1
J(x(i) , b, w) = [fb,w (x(i) ) − y (i) ]2 (11.4)
2M i=0
This approach for predicting a target value from a training set is called
a regression problem. In a regression problem the goal is to predict a
continuous-valued output. In the example above a single feature was con-
sidered, namely the size of the house. Thus, this is called a Univariate linear
regression problem.
n = number of features.
x(i) = set of features of the ith training example.
(i)
xj = value of feature j of the ith training example.
The data for the house could be arranged as shown in Table 11.2. In this table
(i)
it can be seen that there are m + 1 training examples. Then the value for xj
(2)
for the third feature of the second training example is x3 = 14, and the data
for the third training example is x(2) = [2, 1858, 3, 4, 14, 250].
The form of the function is now
fw (x) = w0 x0 + w1 x1 + w2 x2 + w3 x3 (11.5)
For the general case of n features the function fb,w (x) can be written as
where
⎡ ⎤ ⎡ ⎤
w0 1
⎢ w1 ⎥ ⎢ x1 ⎥
⎢ ⎥ ⎢ ⎥
⎢ w2 ⎥ ⎢ x2 ⎥
W =⎢ ⎥, X=⎢ ⎥ (11.8)
⎢ .. ⎥ ⎢ .. ⎥
⎣ . ⎦ ⎣ . ⎦
wn−1 xn−1
1. Start with J(b, w) for a set of initial values for {b, w}.
2. Change {b, w}, and keep changing them, to minimize J(b, w).
3. Use the gradient descent algorithm to minimize J(b, w). In this algorithm
the cost function is minimized by evaluating
∂J(b, w)
wj,new = wj − α (11.11a)
∂wj
∂J(b, w)
bnew =b−α (11.11b)
∂b
(11.11c)
wj = wj,new (11.12a)
b = bnew (11.12b)
Caution must be observed when choosing the value of α, a very small value
for it results in a slow convergence, whereas a large value can lead to non
convergence of the optimization algorithm. It might be possible to have an
α-value for b and a different α-value for w to improve the convergence of the
algorithm.
For linear regression the cost function is given by equation 11.4 and the
hypothesis by equation 11.2. Thus, the cost function is given by
m
1
J(b, w) = [f (x(i) ) − y (i) ]2 (11.14a)
2m i=0
m
1
J(b, w) = [(b + wx(i) ) − y (i) ]2 (11.14b)
2m i=0
m
1
bnew = b − α [f (x(i) ) − y (i) ] (11.15a)
m i=0
m
1
wnew = w − α [f (x(i) ) − y (i) ]x(i) (11.15b)
m i=0
y = 2 + 4x (11.16)
x = np.linspace(0, 3, 100)
for i in range(len(x)):
y[i] = 2 + 4*x[i] + (-1)**randint(0,1)*random()
A plot of these data points is shown in Figure 11.6. Now, the learning rate α,
and the initial values for b and w are given as
alpha = 0.001
w = 0
b = 0
m = len(y)
while (True):
The first step inside the loop is to initialize the sums in equations 11.15 to 0:
sum0 = 0
sum1 = 0
Machine Learning 339
for j in range(len(y)):
sum0 = sum0 + (b + w*x[j] - y[j])
sum1 = sum1 + (b + w*x[j] - y[j])*x[j]
bn = b -(2*alpha/m)*sum0
wn = w -(2*alpha/m)*sum1
But if any of the inequalities do not hold, then the b and w values are updated:
else:
b = bn
w = wn
while (True):
sum0 = 0
sum1 = 0
for j in range(len(y)):
sum0 = sum0 + (b + w*x[j] - y[j])
sum1 = sum1 + (b + w*x[j] - y[j])*x[j]
bn = b -(2*alpha/m)*sum0
wn = w -(2*alpha/m)*sum1
else:
b = bn
w = wn
Finally, the total number of iterations and the values for b and w are displayed
and the straight line corresponding to the computed values (solid line) and the
original straight line (dotted line) are plotted together with the data points:
340 Python with Optimization, ...
# Value of m is computed:
m = len(y)
while (True):
# Initialize the sums to 0:
sum0 = 0
sum1 = 0
bn = b -(2*alpha/m)*sum0
wn = w -(2*alpha/m)*sum1
else:
b = bn
w = wn
A plot for the data points and the two straight lines is shown in Figure 11.7.
The dotted line is the original straight line. Due to the introduced random
noise the coefficients cannot be obtained exactly.
342 Python with Optimization, ...
FIGURE 11.7: Data points and linear regression using the gradient descent.
m
1 (i)
bnew = b − α (y − 1) (11.17a)
m i=0
m
1 (i)
wk,new = wk − α (y − x(i) )x(i) (11.17b)
m i=0
..
.
for k = 1, . . . , n
Feature scaling consists in dividing the input values by the range, that
is, the maximum value minus the minimum value of the input variable. The
result is a variable in a new range between 0 and 1.
Mean normalization consists in subtracting the average value for a feature
from the values for that variable, resulting in a new average value for the
feature that is equal to zero.
Both techniques are implemented in the equation:
x1 − μ i
xi = (11.18)
s1
where μi is the average for the values for feature i and si is either the range
of values (max - min) or si is the standard deviation. Note that both cases
for si give different results.
W = (X T X)−1 X T y (11.21)
There are some pros and cons for this normal equation. Some of them are
listed in Table 11.4 and they do not need further explanation.
344 Python with Optimization, ...
TABLE 11.4: Comparison between optimization and the normal
equation
Optimization Normal equation
It needs many iterations No need to iterate.
It works well when n is large It is very slow for a large n.
O(n2 ) O(n3 ) because of the inverse calculation.
An issue that arises sometimes is the fact that X T X may be non invert-
ible. This problem can be alleviated by looking for features that are either
linearly dependent or very close to be linearly dependent. In this case those
linearly dependencies are eliminated by deleting the features that are linearly
dependent. In some other cases it is necessary to delete some features because
there are too many of them thus reducing the size of the design matrix.
Next, the data point are generated with random deviation for the straight line
y = np.zeros(100)
x = np.linspace(0, 3, 100)
for i in range(len(x)):
y[i] = 2 + 4*x[i] + (-1)**randint(0,1)*random()
The matrix X, according to equation 11.19 has only two columns and the first
column is composed of 1’s and the second column has the features x(i) . The
matrix X can be obtained with a concatenation using
X = np.c_[np.ones((-1, 1)), x]
where the method c_[ ] concatenates the arrays inside the brackets. The re-
sulting array is a numpy array. For numpy arrays a and b, the dot product can
be implemented as a.dot(b). The inverse matrix for an array A can be imple-
mented with np.linalg.inv(A). Then, equation 11.19 can be implemented
with
W = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y)
Machine Learning 345
W = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y)
Finally, the result for W[0] and W[1] are obtained with print(‘W’, W) and
the data points and the straight line obtained with the W values can be plotted
with
print(‘W’, W)
plt.scatter(x, y)
plt.plot(x, W[0] + x*W[1], color = ‘blue’)
plt.plot(x, 2 + 4*x, color = ‘black’)
plt.show()
FIGURE 11.8: Data points and linear regression using the normal equation.
plt.scatter(x, y)
plt.plot(x, W[0] + x*W[1], color = ‘blue’)
plt.plot(x, 2 + 4*x, color = ‘black’)
plt.show()
W [1.98119633 4.04120188]
The data points generated are shown in Figure 11.8 together with the straight
line whose parameters are: W [1.98119633 4.04120188] and the plots are
shown in Figure 11.8.
site provides details on the use of it. The site is scikit-learn.org. In this
chapter the linear regression and the logic regression methods are used. As
the first example of the use of scikit-learn, the linear regression of Example
11.1 is implemented. The library scikit-learn is imported as sklearn.
The data points are generated in the same way and stored in vectors X and
y. This is done with
y = np.zeros(100)
x = np.linspace(0, 3, 100)
for i in range(len(x)):
y[i] = 2 + 4*x[i] + (-1)**randint(0,1)*random()
x = np.reshape(x, (-1,1))
y = np.reshape(y, (-1,1))
lin_reg = LinearRegression()
lin_reg.fit(x, y)
The lin_reg method now has produced the y-axis intercept and the slope of
the straight line. These parameters are obtained with
b = lin_reg.intercept_
348 Python with Optimization, ...
w = lin_reg.coef_
print(‘The y-axis intercept and the slope are:’, b, w)
Finally, the data points and the straight line from the linear regression are
plotted and displayed with
plt.scatter(x, y)
plt.plot(x, b + w*x, color = ‘black’)
plt.show()
In all the examples above, the training of the linear regression has been done
with all the samples in the data. A better approach is to separate some of
the data for the training and use the rest of the data for testing the lin-
ear regression algorithm. This task can be accomplished with the method
train_test_split available in the library sklearn.model_selection. The
training part can be a fraction of the data and the rest of it can be used for
testing. The format is
For example, a good choice for train_size may be 90% of the data for training
and 10% for testing. The value for the test_size is optional and can be
omitted. The choice random_state = 23 is for a random selection of the data
at each run. The splitting of the data is
lin_reg.fit(x_train, y_train)
The squared error can be obtained with the method r2_score from the library
sklearn.metrics. The library is imported
lin_reg = LinearRegression()
lin_reg.fit(x_train, y_train)
# Coefficients b and w
bs = lin_reg.intercept_
ws = lin_reg.coef_
x = np.reshape(x, (-1,1))
y = np.reshape(y, (-1,1))
# The model is
lin_reg = LinearRegression()
lin_reg.fit(x, y)
b = lin_reg.intercept_
w = lin_reg.coef_
# The data is splitted, 80% for trainig and 20% for testing:
x_train, x_test, y_train, y_test = \
train_test_split(x, y, train_size = 0.8, random_state=23)
# The coefficients bs, ws, and the squared error are printed.
# The coefficients b0, w1, and the squared error are printed:
print(‘The y-axis intercept and the slope when data \
is splitted are:\n’, bs[0], ws[0][0])
print(‘The value of r∧2 is: ’ , sqs)
A run for this script produces the values for b, w_1, b0s and w_1s for both
cases are given by
1.8485305132324061 4.066335371892183
The value of r∧2 is: 0.9805030083081524
352 Python with Optimization, ...
FIGURE 11.9: Data points and linear regression straight line from
scikit-learn.
The y-axis intercept and the slope, when data is splitted, are,
respectively:
1.82468152 4.00090227
The value of r∧2 is: 0.9787833851121427
The data points generated are shown in Figure 11.9 together with the straight
a line whose parameters are:
b = 1.8485305132324061
w = 4.066335371892183
It can be seen that the linear regression obtained with scikit-learn is very
close to the results obtained in examples, 11.1 and 11.2. In this example the
model definition, the LinearRegression method and the fit method were
used.
fθ (x) = b + w1 x + w2 x2 (11.22)
fw (x) = b + w1 x + w2 x2 + w3 x3
Machine Learning 353
It may be the case that the exponent is a fractionary one such as in the
equation
√
fw (x) = b + w1 x + w2 x
Polynomial regression may be a better choice for the hypothesis function but
it may be computationally more expensive.
f (x) = 2 − 3x + 2x3
To generate the data for this case, first import the necessary libraries and
methods and then generate a vector for x values as
x = np.linspace(-3, 3, 100)
y = np.zeros(100)
for i in range(len(x)):
y[i] = 2*x[i]**3 - 3*x[i] + 2 + 10*(-1)**randint(0,1)*random()
poly_features = PolynomialFeatures(degree = 3, \
354 Python with Optimization, ...
include_bias = False)
Xpoly = poly_features.fit_transform(x)
lin_reg = LinearRegression()
lin_reg.fit(Xpoly, y)
b = lin_reg.intercept_[0]
w1 = lin_reg.coef_[0][0]
w2 = lin_reg.coef_[0][1]
w3 = lin_reg.coef_[0][2]
sqs = r2_score(yp, y)
print(‘sqs = ’, sqs)
Finally, the plot of the y-points and the yp-points is done with
plt.scatter(x,y)
yp = b+w1*x+w2*x**2+w3*x**3
plt.plot(x, yp)
x = np.linspace(-3, 3, 100)
y = np.zeros(100)
b = lin_reg.intercept_[0]
w1 = lin_reg.coef_[0][0]
w2 = lin_reg.coef_[0][1]
w3 = lin_reg.coef_[0][2]
sqs = 0.8566338231859216
b = 1.3815450427785627
w1 = -3.3138517549947593
w2 = -0.07957952825220471
w3 = 2.010727385384017
A comparison with the original polynomial shows that the independent coef-
ficient deviates from the value 2 to 1.3815450427785627, the coefficient of x
deviates from -3 to -3.3138517549947593, the coefficient of x∧2 goes from 0
to -0.07957952825220471, and finally, the coefficient of x∧3 deviates from 2 to
2.010727385384017. The original values cannot be obtained due to the added
random noise. Furthermore, each run will produce different results due to the
random noise that was added. A plot showing the data points and the cubic
polynomial is shown in Figure 11.10.
Machine Learning 357
• Is an email spam?
• Is a bank transaction fraudulent?
• Is a tumor malignant?
• Is a person diabetic?
These are examples whose answer can be either yes or no. Denoting the answer
with the letter y, it is readily seen that y can only have two values: yes or no,
true or false, 1 or 0. This type of supervised learning algorithm whose output
can take on only two values is known as binary classification.
As an example, a plot of medical records is shown in Figure 11.11 where
the crosses reveal a malignant tumor and the circles a benign one. The feature
in the horizontal axis refers to the size of the tumors and the vertical axis has
marks at 0 and 1. The value of 1 has been chosen for the malignant tumors
and 0 for the benign ones. A malignant tumor is a tumor that is harmful and
dangerous and a benign tumor is a tumor that may be harmless but it requires
attention. For a person whose tumor has a size indicated by the letter A, it
can be concluded that the tumor is benign. In this plot there are eight tumors
that are benign and five tumors that are malignant. This is an example of a
classification problem. It turns out that in classification problems, sometimes
there are more than two possible values for the output. As a concrete example,
maybe there is more than one type of cancer. So, the task is to try to predict a
discrete value output zero, one, two, or three, where zero may mean benign,
one may mean type-one cancer, and two mean a second type of cancer, and
three may mean a third type of cancer.
358 Python with Optimization, ...
The sigmoid function is plotted in Figure 11.12. It can be seen that the func-
tion values are between 0 and 1 and they are equal to 1 for z 0 and to 0
when z 0. Recalling linear regression, the variable z can be written as
z = b + WTx (11.24)
In the multivariate case W is a vector. The function can then be written as
1
L(fW,b (x(i) ), y (i) ) = [fW,b (x(i) ) − y (i) ]2 (11.28)
2
Using the sigmoid function, it can be shown that the loss function is given by
L(fW,b (x(i) ), y (i) ) = −y (i) log(fW,b (x(i) ))−(1−y (i) )log(1−fW,b (x(i) )) (11.29)
m
1 (i)
J(W, b) = − [y log(fW,b (x(i) )) − (1 − y (i) )log(1 − fW,b (x(i) ))] (11.31)
m i=0
360 Python with Optimization, ...
where
m
∂J(W, b) 1
= (fW,b (x(i) ) − y (i) )x(i) (11.34a)
∂wj m i=0
m
∂J(b, w) 1
= (fW,b (x(i) ) − y i ) (11.34b)
∂b m i=0
m
∂
wj,new = wj − α (fW,b (x(i) ) − y (i) )x(i) (11.35a)
∂wj i=0
m
1
bnew = b − α (fW,b (x(i) ) − y (i) ) (11.35b)
m i=0
These equations are identical to equations 11.15. The only difference is in the
function f (x) which in logistic regression is the sigmoid function.
https://www.kaggle.com/datasets/kandij/diabetes-dataset
• x0 Pregnancies.
• x1 Glucose.
• x2 BloodPressure.
• x3 SkinThickness.
• x4 Insulin.
• x6 DiabetesPedigreeFunction.
• x7 Age.
and the last column is the output or target with the name Outcome.
This example is done with Pandas to handle the arrays. The first step is
to import the necessary libraries which are pandas, matplotlib, and numpy.
This is done with
Next, the data file is read as a csv file. This action creates a Pandas data
frame:
data = pd.read_csv(‘diabetes2.csv’)
If the data is printed, it can be seen that the data has a heading, 768 rows and 9
columns. The example only uses the column corresponding to BloodPressure.
The printing of the column corresponding to BloodPressure and the Output
is displayed with
print(train[[‘BloodPressure’, ‘Outcome’]].head())
and only these two columns and the first five rows are displayed.
BloodPressure Outcome
0 72 1
1 66 0
2 64 1
3 66 0
4 40 1
Now, equations 11.35 are implemented. A value for the learning rate α and
initial values for b and w are required. They are initialized as
b = 0.0
w = 0.0
alpha_b = 0.1
alpha_w = 0.001
and for b as
data[‘sigmoid’]=1/(1+np.exp(-(data[‘BloodPressure’]*w+b)))
data[‘partial_loss’] = (data[‘sigmoid’]-data[‘Outcome’])
derivative_w = data[‘loss’.mean()
α T
wnew = w − X (g(X, W, b) − y) (11.36)
m
w_0 = 1
b_0 = -1
alpha_w = 0.001
alpha_b = 0.1
data[‘sigmoid’] = sigmoid(data[‘BloodPressure’], w, b)
The gradient descent algorithm starts. A while loop is used for the iterations.
It starts by initializing the index to 0:
i = 0
The while loop keeps working unless both equations 11.33 are satisfied; thus,
the while loop instruction is:
while (True):
The first step is to compute the value of the sigmoid function for the ini-
tial values of w and b. This is done with (the following lines must have an
indentation):
A new column is added to the data array for the loss considering the w pa-
rameter. This is done with:
derivative_w = data[‘loss’].mean()
The same procedure is followed for the derivative with respect to b. Then:
data[‘loss’] = (data[‘sigmoid’]-data[‘Outcome’])
derivative_b = data[‘loss’].mean()
These new values are compared with the previous ones with equations 11.33
with a value for of 1 × 10−6 and using an if condition. If the condition is
satisfied the loop ends, but otherwise update the values of w and b:
This ends the algorithm. The values for w and b are printed
To check a result consider the value of blood pressure of 140 and see what the
result produces the sigmoid:
x = 140
y = 1/(1 + np.exp(-(w_0*x + b_0)))
print(‘The value of the output is: ’, y)
b = 0.0
w = 0.0
alpha_b = 0.1
alpha_w = 0.001
w_0 = 1
b_0 = -1
alpha_w = 0.001
alpha_b = 0.1
while(True):
# This ends the algorithm. The values for w and b are printed
print(‘The value of w is: ’, w_0)
print(‘The value of b is: ’, b_0)
Next, the data file is read in as a csv file. This action creates a Pandas data
frame:
data = pd.read_csv(‘diabetes2.csv’)
From the previous example, it is known that the information for the target is
in the column Outcome. The model is created and the data is fitted:
model = LogisticRegression()
model.fit(X_data[‘BloodPressure’], X_data[‘Outcome’])
Finally, the b and the w parameters are printed out and compared with the
results in the previous example:
print(f‘Parameter b: {model.intercept_}’)
print(f‘Parameter w: {model.coef_}’)
Parameter b: [-1.14008318]
Parameter w: [[0.00742463]]
368 Python with Optimization, ...
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
Machine Learning 369
data = pd.read_csv(‘diabetes2.csv’)
print(data.head(10))
The data is split. The data has 9 columns, the last one is the Outcome. The
testing size slice is set at 15% and the training slice is 85%.
model = LogisticRegression()
model.fit(X_train, y_train)
Now, the prediction is computed and printed. The prediction produces outputs
according to the model calculated from the fitting:
prediction = model.predict(X_test)
print(prediction)
The score indicates what is the percentage of good results obtained with the
model:
a = model.score(X_test, y_test)
print(a)
print(f’Parameter b: {model.intercept_}’)
print(f‘Parameter w: {model.coef_}’)
A run for this program produces (only the score and the coefficients are dis-
played here):
score = 0.7844827586206896
Parameter b: [-8.65761075]
Parameter w: [[ 0.1054894 0.03793538 -0.01325795 -0.00442582 \
-0.00102874 0.0954708 0.92562988 0.01143644]]
In this run, the score indicates that 78.4% of the results are good as com-
pared with the Outcome column. The coefficients indicate an exponent for the
sigmoid function (the coefficients are displayed to three decimal digits). The
exponent of equation 11.26 is given by:
z = −8.658 + W T X
Machine Learning 371
where
and
Another run will produce a different result due to the random nature of the
split method.
import pandas as pd
from sklearn.model_selection import train_test_split
import seaborn as sns
import matplotlib.pyplot as plt
Next, the dataset is loaded from seaborn and prints the headings:
iris = sns.load_dataset(‘iris’)
print(iris.columns)
The last column corresponds to the target column and it can be any of the
three iris species, namely, setosa, versicolor, and virginica.
372 Python with Optimization, ...
iris[‘species’] = iris[‘species’].replace(‘setosa’:1, \
‘versicolor’:2, ‘virginica’:3)
The model is defined. From scikit-learn the model for logistic regression
must be imported and the fitting is implemented with:
A prediction is run with X_test using the method predict. This method runs
as:
prediction = model.predict(X_test)
print(prediction)
The score is another measure of the algorithm. A score of 1.00 indicates that is
exact and a score less than 1.00 indicates the percentage of success. To obtain
the score for the model use:
model.score(X_test, y_test)
print(‘score = ’, model.score(X_test, y_test))
which in this example is score = 0.977; that is, the algorithm has an accu-
racy of 97.7%. The confusion matrix is a way to see graphically how many of
the tests are correct and how many are wrong. This can be obtained with:
[[10 0 0]
[ 0 14 0]
[ 0 1 20]]
Machine Learning 373
which indicates that for the iris setosa, ten out of ten cases were predicted
correctly. For the iris versicolor, fourteen out of fourteen were correctly pre-
dicted, and for the iris virginica, out of 22, 21 were correctly predicted and
one was incorrect. The confusion matrix can be plotted with:
The plot produced is shown in Figure 11.14. This plot contains the same
information displayed above in the confusion matrix. It is worth to point out
that the confusion matrix changes for each run because the data from the run
is produced by the logistic regression fit that is not a deterministic process. A
second run produces the confusion matrix plot shown in Figure 11.15 and it is
a different one as compared with the previous confusion matrix plot. Another
plot of interest is a scatter plot of petal length vs. petal width that can be
done with a seaborn scatter plot as
The plot produced is shown in Figure 11.16. It is clearly seen that the setosa
type is well separated from the virginica and the versicolor types. A decision
boundary is well established for the setosa type but is not so well established
374 Python with Optimization, ...
FIGURE 11.16: Petal length vs petal width for the iris dataset.
Machine Learning 375
between the virginica and the versicolor types as can be seen in Figure 11.17
where the decision boundaries have been added outside of the script. The
complete script is:
1. Select one of the points of each cluster as a center of the cluster called
the centroid of the cluster.
Machine Learning 379
Usually, the data points associated with each cluster are enclosed in some
geometric shape such as a circle, square, or any other geometric shape, and
they are called blobs. Sometimes it is not easy to “see” the clusters and thus,
step No. 1 is a random choice. Consider Figure 11.20 where the data has been
clustered into 3 and into 5 clusters. The question now is to know which is the
best or optimum number of clusters. To answer this question a cost function
has to be defined.
1. Select one of the points of each cluster as a center of the cluster called
the centroid μk of the cluster.
2. Take the distances of the points to each of the proposed centroids.
3. Associate the closer points to each cluster to the corresponding centroid.
380 Python with Optimization, ...
||x(i) − μ(k)
c ||
2
m−1
1 (i)
J(c(0) , . . . , c(K−1) , μ0 , . . . , μK−1 ) = ||x − μ(i)
c ||
2
m i=0
11. The minimization of this cost function is done over the parameters
where C is the set of cluster points. Although both measures are different,
they both produce optimum results.
The other factor that can decrease the cost function is the number of
clusters. A plot of either the distortion or the inertia versus the number of
clusters is shown in Figure 11.21 where it can be seen that there is not much
improvement in the distortion (or the inertia) as the number of clusters is
greater than 3. Sometimes this plot gives a good idea of the optimum number
of clusters but some other times, the selection of the number of clusters is
based upon the problem to solve, like in the case of T-shirt sizes, baby clothing,
pants, and many more examples.
The package scikit-learn provides methods to implement k-means clus-
tering. The following example generates the data and then implements the
clustering using scikit-learn.
Machine Learning 381
These instructions produce the data points shown in Figure 11.22. To find the
optimum value for the number of clusters, the values for the distortion and
inertia functions can be obtained as
k_mean.cluster_centers_, ‘euclidean’ \
), axis = 1))/points.shape[0])
plt.plot([1,2,3,4,5,6,7,8,9], inertia)
plt.ylabel(‘Inertia’)
plt.xlabel(‘Number of clusters’)
plt.show()
that produces Figures 11.23 and 11.24. It is readily seen that both measures
provide the same results, namely, four clusters as the more appropriate num-
kmeans.fit(dataset[0])
clusters = kmeans.cluster_centers_
print(“The cluster points are: \n”, clusters)
[[-2.40167949 10.17352695]
[-5.56465793 -2.34988939]
[ 0.05161133 -5.35489826]
[-1.92101646 5.21673484]]
The plot shown in Figure 11.25 is the result. The complete file is:
# File Example_11_9.py
# Implements clustering using scikit-learn.
11.11 Conclusions
This chapter has presented a brief introduction to machine learning. Some
examples of supervised and unsupervised learning have covered these topics,
although not exhaustively, some aspects of this chapter topic. The examples
have been made from scratch and also using the package Scikit-learn. There
are many more topics in machine learning that are not covered here. The
purpose of the chapter is to show the use of Python in machine learning.
Chapter 12
Neural Networks
12.1 Introduction
Artificial neural networks have been around for almost 80 years. They were
first proposed in 1943 by McCulloch and Pitts [1]. Neural nets were widely
adopted but in the early 1990’s their use diminished when it was believed that
other new techniques were more promising. It was the development of the in-
crease in computer power, the gaming industry, and the very large amount of
data necessary for training neural networks that gave way to further develop-
ment and use of artificial neural networks (ANN). Neural nets were conceived
to mimic a biological neuron, as shown in Figure 12.1a. In the figure, it can
be seen that a biological neuron cell is composed of a nucleus, input branches
known as dendrites, and an output called the axon with axon terminals. Also,
in Figure 12.1b it is shown an artificial neuron consisting of the same parts.
Nowadays, many researchers have dropped the artificial word and the name
most commonly used is neural networks. The advantage of neural networks is
that thousands of them can be used in a network to fulfill a task. In this chap-
ter models for neurons are presented together with the mathematical functions
needed. The packages TensorFlow and Keras are used in the implementation
of neural networks. Examples presented show how to use these packages in
the implementation of neural networks.
FIGURE 12.2: Typical artificial neural network with inputs and outputs.
Neural Networks 389
interprets the auditory message. These are only two examples of the many
activities processed inside the brain by the billions of neurons that compose
it. A typical artificial neural network is shown in Figure 12.2. It is formed by
inputs, represented by the xi ’s, neuron layers consisting of neurons intercon-
nected with the inputs or the outputs of a previous layer, and outputs. The
neural network shown in Figure 12.2 has a vector of inputs with three compo-
nents x0 , x1 , and x2 , two layers of four neurons each, and a vector of outputs
with two components. Each neuron is connected to neurons in a previous layer,
or to the input vector. The outputs of a previous layer are multiplied by a
weight w. There is also an input b called a bias, not shown in this figure. The
[m]
output of a neuron is denoted by aj where m is the layer number and j is
[m]
the neuron position in the layer. The bias coefficient bj corresponds to the
[m]
bias in the j neuron in the m layer. The weights are denoted as wij where j
is the source node and i is the end node.
This notation for the weights is shown in Figure 12.3. The model for a neuron is
shown in Figure 12.4 and its behavior is to add, represented by the Greek letter
Σ, the inputs, and then apply a nonlinear activation function represented by
the letter f . The addition of the inputs to the j th neuron of the k th layer
which are the outputs of the (k − 1)th layer nodes and the bias inputs, which
are then
[k] [k] [k−1] [k] [k−1] [k] [k−1] [k]
zj = wj0 a0 + wj1 a1 + · · · + wj(n−1) an−1 + bj
and then apply an activation function f (z) to obtain
and
[k] [k]
aj = f (zj )
390 Python with Optimization, ...
[k]
where aj is the output of the activation function. The activation function
may be the sigmoid function from Chapter 11, but there exist other activation
functions as shown later in the chapter. The input +1 is called a bias unit and
the b’s together with the w’s are called the weights, also called parameters,
which can be represented by column vectors as
[k]
The outputs aj are also arranged in a vector as
⎡ [k] ⎤
aj0
⎢ ⎥[k]
⎢ ⎥
aj1
a[k] = ⎢
⎢
⎥
⎥.. (12.2)
⎣ ⎦ .
[k]
aj(n−1)
[k]
The sums zj can be written in vector form as
[k] T
zj = W [k] a[k] + b[k]
Neural Networks 391
where the T indicates the transpose of the vector. The matrix W is formed
by the vectors W [k] as:
⎡ T ⎤
W [0]
⎢ T ⎥
⎢ W [1] ⎥
W =⎢
⎢ ..
⎥
⎥ (12.3)
⎣ . ⎦
T
W [m−1]
⎡ ⎤ ⎡ ⎤
z [0] a[0]
⎢ z [1] ⎥ ⎢ a[1] ⎥
⎢ ⎥ ⎢ ⎥
Z=⎢ .. ⎥ a=⎢ .. ⎥ (12.4)
⎣ . ⎦ ⎣ . ⎦
z [m−1] a[m−1]
where a is given by
a = f (Z)
A neural network is a set of neurons interconnected, for example, as shown
in Figure 12.2 with multiple inputs, but it may have a single input. The
connection between neurons, inputs, and outputs is called the architecture
of the neural network. Figure 12.2 shows an example of an architecture. The
inputs in this figure are called the input layer, the outputs are called the output
layer, and the two layers of neurons that cannot be seen from neither the input
nor the output, are called the hidden layers. The figure also shows the names
[j]
of the output variables for each neuron, namely ai where j indicates the
layer number and i the position of the neuron in the layer. The corresponding
equations for the first layer which has four nodes and receives inputs from the
vector of inputs X. The equations for the z’s in layer 0 are
[0] [0] [0] [0] [0]
z0 = w00 x0 + w01 x1 + w02 x2 + b0
[0] [0]
a1 = f (z1 )
[0] [0]
a2 = f (z2 )
[0] [0]
a3 = f (z3 )
These outputs are fed to the neurons in layer 1 and the equations are
[1] [1] [0] [1] [0] [1] [1] [0] [1]
z0 = w00 a0 + w01 a1 + w02 a[ 0]2 + w13 a3 + b0
[1] [1] [0] [1] [0] [1] [0] [1] [0] [1]
z1 = w10 a0 + w11 a1 + w12 a2 + w13 a3 + b1
[1] [1] [0] [1] [0] [1] [0] [1] [0] [1]
z2 = w20 a0 + w21 a1 + w22 a2 + w23 a3 + b2
[1] [1] [0] [1] [0] [1] [0] [1] [0] [1]
z3 = w30 a0 + w31 a1 + w32 a2 + w33 a3 + b3
The outputs of the neurons are given by
[1] [1]
a0 = f (z0 )
[1] [1]
a1 = f (z1 )
[1] [1]
a2 = f (z2 )
[1] [1]
a3 = f (z3 )
Finally, for the output layer the equations are
[2] [2]
a0 = f (z0 )
[2] [2]
a1 = f (z1 )
Also, the outputs are
[2]
ŷ0 = a0
[2]
ŷ1 = a1
Neural Networks 393
In matrix form
T
a[0] = f (W [0] X + b[0] )
T
a[1] = f (W [1] a[0] + b[1] )
T
a[2] = f (W [2] a[1] + b[1] )
ŷ = a[2]
The Rectified Linear Unit or ReLU, has a linear value for z > 0 and it has
a 0 value for z < 0. It is shown in Figure 12.7 and it is defined by
The Leaky ReLU is shown in Figure 12.8. Note the small slope for z < 0 which
gives the name to this activation function.
It can be shown that the derivatives, used in the cost function, for these
activation functions are as follows. For the sigmoid function
d
f (z) = f (z)[1 − f (z)] (12.8)
dz
For z 0 and z 0 the derivative f (z) ≈ 0. For z = 0 the value of
f (0) = 1/4.
m−1
1
J(W, b) = [−[y (i) logŷ (i) + (1 − y (i) ) log(1 − ŷ (i) )] (12.12)
m i=0
This cost function can be minimized using the gradient descent algorithm
of the previous chapter.
396 Python with Optimization, ...
F = 1.8C + 32 (12.13)
◦
Thus for example, for a Celsius temperature of 23 C the corresponding value
at the Fahrenheit scale is 73.4◦ F. As a first neural net consider a single neuron
with a single input and a single output, as shown in Figure 12.9. It can be
clearly seen that the correct values for b0 and w0 are 32 and 1.8, respectively.
To train the neural net, a set of correct equivalent temperatures is given
in two arrays as
In this example, Keras from TensorFlow and numpy must be imported first:
import numpy as np
import tensorflow.keras as ks
Keras allows for the design of layers. For the first neural net, only one layer
is used. In Keras this can be done using the Dense layer:
Now in the model, the optimizer and the loss criterion have to be defined. The
Adam optimizer is used with a step of 0.1. A smaller step gives more accuracy
but it takes more time and more runs in the learning process. A larger step is
not as accurate but is faster for the learning process. The loss criterion is the
mean squared error. The model is then:
model.compile(optimizer = ks.optimizers.Adam(0.1), \
loss = ‘mean_squared_error’)
The neural net is ready for training. The parameter epochs refers to how
many times the training process is done. The training is done with
When the training is finished, the message ‘Model has been trained’ can be
printed out. The training history can be plotted with
A plot for the training history is shown in Figure 12.10. It can be seen that
there are no changes close to the 600th epoch. Now, the neural net is tested
with a new Celsius temperature and the result is displayed:
model.compile(optimizer = ks.optimizers.Adam(0.1),
loss = ‘mean_squared_error’)
The result is: 73.30528 which is very close to the correct result of 73.4 ◦ F. It
can be seen that the neural network works correctly.
Next, the neural net is implemented with two more layers with three neu-
rons each which correspond to the hidden layers. The network is shown in
Figure 12.11. The layer named layerIn is replaced with the following layers:
The result for a Celsius temperature of 23◦ C is 73.32 which is very close to
the correct result. The learning process plot is shown in Figure 12.12 and it
can be seen that the learning is faster due to the increased number of layers
in the neural network. The weights are given as:
Example 12.2 A neural net implementation for the XOR logic gate
The XOR logic gate is implemented in this example. It is implemented with
two hidden layers and is an adaptation of the previous example. In this case,
the activation function is added in the hidden and output layers. The activa-
tion function tanh is used in the hidden layers and the sigmoid function is
used in the output layer. With these changes in mind, the final script is:
import tensorflow.keras as ks
# Keras Dense layer is used and the hidden and output layers
are:
hidden1 = ks.layers.Dense(units = 3, input_shape = [2],
activation = ‘tanh’)
hidden2 = ks.layers.Dense(units = 3, activation = ‘tanh’)
Out = ks.layers.Dense(units = 1, activation = ‘sigmoid’)
The result is Y:
[[0.02127211]
[0.9962218 ]
[0.96937585]
[0.02036152]]
The results for Y give the probabilities of the result; thus, the output
should be read as [0, 1, 1, 0], or [False, True, True, False], which is
the correct result.
Continuing the procedure of shifting the mask, the final pixel is obtained as
shown in Figure 12.17 with the value 121. From this figure it can be seen that
the convolved image has been shrinked. It can be shown that the size of the
convolved image is given by
FIGURE 12.14: First step in the convolution of the image and the mask.
406 Python with Optimization, ...
FIGURE 12.15: Second step in the convolution of the image and the mask.
12.6.1 Padding
FIGURE 12.16: Fourth step in the convolution of the image and the mask.
Neural Networks 407
The image convolved with a 3×3 filter and padded with two columns is
and this is the reason that every pixel in the image, either on the edges or in
the inner parts of the image, contribute to the convolution result.
5−3
Size of the convolved image with striding = +1=2 (12.16)
2
12.6.3 Pooling
A form to reduce the size of the processed image is the use of pooling. This
is a technique that divides the image in equal-size parts and then implement
any of two techniques, namely max-pooling and mean-pooling.
Neural Networks 409
A color image has three components corresponding to the three colors red,
green and blue. Each component can be filtered by three different filters
• The input X for this example has 7×7×3 pixels. In the case of a larger
image size; for example, 1024×1024 the image size is 3,145,728 pix-
els. For a layer which is not in the input, the input is the output of a
previous layer which is a[j] . So for the first convolutional layer, the input
corresponds to a[−1].
• The filters are of size 3×3×3 pixels that gives 27 pixels for each filter. If
the total number of filters is 10 then the total for the filters is 270. The
output of the filters are the parameters z[j].
• The output of the filters is an array of size 5×5 for this example. If
the size of the original image is 1024×1024 then the output size is
1022×1022. To this array add the bias coefficient b and then apply the
activation function f . The addition of the bias coefficient adds 1 to the
weight parameters. This gives a total of 28 parameters per filter.
• The activation function is applied to the output of the filters plus the
bias coefficient. The output of the activation function is a[j+1] = f (z[j]).
It is a 5×5 array for each filter.
• The total number of parameters for each filter is 27 weights and the bias
for a total of 28 parameters for each filter.
• The last step in the neural net consists of the flattening of the arrays to
form a one-dimensional vector which is applied to a regular neural layer.
• The strides.
• The padding.
• The activation.
412 Python with Optimization, ...
import tensorflow as tf
import tensorflow_datasets as tfds
Neural Networks 413
The metadata is printed out to see the information it contains, and it is seen
that name, description, amount of data, type of the items, homepage, size,
keys, images and labels, and the citation.
tfds.core.DatasetInfo(
name = ‘fashion_mnist’,
full_name = ‘fashion_mnist/3.0.1’,
description = """
Fashion-MNIST is a dataset of Zalando’s article images
consisting of a training set of 60,000 examples and a test set
of 10,000 examples. Each example is a 28x28 grayscale image,
associated with a label from 10 classes.""",
homepage = ‘https://github.com/zalandoresearch/fashion-mnist’,
data_dir = ‘/root/tensorflow_datasets/fashion_mnist/3.0.1’,
file_format = tfrecord,
download_size = 29.45 MiB,
dataset_size = 36.42 MiB,
features = FeaturesDict({
‘image’: Image(shape=(28, 28, 1), dtype=uint8),
‘label’: ClassLabel(shape=(), dtype=int64, num_classes=10), }),
supervised_keys = (‘image’, ‘label’),
disable_shuffling = False,
splits = {
‘test’: <SplitInfo num_examples = 10000, num_shards = 1>,
‘train’: <SplitInfo num_examples = 60000, num_shards = 1>, },
eprint = {1708.07747},
timestamp = {Mon, 13 Aug 2018 16:47:27 +0200},
biburl = {https://dblp.org/rec/bib/journals/corr/abs-1708
-07747}, bibsource = {dblp computer science bibliography,
https://dblp.org}""",
)
Next, the data is separated into the training data and the testing data:
# Label names:
label_names = metadata.features[’label’].names
print(‘The label names are: ’, label_names)
and it can readily be seen that there are 10 item types. As can be seen in
the metadata, the images are arrays with a size of 28×28×1; that is, they are
gray level images with a type uint8. They are 8-bit numbers with gray-level
values between 0 and 255. They have to be normalized to have values between
0 and 1. First, they have to be converted or cast to floating type and then
normalized. This is done in the function normalize as:
This function is applied to both the training data and the testing data and
then they are put in the cache memory to speed up the process:
training_data = training_data.map(normalize)
testing_data = testing_data.map(normalize)
# Add to cache memory to speed up the process:
training_data = training_data.cache()
testing_data = testing_data.cache()
Neural Networks 415
The model is created with two convolutional networks Conv2D, two pooling
layers MaxPooling2D, a flattening layer Flatten, and a 100-neuron layer. The
model is:
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(32, (3,3), activation =‘relu’ \
, input_shape = (28, 28, 1)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(100, activation =‘relu’),
tf.keras.layers.Dense(10, activation = “softmax”)
])
model.compile(optimizer = ‘adam’,
loss = tf.keras.losses.SparseCategoricalCrossentropy
(from_logits = True), metrics = [‘accuracy’])
training_ex_number = metadata.splits[“train”].num_examples
testing_ex_number = metadata.splits[“test”].num_examples
The fitting of the model is done in batches with a lot size of 64 with:
LOT_SIZE = 64
training_data = training_data.repeat(). \
shuffle(training_ex_number).batch(LOT_SIZE)
testing_data = testing_data.batch(LOT_SIZE)
# Training
import math
Model = model.fit(training_data, epochs = 2, \
steps_per_epoch = math.ceil(training_ex_number/LOT_SIZE))
416 Python with Optimization, ...
Epoch 1/2
938/938 [============] - 61s 57ms/step - loss: 0.4995 -
accuracy: 0.8208
Epoch 2/2
938/938 [============] - 52s 56ms/step - loss: 0.3312 -
accuracy: 0.8794
After the two epochs are finished, the loss has been reduced to 0.3312 and
the accuracy is at 0.8794. These results can be improved by increasing the
number of epochs. Now, some of the elements in a batch are plotted together
with the predictions computed. This is done with two methods as follows:
plt.show()
The plots together with the predictions are shown in Figure 12.25. Finally,
the model is tested with a single image:
Prediction: Pullover
418 Python with Optimization, ...
Model.summary()
=======================================
Total params: 179926 (702.84 KB)
Trainable params: 179926 (702.84 KB)
Non-trainable params: 0 (0.00 Byte)
This summary displays the trainable parameters. The complete file is:
# Shuffle mixes the data so the neural net does not learn
# for a fixed order:
training_data = training_data.repeat(). \
shuffle(training_ex_number).batch(LOT_SIZE)
testing_data = testing_data.batch(LOT_SIZE)
# Training:
import math
history = Model.fit(training_data, epochs=1, \
steps_per_epoch= math.ceil(training_ex_number/LOT_SIZE))
plt.xticks([])
plt.yticks([])
plot1 = plt.bar(range(10), arr_predictions, color =\
“# 777777”)
plt.ylim([0, 1])
label_prediction = np.argmax(arr_predictions)
plot1[label_prediction].set_color(‘red’)
plot1[real_label].set_color(‘blue’)
12.9 Conclusions
This chapter has presented an introduction to neural networks for machine
learning. The examples have been used for classification. The use of an acti-
vation function in the neural networks is used to apply non-linearities to the
neurons and decide if a given neuron is activated. Different activation func-
tions were used in the examples. Multilayer neural networks were used in the
examples and convolutional neural networks were used to classify images. The
examples were solved using TensorFlow and Keras which provide the methods
to implement many of the needs in neural network design and implementation.
Besides being a very complete library of methods, they are both free software,
also called open source and can be downloaded and used without restrictions.
Thus, the chapter provides an introduction to the topic and the use of Python
for the design and implementation of neural networks and it does not pretend
to be a comprehensive chapter on the topic.
Appendix A
Installation of Libraries and Packages
and Running the Scripts
A.1 Introduction
This appendix provides the necessary steps to run the scripts in the book
using Google Colab and to install Python as well as the packages and libraries
needed for the book. Instructions are given for the Windows and Mac OS
operating systems.
https://colab.research.google.com/?authuser = 1
The welcome page is shown in Figure A.1. There are two keywords useful for
the user and they are located above the Welcome message. They are +Code
and +Text. Pressing the word +Code, a cell is open, as shown in Figure A.2 and
there the script can be written. The script (or the cell) can be run by pressing
the play symbol to the left of the cell. An advantage of Google Colab is that
most of the packages used in the book are already installed. The interested
readers can find more information on the welcome window.
Windows
3. Select the latest Python version, 3.12.0 at the time of this writing, and
select the appropriate system, either a 32-bit or a 64-bit architecture.
4. When the download is finished, click on the installation file. Select the
option: “Customize installation”, as shown in Figure A.3.
5. Figure A.4 shows the Optional Features window. Select all the options.
Note that the pip feature is going to be installed. Then choose Next
6. In the next window select the installation folder as C:\Python3x\ and
continue with the default options. (A different folder can be chosen
though). (See Figure A.5).
7. To check if the installation was successful, run the Python IDLE from
the Windows Start menu or from the Search window.
Mac OS X
1. To verify if the operating system is either a 32-bit or a 64-byt architec-
ture, from the Apple icon in the upper left corner choose About this
Mac, and then choose the processor. If the processor is a core or core
duo, the system is a 32-bit system. Otherwise, it is a 64-bit system.
2. Open the website https://www.python.org/ and download the latest
version, 3.12.0 at the time of this writing.
3. To check if the installation was successful, go to Applications and click
on the Python IDLE. If the IDLE window opens then everything is OK.
pip in Windows
2. To check that the pip files are ready to install modules or libraries, open
a Terminal window and type
• Windows
1. Open a command window. Change directory to C:\python312\scripts
and type:
import numpy
The computer then downloads the required files. When the installation is
finished open the Python IDLE and type
Installation of Libraries and Packages and Running the Scripts 429
If the IDLE shows the Python prompt then OpenCV has been successfully
installed.
The computer then downloads the required files. When the installation is
finished open the Python IDLE and type
If the IDLE shows the Python prompt then OpenCV has been succesfully
installed.
Index
*, 84 Axes3D, 254
**, 26
+, 84 BFGS, 262, 283
#, 26 binary, 204
&, 26 binary integer programming, 262
Nelder-Mead, 262 bitwise_not, 327
trust-exact, 262 blobs, 379
‘ ’, 26 bool, 26
“ ”, 26 boolean, 5
“ ‘ ”’, 26 bounded minimization, 262
Broyden-Fletcher-Goldfarb-Shanno,
accumulator, 43 262
activation, 393
activation function, 389 C, 1
Adam, 397, 421 C++, 1
adaptiveThreshold, 327 calcHist, 327
add, 82, 179 capitalize, 70
Al Khuarismi, 4 capture, 327
algorithm, 3 center, 70
alphanumeric, 5, 19 centroid, 378
alphanumeric variables, 19 characters, 19
and, 26 circle, 327
anomaly detection, 377 class, 166
append, 77, 94, 106, 120, 122, 136 classification, 357, 358
arange, 254 clear, 81, 82
arithmetic, 16 close, 189–191, 210
arithmetic operators, 16 cluster, 378
array, 88, 136 cluster_centers, 386
Arthur Samuel, 329 clustering, 377
artificial neural networks, 387 cmap, 254
ASCII, 204 coef_, 348, 354, 386
aspect, 254 color, 254
assignment, 16 colorbar, 254
astype, 136 comma-separated-values, 199
attribute, 165 compile, 421
autopct, 254 compound interest, 24
average, 99 comprehension, 136
431
432 Index
unsupervised, 329
Unsupervised learning, 377
update, 81
upper left, 255
upper right, 255
value, 21, 79
values, 81, 83
variable, 4
variable assignment, 6
variance, 99
vectorization, 211
VideoCapture, 327
VideoWriter, 327
visualization, 377
waitKey, 327
weights, 390
while, 40
wireframe, 255
with, 190, 210
write, 188, 191, 210
writelines, 189, 191, 210
writerow, 210
xlim, 255
XOR, 402
xticks, 255
ylim, 255
zdir, 255
zfill, 72
zlim, 255