LSE ME204 · Data Engineering Principles for the Social Sciences
🖥️ Week 01 Day 02 Lecture
10:00 – 10:35
In the first lab yesterday, we had you move through a tree of folders representing different London zones. You did that on the Linux computer you have on Nuvolos, running a Linux Operating System (OS), rather than Windows or Mac. This morning we will cover how that tree works, then open the files inside it.
A computer has four layers:
Examples of Operating Systems (older versions of popular logos):
Ubuntu is a Linux distribution. Windows and macOS are proprietary operating systems.
Each operating system has its own history and philosophy:
UNIX and Linux
Philosophy: open, portable, simple
Windows
Philosophy: user-friendly, commercial
💡 Why this matters for you: different OSes organise files differently and use different terminal commands. When a tutorial uses syntax that only works on one operating system, you will know why.
The directory structure starts from a single root directory called /:
💡 macOS uses /Users/ instead of /home/, but the tree structure is the same. On the Linux computer you have on Nuvolos, your starting point is /files/.
Windows uses drive letters (C:, D:) where each drive is a separate filesystem:
⚠️ Windows uses \ (backslash) for paths. Mac, Linux, and the Linux environment on Nuvolos use / (forward slash).
We can refer to a file in two ways:
Absolute path:
/home/<user>/Documents/data/weather.csv/Users/<user>/Documents/data/weather.csvC:\Users\<user>\Documents\data\weather.csvRelative path:
./data/weather.csv ../data/weather.csv 💡 Tips
pwd in the terminal to check where you are.mkdir: Creating Structure Before You Need ItBefore you start working, set up the folders you will need:
💡 This afternoon you will create scripts/ and write your first Python file inside it. On 💻 Week 01 Day 03 Lab you will run mkdir data/weather before saving API data.
You can practise mkdir, nano, and Markdown by keeping your own study notes. Pick a layout that works for you:
Option A: by day
Option B: flat by session
Option C: by topic
What a note might look like:
# Filesystem
## Key ideas
Files live in a **tree**.
Every absolute path starts from the root (`/` on Linux, `C:\` on Windows).
## Commands I learned
- `pwd` shows where I am
- `ls` lists what is here
- `cd folder/` moves into a folder
- `mkdir name` creates a new folder
## Things I found confusing
Relative paths fail when I am in the wrong folder.💡 This afternoon, start with mkdir study-notes on the Linux computer on Nuvolos and write your first note in nano.
10:35 – 11:00
You now know how files are organised in a tree. Some files store text you can read; others store data only the right software can decode. In this hour we look inside both.
The same file can look completely different depending on the tool you use to open it:
cat shows the raw text:
You see the # symbols, the ** markers, and the [link](url) syntax.
glow renders it:
Now the headings are large, bold text is bold, and links are clickable. The Markdown characters disappear into formatting.
(I particularly prefer to use glow -p <..path..> to be able to paginate through the document)
💡 The file did not change. Only the tool changed. cat shows what is stored. glow interprets the Markdown and renders it.
We use Markdown on these slides, on the course webpages on Moodle, and later in 📚 Jupyter Notebooks (we will learn about them in 🖥️ Week 01 Day 03 Lecture).
| If you type this: | You get this: |
|---|---|
This is a **bold** text. |
This is a bold text. |
This is an _italic_ text. |
This is an italic text. |
[This is a link](https://lse.ac.uk/dsi) |
This is a link |
`print("Hello, World!")`
|
print(“Hello, World!”)
|
```python
# This is a code block
print("Hello, World!")
```
|
|
The code blocks are just to represent code, not to execute it.
There are also headings in Markdown. They help structure content, not just make text big!
| If you type this: | You get this: |
|---|---|
# Title (H1) |
Title (H1) |
## Section (H2) |
Section (H2) |
### Sub-section (H3) |
Sub-section (H3) |
#### Sub-sub-section (H4) |
Sub-sub-section (H4) |
⚠️ Do not use # just to make text bigger! It’s not what it represents.
Use it to create hierarchical demarcations of sections instead.
A short report. More # means a deeper level. Body text belongs under the heading that owns it.
If you type this:
# London Weather Brief A short look at June temperatures. ## Data ### Source Open-Meteo daily series. ### Coverage 1–30 June 2026. ## Findings Hottest day: 36.0°C.
You get this document:
💡 The # count is the nesting depth. H2 belongs under H1 and H3 belongs under H2. That is how long documents stay scannable.
Let’s open a real data file. This is London’s daily temperature for June 2026:
date,temperature_2m_max,temperature_2m_min,data_type
2026-06-01,24.4,13.7,historical
2026-06-02,19.8,14.4,historical
2026-06-03,19.1,12.6,historical
...
Each line is one day. The commas separate the values. The first line holds the column names.
💡 CSV stands for comma-separated values. It is plain text you can read in any editor. Python can read it too, once you tell it where the commas and line breaks are.
💡 vim is another popular tool for viewing and editing files in the terminal. It has a steeper learning curve than cat or nano. If you want to try it later, work through vimtutor.
The same weather data, stored as JSON instead of CSV:
Raw text (for example with cat):
In fx (collapsible tree):
fx lets you collapse and expand sections, so you can explore the structure without scrolling through raw text.
The keys ("time", "temperature_2m_max") name the columns. The values are arrays (lists) of data.
💡 CSV and JSON are both plain text encoding the same data differently. CSV uses commas and line positions. JSON uses braces, keys, and quotes.
Not every file is plain text. Let’s open an image in vim:
The screen fills with gibberish: ^@^@^@^PIHDR, \x89PNG, fragments of binary data that make no sense as text.
Yesterday you saw this chart in the heatwave analysis. It showed a clear trend. Today you see what that same file looks like to the computer when it reads it as text: meaningless characters.
💡 The PNG file stores pixel colours and positions as raw bytes. Only software that knows the PNG format (an image viewer, a browser, Python’s matplotlib) can decode it into the chart you saw.
Plain-text files:
.py)cat, edit them with nano or vimBinary files:
.png, .jpg), PDFs, databases, executablesAll the plain-text files we use in this course are encoded as UTF-8. We will look at what that means later.
💡 This afternoon you will open a CSV file in the terminal with cat and in Python with open(). You have seen the principle: plain text shows structure, binary does not.
11:00 – 11:30
Allow me to go very low-level here, down to the bits…
Numbers, text, images, and sounds are all stored as sequences of 0s and 1s in your computer’s memory. Each 0 or 1 is called a bit.
Think of a bit as a tiny box:
\[ \require{color} \fcolorbox{black}{white}{$\phantom{0}$} \phantom{\leftarrow \text{a bit can have a value of $0$}} \]
Numbers, text, images, and sounds are all stored as sequences of 0s and 1s in your computer’s memory. Each 0 or 1 is called a bit.
Think of a bit as a tiny box:
\[ \require{color} \begin{array}{ccc} \fcolorbox{black}{#eeeeee}{0} & \leftarrow & \text{a bit can have a value of $0$} \end{array} \]
Numbers, text, images, and sounds are all stored as sequences of 0s and 1s in your computer’s memory. Each 0 or 1 is called a bit.
Think of a bit as a tiny box:
\[ \begin{array}{ccc} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \leftarrow & \text{OR it can have a value of $1$} \end{array} \]
but nothing else!
With more bits, we can represent more numbers. Here’s how 4 bits can represent 16 different numbers:
\[\begin{array}{ccccccccccccccc} \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#eeeeee}{0} & \rightarrow 0 & & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#eeeeee}{0} & \rightarrow 8 \\ \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \rightarrow 1 & & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \rightarrow 9 \\ \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#eeeeee}{0} & \rightarrow 2 & & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#eeeeee}{0} & \rightarrow 10 \\ \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \rightarrow 3 & & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \rightarrow 11 \\ \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#eeeeee}{0} & \rightarrow 4 & & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#eeeeee}{0} & \rightarrow 12 \\ \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \rightarrow 5 & & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \rightarrow 13 \\ \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#eeeeee}{0} & \rightarrow 6 & & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#eeeeee}{0} & \rightarrow 14 \\ \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \rightarrow 7 & & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \rightarrow 15 \\ \end{array}\]Each position has a different weight. The leftmost bit is worth the most, the rightmost the least:
\[ \begin{array}{cccccc} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \\ \downarrow & \downarrow & \downarrow & \downarrow \\ \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \times 2^3 & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \times 2^2 & \fcolorbox{black}{#eeeeee}{0} \times 2^1 & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \times 2^0 \\ \downarrow & \downarrow & \downarrow & \downarrow \\ 8 & 4 & 0 & 1 \\ \downarrow & \downarrow & \downarrow & \downarrow \\ 8 & +\quad4 & +\quad0 & +\quad1 & = & 13 \end{array} \]
int32Signed integers use an encoding called two’s complement. The leftmost bit indicates whether the number is negative, but it is part of the complete encoding rather than a separate sign attached to a value.
An int32 uses 32 bits and represents numbers from \(-2{,}147{,}483{,}648\) to \(+2{,}147{,}483{,}647\).
💡 For now, remember the name two’s complement and that the leftmost bit indicates negativity. You do not need to calculate negative binary numbers by hand.
Whole numbers fit neatly into bits, but numbers like 27.3 or 0.1 need more structure. A Python float splits its 64 bits into three parts:
\[ \underbrace{\fcolorbox{#e4002b}{#fce4e4}{$\phantom{0}$}}_{\substack{\textcolor{#e4002b}{1 \text{ bit}} \\ \textcolor{#e4002b}{sign} \\ \textcolor{#e4002b}{+ \text{ or } -}}} \;\bigg|\; \underbrace{\fcolorbox{#3995ba}{#cee8f6}{$\phantom{0}$} \; \fcolorbox{#3995ba}{#cee8f6}{$\phantom{0}$} \; \fcolorbox{#3995ba}{#cee8f6}{$\phantom{0}$} \; \fcolorbox{#3995ba}{#cee8f6}{$\phantom{0}$} \; \fcolorbox{#3995ba}{#cee8f6}{$\phantom{0}$} \; \fcolorbox{#3995ba}{#cee8f6}{$\phantom{0}$} \; \fcolorbox{#3995ba}{#cee8f6}{$\phantom{0}$} \; \fcolorbox{#3995ba}{#cee8f6}{$\phantom{0}$} \; \fcolorbox{#3995ba}{#cee8f6}{$\phantom{0}$} \; \fcolorbox{#3995ba}{#cee8f6}{$\phantom{0}$} \; \fcolorbox{#3995ba}{#cee8f6}{$\phantom{0}$}}_{\substack{\textcolor{#3995ba}{11 \text{ bits}} \\ \textcolor{#3995ba}{exponent} \\ \textcolor{#3995ba}{\text{how big}}}} \;\bigg|\; \underbrace{\fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\cdots$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$} \; \fcolorbox{#47315E}{#e8dff0}{$\phantom{0}$}}_{\substack{\textcolor{#47315E}{52 \text{ bits}} \\ \textcolor{#47315E}{mantissa} \\ \textcolor{#47315E}{\text{the digits}}}} \]
The sign, exponent, and mantissa work like scientific notation: \(-3.14 \times 10^{2}\) has a sign (\(-\)), digits (\(3.14\)), and a power that shifts the decimal point (\(10^{2}\)).
Python’s usual 64 bit float stores 52 fraction bits and provides about 15-16 significant decimal digits. Values between the available binary representations are rounded to the nearest one.
After the decimal point, bit positions are worth \(\frac{1}{2}\), \(\frac{1}{4}\), \(\frac{1}{8}\), and so on.
Before it, they work the same as integers (\(2^0\), \(2^1\), \(2^2\), …):
\[ \begin{array}{ccccccccccccc} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & . & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#eeeeee}{0} & \fcolorbox{black}{#eeeeee}{0} \\ \downarrow & \downarrow & \downarrow & & \downarrow & \downarrow & \downarrow & \downarrow & \downarrow & \downarrow & \downarrow & \downarrow \\ 2^2 & 2^1 & 2^0 & & \tfrac{1}{2} & \tfrac{1}{4} & \tfrac{1}{8} & \tfrac{1}{16} & \tfrac{1}{32} & \tfrac{1}{64} & \tfrac{1}{128} & \tfrac{1}{256} \\ \downarrow & & \downarrow & & \downarrow & \downarrow & & & & & & \\ 4 & + & 1 & + & 0.5 & + \; 0.25 & & & & & & & = \;\; 5.75 \end{array} \]
Four bits are ON, and \(4 + 1 + 0.5 + 0.25\) gives exactly \(5.75\). No leftover, no rounding.
\(0.5\) fits in one bit (\(\frac{1}{2}\), done). But \(0.1\) and \(0.2\) look clean in decimal and turn into repeating patterns in binary, the same way \(\frac{1}{3}\) looks clean as a fraction but repeats forever in decimal (\(0.333\ldots\)):
\[ 0.5 \;=\; 0.\;\fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \quad \text{(exact)} \]
\(0.1\) and \(0.2\) in binary:
\[ \begin{array}{rcl} 0.1 & = & 0.\;\underbrace{\fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$}}_{\text{start}}\;\underbrace{\fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$}}_{\text{repeats}} \;\cdots \\[1.5em] 0.2 & = & 0.\;\underbrace{\fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$}\;\fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$}}_{\text{repeats}} \;\cdots \end{array} \]
The stored fraction has finite space, so Python rounds the input to the nearest representable binary value.
Try this in ipython:
That is not a bug. Python rounds both \(0.1\) and \(0.2\) to the nearest representable binary floating-point values before adding them.
🤯 This happens in every programming language, not just Python. Click here to see examples in 50+ languages.
Each fractional bit is worth \(\frac{1}{2}\), \(\frac{1}{4}\), \(\frac{1}{8}\), \(\frac{1}{16}\), \(\frac{1}{32}\), \(\frac{1}{64}\), \(\frac{1}{128}\), \(\frac{1}{256}\), and so on. If we keep only 8 bits:
\[ \begin{array}{rcl} 0.1 & \approx & 0.\;\fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \;=\; \tfrac{1}{16} + \tfrac{1}{32} + \tfrac{1}{256} \;=\; 0.098 \\[0.8em] 0.2 & \approx & 0.\;\fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \;=\; \tfrac{1}{8} + \tfrac{1}{16} + \tfrac{1}{128} + \tfrac{1}{256} \;=\; 0.199 \end{array} \]
Neither value in this eight bit illustration is exact. Python uses far more precision and rounds to the nearest representable value, so its errors are much smaller.
Now add those stored values, column by column, right to left:
\[ \begin{array}{rrl} & 0.\;& \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$}\;\cdots \\ + & 0.\;& \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$}\;\cdots \\[0.3em] \hline \\[-0.7em] & 0.\;& \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0}\;\fcolorbox{#e4002b}{#fff3cd}{$\textcolor{#e4002b}{?}$} \fcolorbox{#e4002b}{#fff3cd}{$\textcolor{#e4002b}{?}$} \fcolorbox{#e4002b}{#fff3cd}{$\textcolor{#e4002b}{?}$} \fcolorbox{#e4002b}{#fff3cd}{$\textcolor{#e4002b}{?}$}\;\cdots \end{array} \]
The \(\cdots\) show that both binary patterns continue. Python rounds each operand to the nearest representable value, adds them, and rounds the result again. That is why Python prints 0.30000000000000004 rather than exactly 0.3.
Be mindful of the precision you want your numbers to be in!
In the early days of computing, text was represented using the ASCII table. ASCII assigns a code of 7 bits to each character, normally stored inside a byte of 8 bits. Here are some examples:
The letter ‘A’ is represented by the number 65 encoded in binary as:
\[ \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \]
The letter ‘a’ (lowercase) is represented by the number 97 encoded in binary as:
\[ \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \]
The linebreak character ‘\n’ is represented by the number 10 encoded in binary as:
\[ \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#eeeeee}{0} \fcolorbox{black}{#111111}{$\textcolor{white}{1}$} \fcolorbox{black}{#eeeeee}{0} \]
Click here to see the full table. Most modern software uses a different encoding: UTF-8, which includes emojis! 🤗
11:30 – 11:45
After the break:
11:45 – 12:45
You have seen plain text in the terminal. Next we use Python in that same terminal to read those files. No code editors and no notebooks yet: everything here is typed or run from the command line.
You can write Python in a file and run it, or type it line by line in ipython:
Write a script, then run it:
In the terminal: open the editor
Close then back in the terminal: run the file
Output:
Hello from Python
💡 This afternoon you will write your own script in nano and run it with python. You will see the difference between ipython and a script for yourself.
A variable is a name that holds a value. You create one with = (typed in ipython or saved in a .py file):
When you create a variable in Python, you bind a name to an object in memory. The variable refers to that object rather than acting as a container that holds the value itself.
When assignment runs:
25.3temperature is bound to that objectWhen you reassign:
Python does not change the old floating-point object. The assignment binds temperature to another object representing 28.7.
Memory Addresses (simplified):
🔍 You can try it yourself: In CPython, id() normally shows an object’s current memory address. Other Python implementations only guarantee an identity that remains unique during that object’s lifetime.
Four primitive types you will use constantly. Keep this as a reference:
When you read a number from a file, Python gives you text (str), not a number. You convert it yourself:
💡 This will matter this afternoon when you read numbers from a CSV. The values come out as strings, and adding two strings joins them end to end instead of adding numbers.
💡 Although you can’t change the size of the data types in ‘pure Python’, we will enforce this when we start working with numpy and pandas in the next few weeks.
Integer Storage:
int32: Uses 32 bits (4 bytes)
Can store: -2,147,483,648 to 2,147,483,647
int64: Uses 64 bits (8 bytes)
Can store: much larger numbers!
Why this matters:
A DataFrame with 1 million integers:
int32: ~4 MB of memoryint64: ~8 MB of memoryChoosing the right type saves memory!
Float Precision:
Python floats use 64 bits by default.
This is why sometimes:
Oddly, the binary representation of numbers in programming isn’t always exact.
🤯 Click here to read more about this.
A list holds many values in order. You build one with square brackets:
Typed in ipython:
You pick a value by its position (counting from zero):
You can add a value to the end:
💡 When you split a CSV row on commas, you get a list. Each position in the list is one column value.
A dictionary maps names to values, like a lookup table:
Typed in ipython:
You look up a value by its key:
Output:
27.3
💡 A JSON object becomes a Python dictionary. The keys ("city", "temperature") are the column names you saw in the JSON file earlier.
Lists and dictionaries store references to objects rather than placing each object’s full contents inside the collection.
Why this matters:
Collections are containers of references, not containers of actual values.
Why bother? Understanding this memory model helps you understand why some operations are fast (just changing a reference) and others are slow (copying actual data), and why some data structures work better for certain tasks.
for LoopsA loop repeats the same step for each item in a collection:
Typed in ipython:
Output:
25.1
27.3
22.8
19.5
24.0
The indented line runs once for each value in the list. t takes a new value each time.
for Loops: Sum and AverageLoops are not only for printing. You can accumulate a total, then compute a summary:
Typed in ipython:
Output:
119.7
Output:
23.94
💡 A loop can build a number (or a list) as it goes. Printing is only one use.
Python reads a file as one long string. First open a connection, read the text, then close it:
Typed in ipython:
Output (print() writes the line breaks as actual new lines):
date,temperature_2m_max,temperature_2m_min,data_type
2026-06-01,24.4,13.7,historical
...
Once you have the whole file as text, split it on line breaks:
Typed in ipython:
Output:
2026-06-01,24.4,13.7,historical
rows[0] is the header. rows[1] is the first day of data.
Split that row on commas to get one value per column:
Typed in ipython:
Output:
'2026-06-01'
'24.4'
Every piece from .split() is a string, even when it looks like a number:
Typed in ipython:
💡 fields[1] is '24.4' (text), not 24.4 (a number). Use float(fields[1]) or int(...) before you do arithmetic.
You just read a CSV file by hand: open, read, split on line breaks, split on commas, convert types. It works, but it is a lot of steps.
Python has tools that automate this:
| Tool | What it does | When you will see it |
|---|---|---|
json.load |
Reads a JSON file into Python dicts and lists | 💻 Week 01 Day 03 Lab |
pandas |
Loads data into tables you can filter, group, and plot | 🖥️ Week 01 Day 04 Lecture |
Today we did it by hand so you understand what those tools are doing for you.
12:45
This afternoon you will put all of this into practice in the lab: reading files in the terminal and in Python.
💬 Questions?
These slides use Quarto HTML presentations. For more on Markdown, see the Markdown Guide.
LSE Summer School 2026 | ME204 Week 01 Day 02
LSE ME204 (2026)