├── LICENSE ├── README.md ├── code ├── chapter 02 │ ├── chapter 2 │ │ └── chapter2.py │ └── chapter2.py ├── chapter 03 │ └── chapter3.py ├── chapter 04 │ └── chapter4.py ├── chapter 05 │ └── chapter5.py ├── chapter 06 │ └── chapter6.py ├── chapter 07 │ ├── chapter7.py │ ├── circle.py │ └── kids ├── chapter 08 │ └── chapter8.py ├── chapter 09 │ ├── chapter9.py │ └── quiz1grades.txt ├── chapter 10 │ └── chapter10.py ├── chapter 11 │ └── chapter11.py ├── chapter 12 │ └── chapter12.py ├── chapter 13 │ └── chapt13.py ├── chapter 14 │ └── chapter14.py ├── chapter 15 │ └── chapter15.py ├── chapter 16 │ └── chapter16.py ├── chapter 17 │ └── chapter17.py ├── chapter 18 │ └── chapter18.py ├── chapter 19 │ ├── bm_results2012.csv │ └── chapter19.py ├── chapter 20 │ ├── chapter20.py │ ├── launcherData.csv │ └── springData.csv ├── chapter 21 │ ├── bm_results2012.csv │ └── chapter21.py ├── chapter 22 │ ├── chapter22.py │ └── midWestHousingPrices.csv ├── chapter 23 │ ├── US_temperatures.csv │ ├── chapt23.py │ ├── global-fossil-fuel-consumption.csv │ └── wwc2019_q-f.csv ├── chapter 24 │ └── chapt24.py ├── chapter 25 │ ├── chapt25.py │ ├── dentalFormulas.csv │ └── diet.csv └── chapter 26 │ ├── TitanicPassengers.csv │ ├── bm_results2012.csv │ └── chapter26.py ├── cover.jpg └── errata.pdf /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction to Computation and Programming Using Python 2 | 3 | The file [errata](errata.pdf) contains a list of significant known errors in the first and second printings. 4 | 5 | The code for each chapter and any files used by the code are in the folder code files. To download all of the code, click on the green button that says [Code]. That will download all of the files (as a zip file). 6 | 7 | MIT courses based on an earlier edition of this book can be found at: 8 | - [6.0001 Introduction to Computer Science and Programming](https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-0001-introduction-to-computer-science-and-programming-in-python-fall-2016/) 9 | - [6.0002 Introduction to Computational Thinking and Data Science](https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-0002-introduction-to-computational-thinking-and-data-science-fall-2016/) 10 | 11 | ![](cover.jpg) 12 | -------------------------------------------------------------------------------- /code/chapter 02/chapter 2/chapter2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Tue Mar 17 16:05:53 2020 5 | 6 | @author: johnguttag 7 | """ 8 | # # # Code fragment from page 15 9 | # print('Yankees rule!') 10 | # print('But not in Boston!') 11 | # print('Yankees rule,', 'but not in Boston!') 12 | 13 | # # # Code fragment from page 19 14 | # pi = 3 15 | # radius = 11 16 | # area = pi * (radius**2) 17 | # radius = 14 18 | 19 | # # # Code fragment from page 20 20 | # a = 3.14159 21 | # b = 11.2 22 | # c = a*(b**2) 23 | # diameter = 11.2 24 | # pi = 3.14159 25 | # area = pi*(diameter**2) 26 | 27 | # # # Code fragments from page 21 28 | # side = 1 # length of sides of a unit square 29 | # radius = 1 # radius of a unit circle 30 | # # subtract area of unit circle from area of unit square 31 | # area_circle = pi*radius**2 32 | # area_square = side*side 33 | # difference = area_square - area_circle 34 | 35 | # x, y = 2, 3 36 | # x, y = y, x 37 | # print('x =', x) 38 | # print('y =', y) 39 | 40 | # # # Code fragments from page 23 41 | # if x%2 == 0: 42 | # print('Even') 43 | # else: 44 | # print('Odd') 45 | # print('Done with conditional') 46 | 47 | # x = 1111111111111111111111111111111 + 222222222222333222222222 +\ 48 | # 3333333333333333333333333333333 49 | 50 | # # # Code fragments from page 24 51 | # # x = 1111111111111111111111111111111 + 222222222222333222222222 + 52 | # # 3333333333333333333333333333333 53 | 54 | # x = (1111111111111111111111111111111 + 222222222222333222222222 + 55 | # 3333333333333333333333333333333) 56 | 57 | # if x%2 == 0: 58 | # if x%3 == 0: 59 | # print('Divisible by 2 and 3') 60 | # else: 61 | # print('Divisible by 2 and not by 3') 62 | # elif x%3 == 0: 63 | # print('Divisible by 3 and not by 2') 64 | 65 | # # # Test setup for following code 66 | # x = 1 67 | # y = 2 68 | # z = 3 69 | 70 | # if x < y and x < z: 71 | # print('x is least') 72 | # elif y < z: 73 | # print('y is least') 74 | # else: 75 | # print('z is least') 76 | 77 | # # # Code fragments from page 25 78 | # if x%2 != 0 and y%2 != 0 and z%2 != 0: 79 | # print(max(x, y, z)) 80 | # if x%2 != 0 and y%2 != 0 and z%2 == 0: 81 | # print(max(x, y)) 82 | # if x%2 != 0 and y%2 == 0 and z%2 != 0: 83 | # print(max(x, z)) 84 | # if x%2 == 0 and y%2 != 0 and z%2 != 0: 85 | # print(max(y, z)) 86 | # if x%2 != 0 and y%2 == 0 and z%2 == 0: 87 | # print(x) 88 | # if x%2 == 0 and y%2 != 0 and z%2 == 0: 89 | # print(y) 90 | # if x%2 == 0 and y%2 == 0 and z%2 != 0: 91 | # print(z) 92 | # if x%2 == 0 and y%2 == 0 and z%2 == 0: 93 | # print(min(x, y, z)) 94 | 95 | # answer = min(x, y, z) 96 | # if x%2 != 0: 97 | # answer = x 98 | # if y%2 != 0 and y > answer: 99 | # answer = y 100 | # if z%2 != 0 and z > answer: 101 | # answer = z 102 | # print(answer) 103 | 104 | # # # Code fragment from page 26 105 | # print((x if x > z else z) if x > y else (y if y > z else z)) 106 | 107 | # # # Code fragment from page 29 108 | # num = 30000000 109 | # fraction = 1/2 110 | # print(num*fraction, 'is', fraction*100, '%', 'of', num) 111 | # print(num*fraction, 'is', str(fraction*100) + '%', 'of', num) 112 | 113 | # # # Code fragments from page 30 114 | # print(int(num*fraction), 'is', str(fraction*100) + '%', 'of', num) 115 | 116 | # print(f'{int(num*fraction)} is {fraction*100}% of {num}') 117 | 118 | # print(f'{{{3*5}}}') 119 | 120 | # print(f'{3.14159:.2f}') 121 | # print(f'{num*fraction:,.0f} is {fraction*100}% of {num:,}') 122 | 123 | # # # Code fragments from page 31 124 | # name = input('Enter your name: ') 125 | 126 | # print('Are you really ' + name + '?') 127 | # print(f'Are you really {name}?') 128 | 129 | # n = input('Enter an int: ') 130 | # print(type(n)) 131 | 132 | # # # Code fragment from page 32 133 | # print('Mluvíš anglicky?') 134 | # print('क्या आप अंग्रेज़ी बोलते ह�?') 135 | 136 | # # # Code fragments from page 33 137 | # num_x = int(input('How many times should I print the letter X? ')) 138 | # to_print = '' 139 | # if num_x == 1: 140 | # to_print = 'X' 141 | # elif num_x == 2: 142 | # to_print = 'XX' 143 | # elif num_x == 3: 144 | # to_print = 'XXX' 145 | # #... 146 | # print(to_print) 147 | 148 | # # Figure 2-7 149 | x = 0 150 | ans = 0 151 | num_iterations = 0 152 | while (num_iterations != x): 153 | ans = ans + x 154 | num_iterations = num_iterations + 1 155 | print(f'{x}*{x} = {ans}') 156 | 157 | # # # Code fragment from page 36 158 | # #Find a positive integer that is divisible by both 11 and 12 159 | # x = 1 160 | # while True: 161 | # if x%11 == 0 and x%12 == 0: 162 | # break 163 | # x = x + 1 164 | # print(x, 'is divisible by 11 and 12') 165 | 166 | # # # Code fragment from page 37 167 | # total = 0 168 | # for num in (77, 11, 3): 169 | # total = total + num 170 | # print(total) 171 | 172 | # # # Code fragment from page 38 173 | # x = 4 174 | # for i in range(x): 175 | # print(i) 176 | 177 | # # # Figure 2-9 178 | # x = 3 179 | # ans = 0 180 | # for num_iterations in range(abs(x)): 181 | # ans = ans + abs(x) 182 | # print(f'{x}*{x} = {ans}') 183 | 184 | # # # Code fragment from page 38 185 | # for i in range(2): 186 | # print(i) 187 | # i = 0 188 | # print(i) 189 | 190 | # # # Code fragments from page 39 191 | # index = 0 192 | # last_index = 1 193 | # while index <= last_index: 194 | # i = index 195 | # print(i) 196 | # i = 0 197 | # print(i) 198 | # index = index + 1 199 | 200 | # x=1 201 | # for i in range(x): 202 | # print(i) 203 | # x=4 204 | 205 | # x = 4 206 | # for j in range(x): 207 | # for i in range(x): 208 | # x = 2 209 | 210 | # # # Code fragments from page 40 211 | # x = 3 212 | # for j in range(x): 213 | # print('Iteration of outer loop') 214 | # for i in range(x): 215 | # print(' Iteration of inner loop') 216 | # x = 2 217 | 218 | # total = 0 219 | # for c in '12345678': 220 | # total = total + int(c) 221 | # print(total) 222 | -------------------------------------------------------------------------------- /code/chapter 02/chapter2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Tue Mar 17 16:05:53 2020 5 | 6 | @author: johnguttag 7 | """ 8 | # # Code fragment from page 15 9 | print('Yankees rule!') 10 | print('But not in Boston!') 11 | print('Yankees rule,', 'but not in Boston!') 12 | 13 | # # Code fragment from page 19 14 | pi = 3 15 | radius = 11 16 | area = pi * (radius**2) 17 | radius = 14 18 | 19 | # # Code fragment from page 20 20 | a = 3.14159 21 | b = 11.2 22 | c = a*(b**2) 23 | diameter = 11.2 24 | pi = 3.14159 25 | area = pi*(diameter**2) 26 | 27 | # # Code fragments from page 21 28 | side = 1 # length of sides of a unit square 29 | radius = 1 # radius of a unit circle 30 | # subtract area of unit circle from area of unit square 31 | area_circle = pi*radius**2 32 | area_square = side*side 33 | difference = area_square - area_circle 34 | 35 | x, y = 2, 3 36 | x, y = y, x 37 | print('x =', x) 38 | print('y =', y) 39 | 40 | # # Code fragments from page 23 41 | if x%2 == 0: 42 | print('Even') 43 | else: 44 | print('Odd') 45 | print('Done with conditional') 46 | 47 | x = 1111111111111111111111111111111 + 222222222222333222222222 +\ 48 | 3333333333333333333333333333333 49 | 50 | # # Code fragments from page 24 51 | # x = 1111111111111111111111111111111 + 222222222222333222222222 + 52 | # 3333333333333333333333333333333 53 | 54 | x = (1111111111111111111111111111111 + 222222222222333222222222 + 55 | 3333333333333333333333333333333) 56 | 57 | if x%2 == 0: 58 | if x%3 == 0: 59 | print('Divisible by 2 and 3') 60 | else: 61 | print('Divisible by 2 and not by 3') 62 | elif x%3 == 0: 63 | print('Divisible by 3 and not by 2') 64 | 65 | # # Test setup for following code 66 | x = 1 67 | y = 2 68 | z = 3 69 | 70 | if x < y and x < z: 71 | print('x is least') 72 | elif y < z: 73 | print('y is least') 74 | else: 75 | print('z is least') 76 | 77 | # # Code fragments from page 25 78 | if x%2 != 0 and y%2 != 0 and z%2 != 0: 79 | print(max(x, y, z)) 80 | if x%2 != 0 and y%2 != 0 and z%2 == 0: 81 | print(max(x, y)) 82 | if x%2 != 0 and y%2 == 0 and z%2 != 0: 83 | print(max(x, z)) 84 | if x%2 == 0 and y%2 != 0 and z%2 != 0: 85 | print(max(y, z)) 86 | if x%2 != 0 and y%2 == 0 and z%2 == 0: 87 | print(x) 88 | if x%2 == 0 and y%2 != 0 and z%2 == 0: 89 | print(y) 90 | if x%2 == 0 and y%2 == 0 and z%2 != 0: 91 | print(z) 92 | if x%2 == 0 and y%2 == 0 and z%2 == 0: 93 | print(min(x, y, z)) 94 | 95 | answer = min(x, y, z) 96 | if x%2 != 0: 97 | answer = x 98 | if y%2 != 0 and y > answer: 99 | answer = y 100 | if z%2 != 0 and z > answer: 101 | answer = z 102 | print(answer) 103 | 104 | # # Code fragment from page 26 105 | print((x if x > z else z) if x > y else (y if y > z else z)) 106 | 107 | # # Code fragment from page 29 108 | num = 30000000 109 | fraction = 1/2 110 | print(num*fraction, 'is', fraction*100, '%', 'of', num) 111 | print(num*fraction, 'is', str(fraction*100) + '%', 'of', num) 112 | 113 | # # Code fragments from page 30 114 | print(int(num*fraction), 'is', str(fraction*100) + '%', 'of', num) 115 | 116 | print(f'{int(num*fraction)} is {fraction*100}% of {num}') 117 | 118 | print(f'{{{3*5}}}') 119 | 120 | print(f'{3.14159:.2f}') 121 | print(f'{num*fraction:,.0f} is {fraction*100}% of {num:,}') 122 | 123 | # # Code fragments from page 31 124 | name = input('Enter your name: ') 125 | 126 | print('Are you really ' + name + '?') 127 | print(f'Are you really {name}?') 128 | 129 | n = input('Enter an int: ') 130 | print(type(n)) 131 | 132 | # # Code fragment from page 32 133 | print('Mluvíš anglicky?') 134 | print('क्या आप अंग्रेज़ी बोलते ह�?') 135 | 136 | # # Code fragments from page 33 137 | num_x = int(input('How many times should I print the letter X? ')) 138 | to_print = '' 139 | if num_x == 1: 140 | to_print = 'X' 141 | elif num_x == 2: 142 | to_print = 'XX' 143 | elif num_x == 3: 144 | to_print = 'XXX' 145 | #... 146 | print(to_print) 147 | 148 | # # Figure 2-7 149 | x = 3 150 | ans = 0 151 | num_iterations = 0 152 | while (num_iterations < x): 153 | ans = ans + x 154 | num_iterations = num_iterations + 1 155 | print(f'{x}*{x} = {ans}') 156 | 157 | # # Code fragment from page 36 158 | #Find a positive integer that is divisible by both 11 and 12 159 | x = 1 160 | while True: 161 | if x%11 == 0 and x%12 == 0: 162 | break 163 | x = x + 1 164 | print(x, 'is divisible by 11 and 12') 165 | 166 | # # Code fragment from page 37 167 | total = 0 168 | for num in (77, 11, 3): 169 | total = total + num 170 | print(total) 171 | 172 | # # Code fragment from page 38 173 | x = 4 174 | for i in range(x): 175 | print(i) 176 | 177 | # # Figure 2-9 178 | x = 3 179 | ans = 0 180 | for num_iterations in range(abs(x)): 181 | ans = ans + abs(x) 182 | print(f'{x}*{x} = {ans}') 183 | 184 | # # Code fragment from page 38 185 | for i in range(2): 186 | print(i) 187 | i = 0 188 | print(i) 189 | 190 | # # Code fragments from page 39 191 | index = 0 192 | last_index = 1 193 | while index <= last_index: 194 | i = index 195 | print(i) 196 | i = 0 197 | print(i) 198 | index = index + 1 199 | 200 | x=1 201 | for i in range(x): 202 | print(i) 203 | x=4 204 | 205 | x = 4 206 | for j in range(x): 207 | for i in range(x): 208 | x = 2 209 | 210 | # # Code fragments from page 40 211 | x = 3 212 | for j in range(x): 213 | print('Iteration of outer loop') 214 | for i in range(x): 215 | print(' Iteration of inner loop') 216 | x = 2 217 | 218 | total = 0 219 | for c in '12345678': 220 | total = total + int(c) 221 | print(total) 222 | -------------------------------------------------------------------------------- /code/chapter 03/chapter3.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # # Figure 3-1 4 | # # Find the cube root of a perfect cube 5 | # x = int(input('Enter an integer: ')) 6 | # ans = 0 7 | # while ans**3 < abs(x): 8 | # ans = ans + 1 9 | # if ans**3 != abs(x): 10 | # print(x, 'is not a perfect cube') 11 | # else: 12 | # if x < 0: 13 | # ans = -ans 14 | # print('Cube root of', x,'is', ans) 15 | 16 | # #Code fragment on page 47 17 | # max_val = int(input('Enter a postive integer: ')) 18 | # i = 0 19 | # while i < max_val: 20 | # i = i + 1 21 | # print(i) 22 | 23 | # # Figure 3-2 24 | # # Test if an int > 2 is prime. If not, print smallest divisor 25 | # x = int(input('Enter an integer greater than 2: ')) 26 | # smallest_divisor = None 27 | # for guess in range(2, x): 28 | # if x%guess == 0: 29 | # smallest_divisor = guess 30 | # break 31 | # if smallest_divisor != None: 32 | # print('Smallest divisor of', x, 'is', smallest_divisor) 33 | # else: 34 | # print(x, 'is a prime number') 35 | 36 | # # Figure 3-3 37 | # # Test if an int > 2 is prime. If not, print smallest divisor 38 | # x = int(input('Enter an integer greater than 2: ')) 39 | # smallest_divisor = None 40 | # if x%2 == 0: 41 | # smallest_divisor = 2 42 | # else: 43 | # for guess in range(3, x, 2): 44 | # if x%guess == 0: 45 | # smallest_divisor = guess 46 | # break 47 | # if smallest_divisor != None: 48 | # print('Smallest divisor of', x, 'is', smallest_divisor) 49 | # else: 50 | # print(x, 'is a prime number') 51 | # 52 | ## Test if an int > 2 is prime. If not, return smallest divisor 53 | #x = int(input('Enter an integer greater than 2: ')) 54 | #smallest_divisor = None 55 | #if x%2 == 0: 56 | # smallest_divisor = 2 57 | #else: 58 | # for guess in range(3, x, 2): 59 | # if x%guess == 0: 60 | # smallest_divisor = guess 61 | # break 62 | #if smallest_divisor != None: 63 | # print('Smallest divisor of', x, 'is', smallest_divisor) 64 | #else: 65 | # print(x, 'is a prime number') 66 | 67 | # x = 25 # A test case for code in Figure 3-4 68 | # # Figure 3-4 69 | # epsilon = 0.01 70 | # step = epsilon**2 71 | # num_guesses = 0 72 | # ans = 0.0 73 | # while abs(ans**2 - x) >= epsilon and ans <= x: 74 | # ans += step 75 | # num_guesses += 1 76 | # print('number of guesses =', num_guesses) 77 | # if abs(ans**2 - x) >= epsilon: 78 | # print('Failed on square root of', x) 79 | # else: 80 | # print(ans, 'is close to square root of', x) 81 | 82 | # x = 123456 # Another test case for code in Figure 3-4 83 | # epsilon = 0.01 84 | # step = epsilon**2 85 | # num_guesses = 0 86 | # ans = 0.0 87 | # while abs(ans**2 - x) >= epsilon and ans*ans <= x: 88 | # ans += step 89 | # num_guesses += 1 90 | # print('number of guesses =', num_guesses) 91 | # if abs(ans**2 - x) >= epsilon: 92 | # print('Failed on square root of', x) 93 | # else: 94 | # print(ans, 'is close to square root of', x) 95 | 96 | # x = 123456789 # A test case for code in Figure 3-5 97 | # # Figure 3-5 98 | # epsilon = 0.01 99 | # num_guesses, low = 0, 0 100 | # high = max(1, x) 101 | # ans = (high + low)/2 102 | # while abs(ans**2 - x) >= epsilon: 103 | # print('low =', low, 'high =', high, 'ans =', ans) 104 | # num_guesses += 1 105 | # if ans**2 < x: 106 | # low = ans 107 | # else: 108 | # high = ans 109 | # ans = (high + low)/2 110 | # print('number of guesses =', num_guesses) 111 | # print(ans, 'is close to square root of', x) 112 | 113 | # epsilon = 0.01 114 | # x = 65 115 | # # Figure 3-6 116 | # Find lower bound on ans 117 | # lower_bound = 0 118 | # while 2**lower_bound < x: 119 | # lower_bound += 1 120 | # low = lower_bound - 1 121 | # high = lower_bound + 1 122 | # #perform bisection search 123 | # ans = (high + low)/2 124 | # while abs(2**ans - x) >= epsilon: 125 | # if 2**ans < x: 126 | # low = ans 127 | # else: 128 | # high = ans 129 | # ans = (high + low)/2 130 | # print(ans, 'is close to the log base 2 of', x) 131 | 132 | # # Code fragment on page 56 and page 59 133 | # x = 0.0 134 | # for i in range(10): 135 | # x = x + 0.1 136 | # if x == 1.0: 137 | # print(x, '= 1.0') 138 | # else: 139 | # print(x, 'is not 1.0') 140 | 141 | # k = 24 # Test case for Figure 3-7 142 | # # Figure 3-7 143 | # #Newton-Raphson for square root 144 | # #Find x such that x**2 - 24 is within epsilon of 0 145 | # epsilon = 0.01 146 | # guess = k/2 147 | # while abs(guess**2 - k) >= epsilon: 148 | # guess = guess - (((guess**2) - k)/(2*guess)) 149 | # print('Square root of', k, 'is about', guess) 150 | -------------------------------------------------------------------------------- /code/chapter 04/chapter4.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # x = 25 4 | # epsilon = 0.01 5 | 6 | # # Figure 4-1 7 | # #Find approximation to square root of x 8 | # if x < 0: 9 | # print('Does not exist') 10 | # else: 11 | # low = 0 12 | # high = max(1, x) 13 | # ans = (high + low)/2 14 | # while abs(ans**2 - x) >= epsilon: 15 | # if ans**2 < x: 16 | # low = ans 17 | # else: 18 | # high = ans 19 | # ans = (high + low)/2 20 | # print(ans, 'is close to square root of', x) 21 | 22 | # x1 = 25 23 | # epsilon = 0.01 24 | 25 | # # Figure 4-2 26 | # # Find square root of x1 27 | # if x1 < 0: 28 | # print('Does not exist') 29 | # else: 30 | # low = 0 31 | # high = max(1, x1) 32 | # ans = (high + low)/2 33 | # while abs(ans**2 - x1) >= epsilon: 34 | # if ans**2 < x1: 35 | # low = ans 36 | # else: 37 | # high = ans 38 | # ans = (high + low)/2 39 | # x1_root = ans 40 | # x2 = -8 41 | # #find cube root of x2 42 | # if x2 < 0: 43 | # is_pos = False 44 | # x2 = -x2 45 | # else: 46 | # is_pos = True 47 | # low = 0 48 | # high = max(1, x2) 49 | # ans = (high + low)/2 50 | # while abs(ans**3 - x2) >= epsilon: 51 | # if ans**3 < x2: 52 | # low = ans 53 | # else: 54 | # high = ans 55 | # ans = (high + low)/2 56 | # if is_pos: 57 | # x2_root = ans 58 | # else: 59 | # x2_root = -ans 60 | # x2 = -x2 61 | # print('Sum of square root of', x1, 'and cube root of', x2, 62 | # 'is close to', x1_root + x2_root) 63 | 64 | # Function definition on page 66 65 | def max_val(x, y): 66 | if x > y: 67 | return x 68 | else: 69 | return y 70 | 71 | # # Code fragment on page 67 72 | max_val(3, 4) 73 | 74 | # # Figure 4-3 75 | def find_root(x, power, epsilon): 76 | #find interval containing answer 77 | if x < 0 and power%2 == 0: 78 | return None #Negative number has no even-powered roots 79 | low = min(-1, x) 80 | high = max(1, x) 81 | #use bisection search 82 | ans = (high + low)/2 83 | while abs(ans**power - x) >= epsilon: 84 | if ans**power < x: 85 | low = ans 86 | else: 87 | high = ans 88 | ans = (high + low)/2 89 | return ans 90 | 91 | # Figure 4-4 92 | def test_find_root(x_vals, powers, epsilons): 93 | for x in x_vals: 94 | for p in powers: 95 | for e in epsilons: 96 | result = find_root(x, p, e) 97 | if result == None: 98 | val = 'No root exists' 99 | else: 100 | val = 'Okay' 101 | if abs(result**p - x) > e: 102 | val = 'Bad' 103 | print(f'x = {x}, power = {p}, epsilon = {e}: {val}') 104 | 105 | # # Code to test Figure 4-4 106 | x_vals = (0.25, 8, -8) 107 | powers = (1, 2, 3) 108 | epsilons = (0.1, 0.001, 1) 109 | test_find_root(x_vals, powers, epsilons) 110 | 111 | # # Code on page 70 112 | # def print_name(first_name, last_name, reverse): 113 | # if reverse: 114 | # print(last_name + ', ' + first_name) 115 | # else: 116 | # print(first_name, last_name) 117 | 118 | # # Code on page 71 119 | # print_name('Olga', 'Puchmajerova', False) 120 | # print_name('Olga', 'Puchmajerova', reverse = False) 121 | # print_name('Olga', last_name = 'Puchmajerova', reverse = False) 122 | # print_name(last_name = 'Puchmajerova', first_name = 'Olga', 123 | # reverse = False) 124 | 125 | #print_name('Olga', last_name = 'Puchmajerova', False) 126 | 127 | # def print_name(first_name, last_name, reverse = False): 128 | # if reverse: 129 | # print(last_name + ', ' + first_name) 130 | # else: 131 | # print(first_name, last_name) 132 | 133 | # print_name('Olga', 'Puchmajerova') 134 | # print_name('Olga', 'Puchmajerova', True) 135 | # print_name('Olga', 'Puchmajerova', reverse = True) 136 | 137 | # print_name(last_name = 'Puchmajerova', first_name = 'Olga') 138 | 139 | # # Function definition on page 72 140 | def mean(*args): 141 | # Assumes at least one argument and all arguments are numbers 142 | # Returns the mean of the arguments 143 | tot = 0 144 | for a in args: 145 | tot += a 146 | return tot/len(args) 147 | 148 | # # Code on page 73 149 | # def f(x): #name x used as formal parameter 150 | # y = 1 151 | # x = x + y 152 | # print('x =', x) 153 | # return x 154 | 155 | # x = 3 156 | # y = 2 157 | # z = f(x) #value of x used as actual parameter 158 | # print('z =', z) 159 | # print('x =', x) 160 | # print('y =', y) 161 | 162 | 163 | # # Figure 4-5 164 | def f(x): 165 | def g(): 166 | x = 'abc' 167 | print('x =', x) 168 | def h(): 169 | z = x 170 | print('z =', z) 171 | x = x + 1 172 | print('x =', x) 173 | h() 174 | g() 175 | print('x =', x) 176 | return g 177 | 178 | # x = 3 179 | # z = f(x) 180 | # print('x =', x) 181 | # print('z =', z) 182 | # z() 183 | 184 | # # Code on page 77 185 | # def f(): 186 | # print(x) 187 | 188 | # def g(): 189 | # print(x) 190 | # x = 1 191 | 192 | # x = 3 193 | # f() 194 | # x = 3 195 | # g() 196 | 197 | # # Figure 4-7 198 | # def find_root(x, power, epsilon): 199 | # """Assumes x and epsilon int or float, power an int, 200 | # epsilon > 0 & power >= 1 201 | # Returns float y such that y**power is within epsilon of x. 202 | # If such a float does not exist, it returns None""" 203 | # #find interval containing answer 204 | # if x < 0 and power%2 == 0: 205 | # return None 206 | # low = min(-1, x) 207 | # high = max(1, x) 208 | # #use bisection search 209 | # ans = (high + low)/2 210 | # while abs(ans**power - x) >= epsilon: 211 | # if ans**power < x: 212 | # low = ans 213 | # else: 214 | # high = ans 215 | # ans = (high + low)/2 216 | # return ans 217 | 218 | # # Code to test function in Figure 4-7 219 | # e = 0.001 220 | # print(find_root(25, 2, e), find_root(-8, 3, 3), find_root(14, 4, e)) 221 | 222 | # # Header from finger exericise on page 82 223 | def log(x, base, epsilon): 224 | """Assumes x and epsilon int or float, base an int, 225 | x > 1, epsilon > 0 & power >= 1 226 | Returns float y such that base**y is within epsilon of x.""" 227 | 228 | # # Figure 4-8 229 | def find_root_bounds(x, power): 230 | """x a float, power a positive int 231 | return low, high such that low**power <=x and high**power >= x""" 232 | low = min(-1, x) 233 | high = max(1, x) 234 | return low, high 235 | 236 | def bisection_solve(x, power, epsilon, low, high): 237 | """x, epsilon, low, high are floats 238 | epsilon > 0 239 | low <= high and there is an ans between low and high s.t. 240 | ans**power is within epsilon of x 241 | returns ans s.t. ans**power within epsilon of x""" 242 | ans = (high + low)/2 243 | while abs(ans**power - x) >= epsilon: 244 | if ans**power < x: 245 | low = ans 246 | else: 247 | high = ans 248 | ans = (high + low)/2 249 | return ans 250 | 251 | def find_root(x, power, epsilon): 252 | """Assumes x and epsilon int or float, power an int, 253 | epsilon > 0 & power >= 1 254 | Returns float y such that y**power is within epsilon of x. 255 | If such a float does not exist, it returns None""" 256 | if x < 0 and power%2 == 0: 257 | return None #Negative number has no even-powered roots 258 | low, high = find_root_bounds(x, power) 259 | return bisection_solve(x, power, epsilon, low, high) 260 | 261 | # # Code to test Figure 4-8 262 | # x_vals = (0.25, 8, -8) 263 | # powers = (1, 2, 3) 264 | # epsilons = (0.1, 0.001, 1) 265 | # test_find_root(x_vals, powers, epsilons) 266 | 267 | # # Figure 4-9 268 | def bisection_solve(x, eval_ans, epsilon, low, high): 269 | """x, epsilon, low, high are floats 270 | epsilon > 0 271 | eval_ans a function mapping a float to a float 272 | low <= high and there is an ans between low and high s.t. 273 | eval(ans) is within epsilon of x 274 | returns ans s.t. eval(ans) within epsilon of x""" 275 | ans = (high + low)/2 276 | while abs(eval_ans(ans) - x) >= epsilon: 277 | if eval_ans(ans) < x: 278 | low = ans 279 | else: 280 | high = ans 281 | ans = (high + low)/2 282 | return ans 283 | 284 | # # Code from page 85 285 | def square(ans): 286 | return ans**2 287 | 288 | # low, high = find_root_bounds(99, 2) 289 | # print(bisection_solve(99, square, 0.01, low, high)) 290 | 291 | # print(bisection_solve(99, lambda ans: ans**2, 0.01, low, high)) 292 | 293 | # def create_eval_ans(): 294 | # power = input('Enter a positive integer: ') 295 | # return lambda ans: ans**int(power) 296 | 297 | # eval_ans = create_eval_ans() 298 | # print(bisection_solve(99, eval_ans, 0.01, low, high)) 299 | 300 | # # Figure 4-10 301 | def log(x, base, epsilon): 302 | """Assumes x and epsilon int or float, base an int, 303 | x > 1, epsilon > 0 & power >= 1 304 | Returns float y such that base**y is within epsilon of x.""" 305 | def find_log_bounds(x, base): 306 | upper_bound = 0 307 | while base**upper_bound < x: 308 | upper_bound += 1 309 | return upper_bound - 1, upper_bound 310 | low, high = find_log_bounds(x, base) 311 | return bisection_solve(x, lambda ans: base**ans, epsilon, low, high) 312 | 313 | # # Code to test figure 4-10 314 | import math 315 | 316 | def test_log(): 317 | epsilon = 0.001 318 | for b in range(2, 6): 319 | for x in range(1, 100): 320 | if abs(math.log(x, b) - log(x, b, epsilon)) > epsilon: 321 | print('Failed on', x, b) 322 | print('Finished test_log') 323 | 324 | test_log() 325 | 326 | # # Header from Finger exercise on page 87 327 | def find_last(s, sub): 328 | """s and sub are non-empty strings 329 | Returns the index of the last occurrence of sub in s. 330 | Returns None if sub does not occur in s""" -------------------------------------------------------------------------------- /code/chapter 05/chapter5.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # # Code fragment from page 89 4 | # t1 = () 5 | # t2 = (1, 'two', 3) 6 | # print(t1) 7 | # print(t2) 8 | 9 | # # Code fragment from page 90 10 | # t1 = (1, 'two', 3) 11 | # t2 = (t1, 3.25) 12 | # print(t2) 13 | # print((t1 + t2)) 14 | # print((t1 + t2)[3]) 15 | # print((t1 + t2)[2:5]) 16 | 17 | # # Code at top of page 91 18 | # def intersect(t1, t2): 19 | # """Assumes t1 and t2 are tuples 20 | # Returns a tuple containing elements that are in 21 | # both t1 and t2""" 22 | # result = () 23 | # for e in t1: 24 | # if e in t2: 25 | # result += (e,) 26 | # return result 27 | 28 | # print(intersect((1, 'a', 2), ('b', 2, 'a'))) 29 | 30 | # # Code in paragarph starting Section 5.1.1 onpage 91 31 | # x, y = (3, 4) 32 | # print(x, y) 33 | # a, b, c = 'xyz' 34 | # print(a, b, c) 35 | 36 | # # Code at bottom of page 91 37 | # def find_extreme_divisors(n1, n2): 38 | # """Assumes that n1 and n2 are positive ints 39 | # Returns a tuple containing the smallest common divisor > 1 and 40 | # the largest common divisor of n1 & n2. If no common divisor, 41 | # other than 1, returns (None, None)""" 42 | # min_val, max_val = None, None 43 | # for i in range(2, min(n1, n2) + 1): 44 | # if n1%i == 0 and n2%i == 0: 45 | # if min_val == None: 46 | # min_val = i 47 | # max_val = i 48 | # return min_val, max_val 49 | 50 | # # Code on page 92 51 | # min_divisor, max_divisor = find_extreme_divisors(100, 200) 52 | # print(min_divisor, max_divisor) 53 | 54 | # print(range(10)[2:6][2]) 55 | # print(range(0, 7, 2) == range(0, 8, 2)) 56 | # print(range(0, 7, 2) == range(6, -1, -2)) 57 | 58 | # # Code on page 93 59 | # L = ['I did it all', 4, 'love'] 60 | # for e in L: 61 | # print(e) 62 | 63 | # L1 = [1, 2, 3] 64 | # L2 = L1[-1::-1] 65 | # for i in range(len(L1)): 66 | # print(L1[i]*L2[i]) 67 | 68 | # # Code on page 94 69 | # Techs = ['MIT', 'Caltech'] 70 | # Ivys = ['Harvard', 'Yale', 'Brown'] 71 | 72 | # # Code on page 95 73 | # Univs = [Techs, Ivys] 74 | # Univs1 = [['MIT', 'Caltech'], ['Harvard', 'Yale', 'Brown']] 75 | 76 | # print('Univs =', Univs) 77 | # print('Univs1 =', Univs1) 78 | # print(Univs == Univs1) 79 | 80 | # # Code on page 96 81 | # print(Univs == Univs1) #test value equality 82 | # print(id(Univs) == id(Univs1)) #test object equality 83 | # print(Univs is Univs1) #test object equality 84 | # print('Id of Univs =', id(Univs)) 85 | # print('Id of Univs1 =', id(Univs1)) 86 | 87 | # # Code on page 97 88 | # print('Ids of Univs[0] and Univs[1]', id(Univs[0]), id(Univs[1])) 89 | # print('Ids of Univs1[0] and Univs1[1]', id(Univs1[0]), id(Univs1[1])) 90 | 91 | # Techs.append('RPI') 92 | 93 | # # Code on top of page 98 94 | # print('Univs =', Univs) 95 | # print('Univs1 =', Univs1) 96 | 97 | # # Code in middle of page 98 98 | # L1 = [[]]*2 99 | # L2 = [[], []] 100 | # for i in range(len(L1)): 101 | # L1[i].append(i) 102 | # L2[i].append(i) 103 | # print('L1 =', L1, 'but', 'L2 =', L2) 104 | 105 | # # Code for finger exercise on page 98 106 | # L = [1, 2, 3] 107 | # L.append(L) 108 | # print(L is L[-1]) 109 | 110 | # # Code on page 99 111 | # def append_val(val, list_1 = []): 112 | # list_1.append(val) 113 | # print(list_1) 114 | 115 | # append_val(3) 116 | # append_val(4) 117 | 118 | # L1 = [1,2,3] 119 | # L2 = [4,5,6] 120 | # L3 = L1 + L2 121 | # print('L3 =', L3) 122 | # L1.extend(L2) 123 | # print('L1 =', L1) 124 | # L1.append(L2) 125 | # print('L1 =', L1) 126 | 127 | # # Code on page 100 128 | # def remove_dups(L1, L2): 129 | # """Assumes that L1 and L2 are lists. 130 | # Removes any element from L1 that also occurs in L2""" 131 | # for e1 in L1: 132 | # if e1 in L2: 133 | # L1.remove(e1) 134 | # L1 = [1,2,3,4] 135 | # L2 = [1,2,5,6] 136 | # remove_dups(L1, L2) 137 | # print('L1 =', L1) 138 | 139 | # # Corrected version of remove_dups, per paragraph on page 101 140 | # def remove_dups(L1, L2): 141 | # """Assumes that L1 and L2 are lists. 142 | # Removes any element from L1 that also occurs in L2""" 143 | # for e1 in L1.copy(): 144 | # if e1 in L2: 145 | # L1.remove(e1) 146 | # L1 = [1,2,3,4] 147 | # L2 = [1,2,5,6] 148 | # remove_dups(L1, L2) 149 | # print('L1 =', L1) 150 | 151 | # # Code on page 101 (with correction from errata sheet) 152 | # L = [2] 153 | # L1 = [L] 154 | # L2 = L1[:] 155 | # L.append(3) 156 | # print('L1 =', L1, 'L2 =', L2) 157 | 158 | # # Code from page 101 with deepcopy, per pragraph on page 102 159 | import copy 160 | # L = [2] 161 | # L1 = [L] 162 | # L2 = L1[:] 163 | # L2 = copy.deepcopy(L1) 164 | # L.append(3) 165 | # print(f'L1 = {L1}, L2 = {L2}') 166 | 167 | # # Code from page 102 168 | # L1 = [2] 169 | # L2 = [[L1]] 170 | # L3 = copy.deepcopy(L2) 171 | # L1.append(3) 172 | # print('L2 =', L2, 'L3 =', L3) 173 | 174 | # L1 = [2] 175 | # L2 = [L1, L1] 176 | # L3 = copy.deepcopy(L2) 177 | # L3[0].append(3) 178 | # print(L3) 179 | 180 | # # Code from page 103 181 | # print([e**2 for e in range(6)]) 182 | # print([e**2 for e in range(8) if e%2 == 0]) 183 | # print([x**2 for x in [2, 'a', 3, 4.0] if type(x) == int]) 184 | 185 | # L = [(x, y) 186 | # for x in range(6) if x%2 == 0 187 | # for y in range(6) if y%3 == 0] 188 | # print(L) 189 | 190 | # print([[(x,y) for x in range(6) if x%2 == 0] 191 | # for y in range(6) if y%3 == 0]) 192 | 193 | # # Code from page 104 194 | # L = [] 195 | # for x in range(6): 196 | # if x%2 == 0: 197 | # for y in range(6): 198 | # if y%3 == 0: 199 | # L.append((x, y)) 200 | # print(L) 201 | 202 | # [x for x in range(2, 100) if all(x % y != 0 for y in range(3, x))] 203 | 204 | # def gen_primes(): 205 | # primes = [] 206 | # for x in range(2, 100): 207 | # is_prime = True 208 | # for y in range(3, x): 209 | # if x%y == 0: 210 | # is_prime = False 211 | # if is_prime: 212 | # primes.append(x) 213 | # return primes 214 | 215 | # # # Code to test list comprehension on page 104 216 | # e1 = [x for x in range(2, 100) if all(x % y != 0 for y in range(3, x))] 217 | # e2 = gen_primes() 218 | # print((e1 == e2)) 219 | 220 | # # Figure 5-5 on page 105 221 | # def apply_to_each(L, f): 222 | # """Assumes L is a list, f a function 223 | # Mutates L by replacing each element, e, of L by f(e)""" 224 | # for i in range(len(L)): 225 | # L[i] = f(L[i]) 226 | 227 | # L = [1, -2, 3.33] 228 | # print('L =', L) 229 | # print('Apply abs to each element of L.') 230 | # apply_to_each(L, abs) 231 | # print('L =', L) 232 | # print('Apply int to each element of', L) 233 | # apply_to_each(L, int) 234 | # print('L =', L) 235 | # print('Apply squaring to each element of', L) 236 | # apply_to_each(L, lambda x: x**2) 237 | # print('L =', L) 238 | 239 | # # Code from page 106 240 | # print(list(map(str, range(10)))) 241 | # print([str(e) for e in range(10)]) 242 | 243 | # for i in map(lambda x: x**2, [2, 6, 4]): 244 | # print(i) 245 | 246 | # L1 = [1, 28, 36] 247 | # L2 = [2, 57, 9] 248 | # for i in map(min, L1, L2): 249 | # print(i) 250 | 251 | # # Code from page 109 252 | # print('My favorite professor--John G.--rocks'.split(' ')) 253 | # print('My favorite professor--John G.--rocks'.split('-')) 254 | # print('My favorite professor--John G.--rocks'.split('--')) 255 | 256 | # # Code from page 110 257 | # baseball_teams = {'Dodgers', 'Giants', 'Padres', 'Rockies'} 258 | # football_teams = {'Giants', 'Eagles', 'Cardinals', 'Cowboys'} 259 | 260 | # baseball_teams.add('Yankees') 261 | # football_teams.update(['Patriots', 'Jets']) 262 | # print(baseball_teams) 263 | # print(football_teams) 264 | 265 | # # Code from page 111 266 | # print(baseball_teams.union({1, 2})) 267 | # print(baseball_teams.intersection(football_teams)) 268 | # print(baseball_teams.difference(football_teams)) 269 | # print({'Padres', 'Yankees'}.issubset(baseball_teams)) 270 | 271 | # print(baseball_teams | {1, 2}) 272 | # print(baseball_teams & football_teams) 273 | # print(baseball_teams - football_teams) 274 | # print({'Padres', 'Yankees'} <= baseball_teams) 275 | 276 | # # Code from page 112 277 | # month_numbers = {'Jan':1, 'Feb':2, 'Mar':3, 'Apr':4, 'May':5, 278 | # 1:'Jan', 2:'Feb', 3:'Mar', 4:'Apr', 5:'May'} 279 | # print(month_numbers) 280 | # print('The third month is ' + month_numbers[3]) 281 | # dist = month_numbers['Apr'] - month_numbers['Jan'] 282 | # print('Apr and Jan are', dist, 'months apart') 283 | 284 | # month_numbers['June'] = 6 285 | # month_numbers['May'] = 'V' 286 | 287 | # # Figure 5-9 on page 114 288 | # EtoF = {'bread':'pain', 'wine':'vin', 'with':'avec', 'I':'Je', 289 | # 'eat':'mange', 'drink':'bois', 'John':'Jean', 290 | # 'friends':'amis', 'and': 'et', 'of':'du','red':'rouge'} 291 | # FtoE = {'pain':'bread', 'vin':'wine', 'avec':'with', 'Je':'I', 292 | # 'mange':'eat', 'bois':'drink', 'Jean':'John', 293 | # 'amis':'friends', 'et':'and', 'du':'of', 'rouge':'red'} 294 | # dicts = {'English to French':EtoF, 'French to English':FtoE} 295 | 296 | # def translate_word(word, dictionary): 297 | # if word in dictionary: 298 | # return dictionary[word] 299 | # elif word != '': 300 | # return '"' + word + '"' 301 | # return word 302 | 303 | # def translate(phrase, dicts, direction): 304 | # UC_letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 305 | # LC_letters = 'abcdefghijklmnopqrstuvwxyz' 306 | # punctuation = '.,;:?' 307 | # letters = UC_letters + LC_letters 308 | # dictionary = dicts[direction] 309 | # translation = '' 310 | # word = '' 311 | # for c in phrase: 312 | # if c in letters: 313 | # word = word + c 314 | # elif word != '': 315 | # if c in punctuation: 316 | # c = c + ' ' 317 | # translation = (translation + 318 | # translate_word(word, dictionary) + c) 319 | # word = '' 320 | # return f'{translation} {translate_word(word, dictionary)}' 321 | 322 | # print(translate('I drink good red wine, and eat bread.', 323 | # dicts,'English to French')) 324 | # print(translate('Je bois du vin rouge.', 325 | # dicts, 'French to English')) 326 | 327 | # # Code from page 113 328 | # FtoE['bois'] = 'wood' 329 | # print(translate('Je bois du vin rouge.', dicts, 'French to English')) 330 | 331 | # # Code from page 115 332 | # def key_search(L, k): 333 | # for elem in L: 334 | # if elem[0] == k: 335 | # return elem[1] 336 | # return None 337 | 338 | # capitals = {'France': 'Paris', 'Italy': 'Rome', 'Japan': 'Kyoto'} 339 | # for key in capitals: 340 | # print('The capital of', key, 'is', capitals[key]) 341 | 342 | # # Code from page 116 343 | # cities = [] 344 | # for val in capitals.values(): 345 | # cities.append(val) 346 | # print(cities, 'is a list of capital cities') 347 | 348 | # cap_vals = capitals.values() 349 | # print(cap_vals) 350 | # capitals['Japan'] = 'Toyko' 351 | # print(cap_vals) 352 | 353 | # for key, val in capitals.items(): 354 | # print(val, 'is the capital of', key) 355 | 356 | # # Header for finger exercise on page 117 357 | def get_min(d): 358 | """d a dict mapping letters to ints 359 | returns the value in d with the key that occurs first in the 360 | alphabet. E.g., if d = {x = 11, b = 12}, get_min returns 12.""" 361 | 362 | # # Code on page 118 363 | # number_to_word = {1: 'one', 2: 'two', 3: 'three', 4: 'four', 10: 'ten'} 364 | # word_to_number = {w: d for d, w in number_to_word.items()} 365 | # word_to_number = {w: d for d, w in number_to_word.items() if d < 10} 366 | 367 | # # Code on pages 119-120 368 | gen_code_keys = (lambda book, plain_text:( 369 | {c: str(book.find(c)) for c in plain_text})) 370 | 371 | plain_text = 'no is no' 372 | book = 'Once upon a time, in a house in a land far away' 373 | print(gen_code_keys(book, plain_text)) 374 | 375 | Don_Quixote = 'In a village of La Mancha, the name of which I have no desire to call to mind, there lived not long since one of those gentlemen that keep a lance in the lance-rack, an old buckler, a lean hack, and a greyhound for coursing.' 376 | print(gen_code_keys(Don_Quixote, plain_text)) 377 | 378 | encoder = (lambda code_keys, plain_text: 379 | ''.join(['*' + code_keys[c] for c in plain_text])[1:]) 380 | 381 | encrypt = (lambda book, plain_text: 382 | encoder(gen_code_keys(book, plain_text), plain_text)) 383 | 384 | print(encrypt(Don_Quixote, 'no is no')) 385 | 386 | gen_decode_keys = (lambda book, cipher_text: 387 | {s: book[int(s)] for s in cipher_text.split('*')}) 388 | 389 | print(gen_decode_keys(Don_Quixote, '1*13*2*6*57*2*1*13')) 390 | 391 | # # Test string for finger exercise on page 120 392 | '22*13*33*137*59*11*23*11*1*57*6*13*1*2*6*57*2*6*1*22*13*33*137*59*11*23*11*1*57*6*173*7*11' 393 | -------------------------------------------------------------------------------- /code/chapter 06/chapter6.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # # Code from Figure 6-1 on page 124 4 | def fact_iter(n): 5 | """Assumes n an int > 0 6 | Returns n!""" 7 | result = 1 8 | for i in range(1, n+1): 9 | result *= i 10 | return result 11 | 12 | def fact_rec(n): 13 | """Assumes n an int > 0 14 | Returns n!""" 15 | if n == 1: 16 | return n 17 | else: 18 | return n*fact_rec(n - 1) 19 | 20 | # # Figure 6-3 on page 127 21 | # def fib(n): 22 | # """Assumes n int >= 0 23 | # Returns Fibonacci of n""" 24 | # if n == 0 or n == 1: 25 | # return 1 26 | # else: 27 | # return fib(n-1) + fib(n-2) 28 | 29 | # def test_fib(n): 30 | # for i in range(n+1): 31 | # print('fib of', i, '=', fib(i)) 32 | 33 | # test_fib(4) 34 | 35 | # # Figure 6-4 on page 119 36 | def is_palindrome(s): 37 | """Assumes s is a str 38 | Returns True if letters in s form a palindrome; False 39 | otherwise. Non-letters and capitalization are ignored.""" 40 | def to_chars(s): 41 | s = s.lower() 42 | letters = '' 43 | for c in s: 44 | if c in 'abcdefghijklmnopqrstuvwxyz': 45 | letters = letters + c 46 | return letters 47 | def is_pal(s): 48 | if len(s) <= 1: 49 | return True 50 | else: 51 | return s[0] == s[-1] and is_pal(s[1:-1]) 52 | 53 | return is_pal(to_chars(s)) 54 | 55 | # print(is_palindrome('Able was I ere I saw Elba')) 56 | # print(is_palindrome('Able was I ere I saw Atlanta')) 57 | 58 | # # Figure 6-5 on page 131 59 | def is_palindrome(s): 60 | """Assumes s is a str 61 | Returns True if s is a palindrome; False otherwise. 62 | Punctuation marks, blanks, and capitalization are ignored.""" 63 | 64 | def to_chars(s): 65 | s = s.lower() 66 | letters = '' 67 | for c in s: 68 | if c in 'abcdefghijklmnopqrstuvwxyz': 69 | letters = letters + c 70 | return letters 71 | 72 | def is_pal(s): 73 | print(' is_pal called with', s) 74 | if len(s) <= 1: 75 | print(' About to return True from base case') 76 | return True 77 | else: 78 | answer = s[0] == s[-1] and is_pal(s[1:-1]) 79 | print(' About to return', answer, 'for', s) 80 | return answer 81 | 82 | return is_pal(to_chars(s)) 83 | 84 | # print('Try dogGod') 85 | # print(is_palindrome('dogGod')) 86 | # print('Try doGood') 87 | # print(is_palindrome('doGood')) 88 | 89 | # # Figure 6-6 on page 133 90 | def fib(x): 91 | """Assumes x an int >= 0 92 | Returns Fibonacci of x""" 93 | global num_fib_calls 94 | num_fib_calls += 1 95 | if x == 0 or x == 1: 96 | return 1 97 | else: 98 | return fib(x-1) + fib(x-2) 99 | 100 | def test_fib(n): 101 | for i in range(n+1): 102 | global num_fib_calls 103 | num_fib_calls = 0 104 | print('fib of', i, '=', fib(i)) 105 | print('fib called', num_fib_calls, 'times.') 106 | 107 | # test_fib(6) -------------------------------------------------------------------------------- /code/chapter 07/chapter7.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # # Code from page 136 4 | # import circle 5 | 6 | # # pi = 3 7 | # # print(pi) 8 | # # print(circle.pi) 9 | # # print(circle.area(3)) 10 | # # print(circle.circumference(3)) 11 | # # print(circle.sphere_surface(3)) 12 | 13 | # Code from page 137 14 | from circle import * # Note that this will fail if path not set 15 | print(pi) 16 | print(circle.pi) 17 | 18 | # # Code from page 138 19 | # import math 20 | 21 | # x = 8 22 | # print(math.log(x, 2)) 23 | 24 | # # Code from page 139 25 | # import calendar as cal 26 | 27 | # cal_english = cal.TextCalendar() 28 | # print(cal_english.formatmonth(1949, 3)) 29 | 30 | # print(cal.LocaleTextCalendar(locale='fr_FR').formatmonth(2049, 3)) 31 | # print(cal.LocaleTextCalendar(locale='pl_PL').formatmonth(2049, 3)) 32 | # print(cal.LocaleTextCalendar(locale='da_dk').formatmonth(2049, 3)) 33 | 34 | # print(cal.day_name[cal.weekday(2033, 12, 25)]) 35 | 36 | # # Code from page 141 37 | # def find_thanksgiving(year): 38 | # month = cal.monthcalendar(year, 11) 39 | # if month[0][cal.THURSDAY] != 0: 40 | # thanksgiving = month[3][cal.THURSDAY] 41 | # else: 42 | # thanksgiving = month[4][cal.THURSDAY] 43 | # return thanksgiving 44 | 45 | # print('In 2011', 'U.S. Thanksgiving was on November', 46 | # find_thanksgiving(2011)) 47 | 48 | # # Header for finger exercise on page 141 49 | def shopping_days(year): 50 | """year a number >= 1941 51 | returns the number of days between U.S. Thanksgiving and 52 | Christmas in year""" 53 | 54 | # # Code on page 142 55 | # name_handle = open('kids', 'w') 56 | # for i in range(2): 57 | # name = input('Enter name: ') 58 | # name_handle.write(name + '\n') 59 | # name_handle.close() 60 | 61 | # with open('kids', 'r') as name_handle: 62 | # for line in name_handle: 63 | # print(line) 64 | 65 | # name_handle = open('kids', 'w') 66 | # name_handle.write('Michael') 67 | # name_handle.write('Mark') 68 | # name_handle.close() 69 | # name_handle = open('kids', 'r') 70 | # for line in name_handle: 71 | # print(line) 72 | 73 | # name_handle = open('kids', 'a') 74 | # name_handle = open('kids', 'a') 75 | # name_handle.write('David') 76 | # name_handle.write('Andrea') 77 | # name_handle.close() 78 | # name_handle = open('kids', 'r') 79 | # for line in name_handle: 80 | # print(line) 81 | 82 | -------------------------------------------------------------------------------- /code/chapter 07/circle.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # # Figure 7-1 on page 136 4 | pi = 3.14159 5 | 6 | def area(radius): 7 | return pi*(radius**2) 8 | 9 | def circumference(radius): 10 | return 2*pi*radius 11 | 12 | def sphere_surface(radius): 13 | return 4.0*area(radius) 14 | 15 | def sphere_volume(radius): 16 | return (4.0/3.0)*pi*(radius**3) 17 | 18 | -------------------------------------------------------------------------------- /code/chapter 07/kids: -------------------------------------------------------------------------------- 1 | MichaelMarkDavidAndrea -------------------------------------------------------------------------------- /code/chapter 08/chapter8.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # # Code from page 148 4 | def is_smaller(x, y): 5 | """Assumes x and y are ints 6 | Returns True if x is less than y and False otherwise.""" 7 | 8 | # # Code from page 150 9 | def sqrt(x, epsilon): 10 | """Assumes x, epsilon floats 11 | x >= 0 12 | epsilon > 0 13 | Returns result such that 14 | x-epsilon <= result*result <= x+epsilon""" 15 | 16 | # # Code from page 151 17 | def copy(L1, L2): 18 | """Assumes L1, L2 are lists 19 | Mutates L2 to be a copy of L1""" 20 | while len(L2) > 0: #remove all elements from L2 21 | L2.pop() #remove last element of L2 22 | for e in L1: #append L1's elements to initially empty L2 23 | L2.append(e) 24 | 25 | # # Code to test copy (not in book) 26 | # L1 = [1,2,3] 27 | # L2 = [4,5,6] 28 | # copy(L1, L2) 29 | # print(L2) 30 | # copy(L1, L1) 31 | # print(L1) 32 | 33 | # # Code from page 152 34 | def is_prime(x): 35 | """Assumes x is a nonnegative int 36 | Returns True if x is prime; False otherwise""" 37 | if x <= 2: 38 | return False 39 | for i in range(2, x): 40 | if x%i == 0: 41 | return False 42 | return True 43 | 44 | # # Code from page 153 45 | def abs(x): 46 | """Assumes x is an int 47 | Returns x if x>=0 and –x otherwise""" 48 | if x < -1: 49 | return -x 50 | else: 51 | return x 52 | 53 | # # Figure 8-3 from page page 161 54 | def is_pal(x): 55 | """Assumes x is a list 56 | Returns True if the list is a palindrome; False otherwise""" 57 | temp = x 58 | temp.reverse 59 | return temp == x 60 | 61 | def silly(n): 62 | """Assumes n is an int > 0 63 | Gets n inputs from user 64 | Prints 'Yes' if the sequence of inputs forms a palindrome; 65 | 'No' otherwise""" 66 | for i in range(n): 67 | result = [] 68 | elem = input('Enter element: ') 69 | result.append(elem) 70 | if is_pal(result): 71 | print('Yes') 72 | else: 73 | print('No') 74 | 75 | # # Code from page 162 76 | # silly(2) 77 | 78 | # # Code from page 163 79 | def silly(n): 80 | """Assumes n is an int > 0 81 | Gets n inputs from user 82 | Prints 'Yes' if the sequence of inputs forms a palindrome; 83 | 'No' otherwise""" 84 | result = [] 85 | for i in range(n): 86 | elem = input('Enter element: ') 87 | result.append(elem) 88 | print(result) 89 | if is_pal(result): 90 | print('Yes') 91 | else: 92 | print('No') 93 | 94 | # silly(2) 95 | 96 | # # Code from page 164 97 | # def is_pal(x): 98 | # """Assumes x is a list 99 | # Returns True if the list is a palindrome; False otherwise""" 100 | # temp = x[:] 101 | # temp.reverse() 102 | # return temp == x 103 | 104 | # def silly(n): 105 | # """Assumes n is an int > 0 106 | # Gets n inputs from user 107 | # Prints 'Yes' if the sequence of inputs forms a palindrome; 108 | # 'No' otherwise""" 109 | # result = [] 110 | # for i in range(n): 111 | # elem = input('Enter element: ') 112 | # result.append(elem) 113 | # print(result) 114 | # if is_pal(result): 115 | # print('Yes') 116 | # else: 117 | # print('No') 118 | 119 | # silly(2) 120 | 121 | 122 | -------------------------------------------------------------------------------- /code/chapter 09/chapter9.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Code from page 168 4 | # success_failure_ratio = num_successes/num_failures 5 | # print('The success/failure ratio is', success_failure_ratio) 6 | 7 | # Code from page 169 8 | # try: 9 | # success_failure_ratio = num_successes/num_failures 10 | # print('The success/failure ratio is', success_failure_ratio) 11 | # except ZeroDivisionError: 12 | # print('No failures, so the success/failure ratio is undefined.') 13 | 14 | # # Figure 9-1 from page 170 15 | def get_ratios(vect1, vect2): 16 | """Assumes: vect1 and vect2 are equal length lists of numbers 17 | Returns: a list containing the meaningful values of 18 | vect1[i]/vect2[i]""" 19 | ratios = [] 20 | for index in range(len(vect1)): 21 | try: 22 | ratios.append(vect1[index]/vect2[index]) 23 | except ZeroDivisionError: 24 | ratios.append(float('nan')) #nan = Not a Number 25 | except: 26 | raise ValueError('get_ratios called with bad arguments') 27 | return ratios 28 | 29 | # # Code from page 171 30 | # try: 31 | # print(get_ratios([1, 2, 7, 6], [1, 2, 0, 3])) 32 | # print(get_ratios([], [])) 33 | # print(get_ratios([1, 2], [3])) 34 | # except ValueError as msg: 35 | # print(msg) 36 | 37 | # val = int(input('Enter an integer: ')) 38 | # print('The square of the number you entered is', val**2) 39 | 40 | # # Figure 9-1 from page 172 41 | def get_ratios(vect1, vect2): 42 | """Assumes: vect1 and vect2 are lists of equal length of numbers 43 | Returns: a list containing the meaningful values of 44 | vect1[i]/vect2[i]""" 45 | ratios = [] 46 | if len(vect1) != len(vect2): 47 | raise ValueError('get_ratios called with bad arguments') 48 | for index in range(len(vect1)): 49 | vect1_elem = vect1[index] 50 | vect2_elem = vect2[index] 51 | if (type(vect1_elem) not in (int, float))\ 52 | or (type(vect2_elem) not in (int, float)): 53 | raise ValueError('get_ratios called with bad arguments') 54 | if vect2_elem == 0: 55 | ratios.append(float('NaN')) #NaN = Not a Number 56 | else: 57 | ratios.append(vect1_elem/vect2_elem) 58 | return ratios 59 | 60 | # # Code from page 172 61 | # while True: 62 | # val = input('Enter an integer: ') 63 | # try: 64 | # val = int(val) 65 | # print('The square of the number you entered is', val**2) 66 | # break #to exit the while loop 67 | # except ValueError: 68 | # print(val, 'is not an integer') 69 | 70 | # # Code from page 173 71 | def read_int(): 72 | while True: 73 | val = input('Enter an integer: ') 74 | try: 75 | return(int(val)) #convert str to int before returning 76 | except ValueError: 77 | print(val, 'is not an integer') 78 | 79 | def read_val(val_type, request_msg, error_msg): 80 | while True: 81 | val = input(request_msg + ' ') 82 | try: 83 | return(val_type(val)) #convert str to val_typex 84 | except ValueError: 85 | print(val, error_msg) 86 | 87 | # val = read_val(int, 'Enter an integer:', 'is not an integer') 88 | 89 | # # Header from finger exercise on page 175 90 | def find_an_even(L): 91 | """Assumes L is a list of integers 92 | Returns the first even number in L 93 | Raises ValueError if L does not contain an even number""" 94 | 95 | # # Figure 9-1 from page 175 96 | def get_grades(fname): 97 | grades = [] 98 | try: 99 | with open(fname, 'r') as grades_file: 100 | for line in grades_file: 101 | try: 102 | grades.append(float(line)) 103 | except: 104 | raise ValueError('Cannot convert line to float') 105 | except IOError: 106 | raise ValueError('get_grades could not open ' + fname) 107 | return grades 108 | 109 | # try: 110 | # grades = get_grades('quiz1grades.txt') 111 | # grades.sort() 112 | # median = grades[len(grades)//2] 113 | # print('Median grade is', median) 114 | # except ValueError as error_msg: 115 | # print('Whoops.', error_msg) 116 | 117 | -------------------------------------------------------------------------------- /code/chapter 09/quiz1grades.txt: -------------------------------------------------------------------------------- 1 | 83 2 | 76 3 | 94 4 | 85 5 | 82 6 | 85 7 | 74 8 | 84 9 | 92 10 | 95 11 | 99 12 | 93 13 | 79 14 | 77 15 | 93 16 | 76 17 | 94 18 | 74 19 | 99 20 | 70 21 | 84 22 | 97 23 | 82 24 | 85 25 | 77 26 | 95 27 | 97 28 | 100 29 | 83 30 | 87 31 | 75 32 | 84 33 | 82 34 | 80 35 | 100 36 | 91 37 | 74 38 | 93 39 | 73 40 | 98 41 | 81 42 | 80 43 | 79 44 | 76 45 | 80 46 | 86 47 | 94 48 | 73 49 | 74 50 | 78 51 | 74 52 | 89 53 | 93 54 | 86 55 | 78 56 | 84 57 | 94 58 | 82 59 | 89 60 | 85 61 | 72 62 | 78 63 | 92 64 | 75 65 | 81 66 | 83 67 | 85 68 | 81 69 | 73 70 | 86 71 | 80 72 | 80 73 | 74 74 | 88 75 | 78 76 | 76 77 | 94 78 | 84 79 | 71 80 | 70 81 | 91 82 | 93 83 | 80 84 | 80 85 | 86 86 | 78 87 | 70 88 | 90 89 | 80 90 | 90 91 | 86 92 | 74 93 | 78 94 | 91 95 | 94 96 | 76 97 | 70 98 | 85 99 | 89 100 | 72 101 | -------------------------------------------------------------------------------- /code/chapter 10/chapter10.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # # Code from page 179 4 | class Toy(object): 5 | def __init__(self): 6 | self._elems = [] 7 | def add(self, new_elems): 8 | """new_elems is a list""" 9 | self._elems += new_elems 10 | def size(self): 11 | return len(self._elems) 12 | 13 | # print(type(Toy)) 14 | # print(type(Toy.__init__), type(Toy.add), type(Toy.size)) 15 | 16 | # # Code from page 180 17 | # t1 = Toy() 18 | # print(type(t1)) 19 | # print(type(t1.add)) 20 | # t2 = Toy() 21 | # print(t1 is t2) #test for object identity 22 | 23 | # # Code from page 181 24 | # t1 = Toy() 25 | # t2 = Toy() 26 | # t1.add([3, 4]) 27 | # t2.add([4]) 28 | # print(t1.size() + t2.size()) 29 | 30 | # # Figure 10-1 from page 182 31 | class Int_set(object): 32 | """An Int_set is a set of integers""" 33 | #Information about the implementation (not the abstraction): 34 | #Value of a set is represented by a list of ints, self._vals. 35 | #Each int in a set occurs in self._vals exactly once. 36 | 37 | def __init__(self): 38 | """Create an empty set of integers""" 39 | self._vals = [] 40 | 41 | def insert(self, e): 42 | """Assumes e is an integer and inserts e into self""" 43 | if e not in self._vals: 44 | self._vals.append(e) 45 | 46 | def member(self, e): 47 | """Assumes e is an integer 48 | Returns True if e is in self, and False otherwise""" 49 | return e in self._vals 50 | 51 | def remove(self, e): 52 | """Assumes e is an integer and removes e from self 53 | Raises ValueError if e is not in self""" 54 | try: 55 | self._vals.remove(e) 56 | except: 57 | raise ValueError(str(e) + ' not found') 58 | 59 | def get_members(self): 60 | """Returns a list containing the elements of self._ 61 | Nothing can be assumed about the order of the elements""" 62 | return self._vals[:] 63 | 64 | def union(self, other): 65 | """other is an Int_set 66 | mutates self so that it contains exactly the elemnts in self 67 | plus the elements in other.""" 68 | 69 | def __str__(self): 70 | """Returns a string representation of self""" 71 | if self._vals == []: 72 | return '{}' 73 | self._vals.sort() 74 | result = '' 75 | for e in self._vals: 76 | result = result + str(e) + ',' 77 | return f'{{{result[:-1]}}}' 78 | 79 | # # Code from page 183 80 | # s = Int_set() 81 | # s.insert(3) 82 | # print(s.member(3)) 83 | 84 | # # Code from page 184 85 | # s = Int_set() 86 | # s.insert(3) 87 | # s.insert(4) 88 | # print(str(s)) 89 | # print('The value of s is', s) 90 | 91 | # # Header for finger exercise on page 184 92 | def union(self, other): 93 | """other is an Int_set 94 | mutates self so that it contains exactly the elemnts in self 95 | plus the elements in other.""" 96 | 97 | # # Figure 10-2 on page 185 98 | class Toy(object): 99 | def __init__(self): 100 | self._elems = [] 101 | def add(self, new_elems): 102 | """new_elems is a list""" 103 | self._elems += new_elems 104 | def __len__(self): 105 | return len(self._elems) 106 | def __add__(self, other): 107 | new_toy = Toy() 108 | new_toy._elems = self._elems + other._elems 109 | return new_toy 110 | def __eq__(self, other): 111 | return self._elems == other._elems 112 | def __str__(self): 113 | return str(self._elems) 114 | def __hash__(self): 115 | return id(self) 116 | 117 | # t1 = Toy() 118 | # t2 = Toy() 119 | # t1.add([1, 2]) 120 | # t2.add([3, 4]) 121 | # t3 = t1 + t2 122 | # print('The value of t3 is', t3) 123 | # print('The length of t3 is', len(t3)) 124 | # d = {t1: 'A', t2: 'B'} 125 | # print('The value', d[t1], 'is associated with the key t1 in d.') 126 | 127 | # # Import used for class Person 128 | import datetime 129 | 130 | # # Figure 10-3 from page 189 131 | class Person(object): 132 | 133 | def __init__(self, name): 134 | """Assumes name a string. Create a person""" 135 | self._name = name 136 | try: 137 | last_blank = name.rindex(' ') 138 | self._last_name = name[last_blank+1:] 139 | except: 140 | self._last_name = name 141 | self.birthday = None 142 | 143 | def get_name(self): 144 | """Returns self's full name""" 145 | return self._name 146 | 147 | def get_last_name(self): 148 | """Returns self's last name""" 149 | return self._last_name 150 | 151 | def set_birthday(self, birthdate): 152 | """Assumes birthdate is of type datetime.date 153 | Sets self's birthday to birthdate""" 154 | self._birthday = birthdate 155 | 156 | def get_age(self): 157 | """Returns self's current age in days""" 158 | if self._birthday == None: 159 | raise ValueError 160 | return (datetime.date.today() - self._birthday).days 161 | 162 | def __lt__(self, other): 163 | """Assume other a Person 164 | Returns True if self precedes other in alphabetical 165 | order, and False otherwise. Comparison is based on last 166 | names, but if these are the same full names are 167 | compared.""" 168 | if self._last_name == other._last_name: 169 | return self._name < other._name 170 | return self._last_name < other._last_name 171 | 172 | def __str__(self): 173 | """Returns self's name""" 174 | return self._name 175 | 176 | # # Code from page 188 177 | # me = Person('Michael Guttag') 178 | # him = Person('Barack Hussein Obama') 179 | # her = Person('Madonna') 180 | # print(him.get_last_name()) 181 | # him.set_birthday(datetime.date(1961, 8, 4)) 182 | # her.set_birthday(datetime.date(1958, 8, 16)) 183 | # print(him.get_name(), 'is', him.get_age(), 'days old') 184 | 185 | # # Code from page 190 186 | # p_list = [me, him, her] 187 | # for p in p_list: 188 | # print(p) 189 | # p_list.sort() 190 | # for p in p_list: 191 | # print(p) 192 | 193 | # # Figure 10-4 from page 192 194 | class MIT_person(Person): 195 | 196 | _next_id_num = 0 #identification number 197 | 198 | def __init__(self, name): 199 | super().__init__(name) 200 | self._id_num = MIT_person._next_id_num 201 | MIT_person._next_id_num += 1 202 | 203 | def get_id_num(self): 204 | return self._id_num 205 | 206 | def __lt__(self, other): 207 | return self._id_num < other._id_num 208 | 209 | # # Code from page 192 210 | # p1 = MIT_person('Barbara Beaver') 211 | # print(str(p1) + '\'s id number is ' + str(p1.get_id_num())) 212 | 213 | # # Code from page 193 214 | p1 = MIT_person('Mark Guttag') 215 | p2 = MIT_person('Billy Bob Beaver') 216 | p3 = MIT_person('Billy Bob Beaver') 217 | p4 = Person('Billy Bob Beaver') 218 | 219 | # print('p1 < p2 =', p1 < p2) 220 | # print('p3 < p2 =', p3 < p2) 221 | # print('p4 < p1 =', p4 < p1) 222 | 223 | # print('p1 < p4 =', p1 < p4) 224 | 225 | # Finger exercise from page 194 226 | class Politician(Person): 227 | """ A politician is a person that can belong to a political party""" 228 | 229 | def __init__(self, name, party = None): 230 | """name and party are strings""" 231 | 232 | def get_party(self): 233 | """returns the party to which self belongs""" 234 | 235 | def might_agree(self, other): 236 | """returns True if self and other belong to the same part 237 | or at least one of then does not belong to a party""" 238 | 239 | # # Figure 10-5 from page 194 240 | class Student(MIT_person): 241 | pass 242 | 243 | class UG(Student): 244 | def __init__(self, name, class_year): 245 | super().__init__(name) 246 | self._year = class_year 247 | def get_class(self): 248 | return self._year 249 | 250 | class Grad(Student): 251 | pass 252 | 253 | # # Code from page 195 254 | # p5 = Grad('Buzz Aldrin') 255 | # p6 = UG('Billy Beaver', 1984) 256 | # print(p5, 'is a graduate student is', type(p5) == Grad) 257 | # print(p5, 'is an undergraduate student is', type(p5) == UG) 258 | 259 | # # Code from page 195 -- Should be added to class MIT_Person 260 | def is_student(self): 261 | return isinstance(self, Student) 262 | 263 | # print(p5, 'is a student is', p5.is_student()) 264 | # print(p6, 'is a student is', p6.is_student()) 265 | # print(p3, 'is a student is', p3.is_student()) 266 | 267 | # # Code from page 196 268 | class Transfer_student(Student): 269 | 270 | def __init__(self, name, from_school): 271 | MIT_person.__init__(self, name) 272 | self._from_school = from_school 273 | 274 | def get_old_school(self): 275 | return self._from_school 276 | 277 | # # Figure 10-6 from page 198 278 | class Grades(object): 279 | 280 | def __init__(self): 281 | """Create empty grade book""" 282 | self._students = [] 283 | self._grades = {} 284 | self._is_sorted = True 285 | 286 | def add_student(self, student): 287 | """Assumes: student is of type Student 288 | Add student to the grade book""" 289 | if student in self._students: 290 | raise ValueError('Duplicate student') 291 | self._students.append(student) 292 | self._grades[student.get_id_num()] = [] 293 | self._is_sorted = False 294 | 295 | def add_grade(self, student, grade): 296 | """Assumes: grade is a float 297 | Add grade to the list of grades for student""" 298 | try: 299 | self._grades[student.get_id_num()].append(grade) 300 | except: 301 | raise ValueError('Student not in mapping') 302 | 303 | def get_grades(self, student): 304 | """Return a list of grades for student""" 305 | try: 306 | return self._grades[student.get_id_num()][:] 307 | except: 308 | raise ValueError('Student not in mapping') 309 | 310 | def get_students(self): 311 | """Return a sorted list of the students in the grade book""" 312 | if not self._is_sorted: 313 | self._students.sort() 314 | self._is_sorted = True 315 | return self._students[:] 316 | 317 | # def get_students(self): #new version from later in chapter 318 | # """Return the students in the grade book one at a time 319 | # in alphabetical order""" 320 | # if not self._is_sorted: 321 | # self._students.sort() 322 | # self._is_sorted = True 323 | # for s in self._students: 324 | # yield s 325 | 326 | # # Code from page 197 327 | # course = Grades() 328 | # course.add_student(Grad('Bernie')) 329 | # all_students = course.get_students() 330 | # all_students.append(Grad('Liz')) 331 | 332 | # # Figure 10-7 from page 199 333 | def grade_report(course): 334 | """Assumes course is of type Grades""" 335 | report = '' 336 | for s in course.get_students(): 337 | tot = 0.0 338 | num_grades = 0 339 | for g in course.get_grades(s): 340 | tot += g 341 | num_grades += 1 342 | try: 343 | average = tot/num_grades 344 | report = f"{report}\n{s}'s mean grade is {average}" 345 | except ZeroDivisionError: 346 | report = f"{report}\n{s} has no grades" 347 | return report 348 | 349 | # ug1 = UG('Jane Doe', 2021) 350 | # ug2 = UG('Pierce Addison', 2041) 351 | # ug3 = UG('David Henry', 2003) 352 | # g1 = Grad('Billy Buckner') 353 | # g2 = Grad('Bucky F. Dent') 354 | # six_hundred = Grades() 355 | # six_hundred.add_student(ug1) 356 | # six_hundred.add_student(ug2) 357 | # six_hundred.add_student(g1) 358 | # six_hundred.add_student(g2) 359 | # for s in six_hundred.get_students(): 360 | # six_hundred.add_grade(s, 75) 361 | # six_hundred.add_grade(g1, 25) 362 | # six_hundred.add_grade(g2, 100) 363 | # six_hundred.add_student(ug3) 364 | # print(grade_report(six_hundred)) 365 | 366 | # # Figure 10-8 from page 201 367 | class info_hiding(object): 368 | def __init__(self): 369 | self.visible = 'Look at me' 370 | self.__also_visible__ = 'Look at me too' 371 | self.__invisible = 'Don\'t look at me directly' 372 | 373 | def print_visible(self): 374 | print(self.visible) 375 | 376 | def print_invisible(self): 377 | print(self.__invisible) 378 | 379 | def __print_invisible(self): 380 | print(self.__invisible) 381 | 382 | def __print_invisible__(self): 383 | print(self.__invisible) 384 | 385 | # # Code from page 201 386 | # test = info_hiding() 387 | # print(test.visible) 388 | # print(test.__also_visible__) 389 | # print(test.__invisible) 390 | 391 | # test = info_hiding() 392 | # test.print_invisible() 393 | # test.__print_invisible__() 394 | # test.__print_invisible() 395 | 396 | # # Code from page 202 397 | class Sub_class(info_hiding): 398 | def new_print_invisible(self): 399 | print(self.__invisible) 400 | 401 | # test_sub = Sub_class() 402 | # test_sub.new_print_invisible() 403 | 404 | # # Figure 10-9 from page 204 is embedded as a comment in code for Figue 10-7 405 | 406 | # # Code from page 205 407 | # book = Grades() 408 | # book.add_student(Grad('Julie')) 409 | # book.add_student(Grad('Lisa')) 410 | # for s in book.get_students(): 411 | # print(s) 412 | 413 | # # Finger exercise from page 205 414 | def get_students_above(self, grade): 415 | """Return the students a mean grade > g one at a time""" 416 | 417 | # # Figure 10-10 from page 208 418 | def find_payment(loan, r, m): 419 | """Assumes: loan and r are floats, m an int 420 | Returns the monthly payment for a mortgage of size 421 | loan at a monthly rate of r for m months""" 422 | return loan*((r*(1+r)**m)/((1+r)**m - 1)) 423 | 424 | class Mortgage(object): 425 | """Abstract class for building different kinds of mortgages""" 426 | def __init__(self, loan, ann_rate, months): 427 | """Assumes: loan and ann_rate are floats, months an int 428 | Creates a new mortgage of size loan, duration months, and 429 | annual rate ann_rate""" 430 | self._loan = loan 431 | self._rate = ann_rate/12 432 | self._months = months 433 | self._paid = [0.0] 434 | self._outstanding = [loan] 435 | self._payment = find_payment(loan, self._rate, months) 436 | self._legend = None #description of mortgage 437 | 438 | def make_payment(self): 439 | """Make a payment""" 440 | self._paid.append(self._payment) 441 | reduction = self._payment - self._outstanding[-1]*self._rate 442 | self._outstanding.append(self._outstanding[-1] - reduction) 443 | 444 | def get_total_paid(self): 445 | """Return the total amount paid so far""" 446 | return sum(self._paid) 447 | 448 | def __str__(self): 449 | return self._legend 450 | 451 | # Figure 10-11 from page 211 452 | class Fixed(Mortgage): 453 | def __init__(self, loan, r, months): 454 | Mortgage.__init__(self, loan, r, months) 455 | self._legend = f'Fixed, {r*100:.1f}%' 456 | 457 | class Fixed_with_pts(Mortgage): 458 | def __init__(self, loan, r, months, pts): 459 | Mortgage.__init__(self, loan, r, months) 460 | self._pts = pts 461 | self._paid = [loan*(pts/100)] 462 | self._legend = f'Fixed, {r*100:.1f}%, {pts} points' 463 | 464 | class Two_rate(Mortgage): 465 | def __init__(self, loan, r, months, teaser_rate, teaser_months): 466 | Mortgage.__init__(self, loan, teaser_rate, months) 467 | self._teaser_months = teaser_months 468 | self._teaser_rate = teaser_rate 469 | self._nextRate = r/12 470 | self._legend = (f'{100*teaser_rate:.1f}% for ' + 471 | f'{self._teaser_months} months, then {100*r:.1f}%') 472 | 473 | def make_payment(self): 474 | if len(self._paid) == self._teaser_months + 1: 475 | self._rate = self._nextRate 476 | self._payment = find_payment(self._outstanding[-1], 477 | self._rate, 478 | self._months - self._teaser_months) 479 | Mortgage.make_payment(self) 480 | 481 | def compare_mortgages(amt, years, fixed_rate, pts, pts_rate, 482 | var_rate1, var_rate2, var_months): 483 | tot_months = years*12 484 | fixed1 = Fixed(amt, fixed_rate, tot_months) 485 | fixed2 = Fixed_with_pts(amt, pts_rate, tot_months, pts) 486 | two_rate = Two_rate(amt, var_rate2, tot_months, var_rate1, 487 | var_months) 488 | morts = [fixed1, fixed2, two_rate] 489 | for m in range(tot_months): 490 | for mort in morts: 491 | mort.make_payment() 492 | for m in morts: 493 | print(m) 494 | print(f' Total payments = ${m.get_total_paid():,.0f}') 495 | 496 | # # Code from page 210 497 | # compare_mortgages(amt=200000, years=30, fixed_rate=0.035, 498 | # pts = 2, pts_rate=0.03, var_rate1=0.03, 499 | # var_rate2=0.05, var_months=60) 500 | -------------------------------------------------------------------------------- /code/chapter 11/chapter11.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # # Cdoe from page 214 4 | def f(i): 5 | """Assumes i is an int and i >= 0""" 6 | answer = 1 7 | while i >= 1: 8 | answer *= i 9 | i -= 1 10 | return answer 11 | 12 | # # Code from page 215 13 | def linear_search(L, x): 14 | for e in L: 15 | if e == x: 16 | return True 17 | return False 18 | 19 | # # Code from page 216 20 | def fact(n): 21 | """Assumes n is a positive int 22 | Returns n!""" 23 | answer = 1 24 | while n > 1: 25 | answer *= n 26 | n -= 1 27 | return answer 28 | 29 | # # Figure 11-1 from page 217 30 | def square_root_exhaustive(x, epsilon): 31 | """Assumes x and epsilon are positive floats & epsilon < 1 32 | Returns a y such that y*y is within epsilon of x""" 33 | step = epsilon**2 34 | ans = 0.0 35 | while abs(ans**2 - x) >= epsilon and ans*ans <= x: 36 | ans += step 37 | if ans*ans > x: 38 | raise ValueError 39 | return ans 40 | 41 | # # Figure 11-2 from page 217 42 | def square_root_bi(x, epsilon): 43 | """Assumes x and epsilon are positive floats & epsilon < 1 44 | Returns a y such that y*y is within epsilon of x""" 45 | low = 0.0 46 | high = max(1.0, x) 47 | ans = (high + low)/2.0 48 | while abs(ans**2 - x) >= epsilon: 49 | if ans**2 < x: 50 | low = ans 51 | else: 52 | high = ans 53 | ans = (high + low)/2.0 54 | return ans 55 | 56 | # # Figure 11-3 from page 218 57 | def f(x): 58 | """Assume x is an int > 0""" 59 | ans = 0 60 | #Loop that takes constant time 61 | for i in range(1000): 62 | ans += 1 63 | print('Number of additions so far', ans) 64 | #Loop that takes time x 65 | for i in range(x): 66 | ans += 1 67 | print('Number of additions so far', ans) 68 | #Nested loops take time x**2 69 | for i in range(x): 70 | for j in range(x): 71 | ans += 1 72 | ans += 1 73 | print('Number of additions so far', ans) 74 | return ans 75 | 76 | # Code from page 219 77 | f(10) 78 | f(1000) 79 | 80 | # Finger exercise on page 220 81 | def g(L, e): 82 | """L a list of ints, e is an int""" 83 | for i in range(100): 84 | for e1 in L: 85 | if e1 == e: 86 | return True 87 | return False 88 | 89 | def h(L, e): 90 | """L a list of ints, e is an int""" 91 | for i in range(e): 92 | for e1 in L: 93 | if e1 == e: 94 | return True 95 | return False 96 | 97 | # # Code from page 222 98 | def int_to_str(i): 99 | """Assumes i is a nonnegative int 100 | Returns a decimal string representation of i""" 101 | digits = '0123456789' 102 | if i == 0: 103 | return '0' 104 | result = '' 105 | while i > 0: 106 | result = digits[i%10] + result 107 | i = i//10 108 | return result 109 | 110 | 111 | #print(int_to_str(23)) 112 | 113 | def add_digits(n): 114 | """Assumes n is a nonnegative int 115 | Returns the sum of the digits in n""" 116 | string_rep = int_to_str(n) 117 | val = 0 118 | for c in string_rep: 119 | val += int(c) 120 | return val 121 | 122 | #print(add_digits(23)) 123 | 124 | # # Code from page 223 125 | def add_digits(s): 126 | """Assumes s is a string of digits 127 | Returns the sum of the digits in s""" 128 | val = 0 129 | for c in s: 130 | val += int(c) 131 | return val 132 | 133 | # print(add_digits('23')) 134 | 135 | def factorial(x): 136 | """Assumes that x is a positive int 137 | Returns x!""" 138 | if x == 1: 139 | return 1 140 | else: 141 | return x*factorial(x-1) 142 | 143 | # # Figure 11-4 from page 225 144 | def is_subset(L1, L2): 145 | """Assumes L1 and L2 are lists. 146 | Returns True if each element in L1 is also in L2 147 | and False otherwise.""" 148 | for e1 in L1: 149 | matched = False 150 | for e2 in L2: 151 | if e1 == e2: 152 | matched = True 153 | break 154 | if not matched: 155 | return False 156 | return True 157 | 158 | # # Figure 11-5 from page 226 159 | def intersect(L1, L2): 160 | """Assumes: L1 and L2 are lists 161 | Returns a list without duplicates that is the intersection of 162 | L1 and L2""" 163 | #Build a list containing common elements 164 | tmp = [] 165 | for e1 in L1: 166 | for e2 in L2: 167 | if e1 == e2: 168 | tmp.append(e1) 169 | break 170 | #Build a list without duplicates 171 | result = [] 172 | for e in tmp: 173 | if e not in result: 174 | result.append(e) 175 | return result 176 | 177 | # # Figure 11-6 from page 227 178 | def get_binary_rep(n, num_digits): 179 | """Assumes n and numDigits are non-negative ints 180 | Returns a str of length numDigits that is a binary 181 | representation of n""" 182 | result = '' 183 | while n > 0: 184 | result = str(n%2) + result 185 | n = n//2 186 | if len(result) > num_digits: 187 | raise ValueError('not enough digits') 188 | for i in range(num_digits - len(result)): 189 | result = '0' + result 190 | return result 191 | 192 | def gen_powerset(L): 193 | """Assumes L is a list 194 | Returns a list of lists that contains all possible 195 | combinations of the elements of L. E.g., if 196 | L is [1, 2] it will return a list with elements 197 | [], [1], [2], and [1,2].""" 198 | powerset = [] 199 | for i in range(0, 2**len(L)): 200 | bin_str = get_binary_rep(i, len(L)) 201 | subset = [] 202 | for j in range(len(L)): 203 | if bin_str[j] == '1': 204 | subset.append(L[j]) 205 | powerset.append(subset) 206 | return powerset 207 | 208 | 209 | # letters = 'abcdefghijklmnopqrstuvwxyz' 210 | # print(len(gen_powerset(letters[0:10]))) 211 | # print(len(gen_powerset(letters[0:20]))) 212 | 213 | # Code to produce plots in this chapter. Code is not in book 214 | # Don't expect to understand it until after you read chapter on plotting 215 | 216 | import matplotlib.pyplot as plt 217 | import math 218 | 219 | # x_vals = range(1, 100000, 1) 220 | # y_const, y_log = [], [] 221 | # for x in x_vals: 222 | # y_const.append(15) 223 | # y_log.append(math.log2(x)) 224 | # plt.plot(x_vals, y_const, 'r--', label = 'constant') 225 | # plt.plot(x_vals, y_log, 'k-', label = 'log') 226 | # plt.xlabel('Input Size') 227 | # plt.ylabel('Time') 228 | # plt.title('Constant (15) vs. Log (base 2)') 229 | # plt.legend() 230 | 231 | # plt.figure() 232 | # x_vals = range(1, 100000, 1) 233 | # y_log, y_linear = [], [] 234 | # for x in x_vals: 235 | # y_linear.append(x) 236 | # y_log.append(math.log2(x)) 237 | # plt.plot(x_vals, y_linear, 'r--', label = 'linear') 238 | # plt.plot(x_vals, y_log, 'k-', label = 'log') 239 | # plt.xlabel('Input Size') 240 | # plt.ylabel('Time') 241 | # plt.title('Log (base 2) vs. Linear') 242 | # plt.legend() 243 | 244 | # plt.figure() 245 | # x_vals = range(1, 1000, 1) 246 | # y_log_linear, y_linear = [], [] 247 | # for x in x_vals: 248 | # y_linear.append(x) 249 | # y_log_linear.append(x*math.log2(x)) 250 | # plt.plot(x_vals, y_linear, 'r--', label = 'linear') 251 | # plt.plot(x_vals, y_log_linear, 'k-', label = 'log-linear') 252 | # plt.xlabel('Input Size') 253 | # plt.ylabel('Time') 254 | # plt.title('Linear vs. Log-linear') 255 | # plt.legend() 256 | 257 | # plt.figure() 258 | # x_vals = range(1, 1000, 1) 259 | # y_log_linear, y_quadratic = [], [] 260 | # for x in x_vals: 261 | # y_quadratic.append(x**2) 262 | # y_log_linear.append(x*math.log2(x)) 263 | # plt.plot(x_vals, y_quadratic, 'r--', label = 'quadratioc') 264 | # plt.plot(x_vals, y_log_linear, 'k-', label = 'log-linear') 265 | # plt.xlabel('Input Size') 266 | # plt.ylabel('Time') 267 | # plt.title('Log-linear vs. Quadratic') 268 | # plt.legend() 269 | 270 | # plt.figure() 271 | # x_vals = range(1, 100, 1) 272 | # y_quad, y_exp = [], [] 273 | # for x in x_vals: 274 | # y_quad.append(x**2) 275 | # y_exp.append(2**x) 276 | # plt.plot(x_vals, y_quad, 'r--', label = 'quadratic') 277 | # plt.plot(x_vals, y_exp, 'k-', label = 'exponential') 278 | # plt.xlabel('Input Size') 279 | # plt.ylabel('Time') 280 | # plt.title('Quadratic vs. Exponential') 281 | # plt.legend() 282 | 283 | # plt.semilogy() 284 | -------------------------------------------------------------------------------- /code/chapter 12/chapter12.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # # Code from page 235 4 | # for i in range(len(L)): 5 | # if L[i] == e: 6 | # return True 7 | # return False 8 | 9 | # # Figure 12-2 from page 238 10 | def search(L, e): 11 | """Assumes L is a list, the elements of which are in 12 | ascending order. 13 | Returns True if e is in L and False otherwise""" 14 | for i in range(len(L)): 15 | if L[i] == e: 16 | return True 17 | if L[i] > e: 18 | return False 19 | return False 20 | 21 | # L = [1,2,3,4,5] 22 | # print(search(L, 4)) 23 | # print(search(L, 2.4)) 24 | 25 | # # Figure 12-3 from page 239 26 | def search(L, e): 27 | """Assumes L is a list, the elements of which are in 28 | ascending order. 29 | Returns True if e is in L and False otherwise""" 30 | 31 | def bin_search(L, e, low, high): 32 | #Decrements high - low 33 | if high == low: 34 | return L[low] == e 35 | mid = (low + high)//2 36 | if L[mid] == e: 37 | return True 38 | elif L[mid] > e: 39 | if low == mid: #nothing left to search 40 | return False 41 | else: 42 | return bin_search(L, e, low, mid - 1) 43 | else: 44 | return bin_search(L, e, mid + 1, high) 45 | 46 | if len(L) == 0: 47 | return False 48 | else: 49 | return bin_search(L, e, 0, len(L) - 1) 50 | 51 | # L = [1,2,3,4,5] 52 | # print(search(L, 4)) 53 | # print(search(L, 2.4)) 54 | 55 | # # Figure 12-4 from page 243 56 | def sel_sort(L): 57 | """Assumes that L is a list of elements that can be 58 | compared using >. 59 | Sorts L in ascending order""" 60 | suffix_start = 0 61 | while suffix_start != len(L): 62 | #look at each element in suffix 63 | for i in range(suffix_start, len(L)): 64 | if L[i] < L[suffix_start]: 65 | #swap position of elements 66 | L[suffix_start], L[i] = L[i], L[suffix_start] 67 | suffix_start += 1 68 | 69 | # # Figure 12-5 from page 245 70 | def merge(left, right, compare): 71 | """Assumes left and right are sorted lists and 72 | compare defines an ordering on the elements. 73 | Returns a new sorted (by compare) list containing the 74 | same elements as (left + right) would contain.""" 75 | 76 | result = [] 77 | i,j = 0, 0 78 | while i < len(left) and j < len(right): 79 | if compare(left[i], right[j]): 80 | result.append(left[i]) 81 | i += 1 82 | else: 83 | result.append(right[j]) 84 | j += 1 85 | while (i < len(left)): 86 | result.append(left[i]) 87 | i += 1 88 | while (j < len(right)): 89 | result.append(right[j]) 90 | j += 1 91 | return result 92 | 93 | def merge_sort(L, compare = lambda x, y: x < y): 94 | """Assumes L is a list, compare defines an ordering 95 | on elements of L 96 | Returns a new sorted list with the same elements as L""" 97 | if len(L) < 2: 98 | return L[:] 99 | else: 100 | middle = len(L)//2 101 | left = merge_sort(L[:middle], compare) 102 | right = merge_sort(L[middle:], compare) 103 | return merge(left, right, compare) 104 | 105 | # # Code from page 246 106 | # L = [2,1,4,5,3] 107 | # print(merge_sort(L), merge_sort(L, lambda x, y: x > y)) 108 | 109 | # # Figure 12-6 from page 248 110 | def last_name_first_name(name1, name2): 111 | arg1 = name1.split(' ') 112 | arg2 = name2.split(' ') 113 | if arg1[1] != arg2[1]: 114 | return arg1[1] < arg2[1] 115 | else: #last names the same, sort by first name 116 | return arg1[0] < arg2[0] 117 | def first_name_last_name(name1, name2): 118 | arg1 = name1.split(' ') 119 | arg2 = name2.split(' ') 120 | if arg1[0] != arg2[0]: 121 | return arg1[0] < arg2[0] 122 | else: #first names the same, sort by last name 123 | return arg1[1] < arg2[1] 124 | 125 | # L = ['Tom Brady', 'Eric Grimson', 'Gisele Bundchen'] 126 | # newL = merge_sort(L, last_name_first_name) 127 | # print('Sorted by last name =', newL) 128 | # newL = merge_sort(L, first_name_last_name) 129 | # print('Sorted by first name =', newL) 130 | 131 | # # Code from page 248 132 | # L = [3,5,2] 133 | # D = {'a':12, 'c':5, 'b':'dog'} 134 | # print(sorted(L)) 135 | # print(L) 136 | # L.sort() 137 | # print(L) 138 | # print(sorted(D)) 139 | # D.sort() 140 | 141 | # # Code from page 249 142 | # L = [[1,2,3], (3,2,1,0), 'abc'] 143 | # print(sorted(L, key = len, reverse = True)) 144 | 145 | # # Figure 12-7 from page 252 146 | class Int_dict(object): 147 | """A dictionary with integer keys""" 148 | 149 | def __init__(self, num_buckets): 150 | """Create an empty dictionary""" 151 | self.buckets = [] 152 | self.num_buckets = num_buckets 153 | for i in range(num_buckets): 154 | self.buckets.append([]) 155 | 156 | def add_entry(self, key, dict_val): 157 | """Assumes key an int. Adds an entry.""" 158 | hash_bucket = self.buckets[key%self.num_buckets] 159 | for i in range(len(hash_bucket)): 160 | if hash_bucket[i][0] == key: 161 | hash_bucket[i] = (key, dict_val) 162 | return 163 | hash_bucket.append((key, dict_val)) 164 | 165 | def get_value(self, key): 166 | """Assumes key an int. 167 | Returns value associated with key""" 168 | hash_bucket = self.buckets[key%self.num_buckets] 169 | for e in hash_bucket: 170 | if e[0] == key: 171 | return e[1] 172 | return None 173 | 174 | def __str__(self): 175 | result = '{' 176 | for b in self.buckets: 177 | for e in b: 178 | result += f'{e[0]}:{e[1]},' 179 | return result[:-1] + '}' #result[:-1] omits the last comma 180 | 181 | # # Code from page 253 182 | # import random 183 | # random.seed(1) # So results are consistent 184 | # D = Int_dict(17) 185 | # for i in range(20): 186 | # #choose a random int in the range 0 to 10**5 - 1 187 | # key = random.choice(range(10**5)) 188 | # D.add_entry(key, i) 189 | # print('The value of the Int_dict is:') 190 | # print(D) 191 | # print('The buckets are:') 192 | # for hash_bucket in D.buckets: #violates abstraction barrier 193 | # print(' ', hash_bucket) 194 | -------------------------------------------------------------------------------- /code/chapter 13/chapt13.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | 6 | #set line width 7 | plt.rcParams['lines.linewidth'] = 4 8 | #set font size for titles 9 | plt.rcParams['axes.titlesize'] = 20 10 | #set font size for labels on axes 11 | plt.rcParams['axes.labelsize'] = 20 12 | #set size of numbers on x-axis 13 | plt.rcParams['xtick.labelsize'] = 16 14 | #set size of numbers on y-axis 15 | plt.rcParams['ytick.labelsize'] = 16 16 | #set size of ticks on x-axis 17 | plt.rcParams['xtick.major.size'] = 7 18 | #set size of ticks on y-axis 19 | plt.rcParams['ytick.major.size'] = 7 20 | #set size of markers, e.g., circles representing points 21 | plt.rcParams['lines.markersize'] = 10 22 | #set number of times marker is shown when displaying legend 23 | plt.rcParams['legend.numpoints'] = 1 24 | #Set size of type in legend 25 | plt.rcParams['legend.fontsize'] = 14 26 | 27 | 28 | # # Code from page 258 29 | # plt.plot([1,2,3,4], [1,7,3,5]) #draw on current figure 30 | 31 | # # Code from page 259 32 | # plt.figure(1) #create figure 1 33 | # plt.plot([1,2,3,4], [1,2,3,4]) #draw on figure 1 34 | # plt.figure(2) #create figure 2 35 | # plt.plot([1,4,2,3], [5,6,7,8]) #draw on figure 2 36 | # plt.savefig('Figure-Addie') #save figure 2 37 | # plt.figure(1) #go back to working on figure 1 38 | # plt.plot([5,6,10,3]) #draw again on figure 1 39 | # plt.savefig('Figure-Jane') #save figure 1 40 | 41 | # # Code from page 260 42 | # principal = 10000 #initial investment 43 | # interest_rate = 0.05 44 | # years = 20 45 | # values = [] 46 | # for i in range(years + 1): 47 | # values.append(principal) 48 | # principal += principal*interest_rate 49 | # plt.plot(values) 50 | 51 | # plt.title('5% Growth, Compounded Annually') 52 | # plt.xlabel('Years of Compounding') 53 | # plt.ylabel('Value of Principal ($)') 54 | 55 | # # Code from page 261 56 | # principal = 10000 #initial investment 57 | # interestRate = 0.05 58 | # years = 20 59 | # values = [] 60 | # for i in range(years + 1): 61 | # values.append(principal) 62 | # principal += principal*interestRate 63 | # plt.plot(values, '-k', linewidth = 30) 64 | # plt.title('5% Growth, Compounded Annually', 65 | # fontsize = 'xx-large') 66 | # plt.xlabel('Years of Compounding', fontsize = 'x-small') 67 | # plt.ylabel('Value of Principal ($)') 68 | 69 | # # The function find_payment is from Figure 10-10 70 | def find_payment(loan, r, m): 71 | """Assumes: loan and r are floats, m an int 72 | Returns the monthly payment for a mortgage of size 73 | loan at a monthly rate of r for m months""" 74 | return loan*((r*(1+r)**m)/((1+r)**m - 1)) 75 | 76 | # # Figure 13-7 from page 264 77 | class Mortgage(object): 78 | """Abstract class for building different kinds of mortgages""" 79 | def __init__(self, loan, annRate, months): 80 | self._loan = loan 81 | self._rate = annRate/12.0 82 | self._months = months 83 | self._paid = [0.0] 84 | self._outstanding = [loan] 85 | self._payment = find_payment(loan, self._rate, months) 86 | self._legend = None #description of mortgage 87 | 88 | def make_payment(self): 89 | self._paid.append(self._payment) 90 | reduction = self._payment - self._outstanding[-1]*self._rate 91 | self._outstanding.append(self._outstanding[-1] - reduction) 92 | 93 | def get_total_paid(self): 94 | return sum(self._paid) 95 | def __str__(self): 96 | return self._legend 97 | 98 | def plot_payments(self, style): 99 | plt.plot(self._paid[1:], style, label = self._legend) 100 | 101 | def plot_balance(self, style): 102 | plt.plot(self._outstanding, style, label = self._legend) 103 | 104 | def plot_tot_pd(self, style): 105 | tot_pd = [self._paid[0]] 106 | for i in range(1, len(self._paid)): 107 | tot_pd.append(tot_pd[-1] + self._paid[i]) 108 | plt.plot(tot_pd, style, label = self._legend) 109 | 110 | def plot_net(self, style): 111 | tot_pd = [self._paid[0]] 112 | for i in range(1, len(self._paid)): 113 | tot_pd.append(tot_pd[-1] + self._paid[i]) 114 | equity_acquired = np.array([self._loan]*len(self._outstanding)) 115 | equity_acquired = equity_acquired-np.array(self._outstanding) 116 | net = np.array(tot_pd) - equity_acquired 117 | plt.plot(net, style, label = self._legend) 118 | 119 | # # Code from page 265 120 | # a1 = np.array([1, 2, 4]) 121 | # print('a1 =', a1) 122 | # a2 = a1*2 123 | # print('a2 =', a2) 124 | # print('a1 + 3 =', a1 + 3) 125 | # print('3 - a1 =', 3 - a1) 126 | # print('a1 - a2 =', a1 - a2) 127 | # print('a1*a2 =', a1*a2) 128 | 129 | # Code from Figure 13-8 on page 267 130 | class Fixed(Mortgage): 131 | def __init__(self, loan, r, months): 132 | Mortgage.__init__(self, loan, r, months) 133 | self._legend = f'Fixed, {r*100:.1f}%' 134 | 135 | class Fixed_with_pts(Mortgage): 136 | def __init__(self, loan, r, months, pts): 137 | Mortgage.__init__(self, loan, r, months) 138 | self._pts = pts 139 | self._paid = [loan*(pts/100)] 140 | self._legend = f'Fixed, {r*100:.1f}%, {pts} points' 141 | 142 | class Two_rate(Mortgage): 143 | def __init__(self, loan, r, months, teaser_rate, teaser_months): 144 | Mortgage.__init__(self, loan, teaser_rate, months) 145 | self._teaser_months = teaser_months 146 | self._teaser_rate = teaser_rate 147 | self._nextRate = r/12 148 | self._legend = (f'{100*teaser_rate:.1f}% for ' + 149 | f'{self._teaser_months} months, then {100*r:.1f}%') 150 | 151 | def make_payment(self): 152 | if len(self._paid) == self._teaser_months + 1: 153 | self._rate = self._nextRate 154 | self._payment = find_payment(self._outstanding[-1], 155 | self._rate, 156 | self._months - self._teaser_months) 157 | Mortgage.make_payment(self) 158 | 159 | # Code from Figure 13-9 on page 268 160 | def compare_mortgages(amt, years, fixed_rate, pts, pts_rate, 161 | var_rate1, var_rate2, var_months): 162 | tot_months = years*12 163 | fixed1 = Fixed(amt, fixed_rate, tot_months) 164 | fixed2 = Fixed_with_pts(amt, pts_rate, tot_months, pts) 165 | two_rate = Two_rate(amt, var_rate2, tot_months, var_rate1, var_months) 166 | morts = [fixed1, fixed2, two_rate] 167 | for m in range(tot_months): 168 | for mort in morts: 169 | mort.make_payment() 170 | plot_mortgages(morts, amt) 171 | 172 | # Code from Figure 13-10 on page 269 173 | def plot_mortgages(morts, amt): 174 | def label_plot(figure, title, x_label, y_label): 175 | plt.figure(figure) 176 | plt.title(title) 177 | plt.xlabel(x_label) 178 | plt.ylabel(y_label) 179 | plt.legend(loc = 'best') 180 | styles = ['k-', 'k-.', 'k:'] 181 | #Give names to figure numbers 182 | payments, cost, balance, net_cost = 0, 1, 2, 3 183 | for i in range(len(morts)): 184 | plt.figure(payments) 185 | morts[i].plot_payments(styles[i]) 186 | plt.figure(cost) 187 | morts[i].plot_tot_pd(styles[i]) 188 | plt.figure(balance) 189 | morts[i].plot_balance(styles[i]) 190 | plt.figure(net_cost) 191 | morts[i].plot_net(styles[i]) 192 | label_plot(payments, f'Monthly Payments of ${amt:,} Mortages', 193 | 'Months', 'Monthly Payments') 194 | label_plot(cost, f'Cash Outlay of ${amt:,} Mortgages', 195 | 'Months', 'Total Payments') 196 | label_plot(balance, f'Balance Remaining of ${amt:,} Mortages', 197 | 'Months', 'Remaining Loan Balance of $') 198 | label_plot(net_cost, f'Net Cost of ${amt:,} Mortgages', 199 | 'Months', 'Payments - Equity $') 200 | 201 | # # Code from page 268 202 | # compare_mortgages(amt=200000, years=30, fixed_rate=0.07, 203 | # pts = 3.25, pts_rate=0.05, var_rate1=0.045, 204 | # var_rate2=0.095, var_months=48) 205 | 206 | # # Code from Figure 13-14 on page 272 207 | def simulation(fixed, variable): 208 | infected = [fixed['initial_infections']] 209 | new_infections = [fixed['initial_infections']] 210 | total_infections = fixed['initial_infections'] 211 | 212 | for t in range(fixed['duration']): 213 | cur_infections = infected[-1] 214 | # remove people who are no longer contagious 215 | if len(new_infections) > fixed['days_spreading']: 216 | cur_infections -= new_infections[-fixed['days_spreading']-1] 217 | # if social distancing, change number of daily contacts 218 | if t >= variable['red_start'] and t < variable['red_end']: 219 | daily_contacts = variable['red_daily_contacts'] 220 | else: 221 | daily_contacts = fixed['init_contacts'] 222 | # compute number of new cases 223 | total_contacts = cur_infections * daily_contacts 224 | susceptible = fixed['pop'] - total_infections 225 | risky_contacts = total_contacts * (susceptible/fixed['pop']) 226 | newly_infected = round(risky_contacts*fixed['contagiousness']) 227 | # update variables 228 | new_infections.append(newly_infected) 229 | total_infections += newly_infected 230 | infected.append(cur_infections + newly_infected) 231 | 232 | return infected, total_infections 233 | 234 | # # Code from Figure 13-15 on page 273 235 | def plot_infections(infections, total_infections, fixed): 236 | infection_plot = plt.plot(infections, 'r', label = 'Infected')[0] 237 | plt.xticks(fontsize = 'large') 238 | plt.yticks(fontsize = 'large') 239 | plt.xlabel('Days Since First Infection',fontsize = 'xx-large') 240 | plt.ylabel('Number Currently Infected',fontsize = 'xx-large') 241 | plt.title('Number of Infections Assuming No Vaccine\n' + 242 | f'Pop = {fixed["pop"]:,}, ' + 243 | f'Contacts/Day = {fixed["init_contacts"]}, ' + 244 | f'Infectivity = {(100*fixed["contagiousness"]):.1f}%, ' + 245 | f'Days Contagious = {fixed["days_spreading"]}', 246 | fontsize = 'xx-large') 247 | plt.legend(fontsize = 'xx-large') 248 | txt_box = plt.text(plt.xlim()[1]/2, plt.ylim()[1]/1.25, 249 | f'Total Infections = {total_infections:,.0f}', 250 | fontdict = {'size':'xx-large', 'weight':'bold', 251 | 'color':'red'}) 252 | return infection_plot, txt_box 253 | 254 | # # Code from Figure 13-16 on page 274 255 | # fixed = { 256 | # 'pop': 5000000, # population at risk 257 | # 'duration': 500, # number of days for simulation 258 | # 'initial_infections': 4, # initial number of cases 259 | # 'init_contacts': 50, #contacts without social distancing 260 | # 'contagiousness': 0.005, # prob. of getting disease if exposed 261 | # 'days_spreading': 10} # days contagious after infection 262 | 263 | # variable = { 264 | # # 'red_daily_contacts': 4, # social distancing 265 | # 'red_daily_contacts': fixed['init_contacts'], # social distancing 266 | # 'red_start': 20, # start of social distancing 267 | # 'red_end': 200} # end of social distancing 268 | 269 | # infections, total_infections = simulation(fixed, variable) 270 | # fig = plt.figure(figsize=(12, 8.5)) 271 | # plot_infections(infections, total_infections, fixed) 272 | 273 | # To use interactive plots, you might might need change your 274 | # Python preferences. Go to preferences->iPythonConsole->graphics. 275 | # Set backend to automatic, and then restart the iPython console 276 | 277 | # # Cdpe from page 275 278 | # # Layout for figure 279 | # fig = plt.figure(figsize=(12, 8.5)) 280 | # infections_ax = plt.axes([0.12, 0.2, 0.8, 0.65]) 281 | # contacts_ax = plt.axes([0.25, 0.09, 0.65, 0.03]) 282 | # start_ax = plt.axes([0.25, 0.06, 0.65, 0.03]) 283 | # end_ax = plt.axes([0.25, 0.03, 0.65, 0.03]) 284 | 285 | # # Code from page 276 286 | # # Create the sliders 287 | # from matplotlib.widgets import Slider 288 | 289 | # contacts_slider = Slider( 290 | # contacts_ax, # axes object containing the slider 291 | # 'reduced\ncontacts/day', # name of slider 292 | # 0, # minimal value of the parameter 293 | # 50, # maximal value of the parameter 294 | # 50) # initial value of the parameter) 295 | # contacts_slider.label.set_fontsize(12) 296 | # start_day_slider = Slider(start_ax, 'start reduction', 1, 30, 20) 297 | # start_day_slider.label.set_fontsize(12) 298 | # end_day_slider = Slider(end_ax, 'end reduction', 30, 400, 200) 299 | # end_day_slider.label.set_fontsize(12) 300 | 301 | # # Define a function that will be executed each time the value 302 | # # indicated by any slider changes. 303 | # def update(fixed, infection_plot, txt_box, 304 | # contacts_slider, start_day_slider, end_day_slider): 305 | # variable = {'red_daily_contacts': contacts_slider.val, 306 | # 'red_start': start_day_slider.val, 307 | # 'red_end': end_day_slider.val} 308 | # I, total_infections = simulation(fixed, variable) 309 | # infection_plot.set_ydata(I) # new y-coordinates for plot 310 | # txt_box.set_text(f'Total Infections = {total_infections:,.0f}') 311 | 312 | # # Cdoe from page 277 313 | # slider_update = lambda _: update(fixed, infection_plot, txt_box, 314 | # contacts_slider, start_day_slider, 315 | # end_day_slider) 316 | # contacts_slider.on_changed(slider_update) 317 | # start_day_slider.on_changed(slider_update) 318 | # end_day_slider.on_changed(slider_update) 319 | 320 | # infections, total_infections = simulation(fixed, variable) 321 | # plt.axes(infections_ax) 322 | # infection_plot, txt_box = plot_infections(infections, 323 | # total_infections, fixed) 324 | 325 | -------------------------------------------------------------------------------- /code/chapter 14/chapter14.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # # Figure 14-2 from page 284 4 | class Item(object): 5 | def __init__(self, n, v, w): 6 | self._name = n 7 | self._value = v 8 | self._weight = w 9 | def get_name(self): 10 | return self._name 11 | def get_value(self): 12 | return self._value 13 | def get_weight(self): 14 | return self._weight 15 | def __str__(self): 16 | return f'<{self._name}, {self._value}, {self._weight}>' 17 | 18 | def value(item): 19 | return item.get_value() 20 | 21 | def weight_inverse(item): 22 | return 1.0/item.get_weight() 23 | 24 | def density(item): 25 | return item.get_value()/item.get_weight() 26 | 27 | # # Figure 14-3 from page 284 28 | def greedy(items, max_weight, key_function): 29 | """Assumes items a list, max_weight >= 0, 30 | key_function maps elements of items to numbers""" 31 | items_copy = sorted(items, key=key_function, reverse = True) 32 | result = [] 33 | total_value, total_weight = 0.0, 0.0 34 | for i in range(len(items_copy)): 35 | if (total_weight + items_copy[i].get_weight()) <= max_weight: 36 | result.append(items_copy[i]) 37 | total_weight += items_copy[i].get_weight() 38 | total_value += items_copy[i].get_value() 39 | return (result, total_value) 40 | 41 | # # Figure 14-4 from page 286 42 | def build_items(): 43 | names = ['clock','painting','radio','vase','book','computer'] 44 | values = [175,90,20,50,10,200] 45 | weights = [10,9,4,2,1,20] 46 | Items = [] 47 | for i in range(len(values)): 48 | Items.append(Item(names[i], values[i], weights[i])) 49 | return Items 50 | 51 | def test_greedy(items, max_weight, key_function): 52 | taken, val = greedy(items, max_weight, key_function) 53 | print('Total value of items taken is', val) 54 | for item in taken: 55 | print(' ', item) 56 | 57 | def test_greedys(max_weight = 20): 58 | items = build_items() 59 | print('Use greedy by value to fill knapsack of size', max_weight) 60 | test_greedy(items, max_weight, value) 61 | print('\nUse greedy by weight to fill knapsack of size', 62 | max_weight) 63 | test_greedy(items, max_weight, weight_inverse) 64 | print('\nUse greedy by density to fill knapsack of size', 65 | max_weight) 66 | test_greedy(items, max_weight, density) 67 | 68 | # # Code from page 287 69 | # test_greedys() 70 | 71 | # # Code from Figure 11-6 72 | def get_binary_rep(n, num_digits): 73 | """Assumes n and numDigits are non-negative ints 74 | Returns a str of length numDigits that is a binary 75 | representation of n""" 76 | result = '' 77 | while n > 0: 78 | result = str(n%2) + result 79 | n = n//2 80 | if len(result) > num_digits: 81 | raise ValueError('not enough digits') 82 | for i in range(num_digits - len(result)): 83 | result = '0' + result 84 | return result 85 | 86 | def gen_powerset(L): 87 | """Assumes L is a list 88 | Returns a list of lists that contains all possible 89 | combinations of the elements of L. E.g., if 90 | L is [1, 2] it will return a list with elements 91 | [], [1], [2], and [1,2].""" 92 | powerset = [] 93 | for i in range(0, 2**len(L)): 94 | bin_str = get_binary_rep(i, len(L)) 95 | subset = [] 96 | for j in range(len(L)): 97 | if bin_str[j] == '1': 98 | subset.append(L[j]) 99 | powerset.append(subset) 100 | return powerset 101 | 102 | # # Figure 14-5 on page 289 103 | def choose_best(pset, max_weight, get_val, get_weight): 104 | best_val = 0.0 105 | best_set = None 106 | for items in pset: 107 | items_val = 0.0 108 | items_weight = 0.0 109 | for item in items: 110 | items_val += get_val(item) 111 | items_weight += get_weight(item) 112 | if items_weight <= max_weight and items_val > best_val: 113 | best_val = items_val 114 | best_set = items 115 | return (best_set, best_val) 116 | 117 | def test_best(max_weight = 20): 118 | items = build_items() 119 | pset = gen_powerset(items) 120 | taken, val = choose_best(pset, max_weight, Item.get_value, 121 | Item.get_weight) 122 | print('Total value of items taken is', val) 123 | for item in taken: 124 | print(item) 125 | 126 | # test_best() 127 | 128 | # # Figure 14-7 on page 294 129 | class Node(object): 130 | def __init__(self, name): 131 | """Assumes name is a string""" 132 | self._name = name 133 | def get_name(self): 134 | return self._name 135 | def __str__(self): 136 | return self._name 137 | 138 | class Edge(object): 139 | def __init__(self, src, dest): 140 | """Assumes src and dest are nodes""" 141 | self._src = src 142 | self._dest = dest 143 | def get_source(self): 144 | return self._src 145 | def get_destination(self): 146 | return self._dest 147 | def __str__(self): 148 | return self._src.get_name() + '->' + self._dest.get_name() 149 | 150 | class Weighted_edge(Edge): 151 | def __init__(self, src, dest, weight = 1.0): 152 | """Assumes src and dest are nodes, weight a number""" 153 | self._src = src 154 | self._dest = dest 155 | self._weight = weight 156 | def get_weight(self): 157 | return self._weight 158 | def __str__(self): 159 | return (f'{self._src.get_name()}->({self._weight})' + 160 | f'{self._dest.get_name()}') 161 | 162 | # # Figure 14-8 on page 296 163 | class Digraph(object): 164 | #nodes is a list of the nodes in the graph 165 | #edges is a dict mapping each node to a list of its children 166 | def __init__(self): 167 | self._nodes = [] 168 | self._edges = {} 169 | def add_node(self, node): 170 | if node in self._nodes: 171 | raise ValueError('Duplicate node') 172 | else: 173 | self._nodes.append(node) 174 | self._edges[node] = [] 175 | def add_edge(self, edge): 176 | src = edge.get_source() 177 | dest = edge.get_destination() 178 | if not (src in self._nodes and dest in self._nodes): 179 | raise ValueError('Node not in graph') 180 | self._edges[src].append(dest) 181 | def children_of(self, node): 182 | return self._edges[node] 183 | def has_node(self, node): 184 | return node in self._nodes 185 | def __str__(self): 186 | result = '' 187 | for src in self._nodes: 188 | for dest in self._edges[src]: 189 | result = (result + src.get_name() + '->' 190 | + dest.get_name() + '\n') 191 | return result[:-1] #omit final newline 192 | 193 | class Graph(Digraph): 194 | def add_edge(self, edge): 195 | Digraph.add_edge(self, edge) 196 | rev = Edge(edge.get_destination(), edge.get_source()) 197 | Digraph.add_edge(self, rev) 198 | 199 | # # Figure 14-9 on page 299 200 | def print_path(path): 201 | """Assumes path is a list of nodes""" 202 | result = '' 203 | for i in range(len(path)): 204 | result = result + str(path[i]) 205 | if i != len(path) - 1: 206 | result = result + '->' 207 | return result 208 | 209 | def DFS(graph, start, end, path, shortest, to_print = False): 210 | """Assumes graph is a Digraph; start and end are nodes; 211 | path and shortest are lists of nodes 212 | Returns a shortest path from start to end in graph""" 213 | path = path + [start] 214 | if to_print: 215 | print('Current DFS path:', print_path(path)) 216 | if start == end: 217 | return path 218 | for node in graph.children_of(start): 219 | if node not in path: #avoid cycles 220 | if shortest == None or len(path) < len(shortest): 221 | new_path = DFS(graph, node, end, path, shortest, 222 | to_print) 223 | if new_path != None: 224 | shortest = new_path 225 | return shortest 226 | 227 | def shortest_path(graph, start, end, to_print = False): 228 | """Assumes graph is a Digraph; start and end are nodes 229 | Returns a shortest path from start to end in graph""" 230 | return DFS(graph, start, end, [], None, to_print) 231 | 232 | # # Figure 14-10 on page 301 233 | def test_SP(): 234 | nodes = [] 235 | for name in range(6): #Create 6 nodes 236 | nodes.append(Node(str(name))) 237 | g = Digraph() 238 | for n in nodes: 239 | g.add_node(n) 240 | g.add_edge(Edge(nodes[0],nodes[1])) 241 | g.add_edge(Edge(nodes[1],nodes[2])) 242 | g.add_edge(Edge(nodes[2],nodes[3])) 243 | g.add_edge(Edge(nodes[2],nodes[4])) 244 | g.add_edge(Edge(nodes[3],nodes[4])) 245 | g.add_edge(Edge(nodes[3],nodes[5])) 246 | g.add_edge(Edge(nodes[0],nodes[2])) 247 | g.add_edge(Edge(nodes[1],nodes[0])) 248 | g.add_edge(Edge(nodes[3],nodes[1])) 249 | g.add_edge(Edge(nodes[4],nodes[0])) 250 | sp = shortest_path(g, nodes[0], nodes[5], to_print = True) 251 | print('Shortest path found by DFS:', print_path(sp)) 252 | 253 | # test_SP() 254 | 255 | # # Figure 14-11 on page 303 256 | def BFS(graph, start, end, to_print = False): 257 | """Assumes graph is a Digraph; start and end are nodes 258 | Returns a shortest path from start to end in graph""" 259 | init_path = [start] 260 | path_queue = [init_path] 261 | while len(path_queue) != 0: 262 | #Get and remove oldest element in path_queue 263 | tmp_path = path_queue.pop(0) 264 | if to_print: 265 | print('Current BFS path:', print_path(tmp_path)) 266 | last_node = tmp_path[-1] 267 | if last_node == end: 268 | return tmp_path 269 | for next_node in graph.children_of(last_node): 270 | if next_node not in tmp_path: 271 | new_path = tmp_path + [next_node] 272 | path_queue.append(new_path) 273 | return None 274 | 275 | # # test_sp modifed as per code on page 303 276 | def test_SP(): 277 | nodes = [] 278 | for name in range(6): #Create 6 nodes 279 | nodes.append(Node(str(name))) 280 | g = Digraph() 281 | for n in nodes: 282 | g.add_node(n) 283 | g.add_edge(Edge(nodes[0],nodes[1])) 284 | g.add_edge(Edge(nodes[1],nodes[2])) 285 | g.add_edge(Edge(nodes[2],nodes[3])) 286 | g.add_edge(Edge(nodes[2],nodes[4])) 287 | g.add_edge(Edge(nodes[3],nodes[4])) 288 | g.add_edge(Edge(nodes[3],nodes[5])) 289 | g.add_edge(Edge(nodes[0],nodes[2])) 290 | g.add_edge(Edge(nodes[1],nodes[0])) 291 | g.add_edge(Edge(nodes[3],nodes[1])) 292 | g.add_edge(Edge(nodes[4],nodes[0])) 293 | sp = shortest_path(g, nodes[0], nodes[5], to_print = True) 294 | print('Shortest path found by DFS:', print_path(sp)) 295 | sp = BFS(g, nodes[0], nodes[5], to_print = True) 296 | print('Shortest path found by BFS:', print_path(sp)) 297 | 298 | # test_SP() 299 | 300 | -------------------------------------------------------------------------------- /code/chapter 15/chapter15.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import random 4 | import numpy as np 5 | 6 | # # Code from page 306 7 | def fib(n): 8 | """Assumes n is an int >= 0 9 | Returns Fibonacci of n""" 10 | if n == 0 or n == 1: 11 | return 1 12 | else: 13 | return fib(n-1) + fib(n-2) 14 | 15 | # # Figure 15-2 from page 308 16 | def fib_memo(n, memo = None): 17 | """Assumes n is an int >= 0, memo used only by recursive calls 18 | Returns Fibonacci of n""" 19 | if memo == None: 20 | memo = {} 21 | if n == 0 or n == 1: 22 | return 1 23 | try: 24 | return memo[n] 25 | except KeyError: 26 | result = fib_memo(n-1, memo) + fib_memo(n-2, memo) 27 | memo[n] = result 28 | return result 29 | 30 | def fib_tab(n): 31 | """Assumes n is an int >= 0 32 | Returns Fibonacci of n""" 33 | tab = [1]*(n+1) #only first two values matter 34 | for i in range(2, n + 1): 35 | tab[i] = tab[i-1] + tab[i-2] 36 | return tab[n] 37 | 38 | # print(fib_memo(120)) 39 | # print(fib_tab(120)) 40 | 41 | # # Header for finger exercise on page 309 42 | def make_change(coin_vals, change): 43 | """coin_vals is a list of positive ints and coin_vals[0] = 1 44 | change is a positive int 45 | return the minimum number of coins needed to have a set of 46 | coins the values of which sum to change. Coins may be used 47 | more than once. For example, make_change([1, 5, 8], 11)""" 48 | 49 | # # Code from Figure 14-2 50 | class Item(object): 51 | def __init__(self, n, v, w): 52 | self.name = n 53 | self.value = v 54 | self.weight = w 55 | def get_name(self): 56 | return self.name 57 | def get_value(self): 58 | return self.value 59 | def get_weight(self): 60 | return self.weight 61 | def __str__(self): 62 | result = ('<' + self.name + ', ' + str(self.value) 63 | + ', ' + str(self.weight) + '>') 64 | return result 65 | 66 | def value(item): 67 | return item.get_value() 68 | 69 | def weight_inverse(item): 70 | return 1.0/item.get_weight() 71 | 72 | def density(item): 73 | return item.get_value()/item.get_weight() 74 | 75 | # # Figure 15-5 on page 313 76 | def max_val(to_consider, avail): 77 | """Assumes to_consider a list of items, avail a weight 78 | Returns a tuple of the total value of a solution to the 79 | 0/1 knapsack problem and the items of that solution""" 80 | if to_consider == [] or avail == 0: 81 | result = (0, ()) 82 | elif to_consider[0].get_weight() > avail: 83 | #Explore right branch only 84 | result = max_val(to_consider[1:], avail) 85 | else: 86 | next_item = to_consider[0] 87 | #Explore left branch 88 | with_val, with_to_take = max_val(to_consider[1:], 89 | avail - next_item.get_weight()) 90 | with_val += next_item.get_value() 91 | #Explore right branch 92 | without_val, without_to_take = max_val(to_consider[1:], avail) 93 | #Choose better branch 94 | if with_val > without_val: 95 | result = (with_val, with_to_take + (next_item,)) 96 | else: 97 | result = (without_val, without_to_take) 98 | return result 99 | 100 | # # Figure 15-6 on page 314 101 | def small_test(): 102 | names = ['a', 'b', 'c', 'd'] 103 | vals = [6, 7, 8, 9] 104 | weights = [3, 3, 2, 5] 105 | Items = [] 106 | for i in range(len(vals)): 107 | Items.append(Item(names[i], vals[i], weights[i])) 108 | val, taken = max_val(Items, 5) 109 | for item in taken: 110 | print(item) 111 | print('Total value of items taken =', val) 112 | 113 | def build_many_items(num_items, max_val, max_weight): 114 | items = [] 115 | for i in range(num_items): 116 | items.append(Item(str(i), 117 | random.randint(1, max_val), 118 | random.randint(1, max_weight))) 119 | return items 120 | 121 | def big_test(num_items, avail_weight): 122 | items = build_many_items(num_items, 10, 10) 123 | val, taken = max_val(items, avail_weight) 124 | print('Items Taken') 125 | for item in taken: 126 | print(item) 127 | print('Total value of items taken =', val) 128 | 129 | # small_test() 130 | # big_test(10, 40) 131 | # big_test(40, 100) 132 | 133 | # # Figure 15-7 on page 316 134 | def fast_max_val(to_consider, avail, memo = {}): 135 | """Assumes to_consider a list of items, avail a weight 136 | memo supplied by recursive calls 137 | Returns a tuple of the total value of a solution to the 138 | 0/1 knapsack problem and the items of that solution""" 139 | if (len(to_consider), avail) in memo: 140 | result = memo[(len(to_consider), avail)] 141 | elif to_consider == [] or avail == 0: 142 | result = (0, ()) 143 | elif to_consider[0].get_weight() > avail: 144 | #Explore right branch only 145 | result = fast_max_val(to_consider[1:], avail, memo) 146 | else: 147 | next_item = to_consider[0] 148 | #Explore left branch 149 | with_val, with_to_take =\ 150 | fast_max_val(to_consider[1:], 151 | avail - next_item.get_weight(), memo) 152 | with_val += next_item.get_value() 153 | #Explore right branch 154 | without_val, without_to_take = fast_max_val(to_consider[1:], 155 | avail, memo) 156 | #Choose better branch 157 | if with_val > without_val: 158 | result = (with_val, with_to_take + (next_item,)) 159 | else: 160 | result = (without_val, without_to_take) 161 | memo[(len(to_consider), avail)] = result 162 | return result 163 | 164 | # # Version for which dynamic programming will not help on page 319 165 | # def build_many_items(num_items, max_val, max_weight): 166 | # items = [] 167 | # for i in range(num_items): 168 | # items.append(Item(str(i), 169 | # random.randint(1, max_val), 170 | # random.randint(1, max_weight)*random.random())) 171 | 172 | # return items 173 | 174 | -------------------------------------------------------------------------------- /code/chapter 16/chapter16.py: -------------------------------------------------------------------------------- 1 | 2 | import random 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | 6 | #set line width 7 | plt.rcParams['lines.linewidth'] = 4 8 | #set font size for titles 9 | plt.rcParams['axes.titlesize'] = 20 10 | #set font size for labels on axes 11 | plt.rcParams['axes.labelsize'] = 18 12 | #set size of numbers on x-axis 13 | plt.rcParams['xtick.labelsize'] = 16 14 | #set size of numbers on y-axis 15 | plt.rcParams['ytick.labelsize'] = 16 16 | #set size of ticks on x-axis 17 | plt.rcParams['xtick.major.size'] = 7 18 | #set size of ticks on y-axis 19 | plt.rcParams['ytick.major.size'] = 7 20 | #set size of markers, e.g., circles representing points 21 | plt.rcParams['lines.markersize'] = 10 22 | #set number of times marker is shown when displaying legend 23 | plt.rcParams['legend.numpoints'] = 1 24 | #Set size of type in legend 25 | plt.rcParams['legend.fontsize'] = 14 26 | 27 | # # Figure 16-2 from page 326 28 | class Location(object): 29 | def __init__(self, x, y): 30 | """x and y are numbers""" 31 | self._x, self._y = x, y 32 | def move(self, delta_x, delta_y): 33 | """delta_x and delta_y are numbers""" 34 | return Location(self._x + delta_x, self._y + delta_y) 35 | 36 | def get_x(self): 37 | return self._x 38 | 39 | def get_y(self): 40 | return self._y 41 | 42 | def dist_from(self, other): 43 | ox, oy = other._x, other._y 44 | x_dist, y_dist = self._x - ox, self._y - oy 45 | return (x_dist**2 + y_dist**2)**0.5 46 | 47 | def __str__(self): 48 | return f'<{self._x}, {self._y}>' 49 | 50 | class Field(object): 51 | def __init__(self): 52 | self._drunks = {} 53 | 54 | def add_drunk(self, drunk, loc): 55 | if drunk in self._drunks: 56 | raise ValueError('Duplicate drunk') 57 | else: 58 | self._drunks[drunk] = loc 59 | 60 | def move_drunk(self, drunk): 61 | if drunk not in self._drunks: 62 | raise ValueError('Drunk not in field') 63 | x_dist, y_dist = drunk.take_step() 64 | current_location = self._drunks[drunk] 65 | #use move method of Location to get new location 66 | self._drunks[drunk] = current_location.move(x_dist, y_dist) 67 | 68 | def get_loc(self, drunk): 69 | if drunk not in self._drunks: 70 | raise ValueError('Drunk not in field') 71 | return self._drunks[drunk] 72 | 73 | # # Figure 16-3 from page 327 74 | class Drunk(object): 75 | def __init__(self, name = None): 76 | """Assumes name is a str""" 77 | self._name = name 78 | 79 | def __str__(self): 80 | if self != None: 81 | return self._name 82 | return 'Anonymous' 83 | 84 | class Usual_drunk(Drunk): 85 | def take_step(self): 86 | step_choices = [(0,1), (0,-1), (1, 0), (-1, 0)] 87 | return random.choice(step_choices) 88 | return random.choice(step_choices) 89 | 90 | # # Figure 16-4 from page 328 91 | def walk(f, d, num_steps): 92 | """Assumes: f a Field, d a Drunk in f, and num_steps an int >= 0. 93 | Moves d num_steps times; returns the distance between the 94 | final location and the location at the start of the walk.""" 95 | start = f.get_loc(d) 96 | for s in range(num_steps): 97 | f.move_drunk(d) 98 | return start.dist_from(f.get_loc(d)) 99 | 100 | def sim_walks(num_steps, num_trials, d_class): 101 | """Assumes num_steps an int >= 0, num_trials an int > 0, 102 | d_class a subclass of Drunk 103 | Simulates num_trials walks of num_steps steps each. 104 | Returns a list of the final distances for each trial""" 105 | Homer = d_class() 106 | origin = Location(0, 0) 107 | distances = [] 108 | for t in range(num_trials): 109 | f = Field() 110 | f.add_drunk(Homer, origin) 111 | distances.append(round(walk(f, Homer, num_trials), 1)) 112 | return distances 113 | 114 | def drunk_test(walk_lengths, num_trials, d_class): 115 | """Assumes walk_lengths a sequence of ints >= 0 116 | num_trials an int > 0, d_class a subclass of Drunk 117 | For each number of steps in walk_lengths, runs sim_walks with 118 | num_trials walks and prints results""" 119 | for num_steps in walk_lengths: 120 | distances = sim_walks(num_steps, num_trials, d_class) 121 | print(d_class.__name__, 'walk of', num_steps, 'steps: Mean =', 122 | f'{sum(distances)/len(distances):.3f}, Max =', 123 | f'{max(distances)}, Min = {min(distances)}') 124 | 125 | # # Code from page 329 126 | # random.seed(0) 127 | # drunk_test((10, 100, 1000, 10000), 100, Usual_drunk) 128 | # drunk_test((0,1), 100, Usual_drunk) 129 | 130 | # sim_walks with correction described on page 329 131 | def sim_walks(num_steps, num_trials, d_class): 132 | """Assumes num_steps an int >= 0, num_trials an int > 0, 133 | d_class a subclass of Drunk 134 | Simulates num_trials walks of num_steps steps each. 135 | Returns a list of the final distances for each trial""" 136 | Homer = d_class() 137 | origin = Location(0, 0) 138 | distances = [] 139 | for t in range(num_trials): 140 | f = Field() 141 | f.add_drunk(Homer, origin) 142 | distances.append(round(walk(f, Homer, num_steps), 1)) 143 | return distances 144 | 145 | # random.seed(0) 146 | # drunk_test((10, 100, 1000, 10000), 100, Usual_drunk) 147 | # drunk_test((0,1), 100, Usual_drunk) 148 | 149 | # # Figure 16-6 from page 331 150 | class Cold_drunk(Drunk): 151 | def take_step(self): 152 | stepChoices = [(0.0,1.0), (0.0,-2.0), (1.0, 0.0), (-1.0, 0.0)] 153 | return random.choice(stepChoices) 154 | 155 | class EW_drunk(Drunk): 156 | def take_step(self): 157 | stepChoices = [(1.0, 0.0), (-1.0, 0.0)] 158 | return random.choice(stepChoices) 159 | 160 | def sim_all(drunk_kinds, walk_lengths, num_trials): 161 | for d_class in drunk_kinds: 162 | drunk_test(walk_lengths, num_trials, d_class) 163 | 164 | # # Code from page 332 165 | # random.seed(0) 166 | # sim_all((Usual_drunk, Cold_drunk, EW_drunk), (100, 1000), 10) 167 | 168 | # # Figure 16-7 from page 333 169 | class style_iterator(object): 170 | def __init__(self, styles): 171 | self.index = 0 172 | self.styles = styles 173 | 174 | def next_style(self): 175 | result = self.styles[self.index] 176 | if self.index == len(self.styles) - 1: 177 | self.index = 0 178 | else: 179 | self.index += 1 180 | return result 181 | 182 | # # Figure 16-8 from page 333 183 | def sim_drunk(num_trials, d_class, walk_lengths): 184 | meanDistances = [] 185 | for num_steps in walk_lengths: 186 | print('Starting simulation of', num_steps, 'steps') 187 | trials = sim_walks(num_steps, num_trials, d_class) 188 | mean = sum(trials)/len(trials) 189 | meanDistances.append(mean) 190 | return meanDistances 191 | 192 | def sim_all_plot(drunk_kinds, walk_lengths, num_trials): 193 | style_choice = style_iterator(('m-', 'r:', 'k-.')) 194 | for d_class in drunk_kinds: 195 | cur_style = style_choice.next_style() 196 | print('Starting simulation of', d_class.__name__) 197 | means = sim_drunk(num_trials, d_class, walk_lengths) 198 | plt.plot(walk_lengths, means, cur_style, 199 | label = d_class.__name__) 200 | plt.title(f'Mean Distance from Origin ({num_trials} trials') 201 | plt.xlabel('Number of Steps') 202 | plt.ylabel('Distance from Origin') 203 | plt.legend(loc = 'best') 204 | plt.semilogx() 205 | plt.semilogy() 206 | 207 | # # Code from page 334 208 | # sim_all_plot((Usual_drunk, Cold_drunk, EW_drunk), 209 | # (10, 100, 1000, 10000, 100000), 100) 210 | 211 | # # Figure 16-10 from page 335 212 | def get_final_locs(num_steps, num_trials, d_class): 213 | locs = [] 214 | d = d_class() 215 | for t in range(num_trials): 216 | f = Field() 217 | f.add_drunk(d, Location(0, 0)) 218 | for s in range(num_steps): 219 | f.move_drunk(d) 220 | locs.append(f.get_loc(d)) 221 | return locs 222 | 223 | def plot_locs(drunk_kinds, num_steps, num_trials): 224 | style_choice = style_iterator(('k+', 'r^', 'mo')) 225 | for d_class in drunk_kinds: 226 | locs = get_final_locs(num_steps, num_trials, d_class) 227 | x_vals, y_vals = [], [] 228 | for loc in locs: 229 | x_vals.append(loc.get_x()) 230 | y_vals.append(loc.get_y()) 231 | meanX = sum(x_vals)/len(x_vals) 232 | meanY = sum(y_vals)/len(y_vals) 233 | cur_style = style_choice.next_style() 234 | plt.plot(x_vals, y_vals, cur_style, 235 | label = (f'{d_class.__name__} mean loc. = <' + 236 | f'{meanX}, {meanY}>')) 237 | plt.title(f'Location at End of Walks ({num_steps} steps)') 238 | plt.xlabel('Steps East/West of Origin') 239 | plt.ylabel('Steps North/South of Origin') 240 | plt.legend(loc = 'best') 241 | 242 | # # Code from page 335 243 | # random.seed(0) 244 | # plot_locs((Usual_drunk, Cold_drunk, EW_drunk), 100, 200) 245 | 246 | # # Figure 16-12 from page 337 247 | def trace_walk(drunk_kinds, num_steps): 248 | style_choice = style_iterator(('k+', 'r^', 'mo')) 249 | f = Field() 250 | # f = Odd_field(1000, 100, 200) #Added later in chapter 251 | for d_class in drunk_kinds: 252 | d = d_class() 253 | f.add_drunk(d, Location(0, 0)) 254 | locs = [] 255 | for s in range(num_steps): 256 | f.move_drunk(d) 257 | locs.append(f.get_loc(d)) 258 | x_vals, y_vals = [], [] 259 | for loc in locs: 260 | x_vals.append(loc.get_x()) 261 | y_vals.append(loc.get_y()) 262 | cur_style = style_choice.next_style() 263 | plt.plot(x_vals, y_vals, cur_style, 264 | label = d_class.__name__) 265 | plt.title('Spots Visited on Walk (' 266 | + str(num_steps) + ' steps)') 267 | plt.xlabel('Steps East/West of Origin') 268 | plt.ylabel('Steps North/South of Origin') 269 | plt.legend(loc = 'best') 270 | 271 | # random.seed(2) 272 | # trace_walk((Usual_drunk, Cold_drunk, EW_drunk), 200) 273 | 274 | # # Figure 16-14 from page 339 275 | class Odd_field(Field): 276 | def __init__(self, numHoles, x_range, y_range): 277 | Field.__init__(self) 278 | self._wormholes = {} 279 | for w in range(numHoles): 280 | x = random.randint(-x_range, x_range) 281 | y = random.randint(-y_range, y_range) 282 | newX = random.randint(-x_range, x_range) 283 | newY = random.randint(-y_range, y_range) 284 | newLoc = Location(newX, newY) 285 | self._wormholes[(x, y)] = newLoc 286 | 287 | def move_drunk(self, drunk): 288 | Field.move_drunk(self, drunk) 289 | x = self._drunks[drunk].get_x() 290 | y = self._drunks[drunk].get_y() 291 | if (x, y) in self._wormholes: 292 | self._drunks[drunk] = self._wormholes[(x, y)] 293 | 294 | # # Code from page 339 295 | # random.seed(0) 296 | # trace_walk((Usual_drunk, Cold_drunk, EW_drunk), 500) 297 | 298 | # # Answer to finger exercise used to produce Figure 16-5 on page 330 299 | # plt.figure() 300 | # random.seed(0) 301 | # step_list = [10, 100, 1000, 10000, 100000] 302 | # drunk_list = [Usual_drunk] 303 | # sim_all_plot(drunk_list, step_list, 100) 304 | # y_vals = [] 305 | # for i in step_list: 306 | # y_vals.append(i**0.5) 307 | # plt.plot(step_list, y_vals, '--b', label = 'sqrt(steps)') 308 | # plt.legend(loc = 'best') -------------------------------------------------------------------------------- /code/chapter 18/chapter18.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import random 4 | import numpy as np 5 | 6 | # # Figure 18-1 on page 396 7 | def roll_die(): 8 | return random.choice([1,2,3,4,5,6]) 9 | 10 | # #Used later in chapter 11 | # def roll_die(): 12 | # return random.choice([1,1,2,3,3,4,4,5,5,5,6,6]) 13 | 14 | def check_pascal(num_trials): 15 | """Assumes num_trials is an int > 0 16 | Prints an estimate of the probability of winning""" 17 | num_wins = 0 18 | for i in range(num_trials): 19 | for j in range(24): 20 | d1 = roll_die() 21 | d2 = roll_die() 22 | if d1 == 6 and d2 == 6: 23 | num_wins += 1 24 | break 25 | print('Probability of winning =', num_wins/num_trials) 26 | 27 | # check_pascal(1000000) 28 | 29 | # # Figure 18-2 on page 397 30 | class Craps_game(object): 31 | def __init__(self): 32 | self.pass_wins, self.pass_losses = 0, 0 33 | self.dp_wins, self.dp_losses, self.dp_pushes = 0, 0, 0 34 | 35 | def play_hand(self): 36 | throw = roll_die() + roll_die() 37 | if throw == 7 or throw == 11: 38 | self.pass_wins += 1 39 | self.dp_losses += 1 40 | elif throw == 2 or throw == 3 or throw == 12: 41 | self.pass_losses += 1 42 | if throw == 12: 43 | self.dp_pushes += 1 44 | else: 45 | self.dp_wins += 1 46 | else: 47 | point = throw 48 | while True: 49 | throw = roll_die() + roll_die() 50 | if throw == point: 51 | self.pass_wins += 1 52 | self.dp_losses += 1 53 | break 54 | elif throw == 7: 55 | self.pass_losses += 1 56 | self.dp_wins += 1 57 | break 58 | 59 | def pass_results(self): 60 | return (self.pass_wins, self.pass_losses) 61 | 62 | def dp_results(self): 63 | return (self.dp_wins, self.dp_losses, self.dp_pushes) 64 | 65 | def craps_sim(hands_per_game, num_games): 66 | """Assumes hands_per_game and num_games are ints > 0 67 | Play num_games games of hands_per_game hands; print results""" 68 | games = [] 69 | 70 | #Play num_games games 71 | for t in range(num_games): 72 | c = Craps_game() 73 | for i in range(hands_per_game): 74 | c.play_hand() 75 | games.append(c) 76 | 77 | #Produce statistics for each game 78 | p_ROI_per_game, dp_ROI_per_game = [], [] 79 | for g in games: 80 | wins, losses = g.pass_results() 81 | p_ROI_per_game.append((wins - losses)/float(hands_per_game)) 82 | wins, losses, pushes = g.dp_results() 83 | dp_ROI_per_game.append((wins - losses)/float(hands_per_game)) 84 | 85 | #Produce and print summary statistics 86 | mean_ROI = str(round((100*sum(p_ROI_per_game)/num_games), 4)) + '%' 87 | sigma = str(round(100*np.std(p_ROI_per_game), 4)) + '%' 88 | print('Pass:', 'Mean ROI =', mean_ROI, 'Std. Dev. =', sigma) 89 | mean_ROI = str(round((100*sum(dp_ROI_per_game)/num_games), 4)) +'%' 90 | sigma = str(round(100*np.std(dp_ROI_per_game), 4)) + '%' 91 | print('Don\'t pass:','Mean ROI =', mean_ROI, 'Std Dev =', sigma) 92 | 93 | # # Code from page 400 94 | # craps_sim(20, 10) 95 | 96 | # craps_sim(1000000, 10) 97 | 98 | # # Code from page 401 99 | # craps_sim(20, 1000000) 100 | 101 | # # Class with version of play_hand from Figure 18-4 on page 403 102 | class Craps_game(object): 103 | def __init__(self): 104 | self.pass_wins, self.pass_losses = 0, 0 105 | self.dp_wins, self.dp_losses, self.dp_pushes = 0, 0, 0 106 | def play_hand(self): 107 | #An alternative, faster, implementation of play_hand 108 | points_dict = {4:1/3, 5:2/5, 6:5/11, 8:5/11, 9:2/5, 10:1/3} 109 | throw = roll_die() + roll_die() 110 | if throw == 7 or throw == 11: 111 | self.pass_wins += 1 112 | self.dp_losses += 1 113 | elif throw == 2 or throw == 3 or throw == 12: 114 | self.pass_losses += 1 115 | if throw == 12: 116 | self.dp_pushes += 1 117 | else: 118 | self.dp_wins += 1 119 | else: 120 | if random.random() <= points_dict[throw]: # point before 7 121 | self.pass_wins += 1 122 | self.dp_losses += 1 123 | else: # 7 before point 124 | self.pass_losses += 1 125 | self.dp_wins += 1 126 | 127 | def pass_results(self): 128 | return (self.pass_wins, self.pass_losses) 129 | 130 | def dp_results(self): 131 | return (self.dp_wins, self.dp_losses, self.dp_pushes) 132 | 133 | # # Figure 18-6 from page 407 134 | def throw_needles(num_needles): 135 | in_circle = 0 136 | for Needles in range(1, num_needles + 1): 137 | x = random.random() 138 | y = random.random() 139 | if (x*x + y*y)**0.5 <= 1: 140 | in_circle += 1 141 | #Counting needles in one quadrant only, so multiply by 4 142 | return 4*(in_circle/num_needles) 143 | 144 | def get_est(num_needles, num_trials): 145 | estimates = [] 146 | for t in range(num_trials): 147 | pi_guess = throw_needles(num_needles) 148 | estimates.append(pi_guess) 149 | std_dev = np.std(estimates) 150 | cur_est = sum(estimates)/len(estimates) 151 | print('Est. =', str(round(cur_est, 5)) + ',', 152 | 'Std. dev. =', str(round(std_dev, 5)) + ',', 153 | 'Needles =', num_needles) 154 | return (cur_est, std_dev) 155 | 156 | def est_pi(precision, num_trials): 157 | num_needles = 1000 158 | std_dev = precision 159 | while std_dev > precision/1.96: 160 | cur_est, std_dev = get_est(num_needles, num_trials) 161 | num_needles *= 2 162 | return cur_est 163 | 164 | # # Code from page 407 165 | random.seed(0) 166 | est_pi(0.01, 100) -------------------------------------------------------------------------------- /code/chapter 19/chapter19.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import random 4 | import numpy as np 5 | import matplotlib.pyplot as plt 6 | import scipy 7 | 8 | #set line width 9 | plt.rcParams['lines.linewidth'] = 4 10 | #set font size for titles 11 | plt.rcParams['axes.titlesize'] = 20 12 | #set font size for labels on axes 13 | plt.rcParams['axes.labelsize'] = 18 14 | #set size of num_bers on x-axis 15 | plt.rcParams['xtick.labelsize'] = 16 16 | #set size of num_bers on y-axis 17 | plt.rcParams['ytick.labelsize'] = 16 18 | #set size of ticks on x-axis 19 | plt.rcParams['xtick.major.size'] = 7 20 | #set size of ticks on y-axis 21 | plt.rcParams['ytick.major.size'] = 7 22 | #set size of markers, e.g., circles representing points 23 | plt.rcParams['lines.markersize'] = 10 24 | #set num_ber of times marker is shown when displaying legend 25 | plt.rcParams['legend.numpoints'] = 1 26 | #Set size of type in legend 27 | plt.rcParams['legend.fontsize'] = 16 28 | 29 | # # Figure 19-2 on page 416 30 | def get_BM_data(filename): 31 | """Read the contents of the given file. Assumes the file is 32 | in a comma-separated format, with 6 elements in each entry: 33 | 0. Name (string), 1. Gender (string), 2. Age (int) 34 | 3. Division (int), 4. Country (string), 5. Overall time (float) 35 | Returns: dict containing a list for each of the 6 variables.""" 36 | 37 | data = {} 38 | with open(filename, 'r') as f: 39 | f.readline() #discard first line 40 | line = f.readline() 41 | for k in ('name', 'gender', 'age', 'division', 42 | 'country', 'time'): 43 | data[k] = [] 44 | while line != '': 45 | split = line.split(',') 46 | data['name'].append(split[0]) 47 | data['gender'].append(split[1]) 48 | data['age'].append(int(split[2])) 49 | data['division'].append(int(split[3])) 50 | data['country'].append(split[4]) 51 | data['time'].append(float(split[5][:-1])) #remove \n 52 | line = f.readline() 53 | return data 54 | 55 | def make_hist(data, bins, title, xLabel, yLabel): 56 | plt.hist(data, bins) 57 | plt.title(title) 58 | plt.xlabel(xLabel) 59 | plt.ylabel(yLabel) 60 | mean = sum(data)/len(data) 61 | std = np.std(data) 62 | plt.annotate('Mean = ' + str(round(mean, 2)) + 63 | '\nSD = ' + str(round(std, 2)), fontsize = 14, 64 | xy = (0.65, 0.75), xycoords = 'axes fraction') 65 | 66 | # # Code on page 417 67 | # times = get_BM_data('bm_results2012.csv')['time'] 68 | # make_hist(times, 20, '2012 Boston Marathon', 69 | # 'Minutes to Complete Race', 'Number of Runners') 70 | 71 | # # Figure 19-4 on page 418 72 | def sample_times(times, num_examples): 73 | """Assumes times is a list of floats representing finishing 74 | times of all runners. num_examples is an int 75 | Generates a random sample of size num_examples, and produces 76 | a histogram showing the distribution along with its mean and 77 | standard deviation""" 78 | sample = random.sample(times, num_examples) 79 | make_hist(sample, 10, 'Sample of Size ' + str(num_examples), 80 | 'Minutes to Complete Race', 'Number of Runners') 81 | 82 | # random.seed(0) 83 | # sample_size = 40 84 | # sample_times(times, sample_size) 85 | 86 | # # Figure 19-6 on page 419 87 | # def gaussian(x, mu, sigma): 88 | # factor1 = (1/(sigma*((2*np.pi)**0.5))) 89 | # factor2 = np.e**-(((x-mu)**2)/(2*sigma**2)) 90 | # return factor1*factor2 91 | 92 | # area = round(scipy.integrate.quad(gaussian, -3, 3, (0, 1))[0], 4) 93 | # print('Probability of being within 3', 94 | # 'of true mean of tight dist. =', area) 95 | # area = round(scipy.integrate.quad(gaussian, -3, 3, (0, 100))[0], 4) 96 | # print('Probability of being within 3', 97 | # 'of true mean of wide dist. =', area) 98 | 99 | # # Figure 19-7 on page 421 100 | def test_samples(num_trials, sample_size): 101 | tight_means, wide_means = [], [] 102 | for t in range(num_trials): 103 | sample_tight, sample_wide = [], [] 104 | for i in range(sample_size): 105 | sample_tight.append(random.gauss(0, 1)) 106 | sample_wide.append(random.gauss(0, 100)) 107 | tight_means.append(sum(sample_tight)/len(sample_tight)) 108 | wide_means.append(sum(sample_wide)/len(sample_wide)) 109 | return tight_means, wide_means 110 | 111 | # tight_means, wide_means = test_samples(1000, 40) 112 | # plt.plot(wide_means, 'y*', label = ' SD = 100') 113 | # plt.plot(tight_means, 'bo', label = 'SD = 1') 114 | # plt.xlabel('Sample Number') 115 | # plt.ylabel('Sample Mean') 116 | # plt.title('Means of Samples of Size ' + str(40)) 117 | # plt.legend() 118 | 119 | # plt.figure() 120 | # plt.hist(wide_means, bins = 20, label = 'SD = 100') 121 | # plt.title('Distribution of Sample Means') 122 | # plt.xlabel('Sample Mean') 123 | # plt.ylabel('Frequency of Occurrence') 124 | # plt.legend() 125 | 126 | # # Figure 19-9 on page 423 127 | def plot_means(num_dice_per_trial, num_dice_thrown, num_bins, 128 | legend, color, style): 129 | means = [] 130 | num_trials = num_dice_thrown//num_dice_per_trial 131 | for i in range(num_trials): 132 | vals = 0 133 | for j in range(num_dice_per_trial): 134 | vals += 5*random.random() 135 | means.append(vals/num_dice_per_trial) 136 | plt.hist(means, num_bins, color = color, label = legend, 137 | weights = np.array(len(means)*[1])/len(means), 138 | hatch = style) 139 | return sum(means)/len(means), np.var(means) 140 | 141 | # mean, var = plot_means(1, 1000000, 11, '1 die', 'y', '*') 142 | # print('Mean of rolling 1 die =', round(mean,4), 143 | # 'Variance =', round(var,4)) 144 | # mean, var = plot_means(100, 1000000, 11, 145 | # 'Mean 100 dice', 'c', '//') 146 | # print('Mean of rolling 100 dice =', round(mean, 4), 147 | # 'Variance =', round(var, 4)) 148 | # plt.title('Rolling Continuous Dice') 149 | # plt.xlabel('Value') 150 | # plt.ylabel('Probability') 151 | # plt.legend(loc = 'upper left') 152 | 153 | # # Figure 19-11 on page 426 154 | # times = get_BM_data('bm_results2012.csv')['time'] 155 | # mean_of_means, std_of_means = [], [] 156 | # sample_sizes = range(100, 1501, 200) 157 | # for sample_size in sample_sizes: 158 | # sample_means = [] 159 | # for t in range(200): 160 | # sample = random.sample(times, sample_size) 161 | # sample_means.append(sum(sample)/sample_size) 162 | # mean_of_means.append(sum(sample_means)/len(sample_means)) 163 | # std_of_means.append(np.std(sample_means)) 164 | # plt.errorbar(sample_sizes, mean_of_means, color = 'c', 165 | # yerr = 1.96*np.array(std_of_means), 166 | # label = 'Estimated mean and 95% CI') 167 | # plt.axhline(sum(times)/len(times), linestyle = '--', color = 'k', 168 | # label = 'Population mean') 169 | # plt.title('Estimates of Mean Finishing Time') 170 | # plt.xlabel('Sample Size') 171 | # plt.ylabel('Finshing Time (minutes)') 172 | # plt.legend(loc = 'best') 173 | 174 | # # Code used to produce Figure 19-13 on page 427 175 | # def SEM(n, sigma): 176 | # return sigma/n**0.5 177 | 178 | # plt.figure() 179 | # sems = [] 180 | # for sample_size in sample_sizes: 181 | # sems.append(SEM(sample_size, 50.02)) 182 | # plt.plot(sample_sizes, sems, '--', label = 'SEM') 183 | # plt.plot(sample_sizes, std_of_means, label ='STD') 184 | # plt.title('SEM and SD of 200 Means') 185 | # plt.xlabel('Sample Size') 186 | # plt.ylabel('SD and SEM') 187 | # plt.legend() 188 | 189 | # # Figure 19-14 on page 428 190 | # times = get_BM_data('bm_results2012.csv')['time'] 191 | # pos_std = np.std(times) 192 | # sample_sizes = range(2, 200, 2) 193 | # diffs_means = [] 194 | # for sample_size in sample_sizes: 195 | # diffs = [] 196 | # for t in range(100): 197 | # diffs.append(abs(pos_std - np.std(random.sample(times, 198 | # sample_size)))) 199 | # diffs_means.append(sum(diffs)/len(diffs)) 200 | # plt.plot(sample_sizes, diffs_means) 201 | # plt.xlabel('Sample Size') 202 | # plt.ylabel('Abs(Pop. Std - Sample Std)') 203 | # plt.title('Error in Sample SD vs. Sample Size') 204 | 205 | # # Figure 19-16 on page 439 206 | # times = get_BM_data('bm_results2012.csv')['time'] 207 | # pop_mean = sum(times)/len(times) 208 | # sample_size = 200 209 | # num_bad = 0 210 | # for t in range(10000): 211 | # sample = random.sample(times, sample_size) 212 | # sample_mean = sum(sample)/sample_size 213 | # se = np.std(sample)/sample_size**0.5 214 | # if abs(pop_mean - sample_mean) > 1.96*se: 215 | # num_bad += 1 216 | # print('Fraction outside 95% confidence interval =', num_bad/10000) 217 | 218 | -------------------------------------------------------------------------------- /code/chapter 20/chapter20.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | import math 6 | #set line width 7 | plt.rcParams['lines.linewidth'] = 4 8 | #set font size for titles 9 | plt.rcParams['axes.titlesize'] = 18 10 | #set font size for labels on axes 11 | plt.rcParams['axes.labelsize'] = 16 12 | #set size of num_bers on x-axis 13 | plt.rcParams['xtick.labelsize'] = 16 14 | #set size of num_bers on y-axis 15 | plt.rcParams['ytick.labelsize'] = 16 16 | #set size of ticks on x-axis 17 | plt.rcParams['xtick.major.size'] = 7 18 | #set size of ticks on y-axis 19 | plt.rcParams['ytick.major.size'] = 7 20 | #set size of markers, e.g., circles representing points 21 | plt.rcParams['lines.markersize'] = 10 22 | #set num_ber of times marker is shown when displaying legend 23 | plt.rcParams['legend.numpoints'] = 1 24 | #Set size of type in legend 25 | plt.rcParams['legend.fontsize'] = 14 26 | 27 | # # Figure 20-2 from page 434 28 | def get_data(input_file): 29 | with open(input_file, 'r') as data_file: 30 | distances = [] 31 | masses = [] 32 | data_file.readline() #ignore header 33 | for line in data_file: 34 | d, m = line.split(',') 35 | distances.append(float(d)) 36 | masses.append(float(m)) 37 | return (masses, distances) 38 | 39 | # # Figure 20-3 from page 434 40 | def plot_data(input_file): 41 | masses, distances = get_data(input_file) 42 | distances = np.array(distances) 43 | masses = np.array(masses) 44 | forces = masses*9.81 45 | plt.plot(forces, distances, 'bo', 46 | label = 'Measured displacements') 47 | plt.title('Measured Displacement of Spring') 48 | plt.xlabel('|Force| (Newtons)') 49 | plt.ylabel('Distance (meters)') 50 | 51 | # plot_data('springData.csv') 52 | 53 | # # Figure 20-5 from page 438 54 | def fit_data(input_file): 55 | masses, distances = get_data(input_file) 56 | distances = np.array(distances) 57 | forces = np.array(masses)*9.81 58 | plt.plot(forces, distances, 'ko', 59 | label = 'Measured displacements') 60 | plt.title('Measured Displacement of Spring') 61 | plt.xlabel('|Force| (Newtons)') 62 | plt.ylabel('Distance (meters)') 63 | #find linear fit 64 | a,b = np.polyfit(forces, distances, 1) 65 | predicted_distances = a*np.array(forces) + b 66 | k = 1.0/a #see explanation in text 67 | plt.plot(forces, predicted_distances, 68 | label = f'Linear fit, k = {k:.4f}') 69 | plt.legend(loc = 'best') 70 | 71 | # fit_data('springData.csv') 72 | 73 | # # fit_data with code from page 439 74 | def fit_data(input_file): 75 | masses, distances = get_data(input_file) 76 | distances = np.array(distances) 77 | forces = np.array(masses)*9.81 78 | plt.plot(forces, distances, 'ko', 79 | label = 'Measured displacements') 80 | plt.title('Measured Displacement of Spring') 81 | plt.xlabel('|Force| (Newtons)') 82 | plt.ylabel('Distance (meters)') 83 | #find linear fit 84 | a,b = np.polyfit(forces, distances, 1) 85 | predicted_distances = a*np.array(forces) + b 86 | k = 1.0/a #see explanation in text 87 | plt.plot(forces, predicted_distances, 88 | label = 'Linear fit, k = ' + str(round(k, 5))) 89 | #find cubic fit 90 | fit = np.polyfit(forces, distances, 3) 91 | predicted_distances = np.polyval(fit, forces) 92 | plt.plot(forces, predicted_distances, 'k:', label = 'cubic fit') 93 | plt.legend(loc = 'best') 94 | 95 | # # fit_data('springData.csv') 96 | 97 | # # Code used to prodcue plot on page 441 98 | # def fit_data(input_file): 99 | # masses, distances = get_data(input_file) 100 | # distances = np.array(distances) 101 | # forces = np.array(masses)*9.81 102 | # new_forces = np.append(forces, np.array([1.5*9.81])) 103 | # plt.plot(forces, distances, 'ko', 104 | # label = 'Measured displacements') 105 | # plt.title('Measured Displacement of Spring') 106 | # plt.xlabel('|Force| (Newtons)') 107 | # plt.ylabel('Distance (meters)') 108 | # #find linear fit 109 | # a,b = np.polyfit(forces, distances, 1) 110 | # predicted_distances = a*np.array(new_forces) + b 111 | # k = 1.0/a #see explanation in text 112 | # plt.plot(new_forces, predicted_distances, 113 | # label = 'Linear fit, k = ' + str(round(k, 5))) 114 | # # find cubic fit 115 | # fit = np.polyfit(forces, distances, 3) 116 | # predicted_distances = np.polyval(fit, new_forces) 117 | # plt.plot(new_forces, predicted_distances, 'k:', label = 'cubic fit') 118 | # plt.legend(loc = 'best') 119 | 120 | # fit_data('springData.csv') 121 | 122 | # # Figure 20-11 from page 444 123 | def get_trajectory_data(file_name): 124 | distances = [] 125 | heights1, heights2, heights3, heights4 = [],[],[],[] 126 | with open(file_name, 'r') as data_file: 127 | data_file.readline() 128 | for line in data_file: 129 | d, h1, h2, h3, h4 = line.split(',') 130 | distances.append(float(d)) 131 | heights1.append(float(h1)) 132 | heights2.append(float(h2)) 133 | heights3.append(float(h3)) 134 | heights4.append(float(h4)) 135 | return (distances, [heights1, heights2, heights3, heights4]) 136 | 137 | def process_trajectories(file_name): 138 | distances, heights = get_trajectory_data(file_name) 139 | num_trials = len(heights) 140 | distances = np.array(distances) 141 | #Get array containing mean height at each distance 142 | tot_heights = np.array([0]*len(distances)) 143 | for h in heights: 144 | tot_heights = tot_heights + np.array(h) 145 | mean_heights = tot_heights/len(heights) 146 | plt.title('Trajectory of Projectile (Mean of '\ 147 | + str(num_trials) + ' Trials)') 148 | plt.xlabel('Inches from Launch Point') 149 | plt.ylabel('Inches Above Launch Point') 150 | plt.plot(distances, mean_heights, 'ko') 151 | fit = np.polyfit(distances, mean_heights, 1) 152 | altitudes = np.polyval(fit, distances) 153 | plt.plot(distances, altitudes, 'b', label = 'Linear Fit') 154 | fit = np.polyfit(distances, mean_heights, 2) 155 | altitudes = np.polyval(fit, distances) 156 | plt.plot(distances, altitudes, 'k:', label = 'Quadratic Fit') 157 | plt.legend() 158 | 159 | # process_trajectories('launcherData.csv') 160 | 161 | # # Figure 20-13 on page 447 162 | def r_squared(measured, predicted): 163 | """Assumes measured a one-dimensional array of measured values 164 | predicted a one-dimensional array of predicted values 165 | Returns coefficient of determination""" 166 | estimated_error = ((predicted - measured)**2).sum() 167 | mean_of_measured = measured.sum()/len(measured) 168 | variability = ((measured - mean_of_measured)**2).sum() 169 | return 1 - estimated_error/variability 170 | 171 | # # process_trajectories with changes suggested on page 447 172 | def process_trajectories(file_name): 173 | distances, heights = get_trajectory_data(file_name) 174 | num_trials = len(heights) 175 | distances = np.array(distances) 176 | #Get array containing mean height at each distance 177 | tot_heights = np.array([0]*len(distances)) 178 | for h in heights: 179 | tot_heights = tot_heights + np.array(h) 180 | mean_heights = tot_heights/len(heights) 181 | plt.title('Trajectory of Projectile (Mean of '\ 182 | + str(num_trials) + ' Trials)') 183 | plt.xlabel('Inches from Launch Point') 184 | plt.ylabel('Inches Above Launch Point') 185 | plt.plot(distances, mean_heights, 'ko') 186 | fit = np.polyfit(distances, mean_heights, 1) 187 | altitudes = np.polyval(fit, distances) 188 | plt.plot(distances, altitudes, 'b', label = 'Linear Fit') 189 | print('r**2 of linear fit =', r_squared(mean_heights, altitudes)) 190 | fit = np.polyfit(distances, mean_heights, 2) 191 | altitudes = np.polyval(fit, distances) 192 | plt.plot(distances, altitudes, 'k:', label = 'Quadratic Fit') 193 | print('r**2 of quadratic fit =', r_squared(mean_heights, altitudes)) 194 | plt.legend() 195 | 196 | # process_trajectories('launcherData.csv') 197 | 198 | # # Figure 20-14 on page 448 199 | def get_horizontal_speed(quad_fit, min_x, max_x): 200 | """Assumes quad_fit has coefficients of a quadratic polynomial 201 | min_x and max_x are distances in inches 202 | Returns horizontal speed in feet per second""" 203 | inches_per_foot = 12 204 | x_mid = (max_x - min_x)/2 205 | a,b,c = quad_fit[0], quad_fit[1], quad_fit[2] 206 | y_peak = a*x_mid**2 + b*x_mid + c 207 | g = 32.16*inches_per_foot #accel. of gravity in inches/sec/sec 208 | t = (2*y_peak/g)**0.5 #time in seconds from peak to target 209 | print('Horizontal speed =', 210 | int(x_mid/(t*inches_per_foot)), 'feet/sec') 211 | 212 | # # process_trajectories with change suggested on page 449 213 | def process_trajectories(file_name): 214 | distances, heights = get_trajectory_data(file_name) 215 | num_trials = len(heights) 216 | distances = np.array(distances) 217 | #Get array containing mean height at each distance 218 | tot_heights = np.array([0]*len(distances)) 219 | for h in heights: 220 | tot_heights = tot_heights + np.array(h) 221 | mean_heights = tot_heights/len(heights) 222 | plt.title('Trajectory of Projectile (Mean of '\ 223 | + str(num_trials) + ' Trials)') 224 | plt.xlabel('Inches from Launch Point') 225 | plt.ylabel('Inches Above Launch Point') 226 | plt.plot(distances, mean_heights, 'ko') 227 | fit = np.polyfit(distances, mean_heights, 1) 228 | altitudes = np.polyval(fit, distances) 229 | plt.plot(distances, altitudes, 'b', label = 'Linear Fit') 230 | print('r_squared of linear fit =', r_squared(mean_heights, altitudes)) 231 | fit = np.polyfit(distances, mean_heights, 2) 232 | altitudes = np.polyval(fit, distances) 233 | plt.plot(distances, altitudes, 'k:', label = 'Quadratic Fit') 234 | print('r_squared of quadratic fit =', r_squared(mean_heights, altitudes)) 235 | plt.legend() 236 | get_horizontal_speed(fit, distances[-1], distances[0]) 237 | 238 | # process_trajectories('launcherData.csv') 239 | 240 | # # Figure 20-15 on page 450 241 | # vals = [] 242 | # for i in range(10): 243 | # vals.append(3**i) 244 | # plt.plot(vals,'ko', label = 'Actual points') 245 | # x_vals = np.arange(10) 246 | # fit = np.polyfit(x_vals, vals, 5) 247 | # y_vals = np.polyval(fit, x_vals) 248 | # plt.plot(y_vals, 'kx', label = 'Predicted points', 249 | # markeredgewidth = 2, markersize = 25) 250 | # plt.title('Fitting y = 3**x') 251 | # plt.legend(loc = 'upper left') 252 | 253 | # # Code at bottom of page 450 254 | # print('Model predicts that 3**20 is roughly', 255 | # np.polyval(fit, [3**20])[0]) 256 | # print('Actual value of 3**20 is', 3**20) 257 | 258 | # # Code from page 451 259 | # x_vals, y_vals = [], [] 260 | # for i in range(10): 261 | # x_vals.append(i) 262 | # y_vals.append(3**i) 263 | # plt.plot(x_vals, y_vals, 'k') 264 | # plt.semilogy() 265 | 266 | # # Figure 20-18 on page 452 267 | def create_data(f, x_vals): 268 | """Assumes f is a function of one argument 269 | x_vals is an array of suitable arguments for f 270 | Returns array containing results of applying f to the 271 | elements of x_vals""" 272 | y_vals = [] 273 | for i in x_vals: 274 | y_vals.append(f(x_vals[i])) 275 | return np.array(y_vals) 276 | 277 | def fit_exp_data(x_vals, y_vals): 278 | """Assumes x_vals and y_vals arrays of numbers such that 279 | y_vals[i] == f(x_vals[i]), where f is an exponential function 280 | Returns a, b, base such that log(f(x), base) == ax + b""" 281 | log_vals = [] 282 | for y in y_vals: 283 | log_vals.append(math.log(y, 2)) #get log base 2 284 | fit = np.polyfit(x_vals, log_vals, 1) 285 | return fit, 2 286 | 287 | # Code from page 453 288 | x_vals = range(10) 289 | f = lambda x: 3**x 290 | y_vals = create_data(f, x_vals) 291 | plt.plot(x_vals, y_vals, 'ko', label = 'Actual values') 292 | fit, base = fit_exp_data(x_vals, y_vals) 293 | predictedy_vals = [] 294 | for x in x_vals: 295 | predictedy_vals.append(base**np.polyval(fit, x)) 296 | plt.plot(x_vals, predictedy_vals, label = 'Predicted values') 297 | plt.title('Fitting an Exponential Function') 298 | plt.legend(loc = 'upper left') 299 | 300 | #Look at a value for x not in original data 301 | print('f(20) =', f(20)) 302 | print('Predicted value =', int(base**(np.polyval(fit, [20])))) 303 | 304 | # # Code from page 453 modified as described on page 454 305 | x_vals = range(10) 306 | f = lambda x: 3**x + 3 307 | y_vals = create_data(f, x_vals) 308 | plt.plot(x_vals, y_vals, 'ko', label = 'Actual values') 309 | fit, base = fit_exp_data(x_vals, y_vals) 310 | predictedy_vals = [] 311 | for x in x_vals: 312 | predictedy_vals.append(base**np.polyval(fit, x)) 313 | plt.plot(x_vals, predictedy_vals, label = 'Predicted values') 314 | plt.title('Fitting an Exponential Function') 315 | plt.legend(loc = 'upper left') 316 | 317 | #Look at a value for x not in original data 318 | print('f(20) =', f(20)) 319 | print('Predicted value =', int(base**(np.polyval(fit, [20])))) 320 | 321 | -------------------------------------------------------------------------------- /code/chapter 20/launcherData.csv: -------------------------------------------------------------------------------- 1 | Distance,Trial1,Trial2,Trial3,Trial4 2 | 1080,0.0,0.0,0.0,0.0 3 | 1044,2.25,3.25,4.5,6.5 4 | 1008,5.25,6.5,6.5,8.75 5 | 972,7.5,7.75,8.25,9.25 6 | 936,8.75,9.25,9.5,10.5 7 | 900,12.0,12.25,12.5,14.75 8 | 864,13.75,16.0,16.0,16.5 9 | 828,14.75,15.25,15.5,17.5 10 | 792,15.5,16.0,16.6,16.75 11 | 756,17.0,17.0,17.5,19.25 12 | 720,17.5,18.5,18.5,19.0 13 | 540,19.5,20.0,20.25,20.5 14 | 360,18.5,18.5,19.0,19.0 15 | 180,13.0,13.0,13.0,13.0 16 | 0,0.0,0.0,0.0,0.0 17 | -------------------------------------------------------------------------------- /code/chapter 20/springData.csv: -------------------------------------------------------------------------------- 1 | Distance (m),Mass (kg) 2 | 0.0865,0.1 3 | 0.1015,0.15 4 | 0.1106,0.2 5 | 0.1279,0.25 6 | 0.1892,0.3 7 | 0.2695,0.35 8 | 0.2888,0.4 9 | 0.2425,0.45 10 | 0.3465,0.5 11 | 0.3225,0.55 12 | 0.3764,0.6 13 | 0.4263,0.65 14 | 0.4562,0.7 15 | 0.4502,0.75 16 | 0.4499,0.8 17 | 0.4534,0.85 18 | 0.4416,0.9 19 | 0.4304,0.95 20 | 0.437,1.0 21 | -------------------------------------------------------------------------------- /code/chapter 21/chapter21.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import random 4 | import numpy as np 5 | import matplotlib.pyplot as plt 6 | import scipy.stats 7 | 8 | #set line width 9 | plt.rcParams['lines.linewidth'] = 4 10 | #set font size for titles 11 | plt.rcParams['axes.titlesize'] = 16 12 | #set font size for labels on axes 13 | plt.rcParams['axes.labelsize'] = 16 14 | #set size of num_bers on x-axis 15 | plt.rcParams['xtick.labelsize'] = 16 16 | #set size of num_bers on y-axis 17 | plt.rcParams['ytick.labelsize'] = 16 18 | #set size of ticks on x-axis 19 | plt.rcParams['xtick.major.size'] = 7 20 | #set size of ticks on y-axis 21 | plt.rcParams['ytick.major.size'] = 7 22 | #set size of markers, e.g., circles representing points 23 | plt.rcParams['lines.markersize'] = 10 24 | #set num_ber of _times marker is shown when displaying legend 25 | plt.rcParams['legend.numpoints'] = 1 26 | #Set size of type in legend 27 | plt.rcParams['legend.fontsize'] = 14 28 | 29 | 30 | # # Code used to generate data for Figure 21-1 on page 458 31 | random.seed(148) 32 | treatment_dist = (119.5, 5.0) 33 | control_dist = (120, 4.0) 34 | sample_size = 100 35 | treatment_times, control_times = [], [] 36 | for s in range(sample_size): 37 | treatment_times.append(random.gauss(treatment_dist[0], 38 | treatment_dist[1])) 39 | control_times.append(random.gauss(control_dist[0], 40 | control_dist[1])) 41 | control_mean = sum(control_times)/len(control_times) 42 | treatment_mean = sum(treatment_times)/len(treatment_times) 43 | 44 | # plt.plot(treatment_times, 'co', markersize = 8, 45 | # label = 'Treatment group (mean = ' + 46 | # str(round(treatment_mean, 2)) + ')') 47 | # plt.plot(control_times, 'kv', markersize = 8, 48 | # label = 'Control group (mean = ' + 49 | # str(round(control_mean,2)) + ')') 50 | # plt.title('Test of PED-X') 51 | # plt.xlabel('Cyclist') 52 | # plt.ylabel('Finishing Time (minutes)') 53 | # plt.ylim(100, 145) 54 | # plt.legend() 55 | 56 | # # Code from page 463 57 | # t_stat = -2.26 # t-statistic for PED-X example 58 | # t_dist = [] 59 | # num_bins = 1000 60 | # for i in range(10000000): 61 | # t_dist.append(scipy.random.standard_t(198)) 62 | # plt.hist(t_dist, bins = num_bins, 63 | # weights = np.array(len(t_dist)*[1.0])/len(t_dist)) 64 | # plt.axvline(t_stat, color = 'w') 65 | # plt.axvline(-t_stat, color = 'w') 66 | # plt.title('T-distribution with 198 Degrees of Freedom') 67 | # plt.xlabel('T-statistic') 68 | # plt.ylabel('Probability') 69 | 70 | # # Figure 21-5 on page 465 71 | # control_mean = round(sum(control_times)/len(control_times), 2) 72 | # treatment_mean = round(sum(treatment_times)/len(treatment_times), 2) 73 | # print('Treatment mean - control mean =', 74 | # round(treatment_mean - control_mean, 2), 'minutes') 75 | # two_sample_test = scipy.stats.ttest_ind(treatment_times, 76 | # control_times, 77 | # equal_var = False) 78 | # print('The t-statistic from two-sample test is', 79 | # round(two_sample_test[0], 2)) 80 | # print('The p-value from two-sample test is', 81 | # round(two_sample_test[1], 2)) 82 | 83 | # # Figure 21-6 on page 467 84 | # random.seed(148) 85 | # treatment_dist = (119.5, 5.0) 86 | # control_dist = (120, 4.0) 87 | # sample_size = 100 88 | # treatment_times, control_times = [], [] 89 | # for s in range(sample_size): 90 | # treatment_times.append(random.gauss(treatment_dist[0], 91 | # treatment_dist[1])) 92 | # control_times.append(random.gauss(control_dist[0], 93 | # control_dist[1])) 94 | 95 | # # Code that produced Figure 21-7 on page 468 96 | 97 | # random.seed(0) 98 | 99 | # treatment_dist = (119.5, 5.0) 100 | # control_dist = (120, 4.0) 101 | # sample_size = 100 102 | # p_vals = [] 103 | # for _ in range(10000): 104 | # treatment_times, control_times = [], [] 105 | # for s in range(sample_size): 106 | # treatment_times.append(random.gauss(treatment_dist[0], 107 | # treatment_dist[1])) 108 | # control_times.append(random.gauss(control_dist[0], 109 | # control_dist[1])) 110 | # two_sample_test = scipy.stats.ttest_ind(treatment_times, 111 | # control_times, 112 | # equal_var = False) 113 | # p_vals.append(two_sample_test[1]) 114 | # mean = sum(p_vals)/len(p_vals) 115 | # num_below = 0 116 | # cut_off = 0.05 117 | # for e in p_vals: 118 | # if e <= cut_off: 119 | # num_below += 1 120 | # frac_below = round(num_below/len(p_vals), 2) 121 | # plt.hist(p_vals, weights = np.array(len(p_vals)*[1])/len(p_vals), 122 | # bins = 100) 123 | # plt.annotate('Mean = ' + str(round(mean, 2)) 124 | # + '\nFraction below ' + str(cut_off) + ' = ' + 125 | # str(frac_below), 126 | # size = 'x-large', 127 | # xycoords = 'axes fraction', xy = (0.25, 0.7)) 128 | # plt.title('P-values from Actual Distribution') 129 | # plt.ylabel('Probability') 130 | # plt.xlabel('p-value') 131 | 132 | # # Code from Figure 21-5 133 | # control_mean = round(sum(control_times)/len(control_times), 2) 134 | # treatment_mean = round(sum(treatment_times)/len(treatment_times), 2) 135 | # print('Treatment mean - control mean =', 136 | # round(treatment_mean - control_mean, 2), 'minutes') 137 | # two_sample_test = scipy.stats.ttest_ind(treatment_times, 138 | # control_times, 139 | # equal_var = False) 140 | # print('The t-statistic from two-sample test is', 141 | # round(two_sample_test[0], 2)) 142 | # print('The p-value from two-sample test is', 143 | # round(two_sample_test[1], 2)) 144 | 145 | # # Code on page 470 that is to be appended to code from Figure 21-5 146 | # one_sample_test = scipy.stats.ttest_1samp(treatment_times, 120) 147 | # print('The t-statistic from one-sample test is', one_sample_test[0]) 148 | # print('The p-value from one-sample test is', one_sample_test[1]) 149 | 150 | # num_games = 1273 151 | # lyndsay_wins = 666 152 | # outcomes = [1.0]*lyndsay_wins + [0.0]*(num_games - lyndsay_wins) 153 | # print('The p-value from a one-sample test is', 154 | # scipy.stats.ttest_1samp(outcomes, 0.5)[1]) 155 | 156 | # # Code from top of page 472 157 | # num_games = 1273 158 | # lyndsay_wins = 666 159 | # outcomes = [1.0]*lyndsay_wins + [0.0]*(num_games - lyndsay_wins) 160 | # print('The p-value from a one-sample test is', 161 | # scipy.stats.ttest_1samp(outcomes, 0.5)[1]) 162 | 163 | # # Code from Figure 21-8 on page 472 164 | # num_games = 1273 165 | # lyndsay_wins = 666 166 | # num_trials = 10000 167 | # at_least = 0 168 | # for t in range(num_trials): 169 | # l_wins = 0 170 | # for g in range(num_games): 171 | # if random.random() < 0.5: 172 | # l_wins += 1 173 | # if l_wins >= lyndsay_wins: 174 | # at_least += 1 175 | # print('Probability of result at least this', 176 | # 'extreme by accident =', at_least/num_trials) 177 | 178 | # # Figure 21-9 on page 473 179 | # num_games = 1273 180 | # lyndsay_wins = 666 181 | # num_trials = 10000 182 | # at_least = 0 183 | # for t in range(num_trials): 184 | # l_wins, j_wins = 0, 0 185 | # for g in range(num_games): 186 | # if random.random() < 0.5: 187 | # l_wins += 1 188 | # else: 189 | # j_wins += 1 190 | # if l_wins >= lyndsay_wins or j_wins >= lyndsay_wins: 191 | # at_least += 1 192 | # print('Probability of result at least this', 193 | # 'extreme by accident =', at_least/num_trials) 194 | 195 | # # Code to produce Figure 21-10 on page 475 196 | # random.seed(0) 197 | # num_trials = 50 198 | # gaussian_1, gaussian_2 = [], [] 199 | # for _ in range(3100): 200 | # gaussian_1.append(random.gauss(100, 5)) 201 | # gaussian_2.append(random.gauss(100.5, 5)) 202 | # p_vals_means = [] 203 | # for sample_size in range(50, 3040, 50): 204 | # p_vals = [] 205 | # for t in range(num_trials): 206 | # sample_1 = random.sample(gaussian_1, sample_size) 207 | # sample_2 = random.sample(gaussian_2, sample_size) 208 | # p_vals.append(scipy.stats.ttest_ind(sample_1, sample_2)[1]) 209 | # p_vals_means.append(sum(p_vals)/len(p_vals)) 210 | # plt.plot(range(50, 3040, 50), p_vals_means, label = 'Mean p-value') 211 | # plt.ylabel('Mean p-value (500 trials)') 212 | # plt.xlabel('Sample Size') 213 | # plt.title('Gaussians with SD = 5, Means 100 & 100.5') 214 | # plt.axhline(0.05, color = 'r', linestyle = 'dashed', label = 'p = 0.05') 215 | # plt.axhline(0.01, linestyle = ':', label = 'p = 0.01') 216 | # plt.yticks(np.arange(0, 1, 0.1)) 217 | # plt.semilogy() 218 | # plt.legend() 219 | 220 | # # get_BM_data from Figure 19-2 221 | def get_BM_data(filename): 222 | """Read the contents of the given file. Assumes the file 223 | in a comma-separated format, with 6 elements in each entry: 224 | 0. Name (string), 1. Gender (string), 2. Age (int) 225 | 3. Division (int), 4. Country (string), 5. Overall time (float) 226 | Returns: dict containing a list for each of the 6 variables.""" 227 | 228 | data = {} 229 | f = open(filename) 230 | line = f.readline() 231 | data['name'], data['gender'], data['age'] = [], [], [] 232 | data['division'], data['country'], data['time'] = [], [], [] 233 | while line != '': 234 | split = line.split(',') 235 | data['name'].append(split[0]) 236 | data['gender'].append(split[1]) 237 | data['age'].append(int(split[2])) 238 | data['division'].append(int(split[3])) 239 | data['country'].append(split[4]) 240 | data['time'].append(float(split[5][:-1])) #remove \n 241 | line = f.readline() 242 | f.close() 243 | return data 244 | 245 | # # Figure 2-11 on page 476 246 | # data = get_BM_data('bm_results2012.csv') 247 | # countries_to_compare = ['BEL', 'BRA', 'FRA', 'JPN', 'ITA'] 248 | 249 | # # Build mapping from country to list of female finishing _times 250 | # country_times = {} 251 | # for i in range(len(data['name'])): #for each racer 252 | # if (data['country'][i] in countries_to_compare and 253 | # data['gender'][i] == 'F'): 254 | # try: 255 | # country_times[data['country'][i]].append(data['time'][i]) 256 | # except KeyError: 257 | # country_times[data['country'][i]] = [data['time'][i]] 258 | 259 | # # Compare finishing times of countries 260 | # for c1 in countries_to_compare: 261 | # for c2 in countries_to_compare: 262 | # if c1 < c2: # < rather than != so each pair examined once 263 | # pVal = scipy.stats.ttest_ind(country_times[c1], 264 | # country_times[c2], 265 | # equal_var = False)[1] 266 | # if pVal < 0.05: 267 | # print(c1, 'and', c2, 268 | # 'have significantly different means,', 269 | # 'p-value =', round(pVal, 4)) 270 | 271 | # random.seed(0) 272 | 273 | # # Figure 21-12 on page 478 274 | # num_hyps = 50 275 | # sample_size = 200 276 | # population = [] 277 | # for i in range(5000): #Create large population 278 | # population.append(random.gauss(0, 1)) 279 | # sample1s, sample2s = [], [] 280 | # #Generate many pairs of small sanples 281 | # for i in range(num_hyps): 282 | # sample1s.append(random.sample(population, sample_size)) 283 | # sample2s.append(random.sample(population, sample_size)) 284 | # #Check pairs for statistically significant difference 285 | # numSig = 0 286 | # for i in range(num_hyps): 287 | # if scipy.stats.ttest_ind(sample1s[i], sample2s[i])[1] < 0.05: 288 | # numSig += 1 289 | # print('# of statistically significantly different (p < 0.05) pairs =', 290 | # numSig) 291 | 292 | -------------------------------------------------------------------------------- /code/chapter 22/chapter22.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import random 4 | import numpy as np 5 | import matplotlib.pyplot as plt 6 | import scipy.integrate 7 | import scipy.stats 8 | 9 | #set line width 10 | plt.rcParams['lines.linewidth'] = 4 11 | #set font size for titles 12 | plt.rcParams['axes.titlesize'] = 16 13 | #set font size for labels on axes 14 | plt.rcParams['axes.labelsize'] = 16 15 | #set size of numbers on x-axis 16 | plt.rcParams['xtick.labelsize'] = 16 17 | #set size of numbers on y-axis 18 | plt.rcParams['ytick.labelsize'] = 16 19 | #set size of ticks on x-axis 20 | plt.rcParams['xtick.major.size'] = 7 21 | #set size of ticks on y-axis 22 | plt.rcParams['ytick.major.size'] = 7 23 | #set size of markers, e.g., circles representing points 24 | plt.rcParams['lines.markersize'] = 10 25 | #set number of times marker is shown when displaying legend 26 | plt.rcParams['legend.numpoints'] = 1 27 | #Set size of type in legend 28 | plt.rcParams['legend.fontsize'] = 14 29 | 30 | # # Figure 22-2 on page 492 31 | def plot_housing(impression): 32 | """Assumes impression a str. Must be one of 'flat', 33 | 'volatile,' and 'fair' 34 | Produce bar chart of housing prices over time""" 35 | labels, prices = ([], []) 36 | with open('midWestHousingPrices.csv', 'r') as f: 37 | #Each line of file contains year quarter price 38 | #for Midwest region of U.S. 39 | for line in f: 40 | year, quarter, price = line.split(',') 41 | label = year[2:4] + '\n Q' + quarter[1] 42 | labels.append(label) 43 | prices.append(int(price)/1000) 44 | quarters = np.arange(len(labels)) #x coords of bars 45 | width = 0.8 #Width of bars 46 | plt.bar(quarters, prices, width) 47 | plt.xticks(quarters+width/2, labels) 48 | plt.title('Housing Prices in U.S. Midwest') 49 | plt.xlabel('Quarter') 50 | plt.ylabel('Average Price ($1,000\'s)') 51 | if impression == 'flat': 52 | plt.ylim(1, 500) 53 | elif impression == 'volatile': 54 | plt.ylim(180, 220) 55 | elif impression == 'fair': 56 | plt.ylim(150, 250) 57 | else: 58 | raise ValueError 59 | # plot_housing('flat') 60 | # plt.figure() 61 | # plot_housing('volatile') 62 | # plt.figure() 63 | # plot_housing('fair') 64 | 65 | # Solution to finger exercise on page 493 66 | def plot_housing(impression): 67 | """Assumes impression a str. Must be one of 'flat', 68 | 'volatile,' and 'fair' 69 | Produce bar chart of housing prices over time""" 70 | labels, prices = ([], []) 71 | with open('midWestHousingPrices.csv', 'r') as f: 72 | #Each line of file contains year quarter price 73 | #for Midwest region of U.S. 74 | for line in f: 75 | year, quarter, price = line.split(',') 76 | label = year[2:4] + '\n Q' + quarter[1] 77 | labels.append(label) 78 | prices.append(int(price)/1000) 79 | quarters = np.arange(len(labels)) #x coords of bars 80 | width = 0.8 #Width of bars 81 | baseline = 200 82 | bars = plt.bar(quarters, np.array(prices) - baseline, width, 83 | bottom = baseline) 84 | for b in bars: 85 | if b.get_height() < 0: 86 | b.set_color('r') 87 | plt.axhline(200) 88 | plt.xticks(quarters+width/2, labels) 89 | plt.title('Housing Prices in U.S. Midwest') 90 | plt.xlabel('Quarter') 91 | plt.ylabel('Average Price ($1,000\'s)') 92 | if impression == 'flat': 93 | plt.ylim(1, 500) 94 | elif impression == 'volatile': 95 | plt.ylim(180, 220) 96 | elif impression == 'fair': 97 | plt.ylim(150, 250) 98 | else: 99 | raise ValueError 100 | 101 | # plot_housing('fair') 102 | 103 | # # Code to produce plots in Figure 22-5 on page 494 104 | def plot_followers(with_jguttag): 105 | if with_jguttag: 106 | plt.bar('jguttag', 6, color = 'g') 107 | plt.bar('khemric', 130000, color = 'c') 108 | plt.bar('katyperry', 95000000, color = 'y') 109 | plt.title('Number of Followers on Instagram') 110 | plt.semilogy() 111 | 112 | # plot_followers(False) 113 | # plt.figure() 114 | # plot_followers(True) 115 | 116 | # # Figure 22-13 on page 505 117 | def june_prob(num_trials): 118 | june_48 = 0 119 | for trial in range(num_trials): 120 | june = 0 121 | for i in range(446): 122 | if random.randint(1,12) == 6: 123 | june += 1 124 | if june >= 48: 125 | june_48 += 1 126 | print('Probability of at least 48 births in June =', 127 | round(june_48/num_trials, 4)) 128 | 129 | # random.seed(0) 130 | # june_prob(10000) 131 | 132 | # # Figure 22-14 on page 506 133 | def any_prob(num_trials): 134 | any_month_48 = 0 135 | for trial in range(num_trials): 136 | months = [0]*12 137 | for i in range(446): 138 | months[random.randint(0,11)] += 1 139 | if max(months) >= 48: 140 | any_month_48 += 1 141 | print('Probability of at least 48 births in some month =', 142 | round(any_month_48/num_trials, 4)) 143 | 144 | # random.seed(0) 145 | # any_prob(10000) 146 | 147 | # # Code from page 510 148 | # print(scipy.stats.ttest_1samp([1, 1], 0.5)[1]) -------------------------------------------------------------------------------- /code/chapter 22/midWestHousingPrices.csv: -------------------------------------------------------------------------------- 1 | 2006,01,210700 2 | 2006,02,203100 3 | 2006,03,216800 4 | 2006,04,216200 5 | 2007,01,212800 6 | 2007,02,203200 7 | 2007,03,209600 8 | 2007,04,197400 9 | 2008,01,219200 10 | 2008,02,198500 11 | 2008,03,184700 12 | 2008,04,202500 13 | 2009,01,187100 14 | 2009,02,193200 15 | 2009,03,184900 16 | 2009,04,196000 17 | -------------------------------------------------------------------------------- /code/chapter 23/chapt23.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Sat Sep 14 12:19:30 2019 5 | 6 | @author: johnguttag 7 | """ 8 | 9 | import pandas as pd 10 | import numpy as np 11 | import matplotlib.pyplot as plt 12 | 13 | #change defaults for plotting 14 | #set line width 15 | plt.rcParams['lines.linewidth'] = 4 16 | #set font size for titles 17 | plt.rcParams['axes.titlesize'] = 20 18 | #set font size for labels on axes 19 | plt.rcParams['axes.labelsize'] = 20 20 | #set size of numbers on x-axis 21 | plt.rcParams['xtick.labelsize'] = 16 22 | #set size of numbers on y-axis 23 | plt.rcParams['ytick.labelsize'] = 16 24 | #set size of ticks on x-axis 25 | plt.rcParams['xtick.major.size'] = 7 26 | #set size of ticks on y-axis 27 | plt.rcParams['ytick.major.size'] = 7 28 | #set size of markers, e.g., circles representing points 29 | #set numpoints for legend 30 | plt.rcParams['legend.numpoints'] = 1 31 | #set parameters for saving figures 32 | plt.rcParams['savefig.dpi'] = 1000 33 | # plt.rcParams['savefig.bbox'] = 'tight' 34 | plt.rcParams['savefig.pad_inches'] = 0 35 | 36 | # # Code on page 512 37 | # wwc = pd.read_csv('wwc2019_q-f.csv') 38 | # print(wwc.to_string()) 39 | 40 | # # Code on page 513 41 | # for i in wwc.index: 42 | # print(i) 43 | 44 | # # Code on page 514 45 | # for c in wwc.columns: 46 | # print(c) 47 | 48 | # print(wwc.values) 49 | 50 | # # Code on page 515 51 | # print(pd.DataFrame()) 52 | 53 | # rounds = ['Semis', 'Semis', '3rd Place', 'Championship'] 54 | # print(pd.DataFrame(rounds)) 55 | 56 | # print(pd.DataFrame({'Round': rounds})) 57 | 58 | # rounds = ['Semis', 'Semis', '3rd Place', 'Championship'] 59 | # teams = ['USA', 'Netherlands', 'Sweden', 'USA'] 60 | # df = pd.DataFrame({'Round': rounds, 'Winner': teams}) 61 | # print(df) 62 | # 63 | # Code on page 516 64 | # df['W Goals'] = [2, 1, 0, 0] 65 | # print(df) 66 | 67 | # df['W Goals'] = [2, 1, 2, 2] 68 | # print(df) 69 | 70 | # print(df.drop('Winner', axis = 'columns')) 71 | 72 | # # Code on page 517 73 | # quarters_dict = {'Round': ['Quarters']*4, 74 | # 'Winner': ['England', 'USA', 'Netherlands', 'Sweden'], 75 | # 'W Goals': [3, 2, 2, 2]} 76 | # df = pd.concat([pd.DataFrame(quarters_dict), df], sort = False) 77 | # print(df.to_string()) 78 | 79 | # print(pd.concat([pd.DataFrame(quarters_dict), df], sort = True).to_string()) 80 | 81 | # # Code on page 518 82 | # print(df.reset_index(drop = True).to_string()) 83 | 84 | # print(df.set_index('Round').to_string()) 85 | 86 | # print(wwc['Winner'].to_string()) 87 | 88 | # # Code on page 519 89 | # print(wwc['Winner'][3]) 90 | 91 | # winners = '' 92 | # for w in wwc['Winner']: 93 | # winners += w + ',' 94 | # print(winners[:-1]) 95 | 96 | # print(wwc[['Winner', 'Loser']].to_string()) 97 | 98 | # # Code on page 520 99 | # print(wwc[['Round','Winner','Loser','W Goals','L Goals']].to_string()) 100 | 101 | # print(wwc[1:2]) 102 | 103 | # print(wwc.loc[3]) 104 | 105 | # # Code on page 521 106 | # print(wwc.loc[[1,3,5]]) 107 | 108 | # print(wwc.loc[3:7:2]) 109 | 110 | # print(wwc.loc[6:]) 111 | 112 | # # Code on page 522 113 | # print(wwc.loc[:2]) 114 | 115 | # print(wwc.loc[0:2, 'Round':'L Goals':2]) 116 | 117 | # wwc_by_round = wwc.set_index('Round') 118 | # print(wwc_by_round.to_string()) 119 | 120 | # # Code on page 523 121 | # print(wwc_by_round.loc['Semis']) 122 | 123 | # print(wwc_by_round.loc[['Semis', 'Championship']]) 124 | 125 | # print(wwc_by_round.loc['Quarters':'Semis':2]) 126 | 127 | # print(wwc_by_round.iloc[[1,2]]) 128 | 129 | # # Code on page 524 130 | # grouped_by_round = wwc.groupby('Round') 131 | # print(grouped_by_round.sum()) 132 | 133 | # print(wwc.groupby('Winner').mean()) 134 | 135 | # # Code on page 525 136 | # print(wwc.groupby(['Loser', 'Round']).mean()) 137 | 138 | # print(wwc.loc[wwc['Winner'] == 'Sweden']) 139 | 140 | # print(wwc.loc[(wwc['Winner'] == 'Sweden') | (wwc['Loser'] == 'Sweden')]) 141 | 142 | # # Code on page 526 143 | def get_country(df, country): 144 | """df a DataFrame with series labeled Winner and Loser 145 | country a str 146 | returns a DataFrame with all rows in which country appears 147 | in either the Winner or Loser column""" 148 | return df.loc[(df['Winner'] == country) | (df['Loser'] == country)] 149 | 150 | # print(get_country(get_country(wwc, 'Sweden'),'Germany')) 151 | 152 | def get_games(df, countries): 153 | return df[(df['Winner'].isin(countries) | 154 | df['Loser'].isin(countries))] 155 | 156 | 157 | # # Code on page 527 158 | # print(wwc['W Goals'].sum()) 159 | 160 | # print((wwc[wwc['Winner'] == 'Sweden']['W Goals'].sum() + 161 | # wwc[wwc['Winner'] == 'Sweden']['L Goals'].sum())) 162 | 163 | # print((wwc['W Goals'].sum() - wwc['L Goals'].sum())/len(wwc['W Goals'])) 164 | 165 | 166 | # # Code on page 528 167 | # wwc['G Diff'] = wwc['W Goals'] - wwc['L Goals'] 168 | # print(wwc) 169 | 170 | # # Add new column to wwc 171 | # wwc['G Diff'] = wwc['W Goals'] - wwc['L Goals'] 172 | # # create a dict with values for new row 173 | # new_row_dict = {'Round': ['Total'], 174 | # 'W Goals': [wwc['W Goals'].sum()], 175 | # 'L Goals': [wwc['L Goals'].sum()], 176 | # 'G Diff': [wwc['G Diff'].sum()]} 177 | # # Create DataFrame from dict, then pass it to concat 178 | # new_row = pd.DataFrame(new_row_dict) 179 | # wwc = pd.concat([wwc, new_row], sort = False).reset_index(drop = True) 180 | # print(wwc.to_string()) 181 | 182 | # # Code on page 529 183 | # print(wwc.loc[wwc['Round'] != 'Total'].corr(method = 'pearson')) 184 | 185 | # # Code on page 530 186 | # pd.set_option('display.max_rows', 6) 187 | # pd.set_option('display.max_columns', 5) 188 | # temperatures = pd.read_csv('US_temperatures.csv') 189 | # print(temperatures) 190 | 191 | # # Code on page 531 192 | # print(temperatures.loc[temperatures['Date']==19790812][['New York','Tampa']]) 193 | 194 | # temperatures['Max T'] = temperatures.max(axis = 'columns') 195 | # temperatures['Min T'] = temperatures.min(axis = 'columns') 196 | # temperatures['Mean T'] = round(temperatures.mean(axis = 'columns'), 2) 197 | # print(temperatures.loc[temperatures['Date']==20000704]) 198 | 199 | # # code from page 532 200 | # # Read in file again, because above code modified temperatures 201 | # temperatures = pd.read_csv('US_temperatures.csv') 202 | 203 | # temperatures.set_index('Date', drop = True, inplace = True) 204 | # temperatures['Max T'] = temperatures.max(axis = 'columns') 205 | # temperatures['Min T'] = temperatures.min(axis = 'columns') 206 | # temperatures['Mean T'] = round(temperatures.mean(axis = 'columns'), 2) 207 | # print(temperatures.loc[20000704:20000704]) 208 | 209 | # plt.figure(figsize = (14, 3)) #set aspect ratio for figure 210 | # plt.plot(list(temperatures['Mean T'])) 211 | # plt.title('Mean Temp Across 21 US Cities') 212 | # plt.xlabel('Days Since 1/1/1961') 213 | # plt.ylabel('Degrees C') 214 | 215 | # plt.figure(figsize = (14, 3)) #set aspect ratio for figure 216 | # plt.plot(list(temperatures['Mean T'])[0:3*365]) 217 | # plt.title('Mean Temp Across 21 US Cities') 218 | # plt.xlabel('Days Since 1/1/1961') 219 | # plt.ylabel('Degrees C') 220 | 221 | # # Figure 23-3 from page 534 222 | def get_dict(temperatures, labels): 223 | """temperatures a DataFrame. Its indices are ints 224 | representing dates of the form yyyymmdd 225 | labels a list of column labels 226 | returns a dict with strs representing years as keys, 227 | the values dicts with the columns as keys, and 228 | a list of the daily temperatures in that column for 229 | that year as values 230 | """ 231 | year_dict = {} 232 | for index, row in temperatures.iterrows(): 233 | year = str(index)[0:4] 234 | try: 235 | for col in labels: 236 | year_dict[year][col].append(row[col]) 237 | except: 238 | year_dict[year] = {col:[] for col in labels} 239 | for col in labels: 240 | year_dict[year][col].append(row[col]) 241 | return year_dict 242 | 243 | # # Code from page 535 244 | temperatures = pd.read_csv('US_temperatures.csv') 245 | temperatures.set_index('Date', drop = True, inplace = True) 246 | temperatures['Mean T'] = round(temperatures.mean(axis = 'columns'), 2) 247 | temperatures['Max T'] = temperatures.max(axis = 'columns') 248 | temperatures['Min T'] = temperatures.min(axis = 'columns') 249 | yearly_dict = get_dict(temperatures, ['Max T', 'Min T', 'Mean T']) 250 | years, mins, maxes, means = [], [], [], [] 251 | for y in yearly_dict: 252 | years.append(y) 253 | mins.append(min(yearly_dict[y]['Min T'])) 254 | maxes.append(max(yearly_dict[y]['Max T'])) 255 | means.append(round(np.mean(yearly_dict[y]['Mean T']), 2)) 256 | yearly_temps = pd.DataFrame({'Year': years, 'Min T': mins, 257 | 'Max T': maxes, 'Mean T': means}) 258 | print(yearly_temps) 259 | 260 | # Figure 23-5 from page 536 261 | # plt.figure(0) 262 | # plt.plot(yearly_temps['Year'], yearly_temps['Mean T']) 263 | # plt.title('Mean Annual Temp in 21 U.S. Cities') 264 | # plt.figure(1) 265 | # plt.plot(yearly_temps['Year'], yearly_temps['Min T']) 266 | # plt.title('Min Annual Temp in 21 U.S. Cities') 267 | # for i in range(2): 268 | # plt.figure(i) 269 | # plt.xticks(range(0, len(yearly_temps), 4), 270 | # rotation = 'vertical', size = 'large') 271 | # plt.ylabel('Degrees C') 272 | 273 | # # Figure 23-5 modified as shown on page 537 274 | # plt.figure(0) 275 | # plt.plot(yearly_temps['Year'], yearly_temps['Mean T']) 276 | # plt.title('Mean Annual Temp in 21 U.S. Cities') 277 | # plt.figure(1) 278 | # plt.plot(yearly_temps['Min T'].rolling(7).mean()) 279 | # plt.title('Min Annual Temp in 21 U.S. Cities') 280 | # for i in range(2): 281 | # plt.figure(i) 282 | # plt.xticks(range(0, len(yearly_temps), 4), 283 | # rotation = 'vertical', size = 'large') 284 | # plt.ylabel('Degrees C') 285 | 286 | # # Code from page 537 287 | # num_years = 7 288 | # for label in ['Min T', 'Max T', 'Mean T']: 289 | # yearly_temps[label] = yearly_temps[label].rolling(num_years).mean() 290 | # yearly_temps['Year'] = yearly_temps['Year'].apply(int) 291 | # print(yearly_temps.corr()) 292 | 293 | # # Implementation fo r_squared from Section 20.2.1 294 | def r_squared(measured, predicted): 295 | """Assumes measured a one-dimensional array of measured values 296 | predicted a one-dimensional array of predicted values 297 | Returns coefficient of determination""" 298 | estimated_error = ((predicted - measured)**2).sum() 299 | mean_of_measured = measured.sum()/len(measured) 300 | variability = ((measured - mean_of_measured)**2).sum() 301 | return 1 - estimated_error/variability 302 | 303 | # # Code from page 538 304 | # indices = np.isfinite(yearly_temps['Mean T']) 305 | # model = np.polyfit(list(yearly_temps['Year'][indices]), 306 | # list(yearly_temps['Mean T'][indices]), 1) 307 | # print(r_squared(yearly_temps['Mean T'][indices], 308 | # np.polyval(model, yearly_temps['Year'][indices]))) 309 | 310 | # # Code from page 539 311 | # temperatures = pd.read_csv('US_temperatures.csv') 312 | # temperatures.drop('Date', axis = 'columns', inplace = True) 313 | # means = round(temperatures.mean(), 2) 314 | # maxes = temperatures.max() 315 | # mins = temperatures.min() 316 | # city_temps = pd.DataFrame({'Min T':mins, 'Max T':maxes, 317 | # 'Mean T':means}) 318 | # city_temps = city_temps.apply(lambda x: 1.8*x + 32) 319 | # city_temps['Max-Min'] = city_temps['Max T'] - city_temps['Min T'] 320 | # print(city_temps.sort_values('Mean T', ascending = False).to_string()) 321 | 322 | # # Code from page 540 323 | # plt.plot(city_temps.sort_values('Max-Min', ascending=False)['Min T'], 324 | # 'b^', label = 'Min T') 325 | # plt.plot(city_temps.sort_values('Max-Min', ascending=False)['Max T'], 326 | # 'kx', label = 'Max T') 327 | # plt.plot(city_temps.sort_values('Max-Min', ascending=False)['Mean T'], 328 | # 'ro', label = 'Mean T') 329 | # plt.xticks(rotation = 'vertical') 330 | # plt.legend() 331 | # plt.title('Variation in Extremal Daily\nTemperature 1961-2015') 332 | # plt.ylabel('Degrees F') 333 | 334 | # # Code from page 541 335 | # emissions = pd.read_csv('global-fossil-fuel-consumption.csv') 336 | # print(emissions) 337 | 338 | # # Code from page 542 339 | # emissions['Fuels'] = emissions.sum(axis = 'columns') 340 | # emissions.drop(['Coal', 'Crude Oil', 'Natural Gas'], axis = 'columns', 341 | # inplace = True) 342 | # num_years = 5 343 | # emissions['Roll F'] =\ 344 | # emissions['Fuels'].rolling(num_years).mean() 345 | # emissions = emissions.round() 346 | 347 | # plt.plot(emissions['Year'], emissions['Fuels'], 348 | # label = 'Consumption') 349 | # plt.plot(emissions['Year'], emissions['Roll F'], 350 | # label = str(num_years) + ' Year Rolling Ave.') 351 | # plt.legend() 352 | # plt.title('Consumption of Fossil Fuels') 353 | # plt.xlabel('Year') 354 | # plt.ylabel('Consumption') 355 | 356 | # # # Code from page 543 357 | # yearly_temps['Year'] = yearly_temps['Year'].astype(int) 358 | # merged_df = pd.merge(yearly_temps, emissions, 359 | # left_on = 'Year', right_on = 'Year') 360 | # print(merged_df) 361 | 362 | print(merged_df.corr().round(2).to_string()) -------------------------------------------------------------------------------- /code/chapter 23/global-fossil-fuel-consumption.csv: -------------------------------------------------------------------------------- 1 | Year,Coal,Crude Oil,Natural Gas 2 | 1965,16151.96017,18054.69004,6306.370076 3 | 1966,16332.01679,19442.23715,6871.686791 4 | 1967,16071.18119,20830.13575,7377.525476 5 | 1968,16312.60576,22613.21746,8046.478672 6 | 1969,16825.99292,24534.98916,8835.591838 7 | 1970,17065.27113,26649.8116,9614.414364 8 | 1971,16971.04648,28233.71612,10289.89468 9 | 1972,17161.86462,30399.20981,10858.55694 10 | 1973,17673.14043,32775.00958,11374.03922 11 | 1974,17687.80045,32299.54837,11652.60482 12 | 1975,18031.66073,31973.18489,11657.59717 13 | 1976,18688.42129,34064.96456,12350.85663 14 | 1977,19241.4531,35224.40759,12756.89778 15 | 1978,19456.78595,36354.28057,13291.68232 16 | 1979,20359.51044,36953.1491,14121.9509 17 | 1980,20856.53098,35506.32689,14238.31962 18 | 1981,21148.79702,34228.87205,14395.89609 19 | 1982,21384.22049,33177.85701,14473.22634 20 | 1983,22040.19421,32981.31709,14706.11331 21 | 1984,22997.47253,33746.54047,15912.38739 22 | 1985,23906.3229,33792.84203,16263.14014 23 | 1986,24182.95534,34819.31693,16421.36448 24 | 1987,25145.10228,35532.11408,17289.17958 25 | 1988,25889.97449,36735.8996,18083.52241 26 | 1989,26152.07667,37343.11239,18902.85595 27 | 1990,25845.88485,37736.94729,19486.64542 28 | 1991,25561.41954,37763.14824,19984.58677 29 | 1992,25478.81089,38422.53103,20076.92098 30 | 1993,25580.92144,38179.42324,20275.09431 31 | 1994,25729.64169,39021.80173,20405.36342 32 | 1995,25867.8533,39555.43054,21121.78818 33 | 1996,26516.28457,40480.1731,22143.41796 34 | 1997,26549.71899,41544.67299,22082.05319 35 | 1998,26351.79429,41768.48384,22485.93806 36 | 1999,26492.77461,42510.09274,23107.57158 37 | 2000,27403.94562,43038.62001,24019.89227 38 | 2001,27851.05371,43421.10755,24367.11133 39 | 2002,28936.6423,43796.55068,25108.12839 40 | 2003,31475.58334,44803.21017,25769.17552 41 | 2004,33656.31109,46503.96733,26752.16794 42 | 2005,36118.94545,47115.72728,27537.09099 43 | 2006,37979.81684,47732.19992,28347.57835 44 | 2007,40143.91171,48471.73162,29580.25097 45 | 2008,40712.5427,48250.64229,30321.37836 46 | 2009,40088.33994,47422.36853,29477.9263 47 | 2010,41932.74507,48949.72046,31759.12422 48 | 2011,43948.96889,49455.27172,32410.44868 49 | 2012,44129.62497,50065.86499,33270.53388 50 | 2013,44953.01385,50698.38455,33714.94785 51 | 2014,44916.83781,51109.97172,33986.84723 52 | 2015,43786.8458,52053.27008,34741.88349 53 | 2016,43101.23216,53001.86598,35741.82987 54 | 2017,43397.13549,53752.27638,36703.96587 -------------------------------------------------------------------------------- /code/chapter 23/wwc2019_q-f.csv: -------------------------------------------------------------------------------- 1 | Round,Winner,W Goals,Loser,L Goals 2 | Quarters,England,3,Norway,0 3 | Quarters,USA,2,France,1 4 | Quarters,Netherlands,2,Italy,0 5 | Quarters,Sweden,2,Germany,1 6 | Semis,USA,2,England,1 7 | Semis,Netherlands,1,Sweden,0 8 | 3rd Place,Sweden,2,England,1 9 | Championship,USA,2,Netherlands,0 10 | -------------------------------------------------------------------------------- /code/chapter 24/chapt24.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import pandas as pd 4 | import numpy as np 5 | import matplotlib.pyplot as plt 6 | 7 | #change defaults for plotting 8 | #set line width 9 | plt.rcParams['lines.linewidth'] = 4 10 | #set font size for titles 11 | plt.rcParams['axes.titlesize'] = 20 12 | #set font size for labels on axes 13 | plt.rcParams['axes.labelsize'] = 20 14 | #set size of numbers on x-axis 15 | plt.rcParams['xtick.labelsize'] = 16 16 | #set size of numbers on y-axis 17 | plt.rcParams['ytick.labelsize'] = 16 18 | #set size of ticks on x-axis 19 | plt.rcParams['xtick.major.size'] = 7 20 | #set size of ticks on y-axis 21 | plt.rcParams['ytick.major.size'] = 7 22 | #set size of markers, e.g., circles representing points 23 | #set numpoints for legend 24 | plt.rcParams['legend.numpoints'] = 1 25 | #set parameters for saving figures 26 | plt.rcParams['savefig.dpi'] = 1000 27 | plt.rcParams['savefig.bbox'] = 'tight' 28 | plt.rcParams['savefig.pad_inches'] = 0 29 | 30 | # # Figure 24-6 on page 554 31 | def minkowski_dist(v1, v2, p): 32 | """Assumes v1 and v2 are equal-length arrays of numbers 33 | Returns Minkowski distance of order p between v1 and v2""" 34 | dist = 0.0 35 | for i in range(len(v1)): 36 | dist += abs(v1[i] - v2[i])**p 37 | return dist**(1/p) 38 | 39 | # # Figure 24-7 on page 555 40 | class Animal(object): 41 | def __init__(self, name, features): 42 | """Assumes name a string; features a list of numbers""" 43 | self.name = name 44 | self.features = np.array(features) 45 | 46 | def get_name(self): 47 | return self.name 48 | 49 | def get_features(self): 50 | return self.features 51 | 52 | def distance(self, other): 53 | """Assumes other is an Animal 54 | Returns the Euclidean distance between feature vectors 55 | of self and other""" 56 | return minkowski_dist(self.get_features(), 57 | other.get_features(), 2) 58 | 59 | # # Figure 24-8 on page 556 60 | def compare_animals(animals, precision): 61 | """Assumes animals is a list of animals, precision an int >= 0 62 | Builds a table of distances between each animal""" 63 | # Get labels for columns and rows 64 | column_labels = [a.get_name() for a in animals] 65 | row_labels = column_labels[:] 66 | table_vals = [] 67 | # Get distances between pairs of animals 68 | # For each row 69 | for a1 in animals: 70 | row = [] 71 | #For each column 72 | for a2 in animals: 73 | distance = a1.distance(a2) 74 | row.append(str(round(distance, precision))) 75 | table_vals.append(row) 76 | # Produce table 77 | table = plt.table(rowLabels=row_labels, 78 | colLabels=column_labels, 79 | cellText=table_vals, 80 | cellLoc='center', 81 | loc='center', 82 | colWidths=[0.2]*len(animals)) 83 | plt.axis('off') 84 | table.scale(1, 2.5) 85 | 86 | # # Code from page 556 87 | # rattlesnake = Animal('rattlesnake', [1,1,1,1,0]) 88 | # boa = Animal('boa', [0,1,0,1,0]) 89 | # dart_frog = Animal('dart frog', [1,0,1,0,4]) 90 | # animals = [rattlesnake, boa, dart_frog] 91 | # compare_animals(animals, 3) 92 | 93 | # # Previous code with addition described on page 557 94 | # rattlesnake = Animal('rattlesnake', [1,1,1,1,0]) 95 | # boa = Animal('boa', [0,1,0,1,0]) 96 | # dart_frog = Animal('dart frog', [1,0,1,0,4]) 97 | # animals = [rattlesnake, boa, dart_frog] 98 | # alligator = Animal('alligator', [1,1,0,1,4]) 99 | # animals.append(alligator) 100 | # compare_animals(animals, 3) 101 | 102 | # # Binary version described on page 558 103 | # rattlesnake = Animal('rattlesnake', [1,1,1,1,0]) 104 | # boa = Animal('boa', [0,1,0,1,0]) 105 | # dart_frog = Animal('dart frog', [1,0,1,0,1]) 106 | # animals = [rattlesnake, boa, dart_frog] 107 | # alligator = Animal('alligator', [1,1,0,1,1]) 108 | # animals.append(alligator) 109 | # compare_animals(animals, 3) 110 | 111 | -------------------------------------------------------------------------------- /code/chapter 25/chapt25.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import pandas as pd 4 | import numpy as np 5 | import matplotlib.pyplot as plt 6 | import random 7 | 8 | #change defaults for plotting 9 | #set line width 10 | plt.rcParams['lines.linewidth'] = 4 11 | #set font size for titles 12 | plt.rcParams['axes.titlesize'] = 20 13 | #set font size for labels on axes 14 | plt.rcParams['axes.labelsize'] = 20 15 | #set size of numbers on x-axis 16 | plt.rcParams['xtick.labelsize'] = 16 17 | #set size of numbers on y-axis 18 | plt.rcParams['ytick.labelsize'] = 16 19 | #set size of ticks on x-axis 20 | plt.rcParams['xtick.major.size'] = 7 21 | #set size of ticks on y-axis 22 | plt.rcParams['ytick.major.size'] = 7 23 | #set size of markers, e.g., circles representing points 24 | #set numpoints for legend 25 | plt.rcParams['legend.numpoints'] = 1 26 | #set parameters for saving figures 27 | plt.rcParams['savefig.dpi'] = 1000 28 | plt.rcParams['savefig.bbox'] = 'tight' 29 | plt.rcParams['savefig.pad_inches'] = 0 30 | 31 | # # Function from Figure 24-6 32 | def minkowski_dist(v1, v2, p): 33 | """Assumes v1 and v2 are equal-length arrays of numbers 34 | Returns Minkowski distance of order p between v1 and v2""" 35 | dist = 0.0 36 | for i in range(len(v1)): 37 | dist += abs(v1[i] - v2[i])**p 38 | return dist**(1/p) 39 | 40 | # # Figure 25-2 on page 564 41 | class Example(object): 42 | 43 | def __init__(self, name, features, label = None): 44 | #Assumes features is an array of floats 45 | self.name = name 46 | self.features = features 47 | self.label = label 48 | 49 | def dimensionality(self): 50 | return len(self.features) 51 | 52 | def set_label(self, label): 53 | self.label = label 54 | 55 | def get_features(self): 56 | return self.features[:] 57 | 58 | def get_label(self): 59 | return self.label 60 | 61 | def get_name(self): 62 | return self.name 63 | 64 | def distance(self, other): 65 | return minkowski_dist(self.features, other.get_features(), 2) 66 | 67 | def __str__(self): 68 | return '{}:{}:{}'.format(self.name, self.features, self.label) 69 | 70 | # # Figure 25-3 on page 565 71 | class Cluster(object): 72 | 73 | def __init__(self, examples): 74 | """Assumes examples a non-empty list of Examples""" 75 | self.examples = examples 76 | self.centroid = self.compute_centroid() 77 | 78 | def update(self, examples): 79 | """Assume examples is a non-empty list of Examples 80 | Replace examples; return amount centroid has changed""" 81 | old_centroid = self.centroid 82 | self.examples = examples 83 | self.centroid = self.compute_centroid() 84 | return old_centroid.distance(self.centroid) 85 | 86 | def compute_centroid(self): 87 | vals = np.array([0.0]*self.examples[0].dimensionality()) 88 | for e in self.examples: #compute mean 89 | vals += e.get_features() 90 | centroid = Example('centroid', vals/len(self.examples)) 91 | return centroid 92 | 93 | def get_centroid(self): 94 | return self.centroid 95 | 96 | def variability(self): 97 | tot_dist = 0.0 98 | for e in self.examples: 99 | tot_dist += (e.distance(self.centroid))**2 100 | return tot_dist 101 | 102 | def members(self): 103 | for e in self.examples: 104 | yield e 105 | 106 | def __str__(self): 107 | names = [] 108 | for e in self.examples: 109 | names.append(e.get_name()) 110 | names.sort() 111 | result = ('Cluster with centroid ' 112 | + str(self.centroid.get_features()) + ' contains:\n ') 113 | for e in names: 114 | result = result + e + ', ' 115 | return result[:-2] #remove trailing comma and space 116 | 117 | # # Figure 25-5 on page 569 118 | def dissimilarity(clusters): 119 | tot_dist = 0.0 120 | for c in clusters: 121 | tot_dist += c.variability() 122 | return tot_dist 123 | 124 | def try_k_means(examples, num_clusters, num_trials, verbose = False): 125 | """Calls k_means num_trials times and returns the result with the 126 | lowest dissimilarity""" 127 | best = k_means(examples, num_clusters, verbose) 128 | min_dissimilarity = dissimilarity(best) 129 | trial = 1 130 | while trial < num_trials: 131 | try: 132 | clusters = k_means(examples, num_clusters, verbose) 133 | except ValueError: 134 | continue #If failed, try again 135 | curr_dissimilarity = dissimilarity(clusters) 136 | if curr_dissimilarity < min_dissimilarity: 137 | best = clusters 138 | min_dissimilarity = curr_dissimilarity 139 | trial += 1 140 | return best 141 | 142 | # # Figure 25-4 on page 568 143 | def k_means(examples, k, verbose = False): 144 | # Get k randomly chosen initial centroids, create cluster for each 145 | initial_centroids = random.sample(examples, k) 146 | clusters = [] 147 | for e in initial_centroids: 148 | clusters.append(Cluster([e])) 149 | 150 | # Iterate until centroids do not change 151 | converged = False 152 | num_iterations = 0 153 | while not converged: 154 | num_iterations += 1 155 | #Create a list containing k distinct empty lists 156 | new_clusters = [] 157 | for i in range(k): 158 | new_clusters.append([]) 159 | 160 | # Associate each example with closest centroid 161 | for e in examples: 162 | # Find the centroid closest to e 163 | smallest_distance = e.distance(clusters[0].get_centroid()) 164 | index = 0 165 | for i in range(1, k): 166 | distance = e.distance(clusters[i].get_centroid()) 167 | if distance < smallest_distance: 168 | smallest_distance = distance 169 | index = i 170 | # Add e to the list of examples for appropriate cluster 171 | new_clusters[index].append(e) 172 | 173 | for c in new_clusters: # Avoid having empty clusters 174 | if len(c) == 0: 175 | raise ValueError('Empty Cluster') 176 | 177 | # Update each cluster; check if a centroid has changed 178 | converged = True 179 | for i in range(k): 180 | if clusters[i].update(new_clusters[i]) > 0.0: 181 | converged = False 182 | if verbose: 183 | print('Iteration #' + str(num_iterations)) 184 | for c in clusters: 185 | print(c) 186 | print('') #add blank line 187 | return clusters 188 | 189 | # # Figure 25-6 on page 570 190 | def gen_distribution(x_mean, x_sd, y_mean, y_sd, n, name_prefix): 191 | samples = [] 192 | for s in range(n): 193 | x = random.gauss(x_mean, x_sd) 194 | y = random.gauss(y_mean, y_sd) 195 | samples.append(Example(name_prefix+str(s), [x, y])) 196 | return samples 197 | 198 | def plot_samples(samples, marker): 199 | x_vals, y_vals = [], [] 200 | for s in samples: 201 | x = s.get_features()[0] 202 | y = s.get_features()[1] 203 | plt.annotate(s.get_name(), xy = (x, y), 204 | xytext = (x+0.13, y-0.07), 205 | fontsize = 'x-large') 206 | x_vals.append(x) 207 | y_vals.append(y) 208 | plt.plot(x_vals, y_vals, marker) 209 | 210 | def contrived_test(num_trials, k, verbose = False): 211 | x_mean = 3 212 | x_sd = 1 213 | y_mean = 5 214 | y_sd = 1 215 | n = 10 216 | d1_samples = gen_distribution(x_mean, x_sd, y_mean, y_sd, n, 'A') 217 | plot_samples(d1_samples, 'k^') 218 | d2_samples = gen_distribution(x_mean+3, x_sd, y_mean+1, 219 | y_sd, n, 'B') 220 | plot_samples(d2_samples, 'ko') 221 | clusters = try_k_means(d1_samples+d2_samples, k, num_trials, 222 | verbose) 223 | print('Final result') 224 | for c in clusters: 225 | print('', c) 226 | 227 | # random.seed(1) 228 | # contrived_test(1, 2, True) 229 | # contrived_test(50, 2, False) 230 | 231 | # # Figure 25-9 on page 574 232 | def contrived_test2(num_trials, k, verbose = False): 233 | x_mean = 3 234 | x_sd = 1 235 | y_mean = 5 236 | y_sd = 1 237 | n = 8 238 | d1_samples = gen_distribution(x_mean,x_sd, y_mean, y_sd, n, 'A') 239 | plot_samples(d1_samples, 'k^') 240 | d2_samples = gen_distribution(x_mean+3,x_sd,y_mean, y_sd, n, 'B') 241 | plot_samples(d2_samples, 'ko') 242 | d3Samples = gen_distribution(x_mean, x_sd, y_mean+3, y_sd, n, 'C') 243 | plot_samples(d3Samples, 'kx') 244 | clusters = try_k_means(d1_samples + d2_samples + d3Samples, 245 | k, num_trials, verbose) 246 | plt.ylim(0, 12) 247 | print('Final result has dissimilarity', 248 | round(dissimilarity(clusters), 3)) 249 | for c in clusters: 250 | print('', c) 251 | 252 | # # Code on page 575 253 | # random.seed(0) 254 | # contrived_test2(40, 2) 255 | 256 | # random.seed(0) 257 | # contrived_test2(40, 3) 258 | 259 | # random.seed(0) 260 | # contrived_test2(40, 6) 261 | 262 | # # Figure 25-12 on page 578 263 | def read_mammal_data(fName, scale_method = None): 264 | """fName a CSV file describing dentition of mammals 265 | returns a dict mapping species to feature vectors 266 | """ 267 | df = pd.read_csv('dentalFormulas.csv', comment = '#') 268 | df = df.set_index('Name') 269 | if scale_method != None: 270 | for c in df.columns: 271 | df[c] = scale_method(df[c]) 272 | feature_vector_list = [np.array(df.loc[i].values) 273 | for i in df.index] 274 | species_names = list(df.index) 275 | return {species_names[i]: feature_vector_list[i] 276 | for i in range(len(species_names))} 277 | 278 | def build_mammal_examples(species_dict): 279 | examples = [] 280 | for i in species_dict: 281 | example = Example(i, species_dict[i]) 282 | examples.append(example) 283 | return examples 284 | 285 | def test_teeth(file_name, num_clusters, num_trials, 286 | scale_method = None): 287 | def print_clustering(clustering): 288 | for c in clustering: 289 | names = '' 290 | for p in c.members(): 291 | names += p.get_name() + ', ' 292 | print('\n' + names[:-2]) #remove trailing comma and space 293 | species_dict = read_mammal_data(file_name, scale_method) 294 | examples = build_mammal_examples(species_dict) 295 | print_clustering(try_k_means(examples, num_clusters, num_trials)) 296 | 297 | # # Code on page 579 298 | # random.seed(0) 299 | # test_teeth('dentalFormulas.csv', 3, 40) 300 | 301 | # # Figure 25-13 on page 580 302 | def z_scale(vals): 303 | """Assumes vals is a sequence of floats""" 304 | result = np.array(vals) - np.array(vals).mean() 305 | return (result/np.std(result)).round(4) 306 | 307 | def linear_scale(vals): 308 | """Assumes vals is a sequence of floats""" 309 | vals = np.array(vals) 310 | vals -= vals.min() 311 | return (vals/vals.max()).round(4) 312 | 313 | # random.seed(0) 314 | # test_teeth('dentalFormulas.txt', 3, 40, z_scale) 315 | 316 | # # Figure 25-15 on page 582 317 | def add_labels(examples, label_file): 318 | df = pd.read_csv(label_file, comment = '#') 319 | df = df.set_index('Name') 320 | for e in examples: 321 | if e.get_name() in df.index: 322 | e.set_label(df.loc[e.get_name()]['Diet']) 323 | 324 | def check_diet(cluster): 325 | herbivores, carnivores, omnivores = 0, 0, 0 326 | for m in cluster.members(): 327 | if m.get_label() == 0: 328 | herbivores += 1 329 | elif m.get_label() == 1: 330 | carnivores += 1 331 | else: 332 | omnivores += 1 333 | print(' ', herbivores, 'herbivores,', carnivores, 'carnivores,', 334 | omnivores, 'omnivores\n') 335 | 336 | def test_teeth_diet(features_file, labels_file, num_clusters, 337 | num_trials, scale_method = None): 338 | def print_clustering(clustering): 339 | for c in clustering: 340 | names = '' 341 | for p in c.members(): 342 | names += p.get_name() + ', ' 343 | print(names[:-2]) 344 | check_diet(c) 345 | species_dict = read_mammal_data(features_file, scale_method) 346 | examples = build_mammal_examples(species_dict) 347 | add_labels(examples, labels_file) 348 | print_clustering(try_k_means(examples, num_clusters, num_trials)) 349 | 350 | # # Code on page 583 351 | # random.seed(0) 352 | # test_teeth_diet('dentalFormulas.csv', 'diet.csv', 3, 40, z_scale) 353 | -------------------------------------------------------------------------------- /code/chapter 25/dentalFormulas.csv: -------------------------------------------------------------------------------- 1 | #Meaning of columns given by next line (t for top and b or bottom) 2 | #Name,t incisors,t canines,t premolars,t molars,b incisors,b canines, 3 | #b premolars,b molars,weight 4 | Name,ti,tc,tpm,tm,bi,bc,bpm,bm,weight 5 | Badger,3,1,3,1,3,1,3,2,10 6 | Bear,3,1,4,2,3,1,4,3,278 7 | Cougar,3,1,3,1,3,1,2,1,63 8 | Cow,0,0,3,3,3,1,2,1,400 9 | Deer,0,0,3,3,4,0,3,3,200 10 | Dog,3,1,4,2,3,1,4,3,20 11 | Elk,0,1,3,3,3,1,3,3,500 12 | Fox,3,1,4,2,3,1,4,3,5 13 | Fur seal,3,1,4,1,2,1,4,1,200 14 | Grey seal,3,1,3,2,2,1,3,2,268 15 | Guinea pig,1,0,1,3,1,0,1,3,1 16 | Human,2,1,2,3,2,1,2,3,150 17 | Jaguar,3,1,3,1,3,1,2,1,81 18 | Kangaroo,3,1,2,4,1,0,2,4,55 19 | Lion,3,1,3,1,3,1,2,1,175 20 | Mink,3,1,3,1,3,1,3,2,1 21 | Mole,3,1,4,3,3,1,4,3,0.75 22 | Moose,0,0,3,3,4,0,3,3,900 23 | Mouse,1,0,0,3,1,0,0,3,0.3 24 | Pig,3,1,4,3,3,1,4,3,50 25 | Porcupine,1,0,1,3,1,0,1,3,3 26 | Rabbit,2,0,3,3,1,0,2,3,1 27 | Raccoon,3,1,4,2,3,1,4,2,40 28 | Rat,1,0,0,3,1,0,0,3,.75 29 | Red bat,1,1,2,3,3,1,2,3,1 30 | Sea lion,3,1,4,1,2,1,4,1,415 31 | Skunk,3,1,3,1,3,1,3,2,2 32 | Squirrel,1,0,2,3,1,0,1,3,2 33 | Wolf,3,1,4,2,3,1,4,3,27 34 | Woodchuck,1,0,2,3,1,0,1,3,4 35 | -------------------------------------------------------------------------------- /code/chapter 25/diet.csv: -------------------------------------------------------------------------------- 1 | #diet: 0=herbivore, 1=carnivore, 2=omnivore 2 | Name,Diet 3 | Badger,1 4 | Bear,2 5 | Cougar,1 6 | Cow,0 7 | Deer,0 8 | Dog,1 9 | Elk,0 10 | Fox,1 11 | Fur seal,1 12 | Grey seal,1 13 | Guinea pig0 14 | Human,2 15 | Jaguar,1 16 | Kangaroo,0 17 | Lion,1 18 | Mink,1 19 | Mole,1 20 | Moose,0 21 | Mouse,2 22 | Pig,2 23 | Porcupine,0 24 | Rabbit,0 25 | Raccoon,2 26 | Rat,2 27 | Red bat,1 28 | Sea lion,1 29 | Skunk,2 30 | Squirrel,2 31 | Wolf,1 32 | Woodchuck,2 33 | -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guttag/Intro-to-Computation-and-Programming/f65a3300a2c17c73f84ac701d16cc495be880180/cover.jpg -------------------------------------------------------------------------------- /errata.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guttag/Intro-to-Computation-and-Programming/f65a3300a2c17c73f84ac701d16cc495be880180/errata.pdf --------------------------------------------------------------------------------