1.8 Peticiones de Información
1.8.4 Expte: PI 6764/22 RGEP 16186
however:
>>> x.index(4) 1
despite the fact that number 4 is present twice in the list: .index
function returns an index corresponding to its first occurrence. Of course, you can find the second position of 4 by typing:
>>> -x[::-1].index(4) + (len(x)-1) 3
but it’s too complex and still fails if 4 occurs more than two times.
Solution? Based on what we have discussed so far we get:
>>> [i for i in range(len(x)) if x[i] == 4]
[1, 3]
Smoothly and painlessly.
Therefore, in Code 2.17, a function is_in_num.index(True) will work solely for the first entry of 2 in num. The rest of 2.17 follows a requested logic of building a sentence in English. Note that if a special character of "." is in sc list then we print it three times applying a simple string multiplication (see more in Section 2.8).
2.3.6. Maths and statistics with Lists
Some of the abovementioned methods used in creation of Python’s lists can be accomplished with the enumerate object as provided by enumerate(list) function. Analyse the following program being a modification of Code 2.10.
A bank pays on average 4% p.a. for keeping your money in its savings account. However, the interest rate fluctuates month-over-month. Write a code in Python that (i) simulates those monthly fluctuations; (ii) computes a compound return and your capital growth if you hold $1,000 for a half of a year and compounding takes place monthly.
.index()
Code 2.18
It is a great exercise where Python’s lists can be utilised! First, let’s create in a fancy way a temporary list storing 4% interest rate:
r = [i*0.01 for i in [4]*6]
[0.04, 0.04, 0.04, 0.04, 0.04, 0.04]
Next, it would be nice to get a list of numbers with different signs.
Initially assuming that a negative number represents a decrease of the interest rate month-over-month and a positive number denotes its increase, we start from a simple list:
tmp = [] in Python. But we need pseudo-random fluctuations preserving the sign. With a help of modulo operation, we do it, e.g.:
fluct = []
for i in range(1, 6+1):
if(i % 2 == 0): fluct.append(-1*(i % (i+2*i/10.)/1600.)) else: fluct.append((i % (i+103.5*i/20.)/1600.))
[0.000625, -0.00125, 0.001875, -0.0025, 0.003125, -0.00375]
Since this sequence is still periodic we wish to rearrange the order of those elements. We may employ a function of shuffle(list)
from the random module in the following way:
from random import shuffle, seed seed(2016)
shuffle(fluct)
[-0.00125, 0.000625, 0.003125, 0.001875, -0.0025, -0.00375]
where a quoted shuffled list is obtainable for seed(2016) function when executed. Therefore, the resultant 4% numbers destabilised month-over-month we derive as:
R = [sum(e) for e in zip(r, fluct)]
[0.03875, 0.040625, 0.043125, 0.041875, 0.0375, 0.03625]
Let me take this opportunity to tell you a few words on the use of a new function of zip. Its name suggests that it zips parallel elements (an index-wise zipping) coming from different lists. Have a look at some examples below:
>>> x = range(1, 6); y = [X**2 for X in x]; x Built-In, it still has some applications in modern era of programming (e.g.
in Java).
and
>>> z = [list(e) for e in zip(x, y)]
[[1, 1], [2, 4], [3, 9], [4, 16], [5, 25]]
>>> type(z[2])
<class 'list'>
In fact, we can zip more than two lists. Consider the following:
>>> w = [i**3 for i in range(1, 7)]
>>> x
[1, 2, 3, 4, 5]
>>> y
[1, 4, 9, 16, 25]
>>> w
[1, 8, 27, 64, 125, 216] # one element more than in x and y
>>>
>>> z = [list(e) for e in zip(x, y, w)]
>>> z
[[1, 1, 1], [2, 4, 8], [3, 9, 27], [4, 16, 64], [5, 25, 125]]
but if
>>> w = [i**3 for i in range(1, 4)]; w [1, 8, 27]
>>>
>>> z = [list(e) for e in zip(x, y, w)]; z [[1, 1, 1], [2, 4, 8], [3, 9, 27]]
the process of zipping takes the length of all three lists x, y, and w into account and trims the output accordingly.
Therefore, the line of:
R = [sum(e) for e in zip(r, fluct)]
[0.03875, 0.040625, 0.03625, 0.0375, 0.041875, 0.043125]
in our Code 2.18 returns zipped elements of e being the tuples storing [(0.04, -0.00125), (0.04, 0.000625), ... respectively, and by acting upon each of them with the function of sum, we add both tuple’s elements together (more on sum, next).
The remaining part of the 2.18 is trivial:
The entire Python program being the solution to challenge 2.18 could be compiled as follows:
# a complete Code 2.18
from random import shuffle, seed r = [i*0.01 for i in [4]*6]
fluct = []
for i in range(1, 6+1):
if(i % 2 == 0): fluct.append(-1*(i % (i+2*i/10.)/1600.)) else: fluct.append((i % (i+103.5*i/20.)/1600.))
list Converts a set into a list element.
1 + compR =
6 1Y
i=0
⇣1 + ri
12
⌘
seed(2016) shuffle(fluct)
R = [sum(e) for e in zip(r, fluct)]
tmp = [(1+r/12.) for r in R]
compR = 1
for r in enumerate(tmp):
compR *= r[1]
compR -= 1
sav0 = float(format((1000.), ".2f"))
sav = float(format((1000.*(1+compR)), ".2f")) print("compR = %.5f%%" % (100.*compR)) print("Capital growth from $%s to $%s"\
% (format(sav0, ","), format(sav, ",")))
returning the final output:
compR = 2.00084%
Capital growth from $1,000.00 to $1,020.01
The use and functionality of a new enumerate function you can grasp by the careful analysis of the following code:
r = [-7, -5, -1, 9]
for k in enumerate(r):
print(k) print(k[0]) print(k[1]) print()
(0, -7) 0 -7 (1, -5) 1 -5 (2, -1) 2 -1 (3, 9) 3
9
The running variable of k is a tuple with its first element to be the index of 0, next 1, 2, etc. If there is a need, both running index of i and list’s i-th element, they can be processed concurrently. For a more complete picture, consider the following modification:
r = [[-7, 7], [-5, 5], [-1, 1], [9, -9]]
for k in enumerate(r):
print(k) print(k[0]) print(k[1]) print(k[1][0]) print(k[1][1]) print()
(0, [-7, 7]) 0
[-7, 7]
-7 enumerate
7
(1, [-5, 5]) 1
[-5, 5]
-5 5
(2, [-1, 1]) 2
[-1, 1]
-1 1
(3, [9, -9]) 3
[9, -9]
9 -9
No doubt, it is now much easier to understand the logic standing behind the applicability of the enumerate function.
Ready for more nesting, indexing, and slicing? I bet you are! So, here we go again:
For the following list of s containing some information about two stocks given by tickers, display two most recent prices of their shares at the closure of the trading session and make sure that the latest price is being displayed as the first one.
s = [["AAPL", (409.34, 410.23, 410.98, 399.45)], \ ["IBM", (125.53, 124.95, 125.01, 125.99)]]
for stock in s:
print("%s" % stock[0])
prices = stock[-1][-2:] # more nesting, indexing, slicing!
for p in reversed(prices):
print(" $%.2f" % p) AAPL
$399.45 $410.98 IBM $125.99 $125.01
In this code I used indexing and slicing of stock (a list variable) just to show you how effectively we can refer to any nested element in the list using Python. In this case, a list of s is composed of two inner lists, each storing a string (a ticker) and tuple (close prices of a stock for last four days).
Therefore the price of IBM four days ago pulled out from our
"database" would be:
>>> s[1][1][0] # or s[-1][1][0] since IBM is the last 125.53 # element of the list 's'
and the average price of AAPL over past three days:
>>> sum(s[0][1][-3:])/3 406.8866666666667 sum(list/tuple)
Code 2.19
Please mark in your notes that the sum() function works well for lists and tuples though, as discussed in Section 2.1, to ensure there would be no issues with precision of floats, it is advised applying a function of fsum() from the math module when working with Python 2.7.10 interpreter. For the latter, the benefit is two-fold, namely:
>>> from math import fsum
>>> fsum([1, 2, 3])/3 # better when used in Python 2.7.10 2.0
returns float-type number even if a list or tuple contains integers and we divide the sum by integer.
Python 3.5 comes with a handy module of statistics that equips us with an alternative and quick way to compute of basic mathematical statistics functions, i.e.: the mean, sample and population variance, standard deviation, median, and mode.
Those methods work fluently with Python’s lists. Let’s consider a couple of the most useful examples.
For any plain list of numbers:
>>> import statistics as st
>>> x = range(1, 5) # a list or Python 3.5’s iterator 1, 2, 3, 4
>>> sum(x) 10
>>> st.mean(x) 2.5
>>> st.variance(x) 1.6666666666666667
>>> st.stdev(x) 1.2909944487358056
the last two results have been computed with one degree of freedom, i.e. for the variance defined as a sample variance:
As we will see in Chapter 3, the same is accessible in numpy by:
>>> import numpy as np
>>> np.var(x, ddof=1) 1.6666666666666667
>>> np.std(x, ddof=1) 1.2909944487358056
In order to account for the population measure of spread (zero d.o.f.), use st.pvariance and st.pstdev instead. For measures of central location use st.median(x) or st.mode(x). Visit https://
docs.python.org/3.5/library/statistics.html for more detail.
fsum(list/tuple)
var(x) = 1 N 1
XN i=1
(xi x)¯ 2 .mean()
.variance() .stdev()
.pvariance(), .pstdev() .median(), .mode()
statistics