Skip to content

Commit 85c342b

Browse files
committed
feat: add exercise #1
0 parents  commit 85c342b

File tree

10 files changed

+240
-0
lines changed

10 files changed

+240
-0
lines changed

.github/dependabot.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "pip"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: Container Build
2+
on:
3+
- pull_request
4+
- push
5+
6+
jobs:
7+
docker:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- name: Checkout
11+
uses: actions/checkout@v4
12+
13+
- name: Builds Docker Image
14+
run: docker compose build notebook
15+
16+
- name: Stops Containers
17+
run: docker compose down
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Dependabot auto-merge
2+
on: pull_request
3+
4+
permissions:
5+
contents: write
6+
pull-requests: write
7+
8+
jobs:
9+
dependabot:
10+
runs-on: ubuntu-latest
11+
if: ${{ github.actor == 'dependabot[bot]' }}
12+
steps:
13+
- name: Dependabot metadata
14+
id: metadata
15+
uses: dependabot/fetch-metadata@v1
16+
with:
17+
github-token: "${{ secrets.GITHUB_TOKEN }}"
18+
- name: Enable auto-merge for Dependabot PRs
19+
if: ${{ steps.metadata.outputs.update-type == 'version-update:semver-patch' }}
20+
run: gh pr merge --auto --merge "$PR_URL"
21+
env:
22+
PR_URL: ${{github.event.pull_request.html_url}}
23+
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.DS_Store
2+
.ipynb_checkpoints

Dockerfile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
FROM python:3.9-slim-buster
2+
3+
RUN mkdir /app
4+
5+
WORKDIR /app
6+
7+
RUN apt-get update \
8+
&& apt-get install --yes --no-install-recommends \
9+
build-essential
10+
11+
COPY requirements.txt .
12+
13+
RUN pip install -r requirements.txt
14+
15+
COPY . .
16+
17+
EXPOSE 8888
18+
19+
ENTRYPOINT ["jupyter", "notebook", "--ip=0.0.0.0", "--no-browser", "--allow-root"]

Justfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
dev:
2+
docker compose up notebook
3+
4+
build:
5+
docker compose build notebook
6+
7+
cleanup:
8+
docker compose down
9+
10+
bash:
11+
docker exec -it <CONTAINER ID> bash

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<div>
2+
<h1 align="center">Python for Data Science</h1>
3+
<h4 align="center">🐍 Following "Python for Data Science" Book Exercises</h4>
4+
</div>
5+
6+
## Run Locally
7+
8+
Build an run containers using `docker compose`
9+
10+
```bash
11+
docker compose up --build notebook
12+
```
13+
14+
> Using `Justfile` this is a matter of running `just build` and from
15+
> there on `just dev`
16+
17+
After working you can release resources using:
18+
19+
```bash
20+
docker compose down
21+
```
22+
23+
> A [Justfile][1] is included!
24+
25+
[1]: https://just.systems

