(6.5 + 7 + 5.5) / 36.333333333333333
Every data analysis is a long chain of decisions. Which cases are kept and which are excluded, how a messy answer is corrected, which variables are combined into a score, which test is used, and how its result is rounded: each choice shapes the final numbers, and each should be open to inspection. When an analysis is done by clicking through menus, most of these decisions leave no trace. Weeks later, not even the researcher can say exactly how a number in the thesis was produced, and an examiner who asks cannot be given a complete answer.
Writing the analysis as code changes this. A script records every step in order, in a form that a supervisor can read, an examiner can check, and the researcher can run again after correcting a mistake or receiving new data. This is the main reason research is increasingly done in a programming language, and it is the reason this book teaches Python. The chapter starts from nothing: installing Python, finding your way around the program used to write it, and learning the handful of ideas on which everything else rests.
The book follows one research project from its first day to its last. Elaf has just begun a Master’s degree in Educational Psychology. During her first year of graduate study she noticed how tired many of her fellow students were: they slept little, lived on coffee, worried about their supervisors and their money, and a few spoke quietly about leaving. With her supervisor, she turned that observation into a thesis. It asks how sleep, stress, and supervisor support relate to graduate students’ wellbeing, their grades, and their thoughts of dropping out, and whether a short wellbeing workshop can help. Her university agreed to support a two-year study of 600 graduate students from five faculties: a questionnaire at the start, a record of each student’s sleep, study, and wellbeing at the end of every semester, and a six-week workshop to which half of the students would be invited at random.
At their first meeting, her supervisor set out what the thesis would demand. The research questions had to become precise hypotheses before any results were seen. The raw survey export, full of test entries, typing errors, and impossible values, had to be cleaned without losing track of a single change. The sample had to be described honestly, including the students who stopped taking part. Every analysis had to be chosen for a reason and its assumptions checked, and every result reported with its size and its uncertainty, not only with a p-value. At the end, examiners would read the results chapter and could ask how any number in it had been produced. “You should be able to show them,” the supervisor said, “step by step.”
Elaf had used Excel for coursework and had once clicked through an SPSS menu in a statistics class, but she had never written a line of code. Her supervisor suggested Python, for exactly the reason given above: an analysis written as code can be shown step by step. The first data has now arrived, and this chapter is Elaf’s first day with Python, and yours. Each later chapter takes her one step further, from cleaning the data to the finished thesis. By the end of this one, you will have Python running on your computer, you will know your way around the program used to write it, and you will have opened her data and answered a first, simple question about it.
pip.data2thesis.Teaching & Practice: Interactive Lecture Slides · Browser Playground Exercises
Python is a free, open-source programming language for working with data: cleaning it, analysing it, and turning it into tables, graphs, and statistical models. It was created in the late 1980s by Guido van Rossum in the Netherlands, released in 1991, and named after the British comedy troupe Monty Python. Today, Python is the most popular programming language in the world, powering scientific research in universities, national laboratories, hospitals, tech companies, and governments across every continent.
Four properties make Python worth learning for a researcher:
The price of code is that Python asks you to type rather than click. At first, typing feels unfamiliar. Within a few days, however, it becomes second nature—and it pays you back every time you need to re-run an analysis, update a dataset, or generate new figures for your thesis defense.
In SPSS or Excel, you click menus, and the program changes your spreadsheet or displays a table in a viewer. The problem is that the clicks leave no written record. In Python, you write an explicit instruction: students['age'].mean(). The computer executes it and prints the result. Because the instruction is saved in a text file, you can re-run the entire analysis next semester with one keystroke. Chapter 2 shows how familiar Excel and SPSS operations map directly to Python.
Working with Python involves two tools:
You will almost never open Python by itself; you open your editor, and the editor talks to Python for you.
The most popular, modern editor for scientific Python is Visual Studio Code (VS Code), developed by Microsoft. It is free, fast, and available for Windows, macOS, and Linux.
Appendix A walks through this setup step by step for Windows, macOS, and Linux, with troubleshooting for common path issues.
While VS Code is the industry standard, other editors are also excellent. Positron, developed by Posit (the creators of RStudio), is designed specifically for data scientists and provides a dedicated environment for both Python and R in a familiar layout. JupyterLab is another popular browser-based environment for running code notebooks. Everything you learn in this book works identically in VS Code, Positron, and Jupyter.
The practical exercises for this book can also be run directly in your web browser with zero local installation. Try them in the Chapter 1 Playground first!
When you open VS Code with a Python file, the window is organized into functional areas, described in Table 1.1.
| Where | Pane | What it is for |
|---|---|---|
| Left / Top | Editor (Source) | Where you write and save your code scripts (.py files). |
| Bottom / Right | Terminal / Interactive Window | Where Python executes instructions and shows text outputs. |
| Left sidebar | File Explorer | The folders and files in your research project. |
| Bottom / Panel | Plots & Variables | Where data tables, variables in memory, and visual plots appear. |
You can type code directly into the Python Interactive Terminal (or REPL). When you type 2 + 2 and press Enter, Python evaluates the expression and prints 4.
The simplest use of Python is as a calculator. Suppose you slept 6.5, 7, and 5.5 hours on three consecutive nights last week. Your average sleep is:
Python follows standard mathematical order of operations (PEMDAS): parentheses first, followed by exponents, multiplication and division, and finally addition and subtraction. Without the parentheses, Python would divide only the last number by 3:
The standard arithmetic operators in Python are: * + for addition * - for subtraction * * for multiplication * / for division * ** for exponents/powers (for example, 2 ** 3 evaluates to 8; note that in Python, ^ is a bitwise operator, not power!)
Typing numbers repeatedly is slow and error-prone. Instead, you can store a value under a memorable name. In Python, this stored value is held in a variable, created using the assignment operator =:
When you run this line, Python produces no visible output, but it now remembers that nights holds the value 3. You can now use nights anywhere you would use the number:
To store several values together, you can place them in a list, written inside square brackets [ and ], separated by commas:
Notice how much clearer and self-documenting your analysis becomes when the numbers have meaningful names:
Variable names in Python follow clear conventions: * Names start with a letter or underscore, and may contain letters, numbers, and underscores (e.g., sleep_hours, student_01). * Names cannot contain spaces. Use an underscore _ to separate words (this is called snake_case, the standard Python style). * Python is strictly case-sensitive: Sleep, sleep, and SLEEP are three completely different variables. * Choose descriptive names: sleep_hours tells you immediately what the data represents; single letters like x or temp will leave you guessing when you review your code months later.
If you assign a new value to an existing variable name, Python overwrites the old value:
Research data is not only numbers. A study records measurements (hours of sleep), text categories (a student’s faculty), and yes-or-no status flags (whether a student attended a workshop). Python keeps track of the data type of every value, because the type determines what mathematical and logical operations are permitted.
Table 1.2 lists the core types you will encounter in research.
| Type | Name in Python | Description | Example |
|---|---|---|---|
| Integer | int |
Whole numbers without decimals | 600, 4 |
| Floating-point | float |
Numbers with decimal points | 6.5, 3.14159 |
| String | str |
Text characters, enclosed in quotes | "Education", 'Male' |
| Boolean | bool |
Logical truth values | True, False |
The built-in function type() inspects the type of any object:
<class 'float'>
<class 'str'>
<class 'bool'>
Text must always be enclosed in quotes (single '...' or double "..."). If you omit the quotes, Python assumes you are referring to a variable name:
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[12], line 1 ----> 1 faculty = Education NameError: name 'Education' is not defined
This error—NameError: name 'Education' is not defined—is one of the most frequent beginner mistakes. The error message is helpful and specific: Python searched your computer’s memory for a variable named Education and found none.
Real empirical data almost always contains missing answers. A participant might decline to answer their income, or an instrument might briefly lose power.
In pure Python, the absence of a value is represented by the special object None. When working with tabular data and numerical calculations in pandas and scientific libraries, missing numerical values are represented as NaN (short for Not a Number, floating-point missing value).
In Python and pandas, mathematical calculations on missing values are handled safely:
In pandas, functions like .mean() and .sum() are designed specifically for research data and automatically handle missing values cleanly, as you will see shortly.
You have already used several built-in functions: sum(), len(), type(), and print(). A function takes one or more inputs, performs a procedure, and returns a result. You call a function by writing its name followed by parentheses (), enclosing the inputs inside:
Inputs passed to a function are called arguments. If a function accepts multiple arguments, they are separated by commas. For example, round() takes the number you want to round, and the number of decimal digits:
You can also pass arguments by their name (called keyword arguments):
In Python, objects also have methods. A method is a function that belongs directly to an object, called with a dot .. For example, strings have methods to change their casing:
Every Python function and library includes built-in documentation. In an interactive console or notebook, you can read the help docstring for any function by calling help():
In Jupyter or VS Code Interactive, you can also place a question mark ? after any function name (e.g., round?) to pop open its documentation pane, including its expected parameters and usage examples.
Commands typed in an interactive prompt are temporary. For real research work that needs to be defended, documented, and published, you write your code in a script: a plain text file ending in .py.
analysis.py.#. Python completely ignores everything after # on that line; comments are written for human readers (your future self, your supervisor, and your peer reviewers) to explain why a particular decision was made:Average sleep: 6.3 hours
python analysis.py.A thesis involves dozens of files: survey exports, cleaned datasets, analysis scripts, generated plots, and chapter drafts.
The gold standard for scientific computing is to create a dedicated project directory on your computer (for example, graduate-wellbeing-thesis/). Keep all code and data self-contained within this folder:
graduate-wellbeing-thesis/
├── data/ <- Raw survey data (read-only)
├── scripts/ <- Your Python analysis scripts (.py)
├── figures/ <- Exported charts and graphs
└── thesis_chapter.qmd <- Your written manuscript
By organizing your work with relative paths (e.g. data/students.csv), your analysis is fully portable: if you zip the folder and email it to your supervisor, or push it to GitHub, the code runs on their computer without any file path errors.
Python includes a rich standard library, but its true power comes from third-party packages (also called libraries). Using a package is a two-step process:
Install the package once onto your computer using Python’s package manager, pip, in your system terminal:
Import the package in each script where you wish to use it:
A helpful analogy is a workshop: running pip install purchases a specialized power tool and places it in your workshop cabinet. You only need to buy it once. Writing import takes the tool off the shelf and places it on your workbench for today’s session.
With Python and the companion package installed, we can load the Graduate Wellbeing Study:
Elaf, her study, and her data are simulated for teaching. The data was generated by a computer algorithm to look like an authentic survey of graduate students, ensuring every statistical and machine learning method in this book has realistic patterns to discover. It describes no real individuals, and its patterns (for example, that students who sleep more tend to achieve higher GPAs, or that the wellbeing workshop reduced stress) were built in by the author. Nothing in this book should be cited as empirical evidence about the wellbeing of real graduate students.
The students object is a pandas DataFrame: a two-dimensional table of rows and columns, similar to an Excel sheet or SPSS dataset, but optimized for fast computation.
To see the dimensions of the table, check its .shape attribute:
The output (600, 14) tells us immediately that Elaf’s study contains 600 students (rows) and 14 variables (columns).
To inspect the first five rows of the dataset, call the .head() method:
| student_id | supervisor_id | age | gender | faculty | programme | study_mode | employment | has_children | lives_away | financial_worry | workshop | workshop_sessions | considering_dropout | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | S0001 | SUP088 | 31.0 | Female | Health Sciences | Master's | Full-time | None | No | Yes | 2.0 | Not invited | 0 | No |
| 1 | S0002 | SUP116 | 28.0 | Female | Education | PhD | Full-time | Part-time job | No | Yes | 2.0 | Invited | 0 | No |
| 2 | S0003 | SUP040 | 33.0 | Male | Education | PhD | Full-time | None | No | No | 4.0 | Invited | 5 | No |
| 3 | S0004 | SUP112 | 34.0 | Female | Health Sciences | Master's | Part-time | Full-time job | No | No | 2.0 | Invited | 6 | No |
| 4 | S0005 | SUP118 | 35.0 | Female | Social Sciences | Master's | Part-time | None | No | No | 2.0 | Invited | 2 | No |
To see the names of all 14 variables:
['student_id',
'supervisor_id',
'age',
'gender',
'faculty',
'programme',
'study_mode',
'employment',
'has_children',
'lives_away',
'financial_worry',
'workshop',
'workshop_sessions',
'considering_dropout']
Each column is described in the study codebook (dt.load_students?).
To select a single variable from the DataFrame, write the DataFrame name followed by the column name in brackets and quotes: students['age'].
A natural first question in Elaf’s thesis: What is the average age of graduate students entering the study?
In pandas, we call the .mean() method directly on the column:
Notice something important: in pandas, .mean() is designed from the ground up for real-world empirical research: it calculates the average across all known observations while safely ignoring missing values by default (skipna=True).
The average age of the students in the study is 29.7 years.
We can also check whether any student had a missing age using .isna().sum():
Only 1 student’s age was missing from the initial intake survey. Chapter 3 shows how to identify why it was missing and how to clean it.
Next, we can generate frequency tables for categorical variables using the .value_counts() method. For example, how many students participated from each academic faculty?
faculty
Health Sciences 154
Education 148
Social Sciences 116
Humanities 95
Natural Sciences 87
Name: count, dtype: int64
And how many were invited to the wellbeing workshop?
Exactly 300 students—precisely 50% of the sample—were invited to the workshop. That is not an accident: the workshop invitations were assigned using random allocation. Chapter 5 explores why random assignment is the cornerstone of causal inference in empirical research.
Python’s visualization library, seaborn, comes with real-world practice datasets from different fields. For instance, the penguins dataset records morphological measurements of wild penguin colonies in Antarctica:
(344, 7)
| species | island | bill_length_mm | bill_depth_mm | flipper_length_mm | body_mass_g | sex | |
|---|---|---|---|---|---|---|---|
| 0 | Adelie | Torgersen | 39.1 | 18.7 | 181.0 | 3750.0 | Male |
| 1 | Adelie | Torgersen | 39.5 | 17.4 | 186.0 | 3800.0 | Female |
| 2 | Adelie | Torgersen | 40.3 | 18.0 | 195.0 | 3250.0 | Female |
We can inspect species frequencies and calculate the average body mass across the colony using the exact same pandas methods:
.py) contain instructions, and the interactive terminal displays output.=. Lists [...] hold multiple values. Standard math symbols follow PEMDAS, with ** used for exponents.int (integers), float (decimals), str (text strings in quotes), and bool (True or False). Check types using type().function(argument). Object methods are called with a dot: object.method().pip install <package>, and loaded into each script session using import <package>.data2thesis provides pandas DataFrames. Inspect table size with .shape, view preview rows with .head(), compute summary statistics with .mean(), count missing values with .isna().sum(), and count categories with .value_counts().Python, VS Code, script (.py), comment (#), variable, assignment (=), list, data type (int, float, str, bool), missing value (None, NaN), function, argument, method, package, pip, import, pandas DataFrame, .shape, .head(), .isna(), .value_counts(), reproducible research.
Work through these short exercises to test your understanding. The Chapter 1 Playground provides interactive browser versions of these exercises with hints and complete solutions.
supervisor_sleep, calculate the mean sleep duration, and round the result to one decimal place."600" and 600 using Python’s type() function. Explain why adding 1 to one succeeds while adding 1 to the other raises a TypeError.None and pandas/numpy’s NaN. How does pandas .mean() handle missing values by default?students = dt.load_students(), find the age of the youngest student and the oldest student in the study using .min() and .max()..value_counts(), find how many students are enrolled full-time versus part-time (the variable is study_mode).