Read and analyse the weather data with pandas

Task: MIL-003#1
Task: MIL-003#2
Task: MIL-003#3
Task: MIL-003#4
This commit is contained in:
2026-10-13 15:30:00 +08:00
parent 672c4a3f83
commit ffd21f5418
+113
View File
@@ -0,0 +1,113 @@
## @file analysis.py
# @brief Reads and analyses the weather data file with `pandas`.
#
# This is the second half of the lectures: the file is read in one line into a
# `DataFrame`, converted to a dictionary and a list, and the average and
# maximum temperature and the row selections are computed. This is the only
# module of the package that imports `pandas`, which is an optional extra.
"""Reads and analyses the weather data file with pandas."""
from collections.abc import Hashable
from pathlib import Path
from typing import Any
import pandas
from weather.constants import (
COLUMN_DAY,
COLUMN_TEMP,
DATA_FILE,
FAHRENHEIT_DENOMINATOR,
FAHRENHEIT_NUMERATOR,
FAHRENHEIT_OFFSET,
)
def read_data(path: Path | str = DATA_FILE) -> pandas.DataFrame:
"""! @brief Read a weather CSV file into a `DataFrame`.
@param path Path of the CSV file; the weather data file by default.
@return The table, one row per day, with the columns of the file.
"""
return pandas.read_csv(path)
def to_data_dict(data: pandas.DataFrame) -> dict[Hashable, Any]: # Any: cell values
"""! @brief Convert the table to a dictionary of columns.
@param data The weather table.
@return A dictionary that maps each column name to its values by row index.
"""
return data.to_dict()
def to_temp_list(data: pandas.DataFrame) -> list[int]:
"""! @brief Convert the temperature column to a list.
@param data The weather table.
@return The temperatures in row order.
"""
return data[COLUMN_TEMP].to_list()
def average_temp(data: pandas.DataFrame) -> float:
"""! @brief Compute the average temperature from the sum and the length.
@param data The weather table.
@return The average temperature.
"""
temp_list = to_temp_list(data)
return sum(temp_list) / len(temp_list)
def average_temp_mean(data: pandas.DataFrame) -> float:
"""! @brief Compute the average temperature with `Series.mean()`.
@param data The weather table.
@return The average temperature.
"""
return float(data[COLUMN_TEMP].mean())
def max_temp(data: pandas.DataFrame) -> int:
"""! @brief Find the highest temperature.
@param data The weather table.
@return The maximum of the temperature column.
"""
return int(data[COLUMN_TEMP].max())
def row_for_day(data: pandas.DataFrame, day: str) -> pandas.DataFrame:
"""! @brief Select the rows of one day.
@param data The weather table.
@param day Name of the day, such as `Monday`.
@return The matching rows; empty when the day is not in the table.
"""
return data.loc[data[COLUMN_DAY] == day]
def hottest_row(data: pandas.DataFrame) -> pandas.DataFrame:
"""! @brief Select the row or rows with the highest temperature.
@param data The weather table.
@return The rows whose temperature equals the maximum.
"""
return data.loc[data[COLUMN_TEMP] == max_temp(data)]
def day_in_fahrenheit(data: pandas.DataFrame, day: str) -> float:
"""! @brief Convert the temperature of one day from Celsius to Fahrenheit.
@param data The weather table.
@param day Name of the day, such as `Monday`.
@return The temperature in degrees Fahrenheit.
@throws ValueError When the day is not in the table exactly once.
"""
rows = row_for_day(data, day)
if len(rows) != 1:
raise ValueError(f"Expected exactly one row for day {day!r}, got {len(rows)}")
celsius = int(rows[COLUMN_TEMP].iloc[0])
return celsius * FAHRENHEIT_NUMERATOR / FAHRENHEIT_DENOMINATOR + FAHRENHEIT_OFFSET