def get_lab_exercise() -> LabExercise: pd_mono = pl.Monospace('pandas') dfs_mono = pl.Monospace('DataFrames') next_slide = lp.Overlay([lp.UntilEnd(lp.NextWithIncrement())]) df_to_excel_example = pl.Python( "df.to_excel('data.xlsx', sheet_name='My Data', index=False)") df_from_excel_example = pl.Python( "df = pd.read_excel('data.xlsx', sheet_name='My Data')") index_false_mono = pl.Monospace('index=False') addin_install_mono = pl.Monospace('xlwings addin install') addin_install_success = pl.Monospace( 'Successfuly installed the xlwings add-in! Please restart Excel.') random_seed_py = pl.Monospace('random_seed.py') random_seed_excel = pl.Monospace('random_seed.xlsm') quickstart_mono = pl.Monospace('xlwings quickstart') quickstart_project_mono = pl.Monospace( 'xlwings quickstart my_project_name') cd_mono = pl.Monospace('cd') xw_func_decorator = pl.Monospace('@xw.func') random_choice_mono = pl.Monospace('random_choice') random_choices_mono = pl.Monospace('random_choices') random_choice_py = pl.Monospace('random.choices') xlwings_mono = pl.Monospace('xlwings') df_returns_example = pl.Monospace("df['Stock Price'].pct_change()") bullet_contents = [ [[ 'In your', xlwings_mono, 'Python file, add a function which will generate 1, 2, ... N in a column for', 'whatever N is passed.' ], [ 'Add a cell in your wookbook containing the number of rows to be generated, and call your UDF in', 'another cell.' ], [ 'Change the number of rows to be generated and see the number of rows in the output change.' ]], [[ 'In your', xlwings_mono, 'project workbook, add a column Stock Price which has five prices below it,', '100, 110, 115, 108, and 105.' ], [ 'In the Python file, write a UDF, which accepts the top-left cell of this table (the one', 'with Stock Price), and returns the stock returns.' ], [ 'Call this UDF next to the stock price column so that you have the return from last period to this one', 'next to the stock prices.' ], ['You may find', df_returns_example, 'useful for this purpose.'], ['Answers should be 10%, 4.5%, -6%, -2.8%']] ] return LabExercise(bullet_contents, 'Advanced UDFs', f"Dynamic and Array UDFs with {xlwings_mono}", label='lab:dynamic-array-udf')
def get_content(): random.seed(1000) lecture = get_sensitivity_analysis_lecture() sensitivity_excel_lab = get_sensitivity_analysis_excel_lab_lecture().to_pyexlatex() dictionaries_lab = get_dictionaries_lab_lecture().to_pyexlatex() list_comp_lab = get_list_comprehensions_lab_lecture().to_pyexlatex() sensitivity_python_lab = get_sensitivity_analysis_python_lab_lecture().to_pyexlatex() appendix_frames = [ lecture.pyexlatex_resources_frame, sensitivity_excel_lab.appendix_frames(), dictionaries_lab.appendix_frames(), list_comp_lab.appendix_frames(), sensitivity_python_lab.appendix_frames(), ] pd_mono = pl.Monospace('pandas') series_mono = pl.Monospace('Series') df_mono = pl.Monospace('DataFrame') apply_mono = pl.Monospace('apply') import_mono = pl.Monospace('import') for_mono = pl.Monospace('for') dict_mono = pl.Monospace('dict') np_mono = pl.Monospace('numpy') pd_mono = pl.Monospace('pandas') import_something_mono = pl.Monospace('import something') something_file = pl.Monospace('something.py') numpy_file = pl.Monospace('numpy.py') def_mono = pl.Monospace('def') class_mono = pl.Monospace('class') sensitivity_file_mono = pl.Monospace('sensitivity.py') sensitivity_import = pl.Monospace('import sensitivity') sensitivity_func_mono = pl.Monospace('sensitivity.sensitivity_hex_plots?') pip_install_mypackage = pl.Monospace('pip install mypackage') jupyter_install_mypackage = pl.Monospace('!pip install mypackage') itertools_product = pl.Monospace('itertools.product') sensitivity = pl.Monospace('sensitivity') series_ex_1 = pl.Python( """ >>> df = pd.DataFrame() >>> df['Numbers'] = [1, 2, 3] >>> df['Categories'] = ['apple', 'apple', 'orange'] >>> df """ ) series_ex_2 = pl.Python( """ >>> df['Categories'] 0 apple 1 apple 2 orange Name: Categories, dtype: object >>> type(df['Categories']) pandas.core.series.Series """ ) series_ex_3 = pl.Python( """ >>> cats = df['Categories'] >>> cats 0 apple 1 apple 2 orange Name: Categories, dtype: object >>> cats[2] 'orange' >>> cats.index = ['a', 'b', 'c'] >>> cats a apple b apple c orange Name: Categories, dtype: object >>> cats['b'] 'apple' """ ) list_comprehension_ex_1 = pl.Python( """ >>> out_values = [] >>> for i in range(5): >>> out_values.append(i + 10) >>> out_values [10, 11, 12, 13, 14] """ ) list_comprehension_ex_2 = pl.Python( """ >>> out_values = [i + 10 for i in range(5)] >>> out_values [10, 11, 12, 13, 14] """ ) dict_example = pl.Python( """ >>> coffee_levels_emotions = { >>> 'high': 'happy', >>> 'pretty high': 'happy', >>> 'medium': 'neutral', >>> 'low': 'sad', >>> 'empty': 'desparate' >>> } >>> coffee_levels_emotions['pretty high'] 'happy' >>> for coffee_level, emotion in coffee_levels_emotions.items(): >>> print(f"I'm {emotion} when my coffee is {coffee_level}") """ ) dict_printout = """ I'm happy when my coffee is high I'm happy when my coffee is pretty high I'm neutral when my coffee is medium I'm sad when my coffee is low I'm desparate when my coffee is empty """ dict_printouts_mono = [pl.Monospace(item) for item in dict_printout.split('\n') if item] dict_printout_output = [] for po in dict_printouts_mono: dict_printout_output.append(po) dict_printout_output.append('') dict_example_2 = pl.Python( """ >>> coffee_levels_emotions.update({'overflowing': 'burned'}) >>> coffee_levels_emotions['negative'] = 'confused' >>> high_value = coffee_levels_emotions.pop('high') >>> coffee_levels_emotions {'pretty high': 'happy', 'medium': 'neutral', 'low': 'sad', 'empty': 'desparate', 'overflowing': 'burned', 'negative': 'confused'} >>> high_value 'happy' """ ) plain_sensitivity_example = pl.Python( """ inp1_values = [1, 2] inp2_values = [4, 5] results = [] for inp1 in inp1_values: for inp2 in inp2_values: result = model(inp1, inp2,) results.append( (inp1, inp2, result) ) pd.DataFrame(results, columns=['inp1', 'inp2', 'Result']) """ ) easy_sensitivity_example = pl.Python( """ from sensitivity import SensitivityAnalyzer sensitivity_values = { 'inp1': [1, 2], 'inp2': [4, 5], } sa = SensitivityAnalyzer(sensitivity_values, model) sa.df """ ) return [ pl.Section( [ lp.DimRevealListFrame( [ 'So far, I have given you some inputs to use and you have been getting one or more outputs from ' 'those inputs', 'We have not considered how those inputs may change, and how that affects the outputs', 'This is where building a model vs. doing a calculation really starts to pay off' ], title='Moving from a Static Model' ), lp.GraphicFrame( explore_parameters_graphic(), title='How to Explore Inputs and their Affect on Outputs' ), lp.DimRevealListFrame( [ pl.TextSize(-1), 'In this lecture, we will be discussing sensitivity analysis as an approach to exploring the ' 'parameter space.', 'After we cover probabilistic modeling, we will revisit exploring the parameter space with other ' 'methods: scenario analysis and Monte Carlo Simulation.', 'In sensitivity analysis, a fixed set of values for the parameters are chosen, while in Monte Carlo ' 'Simulation, each parameter is assigned a distribution.', 'In scenario analysis, several realistic cases of the inputs are chosen which represent ' 'possible real-world situations', 'All three methods may be used together to fully understand a model.' ], title='Methods of Parameter Exploration' ), ], title='Introduction to Parameter Exploration', short_title='Explore Parameters' ), pl.Section( [ lp.Frame( [ 'For the model given by:', pl.Equation(str_eq='y = f(X)', inline=False), pl.Equation(str_eq='X = [x_1, x_2, ..., x_n]', inline=False), pl.UnorderedList([ [pl.Equation(str_eq='y:'), 'Model output'], [pl.Equation(str_eq='X:'), 'Model input matrix'], [pl.Equation(str_eq='x_i:'), 'Value of $i$th $x$ variable'] ]), 'Follow the following steps:', pl.OrderedList([ ['Choose a set of values for each', pl.Equation(str_eq='x_i')], ['Take the cartesian product of these values as', pl.Equation(str_eq='[X_1, X_2, ..., X_m]')], ['For each', pl.Equation(str_eq='X_i'), 'calculate', pl.Equation(str_eq='y_i = f(X_i)')], ['Store the values of', pl.Equation(str_eq='X_i'), 'mapped to', pl.Equation(str_eq='y_i')], ['Visualize', pl.Equation(str_eq='y_i'), 'versus', pl.Equation(str_eq='X_i')] ]) ], title='Sensitivity Analysis, Formally' ), get_sensitivity_analysis_example_frames(), ], title='Sensitivity Analysis Theory', short_title='SA Theory' ), pl.Section( [ lp.GraphicFrame( images_path('excel-data-table.png'), title='Sensitivity Analysis in Excel' ), lp.DimRevealListFrame( [ 'There are two main ways to visualize sensitivity analysis results in Excel: graphing and ' 'conditional formatting.', 'Graphing is usually appropriate for one-way data tables', 'Conditional formatting is usually appropriate for two-way data tables' ], title='Visualizing Sensitivity Analysis in Excel' ), lp.GraphicFrame( images_path('excel-conditional-formatting.png'), title='Conditional Formatting in Excel' ), InClassExampleFrame( [ 'I will now go through adding sensitivity analysis to the Dynamic Salary Retirement Model ' 'in Excel', 'The completed exercise on the course site, ' '"Dynamic Salary Retirement Model Sensitivity.xlsx"' ], title='Sensitivity Analysis in Excel', block_title='Adding Sensitivity Analysis to the Dynamic Retirement Excel Model' ), sensitivity_excel_lab.presentation_frames(), ], title='Sensitivity Analysis in Excel with Data Tables', short_title='SA Excel' ), pl.Section( [ lp.Frame( [ "We'll cover a couple more Python patterns and a new data type before jumping into sensitivity analysis", pl.UnorderedList([ 'Dictionaries', 'List comprehensions', ['Python', import_mono, 'system and custom code'] ]) ], title=f'Going Deeper into Python Code Structure' ), lp.TwoColumnGraphicDimRevealFrame( [ ['A dictionary, or', dict_mono, 'for short, is another basic Python data type like lists, numbers, and strings.'], 'Like a list, it is a collection: it holds other objects.', ['Unlike a list, a', dict_mono, 'is composed of key-value pairs. It holds relationships between objects.'] ], graphics=[ lg.ModifiedPicture( images_path('dictionary-book.jpg'), draw_items=[ lg.Path('draw', [(0.5, 0.5)], draw_type='circle', options=['radius=0.4', 'red', 'line width=5mm']), lg.Path('draw', [(0.2, 0.75), (0.8, 0.2)], draw_type='--', options=['red', 'line width=5mm']) ] ) ], title='What is a Dictionary?' ), lp.Frame( [ lp.Block( [ pl.TextSize(-2), dict_example, *dict_printout_output ], title='Basic Dictionary Example' ) ], title='How to Use Dictionaries' ), lp.Frame( [ lp.Block( [ dict_example_2, ], title='Add and Delete Items from Dictionaries' ) ], title='How to Modify Dictionaries' ), InClassExampleFrame( [ 'I will now start going through the example notebook called ' '"Python Dicts, List comprehensions, and Imports.ipynb"', 'I will go through the Dictionaries section for now' ], title='More About Dictionaries in Python', block_title='Using Dictionaries' ), dictionaries_lab.presentation_frames(), lp.Frame( [ pl.TextSize(-1), lp.Block( [ list_comprehension_ex_1 ], title=f'The Original Way' ), lp.Block( [ list_comprehension_ex_2 ], title=f'With List Comprehension' ), lp.Block( ['You', pl.Bold('never'), 'need to use list comprehension, it is just for convenience. The original', for_mono, 'loop syntax will always work fine.'], title='Notice' ) ], title=f"An Easier way to Build Simple Lists from Loops" ), InClassExampleFrame( [ 'I will continue going through the example notebook ' '"Python Dicts, List comprehensions, and Imports.ipynb"', 'I will go through the List Comprehensions section for now' ], title='Easier Loops in Python', block_title='Using List Comprehensions' ), list_comp_lab.presentation_frames(), lp.DimRevealListFrame( [ ['In the past we have used', import_mono, 'to load packages such as', np_mono, 'and', pd_mono], ['These packages are just Python files. We can also write our own Python files and', import_mono, 'them the same way'], [f'When you {import_something_mono}, Python first searches the current directory for a file', something_file, "and if it doesn't find it, it searches your installed packages"], ['In fact if you added a', numpy_file, 'in the current directory and tried to', import_mono, np_mono, 'it would', import_mono, 'the contents of that file rather than the', np_mono, 'package.'] ], title=f'Understanding Python {import_mono}s' ), lp.DimRevealListFrame( [ ['You can write your own functions and classes, then put them in a Python file and', import_mono, 'them into your notebook.'], ['When you', import_mono, 'a file, it executes the contents of that file. So you generally want just ' 'function and class definitions, and not really anything outside of', def_mono, 'or', class_mono, 'statements.'], 'Using Python files is a more maintainable structure for building complex models and apps versus ' 'Jupyter notebooks only.' ], title='Importing Custom Code' ), lp.DimRevealListFrame( [ 'Sometimes you will need a package which does not already come installed with Anaconda', ['The general way to do this is with', pip_install_mypackage, 'replacing mypackage with', 'the package you want to install'], ['You would run this in Anaconda Prompt, or in Jupyter you can run it but you need to put an ' 'exclaimation mark before it to say you want to run it in a terminal. So in Jupyter it would be', jupyter_install_mypackage] ], title='Installing Packages' ), InClassExampleFrame( [ 'I will continue going through the example notebook ' '"Python Dicts, List comprehensions, and Imports.ipynb"', 'I will go through the Imports and Installing Packages section for now' ], title='Installing Packages in Python', block_title='How to Install Packages' ), ], title='Python List Comprehensions, Installing Packages, and More on Dictionaries', short_title='Extra Python Basics' ), pl.Section( [ lp.GraphicFrame( images_path('python-sensitivity-hex-bins.pdf'), title='Sensitivity Analysis in Python - Hex-Bin' ), lp.GraphicFrame( images_path('sensitivity-analysis-styled-df.png'), title='Sensitivity Analysis in Python - Styled DataFrame' ), lp.DimRevealListFrame( [ 'Generally, to do sensitivity analysis in Python without any special tools, you would just ' 'create one nested for loop for each input, and finally within all the loops, run your model ' 'with the inputs from the loops', 'This will work fine, but you will have many nested loops which can become hard to read. Also ' 'it is a fair bit of setup involved.', ['You can avoid the nested loops with', itertools_product, 'but then this becomes more ' 'difficult to use and read'] ], title='How to Do Sensitivity Analysis in Python (The Hard Way)' ), lp.Frame( [ pl.TextSize(-3), pl.UnorderedList([ 'Say you have a function which runs your model, called model, which takes inputs of ' 'inp1 and inp2' ]), lp.Block( [ plain_sensitivity_example, pl.Graphic(images_path('plain-sensitivity-result.png'), width=0.2), ], title='Sensitivity Analysis in Python with No Libraries' ) ], title='Sensitivity Analysis Example (Hard Way)' ), lp.DimRevealListFrame( [ "When I first created this course, I thought there should be a good sensitivity analysis " "tool in Python and I couldn't find it", "The beauty of Python is if you want a tool that doesn't exist, you can create it, and " "share it with others so that nobody else has to deal with the problem.", ['So I created', sensitivity, 'a package for sensitivity analysis in Python, ' 'which makes it very easy'] ], title='How to Do Sensitivity Analysis in Python (The Easy Way)' ), lp.Frame( [ pl.TextSize(-3), pl.UnorderedList([ 'Say you have a function which runs your model, called model, which takes inputs of ' 'inp1 and inp2' ]), lp.Block( [ easy_sensitivity_example, pl.Graphic(images_path('plain-sensitivity-result.png'), width=0.2), ], title=f'Sensitivity Analysis in Python with {sensitivity}' ) ], title='Sensitivity Analysis Example (Easy Way)' ), InClassExampleFrame( [ 'I will now go through Sensitivity Analysis example Jupyter notebook', 'This notebook shows both the standard approach and using the sensitivity package', ], title='Intro to Sensitivity Analysis in Python', block_title='An Overview of the Manual and Automated Approaches' ), InClassExampleFrame( [ 'I will now go through adding sensitivity analysis to the Dynamic Salary Retirement Model ' 'in Python', 'The completed exercise available on the course site is called ' '"Dynamic Salary Retirement Model Sensitivity.ipynb"' ], title='Applying Sensitivity Analysis in Python', block_title='Adding Sensitivity Analysis to the Dynamic Retirement Python Model' ), sensitivity_python_lab.presentation_frames(), ], title='Sensitivity Analysis in Python', short_title='SA Python' ), pl.PresentationAppendix(appendix_frames), ]
def get_content(): lecture = get_python_basics_lecture() conditionals_lab = get_python_basics_conditionals_lab_lecture().to_pyexlatex() lists_lab = get_python_basics_lists_lab_lecture().to_pyexlatex() functions_lab = get_python_basics_functions_lab_lecture().to_pyexlatex() data_types_lab = get_python_basics_data_types_lab_lecture().to_pyexlatex() classes_lab = get_python_basics_classes_lab_lecture().to_pyexlatex() appendix_frames = [ *conditionals_lab.appendix_frames(), *lists_lab.appendix_frames(), *functions_lab.appendix_frames(), *data_types_lab.appendix_frames(), *classes_lab.appendix_frames() ] next_slide = lp.Overlay([lp.NextWithIncrement()]) function_example = pl.Python( """ def my_func(a, b, c=10): return a + b + c >>> my_func(5, 6) 21 """) use_class_example = pl.Python( """ from car_example import Car >>> my_car = Car('Honda', 'Civic') >>> print(my_car) Car(make='Honda', model='Civic') >>> type(my_car) car_example.Car >>> my_car.make 'Honda' >>> my_car.drive() 'The Honda Civic is driving away!' """) dataclass_example = pl.Python( """ from dataclasses import dataclass @dataclass class ModelInputs: interest_rates: tuple = (0.05, 0.06, 0.07) pmt: float = 1000 >>> inputs = ModelInputs(pmt=2000) >>> print(inputs) ModelInputs(interest_rates=(0.05, 0.06, 0.07), pmt=2000) >>> type(inputs) __main__.ModelInputs >>> inputs.interest_rates (0.05, 0.06, 0.07) >>> inputs.pmt 2000 """) if_example = [pl.Python( """ >>> if 5 == 6: >>> print('not true') >>> else: >>> print('else clause') >>> >>> this = 'woo' >>> that = 'woo' >>> >>> if this == that: >>> print('yes, print me') >>> if this == 5: >>> print('should not print') """ ), pl.Monospace('else clause'), OutputLineBreak(), pl.Monospace('yes, print me')] build_list_example = pl.Python( """ >>> inputs = [1, 2, 3] >>> outputs = [] >>> for inp in inputs: >>> outputs.append( >>> inp + 10 >>> ) >>> outputs.insert(0, 'a') >>> print(outputs) ['a', 11, 12, 13] """ ) enumerate_example = [pl.Python( """ >>> inputs = ['a', 'b', 'c'] >>> for i, inp in enumerate(inputs): >>> print(f'input number {i}: {inp}') """ ), pl.Monospace('input number 0: a'), OutputLineBreak(), pl.Monospace('input number 1: b'), OutputLineBreak(), pl.Monospace('input number 2: c') ] list_indexing_example = pl.Python( """ >>> my_list = ['a', 'b', 'c', 'd'] >>> my_list[0] # first item 'a' >>> my_list[1] # second item 'b' >>> my_list[-1] # last item 'd' >>> my_list[:-1] # up until last item ['a', 'b', 'c'] >>> my_list[1:] # after the first item ['b', 'c', 'd'] >>> my_list[1:3] # from the second to the third item ['b', 'c'] """ ) f_string_example = pl.Python( """ >>> my_num = 5 / 6 >>> print(my_num) 0.8333333333333334 >>> print(f'My number is {my_num:.2f}') 'My number is 0.83' """ ) f_string = pl.Monospace("f''") f_mono = pl.Monospace('f') try_except_example = pl.Python( """ >>> my_list = ['a', 'b'] >>> try: >>> my_value = my_list[10] >>> except IndexError: >>> print('caught the error') caught the error """ ) list_100_5 = pl.Monospace('[100] * 5') next_slide = lp.Overlay([lp.NextWithIncrement()]) annuity_example = pl.Python( """ >>> annuity = [100] * 5 >>> annuities = [ >>> annuity, >>> [0, 0, 0] + annuity >>> ] >>> n_years = 10 >>> output = [0] * n_years >>> for i in range(n_years): >>> for ann in annuities: >>> try: >>> output[i] += ann[i] >>> except IndexError: >>> pass >>> print(output) [100, 100, 100, 200, 200, 100, 100, 100, 0, 0] """ ) site_link = Hyperlink(SITE_URL, 'the course site') return [ pl.Section( [ lp.TwoColumnGraphicDimRevealFrame( [ "Now we are going to build our first complex Python model", "We will also learn a bit more Python before we can get there", "Just as we did in Excel, we need to add structure to make the model navigatable", "Logic should be organized in functions and be documented", ], graphics=[ images_path('python-logo.png') ], title='An Organized Structure of an Advanced Python Model' ), lp.GraphicFrame( [ get_model_structure_graphic() ], title='The Structure of a Complex Model' ), ], title='Introduction', short_title='Intro' ), pl.Section( [ lp.Frame( [ lp.Block( [ pl.TextSize(-1), if_example, ], title='If Statements in Python' ), ], title='Python Conditionals - If Statement' ), lp.DimRevealListFrame( [ 'Use two equals signs to compare things (single to assign things)', 'Else is equivalent to value if false behavior in Excel', 'We can do a lot more than just set a single value, anything can be done in an if or else statement', [pl.Monospace('elif'), ' is a shorthand for else if, e.g. not the last condition, but this condition'] ], title='Explaining the If-Else Statements' ), InClassExampleFrame( [ f"On {site_link}, there is a Jupyter notebook called Python Basics containing all " f"of the examples for today's lecture", 'Now I will go through the example material under "Conditionals"' ], title='Conditionals Example', block_title='Trying out Conditionals' ), conditionals_lab.presentation_frames(), ], title='Conditionals' ), pl.Section( [ lp.Frame( [ lp.Block( build_list_example, title='List Building' ), pl.UnorderedList([ lp.DimAndRevealListItems([ ['Use ', pl.Monospace('.append'), ' to add an item to the end of a list'], ['Use ', pl.Monospace('.insert'), ' to add an item at a certain position'], ]) ]) ], title='Python Patterns - Building a List' ), lp.Frame( [ pl.UnorderedList([ 'Index is base zero (0 means first item, 1 means second item)', ]), pl.VFill(), list_indexing_example, ], title='List Indexing and Slicing' ), InClassExampleFrame( [ "We will keep working off of Python Basics.ipynb", 'Now I will go through the example material under "Working more with Lists"' ], title='Lists Example', block_title='Doing More with Lists' ), lists_lab.presentation_frames(), ], title='More with Lists', short_title='Lists' ), pl.Section( [ lp.DimRevealListFrame( [ "In Python, we can group logic into functions", "Functions have a name, inputs, and outputs", "Functions are objects like everything else in Python", function_example, ], title='Functions - Grouping Reusable Logic' ), InClassExampleFrame( [ "We will keep working off of Python Basics.ipynb", 'Now I will go through the example material under "Functions"' ], title='Functions Example', block_title='Structuring Code using Functions' ), functions_lab.presentation_frames(), ], title='Functions' ), pl.Section( [ lp.DimRevealListFrame( [ 'In Python, everything is an object except for variable names, which are references to objects', 'Every object has a type. We have learned about strings, numbers, lists, and booleans (True, False)', 'In the next section on classes, we will learn more about the relationship between the type ' 'and the object' ], title='What are Types?' ), # TODO [#12]: add f-strings to Jupyter example lp.Frame( [ pl.UnorderedList([ lp.DimAndRevealListItems([ 'You may have noticed that we can end up with a lot of decimals in Python output', 'Further, you may want to include your results as part of a larger output, such as a sentence.', f'For these operations, we have {f_mono} strings: {f_string}' ], vertical_fill=True) ]), lp.Block( f_string_example, title='Example', overlay=next_slide ) ], title='Formatting Python Strings' ), lp.DimRevealListFrame( [ 'So far I have just said that numbers are a type in Python, but this is a simplification', ['There are two main types of numbers in python:', pl.Monospace('float'), 'and', pl.Monospace('int'), 'corresponding to a floating point number and an integer, respectively'], ['An', pl.Monospace('int'), 'is a number without decimals, while a', pl.Monospace('float'), 'has decimals, regardless of whether they are zero'], ['For example,', pl.Monospace('3.5'), 'and', pl.Monospace('3.0'), 'are floats, while', pl.Monospace('3'), 'is an int, even though', pl.Monospace('3.0 == 3 is True')], ["Usually, this doesn't matter. But to loop a number of times, you must pass an", pl.Monospace('int')] ], title='Numeric Types' ), lp.DimRevealListFrame( [ ['A', pl.Monospace('tuple'), 'is like a', pl.Monospace('list'), "but you can't change it after " "it has been created (it is immutable)"], ['Tuples are in parentheses instead of brackets, e.g.', pl.Monospace('("a", "b")')], ['A', pl.Monospace('dict'), 'short for dictionary, stores a mapping. Use them if you want ' 'to store values associated to other values'], ['We will come back to', pl.Monospace('dicts'), 'later in the course, but I wanted to', 'introduce them now as they are a very fundamental data type'] ], title='Additional Built-In Types' ), InClassExampleFrame( [ "We will keep working off of Python Basics.ipynb", 'Now I will go through the example material under "Exploring Data Types"' ], title='Data Types Example', block_title='Understanding the Different Data Types' ), data_types_lab.presentation_frames(), ], title='More about Data Types', short_title='Data Types' ), pl.Section( [ lp.GraphicFrame( images_path('class-object.pdf'), title='Overview of Classes and Objects' ), lp.DimRevealListFrame( [ 'In Python, everything is an object except for variable names, which are references to objects', 'Strings, floats, ints, lists, and tuples are types of objects. There are many more types of ' 'objects and users can define their own types of objects', 'A class is a definition for a type of object. It defines how it is created, the data ' 'stored in it, and the functions attached to it', 'We can write our own classes to create new types of objects to work with' ], title='Everything is an Object. Every Object has a Class' ), lp.DimRevealListFrame( [ 'From a single class definition, an unlimited number of objects can be created', 'Typically the class definition says it should accept some data to create the object', 'Then when you have multiple objects of the same type (created from the same class), ' 'they will have the same functions (methods) attached to them, but different data stored within', ['For example, we can create two different lists. They will have different contents, but we can', 'do', pl.Monospace('.append'), 'on either of the lists'] ], title='Many Objects to One Class' ), lp.MultiGraphicFrame( [ images_path('class-object.pdf'), images_path('list-object.pdf') ], title='Lists are Objects', vertical=False ), lp.MultiGraphicFrame( [ images_path('class-object.pdf'), images_path('car-object.pdf') ], title='We can Make Custom Objects Too', vertical=False ), lp.Frame( [ pl.UnorderedList(['Constructing an object from a class looks like calling a function:']), lp.Block( [ pl.TextSize(-1), use_class_example, ], title='Using Custom Classes in Python' ), ], title='Creating and Using Objects' ), lp.DimRevealListFrame( [ 'I will not be teaching you about creating general classes in this course. It is very useful ' 'but is generally more advanced. I encourage you to learn them outside the course.', "We covered this material for two reasons:", ['To give a better understanding of how Python works in general, and why sometimes we ' 'call functions as', pl.Monospace('something.my_func()'), 'rather than', pl.Monospace('my_func()')], ['We are going to use', pl.Monospace('dataclasses'), 'to store our model data. They are', 'a simplified version of classes used mainly for storing data.'] ], title='Where we Will Focus in This Course' ), lp.Frame( [ pl.UnorderedList(['An organized way to store our model input data:']), lp.Block( [ pl.TextSize(-3), dataclass_example, ], title='Using Dataclasses in Python' ), ], title='Dataclass Intro' ), lp.DimRevealListFrame( [ ['A', pl.Monospace('dataclass'), 'is just a class which is more convenient to create, and', 'is typically used to group data together'], ['If you need to pass around multiple variables together, they make sense. For our models, we ' 'will want to pass around all the inputs, so one', pl.Monospace('dataclass'), 'for all the', 'inputs to the model makes sense'], 'This way instead of having to pass around every input individually to every function, just ' 'pass all the input data as one argument', ['Also enables easy tab-completion. What were the names of my inputs? Just hit tab after', pl.Monospace('data.')] ], title='What, When and Why Dataclasses?' ), InClassExampleFrame( [ "We will keep working off of Python Basics.ipynb", 'For this example, also go and download car_example.py and put it in the same folder', 'Now I will go through the example material under "Working with Classes"' ], title='Classes Example', block_title='Working with Classes and Creating Dataclasses' ), classes_lab.presentation_frames(), ], title='Classes and Dataclasses', short_title='Classes' ), pl.Section( [ # TODO [#13]: add error handling to Jupyter example lp.Frame( [ pl.UnorderedList([ lp.DimAndRevealListItems([ "You have certainly already seen errors coming from your Python code. When they have come up, the code doesn't run.", 'Sometimes you actually expect to get an error, and want to handle it in some way, rather than having your program fail.' ], vertical_fill=True) ]), lp.Block( try_except_example, title='Example', overlay=next_slide ) ], title='Python Error Handling' ), lp.DimRevealListFrame( [ "Let's say you're receiving annuities. There is a single annuity which produces \$100 for 5 years. You receive this annuity in year 0 and in year 3.", f"You might define the annuity cash flows as a list of 100, 5 times ({list_100_5})", 'Then you want to come up with your overall cash flows, going out to 15 years' ], title='An Example where Error Handling is Useful' ), lp.Frame( [ lp.Block( [ pl.TextSize(-1), annuity_example, ], title='Calculating the Sum of Unaligned Annuity Cash-Flows' ) ], title='Applying Error Handling' ), ], title='Error Handling', short_title='Errors' ), pl.PresentationAppendix( [ lecture.pyexlatex_resources_frame, *appendix_frames ] ) ]
def get_series_example_frames(): pd_mono = pl.Monospace('pandas') series_mono = pl.Monospace('Series') df_mono = pl.Monospace('DataFrame') series_ex_1 = pl.Python(""" >>> df = pd.DataFrame() >>> df['Numbers'] = [1, 2, 3] >>> df['Categories'] = ['apple', 'apple', 'orange'] >>> df """) series_ex_2 = pl.Python(""" >>> df['Categories'] 0 apple 1 apple 2 orange Name: Categories, dtype: object >>> type(df['Categories']) pandas.core.series.Series """) series_ex_3 = pl.Python(""" >>> cats = df['Categories'] >>> cats 0 apple 1 apple 2 orange Name: Categories, dtype: object >>> cats[2] 'orange' >>> cats.index = ['a', 'b', 'c'] >>> cats a apple b apple c orange Name: Categories, dtype: object >>> cats['b'] 'apple' """) return [ lp.DimRevealListFrame([[ 'A', series_mono, 'is the other main', pd_mono, 'data type besides a', df_mono ], [ 'A single column or row of a', df_mono, 'is a', series_mono ], ['A', series_mono, 'has a name, an index, and one value per index'] ], title=f'What is a {series_mono}?'), lp.Frame([ lp.Block([ series_ex_1, pl.Graphic(images_path('series-example-df.png'), width=0.2), series_ex_2 ], title=f'{series_mono} Example') ], title=f"{df_mono}s are Made up of {series_mono}'"), lp.Frame( [ lp.Block([ pl.TextSize(-1), series_ex_3, ], title=f'Working with {series_mono} Example') ], title=f"Access {series_mono} Values Just Like {df_mono} Columns") ]
def get_content(): pd_mono = pl.Monospace('pandas') dfs_mono = pl.Monospace('DataFrames') df_mono = pl.Monospace('DataFrame') next_slide = lp.Overlay([lp.UntilEnd(lp.NextWithIncrement())]) df_to_excel_example = pl.Python( "df.to_excel('data.xlsx', sheet_name='My Data', index=False)") df_from_excel_example = pl.Python( "df = pd.read_excel('data.xlsx', sheet_name='My Data')") index_false_mono = pl.Monospace('index=False') addin_install_mono = pl.Monospace('xlwings addin install') addin_install_success = pl.Monospace( 'Successfuly installed the xlwings add-in! Please restart Excel.') random_seed_py = pl.Monospace('random_seed.py') random_seed_excel = pl.Monospace('random_seed.xlsm') quickstart_mono = pl.Monospace('xlwings quickstart') quickstart_project_mono = pl.Monospace( 'xlwings quickstart my_project_name') cd_mono = pl.Monospace('cd') xw_func_decorator = pl.Monospace('@xw.func') xw_arg_decorator = pl.Monospace('@xw.arg') xw_ret_decorator = pl.Monospace('@xw.ret') x_mono = pl.Monospace('x') expand_table_mono = pl.Monospace("expand='table'") random_choice_mono = pl.Monospace('random_choice') random_choice_py = pl.Monospace('random.choices') lecture = get_combining_excel_python_lecture() pd_read_write_exercise = get_read_write_excel_pandas_lab_lecture( ).to_pyexlatex() xlwings_exercise = get_read_write_xlwings_lab_lecture().to_pyexlatex() read_from_excel_example = pl.Python(""" my_value = sht.range("G11").value # single value # all values in cell range my_value = sht.range("G11:F13").value # expands cell range down and right getting all values my_values = sht.range("G11").expand().value """) write_to_excel_example = pl.Python(""" sht.range("G11").value = 10 sht.range("G11").value = [10, 11] # horizontal sht.range("G11:G12").value = [10, 11] # vertical # table, DataFrame from elsewhere sht.range("G11").value = df """) return [ pl.Section([ lp.DimRevealListFrame([ "We have learned how to use both Excel and Python to solve problems. Throughout this process, there " "were advantages and disadvantages of each tool for each problem.", "I wanted you to know both tools so you could pick whichever is best to tackle your problem", "For larger problems, you'll likely find some parts are better with Excel and some with Python", "After this lecture, you won't need to choose one anymore, you can use both at once." ], title='Leveraging the Power of Both Tools'), ], title='Introduction'), pl.Section([ lp.DimRevealListFrame([ [pd_mono, 'has built-in tools for working with Excel'], [ pd_mono, 'can read Excel workbooks into', dfs_mono, 'and it can write', dfs_mono, 'back to Excel workbooks' ], 'For simple uses, this may be enough. If you just need to get data from somewhere once and put it in your ' 'workbook, or you have your data in Excel and want to analyze it in Python, this is sufficient', [ "If you want to manipulate your workbook from Python, or you want to run Python code from your " "workbook, look to", xlwings_mono ] ], title=f'How Far does {pd_mono} Get Us?'), lp.Frame([ lp.Block([ df_from_excel_example, pl.VSpace(-0.3), pl.UnorderedList([ "If you don't pass a sheet name, it will take the first sheet." ]) ], title='Reading Excel Files', overlay=next_slide), pl.VFill(), lp.Block( [ df_to_excel_example, pl.VSpace(-0.3), pl.UnorderedList( [[ 'We are passing', index_false_mono, 'because usually the 0, 1, 2 ... index is not useful' ], [ "If you had set your index to something useful, then don't include", index_false_mono ]]) ], title='Writing to Excel Files', overlay=next_slide), pl.VFill(), lp.AlertBlock([[ 'When', pd_mono, 'writes to a workbook, it replaces the file. Do not write over an existing ' 'workbook that you want to keep!' ]], title='Careful When Writing!', overlay=next_slide), ], title=f'Reading and Writing to Excel Files with {pd_mono}' ), lp.Frame([ InClassExampleBlock([ pl.UnorderedList([ 'Download the contents of the "Read Write Excel Pandas" folder in Examples', 'Ensure that you put the Excel file and notebook in the same folder for it to work', 'Follow along with the notebook' ]) ], title= f'Read and Write to Excel using {pd_mono}') ], title='Showcasing Reading and Writing to Excel Files'), pd_read_write_exercise.presentation_frames(), ], title=f'To and From Excel with {pd_mono}', short_title=pd_mono), pl.Section([ lp.TwoColumnGraphicDimRevealFrame([[ 'The easiest way to use Python from in Excel, or Excel from in Python, is', xlwings_mono ], "In Windows, it's based off the Microsoft COM API, which is some common tools they give for creating " "plugins.", "It's still in active development, but overall it works pretty well and is far beyond where we were " "a few years ago"], graphics=[ images_path( 'xlwings-logo.png') ], title= f'Introducing {xlwings_mono}'), lp.DimRevealListFrame( [['There are two main ways to use', xlwings_mono], [ 'You can', pl. Bold('manipulate Excel from Python,'), 'which gives you the full power of Excel from', "within Python. In this class we'll focus on reading and writing values, but you can do anything", "that you would normally be able to in Excel, but by executing Python code." ], [ 'Or you can', pl.Bold('run Python from Excel'), 'using one of two approaches:', pl.Underline('Python as a VBA replacement'), 'and', pl.Underline('user-defined functions (UDFs)') ], 'We will focus on manipulating Excel from Python in this class. I encourage you to explore ' 'the other two approaches on your own.'], title=f'What are the Main Ways to use {xlwings_mono}?'), lp.TwoColumnGraphicDimRevealFrame([ pl.TextSize(-1), [ xlwings_mono, 'allows us to write Python values into Excel and fetch Excel values into Python' ], 'There is also a complete VBA API, meaning you can do everything that you could do with VBA ' 'from within Python, which means you have the full capabilities of Excel within Python', 'There are also convenient features to work with entire tables at once rather than ' 'a single value' ], graphics=[ images_path( 'python-excel-logo.png') ], title= 'Using Python to Drive Excel Models' ), lp.Frame([ lp.Block([read_from_excel_example], title='Read Values from Excel'), lp.Block([write_to_excel_example], title='Write Values to Excel') ], title='Write and Read Values to and from Excel'), InClassExampleFrame([ 'Download the contents of the "xlwings" folder in Examples', 'Ensure that you put the Excel file and notebook in the same folder for it to work', 'Follow along with the notebook' ], title=f'How to Use {xlwings_mono}', block_title=f'Trying out {xlwings_mono}'), xlwings_exercise.presentation_frames(), ], title= f'Introducing Full Python-Excel Connection with {xlwings_mono}', short_title=f'{xlwings_mono}'), pl.PresentationAppendix([ lecture.pyexlatex_resources_frame, pd_read_write_exercise.appendix_frames(), xlwings_exercise.appendix_frames(), ]) ]
def get_lab_exercise() -> LabExercise: pd_mono = pl.Monospace('pandas') dfs_mono = pl.Monospace('DataFrames') next_slide = lp.Overlay([lp.UntilEnd(lp.NextWithIncrement())]) df_to_excel_example = pl.Python( "df.to_excel('data.xlsx', sheet_name='My Data', index=False)") df_from_excel_example = pl.Python( "df = pd.read_excel('data.xlsx', sheet_name='My Data')") index_false_mono = pl.Monospace('index=False') addin_install_mono = pl.Monospace('xlwings addin install') addin_install_success = pl.Monospace( 'Successfuly installed the xlwings add-in! Please restart Excel.') random_seed_py = pl.Monospace('random_seed.py') random_seed_excel = pl.Monospace('random_seed.xlsm') quickstart_mono = pl.Monospace('xlwings quickstart') quickstart_project_mono = pl.Monospace( 'xlwings quickstart my_project_name') cd_mono = pl.Monospace('cd') xw_func_decorator = pl.Monospace('@xw.func') random_choice_mono = pl.Monospace('random_choice') random_choices_mono = pl.Monospace('random_choices') random_choice_py = pl.Monospace('random.choices') xlwings_mono = pl.Monospace('xlwings') bullet_contents = [ [[ 'If you have not already created your', xlwings_mono, 'project, go back two slides', 'and follow those steps.' ], [ 'Edit the .py file to add a function', random_choice_mono, 'which will call', random_choice_py ], 'The function should accept the items to choose from, and the probabilities.', 'Write out a few possible items to choose from in your workbook. Put probabilities next ' 'to them.', [ 'Call your', random_choice_mono, 'function on these inputs, and see it pick a random item' ]], [[ 'Work off the existing', xlwings_mono, 'project from the Level 1 exercise' ], [ 'Now add an additional function', random_choices_mono, 'which will accept the items to', 'choose from, the probabilities, and the number of random choices to generate.' ], [ 'The function should return multiple random choices. In Excel, you should see multiple cells of output,' 'with each cell containing a random choice.' ], [ 'If you return a list from the Python function, it should create this behavior.' ]] ] return LabExercise(bullet_contents, 'Write a Simple UDF', f"Getting your Feet Wet with {xlwings_mono}", label='lab:intro-udf')
def get_content(): random.seed(1000) lecture = get_visualization_lecture() intro_pandas_lab = get_intro_to_pandas_lab_lecture().to_pyexlatex() styling_pandas_lab = get_pandas_styling_lab_lecture().to_pyexlatex() graphing_lab = get_intro_python_visualization_lab_lecture().to_pyexlatex() appendix_frames = [ lecture.pyexlatex_resources_frame, intro_pandas_lab.appendix_frames(), styling_pandas_lab.appendix_frames(), graphing_lab.appendix_frames() ] ret_model = RetirementModel() ret_df = ret_model.get_formatted_df(num_years=12) ret_table = lt.Tabular.from_df(ret_df, extra_header=pl.Bold('Retirement Info')) plt_mono = pl.Monospace('matplotlib') df_mono = pl.Monospace('DataFrame') df_basic_example = pl.Python( """ >>> import pandas as pd >>> df = pd.DataFrame() >>> df['Sales'] = [1052, 212, 346] >>> df['Category'] = ['Aprons', 'Apples', 'Bowties'] df """ ) plot_example_code = pl.Python( """ >>> %matplotlib inline >>> ret_df.plot.line(x='Time', y='Salaries') """ ) return [ pl.Section( [ lp.DimRevealListFrame( [ "So far we've had one main output from our model, number of years", "Salaries and wealth over time have also been outputs, but we haven't had a good way of understanding " "that output. It's a bunch of numbers.", "This is where visualization comes in. We have some complex result, and want to make it easily " "interpretable." ], title='Why Visualize?' ), lp.Frame( [ pl.Center(ret_table) ], title='What we Have so Far' ), lp.GraphicFrame( images_path('excel-insert-chart.png'), title='Visualization in Excel' ), lp.GraphicFrame( lg.ModifiedPicture( images_path('python-visualization-landscape.jpg'), [ lg.Path('draw', [(0.52, 0.52), (0.85, 0.67)], options=['red'], draw_type='rectangle', overlay=lp.Overlay([2])) ] ), title='An Overwhelming Number of Options in Python' ), lp.DimRevealListFrame( [ ["Ultimately, we will be creating graphs using", plt_mono, "but we won't use it directly."], ["Instead, we will use", pd_mono], [pd_mono, "is actually creating its graphs using", plt_mono, "for us, but it is simpler to use."] ], title='Explaining Python Visualization in This Class' ), InClassExampleFrame( [ 'I will now go back to the "Dynamic Salary Retirement Model.xlsx" Excel model to ' 'add visualization', 'I have also uploaded the completed workbook from this exercise ' 'as "Dynamic Salary Retirement Model Visualized.xlsx"', 'Follow along as I go through the example.', ], title='Visualization in Excel', block_title='Adding Graphs to the Dynamic Salary Retirement Excel Model' ), ], title='Visualization Introduction', short_title='Intro' ), pl.Section( [ lp.DimRevealListFrame( [ [pd_mono, "does", pl.Bold('a lot'), 'more than just graphing. We will use it throughout the ' 'rest of the class.'], "Previously we've worked with lists, numbers, strings, and even our custom types (our model dataclasses)", [pd_mono, "provides the", df_mono, "as a new type that we can use."], f'Before we can get to graphing, we must learn how to use the {df_mono}.' ], title='Some Setup Before we can Visualize in Python' ), lp.Frame( [ ['A', df_mono, 'is essentially a table. It has rows and columns, just like in Excel.'], pl.VFill(), lp.Block( [ pl.UnorderedList([ 'Add or remove columns or rows', 'Group by and aggregate', 'Load in and output data from/to Excel and many other formats', 'Merge and join data sets', 'Reshape and pivot data', 'Time-series functionality', 'Slice and query your data', 'Handle duplicates and missing data' ]) ], title=f'Some Features of the {df_mono}' ) ], title=f'What is a {df_mono}?' ), lp.Frame( [ df_basic_example, pl.Graphic(images_path('df-basic-example.png'), width=0.3) ], title=f'A Basic {df_mono} Example' ), InClassExampleFrame( [ 'I will now go through the notebook in ' '"Intro to Pandas and Table Visualization.ipynb"', 'Follow along as I go through the example.', 'We will complete everything up until DataFrame Styling' ], title='Introduction to Pandas', block_title='Creating and Using Pandas DataFrames' ), intro_pandas_lab.presentation_frames(), lp.DimRevealListFrame( [ ['It is possible to add styling to our displayed tabular data by styling the', df_mono], 'The styling is very flexible and essentially allows you to do anything', 'Out of the box, it is easy to change colors, size, and positioning of text, add a caption, do ' 'conditional formatting, and draw a bar graph over the cells.' ], title='Styling Pandas DataFrames' ), InClassExampleFrame( [ 'I will now go through the next section in ' '"Intro to Pandas and Table Visualization.ipynb"', 'Follow along as I go through the example.', 'This time we are covering the remainder of the notebook starting from "DataFrame Styling"' ], title='Introduction to Pandas', block_title='Creating and Using Pandas DataFrames' ), styling_pandas_lab.presentation_frames(), ], title='Tables with Pandas DataFrames', short_title='Pandas' ), pl.Section( [ lp.Frame( [ lp.Block( [ plot_example_code, pl.Graphic(images_path('python-salaries-line-graph.pdf'), width=0.5) ], title=f'Line Graphs using {pd_mono}' ) ], title='A Minimal Plotting Example' ), lp.MultiGraphicFrame( [ images_path('excel-salaries-line-graph.png'), images_path('python-salaries-line-graph.pdf'), ], vertical=False, title='Basic Graph Types: Line Graphs' ), lp.MultiGraphicFrame( [ images_path('excel-salaries-bar-graph.png'), images_path('python-salaries-bar-graph.pdf'), ], vertical=False, title='Basic Graph Types: Bar Graphs' ), lp.MultiGraphicFrame( [ images_path('excel-salaries-box-whisker-plot.png'), images_path('python-salaries-box-graph.pdf'), ], vertical=False, title='Basic Graph Types: Box and Whisker Plots' ), InClassExampleFrame( [ 'I will now go through ' '"Intro to Graphics.ipynb"', 'Follow along as I go through the entire example notebook.', ], title='Introduction to Graphing', block_title='Graphing Using Pandas' ), graphing_lab.presentation_frames(), ], title='Graphing using Pandas', short_title='Graphs' ), pl.PresentationAppendix(appendix_frames) ]
def get_content(): random.seed(1000) ev_bet = (999999 / 1000000) * 1 + (1 / 1000000) * (-750001) xlwings_mono = pl.Monospace('xlwings') pd_mono = pl.Monospace('pandas') quickstart_mono = pl.Monospace('quickstart') read_from_excel_example = pl.Python(""" my_value = xw.Range("G11").value # single value # all values in cell range my_value = xw.Range("G11:F13").value # expands cell range down and left getting all values my_values = xw.Range("G11").expand().value """) write_to_excel_example = pl.Python(""" xw.Range("G11").value = 10 xw.Range("G11").value = [10, 11] # horizontal xw.Range("G11").value = [[10], [11]] # vertical xw.Range("G11").value = [[10, 11], [12, 13]] # table """) ball_options = ['fill', 'circle', 'inner sep=8pt'] blue_ball_options = ball_options + ['blue'] red_ball_options = ball_options + ['red'] def rand_pos(): return random.randrange(-150, 150) / 100 blue_nodes = [ lg.Node(None, (rand_pos(), rand_pos()), options=blue_ball_options) for _ in range(10) ] red_nodes = [ lg.Node(None, (rand_pos(), rand_pos()), options=red_ball_options) for _ in range(10) ] red_blue_ball_graphic = lg.TikZPicture([ lg.Rectangle(5, 5, shape_options=['blue', 'thick']), *blue_nodes, *red_nodes ]) lecture = get_monte_carlo_lecture() intro_mc_python_lab = get_intro_monte_carlo_lab_lecture().to_pyexlatex() mc_python_lab = get_python_retirement_monte_carlo_lab_lecture( ).to_pyexlatex() mc_excel_lab = get_excel_retirement_monte_carlo_lab_lecture().to_pyexlatex( ) return [ pl.Section([ lp. TwoColumnGraphicDimRevealFrame([ [ pl.Bold('Monte Carlo Simulation'), 'is a technique which allows understanding the probability ' 'of acheiving certain outputs from a model.' ], 'This gives the modeler a greater understanding of the likelihood of different outputs, rather ' 'than relying on a single number', ], graphics=[ images_path( 'random-numbers.jpg') ], title= 'What is Monte Carlo Simulation?'), lp.DimRevealListFrame([ r'Imagine you have a one-time opportunity to place a bet for \$1. ', r'If you win the bet, you will receive \$2. If you lose the bet, you will lose \$750,000. ' r'You cannot avoid the payment by declaring bankruptcy.', r'The odds of winning the bet are 999,999/1,000,000. In 1/1,000,000 you lose the \$750,000.', fr'The expected profit from the bet is \${ev_bet:.2f}. Should you take it? Depends on your ' fr'risk tolerance.', 'Therefore not only the expected outcome matters, but also what other outcomes may occur and ' 'their probabilities.' ], title='Why Use Monte Carlo Simulation?'), lp.GraphicFrame(explore_parameters_graphic(), title='Monte Carlo Simulation in One Picture'), lp.DimRevealListFrame([ 'Monte Carlo simulation is carried out similarly to external scenario analysis.', 'The main difference is that we manually picked specific cases for the inputs with scenario ' 'analysis.', 'In Monte Carlo simulation, we assign distributions to the inputs, and input values are drawn ' 'from the distributions for each run of the model', 'Finally, we can fit a probability distribution to the outputs to be able to talk about the ' 'chance of a certain outcome occurring' ], title= 'Basic Process for Monte Carlo Simulation') ], title='Introduction'), pl.Section( [ lp.DimRevealListFrame([ 'Monte Carlo simulation can be applied to any model', 'It is generally easier to run them in Python than in Excel.', "With pure Excel, you're either going to VBA or hacking something with data tables", 'In Python, just loop for N iterations, each time drawing inputs, running the model, and collecting ' 'outputs.', [ 'We will start with a pure Python model, then move to using', xlwings_mono, 'to add Monte Carlo ' 'simulations to our Excel models.' ], ], title= 'Running Monte Carlo Simulations - Python or Excel?' ), lp.Frame([ lp.Block([ r'You have \$1,000 now and need to pay \$1,050 in one year. You have available to you ' r'two assets: a risk free asset that returns 3%, and a stock that returns 10% with a ' r'20% standard deviation. How much should you invest in the two assets to maximize ' r'your probability of having at least \$1,050 in one year?' ], title='An Investment Problem'), pl.VFill(), pl.UnorderedList([ lp.DimAndRevealListItems([ 'We must first construct the basic model which gets the portfolio value for given ' 'returns', 'Then draw values of the stock return from a normal distribution, and run the model ' 'many times and visualize the outputs. ', 'Then repeat this process with each weight to determine the best weight.' ]) ]) ], title='An Example Application'), InClassExampleFrame([ 'Go to the course site and download the Jupyter notebook "MC Investment Returns.ipynb" from ' 'Monte Carlo Examples', 'I will go through this example notebook to solve the problem from the prior slide.' ], title='Simluating Portfolio Values', block_title= 'Example for Simulating Portfolio Values'), pl.TextSize(-2), intro_mc_python_lab.presentation_frames(), pl.TextSize(0), ], title='Running a First Monte Carlo Simulation', short_title='Run MC', ), pl.Section( [ lp.Frame([ pl.TextSize(-2), 'For the model given by:', pl.Equation(str_eq='y = f(X)', inline=False), pl.Equation(str_eq='X = [x_1, x_2, ..., x_n]', inline=False), pl.UnorderedList([[ pl.Equation(str_eq='y:'), 'Model output' ], [pl.Equation(str_eq='X:'), 'Model input matrix'], [ pl.Equation(str_eq='x_i:'), 'Value of $i$th $x$ variable' ]]), 'To run $N$ Monte Carlo simulations, follow the following steps:', pl.OrderedList( [[ 'Assign a probability distribution for each', pl.Equation(str_eq='x_i') ], [ 'For each', pl.Equation(str_eq='x_i'), 'randomly pick a value from its probability distribution. Store them as', pl.Equation(str_eq='X_j') ], [ 'Repeat the previous step $N$ times, yielding', pl.Equation(str_eq='[X_1, X_2, ..., X_N]') ], [ 'For each', pl.Equation(str_eq='X_j'), 'calculate', pl.Equation(str_eq='y_j = f(X_j)') ], [ 'Store the values of', pl.Equation(str_eq='X_j'), 'mapped to', pl.Equation(str_eq='y_j') ], [ 'Visualize and analyze', pl.Equation(str_eq='y_j'), 'versus', pl.Equation(str_eq='X_j') ]]) ], title='Monte Carlo Simulation Process'), lp.DimRevealListFrame([ 'There are a multitude of outputs we can get from a Monte Carlo simulation. We saw a few ' 'already in the example.', [ pl.Bold('Outcome probability distributions'), 'are the main output. We saw this with two ' 'approaches in the example, a', pl.Underline('histogram'), 'and a', pl.Underline('probability table.') ], [ 'We also examined the', pl.Bold('probability of a certain outcome'), 'in whether we reached ' 'the desired cash.' ], [ 'The last main output is examining the', pl.Bold('relationship between inputs and outputs.'), 'for which common approaches include', pl.Underline('scatter plots'), 'and', pl.Underline('regressions.') ] ], title= 'Outputs from Monte Carlo Simulation'), lp.TwoColumnGraphicDimRevealFrame( [ pl.TextSize(-3), 'The outcome probability distribution represents the chance of receiving different ' 'outcomes from your model.', 'There are two main ways to visualize a probability distribution: a plot and a table.', [ 'The plot, usually a', pl.Underline('histogram'), 'or', pl.Underline('KDE'), 'gives a high-level overview of the probabilities and can uncover any non-normal ' 'features of the distribution.' ], [ 'The probability table represents the chance of receiving the given value or ' 'lower.' ], 'The Value at Risk (VaR) is a common measure calculated in the industry, and it represents ' 'the probability of losing at least a certain amount. This would be a subset of this analysis ' 'and so this analysis can be used to calculate VaR', ], graphics=[ images_path('outcome-probability-distribution.png'), lt.Tabular([ pl.MultiColumnLabel('Probability Table', span=2), lt.TopRule(), lt.ValuesTable.from_list_of_lists( [['Probability', 'Value']]), lt.TableLineSegment(0, 1), lt.ValuesTable.from_list_of_lists( [['25%', '1020'], ['50%', '1039'], ['75%', '1053']]), lt.BottomRule() ], align='c|c') ], title='Outcome Probability Distributions', graphics_on_right=False, ), lp.TwoColumnGraphicDimRevealFrame( [ 'Imagine a box which contains red and blue balls. You do not know in advance how many there ' 'are of each color.', 'You want to estimate the probability of getting a blue ball when pulling a ball from the box.', 'To evaluate this, you grab a ball, write down its color, and put it back, 1,000 times.', 'You pull a blue ball in 350 out of the 1,000 trials. What is the probability of getting blue?' ], graphics=[red_blue_ball_graphic ], title='Probability of a Certain Outcome - A Simple Example' ), lp.DimRevealListFrame([ 'We followed the same logic when estimating the probability of receiving our desired cash ' 'in the investment example.', pl.Equation( str_eq= fr'p = \frac{{{pl.Text("Count of positive outcomes")}}}{{{pl.Text("Count of trials")}}}' ), [ 'For the balls example, this is simply', pl.Equation(str_eq=r'p = \frac{350}{1000} = 0.35'), ], [ 'In the investment example, we used', pd_mono, 'to check for each trial, whether it was a ' 'positive outcome (made it a 1) or not (made it a 0). Then the sum is the count of ' 'positive outcomes and so the mean is the probability.' ], ], title= 'Probability of a Certain Outcome, Formally' ), lp.DimRevealListFrame([ 'Monte Carlo simulation can also provide a more comprehensive look at the relationship between ' 'inputs and outputs.', 'While sensitivity analysis can be used to estimate the relationship between an input and ' 'output, it is usually done with other inputs at their base case', 'The values of inputs may affect how other inputs affect the output. E.g. for the retirement ' 'model, an increase in interest rate increases wealth more if the initial salary was higher.', 'As all the inputs change each time, you can get a more realistic view of the relationship, e.g. ' 'some trials with a higher interest rate will have high salary and some will have low salary.' ], title= 'Why Monte Carlo Simulations Help Understand Inputs vs. Outputs' ), lp.TwoColumnGraphicDimRevealFrame( [ pl.TextSize(-1), 'A scatter plot is a simple way to visualize the relationship between two variables', 'If there is a relationship, you will see some defined pattern in the points. This may be ' 'somewhat of an upward or downward line (linear relationship) or some other shape such ' 'as a U (non-linear relationship).', 'If there is no relationship, then there will just be a random cloud of points (lower ' 'plot) or a horizontal line.' ], graphics=[ images_path('scatter-plot-line.png'), images_path('scatter-plot-no-relationship.png') ], graphics_on_right=False, title= 'Visualizing the Relationship between Inputs and Outputs'), lp.TwoColumnGraphicDimRevealFrame([ pl.TextSize(-2), 'The scatter plots help give a broad understanding of the relationship but do not answer the ' 'question, how much will my output change if my input changes? E.g. if I earn 10,000 more ' 'for a starting salary, how much sooner can I retire?', 'Simply increasing the input in your model and checking the output is not enough, because it ' 'does not take into account how all the other variables may be changing.', 'Multivariate regression is a general tool which is good at answering these kinds of questions, ' 'while taking into account all the changing inputs.' ], graphics=[ images_path( 'excel-multivariate-reg.png' ) ], title= 'Numerically Analyzing the Relationships' ), lp.DimRevealListFrame([ pl.TextSize(-1), 'The coefficient in a multivariate regression represents how much the outcome variable ' 'changes with a one unit change in the input variable.', 'E.g. a coefficient of -.0002 on starting salary in explaining years to retirement would mean ' r'that a \$1 increase in starting salary is associated with a decrease in years to retirement by .0002 years, or ' r'a \$10,000 increase in starting salary is associated with a decrease in years to retirement by 2 years.', 'All interpretations are "all else constant", meaning that it does not consider relationships ' 'between the inputs. E.g. if starting salary is higher because of a good economy, and interest ' 'rates are also higher due to the good economy, the starting salary coefficient is not taking ' 'into account the increase in interest rates.', 'Be careful about units. If you use decimals for percentages, you will need to multiply or ' 'divide by 100 to get the effect in percentages.' ], title='How to use Multivariate Regression' ), InClassExampleFrame( [ 'I will now go through adding a Monte Carlo simulation to the Dynamic Salary Retirement ' 'Model in Python', 'The completed example is on the course site in ' 'Monte Carlo Examples', ], title='Adding Monte Carlo Simulation to a Formal Model', block_title='Dynamic Salary Retirement with Monte Carlo'), mc_python_lab.presentation_frames(), ], title='A More Formal Treatment of Monte Carlo Simulation', short_title='Formal MC', ), pl.Section([ lp.DimRevealListFrame([ 'In pure Excel, it is much more difficult to run a Monte Carlo Simulation', 'Without going to VBA, typically the only way is to use a data table', 'A data table can be used in situations where you only want to have one or two inputs ' 'varying at once. Just generate the random inputs and use them as the axes of the data table', 'If you want to vary more than two inputs, VBA or Python would be required', 'There are also add-ons that accomplish this but they are usually not free' ], title= "How is it Different Running MC in Excel?"), lp.DimRevealListFrame([ 'The process for Monte Carlo Simulation which works for any number of variables is ' 'very similar to what we were doing in Python.', 'We are still just changing the inputs, running the model, and storing the outputs from each run', [ 'Using', xlwings_mono, 'from Python code we can change and retrieve the values of cells' ], 'This allows us to change inputs, run the model, and store outputs, just as in Python, but running our Excel model.', 'We can either analyze the outputs in Python or output them back to Excel for analysis' ], title= 'Monte Carlo in Excel with More than Two Variables' ), InClassExampleFrame([ 'Go to the course site and download the "Dynamic Salary Retirement Model.xlsx" and ' '"Excel Monte Carlo.ipynb" from the Monte Carlo Examples', 'Open up the Jupyter notebook and follow along with me', 'The completed Excel model is also there in case you lose track. Visualizations ' 'were added after running the Jupyter notebook on the original Excel model.', ], title='Monte Carlo Excel Retirement Model', block_title= f'Using {xlwings_mono} to Run Monte Carlo Simulations' ), mc_excel_lab.presentation_frames(), ], title='Monte Carlo Simulation in Excel', short_title='Excel MC'), pl.PresentationAppendix([ lecture.pyexlatex_resources_frame, intro_mc_python_lab.appendix_frames(), mc_python_lab.appendix_frames(), mc_excel_lab.appendix_frames(), ]) ]