Skip to content

Commit 93d75a1

Browse files
committed
feat(lab-09): expand final challenge
1 parent 4728e5d commit 93d75a1

1 file changed

Lines changed: 58 additions & 17 deletions

File tree

think_and_compute/lab-09.md

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ By the end of this lab, you will be able to:
1818
- Load CSV files into pandas DataFrames with correct data types
1919
- Query and filter DataFrames using `query()` and `iterrows()`
2020
- Join multiple DataFrames using `merge()`
21+
- Compute derived values from existing columns
22+
- Build a new DataFrame from aggregated results
2123
- Save results to CSV files using `to_csv()`
2224
```
2325

@@ -27,7 +29,7 @@ This lab puts into practice the concepts introduced in the [Introduction to Pand
2729

2830
## The dataset: Caravaggio's artworks in Italy
2931

30-
The dataset for this lab consists of three CSV files stored in the `notebook/` directory:
32+
The dataset for this lab consists of three CSV files (you can download each file by clicking on its name):
3133

3234
- **[`artworks.csv`](notebook/artworks.csv)**: a catalogue of 15 paintings by Caravaggio with their title, year, genre, dimensions (height and width in cm), and the museum where they are held
3335
- **[`museums.csv`](notebook/museums.csv)**: a list of 11 Italian museums and churches with their city, type, and founding year
@@ -43,7 +45,7 @@ In this first part, you will load the artworks dataset and explore its content u
4345

4446
### Exercise 1.1: Load the artworks catalogue
4547

46-
Load the file `notebook/artworks.csv` into a pandas DataFrame using `read_csv()`. Make sure to specify `keep_default_na=False` and provide a `dtype` dictionary so that each column is read with the correct data type: `"string"` for text columns and `"int"` for `id`, `year`, `height_cm`, `width_cm`, and `museum_id`. Display the resulting DataFrame.
48+
Load the file `artworks.csv` into a pandas DataFrame using `read_csv()`. Make sure to specify `keep_default_na=False` and provide a `dtype` dictionary so that each column is read with the correct data type: `"string"` for text columns and `"int"` for `id`, `year`, `height_cm`, `width_cm`, and `museum_id`. Display the resulting DataFrame.
4749

4850
```{code-cell} python
4951
:tags: [hide-cell]
@@ -111,7 +113,7 @@ In real datasets, information is often distributed across multiple tables. In th
111113

112114
### Exercise 3.1: Load and join artworks with collections
113115

114-
Load `notebook/museums.csv` and `notebook/collections.csv` into two DataFrames, specifying `keep_default_na=False` and appropriate `dtype` dictionaries. Then, use `merge()` to join the artworks DataFrame with the collections DataFrame. The join should match the `id` column in artworks with the `artwork_id` column in collections. Display the resulting DataFrame and observe which columns it contains.
116+
Load `museums.csv` and `collections.csv` into two DataFrames, specifying `keep_default_na=False` and appropriate `dtype` dictionaries. Then, use `merge()` to join the artworks DataFrame with the collections DataFrame. The join should match the `id` column in artworks with the `artwork_id` column in collections. Display the resulting DataFrame and observe which columns it contains.
115117

116118
```{code-cell} python
117119
:tags: [hide-cell]
@@ -141,7 +143,7 @@ df_art_collections
141143

142144
### Exercise 3.2: Chain a second merge and save results
143145

144-
Starting from the result of the previous exercise, perform a second `merge()` to add the museum names. Join on the `museum_id` column (present in both the artworks data and the museums data). Then, find all artworks in "excellent" condition and print their title and museum name. Finally, save the resulting DataFrame of excellent-condition artworks to a new CSV file called `notebook/excellent_artworks.csv`, using `to_csv()` with `index=False` to avoid writing the row index.
146+
Starting from the result of the previous exercise, perform a second `merge()` to add the museum names. Join on the `museum_id` column (present in both the artworks data and the museums data). Then, find all artworks in "excellent" condition and print their title and museum name. Finally, save the resulting DataFrame of excellent-condition artworks to a new CSV file called `excellent_artworks.csv`, using `to_csv()` with `index=False` to avoid writing the row index.
145147

146148
```{code-cell} python
147149
:tags: [hide-cell]
@@ -157,16 +159,24 @@ df_excellent.to_csv("notebook/excellent_artworks.csv", index=False)
157159

158160
## Part 4: Final challenge
159161

160-
### Exercise 4.1: Artworks per museum
162+
### Exercise 4.1: Museum report
161163