docker-compose.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
version: '3'
2+
3+
services:
4+
notebook:
5+
build:
6+
context: .
7+
dockerfile: Dockerfile
8+
volumes:
9+
- .:/app
10+
ports:
11+
- 8888:8888
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "42b7f162-35b4-4958-b57d-de78a20118ff",
6+
"metadata": {},
7+
"source": [
8+
"In order to always fetch the latest version of the data, such data is fetched from author's repository, then converted into a Python statement and finally executed.\n",
9+
"\n",
10+
"> Note about `exec`, it is discouraged to execute arbirtary code as is done in the following block. A malicious user could post harmful\n",
11+
"> code in such GitHub's file and then such code would be executed."
12+
]
13+
},
14+
{
15+
"cell_type": "code",
16+
"execution_count": 14,
17+
"id": "abae6b96-65db-49fe-ab49-b0f955418d6d",
18+
"metadata": {},
19+
"outputs": [
20+
{
21+
"name": "stdout",
22+
"output_type": "stream",
23+
"text": [
24+
"[{'name': 'photo1.jpg', 'tags': {'food', 'coffee', 'drink', 'cup', 'breakfast', 'table', 'tableware'}}, {'name': 'photo2.jpg', 'tags': {'food', 'dish', 'vegetable', 'dinner', 'meal', 'meat', 'tableware'}}, {'name': 'photo3.jpg', 'tags': {'city', 'skyline', 'skyscraper', 'architecture', 'travel', 'building', 'cityscape'}}, {'name': 'photo4.jpg', 'tags': {'glass', 'drink', 'meal', 'grapes', 'fruit', 'juice', 'food'}}]\n"
25+
]
26+
}
27+
],
28+
"source": [
29+
"import requests\n",
30+
"\n",
31+
"LIST_OF_DICTIONARIES_JSON_URL = \"https://raw.githubusercontent.com/pythondatabook/sources/main/ch2/list_of_dicts.txt\"\n",
32+
"\n",
33+
"response = requests.get(LIST_OF_DICTIONARIES_JSON_URL)\n",
34+
"response_text = response.text\n",
35+
"response_text = 'data = ' + response_text\n",
36+
"\n",
37+
"exec(response_text)\n",
38+
"print(data)"
39+
]
40+
},
41+
{
42+
"cell_type": "markdown",
43+
"id": "9309d683-2707-4857-aee4-a2ef09806dad",
44+
"metadata": {},
45+
"source": [
46+
"Group photos with intersecting tags, saving the results in `photo_groups`."
47+
]
48+
},
49+
{
50+
"cell_type": "code",
51+
"execution_count": 35,
52+
"id": "86df43c8-d757-406c-86b9-b466111f7adb",
53+
"metadata": {},
54+
"outputs": [
55+
{
56+
"name": "stdout",
57+
"output_type": "stream",
58+
"text": [
59+
"{\n",
60+
" \"tableware_food\": [\n",
61+
" \"photo1.jpg\",\n",
62+
" \"photo2.jpg\"\n",
63+
" ],\n",
64+
" \"drink_food\": [\n",
65+
" \"photo1.jpg\",\n",
66+
" \"photo4.jpg\"\n",
67+
" ],\n",
68+
" \"meal_food\": [\n",
69+
" \"photo2.jpg\",\n",
70+
" \"photo4.jpg\"\n",
71+
" ]\n",
72+
"}\n"
73+
]
74+
}
75+
],
76+
"source": [
77+
"import json\n",
78+
"\n",
79+
"photo_groups = {}\n",
80+
"\n",
81+
"for photo_x in range(0, len(data)):\n",
82+
" for photo_y in range(photo_x+1, len(data)):\n",
83+
" intersection = data[photo_x]['tags'].intersection(data[photo_y]['tags'])\n",
84+
"\n",
85+
" if len(intersection) >= 2:\n",
86+
" intersection = list(intersection)\n",
87+
" key = '_'.join(intersection)\n",
88+
" photo_groups.setdefault(key, [data[photo_x]['name'], data[photo_y]['name']])\n",
89+
"\n",
90+
"print(json.dumps(photo_groups, indent=4))"
91+
]
92+
}
93+
],
94+
"metadata": {
95+
"kernelspec": {
96+
"display_name": "Python 3 (ipykernel)",
97+
"language": "python",
98+
"name": "python3"
99+
},
100+
"language_info": {
101+
"codemirror_mode": {
102+
"name": "ipython",
103+
"version": 3
104+
},
105+
"file_extension": ".py",
106+
"mimetype": "text/x-python",
107+
"name": "python",
108+
"nbconvert_exporter": "python",
109+
"pygments_lexer": "ipython3",
110+
"version": "3.9.17"
111+
}
112+
},
113+
"nbformat": 4,
114+
"nbformat_minor": 5
115+
}

requirements.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
h5py == 3.10.0
2+
jupyter == 1.0.0
3+
keras == 3.1.1
4+
matplotlib == 3.8.4
5+
notebook == 7.1.2
6+
numpy == 1.26.4
7+
pandas == 2.2.1
8+
pillow == 10.3.0
9+
scikit-learn == 1.4.0
10+
seaborn == 0.13.2
11+
spacy == 3.7.4

0 commit comments

Comments
 (0)