├── .gitignore ├── .gitkeep ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── admin ├── PSYC_132_syllabus.pages ├── PSYC_132_syllabus.pdf ├── PSYC_32_syllabus.pages └── PSYC_32_syllabus.pdf ├── assignments ├── README.md ├── autograder │ ├── autograde.py │ └── grader.py ├── eliza │ ├── instructions.txt │ └── public_rubric.xls ├── hello-world │ └── public_rubric.xls ├── library-tour │ ├── figs │ │ ├── Murd62_SPCs.png │ │ └── accuracy_by_condition_reference.png │ └── public_rubric.xls └── n-queens │ └── public_rubric.xls └── slides ├── README.md ├── module_0 └── programming_mindset.md ├── module_1 ├── intro_to_python.ipynb ├── introduction_and_overview.ipynb └── python_learning_playground.ipynb ├── module_2 ├── control_flow_and_ooo.ipynb ├── dictionaries_and_classes.ipynb ├── figs │ └── board_notes_pig_latin_translation.jpg ├── interactive_programming.ipynb ├── object_oriented_universe.ipynb ├── pythonic_code.ipynb └── scope_and_passing_by_value_vs_reference.ipynb ├── module_4 ├── bob_ross_libraries_demo.ipynb ├── data_visualization.ipynb └── pandas_and_sklearn.ipynb ├── module_6 ├── ascii_table.csv ├── encrypted.csv └── permutation_tests_hackathon.ipynb ├── module_7 ├── make_a_model.html └── make_a_model.md ├── module_8 ├── NLP_of_IMDB.ipynb ├── intro_to_NLP.html ├── intro_to_NLP.md └── text_embedding_demo.ipynb ├── module_9 ├── forecasting.ipynb └── time_frequency_analyses.ipynb └── theme.css /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | .DS_Store 84 | 85 | # Environments 86 | .env 87 | .venv 88 | env/ 89 | venv/ 90 | ENV/ 91 | env.bak/ 92 | venv.bak/ 93 | 94 | # Spyder project settings 95 | .spyderproject 96 | .spyproject 97 | 98 | # Rope project settings 99 | .ropeproject 100 | 101 | # mkdocs documentation 102 | /site 103 | 104 | # mypy 105 | .mypy_cache/ 106 | 107 | *#* 108 | 109 | assignments/autograder/autograder_dev.ipynb 110 | assignments/autograder/debug_library_tour.py 111 | -------------------------------------------------------------------------------- /.gitkeep: -------------------------------------------------------------------------------- 1 | slides/module_1/* 2 | slides/module_2/* 3 | slides/module_3/* 4 | slides/module_4/* 5 | slides/module_5/* 6 | slides/module_6/* 7 | slides/module_7/* 8 | slides/module_8/* 9 | slides/module_9/* 10 | slides/module_10/* -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "markdown.marp.themes": [ 3 | "./slides/theme.css" 4 | ] 5 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Contextual Dynamics Laboratory 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction to Programming for Psychological Scientists 2 | 3 | This repository contains course materials for the Dartmouth Course [Introduction to Programming for Psychological Scientists (PSYC 132)](https://pbs.dartmouth.edu/undergraduate/courses-and-syllabi/intermediate-courses-2020-2021). The syllabus may be found [here](https://github.com/ContextLab/cs-for-psych/blob/master/admin/PSYC_132_syllabus.pdf) and a hyperlinked outline of all course materials may be found [here](https://github.com/ContextLab/cs-for-psych/blob/master/slides/README.md). Feel free to follow along with the course materials (whether you are officially enrolled in the course or just visiting!), submit comments and suggestions, etc. If you are a Dartmouth student currently enrolled in this course, please read the *Student instructions* below to get set up. A list of tutorials and some ideas for tracking down some nice datasets may be found at the bottom of this document. 4 | 5 | [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5136795.svg)](https://doi.org/10.5281/zenodo.5136795) 6 | 7 | ## A note about this Open Course 8 | This course is taught as an *Open Course*, meaning that the course is designed from the ground up to be shareable and freely accessible to anyone. All code for this course is written in [Python](https://www.python.org/) and most of the material is organized in [Jupyter notebooks](http://jupyter.org/). 9 | 10 | Feel free to follow along with this course, do the assignments, post questions and/or issues to this repository or Discord, suggest changes, etc. However, I won't formally evaluate your submitted work unless you are a Dartmouth student currently enrolled in PSYC 132. 11 | 12 | If you are a course instructor teaching overlapping material, feel free to borrow any materials used in this course! If you directly copy (or "draw heavy inspiration from") the materials, I would appreciate a citation (e.g., a pointer to this repository). I'd also love to hear from you about how you're using this resource! 13 | 14 | This course is a continually evolving work in progress. I plan to update the material to keep the syllabus fresh and relevant. By the same token, although my goal is 100% accuracy and currency, it's unlikely that I'll achieve that goal. You should participate with the understanding that this material will likely have occasional mistakes, ommissions, errors, etc. Given this fact, one way to approach the course is to maintain an open yet critical view of the material. If you think there's a mistake, I encourage you to bring it to my attention! 15 | 16 | # Student instructions 17 | 18 | ## Overview 19 | We will use the following tools in this course: 20 | - [GitHub](https://www.github.com): used to download code and data, collaborate with other students, and submit course assignments 21 | - [Google Colaboratory](https://colab.research.google.com/): a Google resource we will use to write code, download data, and run analyses 22 | - [Discord](https://discord.com/): used to coordinate all course communication. Use this link to join our class server: 23 | 24 | [![](https://dcbadge.vercel.app/api/server/AdDgJd7cbM)](https://discord.gg/AdDgJd7cbM) 25 | 26 | ## Setup 27 | 1. Start by creating a free [GitHub account](https://www.github.com) if you don't already have one. (If you already have an account, you may use it for this course.) 28 | 2. Next, sign into the course's [Discord workspace](https://discord.gg/AdDgJd7cbM). You can ask questions and get help with all aspects of the course via our Discord community. You'll need to create a (free) Discord account. 29 | 3. If you don't already have one, create a [Google account](http://google.com/). (If you already have an account, you may use it for this course.) Make sure you can sign into Colaboratory using [this link](https://colab.research.google.com/). 30 | 31 | # Getting help 32 | Learning to code can be a tricky, rewarding, and often frustrating business. Luckily for us, there are many places to get help! Examples include: 33 | - [Google](https://www.google.com)-- searchable portal to of all human knowledge. Most Internet things are reachable through here, and it's a great place to start your search. You can often find code that other people have written that solves a similar problem to the one you're working on, or a tutorial that teaches you how to solve a particular class of problems. 34 | - [Wikipedia](https://www.wikipedia.org/)-- community-curated encyclopedia. Wikipedia is a good resource for learning about the background of a technique, looking up equations, etc. It's not a good source for tutorials. 35 | - [Discord](https://discord.gg/AdDgJd7cbM)-- course chatroom. A good place to ask questions, post ideas, etc., to other members of the class and community. 36 | - The last (but hopefully not least) option if you're feeling stuck, unhappy with how things are progressing, looking for fun new ideas to revitalize your project and get you interested in science again, etc. is to *talk with me*. If you're a Dartmouth person you can come to my regular office hours, [email me](mailto:jeremy@dartmouth.edu), message me on Discord, or come visit [my lab](http://www.context-lab.com/). 37 | - **Important**-- chances are good that if you're feeling lost, you're not the only one! If you learn something useful, please share it via Discord or by opening a [GitHub issue](https://github.com/ContextLab/cs-for-psych/issues). 38 | 39 | # Where to start 40 | 41 | The [slides folder](https://github.com/ContextLab/cs-for-psych/tree/master/slides) contains all course materials, organized as a set of Jupyter notebooks. Use the [Slides README file](https://github.com/ContextLab/cs-for-psych/blob/master/slides/README.md) to track down the relevant notebooks. 42 | 43 | The [assignments README file](https://github.com/ContextLab/cs-for-psych/blob/master/assignments/README.md) contains links to all course assignments and the associated source code. We'll use [GitHub Classroom](https://classroom.github.com/) to distribute assignments. (You can log into GitHub Classroom with your GitHub credentials.) 44 | -------------------------------------------------------------------------------- /admin/PSYC_132_syllabus.pages: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextLab/cs-for-psych/d4bc7352e53bf2875e032c0da6b8e9d9970bc913/admin/PSYC_132_syllabus.pages -------------------------------------------------------------------------------- /admin/PSYC_132_syllabus.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextLab/cs-for-psych/d4bc7352e53bf2875e032c0da6b8e9d9970bc913/admin/PSYC_132_syllabus.pdf -------------------------------------------------------------------------------- /admin/PSYC_32_syllabus.pages: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextLab/cs-for-psych/d4bc7352e53bf2875e032c0da6b8e9d9970bc913/admin/PSYC_32_syllabus.pages -------------------------------------------------------------------------------- /admin/PSYC_32_syllabus.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextLab/cs-for-psych/d4bc7352e53bf2875e032c0da6b8e9d9970bc913/admin/PSYC_32_syllabus.pdf -------------------------------------------------------------------------------- /assignments/README.md: -------------------------------------------------------------------------------- 1 | # Assignments list 2 | 3 | Click the links below to view (and/or accept) each assignment. 4 | 5 | 1. [Assignment 1: Hello, world!](https://github.com/ContextLab/psyc32-hello-world) [[Accept assignment](https://classroom.github.com/a/xjc-u-1F)] 6 | 2. [Assignment 2: Chess puzzle solver](https://github.com/ContextLab/psyc32-n-queens) [[Accept assignment](https://classroom.github.com/a/oh7d8zy-)] 7 | 3. [Assignment 3: ELIZA](https://github.com/ContextLab/psyc32-eliza) [[Accept assignment](https://classroom.github.com/a/kJAki_Z0)] 8 | 4. [Assignment 4: Library tour!](https://github.com/ContextLab/psyc32-library-tour) [[Accept assignment](https://classroom.github.com/a/yFFZaagF)] 9 | 5. [Assignment 5: MAGELLAN](https://github.com/ContextLab/psyc32-magellan) [[Accept assignment](https://classroom.github.com/a/CUKn-2lL)] 10 | -------------------------------------------------------------------------------- /assignments/autograder/autograde.py: -------------------------------------------------------------------------------- 1 | from grader import autograde, commit_and_push 2 | from glob import glob 3 | import typer 4 | 5 | app = typer.Typer() 6 | 7 | @app.command() 8 | def run(path: str, summarize: bool=False, commit: bool=False, push: bool=False, root=None, grader=None, public=None, private=None): 9 | grades = autograde(path, plot_it=summarize, root=root, grading_repo=grader, public_checks_dir=public, private_checks_dir=private) 10 | 11 | if commit: 12 | commit_and_push(path, grades.index.to_list(), debug=(not push)) 13 | 14 | if __name__ == "__main__": 15 | app() 16 | -------------------------------------------------------------------------------- /assignments/autograder/grader.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | import os 4 | import ast 5 | import sys 6 | import re 7 | from glob import glob 8 | import io 9 | import types 10 | from IPython import get_ipython 11 | from nbformat import read 12 | from IPython.core.interactiveshell import InteractiveShell 13 | from configparser import ConfigParser 14 | import plotly.express as px 15 | from string import ascii_lowercase 16 | import itertools 17 | 18 | ########### 19 | #source: https://jupyter-notebook.readthedocs.io/en/stable/examples/Notebook/Importing%20Notebooks.html 20 | def find_notebook(fullname, path=None): 21 | """find a notebook, given its fully qualified name and an optional path 22 | 23 | This turns "foo.bar" into "foo/bar.ipynb" 24 | and tries turning "Foo_Bar" into "Foo Bar" if Foo_Bar 25 | does not exist. 26 | """ 27 | name = fullname.rsplit('.', 1)[-1] 28 | if not path: 29 | path = [''] 30 | for d in path: 31 | nb_path = os.path.join(d, name + ".ipynb") 32 | if os.path.isfile(nb_path): 33 | return nb_path 34 | # let import Notebook_Name find "Notebook Name.ipynb" 35 | nb_path = nb_path.replace("_", " ") 36 | if os.path.isfile(nb_path): 37 | return nb_path 38 | 39 | class NotebookLoader(object): 40 | """Module Loader for Jupyter Notebooks""" 41 | def __init__(self, path=None): 42 | self.shell = InteractiveShell.instance() 43 | self.path = path 44 | 45 | def load_module(self, fullname): 46 | """import a notebook as a module""" 47 | path = find_notebook(fullname, self.path) 48 | 49 | print ("importing Jupyter notebook from %s" % path) 50 | 51 | # load the notebook object 52 | with io.open(path, 'r', encoding='utf-8') as f: 53 | nb = read(f, 4) 54 | 55 | 56 | # create the module and add it to sys.modules 57 | # if name in sys.modules: 58 | # return sys.modules[name] 59 | mod = types.ModuleType(fullname) 60 | mod.__file__ = path 61 | mod.__loader__ = self 62 | mod.__dict__['get_ipython'] = get_ipython 63 | sys.modules[fullname] = mod 64 | 65 | # extra work to ensure that magics that would affect the user_ns 66 | # actually affect the notebook module's ns 67 | save_user_ns = self.shell.user_ns 68 | self.shell.user_ns = mod.__dict__ 69 | 70 | try: 71 | for cell in nb.cells: 72 | if cell.cell_type == 'code': 73 | # transform the input to executable Python 74 | code = self.shell.input_transformer_manager.transform_cell(cell.source) 75 | # run the code in themodule 76 | exec(code, mod.__dict__) 77 | finally: 78 | self.shell.user_ns = save_user_ns 79 | return mod 80 | 81 | class NotebookFinder(object): 82 | """Module finder that locates Jupyter Notebooks""" 83 | def __init__(self): 84 | self.loaders = {} 85 | 86 | def find_module(self, fullname, path=None): 87 | nb_path = find_notebook(fullname, path) 88 | if not nb_path: 89 | return 90 | 91 | key = path 92 | if path: 93 | # lists aren't hashable 94 | key = os.path.sep.join(path) 95 | 96 | self.loaders[key] = NotebookLoader(path) 97 | return self.loaders[key] 98 | 99 | sys.meta_path.append(NotebookFinder()) 100 | ########### 101 | 102 | 103 | def get_fname_suffix(n): 104 | ''' 105 | return a list of suffixes to append to fnames with the same base: 106 | a, b, c, ..., z, aa, ab, ..., az, ba, ..., bz, aaa, aab, ... 107 | ''' 108 | #source: https://stackoverflow.com/questions/29351492/how-to-make-a-continuous-alphabetic-list-python-from-a-z-then-from-aa-ab-ac-e/29351603 109 | def generate_id(): 110 | i = 1 111 | while True: 112 | for s in itertools.product(ascii_lowercase, repeat=i): 113 | yield ''.join(s) 114 | i += 1 115 | 116 | gen = generate_id() 117 | 118 | def helper(): 119 | for s in gen: 120 | return s 121 | 122 | return [helper() for i in range(n)][-1] 123 | 124 | 125 | 126 | def extract_assignment(dir): 127 | pattern = r'([a-z\-]+)-((([0-9]{2,4})-){5}[0-9]{2,4})' 128 | assignment = re.findall(pattern, os.path.split(dir)[1])[0][0] 129 | return assignment.lower() 130 | 131 | def get_students(submissions_dir): 132 | contents = [os.path.split(g)[1] for g in glob(os.path.join(submissions_dir, '*'))] 133 | return [c for c in contents if os.path.isdir(os.path.join(submissions_dir, c))] 134 | 135 | def notebook_to_module(target): 136 | if target in sys.modules: 137 | sys.modules.pop(target) 138 | exec(f'import {target} as submission', globals()) 139 | 140 | return submission 141 | 142 | 143 | def grade(x, rubric): 144 | if type(rubric) == list: 145 | passed = [] 146 | failed = [] 147 | for r in rubric: 148 | next_passed, next_failed = grade(x, r) 149 | passed.extend(next_passed) 150 | failed.extend(next_failed) 151 | return passed, failed 152 | 153 | r = pd.read_excel(rubric, header=0) 154 | 155 | passed = [] 156 | failed = [] 157 | 158 | for i in range(r.shape[0]): 159 | next_test = {} 160 | if r.loc[i]['function'] == 'identity': 161 | next_test['cmd'] = f"x.{r.loc[i]['args']} == {r.loc[i]['solution']}" 162 | next_test['target'] = True 163 | else: 164 | r.at[i, 'args'] = eval(f"{r.loc[i]['args']}") 165 | 166 | if type(r.loc[i]['kwargs']) != dict: 167 | next_kwargs = '{}' 168 | else: 169 | next_kwargs = r.loc[i]['kwargs'] 170 | 171 | next_test['cmd'] = f"x.{r.loc[i]['function']}(*{r.loc[i]['args']}, **{next_kwargs})" 172 | next_test['target'] = eval(f"{r.loc[i]['solution']}") 173 | next_test['points'] = float(r.loc[i]['points']) 174 | next_test['rubric'] = rubric 175 | 176 | try: 177 | next_test['response'] = eval(next_test['cmd']) 178 | except: 179 | next_test['response'] = None 180 | try: 181 | if next_test['response'] == next_test['target']: 182 | passed.append(next_test) 183 | else: 184 | failed.append(next_test) 185 | except: 186 | try: 187 | if np.isnan(next_test['target']): 188 | passed.append(next_test) 189 | else: 190 | failed.append(next_test) 191 | except: 192 | failed.append(next_test) 193 | 194 | return passed, failed 195 | 196 | def report(passed, failed, outfile=None, quiet=False): 197 | possible = 0 198 | earned = 0 199 | 200 | def summarize(description, cases): 201 | if len(cases) == 0: 202 | return f'No cases {description.lower()}.' 203 | 204 | summary = [f'The following test cases {description}:'] 205 | for i, c in enumerate(cases): 206 | summary.append(f"{i+1}. Command: {c['cmd'][2:]}") 207 | summary.append(f"\t Observed output: {c['response']}") 208 | summary.append(f"\t Expected output: {c['target']}") 209 | summary.append(f"\t Points: {c['points']}") 210 | summary.append('') 211 | 212 | return '\n'.join(summary[:-1]) 213 | 214 | for p in passed: 215 | earned += p['points'] 216 | possible += p['points'] 217 | 218 | for f in failed: 219 | possible += f['points'] 220 | 221 | if outfile is None: 222 | dest = sys.stdout 223 | else: 224 | dest = open(outfile, 'w+') 225 | 226 | if (outfile is not None) or (not quiet): 227 | print(f'Total points earned: {np.round(earned, decimals=2)}/{np.round(possible, decimals=2)} = {np.round(100 * np.round(float(earned), decimals=4)/np.round(float(possible), decimals=4), decimals=2)}%', file=dest) 228 | print('\nDetails:\n', file=dest) 229 | print(summarize('PASSED', passed), file=dest) 230 | print('\n', file=dest) 231 | print(summarize('FAILED', failed), file=dest) 232 | 233 | if outfile is not None: 234 | dest.close() 235 | 236 | return np.round(100.0 * float(earned) / float(possible), decimals=2) 237 | 238 | def grade_assignment(submission, rubrics, outfile=None, quiet=False): 239 | passed, failed = grade(submission, rubrics) 240 | return report(passed, failed, outfile=outfile, quiet=quiet) 241 | 242 | def commit_and_push(submissions_dir, students, root=None, private_dir=None, debug=True): 243 | feedback_branch = 'feedback' 244 | assignment = extract_assignment(submissions_dir) 245 | 246 | if root is None: 247 | root = os.path.abspath(os.path.join('..', '..', '..')) 248 | if private_dir is None: 249 | private_dir = os.path.join(root, 'teaching-tools', 'cs-for-psych', 'assignments') 250 | 251 | #set up git 252 | gitconfig = ConfigParser() 253 | gitconfig.read(os.path.join(private_dir, 'autograder', 'git.ini')) 254 | 255 | os.system(f"git config --global user.name '{gitconfig['github']['user.name']}'"); 256 | os.system(f"git config --global user.email '{gitconfig['github']['user.email']}'"); 257 | 258 | def commit_and_push_single_student(s, debug=True): 259 | mydir = os.path.join(submissions_dir, s) 260 | os.chdir(mydir) 261 | 262 | if debug: 263 | token = '' 264 | else: 265 | token = gitconfig['github']['token'] 266 | 267 | cmds = [f"git remote add {s} https://{token}@github.com/ContextLab/{assignment}-{s}.git", #f'git pull {s} {feedback_branch}', #comment this out after pushing revised reports 268 | f'git fetch {s}', 269 | f'git checkout -b {feedback_branch}', 270 | 'git add report.txt', 271 | 'git commit -a -m "added autograder report"', 272 | f'git push {s} HEAD:{feedback_branch}'] 273 | if debug: 274 | print(f'Simulating commands (running from directory: {mydir})') 275 | [print('\t' + c) for c in cmds] 276 | print('\n') 277 | else: 278 | [os.system(c) for c in cmds] 279 | 280 | start_dir = os.getcwd() 281 | [commit_and_push_single_student(s, debug=debug) for s in students] 282 | os.chdir(start_dir) 283 | 284 | def autograde(submissions_dir, root=None, plot_it=False, grading_repo=None, public_checks_dir=None, private_checks_dir=None): 285 | if root is None: 286 | root = os.path.abspath(os.path.join('..', '..', '..')) 287 | if grading_repo is None: 288 | grading_repo = os.path.join(root, 'cs-for-psych', 'assignments', 'autograder') 289 | if public_checks_dir is None: 290 | public_checks_dir = os.path.join(root, 'cs-for-psych', 'assignments') 291 | if private_checks_dir is None: 292 | private_checks_dir = os.path.join(root, 'teaching-tools', 'cs-for-psych', 'assignments') 293 | 294 | #set up git 295 | gitconfig = ConfigParser() 296 | gitconfig.read(os.path.join(private_checks_dir, 'autograder', 'git.ini')) 297 | 298 | os.system(f"git config --global user.name '{gitconfig['github']['user.name']}'"); 299 | os.system(f"git config --global user.email '{gitconfig['github']['user.email']}'"); 300 | 301 | #get assignment and rubrics 302 | assignment = extract_assignment(submissions_dir) 303 | public_rubric = os.path.join(public_checks_dir, assignment, 'public_rubric.xls') 304 | private_rubric = os.path.join(private_checks_dir, assignment, 'private_rubric.xls') 305 | rubrics = [public_rubric, private_rubric] 306 | 307 | #autograde all students 308 | students = get_students(submissions_dir) 309 | grades = [autograde_notebooks(submissions_dir, rubrics, s) for s in students] 310 | grades = pd.DataFrame(zip(students, grades), columns=['Student', 'Score']).set_index('Student') 311 | 312 | fig = px.histogram(grades, x='Score', range_x=[0, 100], nbins=10, histnorm='percent'); 313 | fig.update_layout(yaxis_title='Percentage of students'); 314 | fig.write_image(os.path.join(submissions_dir, 'grade_summary.pdf')); 315 | 316 | return grades 317 | 318 | def autograde_notebooks(submissions_dir, rubrics, student): 319 | def grade_notebook(notebook_fname, outfile=None, quiet=False): 320 | basedir, notebook = os.path.split(notebook_fname) 321 | target = notebook[:-6] 322 | 323 | bad_chars = [' ', '-', ',', '!', '?', '.'] 324 | modified_target = target 325 | 326 | for b in bad_chars: 327 | if b in modified_target: 328 | modified_target = modified_target.replace(b, '_') 329 | 330 | print(f'grading: {target}.ipynb') 331 | clean_up = False 332 | if modified_target != target: 333 | if os.path.exists(os.path.join(basedir, modified_target + '.ipynb')): 334 | clean_up = True 335 | os.rename(os.path.join(basedir, modified_target + '.ipynb'), os.path.join(basedir, modified_target + '.ipynb.BACKUP')) 336 | os.rename(os.path.join(basedir, target + '.ipynb'), os.path.join(basedir, modified_target + '.ipynb')) 337 | 338 | #mydir = os.getcwd() 339 | if 'submission' in sys.modules: 340 | print('pop!') 341 | sys.modules.pop('submission') 342 | try: 343 | os.chdir(basedir) 344 | submission = notebook_to_module(modified_target) 345 | score = grade_assignment(submission, rubrics, quiet=quiet, outfile=outfile) 346 | except: 347 | print('** ERROR!') 348 | if outfile is not None: 349 | with open(outfile, 'w') as fd: 350 | print('Assignment could not be autograded: notebook failed to run!', file=fd) 351 | score = 0.0 352 | #os.chdir(mydir) 353 | 354 | if modified_target != target: 355 | os.rename(os.path.join(basedir, modified_target + '.ipynb'), os.path.join(basedir, target + '.ipynb')) 356 | 357 | if clean_up: 358 | os.rename(os.path.join(basedir, modified_target + '.ipynb.BACKUP'), os.path.join(basedir, modified_target + '.ipynb')) 359 | 360 | return score 361 | 362 | start_dir = os.getcwd() 363 | mydir = os.path.join(submissions_dir, student) 364 | 365 | os.chdir(mydir) 366 | notebooks = glob(os.path.join('.', '*.ipynb')) 367 | grades = [grade_notebook(n, quiet=True) for n in notebooks] 368 | 369 | best_notebook = notebooks[np.where(np.array(grades) == np.max(grades))[0][0]] 370 | best_grade = grade_notebook(best_notebook, quiet=True, outfile='report.txt') 371 | os.chdir(start_dir) 372 | return best_grade 373 | -------------------------------------------------------------------------------- /assignments/eliza/instructions.txt: -------------------------------------------------------------------------------- 1 | initial: Welcome. What brings you here today ? 2 | initial: How are you doing ? 3 | final: See you again next week. 4 | final: That will be $200. 5 | quit: bye 6 | quit: goodbye 7 | quit: quit 8 | quit: bye 9 | quit: goodbye 10 | quit: quit 11 | pre: dont don't 12 | pre: cant can't 13 | pre: wont won't 14 | pre: recollect remember 15 | pre: dreamt dreamed 16 | pre: dreams dream 17 | pre: maybe perhaps 18 | pre: how what 19 | pre: when what 20 | pre: certainly yes 21 | pre: machine computer 22 | pre: computers computer 23 | pre: were was 24 | pre: you're you are 25 | pre: i'm i am 26 | pre: same alike 27 | post: am are 28 | post: your my 29 | post: me you 30 | post: myself yourself 31 | post: yourself myself 32 | post: i you 33 | post: you me 34 | post: my your 35 | post: i'm you are 36 | synon: belief feel think believe wish 37 | synon: family mother mom father dad sister brother wife children child 38 | synon: desire want need 39 | synon: sad unhappy depressed sick 40 | synon: happy elated glad better 41 | synon: cannot can't 42 | synon: everyone everybody nobody noone 43 | synon: be am is are was 44 | key: xnone 45 | decomp: * 46 | reasmb: I'm not sure I understand you fully. 47 | reasmb: Please go on. 48 | reasmb: What does that suggest to you ? 49 | reasmb: Do you feel strongly about discussing such things ? 50 | key: sorry 51 | decomp: * 52 | reasmb: Please don't apologise. 53 | reasmb: Apologies are not necessary. 54 | reasmb: I've told you that apologies are not required. 55 | key: apologise 56 | decomp: * 57 | reasmb: goto sorry 58 | key: remember 5 59 | decomp: * i remember * 60 | reasmb: Do you often think of (2) ? 61 | reasmb: Does thinking of (2) bring anything else to mind ? 62 | reasmb: What else do you recollect ? 63 | reasmb: Why do you recollect (2) just now ? 64 | reasmb: What in the present situation reminds you of (2) ? 65 | reasmb: What is the connection between me and (2) ? 66 | decomp: * do you remember * 67 | reasmb: Did you think I would forget (2) ? 68 | reasmb: Why do you think I should recall (2) now ? 69 | reasmb: What about (2) ? 70 | reasmb: goto what 71 | reasmb: You mentioned (2) ? 72 | key: if 3 73 | decomp: * if * 74 | reasmb: Do you think its likely that (2) ? 75 | reasmb: Do you wish that (2) ? 76 | reasmb: What do you know about (2) ? 77 | reasmb: Really, if (2) ? 78 | key: dreamed 4 79 | decomp: * i dreamed * 80 | reasmb: Really, (2) ? 81 | reasmb: Have you ever fantasized (2) while you were awake ? 82 | reasmb: Have you ever dreamed (2) before ? 83 | reasmb: goto dream 84 | key: dream 3 85 | decomp: * 86 | reasmb: What does that dream suggest to you ? 87 | reasmb: Do you dream often ? 88 | reasmb: What persons appear in your dreams ? 89 | reasmb: Do you believe that dreams have something to do with your problems ? 90 | key: perhaps 91 | decomp: * 92 | reasmb: You don't seem quite certain. 93 | reasmb: Why the uncertain tone ? 94 | reasmb: Can't you be more positive ? 95 | reasmb: You aren't sure ? 96 | reasmb: Don't you know ? 97 | key: name 15 98 | decomp: * 99 | reasmb: I am not interested in names. 100 | reasmb: I've told you before, I don't care about names -- please continue. 101 | key: deutsch 102 | decomp: * 103 | reasmb: goto xforeign 104 | reasmb: I told you before, I don't understand German. 105 | key: francais 106 | decomp: * 107 | reasmb: goto xforeign 108 | reasmb: I told you before, I don't understand French. 109 | key: italiano 110 | decomp: * 111 | reasmb: goto xforeign 112 | reasmb: I told you before, I don't understand Italian. 113 | key: espanol 114 | decomp: * 115 | reasmb: goto xforeign 116 | reasmb: I told you before, I don't understand Spanish. 117 | key: xforeign 118 | decomp: * 119 | reasmb: I speak only English. 120 | key: hello 121 | decomp: * 122 | reasmb: How do you do. Please state your problem. 123 | reasmb: Hi. What seems to be your problem ? 124 | key: computer 50 125 | decomp: * 126 | reasmb: Do computers worry you ? 127 | reasmb: Why do you mention computers ? 128 | reasmb: What do you think machines have to do with your problem ? 129 | reasmb: Don't you think computers can help people ? 130 | reasmb: What about machines worries you ? 131 | reasmb: What do you think about machines ? 132 | key: am 133 | decomp: * am i * 134 | reasmb: Do you believe you are (2) ? 135 | reasmb: Would you want to be (2) ? 136 | reasmb: Do you wish I would tell you you are (2) ? 137 | reasmb: What would it mean if you were (2) ? 138 | reasmb: goto what 139 | decomp: * 140 | reasmb: Why do you say 'am' ? 141 | reasmb: I don't understand that. 142 | key: are 143 | decomp: * are you * 144 | reasmb: Why are you interested in whether I am (2) or not ? 145 | reasmb: Would you prefer if I weren't (2) ? 146 | reasmb: Perhaps I am (2) in your fantasies. 147 | reasmb: Do you sometimes think I am (2) ? 148 | reasmb: goto what 149 | decomp: * are * 150 | reasmb: Did you think they might not be (2) ? 151 | reasmb: Would you like it if they were not (2) ? 152 | reasmb: What if they were not (2) ? 153 | reasmb: Possibly they are (2) . 154 | key: your 155 | decomp: * your * 156 | reasmb: Why are you concerned over my (2) ? 157 | reasmb: What about your own (2) ? 158 | reasmb: Are you worried about someone else's (2) ? 159 | reasmb: Really, my (2) ? 160 | key: was 2 161 | decomp: * was i * 162 | reasmb: What if you were (2) ? 163 | reasmb: Do you think you were (2) ? 164 | reasmb: Were you (2) ? 165 | reasmb: What would it mean if you were (2) ? 166 | reasmb: What does (2) suggest to you ? 167 | reasmb: goto what 168 | decomp: * i was * 169 | reasmb: Were you really ? 170 | reasmb: Why do you tell me you were (2) now ? 171 | reasmb: Perhaps I already know you were (2) . 172 | decomp: * was you * 173 | reasmb: Would you like to believe I was (2) ? 174 | reasmb: What suggests that I was (2) ? 175 | reasmb: What do you think ? 176 | reasmb: Perhaps I was (2) . 177 | reasmb: What if I had been (2) ? 178 | key: i 179 | decomp: * i @desire * 180 | reasmb: What would it mean to you if you got (3) ? 181 | reasmb: Why do you want (3) ? 182 | reasmb: Suppose you got (3) soon ? 183 | reasmb: What if you never got (3) ? 184 | reasmb: What would getting (3) mean to you ? 185 | reasmb: What does wanting (3) have to do with this discussion ? 186 | decomp: * i am * @sad * 187 | reasmb: I am sorry to hear that you are (3) . 188 | reasmb: Do you think that coming here will help you not to be (3) ? 189 | reasmb: I'm sure it's not pleasant to be (3) . 190 | reasmb: Can you explain what made you (3) ? 191 | decomp: * i am * @happy * 192 | reasmb: How have I helped you to be (3) ? 193 | reasmb: Has your treatment made you (3) ? 194 | reasmb: What makes you (3) just now ? 195 | reasmb: Can you explain why you are suddenly (3) ? 196 | decomp: * i was * 197 | reasmb: goto was 198 | decomp: * i @belief * i * 199 | reasmb: Do you really think so ? 200 | reasmb: But you are not sure you (3) . 201 | reasmb: Do you really doubt you (3) ? 202 | decomp: * i * @belief * you * 203 | reasmb: goto you 204 | decomp: * i am * 205 | reasmb: Is it because you are (2) that you came to me ? 206 | reasmb: How long have you been (2) ? 207 | reasmb: Do you believe it is normal to be (2) ? 208 | reasmb: Do you enjoy being (2) ? 209 | decomp: * i @cannot * 210 | reasmb: How do you think that you can't (3) ? 211 | reasmb: Have you tried ? 212 | reasmb: Perhaps you could (3) now. 213 | reasmb: Do you really want to be able to (3) ? 214 | decomp: * i don't * 215 | reasmb: Don't you really (2) ? 216 | reasmb: Why don't you (2) ? 217 | reasmb: Do you wish to be able to (2) ? 218 | reasmb: Does that trouble you ? 219 | decomp: * do i feel * 220 | reasmb: Tell me more about such feelings. 221 | reasmb: Do you often feel (2) ? 222 | reasmb: Do you enjoy feeling (2) ? 223 | reasmb: Of what does feeling (2) remind you ? 224 | decomp: * i * you * 225 | reasmb: Perhaps in your fantasies we (2) each other. 226 | reasmb: Do you wish to (2) me ? 227 | reasmb: You seem to need to (2) me. 228 | reasmb: Do you (2) anyone else ? 229 | decomp: * 230 | reasmb: You say (1) ? 231 | reasmb: Can you elaborate on that ? 232 | reasmb: Do you say (1) for some special reason ? 233 | reasmb: That's quite interesting. 234 | key: you 235 | decomp: * you remind me of * 236 | reasmb: goto alike 237 | decomp: * you are * 238 | reasmb: What makes you think I am (2) ? 239 | reasmb: Does it please you to believe I am (2) ? 240 | reasmb: Do you sometimes wish you were (2) ? 241 | reasmb: Perhaps you would like to be (2) . 242 | decomp: * you * me * 243 | reasmb: Why do you think I (2) you ? 244 | reasmb: You like to think I (2) you -- don't you ? 245 | reasmb: What makes you think I (2) you ? 246 | reasmb: Really, I (2) you ? 247 | reasmb: Do you wish to believe I (2) you ? 248 | reasmb: Suppose I did (2) you -- what would that mean ? 249 | reasmb: Does someone else believe I (2) you ? 250 | decomp: * you * 251 | reasmb: We were discussing you -- not me. 252 | reasmb: Oh, I (2) ? 253 | reasmb: You're not really talking about me -- are you ? 254 | reasmb: What are your feelings now ? 255 | key: yes 256 | decomp: * 257 | reasmb: You seem to be quite positive. 258 | reasmb: You are sure. 259 | reasmb: I see. 260 | reasmb: I understand. 261 | key: no 262 | decomp: * 263 | reasmb: Are you saying no just to be negative? 264 | reasmb: You are being a bit negative. 265 | reasmb: Why not ? 266 | reasmb: Why 'no' ? 267 | key: my 2 268 | decomp: * my * @family * 269 | reasmb: Tell me more about your family. 270 | reasmb: Who else in your family (4) ? 271 | reasmb: Your (3) ? 272 | reasmb: What else comes to mind when you think of your (3) ? 273 | decomp: $ * my * 274 | reasmb: Your (2) . 275 | reasmb: Let's discuss your (2) further . 276 | reasmb: What does your (2) mean to you ? 277 | reasmb: Tell me more about your (2) . 278 | decomp: * my * 279 | reasmb: Your (2) ? 280 | reasmb: Why do you mention your (2) ? 281 | reasmb: Is your (2) important ? 282 | reasmb: Did you come to me to talk about your (2) ? 283 | key: can 284 | decomp: * can you * 285 | reasmb: You believe I can (2) don't you ? 286 | reasmb: goto what 287 | reasmb: You want me to be able to (2) . 288 | reasmb: Perhaps you would like to be able to (2) yourself. 289 | decomp: * can i * 290 | reasmb: Whether or not you can (2) depends on you more than me. 291 | reasmb: Do you want to be able to (2) ? 292 | reasmb: Perhaps you don't want to (2) . 293 | reasmb: goto what 294 | key: what 295 | decomp: * 296 | reasmb: Why do you ask ? 297 | reasmb: Does that question interest you ? 298 | reasmb: What is it you really wanted to know ? 299 | reasmb: Are such questions much on your mind ? 300 | reasmb: What answer would please you most ? 301 | reasmb: What do you think ? 302 | reasmb: What comes to mind when you ask that ? 303 | reasmb: Have you asked such questions before ? 304 | reasmb: Have you asked anyone else ? 305 | key: because 306 | decomp: * 307 | reasmb: Is that the real reason ? 308 | reasmb: Don't any other reasons come to mind ? 309 | reasmb: Does that reason seem to explain anything else ? 310 | reasmb: What other reasons might there be ? 311 | key: why 312 | decomp: * why don't you * 313 | reasmb: Do you believe I don't (2) ? 314 | reasmb: Perhaps I will (2) in good time. 315 | reasmb: Should you (2) yourself ? 316 | reasmb: You want me to (2) ? 317 | reasmb: goto what 318 | decomp: * why can't i * 319 | reasmb: Do you think you should be able to (2) ? 320 | reasmb: Do you want to be able to (2) ? 321 | reasmb: Do you believe this will help you to (2) ? 322 | reasmb: Have you any idea why you can't (2) ? 323 | reasmb: goto what 324 | decomp: * 325 | reasmb: goto what 326 | key: everyone 2 327 | decomp: * @everyone * 328 | reasmb: Really, (2) ? 329 | reasmb: Surely not (2) . 330 | reasmb: Can you think of anyone in particular ? 331 | reasmb: Who, for example? 332 | reasmb: Are you thinking of a very special person ? 333 | reasmb: Who, may I ask ? 334 | reasmb: Someone special perhaps ? 335 | reasmb: You have a particular person in mind, don't you ? 336 | reasmb: Who do you think you're talking about ? 337 | key: everybody 2 338 | decomp: * 339 | reasmb: goto everyone 340 | key: nobody 2 341 | decomp: * 342 | reasmb: goto everyone 343 | key: noone 2 344 | decomp: * 345 | reasmb: goto everyone 346 | key: always 1 347 | decomp: * 348 | reasmb: Can you think of a specific example ? 349 | reasmb: When ? 350 | reasmb: What incident are you thinking of ? 351 | reasmb: Really, always ? 352 | key: alike 10 353 | decomp: * 354 | reasmb: In what way ? 355 | reasmb: What resemblance do you see ? 356 | reasmb: What does that similarity suggest to you ? 357 | reasmb: What other connections do you see ? 358 | reasmb: What do you suppose that resemblance means ? 359 | reasmb: What is the connection, do you suppose ? 360 | reasmb: Could there really be some connection ? 361 | reasmb: How ? 362 | key: like 10 363 | decomp: * @be * like * 364 | reasmb: goto alike -------------------------------------------------------------------------------- /assignments/eliza/public_rubric.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextLab/cs-for-psych/d4bc7352e53bf2875e032c0da6b8e9d9970bc913/assignments/eliza/public_rubric.xls -------------------------------------------------------------------------------- /assignments/hello-world/public_rubric.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextLab/cs-for-psych/d4bc7352e53bf2875e032c0da6b8e9d9970bc913/assignments/hello-world/public_rubric.xls -------------------------------------------------------------------------------- /assignments/library-tour/figs/Murd62_SPCs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextLab/cs-for-psych/d4bc7352e53bf2875e032c0da6b8e9d9970bc913/assignments/library-tour/figs/Murd62_SPCs.png -------------------------------------------------------------------------------- /assignments/library-tour/figs/accuracy_by_condition_reference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextLab/cs-for-psych/d4bc7352e53bf2875e032c0da6b8e9d9970bc913/assignments/library-tour/figs/accuracy_by_condition_reference.png -------------------------------------------------------------------------------- /assignments/library-tour/public_rubric.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextLab/cs-for-psych/d4bc7352e53bf2875e032c0da6b8e9d9970bc913/assignments/library-tour/public_rubric.xls -------------------------------------------------------------------------------- /assignments/n-queens/public_rubric.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextLab/cs-for-psych/d4bc7352e53bf2875e032c0da6b8e9d9970bc913/assignments/n-queens/public_rubric.xls -------------------------------------------------------------------------------- /slides/README.md: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | 3 | 0. [Orientation](#orientation) 4 | 1. [Course setup and Python basics](#module-1-course-setup-and-python-basics) 5 | 2. [Beyond the basics](#module-2-beyond-the-basics) 6 | 3. [Find your inner hacker](#module-3-find-your-inner-hacker) 7 | 4. [External libraries](#module-4-external-libraries) 8 | 5. [Collecting data](#module-5-collecting-data) 9 | 6. [Interrogating your data](#module-6-interrogating-your-data) 10 | 7. [Models](#module-7-models) 11 | 8. [Natural language processing](#module-8-natural-language-processing) 12 | 9. [Timeseries analysis](#module-9-timeseries-analysis) 13 | 10. [Advanced topics](#module-10-advanced-topics) 14 | 15 | # Orientation 16 | 17 | **Start here!** The materials for each module below are organized sequentially. Work your way from module to module (and from top to bottom within each module). The recorded lectures (in **bold**) typically cover preceding material (after the previous lecture, within the same module). Take notes on questions, comments, concerns, etc. so that you can bring them up for discussion during our synchronous class meetings or in the [Discord workspace](https://discord.gg/AdDgJd7cbM). Several items are marked as optional; they may be skipped if desired, but they are included for students who wish to gain additional exposure to the material. 18 | 19 | - [Welcome message](https://youtu.be/UjHUfUCpTQU) 20 | - [Supplemental welcome message featuring special guest lecturer](https://youtu.be/9SkgGKMBctI) 21 | - [**Lecture 1 recording (W21)**](https://youtu.be/XPsoY9R7dVs): orientation, overview, and "the sandwich exercise" 22 | - [Fostering a programming mindset](https://github.com/ContextLab/cs-for-psych/blob/master/slides/module_0/programming_mindset.md) 23 | 24 | # Module 1: Course setup and Python basics 25 | 26 | - [Introduction and Overview](https://colab.research.google.com/github/ContextLab/cs-for-psych/blob/master/slides/module_1/introduction_and_overview.ipynb) 27 | - [Introduction to Jupyter Notebooks and Python](https://colab.research.google.com/github/ContextLab/cs-for-psych/blob/master/slides/module_1/intro_to_python.ipynb) 28 | - [**Lecture 2 recording (W21)**](https://youtu.be/hDsJgkQdPWs): variables, operators, datatypes, functions, if/elif/else statements, for and while loops 29 | - [**Lecture 3 recording (W21)**](https://youtu.be/bT0HwegxHWQ): libraries, practice "string manipulation" problems 30 | - [Assignment 1: Hello, world!](https://github.com/ContextLab/psyc32-hello-world) [[Accept assignment](https://classroom.github.com/a/xjc-u-1F)] 31 | 32 | # Module 2: Beyond the basics 33 | - [Interactive programs](https://colab.research.google.com/github/ContextLab/cs-for-psych/blob/master/slides/module_2/interactive_programming.ipynb) 34 | - [Control flow and order of operations](https://colab.research.google.com/github/ContextLab/cs-for-psych/blob/master/slides/module_2/control_flow_and_ooo.ipynb) 35 | - [**Lecture 4 recording (W21)**](https://youtu.be/0YmunqHonpE): interactive programs, control flow, exceptions and warnings 36 | - [Dictionaries and classes](https://colab.research.google.com/github/ContextLab/cs-for-psych/blob/master/slides/module_2/dictionaries_and_classes.ipynb) 37 | - [Writing Pythonic code: list comprehensions, generators, and iterators](https://colab.research.google.com/github/ContextLab/cs-for-psych/blob/master/slides/module_2/pythonic_code.ipynb) 38 | - [**Lecture 5 recording (W21)**](https://youtu.be/3VmcI5AjXeY): assert statements, dictionaries, sets, classes, and list comprehensions 39 | - [**Lecture 6 recording (W21)**](https://youtu.be/LbHhsKXeb7E): dictionary and set comprehensions, generators, and iterators 40 | - [Variable scope and passing by value versus by reference](https://colab.research.google.com/github/ContextLab/cs-for-psych/blob/master/slides/module_2/scope_and_passing_by_value_vs_reference.ipynb) 41 | - [**Lecture 7 recording (W21)**](https://youtu.be/WnszGCW0o8g): variable scope, passing by value versus by reference 42 | - [Assignment 2: Chess puzzle solver](https://github.com/ContextLab/psyc32-n-queens) [[Accept assignment](https://classroom.github.com/a/oh7d8zy-)] 43 | 44 | # Module 3: Find your inner hacker 45 | - Recursion (Source: [Hany Farid's *Learn to Code in Python* course](https://farid.berkeley.edu/downloads/tutorials/learnPython/)): 46 | - [Factorial](https://drive.google.com/file/d/1n2vX-cH7JCAEX7AYCgVbBux6V-xJ52wd/view) 47 | - [List reversal](https://drive.google.com/file/d/1jBbKrTOn3KmipNOWWcmSv601hkJeTizp/view?usp=sharing) 48 | - [List sum](https://drive.google.com/file/d/1kFyKqe5OIiJZ6WWS_JypRF5xedcyijrp/view?usp=sharing) ([associated code](https://drive.google.com/file/d/1CCYpy7pThwP2FLGVBHdANEL1uF03Dnif/view?usp=sharing)) 49 | - [Towers of Hanoi](https://drive.google.com/file/d/15SEWU23_iQD80Vs5vbkefdyiegnWoTyO/view?usp=sharing) 50 | - Whirlwind tour of searching, sorting, and data structures (Source: [Hany Farid's *Learn to Code in Python* course](https://farid.berkeley.edu/downloads/tutorials/learnPython/)): 51 | - [Linear and binary search](https://drive.google.com/file/d/1EukvYAyuyVnMJoYJGEO-qF7f2oy2jroX/view?usp=sharing) 52 | - Sorting (**optional**): 53 | - [Selection sort](https://drive.google.com/file/d/1LahEi_vWr1U7gWFNT4SwAh1tzAc8gXn-/view?usp=sharing) 54 | - [Insertion sort](https://drive.google.com/file/d/13BSt9rPYvd1txaXqgHPvM0-CA2tHqQEm/view?usp=sharing) 55 | - [Merge sort](https://drive.google.com/file/d/1nrzVsPfblxft36pc44M3TrVqDaHsnCd3/view?usp=sharing) 56 | - [Quick sort](https://drive.google.com/file/d/1NJWiskxYLYL6F4i_-wjDQU59vhdYzIT4/view?usp=sharing) 57 | - Data structures (**optional**): 58 | - [Linked lists](https://drive.google.com/file/d/1pdff_xyC8VSU_QX8_POLNlo88Wf317Sx/view?usp=sharing) (note: you may find it useful to view [this video](https://drive.google.com/file/d/1bGmFBsp7-kqSPcu1j2hXMM2GgZ7WiULE/view?usp=sharing) first) 59 | - [Doubly linked lists](https://drive.google.com/file/d/1WQ957ItVBXgUovedipVywUz8QNY1neLP/view?usp=sharing) 60 | - [Hashing](https://drive.google.com/file/d/1DYNmUGr2mnaoflaWAecdN0aYRl5HjBsd/view?usp=sharing) (note: you may find it useful to view [this video](https://drive.google.com/file/d/1yTw3wdLTHcsQkjnwwCb9FZp3PPf_xtZu/view?usp=sharing) first) 61 | - Graphs: 62 | - [Overview](https://drive.google.com/file/d/1Phf9dveviodykjUzwCzkR2nFMqyWqiwo/view?usp=sharing) 63 | - [Representing graphs](https://drive.google.com/file/d/1tRRVLJyeuemjMNMyS690lz4IPpYB-IWv/view?usp=sharing) 64 | - [Breadth-first search](https://drive.google.com/file/d/1qHaMQXkPDHU5mfYc9WKRlNhRnHPsyB38/view) 65 | - [Queues and stacks](https://drive.google.com/file/d/13fnBkyRSHuTWwVkJuOZuXL072rrHl5tC/view?usp=sharing) 66 | - [**Lecture 8 recording (W21)**](https://youtu.be/uqafHXnxn9Q): coding exercise on recursion, sorting, and linked lists 67 | - [**Lecture 9 recording (W21)**](https://youtu.be/oEvdowJkhVU): applications of data structures and algorithms, building an English to Pig Latin translator 68 | - [Lambda functions](https://realpython.com/python-lambda/) (Source: [realpython.com](https://realpython.com)) 69 | - [Map, filter, reduce](https://www.learnpython.org/en/Map,_Filter,_Reduce) (Source: [learnpython.org](https://learnpython.org)) 70 | - [Decorators](https://realpython.com/primer-on-python-decorators/) (Source: [realpython.com](https://realpython.com)) 71 | - [Debugging in Google Colaboratory](https://colab.research.google.com/github/jakevdp/PythonDataScienceHandbook/blob/master/notebooks/01.06-Errors-and-Debugging.ipynb) (Source: [Python Data Science Handbook](https://jakevdp.github.io/PythonDataScienceHandbook/index.html) by Jake VanderPlas) 72 | - [Unit tests](https://realpython.com/python-testing/) (Source: [realpython.com](https://realpython.com)) 73 | - [Optimizing your code](https://towardsdatascience.com/optimizing-your-python-code-156d4b8f4a29) (Source: [towardsdatascience](https://towardsdatascience.com)) 74 | - [Writing maintainable and shareable code](https://towardsdatascience.com/the-ultimate-guide-to-writing-better-python-code-1362a1209e5a) (Source: [towardsdatascience](https://towardsdatascience.com)) 75 | - [**Lecture 10 recording (W21)**](https://youtu.be/nixpJySn228): assignment 3 Q&A (part 1), lambda functions 76 | - [**Lecture 11 recording (W21)**](https://youtu.be/yewvdDHgpVY): assignment 3 Q&A (part 2), advanced applications of lambda functions, decorators 77 | - [Assignment 3: ELIZA](https://github.com/ContextLab/psyc32-eliza) [[Accept assignment](https://classroom.github.com/a/kJAki_Z0)] 78 | 79 | # Module 4: External libraries 80 | - [Modules and Packages](https://jakevdp.github.io/WhirlwindTourOfPython/13-modules-and-packages.html) (from [Whirlwind Tour of Python](https://jakevdp.github.io/WhirlwindTourOfPython/index.html) by Jake VanderPlas) 81 | - [Numpy](https://jakevdp.github.io/PythonDataScienceHandbook/02.00-introduction-to-numpy.html) and [Pandas](https://jakevdp.github.io/PythonDataScienceHandbook/03.00-introduction-to-pandas.html) (from [Python Data Science Handbook](https://jakevdp.github.io/PythonDataScienceHandbook/index.html) by Jake VanderPlas) 82 | - [Data visualization overview](https://github.com/ContextLab/cs-for-psych/blob/master/slides/module_4/data_visualization.ipynb) 83 | - More details on plotting libraries: [Matplotlib](https://jakevdp.github.io/PythonDataScienceHandbook/04.00-introduction-to-matplotlib.html) and [Seaborn](https://jakevdp.github.io/PythonDataScienceHandbook/04.14-visualization-with-seaborn.html) (from [Python Data Science Handbook](https://jakevdp.github.io/PythonDataScienceHandbook/index.html) by Jake VanderPlas) 84 | - [Visualizing high-dimensional data with Hypertools](https://hypertools.readthedocs.io/en/latest/tutorials.html) (Source: [hypertools.readthedocs.io](https://hypertools.readthedocs.io/)) 85 | - In-class exercise: [exploring Bob Ross's paintings using numpy, pandas, matplotlib, seaborn, and hypertools](https://github.com/ContextLab/cs-for-psych/blob/master/slides/module_4/bob_ross_libraries_demo.ipynb) 86 | - [**Lecture 12 recording (W21)**](https://youtu.be/dZ7zBnQgKGQ): numpy, pandas, matplotlib, seaborn, and hypertools 87 | - [**Lecture 13 recording (W21)**](https://youtu.be/kk9bdpVHC6c): Bob Ross dataset brainstorm and hackathon (part 1) 88 | - [**Lecture 14 recording (W21)**](https://youtu.be/XMUem0HzngY): Bob Ross hackathon (part 2) 89 | - [**Lecture 15 recording (W21)**](https://youtu.be/vCYMM2e5Fmk): Bob Ross hackathon (part 3) 90 | - [Scikit-learn](https://jakevdp.github.io/PythonDataScienceHandbook/05.02-introducing-scikit-learn.html) (from [Python Data Science Handbook](https://jakevdp.github.io/PythonDataScienceHandbook/index.html) by Jake VanderPlas) 91 | - [Mission "Impossible": more practice with pandas and scikit-learn](https://github.com/ContextLab/cs-for-psych/blob/master/slides/module_4/pandas_and_sklearn.ipynb) 92 | - [**Lecture 16 recording (W21)**](https://youtu.be/pcpdt0sTV1s): hacking with pandas (part 1) 93 | - [**Lecture 17 recording (W21)**](https://youtu.be/x88mZgtFVRQ): hacking with pandas (part 2) 94 | - [**Lecture 18 recording (W21)**](https://youtu.be/L0jdootHQQk): hacking with pandas (part 3) 95 | - [**Lecture 19 recording (W21)**](https://youtu.be/W4WwH1pqqGM): hacking with scikit-learn 96 | - A (shallow) introduction to deep learning with [Tensorflow](https://www.tensorflow.org/tutorials/quickstart/beginner) (Source: [tensorflow.org](https://www.tensorflow.org/)) and [PyTorch](https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html) (Source: [pytorch.org](https://pytorch.org/)) 97 | - [PyTest](https://github.com/ContextLab/CDL-tutorials/tree/master/testing) (Source: [CDL tutorials](https://github.com/ContextLab/CDL-tutorials)) 98 | - [More in-depth PyTest tutorial](https://www.youtube.com/watch?v=LX2ksGYXJ80) (Source: [SciPy 2019 tutorials](https://www.youtube.com/redirect?v=LX2ksGYXJ80&redir_token=QUFFLUhqbFVjTkw0a3djNGx3SnlrdlRsOFVteDU0cmpYd3xBQ3Jtc0tsWkEyeXpHODd4SXJyRWpXUHlOcFhTSEVXUGt4SFpUUmpQOW5sT05GOGVxeTRaaUFQZi15OXFnV3ozTHh4ZWNoSHU5V0lkd0E0UUo2THZ5TnV3YVdvQWxlelVHZW1QYlFlN1JfbGFVZEJDRGdQX0N6MA%3D%3D&event=video_description&q=https%3A%2F%2Fwww.scipy2019.scipy.org%2Ftutorial-participant-instructions)) 99 | - [Assignment 4: Library tour!](https://github.com/ContextLab/psyc32-library-tour) [[Accept assignment](https://classroom.github.com/a/yFFZaagF)] 100 | 101 | # Module 5: Collecting data 102 | - *Note: this module was not covered during the W21 offering of PSYC 132* 103 | - jsPsych (note: this is a [JavaScript](https://en.wikipedia.org/wiki/JavaScript) library, not a Python library. As such, you may find it useful to go through a quick(ish) JavaScript tutorial like [this one](https://www.youtube.com/watch/W6NZfCO5SIk) before going through the jsPsych tutorials below.) 104 | - [Basics](https://www.jspsych.org/tutorials/hello-world/) (Source: [jspsych.org](https://www.jspsych.org/)) 105 | - [Simple reaction time task](https://www.jspsych.org/tutorials/rt-task/) (Source: [jspsych.org](https://www.jspsych.org/)) 106 | - [Sample experiments from Experiment Factory](https://expfactory.github.io/) 107 | - **Optional:** [PsychoPy](https://www.psychopy.org/gettingStarted.html) (Source: [psychopy.org](https://www.psychopy.org/)) and [OpenSesame](https://osdoc.cogsci.nl/3.2/tutorials/beginner/) (Source: [osdoc.cogsci.nl](https://osdoc.cogsci.nl/)) 108 | 109 | # Module 6: Interrogating your data 110 | - [Basic statistical tests using Pingouin](https://pingouin-stats.org/) (Source: [pingouin-stats.org](https://pingouin-stats.org/)) 111 | - [Permutation tests](https://towardsdatascience.com/how-to-assess-statistical-significance-in-your-data-with-permutation-tests-8bb925b2113d) (Source: [towardsdatascience](https://towardsdatascience.com)) 112 | - [Hackathon: code breaking with permutation tests!](https://github.com/ContextLab/cs-for-psych/blob/master/slides/module_6/permutation_tests_hackathon.ipynb) 113 | - [**Lecture 20 recording (W21)**](https://youtu.be/zfRG4ZAa0C4): permutation testing hackathon (part 1) 114 | - [**Lecture 21 recording (W21)**](https://youtu.be/nuiRmPUYU50): permutation testing hackathon (part 2) 115 | - [Monte Carlo simulation](https://pbpython.com/monte-carlo.html) (Source: [Practical Business Python](https://pbpython.com/)) 116 | - [Regression](https://towardsdatascience.com/machine-learning-with-python-regression-complete-tutorial-47268e546cea) (Source: [towardsdatascience](https://towardsdatascience.com)) 117 | - [Dimensionality reduction](https://www.analyticsvidhya.com/blog/2018/08/dimensionality-reduction-techniques-python/) (Source: [Analytics Vidhya](https://www.analyticsvidhya.com/blog/)) 118 | 119 | # Module 7: Models 120 | - [What *is* a model?](https://people.maths.bris.ac.uk/~madjl/course_text.pdf) (Source: [Daniel Lawson](https://people.maths.bris.ac.uk/~madjl/)) 121 | - [Ten simple rules for the computational modeling of behavioral data](https://elifesciences.org/articles/49547) (Source: [eLife](https://elifesciences.org) article by [Robert Wilson](http://u.arizona.edu/~bob/) and [Anne Collins](https://www.ocf.berkeley.edu/~acollins/)) 122 | - [Ten (more) rules for building computational models](https://journals.plos.org/ploscompbiol/article/file?id=10.1371/journal.pcbi.1008539&type=printable) (Source: [PLoS Computational Biology](https://journals.plos.org/ploscompbiol) article by [Korryn Bodner](https://korrynbodner.webnode.com/) et al.) 123 | - [Theory construction methodology: a practical framework for building theories in psychology](https://journals.sagepub.com/doi/abs/10.1177/1745691620969647#articleShareContainer) (Source: [Perspectives on Psychological Science](https://journals.sagepub.com/home/pps) article by [Denny Borsboom](https://dennyborsboom.com/) et al.) 124 | - [**Lecture 22 recording (W21)**](https://youtu.be/-LQvQY8JpCI): introduction to computational models [[Slides, added *post hoc*](https://github.com/ContextLab/cs-for-psych/blob/master/slides/module_7/make_a_model.md)] 125 | - Model fitting: 126 | - [Scipy optimization](https://towardsdatascience.com/optimization-with-scipy-and-application-ideas-to-machine-learning-81d39c7938b8) (Source: [towardsdatascience](https://towardsdatascience.com)) 127 | - [Model training and evaluation with TensorFlow](https://www.tensorflow.org/guide/keras/train_and_evaluate) (Source: [tensorflow.org](https://www.tensorflow.org)) 128 | - [Bayesian inference with PyStan](https://towardsdatascience.com/an-introduction-to-bayesian-inference-in-pystan-c27078e58d53) (Source: [towardsdatascience](https://towardsdatascience.com)) 129 | - Evaluating and comparing models 130 | - **Optional:** [Build, compute, critique, repeat: data analysis with latent variable models](https://oar.princeton.edu/jspui/bitstream/88435/pr12b6p/1/Blei%20-%20Build%2C%20Compute%2C%20Critique%2C%20Repeat.pdf) (Source: [Annual Review of Statistics and its Application](https://www.annualreviews.org/doi/full/10.1146/annurev-statistics-022513-115657) article by [David Blei](http://www.cs.columbia.edu/~blei/)) 131 | - **Optional:** [this repository](https://github.com/brendenlake/CCM-site) contains materials and assignments for NYU's excellent Computational Cognitive Modeling course (Source: [Brenden Lake](https://cims.nyu.edu/~brenden/) and [Todd Gureckis](http://psych.nyu.edu/gureckis/)). Pick and choose whatever seems interesting to you! 132 | - [**Lecture 23 recording (W21)**](https://youtu.be/OkVBwYbOusw): model building brainstorm and discussion 133 | - [Assignment 5: MAGELLAN](https://github.com/ContextLab/psyc32-magellan) [[Accept assignment](https://classroom.github.com/a/CUKn-2lL)] 134 | 135 | # Module 8: Natural language processing 136 | - [Tokenization](https://www.youtube.com/watch?v=JGaA2nT5Qk4) (Source: [DataCamp's Introduction to Natural Language Processing in Python](https://learn.datacamp.com/courses/introduction-to-natural-language-processing-in-python)) 137 | - [Stemming, and lemmatization](https://www.datacamp.com/community/tutorials/stemming-lemmatization-python) (Source: [DataCamp Community Tutorials](https://www.datacamp.com/community/tutorials)) 138 | - [Parsing](https://lost-contact.mit.edu/afs/cs.pitt.edu/projects/nltk/docs/tutorial/parsing.pdf) (Source: [Edward Loper's Natural Language Processing Toolkit tutorials](https://lost-contact.mit.edu/afs/cs.pitt.edu/projects/nltk/docs/tutorial)) 139 | - Word embedding models: 140 | - [Latent Dirichlet Allocation](https://towardsdatascience.com/end-to-end-topic-modeling-in-python-latent-dirichlet-allocation-lda-35ce4ed6b3e0) (Source: [towardsdatascience](https://towardsdatascience.com)) 141 | - [word2vec](https://machinelearningmastery.com/develop-word-embeddings-python-gensim/) (Source: [machinelearningmastery.com](https://machinelearningmastery.com)) 142 | - Context-sensitive text models: 143 | - [Universal Sentence Encoder](https://www.tensorflow.org/hub/tutorials/semantic_similarity_with_tf_hub_universal_encoder) (Source: [tensorflow.org](https://www.tensorflow.org)) 144 | - [Long Short Term Memory networks](https://adventuresinmachinelearning.com/keras-lstm-tutorial/) (Source: [Adventures in Machine Learning](https://adventuresinmachinelearning.com)) 145 | - [Bidirectional Encoder Representations from Transformers](http://jalammar.github.io/a-visual-guide-to-using-bert-for-the-first-time/) (Source: [Jay Alammar](http://jalammar.github.io)) 146 | - [Generative Pre-trained Transformer](https://minimaxir.com/2019/09/howto-gpt2/) (Source: [Max Woolf](https://minimaxir.com/)) 147 | - Demo: [Natural language processing of movie reviews](https://github.com/ContextLab/cs-for-psych/blob/master/slides/module_8/NLP_of_IMDB.ipynb) 148 | - [**Lecture 24 recording (W21)**](https://youtu.be/e_BK1G5WY8A): overview of text embedding models [[Slides from Spring, 2023 offering](https://github.com/ContextLab/cs-for-psych/blob/master/slides/module_8/intro_to_NLP.md)] 149 | - [**Lecture 25 recording (W21)**](https://youtu.be/CrVZl23Lq6c): natural language processing hackathon 150 | - [Text embedding demo notebook](https://github.com/ContextLab/cs-for-psych/blob/master/slides/module_8/text_embedding_demo.ipynb) 151 | 152 | # Module 9: Timeseries analysis 153 | - [Introduction to time-frequency analysis](https://github.com/ContextLab/cs-for-psych/blob/master/slides/module_9/time_frequency_analyses.ipynb) 154 | - Working with brain data: 155 | - [Analyzing neural responses to naturalistic data](http://naturalistic-data.org/intro) (Source: [Organization for Human Brain Mapping](https://www.humanbrainmapping.org) tutorial) 156 | - [DartBrains](https://dartbrains.org) (Source: [Luke Chang](https://cosanlab.com)) 157 | - [BrainIAK Aperture Tutorials](https://github.com/brainiak/brainiak-aperture) (Source: [Brain Imaging Analysis Kit](https://brainiak.org)) 158 | - [MNE Tutorials](https://mne.tools/dev/auto_tutorials/index.html) (Source: [MNE Python](https://mne.tools/dev/index.html)) 159 | - [SkTime User Guide](https://www.sktime.org/en/latest/user_guide.html) (Source: [The Alan Turing Institute](https://www.turing.ac.uk/)) 160 | - [Fun with forecasting using Darts!](https://github.com/ContextLab/cs-for-psych/blob/master/slides/module_9/forecasting.ipynb) 161 | - [High-order correlations with TimeCorr](https://timecorr.readthedocs.io/en/latest/tutorials.html) (Source: [timecorr.readthedocs.io](https://timecorr.readthedocs.io/)) 162 | - Demo: [Exploring brain network dynamics during story listening](https://github.com/brainiak/brainiak-aperture/blob/master/notebooks/htfa/htfa.ipynb) (Source: [BrainIAK Aperture Demos](https://github.com/brainiak/brainiak-aperture); companion to [Kumar et al. (2020)](https://osf.io/db2ev/)) 163 | - [**Lecture 26 recording (W21)**](https://youtu.be/YGIWmft-BA4): network dynamics, course wrap-up 164 | 165 | # Module 10: Advanced topics 166 | - *Note: this module was not covered during the W21 offering of PSYC 132* 167 | - Graphs and networks: 168 | - [NetworkX](https://networkx.org/documentation/stable/tutorial.html) (Source: [networkx.org](https://networkx.org)) 169 | - [Brain Connectivity Toolbox](https://sites.google.com/site/bctnet/Home/help) 170 | - [Writing your own library](https://github.com/ContextLab/CDL-tutorials/blob/master/packages/README.md) (Source: [CDL-tutorials](https://github.com/ContextLab/CDL-tutorials)) 171 | -------------------------------------------------------------------------------- /slides/module_0/programming_mindset.md: -------------------------------------------------------------------------------- 1 | # Adopting a 'programming mindset' 2 | 3 | Writing computer code, or "programming" is fundamentally about using highly 4 | structured and simplified languages to tell fancy calculators which numbers to 5 | crunch. Everything modern computers do may (with enough digging) be reduced to 6 | repeated calls to a small number of instructions similar to what you've likely 7 | already encountered if you've used a standard scientific calculator or graphing 8 | calculator. The challenge of programming is to arrange those seemingly simple 9 | instructions in just the right way such that the computer you're feeding them to 10 | does the stuff you want it to. Two key principles are useful to keep in mind 11 | as you're learning how to program. 12 | 13 | ## Computers are dumb and unthinking 14 | 15 | The earliest general purpose programmable computers, including 16 | [ENIAC](https://en.wikipedia.org/wiki/ENIAC), the [Bendix 17 | G15](https://en.wikipedia.org/wiki/Bendix_G15), 18 | [LGP-30of](https://en.wikipedia.org/wiki/LGP-30), and 19 | [MIR](https://en.wikipedia.org/wiki/MIR_(computer)) were developed in the 1940s 20 | and 1950s, around the time same time that modern psychology started to gain 21 | momentum as a field. Formal psychological theories developed in parallel drew 22 | heavy inspiration from computers. For example, classic memory theories still 23 | discussed in introductory psychology courses today (e.g., the [Atkinson-Shiffrin 24 | memory 25 | model](https://en.wikipedia.org/wiki/Atkinson%E2%80%93Shiffrin_memory_model)) suggest that our memory systems have a short-term (working memory) storage buffer that is low-capacity but fast and easy to access, along with a long-term storage mechanism that is high-capacity but relatively slower and more difficult to access. These concepts were inspired in part by computer [RAM](https://en.wikipedia.org/wiki/Random-access_memory) (which acts like a fast-access low-capacity buffer) and [hard disks](https://en.wikipedia.org/wiki/Hard_disk_drive) (which are slower but have a large capacity). Theories like these have continued to propagate the misconception that silicon computers are brain-like in a deep sense. Although many biological systems, including brains, fit some definitions of the word "computer" (e.g., see [this blog post](https://medium.com/the-spike/yes-the-brain-is-a-computer-11f630cad736)), the converse does not hold. Biological brains bear very little resemblance to modern silicon computers. 26 | 27 | This historical context is important to internalize because it can help to 28 | de-mystify many aspects of how computers work. Unlike biological brains, 29 | computers can *only* do exactly what its programming instructions tell it to do: 30 | no more, and no less. When you are in the throes of a programming challenge you 31 | can't seem to make sense of, it can be incredibly tempting in the moment to 32 | resort to dangerous thoughts like "my computer hates me" or others that ascribe 33 | any sort of intelligence or "will" to the computer. Some programming challenges 34 | are incredibly difficult to work through, and can stump even seasoned 35 | professional programmers. Many questions in computer science remain unsolved. 36 | But there can be no *true* mysteries in computer programming: unlike the "real 37 | world," computer systems are fully deterministic, and you (as the programmer) 38 | will have the means of knowing and tracking every single tiny computation that 39 | the computer performs. With sufficient time and patience, this gives you the 40 | power to track any "behavior" (calculations) that the computer carries out. 41 | 42 | ## Complexity can arise from simple building blocks 43 | 44 | Every biological organism on earth is comprised of cells whose structures and 45 | functions are encoded in [DNA](https://en.wikipedia.org/wiki/DNA) using an 46 | "alphabet" with just 4 "letters" 47 | ([bases](https://en.wikipedia.org/wiki/Nucleobase)) and a small number of 48 | "words" ([codons](https://en.wikipedia.org/wiki/DNA_codon_table)). All past, 49 | current, and future biodiversity may be expressed using this tiny "language." 50 | 51 | In an analogous way, the full diversity of programs that run on computers may be 52 | reduced to a small set of computer 53 | [instructions](https://en.wikipedia.org/wiki/Instruction_set_architecture) 54 | (e.g., addition, subtraction, multiplication, division, logical comparisons, 55 | loading and storing data, etc.) that may be carried out by the 56 | [CPU](https://en.wikipedia.org/wiki/Central_processing_unit). The key to 57 | harnessing the full power of computers is to iteratively build complexity. In 58 | other words, basic commands may be combined in sequences that form more 59 | expressive and complex commands. In turn, those hybrid commands may be combined 60 | in sequences that form still more expressive and complex commands. After just a 61 | few iterations of this approach, it is possible to create all existing computer 62 | programs-- [operating systems](https://en.wikipedia.org/wiki/Operating_system), 63 | [video games](https://en.wikipedia.org/wiki/Video_game), [self-driving 64 | cars](https://en.wikipedia.org/wiki/Self-driving_car), 65 | [chatbots](https://en.wikipedia.org/wiki/Chatbot), etc. The key challenge is to 66 | build up intuitions for which combinations of instructions will be useful for 67 | efficiently carrying out a particular desired task. 68 | 69 | # Learning to think like a programmer 70 | 71 | Thinking like a programmer means mentally tackling a difficult challenge by 72 | continually breaking the problem down into successively smaller (and simpler) 73 | pieces, until you find a small enough and simple enough piece that you're able 74 | to solve that one thing. Then you just "[do the next right 75 | thing](https://www.youtube.com/watch?v=w6g1yQV0dIY)" and repeat the process 76 | until your challenge is solved. 77 | 78 | Realistically, although this approach will (in principle) allow you to solve any 79 | programming problem, many novice programmers find it difficult to build up good 80 | intuitions for how to systematically break a complex problem down. You may find 81 | some of the following exercises useful to work through: 82 | 83 | 1. Instruct someone to make an [ice cream 84 | sundae](https://en.wikipedia.org/wiki/Sundae) or put on a jacket. Be as detailed 85 | and specific as possible. Pretend that the person you're instructing is a "dumb" 86 | robot who can understand only primitive instructions (e.g., raise your right arm 87 | by this amount; rotate your hips 30 degrees clockwise; walk forward until you 88 | encounter resistance; etc.). Your instructions should take the form of a 89 | numbered list or flow chart. Following the flow chart should result in the 90 | desired (complex) action being performed (e.g., a sundae is made). 91 | 92 | 2. Practice defining, with as much detail and as specifically as possible, 93 | commonly encountered categories of things. Foods work particularly well. For 94 | example, define what a "sandwich" is, or what a "soup" is. Your definition 95 | should take the form of a numbered list or flow chart that could be followed in 96 | order to determine if something does or does not satisfy the definition. After 97 | designing your definition, "debug" it by verifying that some examples are 98 | correctly classified. Now try to come up with "adversarial" examples to "break" 99 | your definition. For example, is a [hot 100 | dog](https://en.wikipedia.org/wiki/Hot_dog) a sandwich? Are two pieces of bread 101 | with nothing in between a sandwich? Can a sandwich be made of non-bread (or 102 | non-edible) materials? Does your definition accommodate multi-layered sandwiches? 103 | 104 | 3. From the moment you wake up until the moment you go to sleep, spend a day 105 | trying to see the world through the eyes of a computer. Break down every action 106 | or observation or thought into its constituent parts and instructions. Separate 107 | data (what is physically happening) from interpretation (what you *think* is 108 | happening). Think about how each moment of your day could be broken down and 109 | characterized (or explained) using combinations of very simple instructions. 110 | -------------------------------------------------------------------------------- /slides/module_1/introduction_and_overview.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "Copy of introduction_and_overview.ipynb", 7 | "provenance": [], 8 | "collapsed_sections": [], 9 | "include_colab_link": true 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "metadata": { 20 | "id": "view-in-github", 21 | "colab_type": "text" 22 | }, 23 | "source": [ 24 | "\"Open" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": { 30 | "id": "yIWcMraIKoq_" 31 | }, 32 | "source": [ 33 | "### Introduction and overview\n", 34 | "\n", 35 | "Welcome to [PSYC 132: Introduction to Programming for Psychological Scientists](https://github.com/ContextLab/cs-for-psych)!\n", 36 | "\n", 37 | "In this course we'll be using [Google Colaboratory](https://colab.research.google.com/) and [GitHub Classroom](https://classroom.github.com/) to learn how to:\n", 38 | "\n", 39 | "\n", 40 | "* Write and understand computer programs written in Python\n", 41 | "* Design and implement psychological experiments\n", 42 | "* Carry out data analyses on real experimental data\n", 43 | "* Build basic computational models of experimental data\n", 44 | "* Generate compelling figures to display the results visually and help you understand what your data are telling you\n", 45 | "\n", 46 | "A full course syllabus is available [here](https://github.com/ContextLab/cs-for-psych/blob/master/admin/PSYC_132_syllabus.pdf).\n", 47 | "\n" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": { 53 | "id": "X1JNxUREMZ_l" 54 | }, 55 | "source": [ 56 | "# Learning objectives\n", 57 | "\n", 58 | "This notebook is intended to teach you:\n", 59 | "\n", 60 | "1. How to set up your Google Colaboratory and GitHub accounts\n", 61 | "2. How to use Jupyter (Colaboratory) notebooks\n", 62 | "\n" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "metadata": { 68 | "id": "3dm7OT9bUUca" 69 | }, 70 | "source": [ 71 | "## How to set up your Google Colaboratory and GitHub accounts\n", 72 | "\n", 73 | "### Google Colaboratory\n", 74 | "\n", 75 | "Google Colaboratory is a system for writing and running code through a web browser. Your files are stored on Google Drive, and code that you run is executed on a remote Google Cloud server. To learn more about Google Colaboratory, check out [this document](https://colab.research.google.com/notebooks/welcome.ipynb#scrollTo=xitplqMNk_Hc).\n", 76 | "\n", 77 | "Google Colaboratory (including access to Google Cloud computers) is included as part of all Google accounts. To gain access to this resource, you first need to sign up for a Google account (if you don't already have one). Remember your username (email address) and password; you'll use it throughout the term and you'll rely on Colaboratory for most of your slides. You can sign up for a Google account [here](http://www.google.com/). Once you've signed into your Google account, you can access Google Colaboratory [here](https://colab.research.google.com/).\n", 78 | "\n", 79 | "### GitHub\n", 80 | "\n", 81 | "We'll use GitHub to distribute and submit slides. We'll learn more about Git and GitHub (soon!) as we progress in the course. At a high level, Git is a tool for saving and tracking different versions of your files, and GitHub is a server (computer that you can access remotely via the web) that stores your files. For now you'll just need to set up an account-- you don't yet need to know what you're doing on GitHub or why (although if you want to learn more you can check out [this quick-start tutorial](https://www.codecademy.com/learn/learn-git)). I also put together a [YouTube playlist](https://www.youtube.com/playlist?list=PLjQYT8Fwp984zMjN5rJChfdI5Z8jtaWww) to provide some additional background (that playlist is part of my [Storytelling with Data](https://github.com/ContextLab/storytelling-with-data) course). \n", 82 | "\n", 83 | "For now, you just need to create a GitHub account and get yourself set up so that you are able to access and submit course assignments. To create an account (if you don't already have one), go to [github.com](https://github.com/) and follow the \"sign up\" instructions. Remember your username and password; you'll need it throughout the rest of the course.\n", 84 | "\n" 85 | ] 86 | }, 87 | { 88 | "cell_type": "markdown", 89 | "metadata": { 90 | "id": "yOi1Dd-cNHZu" 91 | }, 92 | "source": [ 93 | "### How to use Jupyter (Colaboratory) notebooks\n", 94 | "\n", 95 | "The document you're viewing right now is a Jupyter notebook. A Jupyter notebook is a file (extension: .ipynb, which stands for \"**i**nteractive **Py**thon **n**ote**b**ook). The contents of Jupyter notebooks are stored as .json (JavaScript Object Notation) files. It's not super important that you familiarize yourself with the nitty-gritties of the .json format at this point in the course, but we'll revisit it later when we start working with data.\n", 96 | "\n", 97 | "### What's a Jupyter notebook?\n", 98 | "For a more complete answer, check out [this video](https://youtu.be/CSkTJRNBTME). The short answer is that a Jupyter notebook is an interactive tool that allows you to take notes, execute code, create figures, and easily share it all with other people. Jupyter notebooks comprise a series of _cells_. Each cell (looks like a rectangular block of text) in a notebook contains one of two basic categories of content:\n", 99 | " 1. **Markdown cells** (like the current cell) contain formatted text in the [Markdown text formatting language](https://www.markdowntutorial.com/). You can use these cells kind of like the code underlying text you'd write in a word processor. What you type is what eventually appears on the screen. For the most part, text in Markdown cells gets \"rendered\" (i.e. drawn on the screen) just as you write it. However, you can also specify various formatting tweaks, like creating _italicized_ or **bolded** text, etc. [This tutorial](https://www.markdowntutorial.com/) provides a quick and gentle interactive introduction to Markdown. You can create a new Markdown cell by pressing the \"+\" button in the toolbar and selecting \"Markdown\" from the dropdown list in the toolbar.\n", 100 | " 2. **Code cells** (like the next cell) contains computer code. A computer is like a fancy calculator; computer code is a set of instructions that tells the computer which things to do (and in which order). You can create a new Code cell by pressing the \"+\" button in the toolbar and selecting \"Code\" from the dropdown list in the toolbar.\n", 101 | " \n", 102 | "The text you type into a new notebook cell is a set of instructions that tell the notebook what to do when the cell is _run_ (i.e., transformed from a set of instructions into an executed set of actions). To run a cell, hold the `shift` key and press `enter/return`.\n", 103 | " - When you run a Markdown cell, the text is rendered with the formatting options you specify. To see and/or edit the underlying code, simply double click on the rendered text.\n", 104 | " - When you run a Code cell, the Python instructions you type in are run. We'll explore what this means below. Note: the first time you run a Code cell, you'll see a warning message pop up (asking if it's OK to run code not authored by Google). You should give the notebook permission to run so that you can interact with it." 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "metadata": { 110 | "id": "hZrU6z9eNq-y" 111 | }, 112 | "source": [ 113 | " # Running Python code in Jupyter notebooks\n", 114 | "\n", 115 | "If you're accessing this notebook within Google Colaboratory, you can interact with Code by running it on Google's computers (via Google Cloud-- i.e., Google's high performance computing cluster). The first time you run a command within a colaboratory notebook, you'll automatically be allocated a virtual computer (i.e., a simulation of a computer that's running somewhere on Google's servers). It takes a few seconds to boot that system up (you'll see a \"connecting\" message in the upper right when the new computer is being allocated, and you'll see a bar graph showing RAM and disk usage once the computer is ready). This all happens automatically (there's nothing you need to \"do\" in order to set up one of these virtual computers, aside from view and interact with the notebook in Google Colaboratory).\n", 116 | "\n", 117 | "## A small taste of Python\n", 118 | "\n", 119 | "The simplest way to think about Python is like a sort of calculator. For example, you can type in an equation, and when you \"run\" that line of code the answer is printed to the console window. Play around with the examples below to explore (double click on code to edit it, and press `shift` + `return` to run it." 120 | ] 121 | }, 122 | { 123 | "cell_type": "code", 124 | "metadata": { 125 | "id": "f6gFIBwOCv1n", 126 | "colab": { 127 | "base_uri": "https://localhost:8080/", 128 | "height": 34 129 | }, 130 | "outputId": "c621bd08-28ee-402f-d6a0-8bd01308d01f" 131 | }, 132 | "source": [ 133 | "1 + 1" 134 | ], 135 | "execution_count": null, 136 | "outputs": [ 137 | { 138 | "output_type": "execute_result", 139 | "data": { 140 | "text/plain": [ 141 | "2" 142 | ] 143 | }, 144 | "metadata": { 145 | "tags": [] 146 | }, 147 | "execution_count": 1 148 | } 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "metadata": { 154 | "id": "pZjbR4RtCxJz", 155 | "colab": { 156 | "base_uri": "https://localhost:8080/", 157 | "height": 34 158 | }, 159 | "outputId": "7d1a7dbf-f3ee-450d-f24d-ca6512aa8c71" 160 | }, 161 | "source": [ 162 | "3 * (4 + 1)" 163 | ], 164 | "execution_count": null, 165 | "outputs": [ 166 | { 167 | "output_type": "execute_result", 168 | "data": { 169 | "text/plain": [ 170 | "15" 171 | ] 172 | }, 173 | "metadata": { 174 | "tags": [] 175 | }, 176 | "execution_count": 2 177 | } 178 | ] 179 | }, 180 | { 181 | "cell_type": "markdown", 182 | "metadata": { 183 | "id": "WQl7-gbyHb1r" 184 | }, 185 | "source": [ 186 | "You can also do fancier stuff in Python, like generating plots. Whereas basic math functions (addition, subtraction, multiplication, division, etc.) are included in the [Python standard library](https://docs.python.org/3/library/) (i.e., the base set of instructions that the Python language is built on), generating graphics and figures will require you to use additional [libraries](https://en.wikipedia.org/wiki/Python_(programming_language)#Libraries) (you can gain access to them using `import` statements). We'll learn more about this later." 187 | ] 188 | }, 189 | { 190 | "cell_type": "code", 191 | "metadata": { 192 | "id": "LbJWOsoBIQ_Z", 193 | "colab": { 194 | "base_uri": "https://localhost:8080/", 195 | "height": 282 196 | }, 197 | "outputId": "78f932a5-655d-4c28-ceed-7db8eb1fd29f" 198 | }, 199 | "source": [ 200 | "from matplotlib import pyplot as plt\n", 201 | "import numpy as np\n", 202 | "\n", 203 | "x = np.arange(0, 2*np.math.pi, 0.1)\n", 204 | "plt.plot(x, np.sin(x))" 205 | ], 206 | "execution_count": null, 207 | "outputs": [ 208 | { 209 | "output_type": "execute_result", 210 | "data": { 211 | "text/plain": [ 212 | "[]" 213 | ] 214 | }, 215 | "metadata": { 216 | "tags": [] 217 | }, 218 | "execution_count": 20 219 | }, 220 | { 221 | "output_type": "display_data", 222 | "data": { 223 | "image/png": "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\n", 224 | "text/plain": [ 225 | "
" 226 | ] 227 | }, 228 | "metadata": { 229 | "tags": [] 230 | } 231 | } 232 | ] 233 | }, 234 | { 235 | "cell_type": "markdown", 236 | "metadata": { 237 | "id": "98DxCO5xMEIm" 238 | }, 239 | "source": [ 240 | "Later on in the course we'll learn how to use `matplotlib` (a library for generating graphics and figures) and `numpy` a library for efficiently working with matrices and arrays. For now don't worry about understanding the code above in detail. You can still play around with the contents of each line and see how it changes the figure. For example:\n", 241 | "\n", 242 | "\n", 243 | "1. Change the `0` in `np.arange(0, 2*np.math.pi, 0.1)` to another number. What part of the graph does this affect?\n", 244 | "2. Change the `2*np.math.pi` in `np.arange(0, 2*np.math.pi, 0.1)` to another number. What part of the graph does this affect?\n", 245 | "3. Change the `0.1` in `np.arange(0, 2*np.math.pi, 0.1)` to another number. What part of the graph does this affect?\n", 246 | "4. Change the `np.sin(x)` to `np.cos(x)` in the line `plt.plot(x, np.sin(x))`. What other functions are supported?\n", 247 | "5. What do you think the `np.arange` function does?\n", 248 | "6. What do you think the `plt.plot` function does?\n", 249 | "7. Which aspects of the code *don't* you think you understand? Practice articulating your questions by separating out what you think you understand from what you think you don't understand. Turn your confusion into askable questions!\n", 250 | "\n", 251 | "If you've used a graphing calculator before, you might recognize some similarities between how you interacted with the graphing calculator to plot functions and the code you see above.\n" 252 | ] 253 | }, 254 | { 255 | "cell_type": "markdown", 256 | "metadata": { 257 | "id": "fxwr5orkPcZy" 258 | }, 259 | "source": [ 260 | "# Where to next?\n", 261 | "\n", 262 | "Once you've created your GitHub and Google accounts and gotten a basic sense of what Jupyter notebooks are (and how to run code), you're ready to move on to learning how to write real progams!\n", 263 | "\n", 264 | "[This notebook](https://colab.research.google.com/github/ContextLab/cs-for-psych/blob/master/slides/module_1/intro_to_python.ipynb) provides an introduction to coding basics. You can also return to the course table of contents via [this link](https://github.com/ContextLab/cs-for-psych/blob/master/slides/README.md)." 265 | ] 266 | } 267 | ] 268 | } -------------------------------------------------------------------------------- /slides/module_1/python_learning_playground.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [], 7 | "authorship_tag": "ABX9TyN0rl1cG6REGyz2KivRW+zP", 8 | "include_colab_link": true 9 | }, 10 | "kernelspec": { 11 | "name": "python3", 12 | "display_name": "Python 3" 13 | }, 14 | "language_info": { 15 | "name": "python" 16 | } 17 | }, 18 | "cells": [ 19 | { 20 | "cell_type": "markdown", 21 | "metadata": { 22 | "id": "view-in-github", 23 | "colab_type": "text" 24 | }, 25 | "source": [ 26 | "\"Open" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "source": [ 32 | "# Welcome to the Python playground!\n", 33 | "\n", 34 | "We've got a few activities planned for you today-- pick and choose your favorites!\n", 35 | "\n", 36 | "![](https://media2.giphy.com/media/3oKIPnAiaMCws8nOsE/giphy.gif)" 37 | ], 38 | "metadata": { 39 | "id": "z7k4lvjqBzF-" 40 | } 41 | }, 42 | { 43 | "cell_type": "markdown", 44 | "source": [ 45 | "# Variable Scavenger Hunt\n", 46 | "\n", 47 | "In each line of python below, add a comment (`#`) with each variable's datatype and value, like this:\n", 48 | "\n", 49 | "```python\n", 50 | "x = 1.2345 # type: float; value: 1.2345\n", 51 | "```" 52 | ], 53 | "metadata": { 54 | "id": "rjzIGWDSCyrG" 55 | } 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": 1, 60 | "metadata": { 61 | "colab": { 62 | "base_uri": "https://localhost:8080/" 63 | }, 64 | "id": "ORSyTkFakBOX", 65 | "outputId": "76db2eb0-d982-42b7-85df-48ac7b0e2097" 66 | }, 67 | "outputs": [ 68 | { 69 | "output_type": "stream", 70 | "name": "stdout", 71 | "text": [ 72 | "hello world\n" 73 | ] 74 | } 75 | ], 76 | "source": [ 77 | "num = 5\n", 78 | "str1 = \"hello\"\n", 79 | "str2 = 'world'\n", 80 | "result = str1 + \" \" + str2\n", 81 | "print(result)" 82 | ] 83 | }, 84 | { 85 | "cell_type": "markdown", 86 | "source": [ 87 | "Now write your own code by following the prompts in each comment:" 88 | ], 89 | "metadata": { 90 | "id": "Ox8IyaNRDX2H" 91 | } 92 | }, 93 | { 94 | "cell_type": "code", 95 | "source": [ 96 | "# Define a variable 'num' with datatype 'integer' and value '10'\n", 97 | "\n", 98 | "# Define a variable 'name' with datatype 'string' and value 'John'\n", 99 | "\n", 100 | "# Define a variable 'is_student' with datatype 'boolean' and value 'True'" 101 | ], 102 | "metadata": { 103 | "id": "Z42ZKskVkMDa" 104 | }, 105 | "execution_count": 2, 106 | "outputs": [] 107 | }, 108 | { 109 | "cell_type": "markdown", 110 | "source": [ 111 | "# Function Mad Libs\n", 112 | "\n", 113 | "I'll provide a function with some blanks (`___`) for arguments. Your job is to replace the blanks to create functions that do the desired tasks. For example if I gave you this code block:\n", 114 | "```python\n", 115 | "def multiply_numbers(___, ___):\n", 116 | " return ___ * ___\n", 117 | "```\n", 118 | "\n", 119 | "you could fill in the blanks as:\n", 120 | "```python\n", 121 | "def multiply_numbers(x, y):\n", 122 | " return x * y\n", 123 | "```" 124 | ], 125 | "metadata": { 126 | "id": "8xvu_BaqDh1y" 127 | } 128 | }, 129 | { 130 | "cell_type": "code", 131 | "source": [ 132 | "def add_numbers(___, ___):\n", 133 | " result = ___ + ___\n", 134 | " return result" 135 | ], 136 | "metadata": { 137 | "id": "JP1-QtgbDgeJ" 138 | }, 139 | "execution_count": null, 140 | "outputs": [] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "source": [ 145 | "def square_it(___):\n", 146 | " return ___ ___ ___" 147 | ], 148 | "metadata": { 149 | "id": "NHuvGY3TEQT9" 150 | }, 151 | "execution_count": null, 152 | "outputs": [] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "source": [ 157 | "def convert_to_string(___):\n", 158 | " return ____(___)" 159 | ], 160 | "metadata": { 161 | "id": "u8GpmHCLEYar" 162 | }, 163 | "execution_count": null, 164 | "outputs": [] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "source": [ 169 | "def factorial(___):\n", 170 | " if ________ :\n", 171 | " return 1\n", 172 | " else:\n", 173 | " return ____ * factorial(____)" 174 | ], 175 | "metadata": { 176 | "id": "TrD5Ojz4EjNN" 177 | }, 178 | "execution_count": null, 179 | "outputs": [] 180 | }, 181 | { 182 | "cell_type": "markdown", 183 | "source": [ 184 | "# Conditional Card Game\n", 185 | "\n", 186 | "Below, we provide a function that draws cards for two players. Player 1's card is stored in the variable `p1` and Player 2's card is stored in the variable `p2`. Your job is to use conditional statements to write a set of rules (that you make up!) for determining which player \"wins\" the hand.\n", 187 | "\n", 188 | "For example, if your rules say \"whoever gets the bigger card wins\" then you might write something like:\n", 189 | "```python\n", 190 | "if p1 > p2:\n", 191 | " winner = \"Player 1\"\n", 192 | "elif p2 > p1:\n", 193 | " winner = \"Player 2\"\n", 194 | "else:\n", 195 | " winner = \"It's a tie\"\n", 196 | "```\n", 197 | "\n", 198 | "Try to come up with something interesting/fun." 199 | ], 200 | "metadata": { 201 | "id": "4MvmDbTVEw3O" 202 | } 203 | }, 204 | { 205 | "cell_type": "code", 206 | "source": [ 207 | "import numpy as np\n", 208 | "\n", 209 | "def draw_cards(max_val=10):\n", 210 | " assert type(max_val) is int, 'The maximum value must be an integer'\n", 211 | " assert max_val >= 2, 'There need to be at least 2 cards'\n", 212 | " shuffle = np.random.permutation(max_val)\n", 213 | " return shuffle[0] + 1, shuffle[1] + 1\n", 214 | "\n", 215 | "p1, p2 = draw_cards()\n", 216 | "print(f'Player 1 drew a \"{p1}\" and Player 2 drew a \"{p2}\"')" 217 | ], 218 | "metadata": { 219 | "colab": { 220 | "base_uri": "https://localhost:8080/" 221 | }, 222 | "id": "TNUSZDUrFTQt", 223 | "outputId": "7d7ca476-427c-438c-93cb-9a3060f5253a" 224 | }, 225 | "execution_count": 5, 226 | "outputs": [ 227 | { 228 | "output_type": "stream", 229 | "name": "stdout", 230 | "text": [ 231 | "Player 1 drew a \"5\" and Player 2 drew a \"3\"\n" 232 | ] 233 | } 234 | ] 235 | }, 236 | { 237 | "cell_type": "code", 238 | "source": [ 239 | "winner = 'Unknown'\n", 240 | "\n", 241 | "# define your game's rules here! you should reassign the variable \"winner\" to be\n", 242 | "# either \"Player 1\" or \"Player 2\"\n", 243 | "#---BEGIN---\n", 244 | "\n", 245 | "#---END---\n", 246 | "print(f'Winner: {winner}!')\n", 247 | "\n" 248 | ], 249 | "metadata": { 250 | "id": "z9u3ycCpENtW" 251 | }, 252 | "execution_count": null, 253 | "outputs": [] 254 | }, 255 | { 256 | "cell_type": "markdown", 257 | "source": [ 258 | "# Looping puzzles\n", 259 | "\n", 260 | "Use `for` and/or `while` loops to fill in the functions below" 261 | ], 262 | "metadata": { 263 | "id": "V914ieEOHXi6" 264 | } 265 | }, 266 | { 267 | "cell_type": "code", 268 | "source": [ 269 | "# count the number of times a given character, x, appears in the string my_string:\n", 270 | "def count_char(x, my_string):\n", 271 | " ### fill this in..." 272 | ], 273 | "metadata": { 274 | "id": "h5uCVWT7GiAE" 275 | }, 276 | "execution_count": null, 277 | "outputs": [] 278 | }, 279 | { 280 | "cell_type": "code", 281 | "source": [ 282 | "# write a function that takes a string, my_string, as input and removes all vowels\n", 283 | "def vowel_remover(my_string):\n", 284 | " ### fill me in!" 285 | ], 286 | "metadata": { 287 | "id": "F86bvAT7H2D0" 288 | }, 289 | "execution_count": null, 290 | "outputs": [] 291 | }, 292 | { 293 | "cell_type": "code", 294 | "source": [ 295 | "# write a function that removes any letters in my_string that appear more than once\n", 296 | "def remove_duplicates(my_string):\n", 297 | " ### fill in..." 298 | ], 299 | "metadata": { 300 | "id": "cBPwHFZ0ID9m" 301 | }, 302 | "execution_count": null, 303 | "outputs": [] 304 | }, 305 | { 306 | "cell_type": "markdown", 307 | "source": [ 308 | "# Expert Zone\n", 309 | "\n", 310 | "![](https://gifdb.com/images/high/glitching-hacker-hacking-v56g4l1vaykmsno6.gif)\n", 311 | "\n", 312 | "If you're already a `l33t h4x0r`, why not take on a little challenge from [leetcode](https://leetcode.com/)? (First sign up for a free account if you don't already have one!)\n", 313 | "\n", 314 | "Some fun problems you can answer only knowing concepts we've learned about so far, by difficulty:\n", 315 | " - Easy problems:\n", 316 | " - [Length of last word](https://leetcode.com/problems/length-of-last-word/)\n", 317 | " - [Excel sheet column title](https://leetcode.com/problems/excel-sheet-column-title/)\n", 318 | " - [Roman to integer](https://leetcode.com/problems/roman-to-integer/)\n", 319 | " - Medium problems:\n", 320 | " - [Reverse integer](https://leetcode.com/problems/reverse-integer/)\n", 321 | " - [String to integer](https://leetcode.com/problems/string-to-integer-atoi/)\n", 322 | " - [Valid sudoku](https://leetcode.com/problems/valid-sudoku/)\n", 323 | " - Hard problems:\n", 324 | " - [Median of two sorted arrays](https://leetcode.com/problems/median-of-two-sorted-arrays/)\n", 325 | " - [Regular expression matching](https://leetcode.com/problems/regular-expression-matching/)\n", 326 | " - [N-queens](https://leetcode.com/problems/n-queens/)\n", 327 | "\n", 328 | "\n" 329 | ], 330 | "metadata": { 331 | "id": "fzbQ0MmqIQmr" 332 | } 333 | } 334 | ] 335 | } -------------------------------------------------------------------------------- /slides/module_2/figs/board_notes_pig_latin_translation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ContextLab/cs-for-psych/d4bc7352e53bf2875e032c0da6b8e9d9970bc913/slides/module_2/figs/board_notes_pig_latin_translation.jpg -------------------------------------------------------------------------------- /slides/module_2/interactive_programming.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "interactive_programming.ipynb", 7 | "provenance": [], 8 | "collapsed_sections": [], 9 | "include_colab_link": true 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "metadata": { 20 | "id": "view-in-github", 21 | "colab_type": "text" 22 | }, 23 | "source": [ 24 | "\"Open" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": { 30 | "id": "T97mSHllv89B", 31 | "colab_type": "text" 32 | }, 33 | "source": [ 34 | "# Interactive programming\n", 35 | "\n", 36 | "In this notebook you'll learn how to create programs that you can interact with via the terminal or console. This is called a [Text-based User Interface (TUI)](https://en.wikipedia.org/wiki/Text-based_user_interface). If you've used the Terminal or Command Prompt on your computer, you may already have some experience interacting with TUIs. You likely typically interact with your computer using the mouse and keyboard, or via a touchscreen interface. These interactions that entail displaying complex graphics on the computer screen occur through a [Graphical User Interface (GUI)](https://en.wikipedia.org/wiki/Graphical_user_interface). From a programming standpoint, both TUIs and GUIs are similar with respect to the calculations and operations that users' interactions trigger (this is called the [back end](https://en.wikipedia.org/wiki/Front_and_back_ends)-- the part of the code that the user doesn't need to see or care about, and that typically does the main \"work\" of the program). However, the two styles of interface differ in their [front end](https://en.wikipedia.org/wiki/Front_and_back_ends) (the part of the program that the user sees). TUIs consist of text printed to the console and interactions entail typing with the keyboard. GUIs entail creating clickable windows, images, etc. that you often see when using professionally developed software. We won't be learning about GUIs in this course, but if you'd like to do some learning on your own I would recomend using the `tkinter` library and starting with [this tutorial](https://likegeeks.com/python-gui-examples-tkinter-tutorial/).\n", 37 | "\n", 38 | "# The `input` function\n", 39 | "\n", 40 | "The main drivers of interactive programs are the `print` function (which you learned about in the [previous tutorial](https://colab.research.google.com/github/ContextLab/cs-for-psych/blob/master/slides/intro_to_python.ipynb)) and the `input` function.\n", 41 | "\n", 42 | "The way you use the `input` function is very simple. The function takes a single argument (a string), which (like when you call `print`) is printed to the console and displayed to the user. After printing the given string, `input` causes the currently running program to pause and wait for the user to type something on the keyboard. When the user presses `return`, the function exits and returns any text that the user typed in (as a string). If you assign the output of `input` to a variable, you can access the contents of what the user typed later in your code:\n" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "metadata": { 48 | "id": "0zxqfMK91RXP", 49 | "colab_type": "code", 50 | "colab": { 51 | "base_uri": "https://localhost:8080/", 52 | "height": 51 53 | }, 54 | "outputId": "eebcf978-ed6c-42f8-c174-beca1f1c0fe2" 55 | }, 56 | "source": [ 57 | "name = input('What is your name? ')\n", 58 | "print('Hello, ', name, '!', sep='')" 59 | ], 60 | "execution_count": 11, 61 | "outputs": [ 62 | { 63 | "output_type": "stream", 64 | "text": [ 65 | "What is your name? Jeremy\n", 66 | "Hello, Jeremy!\n" 67 | ], 68 | "name": "stdout" 69 | } 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": { 75 | "id": "bnQHMGSl1kS0", 76 | "colab_type": "text" 77 | }, 78 | "source": [ 79 | "There are a few things worth highlighting in the example above. First, notice that the last character in the `input` function's string, after, the `?`, is a space character (`' '`). This provides some visual separation between the last character of the prompt and the first character that the user types in. Try removing that space and see how the displayed text changes.\n", 80 | "\n", 81 | "A second note is that the `print` function has been called in a new way. There are two differences from how we've used `print` in the past. One difference is that several variables have been stitched together (separated by commas): `'Hello, '` (an unnamed variable), `name` (a string containing the text that the user typed in), and `'!'` (a second unnamed variable). When you pass multiple variables to `print`, the function tries to cast each variable into type `str` and then [concatenates](https://en.wikipedia.org/wiki/Concatenation) the resulting strings (i.e., joins them). By default, each string is separated by a space (`' '`). However, you can specify that the strings should instead by separated by another string of your choice using the `sep` keyword argument. In this case, the separater has been set to the empty string (`''`), which means that no character will be added in between successive strings by the `print` function. This allows us to avoid an additonal space before the `'!'` character (after `name` is printed). You can experiment with removing the `sep` keyword and/or changing its value to see how it affects the outputted text. Note that keyword (named) arguments always come after unnamed arguments. You can distinguish named from unnamed arguments by the fact that named keyword arguments begin with a variable name followed by the assignment operator (`=`).\n", 82 | "\n", 83 | "# Logic and loops\n", 84 | "\n", 85 | "You can make interesting and complex TUIs using `print`, `input`, logic statements (`if`, `elif`, and `else`), and loops (`while` and `for`). For example, the code in the next cell continues to ask for additional inputs until the user types `exit`. The set of inputted strings is returned as a list (excluding the `exit` string)." 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "metadata": { 91 | "id": "VT-Zi1h-v56g", 92 | "colab_type": "code", 93 | "colab": { 94 | "base_uri": "https://localhost:8080/", 95 | "height": 102 96 | }, 97 | "outputId": "e5ad3e4c-c556-421e-a233-fc76913da294" 98 | }, 99 | "source": [ 100 | "def get_inputs():\n", 101 | " x = ''\n", 102 | " i = 0\n", 103 | " xs = []\n", 104 | " while not (x.lower() == 'exit'):\n", 105 | " x = input('Input ' + str(i) + ': ')\n", 106 | " xs.append(x)\n", 107 | " i = i + 1\n", 108 | " return xs[:-1] #returns everything except the last element of xs\n", 109 | "\n", 110 | "inputs = get_inputs()" 111 | ], 112 | "execution_count": 15, 113 | "outputs": [ 114 | { 115 | "output_type": "stream", 116 | "text": [ 117 | "Input 0: This is the first line!\n", 118 | "Input 1: The second line, this is...\n", 119 | "Input 2: And the third line is after the second, but before the fourth.\n", 120 | "Input 3: Are we at the fourth line already?\n", 121 | "Input 4: EXIT\n" 122 | ], 123 | "name": "stdout" 124 | } 125 | ] 126 | }, 127 | { 128 | "cell_type": "markdown", 129 | "metadata": { 130 | "id": "HLw0znvy9pj1", 131 | "colab_type": "text" 132 | }, 133 | "source": [ 134 | "Now we can access everything the user entered, using the `inputs` variable (that we assigned using the output of `get_inputs`):" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "metadata": { 140 | "id": "wqEii9QU9xub", 141 | "colab_type": "code", 142 | "colab": { 143 | "base_uri": "https://localhost:8080/", 144 | "height": 85 145 | }, 146 | "outputId": "8787a293-d9f6-47f1-8f0f-2c54eb90947e" 147 | }, 148 | "source": [ 149 | "inputs" 150 | ], 151 | "execution_count": 16, 152 | "outputs": [ 153 | { 154 | "output_type": "execute_result", 155 | "data": { 156 | "text/plain": [ 157 | "['This is the first line!',\n", 158 | " 'The second line, this is...',\n", 159 | " 'And the third line is after the second, but before the fourth.',\n", 160 | " 'Are we at the fourth line already?']" 161 | ] 162 | }, 163 | "metadata": { 164 | "tags": [] 165 | }, 166 | "execution_count": 16 167 | } 168 | ] 169 | }, 170 | { 171 | "cell_type": "markdown", 172 | "metadata": { 173 | "id": "NPJfRAWW-F0E", 174 | "colab_type": "text" 175 | }, 176 | "source": [ 177 | "# Practice exercise 1\n", 178 | "\n", 179 | "Try writing a short program to ask the user's age (in years). Print out an appropriate message that depends on what the user says (e.g., \"Wow, that's old!\" or \"That's my age too!\"). Things to consider:\n", 180 | "- You'll need to use type casting to convert the user's response (a string) into a number\n", 181 | "- What sorts of inputs would be appropriate? For example:\n", 182 | " - What happens if the user doesn't enter something that can be converted into a number?\n", 183 | " - What if the user enters a number, but spelled out rather than as digits?\n", 184 | " - What if the user enters a negative number?\n", 185 | " - Will you support decimals? Integers? Complex numbers?\n", 186 | "- Try adding a greeting message and an exit message to make interactions with your program more pleasant for the user" 187 | ] 188 | }, 189 | { 190 | "cell_type": "code", 191 | "metadata": { 192 | "id": "6XVKG-M_wIPO", 193 | "colab_type": "code", 194 | "colab": {} 195 | }, 196 | "source": [ 197 | "# enter your code here..." 198 | ], 199 | "execution_count": 0, 200 | "outputs": [] 201 | }, 202 | { 203 | "cell_type": "markdown", 204 | "metadata": { 205 | "id": "lGQOBpn0_fqL", 206 | "colab_type": "text" 207 | }, 208 | "source": [ 209 | "# Practice exercise 2\n", 210 | "\n", 211 | "Let's make an English to [Pig Latin](https://en.wikipedia.org/wiki/Pig_Latin) translator. Ask the user for some (English) text and return the Pig Latin translation:\n", 212 | "- For words that begin with consonant sounds, all letters before the initial vowel are placed at the end of the word sequence. Then, \"ay\" is added.\n", 213 | "- When words begin with consonant clusters (multiple consonants that form one sound), the whole sound is added to the end when speaking or writing.\n", 214 | "- For words that begin with vowel sounds, one just adds \"way\" or \"yay\" to the end (or just \"ay\").\n", 215 | "\n", 216 | "Example considerations:\n", 217 | "- How will you organize your code?\n", 218 | "- What sorts of unexpected inputs might the user provide and how will you handle them?\n", 219 | "- How will you handle capitalization?\n", 220 | "- How can you \"spiff up\" the user interface to make your program more pleasant to interact with?" 221 | ] 222 | }, 223 | { 224 | "cell_type": "code", 225 | "metadata": { 226 | "id": "lyJ-hjxCBYkd", 227 | "colab_type": "code", 228 | "colab": {} 229 | }, 230 | "source": [ 231 | "# enter your code here..." 232 | ], 233 | "execution_count": 0, 234 | "outputs": [] 235 | } 236 | ] 237 | } -------------------------------------------------------------------------------- /slides/module_2/object_oriented_universe.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [], 7 | "authorship_tag": "ABX9TyNrqCsnao5HfL6Zaq+R+LvV", 8 | "include_colab_link": true 9 | }, 10 | "kernelspec": { 11 | "name": "python3", 12 | "display_name": "Python 3" 13 | }, 14 | "language_info": { 15 | "name": "python" 16 | } 17 | }, 18 | "cells": [ 19 | { 20 | "cell_type": "markdown", 21 | "metadata": { 22 | "id": "view-in-github", 23 | "colab_type": "text" 24 | }, 25 | "source": [ 26 | "\"Open" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "source": [ 32 | "# You could build the universe!\n", 33 | "\n", 34 | "In object-oriented programming, *everything* is an object. Built-in objects, like operators, specific datatypes, etc., are useful. But we can get even more power by defining our own functions and classes that extend Python with *new* objects.\n", 35 | "\n", 36 | "Suppose you wanted to build a simulation of the entire universe. How might you start?\n", 37 | "\n", 38 | "![universe](https://i.pinimg.com/originals/29/65/26/29652645bfe64e65f453810ea6b48d67.gif)\n", 39 | "\n", 40 | "We could define a `class` that represents the entire universe. The `Universe` class might have particular methods, attributes, etc., attached to it. In turn, some of those attributes might be comprised of their own classes, like `Galaxy`, `Star`, `BlackHole`, `Planet`, `SolarSystem`, etc. We could define operations (methods) that describe how different objects interact (potentially affecting each others' attributes). If we drilled down far enough, we could end up with some approximation of the entire universe!" 41 | ], 42 | "metadata": { 43 | "id": "JNRBBuYcIXzi" 44 | } 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "source": [ 49 | "# What do *you* want to build?\n", 50 | "\n", 51 | "Let's think about some subset of the universe, or some concept, that we want to turn into object-oriented code. Some ideas:\n", 52 | " - We could simulate a mechanical device comprised of parts\n", 53 | " - We could simulate an organization comprised of people and resources\n", 54 | " - We could simulate something more abstract, like a conceptual hierarchy, a language, a number system, etc.\n", 55 | "\n", 56 | "Things to think about:\n", 57 | " - What is the \"base\" class?\n", 58 | " - How will classes build on each other or inherit each others' properties/attributes/methods?\n", 59 | " - What attributes or methods will the classes support?\n", 60 | " - What datatypes will we use for different attributes?\n", 61 | " - How will instances interact with each other?\n", 62 | "\n", 63 | "Note: for this exercise, we'll focus on \"sketching out\" the ideas/scope, rather than prioritizing debugging and getting the full thing to \"work.\" (If the code works/runs, that'll be a bonus!)" 64 | ], 65 | "metadata": { 66 | "id": "5C5YbZllKHAC" 67 | } 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": null, 72 | "metadata": { 73 | "id": "FSj9tI8nIS1N" 74 | }, 75 | "outputs": [], 76 | "source": [ 77 | "class MyClass(object):\n", 78 | " def __init__(self, *args):\n", 79 | " pass" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "source": [ 85 | "def run_simulation(*args, **kwargs):\n", 86 | " pass" 87 | ], 88 | "metadata": { 89 | "id": "248XghfLLPCo" 90 | }, 91 | "execution_count": null, 92 | "outputs": [] 93 | } 94 | ] 95 | } -------------------------------------------------------------------------------- /slides/module_2/pythonic_code.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "pythonic_code.ipynb", 7 | "provenance": [], 8 | "collapsed_sections": [], 9 | "include_colab_link": true 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "metadata": { 20 | "id": "view-in-github", 21 | "colab_type": "text" 22 | }, 23 | "source": [ 24 | "\"Open" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": { 30 | "id": "qR8_HVkkIDAL", 31 | "colab_type": "text" 32 | }, 33 | "source": [ 34 | "# Writing Pythonic code\n", 35 | "\n", 36 | "The \"Pythonic\" way of writing code is described in [20 aphorisms (only 19 of which have been written down)](https://www.python.org/dev/peps/pep-0020/):" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "metadata": { 42 | "id": "YyrBA0D8IkAb", 43 | "colab_type": "code", 44 | "outputId": "bbb15b91-09b1-4477-e500-4f017ce25ed4", 45 | "colab": { 46 | "base_uri": "https://localhost:8080/", 47 | "height": 374 48 | } 49 | }, 50 | "source": [ 51 | "import this" 52 | ], 53 | "execution_count": 0, 54 | "outputs": [ 55 | { 56 | "output_type": "stream", 57 | "text": [ 58 | "The Zen of Python, by Tim Peters\n", 59 | "\n", 60 | "Beautiful is better than ugly.\n", 61 | "Explicit is better than implicit.\n", 62 | "Simple is better than complex.\n", 63 | "Complex is better than complicated.\n", 64 | "Flat is better than nested.\n", 65 | "Sparse is better than dense.\n", 66 | "Readability counts.\n", 67 | "Special cases aren't special enough to break the rules.\n", 68 | "Although practicality beats purity.\n", 69 | "Errors should never pass silently.\n", 70 | "Unless explicitly silenced.\n", 71 | "In the face of ambiguity, refuse the temptation to guess.\n", 72 | "There should be one-- and preferably only one --obvious way to do it.\n", 73 | "Although that way may not be obvious at first unless you're Dutch.\n", 74 | "Now is better than never.\n", 75 | "Although never is often better than *right* now.\n", 76 | "If the implementation is hard to explain, it's a bad idea.\n", 77 | "If the implementation is easy to explain, it may be a good idea.\n", 78 | "Namespaces are one honking great idea -- let's do more of those!\n" 79 | ], 80 | "name": "stdout" 81 | } 82 | ] 83 | }, 84 | { 85 | "cell_type": "markdown", 86 | "metadata": { 87 | "id": "ibkBCaw6InZY", 88 | "colab_type": "text" 89 | }, 90 | "source": [ 91 | "in short, the Python ideal is to strive in every circumstance to write clear, readable, short code.\n", 92 | "\n", 93 | "With this in mind, consider this simple `for` loop for creating a `list` containing the even squares of the integers 0 -- 9:" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "metadata": { 99 | "id": "J0pc_TQzJsrn", 100 | "colab_type": "code", 101 | "outputId": "5e5f7fa3-c912-4bf1-a042-c6c9ffc447a8", 102 | "colab": { 103 | "base_uri": "https://localhost:8080/", 104 | "height": 34 105 | } 106 | }, 107 | "source": [ 108 | "x = []\n", 109 | "for i in range(10):\n", 110 | " y = i ** 2\n", 111 | " if y % 2 == 0:\n", 112 | " x.append(y)\n", 113 | "\n", 114 | "print(x)" 115 | ], 116 | "execution_count": 0, 117 | "outputs": [ 118 | { 119 | "output_type": "stream", 120 | "text": [ 121 | "[0, 4, 16, 36, 64]\n" 122 | ], 123 | "name": "stdout" 124 | } 125 | ] 126 | }, 127 | { 128 | "cell_type": "markdown", 129 | "metadata": { 130 | "id": "cYEXqlb4J1YF", 131 | "colab_type": "text" 132 | }, 133 | "source": [ 134 | "The Pythonic \"shorthand\" for the above block of code is to use **list comprehensions**.\n", 135 | "\n", 136 | "# List comprehensions\n", 137 | "\n", 138 | "A list comprehension is a concise syntax for creating a list:\n", 139 | "```\n", 140 | "y = [myfunc(i) for i in x if condition(i)]\n", 141 | "```\n", 142 | "Let's unpack this:\n", 143 | "- `y` is the new list we're creating.\n", 144 | "- `x` is a list of values that `y` will be based on.\n", 145 | "- `i` is our way of referring to each individual element of `x`.\n", 146 | "- `myfunc` is a function that we'll apply to each element of `x`.\n", 147 | "- `condition` is a statement that modifies which elements of `x` are included; only elements `i` where `condition(i)` is `True` will be used in constructing `y`. The `if condition(i)` part of the list comprehension is optional; if we exclude it (as in `[myfunc(i) for i in x]`), all elements of `x` will be used to condstruct `y`.\n", 148 | "\n", 149 | "One line of code has packed in an impressive amount of functionality. Further, list comprehensions can be easier to read than complicated loops. For example, the list comprehension syntax makes it clear that the final result will be a `list`, and it forces us to clearly indicate the way element's value is computed.\n", 150 | "\n", 151 | "As an example, we can re-write the above `for` loop using a list comphrension. First, let's use a list comprehension to print out the squares of the integers from 0 -- 9:" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "metadata": { 157 | "id": "IAuI_s9IM9yi", 158 | "colab_type": "code", 159 | "outputId": "f6725038-ca64-4f74-9034-d7639ea9e503", 160 | "colab": { 161 | "base_uri": "https://localhost:8080/", 162 | "height": 34 163 | } 164 | }, 165 | "source": [ 166 | "y = [i ** 2 for i in range(10)]\n", 167 | "print(y)" 168 | ], 169 | "execution_count": 0, 170 | "outputs": [ 171 | { 172 | "output_type": "stream", 173 | "text": [ 174 | "[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]\n" 175 | ], 176 | "name": "stdout" 177 | } 178 | ] 179 | }, 180 | { 181 | "cell_type": "markdown", 182 | "metadata": { 183 | "id": "fMmqcr9xNObk", 184 | "colab_type": "text" 185 | }, 186 | "source": [ 187 | "We can filter out the odd values in two ways; one minimizes the number of repeated calculations and the second is more compact. First, given that we've already computed `y`, we can use the `condition(i)` filtering mechanism to remove odd values:" 188 | ] 189 | }, 190 | { 191 | "cell_type": "code", 192 | "metadata": { 193 | "id": "K7oUy2U3Nlp3", 194 | "colab_type": "code", 195 | "outputId": "ba59db50-f0e9-427d-e099-a3bead623341", 196 | "colab": { 197 | "base_uri": "https://localhost:8080/", 198 | "height": 34 199 | } 200 | }, 201 | "source": [ 202 | "z = [i for i in y if i % 2 == 0]\n", 203 | "print(z)" 204 | ], 205 | "execution_count": 0, 206 | "outputs": [ 207 | { 208 | "output_type": "stream", 209 | "text": [ 210 | "[0, 4, 16, 36, 64]\n" 211 | ], 212 | "name": "stdout" 213 | } 214 | ] 215 | }, 216 | { 217 | "cell_type": "markdown", 218 | "metadata": { 219 | "id": "iad46NU_NrgB", 220 | "colab_type": "text" 221 | }, 222 | "source": [ 223 | "We can also construct the entire `y` list in one line (although this requires squaring each element of `range(10)` twice):" 224 | ] 225 | }, 226 | { 227 | "cell_type": "code", 228 | "metadata": { 229 | "id": "BPfNgqAtNqUt", 230 | "colab_type": "code", 231 | "outputId": "7aa623fc-30da-4eab-c562-073b011642ba", 232 | "colab": { 233 | "base_uri": "https://localhost:8080/", 234 | "height": 34 235 | } 236 | }, 237 | "source": [ 238 | "y = [i ** 2 for i in range(10) if (i ** 2) % 2 == 0]\n", 239 | "print(y)" 240 | ], 241 | "execution_count": 0, 242 | "outputs": [ 243 | { 244 | "output_type": "stream", 245 | "text": [ 246 | "[0, 4, 16, 36, 64]\n" 247 | ], 248 | "name": "stdout" 249 | } 250 | ] 251 | }, 252 | { 253 | "cell_type": "markdown", 254 | "metadata": { 255 | "id": "EoJJh_IXOLbR", 256 | "colab_type": "text" 257 | }, 258 | "source": [ 259 | "## What have we gained?\n", 260 | "\n", 261 | "List comprehensions do not add functionality to Python; we could exactly replicate the functionality of any list comprehension using an appropriate `for` loop. What list comprehensions give us is a clear and compact notation for carrying out a common programming task.\n", 262 | "\n", 263 | "# Generators and lazy evaluation\n", 264 | "\n", 265 | "In some of the previous tutorials, we've been using the `range` function to write `for` loops-- e.g.\n", 266 | "```\n", 267 | "for i in range(99, -1, -1):\n", 268 | " print(i, 'bottle(s) of beer on the wall,', i, 'bottle(s) of beer...')\n", 269 | "```\n", 270 | "We've been thinking about `range(99, -1, -1)` as a list of integers from 99 to 0, counting down by 1s. But let's take a closer look to see what's really going on:" 271 | ] 272 | }, 273 | { 274 | "cell_type": "code", 275 | "metadata": { 276 | "id": "w_r7GfzyV4Q5", 277 | "colab_type": "code", 278 | "outputId": "2906d3aa-3040-44f1-b9b0-6922e8fb436b", 279 | "colab": { 280 | "base_uri": "https://localhost:8080/", 281 | "height": 34 282 | } 283 | }, 284 | "source": [ 285 | "print(range(99, -1, -1))" 286 | ], 287 | "execution_count": 0, 288 | "outputs": [ 289 | { 290 | "output_type": "stream", 291 | "text": [ 292 | "range(99, -1, -1)\n" 293 | ], 294 | "name": "stdout" 295 | } 296 | ] 297 | }, 298 | { 299 | "cell_type": "markdown", 300 | "metadata": { 301 | "id": "nEpbdT34V6-Z", 302 | "colab_type": "text" 303 | }, 304 | "source": [ 305 | "Why aren't 100 numbers printed out in this example? The reason is that `range` is a `generator`, not a `list`. Whereas the elements of a `list` object are all stored in memory at each moment of the object's existence, the values of each element of a `generator` object are only computed and stored in memory at the moment those values are needed to do further computations. This property, of carrying out each computation only once it is necessary to proceed (rather than when the associated objects are created) is called *lazy evaluation*.\n", 306 | "\n", 307 | "As an extreme example, consider how we might manipulate an infinitely long sequence (e.g. the set of positive integers). Without explicitly representing every integer in memory, it's still possible for us to know what the *n*th integer in the sequence is. We could also (in principle) know what the *n*th integer minus the *m*th integer is, for arbitrary (positive integer) values of *n* and *m*. These operations would be impossible (due to requiring infinite memory) if we had to explicitly store the full sequence. Python `generator` objects allow us to create, manipulate, and utilize very long (or even infinite!) sequences in analogous ways to how `list` objects are used.\n", 308 | "\n", 309 | "The Pythonic way to create a `generator` is very similar to the list comprehension syntax, but replacing the outermost square brackets (`[]`) with parentheses (`()`):" 310 | ] 311 | }, 312 | { 313 | "cell_type": "code", 314 | "metadata": { 315 | "id": "ltkMmYWTNAdJ", 316 | "colab_type": "code", 317 | "colab": { 318 | "base_uri": "https://localhost:8080/", 319 | "height": 34 320 | }, 321 | "outputId": "da3cd524-bd5f-4be3-bfba-f9bdb4f3d3b2" 322 | }, 323 | "source": [ 324 | "y = (i ** 2 for i in range(10) if (i ** 2) % 2 == 0)\n", 325 | "print(y)" 326 | ], 327 | "execution_count": 5, 328 | "outputs": [ 329 | { 330 | "output_type": "stream", 331 | "text": [ 332 | " at 0x7f70fd0a6888>\n" 333 | ], 334 | "name": "stdout" 335 | } 336 | ] 337 | }, 338 | { 339 | "cell_type": "markdown", 340 | "metadata": { 341 | "id": "0romhm1TNKCd", 342 | "colab_type": "text" 343 | }, 344 | "source": [ 345 | "Note that the actual values in `y` haven't yet been computed. Nevertheless, we can iterate through the elements of `y` in a `for` loop, just as if `y` was a `list`:" 346 | ] 347 | }, 348 | { 349 | "cell_type": "code", 350 | "metadata": { 351 | "id": "uH0-swZ8NgWL", 352 | "colab_type": "code", 353 | "colab": { 354 | "base_uri": "https://localhost:8080/", 355 | "height": 102 356 | }, 357 | "outputId": "7ce248ce-2e74-43e7-fe92-da712918adcd" 358 | }, 359 | "source": [ 360 | "for i in y:\n", 361 | " print(i)" 362 | ], 363 | "execution_count": 6, 364 | "outputs": [ 365 | { 366 | "output_type": "stream", 367 | "text": [ 368 | "0\n", 369 | "4\n", 370 | "16\n", 371 | "36\n", 372 | "64\n" 373 | ], 374 | "name": "stdout" 375 | } 376 | ] 377 | }, 378 | { 379 | "cell_type": "markdown", 380 | "metadata": { 381 | "id": "ZbGVQEj0P7wx", 382 | "colab_type": "text" 383 | }, 384 | "source": [ 385 | "Another way to create a `generator` is to use the `yield` keyword, which is kind of like an alternative form of `return`. The difference between `yield` and `return` is:\n", 386 | "- When `return` is called, the function exits and the namespace created for that function is destroyed. The function evaluates to the returned value. The next time the function is called, the function behaves just like the first time it was called.\n", 387 | "- When `yield` is called, the namespace (and the interpreter's position within the function) is preserved. The function evaluates to the yielded value. The next time the function is called, the interpreter restores the saved namespace and picks up execution where the previous call left off (after the `yield` statement).\n", 388 | "\n", 389 | "This formulation supports some additional functionality, such as infinite sequences. For example, we can create a generator to print out the first `n` even squares:" 390 | ] 391 | }, 392 | { 393 | "cell_type": "code", 394 | "metadata": { 395 | "id": "b7azcectREJ7", 396 | "colab_type": "code", 397 | "colab": {} 398 | }, 399 | "source": [ 400 | "def even_square_getter():\n", 401 | " i = 0\n", 402 | " while True: #this is an infinite loop! think about why this is ok...\n", 403 | " while (i ** 2) % 2 != 0: #skip over odd squares\n", 404 | " i += 1\n", 405 | " yield i ** 2\n", 406 | " i += 1" 407 | ], 408 | "execution_count": 0, 409 | "outputs": [] 410 | }, 411 | { 412 | "cell_type": "markdown", 413 | "metadata": { 414 | "id": "aCk9OBYYRjG9", 415 | "colab_type": "text" 416 | }, 417 | "source": [ 418 | "Let's test out our generator by printing out the first 100 even squares:" 419 | ] 420 | }, 421 | { 422 | "cell_type": "code", 423 | "metadata": { 424 | "id": "LRZSINLcRopv", 425 | "colab_type": "code", 426 | "colab": { 427 | "base_uri": "https://localhost:8080/", 428 | "height": 54 429 | }, 430 | "outputId": "413ab03d-0b44-4c03-f7af-c1048c108824" 431 | }, 432 | "source": [ 433 | "for i, es in enumerate(even_square_getter()):\n", 434 | " if i >= 100:\n", 435 | " break\n", 436 | " print(es, end=' ') #specifying end=' ' prints out a space after each number rather than a newline character" 437 | ], 438 | "execution_count": 15, 439 | "outputs": [ 440 | { 441 | "output_type": "stream", 442 | "text": [ 443 | "0 4 16 36 64 100 144 196 256 324 400 484 576 676 784 900 1024 1156 1296 1444 1600 1764 1936 2116 2304 2500 2704 2916 3136 3364 3600 3844 4096 4356 4624 4900 5184 5476 5776 6084 6400 6724 7056 7396 7744 8100 8464 8836 9216 9604 10000 10404 10816 11236 11664 12100 12544 12996 13456 13924 14400 14884 15376 15876 16384 16900 17424 17956 18496 19044 19600 20164 20736 21316 21904 22500 23104 23716 24336 24964 25600 26244 26896 27556 28224 28900 29584 30276 30976 31684 32400 33124 33856 34596 35344 36100 36864 37636 38416 39204 " 444 | ], 445 | "name": "stdout" 446 | } 447 | ] 448 | }, 449 | { 450 | "cell_type": "markdown", 451 | "metadata": { 452 | "id": "cinoDMrYSirU", 453 | "colab_type": "text" 454 | }, 455 | "source": [ 456 | "As an exercise, try adding a `print` statements to `even_square_getter` to explore when:\n", 457 | "- the interpreter enters the function body\n", 458 | "- each value is computed\n", 459 | "- the internal iterator (`i`) is incremented\n", 460 | "\n", 461 | "## Iterators\n", 462 | "\n", 463 | "An interator is similar to a `generator` object in that it provides a mechanism for producing list-like sequences whose elements are evaluatated lazily. Any class of object can be made into an iterator by adding two methods:\n", 464 | "- `__iter__`: called when the iterator is initialized. This should return an object that has a `__next__` method.\n", 465 | "- `__next__`: called each time a new element is needed. This should return the next value in the sequence. At the end of the sequence (if it exists), the method should raise a `StopIteration` signal.\n", 466 | "\n", 467 | "Let's continue our example of printing out even squares using the iterator formulation:" 468 | ] 469 | }, 470 | { 471 | "cell_type": "code", 472 | "metadata": { 473 | "id": "NREwSYHnRhzl", 474 | "colab_type": "code", 475 | "colab": {} 476 | }, 477 | "source": [ 478 | "class EvenSquareIterable:\n", 479 | " def __init__(self, n): \n", 480 | " self.n = n #the maximum number of squares to produce\n", 481 | " \n", 482 | " def __iter__(self):\n", 483 | " self.i = 0 #base value that squares are computed from\n", 484 | " self.j = 0 #the number of squares that have been produced so far\n", 485 | " return self\n", 486 | " \n", 487 | " def __next__(self):\n", 488 | " if self.j >= self.n:\n", 489 | " raise StopIteration\n", 490 | " \n", 491 | " self.i += 1\n", 492 | " while (self.i ** 2) % 2 != 0:\n", 493 | " self.i += 1\n", 494 | " \n", 495 | " self.j += 1\n", 496 | " return self.i ** 2" 497 | ], 498 | "execution_count": 0, 499 | "outputs": [] 500 | }, 501 | { 502 | "cell_type": "markdown", 503 | "metadata": { 504 | "id": "CMfA2OEhWfHj", 505 | "colab_type": "text" 506 | }, 507 | "source": [ 508 | "Now we can use `EvenSquareIterable` to print out the first 20 even squares:" 509 | ] 510 | }, 511 | { 512 | "cell_type": "code", 513 | "metadata": { 514 | "id": "tYZqfdSXWmA8", 515 | "colab_type": "code", 516 | "colab": { 517 | "base_uri": "https://localhost:8080/", 518 | "height": 34 519 | }, 520 | "outputId": "451dab69-fd93-41b4-dfb6-1162ee9398fc" 521 | }, 522 | "source": [ 523 | "for x in EvenSquareIterable(20):\n", 524 | " print(x, end=' ')" 525 | ], 526 | "execution_count": 35, 527 | "outputs": [ 528 | { 529 | "output_type": "stream", 530 | "text": [ 531 | "4 16 36 64 100 144 196 256 324 400 484 576 676 784 900 1024 1156 1296 1444 1600 " 532 | ], 533 | "name": "stdout" 534 | } 535 | ] 536 | }, 537 | { 538 | "cell_type": "markdown", 539 | "metadata": { 540 | "id": "UizDeA7UYzvz", 541 | "colab_type": "text" 542 | }, 543 | "source": [ 544 | "## Suggested exercises\n", 545 | "\n", 546 | "To solidify your understanding of list comprenensions, generators, and iterators, try to do the following:\n", 547 | "- Use a list comprehension to create a list of the integers from 1 to 15, but where all even numbers are multiplied by -1 (i.e. `[1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12, 13, -14, 15]`)\n", 548 | "- Define a generator function that produces the values of `sin(x)` for `x` starting at 0 and incrementing by 0.1 radians with each new call\n", 549 | "- Define an iterable object that counts backwards (in increments of -1) down to 50, starting from 100.\n" 550 | ] 551 | }, 552 | { 553 | "cell_type": "code", 554 | "metadata": { 555 | "id": "8zavd9lVb7mm", 556 | "colab_type": "code", 557 | "colab": {} 558 | }, 559 | "source": [ 560 | "#use this cell to experiment..." 561 | ], 562 | "execution_count": 0, 563 | "outputs": [] 564 | } 565 | ] 566 | } -------------------------------------------------------------------------------- /slides/module_2/scope_and_passing_by_value_vs_reference.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "scope_and_passing_by_value_vs_reference.ipynb", 7 | "provenance": [], 8 | "collapsed_sections": [], 9 | "include_colab_link": true 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "metadata": { 20 | "id": "view-in-github", 21 | "colab_type": "text" 22 | }, 23 | "source": [ 24 | "\"Open" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": { 30 | "id": "Yz0MlDiIuxMh", 31 | "colab_type": "text" 32 | }, 33 | "source": [ 34 | "# The scope of variables in Python\n", 35 | "\n", 36 | "The term *scope* refers to the circumstances under which a given variable is accessible. In other words, the places in a program that you can refer to the variable without getting a `NameError` exception like this:" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "metadata": { 42 | "id": "D7rAQA1vuoID", 43 | "colab_type": "code", 44 | "outputId": "f09e45cd-db7c-4ba0-a8c2-75f346e8dea2", 45 | "colab": { 46 | "base_uri": "https://localhost:8080/", 47 | "height": 164 48 | } 49 | }, 50 | "source": [ 51 | "x #gives an error because x hasn't been defined yet" 52 | ], 53 | "execution_count": 0, 54 | "outputs": [ 55 | { 56 | "output_type": "error", 57 | "ename": "NameError", 58 | "evalue": "ignored", 59 | "traceback": [ 60 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 61 | "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", 62 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mx\u001b[0m \u001b[0;31m#gives an error because x hasn't been defined yet\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 63 | "\u001b[0;31mNameError\u001b[0m: name 'x' is not defined" 64 | ] 65 | } 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": { 71 | "id": "8AynV2MMvTvl", 72 | "colab_type": "text" 73 | }, 74 | "source": [ 75 | "When a particular variable has *never* been specified anywhere in your code (or code you've imported), you should get a `NameError`-- Python can't know what you \"mean\" by that variable name, because you haven't defined it yet. Python isn't omniscient or psychic; it can't know what a particular name refers to unless it's either built-in (in which case the implementation of Python itself provides an association between the name of the variable and the object it's referring to), or unless you've explicitly told Python what the name refers to. It's kind of like you not knowing what the word *sneefuloop* means before someone tells you. How could you reasonably be expected to use 'sneefuloop' in a sentence if you don't know what it means? You couldn't!\n", 76 | "\n", 77 | "In a similar vein, because Python executes code sequentially (from top to bottom), you can't refer to a variable *before* it's defined either. For example, consider the following:\n", 78 | "```\n", 79 | "y = x + 7 #fails because x hasn't been defined yet\n", 80 | "x = 3\n", 81 | "y = x + 7 #succeeds because x was set to 3 prior to this line\n", 82 | "```\n", 83 | "Even though both `y = x + 7` are identical, only the second one is interpretable to Python-- the variable `x` doesn't exist until the second line (`x = 3`) when it is defined. Only once `x` is defined can it be used and referred to.\n", 84 | "\n", 85 | "## Variable scope in function definitions\n", 86 | "\n", 87 | "Now consider another example:\n", 88 | "```\n", 89 | "x = 4\n", 90 | "\n", 91 | "def add_to_x(y):\n", 92 | " return x + y\n", 93 | "\n", 94 | "add_to_x(3)\n", 95 | "```\n", 96 | "\n", 97 | "What do you think `add_to_x(3)` would return? Would the function throw an error, because `x` isn't defined inside the body of `add_to_x`? Or will it return `7` because `x` was set to `3` prior to the function definition?\n", 98 | "\n", 99 | "And consider this example:\n", 100 | "```\n", 101 | "def add_to_z(y):\n", 102 | " return z + y\n", 103 | "\n", 104 | "z = 10\n", 105 | "add_to_z(20)\n", 106 | "```\n", 107 | "Will the code fail, beacuse `z` is only defined *after* `add_to_z`? Or will it succeed, because `add_to_z(10)` isn't called until after `z` is defined? The answer is that *both* examples will run. The reason has to do with a concept called *workspaces*\n", 108 | "\n", 109 | "### Python workspaces\n", 110 | "\n", 111 | "A *workspace* is a set of named variables that the interpreter currently has access to. When Python starts, the default workspace provides access only to built-in Python functions and named variables. When you `import` new libraries, the command adds the functions and variables defined in those libraries to the current workspace. One way to think about the workspace is to imagine it looking like a [blueberry pancake](https://en.wikipedia.org/wiki/Pancake). The \"cake\" part of the pancake provides a framework for the variables (blueberries) to sit in. By looking down at the top of the pancake, you can see (access) each variable/blueberry. The total set of variables available in the workspace is the set of blueberries that you can see when you look down at the top of the pancake. You can view them using the `dir` command.\n", 112 | "\n", 113 | "New workspaces are created when you enter the body of a [compound statement](https://docs.python.org/3/reference/compound_stmts.html)---i.e. an `if`, `elif`, `else`, `for`, `while`, function or class definitions, etc. statement where multiple lines are indented to indicate they're grouped together. Specifically, the code inside the statement body gets a new workspace, like throwing another pancake onto the stack. Any variables defined inside the statement body get put into the top-most pancake. When the body of the compound statement ends, the corresponding pancake (workspace) is discarded, along with any of its associated variables. This means, for example, that if you define a new variable inside of a function, it will only be accessible *within that function* (or any compound statements within that function). But once the function exits, its workspace is discarded and its corresponding variables aren't accessible anymore.\n", 114 | "\n", 115 | "The one \"trick,\" and a place where the pancake analogy breaks down somewhat, is that in addition to the top-most workspace (pancake), Python can also access any pancakes *below* that one (i.e., that the given workspace or its ancestors were defined in).\n", 116 | "\n", 117 | "Now that we know that workspaces are like blueberry pancakes, the above examples should be clear, right? Let's go through them line by line, using `dir` to print out the changing workspaces:\n" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "metadata": { 123 | "id": "lansVeS87zXT", 124 | "colab_type": "code", 125 | "outputId": "38c6cb5e-d95a-4a5f-d610-f92e19f2e3f1", 126 | "colab": { 127 | "base_uri": "https://localhost:8080/", 128 | "height": 1000 129 | } 130 | }, 131 | "source": [ 132 | "from pprint import pprint\n", 133 | "\n", 134 | "print('Top-level workspace after importing pprint:')\n", 135 | "pprint(dir())\n", 136 | "\n", 137 | "x = 4\n", 138 | "print('\\nTop-level workspace after x = 4 line:')\n", 139 | "pprint(dir())\n", 140 | " \n", 141 | "def add_to_x(y):\n", 142 | " print('\\nTop-level workspace inside function:')\n", 143 | " pprint(dir())\n", 144 | " return x + y\n", 145 | "\n", 146 | "print('\\nTop-level workspace after function definition:')\n", 147 | "pprint(dir())\n", 148 | "\n", 149 | "add_to_x(3)" 150 | ], 151 | "execution_count": 0, 152 | "outputs": [ 153 | { 154 | "output_type": "stream", 155 | "text": [ 156 | "Top-level workspace after importing pprint:\n", 157 | "['In',\n", 158 | " 'Out',\n", 159 | " '_',\n", 160 | " '_1',\n", 161 | " '_2',\n", 162 | " '_3',\n", 163 | " '_4',\n", 164 | " '__',\n", 165 | " '___',\n", 166 | " '__builtin__',\n", 167 | " '__builtins__',\n", 168 | " '__doc__',\n", 169 | " '__loader__',\n", 170 | " '__name__',\n", 171 | " '__package__',\n", 172 | " '__spec__',\n", 173 | " '_dh',\n", 174 | " '_i',\n", 175 | " '_i1',\n", 176 | " '_i2',\n", 177 | " '_i3',\n", 178 | " '_i4',\n", 179 | " '_i5',\n", 180 | " '_ih',\n", 181 | " '_ii',\n", 182 | " '_iii',\n", 183 | " '_oh',\n", 184 | " '_sh',\n", 185 | " 'add_to_x',\n", 186 | " 'exit',\n", 187 | " 'get_ipython',\n", 188 | " 'pprint',\n", 189 | " 'quit',\n", 190 | " 'x']\n", 191 | "\n", 192 | "Top-level workspace after x = 4 line:\n", 193 | "['In',\n", 194 | " 'Out',\n", 195 | " '_',\n", 196 | " '_1',\n", 197 | " '_2',\n", 198 | " '_3',\n", 199 | " '_4',\n", 200 | " '__',\n", 201 | " '___',\n", 202 | " '__builtin__',\n", 203 | " '__builtins__',\n", 204 | " '__doc__',\n", 205 | " '__loader__',\n", 206 | " '__name__',\n", 207 | " '__package__',\n", 208 | " '__spec__',\n", 209 | " '_dh',\n", 210 | " '_i',\n", 211 | " '_i1',\n", 212 | " '_i2',\n", 213 | " '_i3',\n", 214 | " '_i4',\n", 215 | " '_i5',\n", 216 | " '_ih',\n", 217 | " '_ii',\n", 218 | " '_iii',\n", 219 | " '_oh',\n", 220 | " '_sh',\n", 221 | " 'add_to_x',\n", 222 | " 'exit',\n", 223 | " 'get_ipython',\n", 224 | " 'pprint',\n", 225 | " 'quit',\n", 226 | " 'x']\n", 227 | "\n", 228 | "Top-level workspace after function definition:\n", 229 | "['In',\n", 230 | " 'Out',\n", 231 | " '_',\n", 232 | " '_1',\n", 233 | " '_2',\n", 234 | " '_3',\n", 235 | " '_4',\n", 236 | " '__',\n", 237 | " '___',\n", 238 | " '__builtin__',\n", 239 | " '__builtins__',\n", 240 | " '__doc__',\n", 241 | " '__loader__',\n", 242 | " '__name__',\n", 243 | " '__package__',\n", 244 | " '__spec__',\n", 245 | " '_dh',\n", 246 | " '_i',\n", 247 | " '_i1',\n", 248 | " '_i2',\n", 249 | " '_i3',\n", 250 | " '_i4',\n", 251 | " '_i5',\n", 252 | " '_ih',\n", 253 | " '_ii',\n", 254 | " '_iii',\n", 255 | " '_oh',\n", 256 | " '_sh',\n", 257 | " 'add_to_x',\n", 258 | " 'exit',\n", 259 | " 'get_ipython',\n", 260 | " 'pprint',\n", 261 | " 'quit',\n", 262 | " 'x']\n", 263 | "\n", 264 | "Top-level workspace inside function:\n", 265 | "['y']\n" 266 | ], 267 | "name": "stdout" 268 | }, 269 | { 270 | "output_type": "execute_result", 271 | "data": { 272 | "text/plain": [ 273 | "7" 274 | ] 275 | }, 276 | "metadata": { 277 | "tags": [] 278 | }, 279 | "execution_count": 5 280 | } 281 | ] 282 | }, 283 | { 284 | "cell_type": "markdown", 285 | "metadata": { 286 | "id": "jaRMPDK682Ex", 287 | "colab_type": "text" 288 | }, 289 | "source": [ 290 | "As an exercise, use the `dir` command to understand the following:\n", 291 | "- The second example above (where `add_to_z` is defined)\n", 292 | "- The scope of variables inside a `class` definition\n", 293 | "- The scope of variables inside a `for` loop-- in particular, where/when can the loop iterator (e.g. the `i` in `for i in range(10):...`) be accessed?\n", 294 | "- The scope of variables inside a `try`/`except`/`finally` statement-- which variables are available relative to when an error is raised?\n", 295 | "\n", 296 | "## Some potentially confusing stuff\n", 297 | "\n", 298 | "Consider the following example:\n", 299 | "```\n", 300 | "x = 1\n", 301 | "\n", 302 | "def myfunc(x):\n", 303 | " return x + 1\n", 304 | "\n", 305 | "myfunc(2)\n", 306 | "```\n", 307 | "what value do you think `myfunc(2)` will return? In other words, does the `x` in the `return` statement refer to the value of `x` above the function definition (where it has a value of 1) or does it refer to the value of `x` assigned during the function call (where it has a value of 2)?\n", 308 | "\n", 309 | "When a given variable name appears in multiple workspaces, the *top-most* workspaces are considered first. In other words, once a variable is found in a given workspace, the interpreter uses that variable's value and stops looking in other workspaces. Since the top-most workspace when the `return` statment is executed has `x` assigned the value 2, the function call will return 3. (You should verify this for yourself in a scratch code cell!)\n", 310 | "\n", 311 | "Now consider a tricker example:\n", 312 | "```\n", 313 | "x = {'a': 1, 'b': 2}\n", 314 | "\n", 315 | "def myfunc2(x):\n", 316 | " x['a'] = 2\n", 317 | " return x\n", 318 | "\n", 319 | "y = myfunc2(x)\n", 320 | "```\n", 321 | "What do you expect the values of `y['a']` and `x['a']` are afer calling `myfunc2(x)`? You may be surprised to learn that both `y['a']` and `x['a']` will have a value of 2. (Use a scratch code cell to convince yourself!) The reason has to do with how Python passes variables to functions. We'll explore this next." 322 | ] 323 | }, 324 | { 325 | "cell_type": "markdown", 326 | "metadata": { 327 | "id": "B8zjLjdRF3sh", 328 | "colab_type": "text" 329 | }, 330 | "source": [ 331 | "# Passing by value versus by reference\n", 332 | "\n", 333 | "In our Pythonic learning journey thus far, we've been able to gloss over some of the details underlying what it means to assign a value to a variable. Now it's time to take a peak behind the curtain so that we can deepen our understanding.\n", 334 | "\n", 335 | "The \"secret\" way variables work is that they provide a convenient way of referring to specific blobs of information in the computer's memory. When we execute the statement `x = 2`, what we are really doing is:\n", 336 | "\n", 337 | "1. Storing the value 2 somewhere in the computer's memory\n", 338 | "2. Linking the location of that stored value with the variable name `x`\n", 339 | "\n", 340 | "When we refer to `x` later, the Python interpreter knows where in memory the value of `x` is stored, and whenever some computation needs to be done using the value of `x`, the Python interpreter simply looks up the value stored in the corresponding memory location.\n", 341 | "\n", 342 | "If we were to modify the contents of the computer's memory at the linked-to location, `x` would then have a different value in all subsequent computations. We have already encountered one way of modifying stored values: the assignment operator (`=`). If we call `x = 3` (after having already called `x = 2`), then the value stored at `x`'s location in memory will be updated from 2 to 3.\n", 343 | "\n", 344 | "What happens when we pass a variable (e.g., `x`) to a function? Does the *value* stored at that variable's memory location get passed to the function? Or does the *reference* to the location get passed to the function instead? These two possibilities are called *passing by value* and *passing by reference*, respectively. To foreshadow, Python always passes by reference. But let's work through hypothetical examples of how and when the values of variables are updated when they are passed by value versus by reference.\n", 345 | "\n", 346 | "## Implications of passing by value\n", 347 | "\n", 348 | "To understand how passing by value would work, let's revisit the above example where we defined `myfunc2`:\n", 349 | "```\n", 350 | "x = {'a': 1, 'b': 2}\n", 351 | " \n", 352 | "def myfunc2(x):\n", 353 | " x['a'] = 2\n", 354 | " return x\n", 355 | " \n", 356 | "y = myfunc2(x)\n", 357 | "```\n", 358 | "\n", 359 | "If `x` were passed by value, then the `x` referenced inside the body of `myfunc2` would point to a *different* set of memory locations than the `x` outside of the function body. The value of `x['a']` stored at those new locations would then be modified inside of `myfunc2`. Finally, the assignment statement assigns the (new) locations in memory (containing those modified values) to the named variable `y`. Because only the values in the new memory locations were updated, we're left with two different `dict` objects afer the above code executes: `x` holds its original values, where `a` is 1, whereas `y` holds the updated values, where `a` is 2. (Remember that this is a hypothetical example, since Python passes by reference, not by value.)\n", 360 | "\n", 361 | "## Implications of passing by reference\n", 362 | "\n", 363 | "Now let's walk through what happens when `x` is passed by reference instead of by value. Inside the body of `myfunc2`, the `x` variable points to the *same* memory location as the `x` variable assigned before the function is defined. The function call then modifies the value of `a` stored at `x`'s location in memory. When the function returns, the variable `y` is linked to the same location in memory as `x`. Therefore both `x` and `y` will now have `a` equal to 2, since both of those variables actually refer to the same location in memory. In fact, if we call `x['a'] = 3` after the `y = myfunc2(x)` line, the value of `y['a']` will change to 3 as well! If `x` and `y` both refer to the same location in memory, changing the values stored at that location will change *both* `x` and `y`.\n", 364 | "\n", 365 | "## How can we get Python to pass by value?\n", 366 | "\n", 367 | "All Python functions pass variables by reference (not value)-- so there is no \"clean\" way of changing Python's behavior. However, we can emulate the effects of passing by value using Python's `copy` library. The code below will behave like the \"passing by value\" example above:" 368 | ] 369 | }, 370 | { 371 | "cell_type": "code", 372 | "metadata": { 373 | "id": "8FWuWTckycBm", 374 | "colab_type": "code", 375 | "colab": { 376 | "base_uri": "https://localhost:8080/", 377 | "height": 51 378 | }, 379 | "outputId": "c5b98859-671e-49b3-e935-c42f9eeb8d14" 380 | }, 381 | "source": [ 382 | "import copy\n", 383 | "\n", 384 | "x = {'a': 1, 'b': 2}\n", 385 | " \n", 386 | "def myfunc2(x):\n", 387 | " x['a'] = 2\n", 388 | " return x\n", 389 | " \n", 390 | "y = myfunc2(copy.deepcopy(x)) #this line is what's different\n", 391 | "\n", 392 | "print('x:', x)\n", 393 | "print('y:', y)\n" 394 | ], 395 | "execution_count": 9, 396 | "outputs": [ 397 | { 398 | "output_type": "stream", 399 | "text": [ 400 | "x: {'a': 1, 'b': 2}\n", 401 | "y: {'a': 2, 'b': 2}\n" 402 | ], 403 | "name": "stdout" 404 | } 405 | ] 406 | }, 407 | { 408 | "cell_type": "markdown", 409 | "metadata": { 410 | "id": "-5KpYKm6R4dE", 411 | "colab_type": "text" 412 | }, 413 | "source": [ 414 | "Calling `copy.deepcopy(x)` takes the values stored at the location refered to by `x`, copies them to a new memory location, and returns a reference to that new location. In the example, that new location is then passed to `myfunc2`. When the interpreter enters `myfunc2`, both the old location (of `x`) and the new location (returned by `copy.deepcopy`) contain the same values, but those values are stored at different physical locations in memory. Becaues `myfunc2` only modifies the values stored at the new location, the original values of `x` remain unchanged.\n", 415 | "\n", 416 | "## The costs of copying\n", 417 | "\n", 418 | "In this simple example, there is little cost to copying `x`'s value to a new location in memory. However, when a variable occupies a lot of space in memory (e.g. more than can fit in [RAM](https://en.wikipedia.org/wiki/Random-access_memory)), the `copy.deepcopy` operation can take a long time to run. Therefore the design decision to pass everything by reference in Python helps to make Python code run faster (and require less memory) than if variables were instead passed by value (requiring constant copying). Nevertheless, sometimes it's necessary to maintain separate copies (e.g., pre- and post-modification), and in those scenarios the cost of running `copy.deepcopy` may be warranted." 419 | ] 420 | } 421 | ] 422 | } -------------------------------------------------------------------------------- /slides/module_6/ascii_table.csv: -------------------------------------------------------------------------------- 1 | character,ascii code,binary 2 | a,97,01100001 3 | b,98,01100010 4 | c,99,01100011 5 | d,100,01100100 6 | e,101,01100101 7 | f,102,01100110 8 | g,103,01100111 9 | h,104,01101000 10 | i,105,01101001 11 | j,106,01101010 12 | k,107,01101011 13 | l,108,01101100 14 | m,109,01101101 15 | n,110,01101110 16 | o,111,01101111 17 | p,112,01110000 18 | q,113,01110001 19 | r,114,01110010 20 | s,115,01110011 21 | t,116,01110100 22 | u,117,01110101 23 | v,118,01110110 24 | w,119,01110111 25 | x,120,01111000 26 | y,121,01111001 27 | z,122,01111010 28 | A,65,01000001 29 | B,66,01000010 30 | C,67,01000011 31 | D,68,01000100 32 | E,69,01000101 33 | F,70,01000110 34 | G,71,01000111 35 | H,72,01001000 36 | I,73,01001001 37 | J,74,01001010 38 | K,75,01001011 39 | L,76,01001100 40 | M,77,01001101 41 | N,78,01001110 42 | O,79,01001111 43 | P,80,01010000 44 | Q,81,01010001 45 | R,82,01010010 46 | S,83,01010011 47 | T,84,01010100 48 | U,85,01010101 49 | V,86,01010110 50 | W,87,01010111 51 | X,88,01011000 52 | Y,89,01011001 53 | Z,90,01011010 54 | ,32,00100000 55 | !,33,00100001 56 | -,45,00101101 57 | .,46,00101110 58 | -------------------------------------------------------------------------------- /slides/module_6/permutation_tests_hackathon.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "cracking_the_code.ipynb", 7 | "provenance": [], 8 | "collapsed_sections": [ 9 | "hq-IA2MqcN7Y" 10 | ], 11 | "toc_visible": true, 12 | "authorship_tag": "ABX9TyMTlqVwhu85BSBkSZRw7koZ", 13 | "include_colab_link": true 14 | }, 15 | "kernelspec": { 16 | "name": "python3", 17 | "display_name": "Python 3" 18 | } 19 | }, 20 | "cells": [ 21 | { 22 | "cell_type": "markdown", 23 | "metadata": { 24 | "id": "view-in-github", 25 | "colab_type": "text" 26 | }, 27 | "source": [ 28 | "\"Open" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": { 34 | "id": "1aKpWiQ99H2R" 35 | }, 36 | "source": [ 37 | "# Codebreaking using permutation tests\n", 38 | "\n", 39 | "Congratulations, this is the day you've been waiting for: it's time for you to upgrade your [5K1ll5](https://www.urbandictionary.com/define.php?term=5K1ll3d) by becoming a [*1337 H4X0R*](https://www.urbandictionary.com/define.php?term=1337%20h4x0r)!\n", 40 | "\n", 41 | "![hacking](https://i.giphy.com/media/3oEjHWbXcpeKhTktXi/giphy.webp)\n", 42 | "\n", 43 | "At [this point in our course](https://github.com/ContextLab/cs-for-psych/tree/master/slides#module-6-interrogating-your-data), you're now well-acquainted with the fundamentals of Python, and you've gotten practice with some really [powerful libraries](https://github.com/ContextLab/cs-for-psych/tree/master/slides#module-4-external-libraries). Now it's time to put your knowledge and skills to the test by doing some simple code-breaking (and learning about permutation tests at the same time).\n", 44 | "\n", 45 | "## Overview\n", 46 | "\n", 47 | "We'll be implementing a simple encryption/decryption system, and then using permutation tests to \"break\" each other's encrypted messages.\n", 48 | "\n", 49 | "First let's load in some useful libraries and a character lookup table:" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "metadata": { 55 | "colab": { 56 | "base_uri": "https://localhost:8080/", 57 | "height": 238 58 | }, 59 | "id": "7bT94loiqd6v", 60 | "outputId": "774c5b34-c03c-4f38-cbb2-e56545c73593" 61 | }, 62 | "source": [ 63 | "import numpy as np\n", 64 | "import pandas as pd\n", 65 | "from matplotlib import pyplot as plt\n", 66 | "\n", 67 | "ascii_table = pd.read_csv('https://raw.githubusercontent.com/ContextLab/cs-for-psych/master/slides/module_6/ascii_table.csv', dtype=str)\n", 68 | "ascii_table['ascii code'] = ascii_table['ascii code'].apply(int)\n", 69 | "ascii_table.set_index('ascii code', inplace=True)\n", 70 | "ascii_table.sort_index(inplace=True)\n", 71 | "\n", 72 | "ascii_table.head()" 73 | ], 74 | "execution_count": null, 75 | "outputs": [ 76 | { 77 | "output_type": "execute_result", 78 | "data": { 79 | "text/html": [ 80 | "
\n", 81 | "\n", 94 | "\n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | "
characterbinary
ascii code
3200100000
33!00100001
45-00101101
46.00101110
65A01000001
\n", 135 | "
" 136 | ], 137 | "text/plain": [ 138 | " character binary\n", 139 | "ascii code \n", 140 | "32 00100000\n", 141 | "33 ! 00100001\n", 142 | "45 - 00101101\n", 143 | "46 . 00101110\n", 144 | "65 A 01000001" 145 | ] 146 | }, 147 | "metadata": { 148 | "tags": [] 149 | }, 150 | "execution_count": 145 151 | } 152 | ] 153 | }, 154 | { 155 | "cell_type": "markdown", 156 | "metadata": { 157 | "id": "8jfwUjMmaKEt" 158 | }, 159 | "source": [ 160 | "\n", 161 | "## Encoding (and encrypting) messages\n", 162 | "\n", 163 | "We'll use a simple algorithm to encrypt a message, encoded as a string of human-readable characters (all of this is provided for you in the `encode` function):\n", 164 | "1. Turn the string of human-readable characters into a binary sequence (i.e., a sequence of 0s and 1s). Each character is represented by one byte (a sequence of 8 bits-- i.e., 0s and 1s).\n", 165 | "2. [Circularly shift](https://en.wikipedia.org/wiki/Circular_shift) the binary sequence by some number of positions, $k$ ($k$ will be your encryption key).\n", 166 | "\n", 167 | "The idea of applying a circular shift is to move each element in the sequence ahead by $k$ positions. Then, for the last $k$ elements, loop their positions around back to the front of the sequence. Here's a schematic of what it looks like to circularly shift a sequence of 8 bits forward by 1 position:\n", 168 | "\n", 169 | "![circular shift](https://upload.wikimedia.org/wikipedia/commons/3/37/Rotate_right.svg)\n", 170 | "\n", 171 | "This results in a new \"scrambled\" binary sequence.\n", 172 | "\n", 173 | "**_Important note_: the lookup table (for converting characters to bytes) may not include every character in the message. If a character is missing from the lookup table, the encoder will generate a *random* set of 8 0s and 1s for that character.**\n" 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "metadata": { 179 | "id": "C0U6St84woeQ" 180 | }, 181 | "source": [ 182 | "def circshift(s, shift):\n", 183 | " shift %= len(s) #think about what this line does and why it's needed...\n", 184 | " return s[shift:] + s[:shift]" 185 | ], 186 | "execution_count": null, 187 | "outputs": [] 188 | }, 189 | { 190 | "cell_type": "code", 191 | "metadata": { 192 | "id": "2og2lZI2tDYz" 193 | }, 194 | "source": [ 195 | "def encode(msg, encrypt_key=0):\n", 196 | " x = ''\n", 197 | " for c in msg:\n", 198 | " try:\n", 199 | " x += ascii_table.query(f'character == \"{c}\"')['binary'].values[0]\n", 200 | " except: #generate a random sequence of 0s and 1s\n", 201 | " n = np.random.randint(8) + 1 #number of 1s\n", 202 | " chars = [*(['1'] * n), *(['0'] * (8 - n))]\n", 203 | " x += ''.join(np.random.permutation(chars).tolist())\n", 204 | " \n", 205 | " return circshift(x, encrypt_key)" 206 | ], 207 | "execution_count": null, 208 | "outputs": [] 209 | }, 210 | { 211 | "cell_type": "markdown", 212 | "metadata": { 213 | "id": "pmGxHiDhaZRS" 214 | }, 215 | "source": [ 216 | "\n", 217 | "## Decoding (and decrypting) messages\n", 218 | "\n", 219 | "If you knew the encrypted string's key, you could simply:\n", 220 | "1. Apply a circular shift of $-k$ to offset the \"encryption\"\n", 221 | "2. Break the sequence into bytes\n", 222 | "3. Use a reverse lookup table to turn each byte back into a human-readable character\n", 223 | "\n", 224 | "I've provided the `decode` function below for convenience. Given an encrypted message and an encryption key, the function attempts to use the character lookup table to replace each byte in the message with a human-readable character. If no valid character is found, any illegal byte sequences are replaced with \"\\*\".\n", 225 | "\n", 226 | "The challenge is that, in this exercise, you *won't* always know the encryption key.\n" 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "metadata": { 232 | "id": "I5q4Odwouldh" 233 | }, 234 | "source": [ 235 | "def decode(x, encrypt_key=0):\n", 236 | " msg = ''\n", 237 | " for c in [''.join(b) for b in np.split(np.array(list(circshift(x, -encrypt_key))), len(x) / 8)]:\n", 238 | " try:\n", 239 | " msg += ascii_table.query(f'binary == \"{c}\"')['character'].values[0]\n", 240 | " except:\n", 241 | " msg += '*'\n", 242 | " return msg" 243 | ], 244 | "execution_count": null, 245 | "outputs": [] 246 | }, 247 | { 248 | "cell_type": "markdown", 249 | "metadata": { 250 | "id": "hq-IA2MqcN7Y" 251 | }, 252 | "source": [ 253 | "\n", 254 | "## Code breaking\n", 255 | "\n", 256 | "Your first job is to write a function, `decrypt`, to reliably(!) decrypt a message containing the characters a--z (lowercase letters), A--Z (uppercase letters), and some basic punctuation (!, -, ., and \" \"). You can assume that the original message would make sense (e.g., to a fluent English speaker).\n", 257 | "\n", 258 | "I'd recommend first defining a \"goodness\" measure (computed for each possible key) that reflects (a) the proportion or count of legal characters (non-\\*s) in the decoded string and (b) the proportion of valid English words in the decoded string. (You may find [this library](https://pypi.org/project/english-words/) useful-- it contains lists of most English words.)\n", 259 | "\n", 260 | "Once you've defined your goodness measure, decrypting a message means simply returning the decoded message with the highest goodness score (along with the key that produced that score).\n", 261 | "\n", 262 | "Considerations:\n", 263 | "- Could you speed this function up by only looking at part of the message? (Or by only looking at part of the message at *first*?) Hint: think about what would happen if you had randomly cut off $n$ bits from the start or end of your message. How could you compensate for those missing bits and decode the rest of the message?\n", 264 | "- How will you deal with potential ambiguities (e.g., multiple keys that yield the same goodness scores)?" 265 | ] 266 | }, 267 | { 268 | "cell_type": "code", 269 | "metadata": { 270 | "id": "jcNCLjMOcNch" 271 | }, 272 | "source": [ 273 | "def decrypt(x):\n", 274 | " ### BEGIN YOUR CODE\n", 275 | " pass\n", 276 | " ### END YOUR CODE\n", 277 | " return msg, key #best guess at decoded message and key" 278 | ], 279 | "execution_count": null, 280 | "outputs": [] 281 | }, 282 | { 283 | "cell_type": "markdown", 284 | "metadata": { 285 | "id": "4fiJXrKYUrMm" 286 | }, 287 | "source": [ 288 | "Next, let's use a permutation test to compute the probability that a given key, $k$ is the correct decryption key for a given encrypted message, $m$:\n", 289 | "\n", 290 | "- First compute the goodness score for the given message, using the encryption key $k$. This is your \"observed\" goodness.\n", 291 | "- Next, compute a \"reference\" distribution by computing goodness scores for a large number of randomly chosen $k$s (you may find `np.random.randint` useful for this). Since the number of possible keys will be finite (and manageable!), you could also simply compute the reference distribution as the goodness scores obtained from *all* possible keys.\n", 292 | "- Now compute a $p$-value by computing the proportion of goodness scores in the reference distribution that are greater than the observed goodness score. This is the permuted estimate of the probability that $k$ is a random guess (e.g., rather than the true key)." 293 | ] 294 | }, 295 | { 296 | "cell_type": "code", 297 | "metadata": { 298 | "id": "PcMwEdsvc_0Q" 299 | }, 300 | "source": [ 301 | "def permutation_test(x, encrypt_key):\n", 302 | " ### BEGIN YOUR CODE\n", 303 | " pass\n", 304 | " ### END YOUR CODE\n", 305 | " return p #p-value (estimated probability that the given encrypt_key is *not* correct)" 306 | ], 307 | "execution_count": null, 308 | "outputs": [] 309 | }, 310 | { 311 | "cell_type": "markdown", 312 | "metadata": { 313 | "id": "1k3GqRz-dHkB" 314 | }, 315 | "source": [ 316 | "# Some examples to get you started\n", 317 | "\n", 318 | "Let's explore a few simple examples to explore how `encode` and `decode` work. We'll start by using an encryption key of 5 to encode and encrypt the string `'this is a test'`:" 319 | ] 320 | }, 321 | { 322 | "cell_type": "code", 323 | "metadata": { 324 | "colab": { 325 | "base_uri": "https://localhost:8080/" 326 | }, 327 | "id": "ZgwI9NDT7dzw", 328 | "outputId": "ac6341c2-6d1d-4324-9190-6773f9bcd4c7" 329 | }, 330 | "source": [ 331 | "test_message = 'this is a test'\n", 332 | "key = 5\n", 333 | "encrypted_message = encode(test_message, encrypt_key=key)\n", 334 | "print(encrypted_message)" 335 | ], 336 | "execution_count": null, 337 | "outputs": [ 338 | { 339 | "output_type": "stream", 340 | "text": [ 341 | "1000110100001101001011100110010000001101001011100110010000001100001001000000111010001100101011100110111010001110\n" 342 | ], 343 | "name": "stdout" 344 | } 345 | ] 346 | }, 347 | { 348 | "cell_type": "markdown", 349 | "metadata": { 350 | "id": "R5yqzaD3eJ03" 351 | }, 352 | "source": [ 353 | "If we try to decode the encrypted message with the wrong key, we get gibberish:" 354 | ] 355 | }, 356 | { 357 | "cell_type": "code", 358 | "metadata": { 359 | "colab": { 360 | "base_uri": "https://localhost:8080/" 361 | }, 362 | "id": "AJ3cfKw0eQ8b", 363 | "outputId": "dcc0ef39-b9cb-463c-c642-8c6ab7608955" 364 | }, 365 | "source": [ 366 | "guess = 0\n", 367 | "print(decode(encrypted_message, encrypt_key=guess))" 368 | ], 369 | "execution_count": null, 370 | "outputs": [ 371 | { 372 | "output_type": "stream", 373 | "text": [ 374 | "**.d*.d*****n*\n" 375 | ], 376 | "name": "stdout" 377 | } 378 | ] 379 | }, 380 | { 381 | "cell_type": "markdown", 382 | "metadata": { 383 | "id": "PdH-xVh9eegd" 384 | }, 385 | "source": [ 386 | "But if we decode the encrypted message with the correct key, we get back the original message:" 387 | ] 388 | }, 389 | { 390 | "cell_type": "code", 391 | "metadata": { 392 | "colab": { 393 | "base_uri": "https://localhost:8080/" 394 | }, 395 | "id": "nNC6ciVtejDL", 396 | "outputId": "464a60bb-f1f7-40c9-e292-631ba5eced38" 397 | }, 398 | "source": [ 399 | "print(decode(encrypted_message, encrypt_key=key))" 400 | ], 401 | "execution_count": null, 402 | "outputs": [ 403 | { 404 | "output_type": "stream", 405 | "text": [ 406 | "this is a test\n" 407 | ], 408 | "name": "stdout" 409 | } 410 | ] 411 | }, 412 | { 413 | "cell_type": "markdown", 414 | "metadata": { 415 | "id": "gW4jUe7geomf" 416 | }, 417 | "source": [ 418 | "We can also add in some \"illegal\" characters that aren't in the lookup table, to see how that can make things more...interesting:" 419 | ] 420 | }, 421 | { 422 | "cell_type": "code", 423 | "metadata": { 424 | "colab": { 425 | "base_uri": "https://localhost:8080/", 426 | "height": 36 427 | }, 428 | "id": "gOWoNDWrGtLt", 429 | "outputId": "b5d3f396-4777-4e54-d77c-d966ce7d3db6" 430 | }, 431 | "source": [ 432 | "decode(encode('Is this a test? Or is this just practice? Or both!?'))" 433 | ], 434 | "execution_count": null, 435 | "outputs": [ 436 | { 437 | "output_type": "execute_result", 438 | "data": { 439 | "application/vnd.google.colaboratory.intrinsic+json": { 440 | "type": "string" 441 | }, 442 | "text/plain": [ 443 | "'Is this a testw Or is this just practice* Or both!*'" 444 | ] 445 | }, 446 | "metadata": { 447 | "tags": [] 448 | }, 449 | "execution_count": 182 450 | } 451 | ] 452 | }, 453 | { 454 | "cell_type": "markdown", 455 | "metadata": { 456 | "id": "QdXXrTEtmx1E" 457 | }, 458 | "source": [ 459 | "# Now for some \"real\" messages...\n", 460 | "\n", 461 | "I've encrypted a set of 83 messages using a new randomly selected encryption key for each message:" 462 | ] 463 | }, 464 | { 465 | "cell_type": "code", 466 | "metadata": { 467 | "colab": { 468 | "base_uri": "https://localhost:8080/", 469 | "height": 206 470 | }, 471 | "id": "9bujENyYmZcI", 472 | "outputId": "8b3191aa-1dab-409a-9dcb-d535cbe11f6c" 473 | }, 474 | "source": [ 475 | "encrypted = pd.read_csv('https://raw.githubusercontent.com/ContextLab/cs-for-psych/master/slides/module_6/encrypted.csv').drop(['Unnamed: 0'], axis=1)\n", 476 | "encrypted.head()" 477 | ], 478 | "execution_count": null, 479 | "outputs": [ 480 | { 481 | "output_type": "execute_result", 482 | "data": { 483 | "text/html": [ 484 | "
\n", 485 | "\n", 498 | "\n", 499 | " \n", 500 | " \n", 501 | " \n", 502 | " \n", 503 | " \n", 504 | " \n", 505 | " \n", 506 | " \n", 507 | " \n", 508 | " \n", 509 | " \n", 510 | " \n", 511 | " \n", 512 | " \n", 513 | " \n", 514 | " \n", 515 | " \n", 516 | " \n", 517 | " \n", 518 | " \n", 519 | " \n", 520 | " \n", 521 | " \n", 522 | " \n", 523 | " \n", 524 | " \n", 525 | " \n", 526 | " \n", 527 | "
message
01100001001000000110001001101111011011110110101...
11100101011101000111010101101110011010010110000...
21000010110111001100100001000000110000101101110...
31100110011100100000011101000110111100100000011...
40011010010110000100101110001000000100100001101...
\n", 528 | "
" 529 | ], 530 | "text/plain": [ 531 | " message\n", 532 | "0 1100001001000000110001001101111011011110110101...\n", 533 | "1 1100101011101000111010101101110011010010110000...\n", 534 | "2 1000010110111001100100001000000110000101101110...\n", 535 | "3 1100110011100100000011101000110111100100000011...\n", 536 | "4 0011010010110000100101110001000000100100001101..." 537 | ] 538 | }, 539 | "metadata": { 540 | "tags": [] 541 | }, 542 | "execution_count": 231 543 | } 544 | ] 545 | }, 546 | { 547 | "cell_type": "markdown", 548 | "metadata": { 549 | "id": "Ak89hyKjnQK8" 550 | }, 551 | "source": [ 552 | "Can you recover the keys and decode the messages? Good luck!" 553 | ] 554 | } 555 | ] 556 | } -------------------------------------------------------------------------------- /slides/module_7/make_a_model.md: -------------------------------------------------------------------------------- 1 | --- 2 | marp: true 3 | title: Make a model! 4 | description: Introduction to model design and implementation 5 | url: https://github.com/ContextLab/storytelling-with-data 6 | theme: cdl-theme 7 | transition: fade 0.25s 8 | class: 9 | - lead 10 | --- 11 | ![bg opacity:0.1](https://cdn.theatlantic.com/thumbor/FPTWEk2jCD_GOlSx-Q3p04tDPOk=/302x50:4317x2308/1600x900/media/img/mt/2014/08/shutterstock_187027727-1/original.jpg) 12 | 13 | # Make a model! 14 | ## Jeremy R. Manning 15 | PSYC 132: Introduction to Programming for Psychological Scientists 16 | 17 | --- 18 | 19 | ### What *is* a model (and what do "models" *do*)? 20 | 21 | ![bg opacity:0.1](https://cdn.theatlantic.com/thumbor/FPTWEk2jCD_GOlSx-Q3p04tDPOk=/302x50:4317x2308/1600x900/media/img/mt/2014/08/shutterstock_187027727-1/original.jpg) 22 | 23 | - Capture key attributes of a system or phenomenon 24 | - Predict something we can't directly observe 25 | - Simulate some process 26 | 27 | ![width:400](https://thumbs.gfycat.com/EminentTinyAlbino-size_restricted.gif) 28 | 29 | --- 30 | 31 | # What do (real) models "look" like? 32 | 33 | ![bg opacity:0.1](https://cdn.theatlantic.com/thumbor/FPTWEk2jCD_GOlSx-Q3p04tDPOk=/302x50:4317x2308/1600x900/media/img/mt/2014/08/shutterstock_187027727-1/original.jpg) 34 | 35 | - A physical thing in the real world (e.g., a mouse brain is "model" of a human brain) 36 | - A system of differential equations that describe how different variables in a system interact 37 | - A computer program that acts like a "machine" that tries to replicate behavior(s) of the "real" system 38 | 39 | --- 40 | 41 | # What do ("fake") models "look" like? 42 | 43 | ![bg opacity:0.1](https://t3.ftcdn.net/jpg/04/54/68/48/360_F_454684814_onsuNLFkDyP6ctPCA4mOg8IHeFEekSIw.jpg) 44 | 45 | - Regressions, ANOVAs, statistical tests 46 | - Technically these are "models," but they're not particularly satisfying to build, and in most cases we don't think these approaches "work" anything like what we're trying to explain in the real world 47 | 48 | --- 49 | 50 | # Model *input* 51 | 52 | A model's inputs are usually one or more datasets, usually in the form of tables of numbers, that describe the behaviors of different equations or processes encompassed by the model. 53 | 54 | ![width:700px](https://media.tenor.com/cLnzRPB0jEAAAAAC/ally-sheedy-short-circuit.gif) 55 | 56 | --- 57 | 58 | # Model *output* 59 | 60 | The output of a model is usually (also) one or more tables of numbers that describe the behaviors of the equations or processes encompassed by the model 61 | 62 | 63 | ![width:500px](https://miro.medium.com/v2/resize:fit:1400/1*bhFifratH9DjKqMBTeQG5A.gif) 64 | 65 | --- 66 | 67 | # The model "game" 68 | 69 | Take in some numbers and give out some (usually different) numbers. 70 | 71 | ![width:500px](https://cdn-wordpress-info.futurelearn.com/info/wp-content/uploads/1-3-IPO-Football-1.gif) 72 | 73 | --- 74 | 75 | # Why is this interesting/useful? 76 | 77 | In the "real world," important stuff happens. In models, we're only pushing numbers around. So...who cares? 78 | 79 | ![width:500](https://thumbs.gfycat.com/AcrobaticYellowCoati-size_restricted.gif) 80 | 81 | --- 82 | 83 | # The "star trek" version of building a model: 84 | 85 | - Scan every molecule in the system 86 | - Input all of the (true) rules of the universe 87 | - Churn through some computations and get out the answer to whatever your question was 88 | 89 | ![200px](https://i.gifer.com/IQta.gif) 90 | 91 | --- 92 | 93 | # How modeling works in the "real" world: 94 | 95 | - Make up the components of the system you care about 96 | - Make up some rules about how the system works 97 | - Churn through some computations and see how the system behaves 98 | 99 | ![200px](https://media3.giphy.com/media/l0IylOPCNkiqOgMyA/giphy.gif?cid=6c09b952j9guhob9b92sykuu5jcyirwlzzldx25tyj2u64ci&ep=v1_gifs_search&rid=giphy.gif&ct=g) 100 | 101 | --- 102 | 103 | # But...(!!) 104 | 105 | ![bg opacity:0.1](https://media.tenor.com/VKFtl5C7jIYAAAAC/mind-blown.gif) 106 | 107 | - Think about how you'd *represent* a "star trek" style "every molecule" dataset. Probably...with numbers! 108 | - Think about how you'd write down the rules of the system. Maybe with equations? Functions? 109 | 110 | --- 111 | 112 | # So what are models *really* doing? 113 | 114 | ![bg opacity:0.1](https://media0.giphy.com/media/2bYewTk7K2No1NvcuK/giphy.gif) 115 | 116 | Computers (and math) can only tell us about the world in the first place by using and manipulating numbers. For a computer, reality *is* numbers. *To a computer, there's no distinction between a thing in the real world and the measurement or representation of that thing!* 117 | 118 | --- 119 | 120 | # So what are models *really* doing? 121 | 122 | ![bg opacity:0.1](https://media0.giphy.com/media/2bYewTk7K2No1NvcuK/giphy.gif) 123 | 124 | When a number changes in a model, if that number is attached to something you think is meaningful, from the perspective of the computer *it's as though reality itself is changing.* You are the god of your simulated (model) universe. 125 | 126 | ![width:500px](https://media.tenor.com/D2ZlkeUWSk4AAAAd/zenitsu-god-mode.gif) 127 | 128 | --- 129 | ![bg opacity:0.1](https://www.securitysales.com/wp-content/uploads/2022/10/AdobeStock_84097438.jpeg) 130 | 131 | > All models are wrong, but some are useful 132 | --George Box (1976) 133 | 134 | --- 135 | 136 | # How can you get started? 137 | 138 | ![bg opacity:0.1](https://owncloud.com/wp-content/uploads/2020/09/20200327-few-graphic-1080x675.png) 139 | 140 | - What do you want to model? 141 | - How are you going to model it? 142 | - What are the components/processes in the model's scope? 143 | - What are the "rules" of the model? 144 | - How will you get out an "answer" or characterize the model's behaviors? -------------------------------------------------------------------------------- /slides/module_8/intro_to_NLP.md: -------------------------------------------------------------------------------- 1 | --- 2 | marp: true 3 | title: A quick introduction to natural language processing in Python 4 | description: Introduce some NLP models and approaches 5 | url: https://github.com/ContextLab/storytelling-with-data 6 | theme: cdl-theme 7 | transition: fade 0.25s 8 | class: 9 | - lead 10 | --- 11 | 12 | ![bg opacity:0.1](https://uploads-ssl.webflow.com/614c82ed388d53640613982e/635bcc3c2b1b16702f8917c9_634fd7afbe19224c4a7a4a0e_6320786b1cfec14310b5f181_natural-language-processing--NLP-.png) 13 | 14 | # A quick introduction to natural language processing in Python 15 | ## Jeremy R. Manning 16 | PSYC 132: Introduction to Programming for Psychological Scientists 17 | 18 | --- 19 | 20 | ![bg opacity:0.1](https://uploads-ssl.webflow.com/614c82ed388d53640613982e/635bcc3c2b1b16702f8917c9_634fd7afbe19224c4a7a4a0e_6320786b1cfec14310b5f181_natural-language-processing--NLP-.png) 21 | 22 | # What is natural language processing? 23 | 24 | - Branch of computational linguistics 25 | - Use computational approaches to process, analyze, and understand language 26 | 27 | --- 28 | 29 | # Early tasks 30 | 31 | ![width:1000px](https://byteiota.com/wp-content/uploads/2021/01/POS-Tagging-800x400.jpg) 32 | 33 | --- 34 | 35 | # Early tasks 36 | 37 | ![width:1000px](https://wisdomml.in/wp-content/uploads/2022/08/stem_feats.jpg) 38 | 39 | --- 40 | 41 | # Early tasks: automatic summarization 42 | 43 | ![width:1000px](https://techcommunity.microsoft.com/t5/image/serverpage/image-id/180981i9EA877DDFF97D50D/image-size/large?v=v2&px=999) 44 | 45 | --- 46 | 47 | # But how can we get at the *meaning* of natural language? 48 | 49 | --- 50 | 51 | # Text embedding models 52 | 53 | - Preprocess some text to make a "training corpus" 54 | - Train a model to parse the documents in the corpus 55 | - Goal: generate "feature vectors" (for words, phrases, documents, etc.) that capture semantic properties of the text 56 | 57 | --- 58 | 59 | # Latent semantic analysis 60 | 61 | ![width:800px](https://i.ytimg.com/vi/M1duqgg8-IM/maxresdefault.jpg) 62 | 63 | --- 64 | 65 | # Latent Dirichlet Allocation (LDA) 66 | 67 | ![width:600px](https://community.alteryx.com/t5/image/serverpage/image-id/124666i826A507A4B5E3107?v=v2) 68 | 69 | --- 70 | 71 | # Word2vec 72 | 73 | ![width:1000px](https://miro.medium.com/v2/resize:fit:678/1*5F4TXdFYwqi-BWTToQPIfg.jpeg) 74 | 75 | --- 76 | 77 | # Consider the following phrases: 78 | - My dog ate my homework 79 | 80 | - My homework ate my dog 81 | 82 | --- 83 | 84 | ### Bag of words vs. context-sensitive models 85 | 86 | - BoW models (e.g., LSA, LDA, word2vec) don't care about word order 87 | - C-S models "care" about *context* and *grammar* by picking up on word order effects 88 | 89 | --- 90 | 91 | # Universal Sentence Encoder 92 | 93 | ![width:1000px](https://learnopencv.com/wp-content/uploads/2018/11/Universal-Sentence-Encoder.png) 94 | 95 | --- 96 | 97 | # Transformers 98 | 99 | ![width:850px](https://miro.medium.com/v2/resize:fit:1400/1*iy12bH-FiUNOy9-0bULgSg.png) 100 | 101 | --- 102 | 103 | # Transfomers 104 | 105 | 1. Tokenize text into smaller units (words/sub-words) 106 | 2. Embed tokens (ignoring order) 107 | 3. Update the embeddings to include position information (add features) 108 | 4. Update the embneddings using the encoder and decoder layers: 109 | a. The encoder processes the inputs 110 | b. The decoder generates outputs 111 | 112 | --- 113 | 114 | # Transformers 115 | 116 | - Initially used for "sequence-to-sequence" tasks (e.g., translation) 117 | - Now the basis of most state-of-the-art NLP models 118 | 119 | --- 120 | 121 | # Generative Pretrained Transformer (GPT) 122 | 123 | - Variant of transformers 124 | - "Regular" transformers have both an encoder and decoder; GPT only has the decoder part 125 | - The goal is to predict the next token in a sequence, given the previous context 126 | - The model is "pre-trained" on a large corpus of text to learn which tokens are likely to follow which other tokens 127 | - The model can then be "fine-tuned" on specific tasks 128 | - Goal: text completion, translation, summarization, etc. 129 | 130 | --- 131 | 132 | # NLP in practice 133 | 134 | - Natural Language Toolkit (NLTK) implements lots of basic text processing tasks like tokenization, lemmatization, part of speech tagging, etc. 135 | - Scikit-learn has some basic models, like LDA 136 | - For fancier models the best place to look is Hugging Face 137 | 138 | --- 139 | 140 | # NLTK 141 | 142 | Implements lots of fundemantal "traditional" computational linguistics tasks 143 | ```python 144 | import nltk 145 | 146 | sentence = """At eight o'clock on Thursday morning 147 | ... Arthur didn't feel very good.""" 148 | tokens = nltk.word_tokenize(sentence) 149 | 150 | tagged = nltk.pos_tag(tokens) 151 | ``` 152 | 153 | 154 | --- 155 | 156 | ### Hugging Face 157 | 158 | ![width:1000px](https://huggingface.co/front/assets/activity-feed.png) 159 | 160 | --- 161 | 162 | # `transformers` library (by Hugging Face) 163 | 164 | Direct interactions with text and models 165 | 166 | ```python 167 | from transformers import AutoTokenizer, AutoModelForMaskedLM 168 | tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased") 169 | model = AutoModelForMaskedLM.from_pretrained("bert-base-uncased") 170 | ``` 171 | 172 | --- 173 | 174 | # `pydata-wrangler` library 175 | 176 | Wrapper for `scikit-learn` and Hugging Face models, focused on computing text embeddings 177 | 178 | ```python 179 | import datawrangler as dw 180 | 181 | bert = {'model': 'TransformerDocumentEmbeddings', 182 | 'args': ['bert-base-uncased'], 183 | 'kwargs': {}} 184 | bert_embeddings = dw.wrangle(my_text, 185 | text_kwargs={'model': bert}) 186 | ``` 187 | 188 | --- 189 | 190 | # What's next? 191 | 192 | The best way to learn is to *do*: pick a task and have fun with it! -------------------------------------------------------------------------------- /slides/theme.css: -------------------------------------------------------------------------------- 1 | /* @theme cdl-theme */ 2 | 3 | @import 'uncover'; 4 | @import url('https://fonts.googleapis.com/css?family=Roboto+Mono|Varela|Special+Elite&display=swap'); 5 | 6 | code { 7 | display: inline-block; 8 | font-family: 'Roboto Mono', monospace; 9 | font-size: 1em; 10 | letter-spacing: 0; 11 | margin: 0em 0.05em; 12 | padding: 0.2em 0.3em; 13 | vertical-align: baseline; 14 | color: #0d5f2e; 15 | } 16 | 17 | h1 { 18 | font-size: 1.5em; 19 | } 20 | 21 | h2 { 22 | font-size: 1.3em; 23 | } 24 | 25 | h3 { 26 | font-size: 1.1em; 27 | } 28 | 29 | h4 { 30 | font-size: 1em; 31 | } 32 | 33 | h5 { 34 | font-size: 0.9em; 35 | } 36 | 37 | h6 { 38 | font-size: 0.8em; 39 | } 40 | 41 | p, 42 | blockquote { 43 | margin: 1em 3.5em 0; 44 | } 45 | 46 | pre { 47 | display: block; 48 | margin: 1em 2em 0; 49 | overflow: visible; 50 | } 51 | 52 | blockquote { 53 | margin: 1em 0 0; 54 | padding: 0 1.5em; 55 | position: relative; 56 | font-family: 'Special Elite'; 57 | } 58 | 59 | mark { 60 | background: transparent; 61 | } 62 | 63 | table { 64 | border-spacing: 0; 65 | border-collapse: collapse; 66 | margin: 1em 0 0; 67 | font-size: 0.8em; 68 | } 69 | 70 | a { 71 | color: #000000; 72 | text-decoration: underline; 73 | } 74 | 75 | figure { 76 | height: 100px; 77 | max-width: 130px; 78 | padding-bottom: 10px; 79 | } 80 | 81 | figcaption { 82 | position: relative; 83 | font-size: 9pt; 84 | left: -5px; 85 | top: -60px; 86 | overflow: visible; 87 | overflow-wrap: break-word; 88 | width: 90px; 89 | font-weight: bold; 90 | } 91 | 92 | section { 93 | background-color: #dfdfdf; 94 | color: #000000; 95 | font-size: 35px; 96 | font-family: 'Varela'; 97 | height: 720px; 98 | line-height: 1.35; 99 | letter-spacing: 1.25px; 100 | padding: 70px; 101 | width: 1280px; 102 | word-wrap: break-word; 103 | } 104 | 105 | .note { 106 | position: relative; 107 | top: -35px; 108 | font-size: 20pt; 109 | } 110 | 111 | .people_gallery { 112 | display: grid; 113 | grid-template-columns: repeat(11, 2.5em); 114 | grid-template-rows: repeat(4, 100px); 115 | position: relative; 116 | grid-gap: 5px; 117 | left: 0.75em; 118 | top: -40px; 119 | } 120 | 121 | .funding_gallery { 122 | display: grid; 123 | grid-template-columns: repeat(8, 2.5em); 124 | grid-template-rows: repeat(1, 100px); 125 | position: relative; 126 | grid-gap: 5px; 127 | left: 2.5em; 128 | top: -30px; 129 | } 130 | 131 | .funding_caption { 132 | position: relative; 133 | left: -8px !important; 134 | } 135 | 136 | .gallery_img { 137 | max-height: 75px; 138 | max-width: 75px; 139 | } 140 | 141 | .reference { 142 | font-size: 12pt; 143 | text-align: right; 144 | position: fixed; 145 | bottom: 0.5em; 146 | right: 0.25em; 147 | display: block; 148 | line-height: 12pt; 149 | } --------------------------------------------------------------------------------