162-
Using all three CSV files, produce a dictionary where each key is a museum name and each value is the number of artworks that museum holds. Print the result.
164+
Using all three CSV files, produce a summary report as a new DataFrame with one row per museum and the following columns:
165+
166+
- `museum`: the museum name
167+
- `city`: the city where the museum is located
168+
- `num_artworks`: the number of Caravaggio artworks held by the museum
169+
- `largest_artwork`: the title of the largest artwork (by area, computed as `height_cm * width_cm`)
170+
- `excellent_pct`: the percentage of artworks in "excellent" condition (as an integer between 0 and 100)
171+
172+
Save the resulting DataFrame to a CSV file called `museum_report.csv` (without the row index) and display it.
163173

164174
````{admonition} Solution
165175
:class: tip, dropdown
166176
```python
167-
from pandas import read_csv, merge
177+
from pandas import read_csv, merge, DataFrame, Series
168178
169-
df_artworks = read_csv("notebook/artworks.csv",
179+
df_artworks = read_csv("artworks.csv",
170180
keep_default_na=False,
171181
dtype={
172182
"id": "int",
@@ -178,7 +188,7 @@ df_artworks = read_csv("notebook/artworks.csv",
178188
"museum_id": "int"
179189
})
180190
181-
df_museums = read_csv("notebook/museums.csv",
191+
df_museums = read_csv("museums.csv",
182192
keep_default_na=False,
183193
dtype={
184194
"museum_id": "int",
@@ -188,7 +198,7 @@ df_museums = read_csv("notebook/museums.csv",
188198
"founded": "int"
189199
})
190200
191-
df_collections = read_csv("notebook/collections.csv",
201+
df_collections = read_csv("collections.csv",
192202
keep_default_na=False,
193203
dtype={
194204
"artwork_id": "int",
@@ -199,15 +209,44 @@ df_collections = read_csv("notebook/collections.csv",
199209
df_full = merge(df_artworks, df_collections, left_on="id", right_on="artwork_id")
200210
df_full = merge(df_full, df_museums, on="museum_id")
201211
202-
museum_counts = dict()
212+
report = dict()
203213
for idx, row in df_full.iterrows():
204214
museum_name = row["name"]
205-
if museum_name in museum_counts:
206-
museum_counts[museum_name] = museum_counts[museum_name] + 1
207-
else:
208-
museum_counts[museum_name] = 1
209-
210-
print(museum_counts)
215+
area = row["height_cm"] * row["width_cm"]
216+
217+
if museum_name not in report:
218+
report[museum_name] = {
219+
"city": row["city"],
220+
"num_artworks": 0,
221+
"largest_artwork": row["title"],
222+
"largest_area": area,
223+
"excellent_count": 0
224+
}
225+
226+
report[museum_name]["num_artworks"] = report[museum_name]["num_artworks"] + 1
227+
228+
if area > report[museum_name]["largest_area"]:
229+
report[museum_name]["largest_artwork"] = row["title"]
230+
report[museum_name]["largest_area"] = area
231+
232+
if row["condition"] == "excellent":
233+
report[museum_name]["excellent_count"] = report[museum_name]["excellent_count"] + 1
234+
235+
rows = list()
236+
for museum_name in report:
237+
row = Series({
238+
"museum": museum_name,
239+
"city": report[museum_name]["city"],
240+
"num_artworks": report[museum_name]["num_artworks"],
241+
"largest_artwork": report[museum_name]["largest_artwork"],
242+
"excellent_pct": int(report[museum_name]["excellent_count"] / report[museum_name]["num_artworks"] * 100)
243+
})
244+
rows.append(row)
245+
246+
df_report = DataFrame(rows)
247+
248+
df_report.to_csv("museum_report.csv", index=False)
249+
df_report
211250
```
212251
````
213252

@@ -220,6 +259,8 @@ In this lab, you practised:
220259
- **Loading data**: using `read_csv()` with `keep_default_na=False` and `dtype` to control how pandas interprets each column
221260
- **Exploring data**: iterating over rows with `iterrows()` and filtering with `query()`
222261
- **Combining tables**: using `merge()` to join DataFrames on shared columns
262+
- **Computing derived values**: calculating new quantities (such as area) from existing columns
263+
- **Building DataFrames**: creating a new `DataFrame` from aggregated results using `DataFrame()`
223264
- **Saving results**: writing DataFrames to CSV files with `to_csv()`
224265

225266
---

0 commit comments

Comments
 (0)