ββββββββββ
β n_rows β
β int64 β
ββββββββββ€
β 59024 β
ββββββββββ
Lecture 26 - Revision: Scaling, SQL and Containers
Source: The Turing Way Community (2025)
1. Scaling and performance
2. SQL revision
WHERE and HAVING, COUNT, joins3. SQL practice
4. Containers
5. Quiz 05 preparation
map, joblib and concurrent.futures| Your task | Tool |
|---|---|
| Number crunching | ProcessPoolExecutor |
| Downloading many URLs | ThreadPoolExecutor |
| sklearn, numeric loops | joblib (n_jobs=-1) |
| Bigger than RAM | Dask |
concurrent.futures ships with Python, so it works where you cannot install anythingnn costs nothing, twice as much, or four times as muchp cores turn O(n) into O(n/p + overhead). The class stays the samecalculation for a download, and the threads windelayed).compute(). Until then, Dask builds a task graph.persist() keeps a small result in memorylocalhost:8787 shows the tasks livevalue by indicator and decade, on 200,681,600 rows, Apple M5 laptop:| pandas | Dask | DuckDB |
|---|---|---|
| 9.65 s | 5.39 s | 0.53 s |
| Your situation | Reach for |
|---|---|
| Fits in RAM, exploring, plotting | pandas |
| One large file on one machine | DuckDB |
| Bigger than the machine, or a cluster | Dask |
WHERE and HAVING differSELECT first, but the engine runs it fifthWHERE filters rows before grouping. HAVING filters groups afterWHERE: the groups do not exist yetSELECT column is in GROUP BY or inside an aggregateSELECT alias in WHERE, but PostgreSQL does notWHERE year >= 2010 drops old rowsHAVING AVG(value) > 60000 drops poorer countriesCOUNT(*) counts rows. COUNT(value) counts rows with a valueAVG, SUM, MIN and MAX skip missing values without warningprimary_enrolment_net in 2020: 217 rows and no numbers, so AVG is NULL../lecture-19/data/wdi_panel.parquetββββββββββ
β n_rows β
β int64 β
ββββββββββ€
β 59024 β
ββββββββββ
country, iso3, indicator, year and valuegdp_per_capita, life_expectancy, co2_per_capita and internet_users_pctWhich countries emitted the most CO2 per person in 2020?
wdi view existsco2_per_capitacountry and value, rounded to one decimalco2_pcWhat to look for:
AND inside one WHEREDESC, because ASC is the defaultSolution and the full output: Appendix 01
Which countries have been the most connected since 2015?
internet_users_pctvalue, and call it n_yearsvalue, rounded to one decimal, as mean_internetWhat to look for:
year and the two filters on the group go in different clausesCOUNT(value) and COUNT(*) disagree here, and only one of them counts years with dataWHERE means the evaluation ladder is worth another lookSolution and the full output: Appendix 02
print "hello" was valid Python 2. In Python 3 it is a SyntaxError| Tool | File you commit | Key commands |
|---|---|---|
venv + pip |
requirements.txt |
pip freeze, pip install -r |
| conda | environment.yml |
conda env export --from-history |
uv |
pyproject.toml, uv.lock |
uv add, uv sync, uv export |
pip freeze inside conda writes @ file:/// paths that break elsewhereuv in more detail: Appendix 05Whichever tool you use, you hand in requirements.txt with == pins, because every Dockerfile reads it
# 1. Base image
FROM ubuntu:24.04
# 2. Build-time settings
ENV DEBIAN_FRONTEND=noninteractive
SHELL ["/bin/bash", "-c"]
# 3. System packages
RUN apt-get update && apt-get install -y [...]
# 4. Quarto
RUN ARCH=$(dpkg --print-architecture) && [...]
# 5. Python environment
RUN python3 -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
COPY requirements.txt /project/requirements.txt
RUN pip install --no-cache-dir -r /project/requirements.txt
# 6. Project files
WORKDIR /project
COPY . /project
# 7. Default command
ENV QUARTO_PYTHON=/opt/venv/bin/python
CMD ["bash", "-c", "quarto render report.qmd && [...]"]FROM pins the base image. latest moves, which breaks reproducibilityDEBIAN_FRONTEND=noninteractive stops apt asking questions.deb. dpkg --print-architecture picks arm64 or amd64/opt/venv, first on the PATHCOPY requirements.txt comes before COPY . /project, so editing the report keeps pip install cached[1/8] to [8/8]-v flagDockerfilerequirements.txt: pip runs again--rm deletes the container when it exits-v host:container links a folder on your laptop to one in the container-v, the report renders, then disappears with the container-p host:container does the same for ports. Your project needs only -v.dockerignore keeps .git, caches and outputs out of the imagedata/raw/, and check with git ls-files data/raw==, to a version that exists on PyPIls output after the container exits, and check the fileβs timestampIOException: No files found-v: the report disappears with the containerData.csv and data.csv as the same file, but Linux does not
.gitattributes file does this for you, so do not delete it~/), not under /mnt/c/
docker build from the shared repositoryREADME.md, under βWorking in a mixed groupβWHERECOUNT does with a NULLvenv, conda and uv to their filespip freeze writes and what == meansDockerfile block and say what it doesCOPY requirements.txt comes before COPY .-vFROM ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y [...]
RUN python3 -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
COPY requirements.txt /project/requirements.txt
RUN pip install --no-cache-dir -r \
/project/requirements.txt
WORKDIR /project
COPY . /project
CMD ["bash", "-c", "quarto render report.qmd"]FROM ubuntu:24.04 pin, and why do we avoid latest?COPY requirements.txt come before COPY . /project?ENV PATH="/opt/venv/bin:$PATH" change?report.qmd, and which if you edit requirements.txt?output/report.html if you run the container without -v?Answers: Appendix 04
joblib, processes for computing, threads for waiting.compute(). A DuckDB result runs when you print it or call .df()FROM, WHERE, GROUP BY, HAVING, then SELECTCOUNT(*) counts rows, and COUNT(value) counts valuesrequirements.txt with == pins, whichever tool wrote it-v flag that saves the reportcd and ls to shipping an image someone else can runSource: datasci350-project-starter
βββββββββββββββββββββββ¬βββββββββ
β country β co2_pc β
β varchar β double β
βββββββββββββββββββββββΌβββββββββ€
β Palau β 71.7 β
β Qatar β 41.3 β
β Bahrain β 25.0 β
β Brunei Darussalam β 22.6 β
β Trinidad and Tobago β 21.8 β
βββββββββββββββββββββββ΄βββββββββ
WHERE drops every other indicator and every other yearROUND(value, 1) computes a new column, and AS co2_pc names itORDER BY value DESC sorts on the original column, which works just as well as sorting on the aliasββββββββββββββ¬ββββββββββ¬ββββββββββββββββ
β country β n_years β mean_internet β
β varchar β int64 β double β
ββββββββββββββΌββββββββββΌββββββββββββββββ€
β Iceland β 9 β 98.7 β
β Bahrain β 9 β 98.4 β
β Luxembourg β 9 β 97.9 β
β Qatar β 9 β 97.8 β
β Denmark β 9 β 97.5 β
ββββββββββββββ΄ββββββββββ΄ββββββββββββββββ
WHERE keeps rows, and both HAVING conditions test the groupCOUNT(value) returns 9 for each of these countries, so the panel holds 2015 to 2023COUNT(*) would return 9 for every country in the world, including the ones with no numbers at allORDER BY names mean_internet, the alias created in SELECTFROM ubuntu:24.04 pins the base operating system to one Ubuntu release
latest moves: it resolved to 24.04 last year and to 26.04 todayCOPY requirements.txt on its own line gives pip a layer of its own
pip install cachedENV PATH="/opt/venv/bin:$PATH" puts the virtual environment first on the PATH
python and pip then mean the ones in /opt/venv, and Ubuntuβs own Python stays untouchedreport.qmd misses the cache at COPY . /project, so only that step rebuilds
requirements.txt misses at COPY requirements.txt, so pip and everything below it runs again-v the render succeeds inside the container
--rm then deletes the container, and the file goes with itls output on your laptop says there is no such directoryuv in more detailuv is an environment and package manager from Astral, written in Rustuv init starts the project, uv add installs a package and records ituv sync rebuilds the environment from the lock fileuv run executes inside that environment, so there is nothing to activatepyproject.toml holds your direct dependencies, and you read and edit ituv.lock holds the exact version and hash of every package, direct or notuv export --format requirements-txt --no-hashes > requirements.txt writes the file your Dockerfile reads