unit 3 python
unit 3 python
A simple example
Let’s start with a simple example that uses pylab.plot to produce two plots.
import pylab
pylab.plot([1,2,3,4], [1,2,3,4])
pylab.plot([1,4,2,3], [5,6,7,8])
pylab.show()
Executing the code will cause a window to appear on your computer monitor. Its exact
appearance will depend on the operating system on your machine, but it will always look
something like:
The bar at the top contains the name of the window, in this case “Figure 1.” In this example, the
name is generated automatically by pylab.
The middle section of the window contains the plot generated by the two lines of code following
the import statement. The bottom line was generated by the statement pylab.plot([1,2,3,4],
[1,2,3,4]). Notice that the two arguments are lists of the same length. Together, they provide a
sequence of four <x, y> coordinate pairs, [(1,1), (2,2), (3,3),(4,4)]. These are plotted in order, and
then connected by a line. (Pylab automatically chooses the line color for each plot command, but
this can be overridden by an optional argument, as we shall see.) The zig zag plot at the top of
the middle section is produced the same way. It zig zags
because the sequence of Cartesian points being connected is [(1,5), (4,6), (2,7), (3,8)].
pylab.show()
The final line of code, pylab.show() causes the window to appear on the screen. If that line were
not there, the figure would still have been produced, but it would not have been displayed.
import pylab
pylab.figure(1)
pylab.plot([1,2,3,4], [1,2,3,4])
pylab.figure(2)
pylab.plot([1,4,2,3], [5,6,7,8])
pylab.savefig('firstSaved')
pylab.figure(1)
pylab.plot([5,6,7,10])
pylab.savefig('secondSaved')
firstSaved.png
secondSaved.png
One argument
Observe that the last call to pylab.plot is passed only one argument. This argument supplies the Y
values. The corresponding X values are range(len(Y-values)), which is why they range from 0 to
3 in this case.
“Current figure.”
Pylab has a notion of “current figure.” Executing the statement pylab.figure(x) sets the current
figure to the figure numbered x. Subsequently executed pylab commands implicitly refer to that
figure, until another pylab.figure command is executed. This explains why the plot on the left,
which corresponds to the figured numbered 2, is stored in firstSaved.png.
Informative Titles
If we look at the code, we can deduce that this is a plot showing the growth of an initial
investment of $10,000 with at an annually compounded interest rate of 5%. However, this cannot
be easily inferred looking only at the plot itself. That’s a bad thing. All plots should have
informative titles, and all axes should be labeled.
If we add to the end of our code(before show()) the following lines
pylab.title('5% Growth, Compounded Annually')
pylab.xlabel('Years of Compounding')
pylab.ylabel('Value of Principal ($)')
Scatter plots
Alternatively, you may want to plot quantities which have an x and y position. For Example,
plotting the location of stars or galaxies in a field for example such as the plot.
Optional argument
For every plotted curve, there is an optional argument that is a format string indicating the color
and line type of the plot. The letters and symbols of the format string are derived from those used
in MATLAB, and are composed of a color indicator followed by an optional line-style indicator.
The default format string is 'b-', which produces a solid blue line. To plot the the growth in
principal with black circles, one would replace the call
pylab.plot(values, 'ko', )
which produces the plot:
The following format string characters are accepted to control the line style or marker:
character description
'x' x marker
character description
character color
‘b’ blue
‘g’ green
‘r’ red
‘c’ cyan
‘m’ magenta
‘y’ yellow
‘k’ black
‘w’ white
Histograms
Histograms are very often used in science applications and it is highly likely that you will need to
plot them at some point! They are very useful to plot distributions
e.g. what is the distribution of galaxy velocities in my sample? etc. In Matplotlib you use the hist
command to make a histogram. Take a look at the short macro below which makes the plot.
import numpy as np
import pylab as pl
# make an array of random numbers with a gaussian distribution with
# mean = 5.0
# rms = 3.0
# number of points = 1000
data = np.random.normal(5.0, 3.0, 1000)
# make a histogram of the data array
pl.hist(data)
# make plot labels
pl.xlabel(’data’)
pl.show()
It will produce following output:
Mortgages
To install mortgage,
python -m pip install mortgage
simple example
from mortgage import Loan
pylab.plot uses the label keyword argument to associate a string with the plot produced by that
invocation. (This and other keyword arguments must follow any format strings.) A key can then
be added to the figure by calling the function pylab.legend, as shown in Figure. The nontrivial
methods in class Mortgage are plotTotPd and plotNet. The method plotTotPd simply plots the
cumulative total of the payments made. The method plotNet plots an approximation to the total
cost of the mortgage over time by plotting the cash expended minus the equity acquired by
paying off part of the loan.
import pylab
def findPayment(loan, r, m):
return loan*((r*(1+r)**m)/((1+r)**m - 1))
class Mortgage(object):
def __init__(self, loan, r, months):
self.loan = loan
self.rate = r/12.0
self.months = months
self.paid = [0.0]
self.owed = [loan]
self.payment = findPayment(loan, self.rate, months)
self.legend = None
def makePayment(self):
"""Make a payment"""
self.paid.append(self.payment)
reduction = self.payment - self.owed[-1]*self.rate
self.owed.append(self.owed[-1] - reduction)
def getTotalPaid(self):
"""Return the total amount paid so far"""
return sum(self.paid)
def __str__(self):
return self.legend
def plotPayments(self, style):
pylab.plot(self.paid[1:], style, label = self.legend)
def plotBalance(self, style):
pylab.plot(self.owed, style, label = self.legend)
def plotTotPd(self, style):
"""Plot the cumulative total of the payments made"""
totPd = [self.paid[0]]
for i in range(1, len(self.paid)):
totPd.append(totPd[-1] + self.paid[i])
pylab.plot(totPd, style, label = self.legend)
def plotNet(self, style):
"""Plot an approximation to the total cost of the mortgage
over time by plotting the cash expended minus the equity
acquired by paying off part of the loan"""
totPd = [self.paid[0]]
for i in range(1, len(self.paid)):
totPd.append(totPd[-1] + self.paid[i])
#Equity acquired through payments is amount of original loan
# paid to date, which is amount of loan minus what is still owed
equityAcquired = pylab.array([self.loan]*len(self.owed))
equityAcquired = equityAcquired - pylab.array(self.owed)
net = pylab.array(totPd) - equityAcquired
pylab.plot(net, style, label = self.legend)
class Fixed(Mortgage):
def __init__(self, loan, r, months):
Mortgage.__init__(self, loan, r, months)
self.legend = 'Fixed, ' + str(r*100) + '%'
class FixedWithPts(Mortgage):
def __init__(self, loan, r, months, pts):
Mortgage.__init__(self, loan, r, months)
self.pts = pts
self.paid = [loan*(pts/100.0)]
self.legend = 'Fixed, ' + str(r*100) + '%, '\
+ str(pts) + ' points'
class TwoRate(Mortgage):
def __init__(self, loan, r, months, teaserRate, teaserMonths):
Mortgage.__init__(self, loan, teaserRate, months)
self.teaserMonths = teaserMonths
self.teaserRate = teaserRate
self.nextRate = r/12.0
self.legend = str(teaserRate*100)\
+ '% for ' + str(self.teaserMonths)\
+ ' months, then ' + str(r*100) + '%'
def makePayment(self):
if len(self.paid) == self.teaserMonths + 1:
self.rate = self.nextRate
self.payment = findPayment(self.owed[-1], self.rate,
self.months - self.teaserMonths)
Mortgage.makePayment(self)
The next Figure contain functions that can be used to generate plots intended to provide insight
about the different kinds of mortgages. The function plotMortgages generates appropriate titles
and axis labels for each plot, and then uses the methods in MortgagePlots to produce the actual
plots. It uses calls to pylab.figure to ensure that the appropriate plots appear in a given figure. It
uses the index i to select elements from the lists morts and styles in a way that ensures that
different kinds of mortgages are represented in a consistent way across figures. For example,
since the third element in morts is a variable rate mortgage and the third element in styles is 'b:',
the variable-rate mortgage is always plotted using a blue dotted line.
The function compareMortgages generates a list of different mortgages, and simulates making a
series of payments on each, as it did in Chapter 8. It then calls plotMortgages to produce the
plots.
def plotMortgages(morts, amt):
styles = ['b-', 'r-.', 'g:']
payments = 0
cost = 1
balance = 2
netCost = 3
pylab.figure(payments)
pylab.title('Monthly Payments of Different $' + str(amt)+ ' Mortgages')
pylab.xlabel('Months')
pylab.ylabel('Monthly Payments')
pylab.figure(cost)
pylab.title('Cash Outlay of Different $' + str(amt) + ' Mortgages')
pylab.xlabel('Months')
pylab.ylabel('Total Payments')
pylab.figure(balance)
pylab.title('Balance Remaining of $' + str(amt) + ' Mortgages')
pylab.xlabel('Months')
pylab.ylabel('Remaining Loan Balance of $')
pylab.figure(netCost)
pylab.title('Net Cost of $' + str(amt) + ' Mortgages')
pylab.xlabel('Months')
pylab.ylabel('Payments - Equity $')
for i in range(len(morts)):
pylab.figure(payments)
morts[i].plotPayments(styles[i])
pylab.figure(cost)
morts[i].plotTotPd(styles[i])
pylab.figure(balance)
morts[i].plotBalance(styles[i])
pylab.figure(netCost)
morts[i].plotNet(styles[i])
pylab.figure(payments)
pylab.legend(loc = 'upper center')
pylab.figure(cost)
pylab.legend(loc = 'best')
pylab.figure(balance)
pylab.legend(loc = 'best')
pylab.show()
The next two plots show the remaining debt and the total net cost of having the mortgage.
Notice that we are computing the same values over and over again. For example fib gets called
with 3 three times, and each of these calls provokes four additional calls of fib. It doesn’t require
a genius to think that it might be a good idea to record the value returned by the first call, and
then look it up rather than compute it each time it is needed. This is called memoization, and
is the key idea behind dynamic programming.
Figure below contains an implementation of Fibonacci based on this idea. The function fastFib
has a parameter, memo, that it uses to keep track of the numbers it has already evaluated. The
parameter has a default value, the empty dictionary, so that clients of fastFib don’t have to worry
about supplying an initial value for memo. When fastFib is called with an n > 1, it attempts to
look up n in memo. If it is not there (because this is the first time fastFib has been called with
that value), an exception is raised. When this happens, fastFib uses the normal Fibonacci
recurrence, and then stores the result in memo.
A simple solution is to consider all subsets of items and calculate the total weight and value of all
subsets. Consider the only subsets whose total weight is smaller than W. From all such subsets,
pick the maximum value subset.
1) Optimal Substructure:
To consider all subsets of items, there can be two cases for every item: (1) the item is included in
the optimal subset, (2) not included in the optimal set.
Therefore, the maximum value that can be obtained from n items is max of following two values.
1) Maximum value obtained by n-1 items and W weight (excluding nth item).
2) Value of nth item plus maximum value obtained by n-1 items and W minus weight of the nth
item (including nth item).
If weight of nth item is greater than W, then the nth item cannot be included and case 1 is the
only possibility.
2) Overlapping Subproblems
Following is recursive implementation that simply follows the recursive structure mentioned
above.
#A naive recursive implementation of 0-1 Knapsack Problem
# Returns the maximum value that can be put in a knapsack of capacity W
def knapSack(W , wt , val , n):
# Base Case
if n == 0 or W == 0 :
return 0
# If weight of the nth item is more than Knapsack of capacity
# W, then this item cannot be included in the optimal solution
if (wt[n-1] > W):
return knapSack(W , wt , val , n-1)
In the following recursion tree, K() refers to knapSack(). The two parameters indicated in the
following recursion tree are n and W. The recursion tree is for following sample inputs.
wt[] = {1, 1, 1}, W = 2, val[] = {10, 20, 30}
Since suproblems are evaluated again, this problem has Overlapping Subprolems property. So
the 0-1 Knapsack problem has both properties of a dynamic programming problem. Like other
typical Dynamic Programming(DP) problems, recomputations of same subproblems can be
avoided by constructing a temporary array K[][] in bottom up manner. Following is Dynamic
Programming based implementation.
return K[n][W]
n = len(val)
print(knapSack(W, wt, val, n))
Output:
220
Divide/Break
This step involves breaking the problem into smaller sub-problems. Sub-problems should
represent a part of the original problem. This step generally takes a recursive approach to divide
the problem until no sub-problem is further divisible. At this stage, sub-problems become
atomic in nature but still represent some part of the actual problem.
Conquer/Solve
This step receives a lot of smaller sub-problems to be solved. Generally, at this level, the
problems are considered 'solved' on their own.
Merge/Combine
When the smaller sub-problems are solved, this stage recursively combines them until they
formulate a solution of the original problem. This algorithmic approach works recursively and
conquer & merge steps works so close that they appear as one.
1.It deals (involves) three steps at each level of 1.It involves the sequence of four steps:
recursion: o Characterize the structure of
Divide the problem into a number of optimal solutions.
subproblems. o Recursively defines the values of
Conquer the subproblems by solving them optimal solutions.
recursively.
o Compute the value of optimal
Combine the solution to the subproblems into
solutions in a Bottom-up
3. It does more work on subproblems and 3. It solves subproblems only once and
hence has more time consumption. then stores in the table.
6. For example: Merge Sort & Binary Search 6. For example: Matrix Multiplication.
etc.