From 8236dfda74690c4cdfa5952bbd238b38417e89ed Mon Sep 17 00:00:00 2001 From: Jude Baffoe-Bonnie Date: Thu, 2 Apr 2026 15:02:11 -0400 Subject: [PATCH 1/8] Add project template --- .../Dockerfile | 30 + .../Dockerfile.python_slim | 28 + .../Dockerfile.ubuntu | 40 + .../Dockerfile.uv | 49 ++ .../README.md | 802 ++++++++++++++++++ .../bashrc | 1 + .../copy_docker_files.py | 140 +++ .../docker_bash.sh | 34 + .../docker_build.sh | 40 + .../docker_build.version.log | 1 + .../docker_clean.sh | 26 + .../docker_cmd.sh | 41 + .../docker_exec.sh | 25 + .../docker_jupyter.sh | 39 + .../docker_name.sh | 12 + .../docker_push.sh | 25 + .../etc_sudoers | 31 + .../requirements.txt | 4 + .../run_jupyter.sh | 35 + .../template.API.ipynb | 215 +++++ .../template.API.py | 129 +++ .../template.example.ipynb | 198 +++++ .../template.example.py | 125 +++ .../template_utils.py | 72 ++ .../test/test_docker_all.py | 48 ++ .../utils.sh | 607 +++++++++++++ .../version.sh | 28 + 27 files changed, 2825 insertions(+) create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dockerfile create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dockerfile.python_slim create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dockerfile.ubuntu create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dockerfile.uv create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/README.md create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/bashrc create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/copy_docker_files.py create mode 100755 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_bash.sh create mode 100755 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_build.sh create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_build.version.log create mode 100755 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_clean.sh create mode 100755 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_cmd.sh create mode 100755 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_exec.sh create mode 100755 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_jupyter.sh create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_name.sh create mode 100755 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_push.sh create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/etc_sudoers create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/requirements.txt create mode 100755 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/run_jupyter.sh create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template.API.ipynb create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template.API.py create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template.example.ipynb create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template.example.py create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template_utils.py create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/test/test_docker_all.py create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/utils.sh create mode 100755 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/version.sh diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dockerfile b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dockerfile new file mode 100644 index 000000000..f5c02c562 --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dockerfile @@ -0,0 +1,30 @@ +# Use Python 3.12 slim (already has Python and pip). +FROM python:3.12-slim + +# Avoid interactive prompts during apt operations. +ENV DEBIAN_FRONTEND=noninteractive + +# Install CA certificates (needed for HTTPS). +RUN apt-get update && apt-get install -y \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Install project specific packages. +RUN mkdir -p /install +COPY requirements.txt /install/requirements.txt +RUN pip install --upgrade pip && \ + pip install --no-cache-dir jupyterlab jupyterlab_vim jupytext -r /install/requirements.txt + +# Config. +COPY etc_sudoers /install/ +COPY etc_sudoers /etc/sudoers +COPY bashrc /root/.bashrc + +# Report package versions. +COPY version.sh /install/ +RUN /install/version.sh 2>&1 | tee version.log + +# Jupyter. +EXPOSE 8888 + +CMD ["/bin/bash"] diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dockerfile.python_slim b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dockerfile.python_slim new file mode 100644 index 000000000..cc8f18f2f --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dockerfile.python_slim @@ -0,0 +1,28 @@ +# Use Python 3.12 slim (already has Python and pip). +FROM python:3.12-slim + +# Avoid interactive prompts during apt operations. +ENV DEBIAN_FRONTEND=noninteractive + +# Install CA certificates (needed for HTTPS). +RUN apt-get update && apt-get install -y \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Install project specific packages. +RUN mkdir -p /install +COPY requirements.txt /install/requirements.txt +RUN pip install --upgrade pip && \ + pip install --no-cache-dir jupyterlab jupyterlab_vim jupytext -r /install/requirements.txt + +# Config. +COPY etc_sudoers /install/ +COPY etc_sudoers /etc/sudoers +COPY bashrc /root/.bashrc + +# Report package versions. +COPY version.sh /install/ +RUN /install/version.sh 2>&1 | tee version.log + +# Jupyter. +EXPOSE 8888 diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dockerfile.ubuntu b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dockerfile.ubuntu new file mode 100644 index 000000000..705105d91 --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dockerfile.ubuntu @@ -0,0 +1,40 @@ +FROM ubuntu:24.04 +ENV DEBIAN_FRONTEND noninteractive + +# Install system utilities and Python in a single layer. +RUN apt-get update && \ + apt-get upgrade -y && \ + apt-get install -y --no-install-recommends \ + sudo \ + curl \ + git \ + build-essential \ + python3 \ + python3-pip \ + python3-dev \ + python3-venv \ + && rm -rf /var/lib/apt/lists/* + +# Create virtual environment. +RUN python3 -m venv /opt/venv + +# Make the venv the default Python. +ENV PATH="/opt/venv/bin:$PATH" + +# Install project specific packages. +RUN mkdir /install +COPY requirements.txt /install/requirements.txt +RUN pip install --upgrade pip && \ + pip install --no-cache-dir jupyterlab jupyterlab_vim jupytext -r /install/requirements.txt + +# Config. +COPY etc_sudoers /install/ +COPY etc_sudoers /etc/sudoers +COPY bashrc /root/.bashrc + +# Report package versions. +COPY version.sh /install/ +RUN /install/version.sh 2>&1 | tee version.log + +# Jupyter. +EXPOSE 8888 diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dockerfile.uv b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dockerfile.uv new file mode 100644 index 000000000..d3b2a0abc --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dockerfile.uv @@ -0,0 +1,49 @@ +FROM ubuntu:24.04 +ENV DEBIAN_FRONTEND noninteractive + +# Install system utilities and Python in a single layer. +RUN apt-get update && \ + apt-get upgrade -y && \ + apt-get install -y --no-install-recommends \ + sudo \ + curl \ + git \ + build-essential \ + python3 \ + python3-pip \ + python3-dev \ + python3-venv \ + libgomp1 \ + g++ \ + && rm -rf /var/lib/apt/lists/* + +# Install uv for package management. +RUN curl -LsSf https://astral.sh/uv/install.sh | sh +ENV PATH="/root/.local/bin:$PATH" + +# Install project specific packages using uv. +COPY pyproject.toml uv.lock /app/ +WORKDIR /app +RUN uv sync +ENV PATH="/app/.venv/bin:$PATH" + +# Install Jupyter. +RUN pip install --upgrade pip && \ + pip install --no-cache-dir jupyterlab jupyterlab_vim jupytext + +# Copy project files. +COPY . /app + +RUN mkdir /install + +# Config. +COPY etc_sudoers /install/ +COPY etc_sudoers /etc/sudoers +COPY bashrc /root/.bashrc + +# Report package versions. +COPY version.sh /install/ +RUN /install/version.sh 2>&1 | tee version.log + +# Jupyter. +EXPOSE 8888 diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/README.md b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/README.md new file mode 100644 index 000000000..58d90e2d1 --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/README.md @@ -0,0 +1,802 @@ +# Summary +This directory contains a Docker-based development environment template with: + +- Utility scripts for Docker operations (build, run, clean, push) +- Configuration files for Dockerfile and environment setup +- Jupyter notebook templates for standardized project development +- Shell utilities and Python helpers for container-based workflows + +A guide to set up Docker-based projects using the template, customize it for +your needs, and maintain it over time. + +## Description of Files +- `bashrc` + - Bash configuration file enabling `vi` mode for command-line editing + +- `copy_docker_files.py` + - Python script for copying Docker configuration files to destination + directories + +- `docker_build.version.log` + - Log file containing Python, `pip`, Jupyter, and package version information + from Docker build + +- `docker_cmd.sh` + - Shell script for executing arbitrary commands inside Docker containers with + volume mounting + +- `docker_jupyter.sh` + - Shell script for launching Jupyter Lab server inside Docker containers + +- `docker_name.sh` + - Configuration file defining Docker repository and image naming variables + +- `Dockerfile` + - Docker image build configuration with Ubuntu, Python, Jupyter, and project + dependencies + +- `etc_sudoers` + - Sudoers configuration file granting passwordless sudo access for postgres + user + +- `README.md` + - Documentation file describing directory contents, files, and executable + scripts + +- `template_utils.py` + - Python utility functions supporting tutorial notebooks with data processing + and modeling helpers + +- `template.API.ipynb` + - Jupyter notebook template for API exploration and library usage examples + +- `template.example.ipynb` + - Jupyter notebook template for project examples and demonstrations + +- `utils.sh` + - Bash utility library with reusable functions for Docker operations + - Provides centralized argument parsing (`parse_default_args`) for `-h` and + `-v` flags used by all `docker_*.sh` scripts + - Provides Jupyter configuration logic: vim keybindings, notification + settings, and Docker run option builders + - All `docker_*.sh`, `docker_jupyter.sh`, and `run_jupyter.sh` scripts across + the repo source this file from `class_project/project_template/utils.sh` + +## Workflows +- All commands should be run from inside the project directory + ```bash + > cd tutorials/FilterPy + ``` + +- To build the container for a project + ```bash + > cd $PROJECT + # Build the container. + > docker_build.sh + # Build without cache (pass extra args after -v). + > docker_build.sh --no-cache + # Test the container. + > docker_bash.sh ls + ``` + +- Enable verbose (trace) output with `-v` + ```bash + > docker_build.sh -v + > docker_bash.sh -v + ``` + +- Get help for any docker script + ```bash + > docker_build.sh -h + > docker_jupyter.sh -h + ``` + +- Start Jupyter + ```bash + > docker_jupyter.sh + # Go to localhost:8888 + ``` + +- Start Jupyter on a specific port with vim support + ```bash + > docker_jupyter.sh -p 8890 -u + # Go to localhost:8890 + ``` + +## How to Customize a Project Template +- Copy the template + ```bash + > cp -r class_project/project_template $TARGET + ``` + +## Description of Executables + +### `copy_docker_files.py` +- **What It Does** + - Copies Docker configuration and utility files from project_template to a + destination directory + - Preserves all file permissions and attributes during copying + - Creates destination directory if it doesn't exist + +- Copy all Docker files to a target directory: + ```bash + > ./copy_docker_files.py --dst_dir /path/to/destination + ``` + +- Copy with verbose logging: + ```bash + > ./copy_docker_files.py --dst_dir /path/to/destination -v DEBUG + ``` + +### `docker_bash.sh` +- **What It Does** + - Launches an interactive bash shell inside a Docker container + - Mounts the current working directory as `/data` inside the container + - Exposes port 8888 for potential services running in the container + - Accepts `-h` (help) and `-v` (verbose/trace) flags via `parse_default_args` + +- Launch bash shell in the container: + ```bash + > ./docker_bash.sh + ``` + +- Launch with verbose output (prints each command): + ```bash + > ./docker_bash.sh -v + ``` + +### `docker_build.sh` +- **What It Does** + - Builds Docker container images using Docker BuildKit + - Supports single-architecture builds (default) or multi-architecture builds + (`linux/arm64`, `linux/amd64`) + - Copies project files to temporary build directory and generates build logs + - Accepts `-h` (help) and `-v` (verbose/trace) flags; any extra arguments + after flags are forwarded to `docker build` + +- Build container image for current architecture: + ```bash + > ./docker_build.sh + ``` + +- Build without Docker layer cache: + ```bash + > ./docker_build.sh --no-cache + ``` + +- Build multi-architecture image (requires setting `DOCKER_BUILD_MULTI_ARCH=1` + in the script): + ```bash + > # Edit docker_build.sh to set DOCKER_BUILD_MULTI_ARCH=1 + > ./docker_build.sh + ``` + +### `docker_clean.sh` +- **What It Does** + +- Removes all Docker images matching the project's full image name +- Lists images before and after removal for verification +- Uses force removal to ensure cleanup completes + +- Remove project's Docker images: + ```bash + > ./docker_clean.sh + ``` + +### `docker_cmd.sh` +- **What It Does** + - Executes arbitrary commands inside a Docker container + - Mounts current directory as `/data` for accessing project files + - Automatically removes container after command execution completes + - Accepts `-h` (help) and `-v` (verbose/trace) flags; remaining arguments + form the command to execute + +- Run Python script inside container: + ```bash + > ./docker_cmd.sh python script.py --arg value + ``` + +- List files in the container: + ```bash + > ./docker_cmd.sh ls -la /data + ``` + +- Run tests inside container: + ```bash + > ./docker_cmd.sh pytest tests/ + ``` + +### `docker_exec.sh` +- **What It Does** + - Attaches to an already running Docker container with an interactive bash + shell + - Finds the container ID automatically based on the image name + - Useful for debugging or inspecting running containers + - Accepts `-h` (help) and `-v` (verbose/trace) flags via `parse_default_args` + +- Attach to running container: + ```bash + > ./docker_exec.sh + ``` + +### `docker_jupyter.sh` +- **What It Does** + - Launches Jupyter Lab server inside a Docker container + - Supports custom port configuration (default 8888), vim keybindings, and + custom directory mounting + - Runs `run_jupyter.sh` script inside the container with specified options + +- Start Jupyter on default port 8888: + ```bash + > ./docker_jupyter.sh + ``` + +- Start Jupyter on custom port with vim bindings: + ```bash + > ./docker_jupyter.sh -p 8889 -u + ``` + +- Start Jupyter with external directory mounted: + ```bash + > ./docker_jupyter.sh -d /path/to/notebooks -p 8889 + ``` + +- Start Jupyter in verbose mode: + ```bash + > ./docker_jupyter.sh -v -p 8890 + ``` + +### `docker_push.sh` +- **What It Does** + - Authenticates to Docker registry using credentials from + `~/.docker/passwd.$REPO_NAME.txt` + - Pushes the project's Docker image to the remote repository + - Lists images before pushing for verification + +- Push container image to registry: + ```bash + > ./docker_push.sh + ``` + +### `run_jupyter.sh` +- **What It Does** + - Launches Jupyter Lab server with no authentication (token and password + disabled) + - Binds to all network interfaces (0.0.0.0) on port 8888 + - Allows root access for container environments + - When `JUPYTER_USE_VIM=1`, verifies that `jupyterlab_vim` is installed + before enabling vim keybindings; exits with an error if not found + +- Start Jupyter Lab server (typically called from docker_jupyter.sh): + ```bash + > ./run_jupyter.sh + ``` + +- Start with vim keybindings (requires `jupyterlab_vim` installed in the + container): + ```bash + > JUPYTER_USE_VIM=1 ./run_jupyter.sh + ``` + +### `utils.sh` +- **What It Does** + - Central Bash library sourced by all `docker_*.sh` and `run_jupyter.sh` + scripts across the repository + - Provides `parse_default_args` which adds `-h` (help) and `-v` + (verbose/`set -x`) flags to every docker script + - Provides `build_container_image`, `push_container_image`, + `remove_container_image`, `kill_container`, `exec_container` utilities + - Provides Jupyter configuration helpers: vim keybindings, notification + suppression, and Docker run option builders + +### `version.sh` +- **What It Does** + - Reports version information for Python3, pip3, and Jupyter + - Lists all installed Python packages with versions + - Used during Docker image builds to log environment configuration + +- Display version information: + ```bash + > ./version.sh + ``` + +- Save version information to a log file: + ```bash + > ./version.sh 2>&1 | tee version.log + ``` + +# Template Customization and Maintenance + +## Quick Start for New Projects + +### Step 1: Copy the Template +```bash +> cd class_project/project_template +> cp -r . /path/to/your/new/project +> cd /path/to/your/new/project +``` + +### Step 2: Choose a Base Image +The template includes three Dockerfile options. Choose the one that best fits +your project: + +| Option | File | Best For | +| -------------------------- | ------------------------ | ---------------------------------------------------------------- | +| **Standard** | `Dockerfile.ubuntu` | Full Ubuntu environment with system tools | +| **Lightweight** | `Dockerfile.python_slim` | Minimal Python environment; reduced image size | +| **Modern Package Manager** | `Dockerfile.uv` | Fast dependency resolution with [uv](https://docs.astral.sh/uv/) | + +**How to choose:** + +- **Use Standard** if you need system-level tools (git, curl, graphviz, etc.) +- **Use Python Slim** to minimize image size and build time +- **Use uv** if you want faster, more reliable dependency management + +### Step 3: Set Up Your Dockerfile +- Delete unused reference files + ```bash + > rm Dockerfile.ubuntu Dockerfile.python_slim Dockerfile.uv + ``` + +- Create your working Dockerfile + ```bash + > cp Dockerfile.ubuntu Dockerfile + ``` + +- Add your dependencies + ```bash + > echo "numpy\npandas\nscikit-learn" > requirements.in + > pip-compile requirements.in > requirements.txt + ``` + +### Step 4: Keep Customization Minimal +- Only modify what's necessary for your project +- Use `requirements.txt` for all Python packages (don't edit Dockerfile for + this) +- Keep `bashrc` and `etc_sudoers` as-is unless you need custom shell setup +- Keep base image and Python version unless you have specific requirements + +## Understanding the Dockerfile Flow +Each Dockerfile follows the same structure. Here are the key stages: + +### Stage 1: Base Image and System Setup +```dockerfile +FROM ubuntu:24.04 # or python:3.12-slim, depending on your requirement +ENV DEBIAN_FRONTEND noninteractive +RUN apt-get -y update && apt-get -y upgrade +``` + +- **Purpose**: Start with a clean base image and disable interactive + installation prompts + +- **When to customize**: Only change the base image or version if your project + has specific requirements (different Ubuntu version, specific Python version, + etc.) + +### Stage 2: System Utilities (Ubuntu-based Dockerfiles Only) +```dockerfile +RUN apt install -y --no-install-recommends \ + sudo \ + curl \ + systemctl \ + gnupg \ + git \ + vim +``` + +- **Purpose**: Install essential system tools for development and container + management + +- **When to customize**: Add only if needed for your project + - `postgresql-client`: for database connections + - `graphviz`: for graph visualizations + - `ffmpeg`: for media processing + +- **Best practice**: Use `--no-install-recommends` to keep the image small + +### Stage 3: Python and Build Tools (Ubuntu-based Dockerfiles Only) +```dockerfile +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + python3 \ + python3-pip \ + python3-dev \ + python3-venv \ + && rm -rf /var/lib/apt/lists/* +``` + +- **Purpose**: Install Python 3, pip, and build tools needed for compiled + packages + +- **Why venv**: Creates an isolated Python environment separate from system + Python + +- **When to customize**: Rarely. Only change if you need a specific Python + version (e.g., `python3.11` instead of `python3`) + +### Stage 4: Virtual Environment Setup +```dockerfile +RUN python3 -m venv /opt/venv +ENV PATH="/opt/venv/bin:$PATH" +RUN python -m pip install --upgrade pip +``` + +- **Purpose**: Create and activate an isolated virtual environment for your + project + +- **Why this matters**: Ensures reproducibility and prevents dependency + conflicts across projects + +- **When to customize**: Never. This is a standard best practice + +### Stage 5: Jupyter Installation +```dockerfile +RUN pip install jupyterlab jupyterlab_vim +``` + +- **Purpose**: Install JupyterLab and the Vim keybinding extension for + interactive development + - `jupyterlab`: the main IDE for running notebooks in the browser + - `jupyterlab_vim`: adds Vim-style navigation to notebook cells + +- **Why in Dockerfile, not requirements.txt**: These are infrastructure + packages (the IDE itself), not project-specific dependencies + - Do NOT add `jupyterlab`, `jupyterlab-vim`, or `ipywidgets` to + `requirements.txt`; they are already installed here + +- **When to customize**: + - **Remove** this line if your project doesn't use Jupyter + - **Add more extensions** if needed (e.g., `jupyterlab-git`, + `jupyterlab-variableinspector`) + +### Stage 6: Project Dependencies +```dockerfile +COPY requirements.txt /install/requirements.txt +RUN pip install --no-cache-dir -r /install/requirements.txt +``` + +- **Purpose**: Install your project-specific Python packages + +- **When to customize**: This is the primary place to customize. Define all your + dependencies in `requirements.txt` + +- **Best practice**: + - **Pin all versions**: `numpy==1.24.0` (not `numpy>=1.20.0`) + - **Use `--no-cache-dir`**: Reduces image size by skipping pip cache + - **For complex dependencies**: Use `requirements.in` with `pip-tools` or + `pip-compile` + +- **Example requirements.txt**: + ```text + numpy==1.24.0 + pandas==2.0.0 + scikit-learn==1.2.2 + tensorflow==2.13.0 + ``` + +### Stage 7: Configuration +```dockerfile +COPY etc_sudoers /etc/sudoers +COPY bashrc /root/.bashrc +``` + +- **Purpose**: Apply custom bash configuration and sudo permissions + +- **When to customize**: + - **Edit `bashrc`**: to add aliases, environment variables, or custom prompt + - **Edit `etc_sudoers`**: if additional users need passwordless sudo access + +### Stage 8: Version Logging +```dockerfile +ADD version.sh /install/ +RUN /install/version.sh 2>&1 | tee version.log +``` + +- **Purpose**: Document the exact versions of Python, pip, Jupyter, and all + installed packages + +- **What it logs**: + - Python 3 version + - Pip version + - Jupyter version + - Complete list of all installed Python packages + +- **Why it matters**: Creates a detailed record of your container's environment + for troubleshooting and reproducibility + +- **How to use**: After building, review `version.log` to verify all + dependencies installed correctly + ```bash + > docker build -t my-project . + > cat version.log + ``` + +- **Extending it**: If you need to log additional tools (MongoDB, Node.js, + etc.), add them to `version.sh`: + ```bash + > echo "# mongo" + > mongod --version + ``` + +### Stage 9: Port Declaration +```dockerfile +EXPOSE 8888 +``` + +- **Purpose**: Declare that the container uses port 8888 (informational for + Docker) + +- **When to customize**: Add additional ports if your application needs them + (e.g., `EXPOSE 8888 5432 3000`) + +## Best Practices: Keep It Simple + +### The Core Principle +Only change what's necessary for your project. Everything else should inherit +from the template. + +This approach: + +- Makes Dockerfiles easier to understand and maintain +- Keeps images smaller and faster to build +- Simplifies future updates from the template +- Ensures consistency across similar projects + +### How to Do It Right +| What | Where | Example | +| :--------------------------- | :--------------------------- | :------------------------------ | +| Project Python packages | `requirements.txt` | `numpy==1.24.0` | +| Jupyter + Vim (always there) | Dockerfile Stage 5 | `jupyterlab jupyterlab_vim` | +| System tools | Dockerfile `apt-get` section | `postgresql-client` | +| Shell aliases | `bashrc` | `alias jlab="jupyter lab"` | +| Custom scripts | `scripts/` directory | Setup or initialization scripts | +| User permissions | `etc_sudoers` | Grant passwordless sudo | + +- **Do NOT add to `requirements.txt`**: `jupyterlab`, `jupyterlab-vim`, + `jupyterlab_vim`, or `ipywidgets` — these are Jupyter infrastructure packages + and are already installed in Stage 5 of the Dockerfile + +### Wrong Vs. Right Approach +- **Wrong**: Embed everything in the Dockerfile + ```dockerfile + RUN pip install my-package && python my_setup.py && npm install + ``` + +- **Right**: Use separate files and keep Dockerfile clean + ```dockerfile + COPY requirements.txt /install/ + RUN pip install -r /install/requirements.txt + COPY scripts/setup.sh /install/ + RUN /install/setup.sh + ``` + +## .Dockerignore Policy + +### Why It Matters +The `.dockerignore` file prevents unnecessary files from being added to the +Docker build context: + +- **Reduces build time**: Fewer files to transfer to Docker daemon +- **Reduces image size**: Only necessary files are included +- **Improves security**: Prevents leaking sensitive data + +### What to Exclude: Category Breakdown +- Python Artifacts (Always Exclude) + ```verbatim + __pycache__/ + *.pyc + *.pyo + *.pyd + ``` + - Why: Compiled bytecode generated at runtime. Regenerated in container, adds + bloat + +- Virtual Environments (Always Exclude) + ```verbatim + venv/ + .venv/ + env/ + .env/ + ``` + - Why: Local venvs aren't portable to containers. The Dockerfile creates its + own + +- Jupyter Checkpoints (Always Exclude) + ```verbatim + .ipynb_checkpoints/ + ``` + - Why: Auto-generated by Jupyter, not needed in the image + +- Git and Version Control (Always Exclude) + ```verbatim + .git/ + .gitignore + .gitattributes + ``` + - Why: Repository history not needed at runtime + +- Docker Build Scripts (Always Exclude) + ```verbatim + docker_build.sh + docker_push.sh + docker_clean.sh + docker_exec.sh + docker_cmd.sh + docker_bash.sh + docker_jupyter.sh + docker_name.sh + Dockerfile.* + ``` + - Why: Local development scripts don't run inside the container + +- Large Data Files (Recommended) + ```verbatim + data/ + *.csv + *.pkl + *.h5 + *.parquet + ``` + - Why: Don't ship large training and test data in the image. Mount via volume + instead + - Best practice: `bash > docker run -v /path/to/data:/data my-image ` + +- Test Files (Project-Dependent) + ```verbatim + tests/ + tutorials/ + ``` + - Why: Exclude if tests don't run in the container + - When to include: If CI and CD runs tests inside the container + +- Documentation (Recommended) + ```verbatim + README.md + docs/ + *.md + ``` + - Why: Not needed at runtime + - Exception: Only keep if your app reads these files at runtime + +- Generated Files (Always Exclude) + ```verbatim + *.log + *.tmp + *.cache + build/ + dist/ + ``` + - Why: Generated at runtime, not needed in the image + +## Workflow: From Template to Your Project + +### Complete Setup Checklist +- Copy the template + ```bash + > cp -r project_template my-new-project + > cd my-new-project + ``` + +- Keep all reference Dockerfiles + ```verbatim + Dockerfile.ubuntu_24_04 + Dockerfile.python_slim + Dockerfile.uv + ``` + +- Create your working Dockerfile + ```bash + > cp Dockerfile.ubuntu_24_04 Dockerfile + ``` + +- Add your dependencies + ```bash + > pip freeze > requirements.txt + ``` + +- Configure `.dockerignore`: Review the template `.dockerignore` and add your + project-specific exclusions (e.g., data directories) + +- Test the build + ```bash + > docker build -t my-project:latest . + > docker run -it my-project:latest bash + ``` + +- Test Jupyter (if using) + ```bash + > ./docker_jupyter.sh -p 8888 + ``` + +- Document customizations in your project README: + - Base image chosen and why + - Key dependencies + - Any Dockerfile modifications + - How to build and run + +## Maintaining Your Setup + +### Document Any Changes +- If you modify the Dockerfile, add explanatory comments: + ```dockerfile + # Custom: PostgreSQL client for database access + postgresql-client \ + + # Custom: Node.js for frontend builds + nodejs \ + ``` + +### Monitor Package Versions +- After each build, review `version.log`: + ```bash + > docker build -t my-project . + > cat version.log + ``` + +### Keep `.dockerignore` Updated +- If you add new directories or files, update `.dockerignore`. Add to + `.dockerignore` if the directory shouldn't be in the image: + ```verbatim + data/ + cache/ + .temp/ + ``` + +### Contribute Improvements Back +When you improve your project's Docker setup: + +- Test thoroughly in your project +- Document the improvement clearly +- Submit back to `project_template` +- Other projects can adopt it when they update + +Example improvements: + +- Better way to install TensorFlow with GPU support +- Optimized `.dockerignore` for data science projects +- Security hardening (non-root user setup) + +## Troubleshooting + +### Build Is Slow +- Check `.dockerignore`: Ensure large directories (data/, .git/) are excluded +- Check Docker daemon: Verify Docker is running properly +- Check layer caching: Docker reuses cached layers; avoid changing early layers + +### Image Is Too Large +- Check layer sizes: + ```bash + > docker history my-project:latest + ``` + +- Remove unnecessary packages or use `python_slim` base image + +### Package Not Found Error +- Verify package name in PyPI (packages are case-sensitive) +- Check Python version compatibility +- Pin specific version if needed + +### Permission Issues in Container +- Check `etc_sudoers`: Ensure user has appropriate permissions +- Check file ownership: Ensure COPY doesn't create root-only files + +### Jupyter Won't Connect +- Run Jupyter + ```bash + > ./docker_jupyter.sh -p 8888 + ``` + +- Verify http://localhost:8888 (not https). Check firewall if remote access + needed + +### Vim Keybindings Not Working +- If `run_jupyter.sh` exits with `ERROR: jupyterlab_vim is not installed`, it + means `jupyterlab_vim` is missing from the container image +- Make sure `jupyterlab_vim` is installed in the Dockerfile: + ```dockerfile + RUN pip install jupyterlab jupyterlab_vim + ``` +- Rebuild the image after adding the package: + ```bash + > ./docker_build.sh + ``` diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/bashrc b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/bashrc new file mode 100644 index 000000000..4b7ff4c49 --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/bashrc @@ -0,0 +1 @@ +set -o vi diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/copy_docker_files.py b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/copy_docker_files.py new file mode 100644 index 000000000..0e97c194c --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/copy_docker_files.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python + +""" +Copy Docker-related files from the source directory to a destination directory. + +This script copies all Docker configuration and utility files from +class_project/project_template/ to a specified destination directory. + +Usage examples: + # Copy all files to a target directory. + > ./copy_docker_files.py --dst_dir /path/to/destination + + # Copy with verbose logging. + > ./copy_docker_files.py --dst_dir /path/to/destination -v DEBUG + +Import as: + +import class_project.project_template.copy_docker_files as cpdccodo +""" + +import argparse +import logging +import os +from typing import List + +import helpers.hdbg as hdbg +import helpers.hio as hio +import helpers.hparser as hparser +import helpers.hsystem as hsystem + +_LOG = logging.getLogger(__name__) + +# ############################################################################# +# Constants +# ############################################################################# + +# List of files to copy from the source directory. +_FILES_TO_COPY = [ + "bashrc", + "docker_bash.sh", + "docker_build.sh", + "docker_clean.sh", + "docker_cmd.sh", + "docker_exec.sh", + "docker_jupyter.sh", + "docker_name.sh", + "docker_push.sh", + "etc_sudoers", + "install_jupyter_extensions.sh", + "run_jupyter.sh" + "version.sh", +] + + +# ############################################################################# +# Helper functions +# ############################################################################# + + +def _get_source_dir() -> str: + """ + Get the absolute path to the source directory containing Docker files. + + :return: absolute path to class_project/project_template/ + """ + # Get the directory where this script is located. + script_dir = os.path.dirname(os.path.abspath(__file__)) + _LOG.debug("Script directory='%s'", script_dir) + return script_dir + + +def _copy_files( + *, + src_dir: str, + dst_dir: str, + files: List[str], +) -> None: + """ + Copy specified files from source directory to destination directory. + + :param src_dir: source directory path + :param dst_dir: destination directory path + :param files: list of filenames to copy + """ + # Verify source directory exists. + hdbg.dassert_dir_exists(src_dir, "Source directory does not exist:", src_dir) + # Create destination directory if it doesn't exist. + hio.create_dir(dst_dir, incremental=True) + _LOG.info("Copying %d files from '%s' to '%s'", len(files), src_dir, dst_dir) + # Copy each file. + copied_count = 0 + for filename in files: + src_path = os.path.join(src_dir, filename) + dst_path = os.path.join(dst_dir, filename) + # Verify source file exists. + hdbg.dassert_path_exists( + src_path, "Source file does not exist:", src_path + ) + # Copy the file using cp -a to preserve all permissions and attributes. + _LOG.debug("Copying '%s' -> '%s'", src_path, dst_path) + cmd = f"cp -a {src_path} {dst_path}" + hsystem.system(cmd) + copied_count += 1 + # + _LOG.info("Successfully copied %d files", copied_count) + + +# ############################################################################# + + +def _parse() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + parser.add_argument( + "--dst_dir", + action="store", + required=True, + help="Destination directory where files will be copied", + ) + hparser.add_verbosity_arg(parser) + return parser + + +def _main(parser: argparse.ArgumentParser) -> None: + args = parser.parse_args() + hdbg.init_logger(verbosity=args.log_level, use_exec_path=True) + # Get source directory. + src_dir = _get_source_dir() + # Copy files to destination. + _copy_files( + src_dir=src_dir, + dst_dir=args.dst_dir, + files=_FILES_TO_COPY, + ) + + +if __name__ == "__main__": + _main(_parse()) diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_bash.sh b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_bash.sh new file mode 100755 index 000000000..0025e81f4 --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_bash.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# """ +# This script launches a Docker container with an interactive bash shell for +# development. +# """ + +# Exit immediately if any command exits with a non-zero status. +set -e + +# Import the utility functions from the project template. +GIT_ROOT=$(git rev-parse --show-toplevel) +source $GIT_ROOT/class_project/project_template/utils.sh + +# Parse default args (-h, -v) and enable set -x if -v is passed. +parse_default_args "$@" + +# Load Docker configuration variables for this script. +get_docker_vars_script ${BASH_SOURCE[0]} +source $DOCKER_NAME +print_docker_vars + +# List the available Docker images matching the expected image name. +run "docker image ls $FULL_IMAGE_NAME" + +# Configure and run the Docker container with interactive bash shell. +# - Container is removed automatically on exit (--rm) +# - Interactive mode with TTY allocation (-ti) +# - Port forwarding for Jupyter or other services +# - Git root mounted to /git_root inside container +CONTAINER_NAME=${IMAGE_NAME}_bash +PORT= +DOCKER_CMD=$(get_docker_bash_command) +DOCKER_CMD_OPTS=$(get_docker_bash_options $CONTAINER_NAME $PORT) +run "$DOCKER_CMD $DOCKER_CMD_OPTS $FULL_IMAGE_NAME" diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_build.sh b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_build.sh new file mode 100755 index 000000000..5b0957a99 --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_build.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# """ +# Build a Docker container image for the project. +# +# This script sets up the build environment with error handling and command +# tracing, loads Docker configuration from docker_name.sh, and builds the +# Docker image using the build_container_image utility function. It supports +# both single-architecture and multi-architecture builds via the +# DOCKER_BUILD_MULTI_ARCH environment variable. +# """ + +# Exit immediately if any command exits with a non-zero status. +set -e + +# Import the utility functions. +GIT_ROOT=$(git rev-parse --show-toplevel) +source $GIT_ROOT/class_project/project_template/utils.sh + +# Parse default args (-h, -v) and enable set -x if -v is passed. +# Shift processed option flags so remaining args are passed to the build. +parse_default_args "$@" +shift $((OPTIND-1)) + +# Load Docker configuration variables (REPO_NAME, IMAGE_NAME, FULL_IMAGE_NAME). +get_docker_vars_script ${BASH_SOURCE[0]} +source $DOCKER_NAME +print_docker_vars + +# Configure Docker build settings. +# Enable BuildKit for improved build performance and features. +export DOCKER_BUILDKIT=1 +#export DOCKER_BUILDKIT=0 + +# Configure single-architecture build (set to 1 for multi-arch build). +#export DOCKER_BUILD_MULTI_ARCH=1 +export DOCKER_BUILD_MULTI_ARCH=0 + +# Build the container image. +# Pass extra arguments (e.g., --no-cache) via command line after -v. +build_container_image "$@" diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_build.version.log b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_build.version.log new file mode 100644 index 000000000..8315eefe2 --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_build.version.log @@ -0,0 +1 @@ +the input device is not a TTY diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_clean.sh b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_clean.sh new file mode 100755 index 000000000..7e40839ae --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_clean.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# """ +# Remove Docker container image for the project. +# +# This script cleans up Docker images by removing the container image +# matching the project configuration. Useful for freeing disk space or +# ensuring a fresh build. +# """ + +# Exit immediately if any command exits with a non-zero status. +set -e + +# Import the utility functions. +GIT_ROOT=$(git rev-parse --show-toplevel) +source $GIT_ROOT/class_project/project_template/utils.sh + +# Parse default args (-h, -v) and enable set -x if -v is passed. +parse_default_args "$@" + +# Load Docker configuration variables for this script. +get_docker_vars_script ${BASH_SOURCE[0]} +source $DOCKER_NAME +print_docker_vars + +# Remove the container image. +remove_container_image diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_cmd.sh b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_cmd.sh new file mode 100755 index 000000000..906d7a77b --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_cmd.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# """ +# Execute a command in a Docker container. +# +# This script runs a specified command inside a new Docker container instance. +# The container is removed automatically after the command completes. The +# git root is mounted to /git_root inside the container. +# """ + +# Exit immediately if any command exits with a non-zero status. +set -e + +# Import the utility functions. +GIT_ROOT=$(git rev-parse --show-toplevel) +source $GIT_ROOT/class_project/project_template/utils.sh + +# Parse default args (-h, -v) and enable set -x if -v is passed. +# Shift processed option flags so remaining args form the command. +parse_default_args "$@" +shift $((OPTIND-1)) + +# Capture the command to execute from remaining arguments. +CMD="$@" +echo "Executing: '$CMD'" + +# Load Docker configuration variables for this script. +get_docker_vars_script ${BASH_SOURCE[0]} +source $DOCKER_NAME +print_docker_vars + +# List available Docker images matching the expected image name. +run "docker image ls $FULL_IMAGE_NAME" +#(docker manifest inspect $FULL_IMAGE_NAME | grep arch) || true + +# Configure and run the Docker container with the specified command. +CONTAINER_NAME=$IMAGE_NAME +DOCKER_CMD=$(get_docker_cmd_command) +PORT="" +DOCKER_RUN_OPTS="" +DOCKER_CMD_OPTS=$(get_docker_bash_options $CONTAINER_NAME $PORT $DOCKER_RUN_OPTS) +run "$DOCKER_CMD $DOCKER_CMD_OPTS $FULL_IMAGE_NAME bash -c '$CMD'" diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_exec.sh b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_exec.sh new file mode 100755 index 000000000..24f8e401a --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_exec.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# """ +# Execute a bash shell in a running Docker container. +# +# This script connects to an already running Docker container and opens an +# interactive bash session for debugging or inspection purposes. +# """ + +# Exit immediately if any command exits with a non-zero status. +set -e + +# Import the utility functions. +GIT_ROOT=$(git rev-parse --show-toplevel) +source $GIT_ROOT/class_project/project_template/utils.sh + +# Parse default args (-h, -v) and enable set -x if -v is passed. +parse_default_args "$@" + +# Load Docker configuration variables for this script. +get_docker_vars_script ${BASH_SOURCE[0]} +source $DOCKER_NAME +print_docker_vars + +# Execute bash shell in the running container. +exec_container diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_jupyter.sh b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_jupyter.sh new file mode 100755 index 000000000..1a60dfd3a --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_jupyter.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# """ +# Execute Jupyter Lab in a Docker container. +# +# This script launches a Docker container running Jupyter Lab with +# configurable port, directory mounting, and vim bindings. It passes +# command-line options to the run_jupyter.sh script inside the container. +# +# Usage: +# > docker_jupyter.sh [options] +# """ + +# Exit immediately if any command exits with a non-zero status. +set -e + +# Import the utility functions. +GIT_ROOT=$(git rev-parse --show-toplevel) +source $GIT_ROOT/class_project/project_template/utils.sh + +# Parse command-line options and set Jupyter configuration variables. +parse_docker_jupyter_args "$@" + +# Load Docker configuration variables for this script. +get_docker_vars_script ${BASH_SOURCE[0]} +source $DOCKER_NAME +print_docker_vars + +# List available Docker images and inspect architecture. +list_and_inspect_docker_image + +# Run the Docker container with Jupyter Lab. +CMD=$(get_run_jupyter_cmd "${BASH_SOURCE[0]}" "$OLD_CMD_OPTS") +CONTAINER_NAME=$IMAGE_NAME +# Kill existing container if -f flag is set. +kill_existing_container_if_forced + +DOCKER_CMD=$(get_docker_jupyter_command) +DOCKER_CMD_OPTS=$(get_docker_jupyter_options $CONTAINER_NAME $JUPYTER_HOST_PORT $JUPYTER_USE_VIM) +run "$DOCKER_CMD $DOCKER_CMD_OPTS $FULL_IMAGE_NAME $CMD" diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_name.sh b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_name.sh new file mode 100644 index 000000000..32a546cf3 --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_name.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# """ +# Docker image naming configuration. +# +# This file defines the repository name, image name, and full image name +# variables used by all docker_*.sh scripts in the project template. +# """ + +REPO_NAME=gpsaggese +# The file should be all lower case. +IMAGE_NAME=umd_project_template +FULL_IMAGE_NAME=$REPO_NAME/$IMAGE_NAME diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_push.sh b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_push.sh new file mode 100755 index 000000000..27d752dd9 --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/docker_push.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# """ +# Push Docker container image to Docker Hub or registry. +# +# This script authenticates with the Docker registry using credentials from +# ~/.docker/passwd.$REPO_NAME.txt and pushes the locally built container +# image to the remote repository. +# """ + +# Exit immediately if any command exits with a non-zero status. +set -e + +# Import the utility functions. +GIT_ROOT=$(git rev-parse --show-toplevel) +source $GIT_ROOT/class_project/project_template/utils.sh + +# Parse default args (-h, -v) and enable set -x if -v is passed. +parse_default_args "$@" + +# Load Docker image naming configuration. +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source $SCRIPT_DIR/docker_name.sh + +# Push the container image to the registry. +push_container_image diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/etc_sudoers b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/etc_sudoers new file mode 100644 index 000000000..ee0816a15 --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/etc_sudoers @@ -0,0 +1,31 @@ +# +# This file MUST be edited with the 'visudo' command as root. +# +# Please consider adding local content in /etc/sudoers.d/ instead of +# directly modifying this file. +# +# See the man page for details on how to write a sudoers file. +# +Defaults env_reset +Defaults mail_badpass +Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin" + +# Host alias specification + +# User alias specification + +# Cmnd alias specification + +# User privilege specification +root ALL=(ALL:ALL) ALL + +# Members of the admin group may gain root privileges +%admin ALL=(ALL) ALL + +# Allow members of group sudo to execute any command +%sudo ALL=(ALL:ALL) ALL + +# See sudoers(5) for more information on "#include" directives: +postgres ALL=(ALL) NOPASSWD:ALL + +#includedir /etc/sudoers.d diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/requirements.txt b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/requirements.txt new file mode 100644 index 000000000..49aca3901 --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/requirements.txt @@ -0,0 +1,4 @@ +matplotlib +numpy +pandas +seaborn diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/run_jupyter.sh b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/run_jupyter.sh new file mode 100755 index 000000000..d725c3fe7 --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/run_jupyter.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# """ +# Launch Jupyter Lab server. +# +# This script starts Jupyter Lab on port 8888 with the following configuration: +# - No browser auto-launch (useful for Docker containers) +# - Accessible from any IP address (0.0.0.0) +# - Root user allowed (required for Docker environments) +# - No authentication token or password (for development convenience) +# - Vim keybindings can be enabled via JUPYTER_USE_VIM environment variable +# """ + +# Exit immediately if any command exits with a non-zero status. +set -e + +# Print each command to stdout before executing it. +#set -x + +# Import the utility functions from /git_root. +GIT_ROOT=/git_root +source $GIT_ROOT/class_project/project_template/utils.sh + +# Load Docker configuration variables for this script. +get_docker_vars_script ${BASH_SOURCE[0]} +source $DOCKER_NAME +print_docker_vars + +# Setup Jupyter Lab environment. +setup_jupyter_environment + +# Initialize Jupyter Lab command with base configuration. +JUPYTER_ARGS=$(get_jupyter_args) + +# Start Jupyter Lab with development-friendly settings. +run "jupyter lab $JUPYTER_ARGS" diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template.API.ipynb b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template.API.ipynb new file mode 100644 index 000000000..3afca937c --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template.API.ipynb @@ -0,0 +1,215 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "183c2248-ea3d-43ba-b87e-d821bba1bbc6", + "metadata": {}, + "source": [ + "# Template API Notebook\n", + "\n", + "This is a template notebook. The first heading should be the title of what notebook is about. For example, if it is a neo4j tutorial the heading should be `Neo4j API`.\n", + "\n", + "- Add description of what the notebook does.\n", + "- Point to references, e.g. (neo4j.API.md)\n", + "- Add citations.\n", + "- Keep the notebook flow clear.\n", + "- Comments should be imperative and have a period at the end.\n", + "- Your code should be well commented.\n", + "\n", + "The name of this notebook should in the following format:\n", + "- if the notebook is exploring `pycaret API`, then it is `pycaret.API.ipynb`\n", + "\n", + "Follow the reference to write notebooks in a clear manner: https://github.com/causify-ai/helpers/blob/master/docs/coding/all.jupyter_notebook.how_to_guide.md" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "265e0d58-a7cd-4edf-a0b4-96b60220e801", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The autoreload extension is already loaded. To reload it, use:\n", + " %reload_ext autoreload\n" + ] + } + ], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "id": "d3b2f997-5c9b-4238-b6d5-e5f2cea43809", + "metadata": {}, + "source": [ + "## Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "d1480ee9-d6a6-437d-b927-da6cbb05bdf5", + "metadata": {}, + "outputs": [], + "source": [ + "import logging\n", + "# Import libraries in this section.\n", + "# Avoid imports like import *, from ... import ..., from ... import *, etc.\n", + "\n", + "import helpers.hdbg as hdbg\n", + "import helpers.hnotebook as hnotebo" + ] + }, + { + "cell_type": "markdown", + "id": "f9208cc9-837d-4fec-a312-9c4aa5b7648d", + "metadata": {}, + "source": [ + "## Configuration" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "9a2d7a9c-c6c5-48c9-8445-11c97045d00b", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[0mWARNING: Running in Jupyter\n", + "INFO > cmd='/venv/lib/python3.12/site-packages/ipykernel_launcher.py -f /home/.local/share/jupyter/runtime/kernel-085a2ce7-6161-4c8a-92d5-492051832f3c.json'\n" + ] + } + ], + "source": [ + "hdbg.init_logger(verbosity=logging.INFO)\n", + "\n", + "_LOG = logging.getLogger(__name__)\n", + "\n", + "hnotebo.config_notebook()" + ] + }, + { + "cell_type": "markdown", + "id": "79c37ba3-bd5d-4a44-87df-645eee54977a", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "## Make the notebook flow clear\n", + "Each notebook needs to follow a clear and logical flow, e.g:\n", + "- Load data\n", + "- Compute stats\n", + "- Clean data\n", + "- Compute stats\n", + "- Do analysis\n", + "- Show results\n", + "\n", + "\n", + "\n", + "\n", + "#############################################################################\n", + "Template\n", + "#############################################################################" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "a8a109cd-fc8e-4b9e-9dc0-4fc8d4126ad8", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "class Template:\n", + " \"\"\"\n", + " Brief imperative description of what the class does in one line, if needed.\n", + " \"\"\"\n", + "\n", + " def __init__(self):\n", + " pass\n", + "\n", + " def method1(self, arg1: int) -> None:\n", + " \"\"\"\n", + " Brief imperative description of what the method does in one line.\n", + "\n", + " You can elaborate more in the method docstring in this section, for e.g. explaining\n", + " the formula/algorithm. Every method/function should have a docstring, typehints and include the\n", + " parameters and return as follows:\n", + "\n", + " :param arg1: description of arg1\n", + " :return: description of return\n", + " \"\"\"\n", + " # Code bloks go here.\n", + " # Make sure to include comments to explain what the code is doing.\n", + " # No empty lines between code blocks.\n", + " pass\n", + "\n", + "\n", + "def template_function(arg1: int) -> None:\n", + " \"\"\"\n", + " Brief imperative description of what the function does in one line.\n", + "\n", + " You can elaborate more in the function docstring in this section, for e.g. explaining\n", + " the formula/algorithm. Every function should have a docstring, typehints and include the\n", + " parameters and return as follows:\n", + "\n", + " :param arg1: description of arg1\n", + " :return: description of return\n", + " \"\"\"\n", + " # Code bloks go here.\n", + " # Make sure to include comments to explain what the code is doing.\n", + " # No empty lines between code blocks.\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "id": "00926523-ae59-497d-bba8-b22e58333849", + "metadata": {}, + "source": [ + "## The flow should be highlighted using headings in markdown\n", + "```\n", + "# Level 1\n", + "## Level 2\n", + "### Level 3\n", + "```" + ] + } + ], + "metadata": { + "jupytext": { + "formats": "ipynb,py:percent" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template.API.py b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template.API.py new file mode 100644 index 000000000..4192ef8fe --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template.API.py @@ -0,0 +1,129 @@ +# --- +# jupyter: +# jupytext: +# formats: ipynb,py:percent +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.19.0 +# kernelspec: +# display_name: Python 3 (ipykernel) +# language: python +# name: python3 +# --- + +# %% [markdown] +# # Template API Notebook +# +# This is a template notebook. The first heading should be the title of what notebook is about. For example, if it is a neo4j tutorial the heading should be `Neo4j API`. +# +# - Add description of what the notebook does. +# - Point to references, e.g. (neo4j.API.md) +# - Add citations. +# - Keep the notebook flow clear. +# - Comments should be imperative and have a period at the end. +# - Your code should be well commented. +# +# The name of this notebook should in the following format: +# - if the notebook is exploring `pycaret API`, then it is `pycaret.API.ipynb` +# +# Follow the reference to write notebooks in a clear manner: https://github.com/causify-ai/helpers/blob/master/docs/coding/all.jupyter_notebook.how_to_guide.md + +# %% +# %load_ext autoreload +# %autoreload 2 +# %matplotlib inline + +# %% [markdown] +# ## Imports + +# %% +import logging +# Import libraries in this section. +# Avoid imports like import *, from ... import ..., from ... import *, etc. + +import helpers.hdbg as hdbg +import helpers.hnotebook as hnotebo + +# %% [markdown] +# ## Configuration + +# %% +hdbg.init_logger(verbosity=logging.INFO) + +_LOG = logging.getLogger(__name__) + +hnotebo.config_notebook() + + +# %% [markdown] +# ## Make the notebook flow clear +# Each notebook needs to follow a clear and logical flow, e.g: +# - Load data +# - Compute stats +# - Clean data +# - Compute stats +# - Do analysis +# - Show results +# +# +# +# + + +# ############################################################################# +# Template +# ############################################################################# + + +# %% +class Template: + """ + Brief imperative description of what the class does in one line, if needed. + """ + + def __init__(self): + pass + + def method1(self, arg1: int) -> None: + """ + Brief imperative description of what the method does in one line. + + You can elaborate more in the method docstring in this section, for e.g. explaining + the formula/algorithm. Every method/function should have a docstring, typehints and include the + parameters and return as follows: + + :param arg1: description of arg1 + :return: description of return + """ + # Code bloks go here. + # Make sure to include comments to explain what the code is doing. + # No empty lines between code blocks. + pass + + +def template_function(arg1: int) -> None: + """ + Brief imperative description of what the function does in one line. + + You can elaborate more in the function docstring in this section, for e.g. explaining + the formula/algorithm. Every function should have a docstring, typehints and include the + parameters and return as follows: + + :param arg1: description of arg1 + :return: description of return + """ + # Code bloks go here. + # Make sure to include comments to explain what the code is doing. + # No empty lines between code blocks. + pass + + +# %% [markdown] +# ## The flow should be highlighted using headings in markdown +# ``` +# # Level 1 +# ## Level 2 +# ### Level 3 +# ``` diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template.example.ipynb b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template.example.ipynb new file mode 100644 index 000000000..a2e9aedd7 --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template.example.ipynb @@ -0,0 +1,198 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "50f78f7e-2dee-45d6-9d37-7a55eeaae283", + "metadata": {}, + "source": [ + "# Template Example Notebook\n", + "\n", + "This is a template notebook. The first heading should be the title of what notebook is about. For example, if it is a project on neo4j tutorial the heading should be `Project Title`.\n", + "\n", + "- Add description of what the notebook does.\n", + "- Point to references, e.g. (neo4j.example.md)\n", + "- Add citations.\n", + "- Keep the notebook flow clear.\n", + "- Comments should be imperative and have a period at the end.\n", + "- Your code should be well commented.\n", + "\n", + "The name of this notebook should in the following format:\n", + "- if the notebook is exploring `pycaret API`, then it is `pycaret.example.ipynb`\n", + "\n", + "Follow the reference to write notebooks in a clear manner: https://github.com/causify-ai/helpers/blob/master/docs/coding/all.jupyter_notebook.how_to_guide.md" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "6226667e-cab5-479c-be6a-6b7d6f580a97", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "8020901a-4bc7-4b73-95e8-aaa462b4fc19", + "metadata": {}, + "outputs": [], + "source": [ + "import logging\n", + "# Import libraries in this section.\n", + "# Avoid imports like import *, from ... import ..., from ... import *, etc.\n", + "\n", + "import helpers.hdbg as hdbg\n", + "import helpers.hnotebook as hnotebo" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "4ecb72b2-b21d-4fb0-ac92-e7174da390e6", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[0mWARNING: Running in Jupyter\n", + "INFO > cmd='/venv/lib/python3.12/site-packages/ipykernel_launcher.py -f /home/.local/share/jupyter/runtime/kernel-783e0930-1631-4d64-8bb4-f3a98bb74fcd.json'\n" + ] + } + ], + "source": [ + "hdbg.init_logger(verbosity=logging.INFO)\n", + "\n", + "_LOG = logging.getLogger(__name__)\n", + "\n", + "hnotebo.config_notebook()" + ] + }, + { + "cell_type": "markdown", + "id": "1ede6422-bff2-4f0a-8d28-29a01d4786b2", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "## Make the notebook flow clear\n", + "Each notebook needs to follow a clear and logical flow, e.g:\n", + "- Load data\n", + "- Compute stats\n", + "- Clean data\n", + "- Compute stats\n", + "- Do analysis\n", + "- Show results\n", + "\n", + "\n", + "\n", + "\n", + "#############################################################################\n", + "Template\n", + "#############################################################################" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "8bbd660d-d22f-44fa-bf53-dd622dee0f53", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "class Template:\n", + " \"\"\"\n", + " Brief imperative description of what the class does in one line, if needed.\n", + " \"\"\"\n", + "\n", + " def __init__(self):\n", + " pass\n", + "\n", + " def method1(self, arg1: int) -> None:\n", + " \"\"\"\n", + " Brief imperative description of what the method does in one line.\n", + "\n", + " You can elaborate more in the method docstring in this section, for e.g. explaining\n", + " the formula/algorithm. Every method/function should have a docstring, typehints and include the\n", + " parameters and return as follows:\n", + "\n", + " :param arg1: description of arg1\n", + " :return: description of return\n", + " \"\"\"\n", + " # Code bloks go here.\n", + " # Make sure to include comments to explain what the code is doing.\n", + " # No empty lines between code blocks.\n", + " pass\n", + "\n", + "\n", + "def template_function(arg1: int) -> None:\n", + " \"\"\"\n", + " Brief imperative description of what the function does in one line.\n", + "\n", + " You can elaborate more in the function docstring in this section, for e.g. explaining\n", + " the formula/algorithm. Every function should have a docstring, typehints and include the\n", + " parameters and return as follows:\n", + "\n", + " :param arg1: description of arg1\n", + " :return: description of return\n", + " \"\"\"\n", + " # Code bloks go here.\n", + " # Make sure to include comments to explain what the code is doing.\n", + " # No empty lines between code blocks.\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "id": "103f6e36-54cf-442c-b137-8091d48805a7", + "metadata": {}, + "source": [ + "## The flow should be highlighted using headings in markdown\n", + "```\n", + "# Level 1\n", + "## Level 2\n", + "### Level 3\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d05d52af-67ba-4a4f-a561-af453e43854f", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "jupytext": { + "formats": "ipynb,py:percent" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template.example.py b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template.example.py new file mode 100644 index 000000000..8566ff277 --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template.example.py @@ -0,0 +1,125 @@ +# --- +# jupyter: +# jupytext: +# formats: ipynb,py:percent +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.19.0 +# kernelspec: +# display_name: Python 3 (ipykernel) +# language: python +# name: python3 +# --- + +# %% [markdown] +# # Template Example Notebook +# +# This is a template notebook. The first heading should be the title of what notebook is about. For example, if it is a project on neo4j tutorial the heading should be `Project Title`. +# +# - Add description of what the notebook does. +# - Point to references, e.g. (neo4j.example.md) +# - Add citations. +# - Keep the notebook flow clear. +# - Comments should be imperative and have a period at the end. +# - Your code should be well commented. +# +# The name of this notebook should in the following format: +# - if the notebook is exploring `pycaret API`, then it is `pycaret.example.ipynb` +# +# Follow the reference to write notebooks in a clear manner: https://github.com/causify-ai/helpers/blob/master/docs/coding/all.jupyter_notebook.how_to_guide.md + +# %% +# %load_ext autoreload +# %autoreload 2 +# %matplotlib inline + +# %% +import logging +# Import libraries in this section. +# Avoid imports like import *, from ... import ..., from ... import *, etc. + +import helpers.hdbg as hdbg +import helpers.hnotebook as hnotebo + +# %% +hdbg.init_logger(verbosity=logging.INFO) + +_LOG = logging.getLogger(__name__) + +hnotebo.config_notebook() + + +# %% [markdown] +# ## Make the notebook flow clear +# Each notebook needs to follow a clear and logical flow, e.g: +# - Load data +# - Compute stats +# - Clean data +# - Compute stats +# - Do analysis +# - Show results +# +# +# +# + + +# ############################################################################# +# Template +# ############################################################################# + + +# %% +class Template: + """ + Brief imperative description of what the class does in one line, if needed. + """ + + def __init__(self): + pass + + def method1(self, arg1: int) -> None: + """ + Brief imperative description of what the method does in one line. + + You can elaborate more in the method docstring in this section, for e.g. explaining + the formula/algorithm. Every method/function should have a docstring, typehints and include the + parameters and return as follows: + + :param arg1: description of arg1 + :return: description of return + """ + # Code bloks go here. + # Make sure to include comments to explain what the code is doing. + # No empty lines between code blocks. + pass + + +def template_function(arg1: int) -> None: + """ + Brief imperative description of what the function does in one line. + + You can elaborate more in the function docstring in this section, for e.g. explaining + the formula/algorithm. Every function should have a docstring, typehints and include the + parameters and return as follows: + + :param arg1: description of arg1 + :return: description of return + """ + # Code bloks go here. + # Make sure to include comments to explain what the code is doing. + # No empty lines between code blocks. + pass + + +# %% [markdown] +# ## The flow should be highlighted using headings in markdown +# ``` +# # Level 1 +# ## Level 2 +# ### Level 3 +# ``` + +# %% diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template_utils.py b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template_utils.py new file mode 100644 index 000000000..f8916102e --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/template_utils.py @@ -0,0 +1,72 @@ +""" +template_utils.py + +This file contains utility functions that support the tutorial notebooks. + +- Notebooks should call these functions instead of writing raw logic inline. +- This helps keep the notebooks clean, modular, and easier to debug. +- Students should implement functions here for data preprocessing, + model setup, evaluation, or any reusable logic. + +Import as: + +import class_project.project_template.template_utils as cpptteut +""" + +import pandas as pd +import logging +from sklearn.model_selection import train_test_split +from pycaret.classification import compare_models + +# ----------------------------------------------------------------------------- +# Logging +# ----------------------------------------------------------------------------- + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +# ----------------------------------------------------------------------------- +# Example 1: Split the dataset into train and test sets +# ----------------------------------------------------------------------------- + + +def split_data(df: pd.DataFrame, target_column: str, test_size: float = 0.2): + """ + Split the dataset into training and testing sets. + + :param df: full dataset + :param target_column: name of the target column + :param test_size: proportion of test data (default = 0.2) + + :return: X_train, X_test, y_train, y_test + """ + logger.info("Splitting data into train and test sets") + X = df.drop(columns=[target_column]) + y = df[target_column] + return train_test_split(X, y, test_size=test_size, random_state=42) + + +# ----------------------------------------------------------------------------- +# Example 2: PyCaret classification pipeline +# ----------------------------------------------------------------------------- + + +def run_pycaret_classification( + df: pd.DataFrame, target_column: str +) -> pd.DataFrame: + """ + Run a basic PyCaret classification experiment. + + :param df: dataset containing features and target + :param target_column: name of the target column + + :return: comparison of top-performing models + """ + logger.info("Initializing PyCaret classification setup") + ... + + logger.info("Comparing models") + results = compare_models() + ... + + return results diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/test/test_docker_all.py b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/test/test_docker_all.py new file mode 100644 index 000000000..904cdd7af --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/test/test_docker_all.py @@ -0,0 +1,48 @@ +""" +Run each notebook in class_project/project_template/ inside Docker using docker_cmd.sh. + +Import as: + +import class_project.project_template.test.test_docker_all as tptdal +""" + +import logging + +import pytest + +import helpers.hdocker_tests as hdoctest + +_LOG = logging.getLogger(__name__) + + +# ############################################################################# +# Test_docker +# ############################################################################# + + +class Test_docker(hdoctest.DockerTestCase): + """ + Run all Docker tests for class_project/project_template/. + """ + + _test_file = __file__ + + @pytest.mark.slow + def test1(self) -> None: + """ + Test that template.example.ipynb runs without error inside Docker. + """ + # Prepare inputs. + notebook_name = "template.example.ipynb" + # Run test. + self._helper(notebook_name) + + @pytest.mark.slow + def test2(self) -> None: + """ + Test that template.API.ipynb runs without error inside Docker. + """ + # Prepare inputs. + notebook_name = "template.API.ipynb" + # Run test. + self._helper(notebook_name) diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/utils.sh b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/utils.sh new file mode 100644 index 000000000..cc0ed8c4a --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/utils.sh @@ -0,0 +1,607 @@ +#!/bin/bash +# """ +# Utility functions for Docker container management. +# """ + + +# ############################################################################# +# General utilities +# ############################################################################# + + +run() { + # """ + # Execute a command with echo output. + # + # :param cmd: Command string to execute + # :return: Exit status of the executed command + # """ + cmd="$*" + echo "> $cmd" + eval "$cmd" +} + + +enable_verbose_mode() { + # """ + # Enable shell command tracing (set -x) when VERBOSE is set to 1. + # + # Reads the VERBOSE variable set by parse_docker_jupyter_args. + # Call this after parsing args to activate tracing for the rest of the script. + # """ + if [[ $VERBOSE == 1 ]]; then + set -x + fi +} + + +# ############################################################################# +# Argument parsing +# ############################################################################# + + +_print_default_help() { + # """ + # Print usage information and available default options for docker scripts. + # """ + echo "Usage: $(basename $0) [options]" + echo "" + echo "Options:" + echo " -f Force kill existing container with same name before starting" + echo " -h Print this help message and exit" + echo " -v Enable verbose output (set -x)" +} + + +parse_default_args() { + # """ + # Parse default command-line arguments for docker scripts. + # + # Sets VERBOSE and FORCE variables in the caller's scope. Enables set -x + # when -v is passed. Prints help and exits when -h is passed. + # Updates OPTIND so the caller can shift away processed arguments. + # + # :param @: command-line arguments forwarded from the calling script + # """ + VERBOSE=0 + FORCE=0 + while getopts "fhv" flag; do + case "${flag}" in + f) FORCE=1;; + h) _print_default_help; exit 0;; + v) VERBOSE=1;; + *) _print_default_help; exit 1;; + esac + done + enable_verbose_mode +} + + +_print_docker_jupyter_help() { + # """ + # Print usage information and available options for docker_jupyter.sh. + # """ + echo "Usage: $(basename $0) [options]" + echo "" + echo "Launch Jupyter Lab inside a Docker container." + echo "" + echo "Options:" + echo " -f Force kill existing container with same name before starting" + echo " -h Print this help message and exit" + echo " -p PORT Host port to forward to Jupyter Lab (default: 8888)" + echo " -u Enable vim keybindings in Jupyter Lab" + echo " -v Enable verbose output (set -x)" +} + + +parse_docker_jupyter_args() { + # """ + # Parse command-line arguments for docker_jupyter.sh. + # + # Sets JUPYTER_HOST_PORT, JUPYTER_USE_VIM, TARGET_DIR, VERBOSE, FORCE, and + # OLD_CMD_OPTS in the caller's scope. Enables set -x when -v is passed. + # Prints help and exits when -h is passed. + # + # :param @: command-line arguments forwarded from the calling script + # """ + # Set defaults. + JUPYTER_HOST_PORT=8888 + JUPYTER_USE_VIM=0 + VERBOSE=0 + FORCE=0 + # Save original args to pass through to run_jupyter.sh. + OLD_CMD_OPTS="$*" + # Parse options. + while getopts "fhp:uv" flag; do + case "${flag}" in + f) FORCE=1;; + h) _print_docker_jupyter_help; exit 0;; + p) JUPYTER_HOST_PORT=${OPTARG};; # Port for Jupyter Lab. + u) JUPYTER_USE_VIM=1;; # Enable vim bindings. + v) VERBOSE=1;; # Enable verbose output. + *) _print_docker_jupyter_help; exit 1;; + esac + done + # Enable command tracing if verbose mode is requested. + enable_verbose_mode +} + + +# ############################################################################# +# Docker image management +# ############################################################################# + + +get_docker_vars_script() { + # """ + # Load Docker variables from docker_name.sh script. + # + # :param script_path: Path to the script to determine the Docker configuration directory + # :return: Sources REPO_NAME, IMAGE_NAME, and FULL_IMAGE_NAME variables + # """ + local script_path=$1 + # Find the name of the container. + SCRIPT_DIR=$(dirname $script_path) + DOCKER_NAME="$SCRIPT_DIR/docker_name.sh" + if [[ ! -e $SCRIPT_DIR ]]; then + echo "Can't find $DOCKER_NAME" + exit -1 + fi; + source $DOCKER_NAME +} + + +print_docker_vars() { + # """ + # Print current Docker variables to stdout. + # """ + echo "REPO_NAME=$REPO_NAME" + echo "IMAGE_NAME=$IMAGE_NAME" + echo "FULL_IMAGE_NAME=$FULL_IMAGE_NAME" +} + + +build_container_image() { + # """ + # Build a Docker container image. + # + # Supports both single-architecture and multi-architecture builds. + # Creates temporary build directory, copies files, and builds the image. + # + # :param @: Additional options to pass to docker build/buildx build + # """ + echo "# ${FUNCNAME[0]} ..." + FULL_IMAGE_NAME=$REPO_NAME/$IMAGE_NAME + echo "FULL_IMAGE_NAME=$FULL_IMAGE_NAME" + # Prepare build area. + #tar -czh . | docker build $OPTS -t $IMAGE_NAME - + DIR="../tmp.build" + if [[ -d $DIR ]]; then + rm -rf $DIR + fi; + cp -Lr . $DIR || true + # Build container. + echo "DOCKER_BUILDKIT=$DOCKER_BUILDKIT" + echo "DOCKER_BUILD_MULTI_ARCH=$DOCKER_BUILD_MULTI_ARCH" + if [[ $DOCKER_BUILD_MULTI_ARCH != 1 ]]; then + # Build for a single architecture. + echo "Building for current architecture..." + OPTS="--progress plain $@" + (cd $DIR; docker build $OPTS -t $FULL_IMAGE_NAME . 2>&1 | tee ../docker_build.log; exit ${PIPESTATUS[0]}) + else + # Build for multiple architectures. + echo "Building for multiple architectures..." + OPTS="$@" + export DOCKER_CLI_EXPERIMENTAL=enabled + # Create a new builder. + #docker buildx rm --all-inactive --force + #docker buildx create --name mybuilder + #docker buildx use mybuilder + # Use the default builder. + docker buildx use multiarch + docker buildx inspect --bootstrap + # Note that one needs to push to the repo since otherwise it is not + # possible to keep multiple. + (cd $DIR; docker buildx build --push --platform linux/arm64,linux/amd64 $OPTS --tag $FULL_IMAGE_NAME . 2>&1 | tee ../docker_build.log; exit ${PIPESTATUS[0]}) + # Report the status. + docker buildx imagetools inspect $FULL_IMAGE_NAME + fi; + # Report build version. + if [ -f docker_build.version.log ]; then + rm docker_build.version.log + fi + (cd $DIR; docker run --rm -it -v $(pwd):/data $FULL_IMAGE_NAME bash -c "/data/version.sh") 2>&1 | tee docker_build.version.log + # + docker image ls $REPO_NAME/$IMAGE_NAME + rm -rf $DIR + echo "*****************************" + echo "SUCCESS" + echo "*****************************" +} + + +remove_container_image() { + # """ + # Remove Docker container image(s) matching the current configuration. + # """ + echo "# ${FUNCNAME[0]} ..." + FULL_IMAGE_NAME=$REPO_NAME/$IMAGE_NAME + echo "FULL_IMAGE_NAME=$FULL_IMAGE_NAME" + docker image ls | grep $FULL_IMAGE_NAME + docker image ls | grep $FULL_IMAGE_NAME | awk '{print $1}' | xargs -n 1 -t docker image rm -f + docker image ls + echo "${FUNCNAME[0]} ... done" +} + + +push_container_image() { + # """ + # Push Docker container image to registry. + # + # Authenticates using credentials from ~/.docker/passwd.$REPO_NAME.txt. + # """ + echo "# ${FUNCNAME[0]} ..." + FULL_IMAGE_NAME=$REPO_NAME/$IMAGE_NAME + echo "FULL_IMAGE_NAME=$FULL_IMAGE_NAME" + docker login --username $REPO_NAME --password-stdin <~/.docker/passwd.$REPO_NAME.txt + docker images $FULL_IMAGE_NAME + docker push $FULL_IMAGE_NAME + echo "${FUNCNAME[0]} ... done" +} + + +pull_container_image() { + # """ + # Pull Docker container image from registry. + # """ + echo "# ${FUNCNAME[0]} ..." + FULL_IMAGE_NAME=$REPO_NAME/$IMAGE_NAME + echo "FULL_IMAGE_NAME=$FULL_IMAGE_NAME" + docker pull $FULL_IMAGE_NAME + echo "${FUNCNAME[0]} ... done" +} + + +# ############################################################################# +# Docker container management +# ############################################################################# + + +kill_container() { + # """ + # Kill and remove Docker container(s) matching the current configuration. + # """ + echo "# ${FUNCNAME[0]} ..." + FULL_IMAGE_NAME=$REPO_NAME/$IMAGE_NAME + echo "FULL_IMAGE_NAME=$FULL_IMAGE_NAME" + docker container ls + # + CONTAINER_ID=$(docker container ls -a | grep $FULL_IMAGE_NAME | awk '{print $1}') + echo "CONTAINER_ID=$CONTAINER_ID" + if [[ ! -z $CONTAINER_ID ]]; then + docker container rm -f $CONTAINER_ID + docker container ls + fi; + echo "${FUNCNAME[0]} ... done" +} + + +kill_container_by_name() { + # """ + # Kill and remove a Docker container by its name. + # + # :param container_name: Name of the container to kill + # """ + local container_name=$1 + echo "# ${FUNCNAME[0]}: $container_name" + # Check if container exists (running or stopped). + local container_id=$(docker container ls -a --filter "name=^${container_name}$" --format "{{.ID}}") + if [[ -n $container_id ]]; then + echo "Killing container: $container_name (ID: $container_id)" + docker container rm -f $container_id + else + echo "Container '$container_name' not found" + fi + echo "${FUNCNAME[0]} ... done" +} + + +exec_container() { + # """ + # Execute bash shell in running Docker container. + # + # Opens an interactive bash session in the first container matching the + # current configuration. + # """ + echo "# ${FUNCNAME[0]} ..." + FULL_IMAGE_NAME=$REPO_NAME/$IMAGE_NAME + echo "FULL_IMAGE_NAME=$FULL_IMAGE_NAME" + docker container ls + # + CONTAINER_ID=$(docker container ls -a | grep $FULL_IMAGE_NAME | awk '{print $1}') + echo "CONTAINER_ID=$CONTAINER_ID" + docker exec -it $CONTAINER_ID bash + echo "${FUNCNAME[0]} ... done" +} + + +# ############################################################################# +# Docker common options +# ############################################################################# + + +get_docker_common_options() { + # """ + # Return docker run options common to all container types. + # + # Includes volume mount for the git root, plus environment variables for + # PYTHONPATH and host OS name. + # + # :return: docker run options string with volume mounts and env vars + # """ + echo "-v $GIT_ROOT:/git_root \ + -e PYTHONPATH=/git_root:/git_root/helpers_root:/git_root/msml610/tutorials \ + -e CSFY_GIT_ROOT_PATH=/git_root \ + -e CSFY_HOST_OS_NAME=$(uname -s) \ + -e CSFY_HOST_NAME=$(uname -n)" +} + + +# ############################################################################# +# Docker bash +# ############################################################################# + + +get_docker_bash_command() { + # """ + # Return the base docker run command for an interactive bash shell. + # + # :return: docker run command string with --rm and -ti flags + # """ + if [ -t 0 ]; then + echo "docker run --rm -ti" + else + echo "docker run --rm -i" + fi +} + + +get_docker_bash_options() { + # """ + # Return docker run options for a Docker container. + # + # :param container_name: Name for the Docker container + # :param port: Port number to forward (optional, skipped if empty) + # :param extra_opts: Additional docker run options (optional) + # :return: docker run options string with name, volume mounts, and env vars + # """ + local container_name=$1 + local port=$2 + local extra_opts=$3 + local port_opt="" + if [[ -n $port ]]; then + port_opt="-p $port:$port" + fi + echo "--name $container_name \ + $port_opt \ + $extra_opts \ + $(get_docker_common_options)" +} + + +# ############################################################################# +# Docker cmd +# ############################################################################# + + +get_docker_cmd_command() { + # """ + # Return the base docker run command for executing a non-interactive command. + # + # :return: docker run command string with --rm and -i flags + # """ + echo "docker run --rm -i" +} + + +# ############################################################################# +# Docker Jupyter +# ############################################################################# + + +get_docker_jupyter_command() { + # """ + # Return the base docker run command for running Jupyter Lab interactively. + # + # :return: docker run command string with --rm and -ti flags (if TTY available) + # """ + local docker_cmd="docker run --rm" + # Add interactive and TTY flags only if stdin is a TTY. + if [[ -t 0 ]]; then + docker_cmd="$docker_cmd -ti" + fi + echo "$docker_cmd" +} + + +get_docker_jupyter_options() { + # """ + # Return docker run options for a Jupyter Lab container. + # + # :param container_name: Name for the Docker container + # :param host_port: Host port to forward to container port 8888 + # :param jupyter_use_vim: 0 or 1 to enable vim bindings + # :return: docker run options string + # """ + local container_name=$1 + local host_port=$2 + local jupyter_use_vim=$3 + # Run as the current user when user is saggese. + if [[ "$(whoami)" == "saggese" ]]; then + echo "Overwriting jupyter_use_vim since user='saggese'" >&2 + jupyter_use_vim=1 + fi + echo "--name $container_name \ + -p $host_port:8888 \ + $(get_docker_common_options) \ + -e JUPYTER_USE_VIM=$jupyter_use_vim" +} + + +configure_jupyter_vim_keybindings() { + # """ + # Configure JupyterLab vim keybindings based on JUPYTER_USE_VIM env var. + # + # Reads JUPYTER_USE_VIM; if 1, verifies jupyterlab_vim is installed and + # writes enabled settings; otherwise writes disabled settings. + # """ + mkdir -p ~/.jupyter/lab/user-settings/@axlair/jupyterlab_vim + if [[ $JUPYTER_USE_VIM == 1 ]]; then + # Check that jupyterlab_vim is installed before trying to enable it. + if ! pip show jupyterlab_vim > /dev/null 2>&1; then + echo "ERROR: jupyterlab_vim is not installed but vim bindings were requested." + echo "Install it with: pip install jupyterlab_vim" + exit 1 + fi + echo "Enabling vim." + cat < ~/.jupyter/lab/user-settings/\@axlair/jupyterlab_vim/plugin.jupyterlab-settings +{ + "enabled": true, + "enabledInEditors": true, + "extraKeybindings": [], + "autosaveInterval": 6 +} +EOF + else + echo "Disabling vim." + cat < ~/.jupyter/lab/user-settings/\@axlair/jupyterlab_vim/plugin.jupyterlab-settings +{ + "enabled": false, + "enabledInEditors": false, + "extraKeybindings": [], + "autosaveInterval": 6 +} +EOF + fi; +} + + +configure_jupyter_notifications() { + # """ + # Disable JupyterLab news fetching and update checks. + # """ + mkdir -p ~/.jupyter/lab/user-settings/@jupyterlab/apputils-extension + cat < ~/.jupyter/lab/user-settings/\@jupyterlab/apputils-extension/notification.jupyterlab-settings +{ + // Notifications + // @jupyterlab/apputils-extension:notification + // Notifications settings. + + // Fetch official Jupyter news + // Whether to fetch news from the Jupyter news feed. If Always (`true`), it will make a request to a website. + "fetchNews": "false", + "checkForUpdates": false +} +EOF +} + + +configure_jupyter_autosave() { + # """ + # Configure JupyterLab global autosave interval to 6 seconds. + # """ + mkdir -p ~/.jupyter/lab/user-settings/@jupyterlab/docmanager-extension + cat < ~/.jupyter/lab/user-settings/\@jupyterlab/docmanager-extension/plugin.jupyterlab-settings +{ + "autosaveInterval": 6 +} +EOF +} + + +check_jupytext_installed() { + # """ + # Verify that jupytext is installed before starting Jupyter Lab. + # + # Jupytext is required for pair notebook/Python file functionality. + # Exits with error if jupytext is not installed. + # """ + if ! pip show jupytext > /dev/null 2>&1; then + echo "ERROR: jupytext is not installed but is required to run Jupyter Lab." + echo "Install it with: pip install jupytext" + exit 1 + fi +} + + +setup_jupyter_environment() { + # """ + # Configure Jupyter Lab environment before launching. + # + # Performs all necessary setup steps: + # - Configure vim keybindings + # - Disable notifications + # - Configure autosave interval + # - Verify jupytext is installed + # """ + configure_jupyter_vim_keybindings + configure_jupyter_notifications + configure_jupyter_autosave + check_jupytext_installed +} + + +get_jupyter_args() { + # """ + # Print the standard Jupyter Lab command-line arguments. + # + # :return: space-separated Jupyter Lab args for port 8888 with no browser, + # allow root, and no authentication + # """ + echo "--port=8888 --no-browser --ip=0.0.0.0 --allow-root --ServerApp.token='' --ServerApp.password=''" +} + + +get_run_jupyter_cmd() { + # """ + # Return the command to run run_jupyter.sh inside a container. + # + # Computes the script's path relative to GIT_ROOT and builds the + # corresponding /git_root/... path used inside the container. + # + # :param script_path: path of the calling script (pass ${BASH_SOURCE[0]}) + # :param cmd_opts: options to forward to run_jupyter.sh + # :return: full command string to run run_jupyter.sh + # """ + local script_path=$1 + local cmd_opts=$2 + local script_dir + script_dir=$(cd "$(dirname "$script_path")" && pwd) + local rel_dir="${script_dir#${GIT_ROOT}/}" + echo "/git_root/${rel_dir}/run_jupyter.sh $cmd_opts" +} + + +list_and_inspect_docker_image() { + # """ + # List available Docker images and inspect their architecture. + # + # Lists all images matching FULL_IMAGE_NAME and attempts to inspect + # their architecture using docker manifest inspect. + # """ + run "docker image ls $FULL_IMAGE_NAME" + (docker manifest inspect $FULL_IMAGE_NAME | grep arch) || true +} + + +kill_existing_container_if_forced() { + # """ + # Kill existing container if FORCE flag is set. + # + # If FORCE is set to 1, kills and removes the container with name + # CONTAINER_NAME. This is typically set by the -f flag. + # """ + if [[ $FORCE == 1 ]]; then + kill_container_by_name $CONTAINER_NAME + fi +} diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/version.sh b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/version.sh new file mode 100755 index 000000000..c46ed254c --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/version.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# """ +# Display versions of installed tools and packages. +# +# This script prints version information for Python, pip, Jupyter, and all +# installed Python packages. Used for debugging and documentation purposes +# to verify the Docker container environment setup. +# """ + +# Display Python 3 version. +echo "# Python3" +python3 --version + +# Display pip version. +echo "# pip3" +pip3 --version + +# Display Jupyter version. +echo "# jupyter" +jupyter --version + +# List all installed Python packages and their versions. +echo "# Python packages" +pip3 list + +# Template for adding additional tool versions. +# echo "# mongo" +# mongod --version From 6b754228632137693f1217efdc93c2bd0b03cf57 Mon Sep 17 00:00:00 2001 From: jbaffoeb Date: Fri, 8 May 2026 14:21:47 -0400 Subject: [PATCH 2/8] Added ReadME --- .../README.md | 812 +----------------- 1 file changed, 20 insertions(+), 792 deletions(-) diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/README.md b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/README.md index 58d90e2d1..5cd5df9fe 100644 --- a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/README.md +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/README.md @@ -1,802 +1,30 @@ -# Summary -This directory contains a Docker-based development environment template with: +# DataPrep Tutorial +This project demonstrates how to use DataPrep (Python) for data analysis, specifically to predict the California Housing Dataset target variable (MedHouseVal) -- Utility scripts for Docker operations (build, run, clean, push) -- Configuration files for Dockerfile and environment setup -- Jupyter notebook templates for standardized project development -- Shell utilities and Python helpers for container-based workflows - -A guide to set up Docker-based projects using the template, customize it for -your needs, and maintain it over time. - -## Description of Files -- `bashrc` - - Bash configuration file enabling `vi` mode for command-line editing - -- `copy_docker_files.py` - - Python script for copying Docker configuration files to destination - directories - -- `docker_build.version.log` - - Log file containing Python, `pip`, Jupyter, and package version information - from Docker build - -- `docker_cmd.sh` - - Shell script for executing arbitrary commands inside Docker containers with - volume mounting - -- `docker_jupyter.sh` - - Shell script for launching Jupyter Lab server inside Docker containers - -- `docker_name.sh` - - Configuration file defining Docker repository and image naming variables - -- `Dockerfile` - - Docker image build configuration with Ubuntu, Python, Jupyter, and project - dependencies - -- `etc_sudoers` - - Sudoers configuration file granting passwordless sudo access for postgres - user - -- `README.md` - - Documentation file describing directory contents, files, and executable - scripts - -- `template_utils.py` - - Python utility functions supporting tutorial notebooks with data processing - and modeling helpers - -- `template.API.ipynb` - - Jupyter notebook template for API exploration and library usage examples - -- `template.example.ipynb` - - Jupyter notebook template for project examples and demonstrations - -- `utils.sh` - - Bash utility library with reusable functions for Docker operations - - Provides centralized argument parsing (`parse_default_args`) for `-h` and - `-v` flags used by all `docker_*.sh` scripts - - Provides Jupyter configuration logic: vim keybindings, notification - settings, and Docker run option builders - - All `docker_*.sh`, `docker_jupyter.sh`, and `run_jupyter.sh` scripts across - the repo source this file from `class_project/project_template/utils.sh` - -## Workflows -- All commands should be run from inside the project directory - ```bash - > cd tutorials/FilterPy - ``` - -- To build the container for a project - ```bash - > cd $PROJECT - # Build the container. - > docker_build.sh - # Build without cache (pass extra args after -v). - > docker_build.sh --no-cache - # Test the container. - > docker_bash.sh ls - ``` - -- Enable verbose (trace) output with `-v` - ```bash - > docker_build.sh -v - > docker_bash.sh -v - ``` - -- Get help for any docker script - ```bash - > docker_build.sh -h - > docker_jupyter.sh -h - ``` - -- Start Jupyter - ```bash - > docker_jupyter.sh - # Go to localhost:8888 - ``` - -- Start Jupyter on a specific port with vim support - ```bash - > docker_jupyter.sh -p 8890 -u - # Go to localhost:8890 - ``` - -## How to Customize a Project Template -- Copy the template - ```bash - > cp -r class_project/project_template $TARGET - ``` - -## Description of Executables - -### `copy_docker_files.py` -- **What It Does** - - Copies Docker configuration and utility files from project_template to a - destination directory - - Preserves all file permissions and attributes during copying - - Creates destination directory if it doesn't exist - -- Copy all Docker files to a target directory: - ```bash - > ./copy_docker_files.py --dst_dir /path/to/destination - ``` - -- Copy with verbose logging: - ```bash - > ./copy_docker_files.py --dst_dir /path/to/destination -v DEBUG - ``` - -### `docker_bash.sh` -- **What It Does** - - Launches an interactive bash shell inside a Docker container - - Mounts the current working directory as `/data` inside the container - - Exposes port 8888 for potential services running in the container - - Accepts `-h` (help) and `-v` (verbose/trace) flags via `parse_default_args` - -- Launch bash shell in the container: - ```bash - > ./docker_bash.sh - ``` - -- Launch with verbose output (prints each command): - ```bash - > ./docker_bash.sh -v - ``` - -### `docker_build.sh` -- **What It Does** - - Builds Docker container images using Docker BuildKit - - Supports single-architecture builds (default) or multi-architecture builds - (`linux/arm64`, `linux/amd64`) - - Copies project files to temporary build directory and generates build logs - - Accepts `-h` (help) and `-v` (verbose/trace) flags; any extra arguments - after flags are forwarded to `docker build` - -- Build container image for current architecture: - ```bash - > ./docker_build.sh - ``` - -- Build without Docker layer cache: - ```bash - > ./docker_build.sh --no-cache - ``` - -- Build multi-architecture image (requires setting `DOCKER_BUILD_MULTI_ARCH=1` - in the script): - ```bash - > # Edit docker_build.sh to set DOCKER_BUILD_MULTI_ARCH=1 +Quick Start +From the directory, build the docker image +```bash > ./docker_build.sh ``` - -### `docker_clean.sh` -- **What It Does** - -- Removes all Docker images matching the project's full image name -- Lists images before and after removal for verification -- Uses force removal to ensure cleanup completes - -- Remove project's Docker images: - ```bash - > ./docker_clean.sh - ``` - -### `docker_cmd.sh` -- **What It Does** - - Executes arbitrary commands inside a Docker container - - Mounts current directory as `/data` for accessing project files - - Automatically removes container after command execution completes - - Accepts `-h` (help) and `-v` (verbose/trace) flags; remaining arguments - form the command to execute - -- Run Python script inside container: - ```bash - > ./docker_cmd.sh python script.py --arg value - ``` - -- List files in the container: - ```bash - > ./docker_cmd.sh ls -la /data - ``` - -- Run tests inside container: - ```bash - > ./docker_cmd.sh pytest tests/ - ``` - -### `docker_exec.sh` -- **What It Does** - - Attaches to an already running Docker container with an interactive bash - shell - - Finds the container ID automatically based on the image name - - Useful for debugging or inspecting running containers - - Accepts `-h` (help) and `-v` (verbose/trace) flags via `parse_default_args` - -- Attach to running container: - ```bash - > ./docker_exec.sh - ``` - -### `docker_jupyter.sh` -- **What It Does** - - Launches Jupyter Lab server inside a Docker container - - Supports custom port configuration (default 8888), vim keybindings, and - custom directory mounting - - Runs `run_jupyter.sh` script inside the container with specified options - -- Start Jupyter on default port 8888: - ```bash - > ./docker_jupyter.sh - ``` - -- Start Jupyter on custom port with vim bindings: - ```bash - > ./docker_jupyter.sh -p 8889 -u - ``` - -- Start Jupyter with external directory mounted: - ```bash - > ./docker_jupyter.sh -d /path/to/notebooks -p 8889 - ``` - -- Start Jupyter in verbose mode: - ```bash - > ./docker_jupyter.sh -v -p 8890 - ``` - -### `docker_push.sh` -- **What It Does** - - Authenticates to Docker registry using credentials from - `~/.docker/passwd.$REPO_NAME.txt` - - Pushes the project's Docker image to the remote repository - - Lists images before pushing for verification - -- Push container image to registry: - ```bash - > ./docker_push.sh - ``` - -### `run_jupyter.sh` -- **What It Does** - - Launches Jupyter Lab server with no authentication (token and password - disabled) - - Binds to all network interfaces (0.0.0.0) on port 8888 - - Allows root access for container environments - - When `JUPYTER_USE_VIM=1`, verifies that `jupyterlab_vim` is installed - before enabling vim keybindings; exits with an error if not found - -- Start Jupyter Lab server (typically called from docker_jupyter.sh): - ```bash - > ./run_jupyter.sh - ``` - -- Start with vim keybindings (requires `jupyterlab_vim` installed in the - container): - ```bash - > JUPYTER_USE_VIM=1 ./run_jupyter.sh - ``` - -### `utils.sh` -- **What It Does** - - Central Bash library sourced by all `docker_*.sh` and `run_jupyter.sh` - scripts across the repository - - Provides `parse_default_args` which adds `-h` (help) and `-v` - (verbose/`set -x`) flags to every docker script - - Provides `build_container_image`, `push_container_image`, - `remove_container_image`, `kill_container`, `exec_container` utilities - - Provides Jupyter configuration helpers: vim keybindings, notification - suppression, and Docker run option builders - -### `version.sh` -- **What It Does** - - Reports version information for Python3, pip3, and Jupyter - - Lists all installed Python packages with versions - - Used during Docker image builds to log environment configuration - -- Display version information: - ```bash - > ./version.sh - ``` - -- Save version information to a log file: - ```bash - > ./version.sh 2>&1 | tee version.log - ``` - -# Template Customization and Maintenance - -## Quick Start for New Projects - -### Step 1: Copy the Template +Open Jupyter Lab ```bash -> cd class_project/project_template -> cp -r . /path/to/your/new/project -> cd /path/to/your/new/project -``` - -### Step 2: Choose a Base Image -The template includes three Dockerfile options. Choose the one that best fits -your project: - -| Option | File | Best For | -| -------------------------- | ------------------------ | ---------------------------------------------------------------- | -| **Standard** | `Dockerfile.ubuntu` | Full Ubuntu environment with system tools | -| **Lightweight** | `Dockerfile.python_slim` | Minimal Python environment; reduced image size | -| **Modern Package Manager** | `Dockerfile.uv` | Fast dependency resolution with [uv](https://docs.astral.sh/uv/) | - -**How to choose:** - -- **Use Standard** if you need system-level tools (git, curl, graphviz, etc.) -- **Use Python Slim** to minimize image size and build time -- **Use uv** if you want faster, more reliable dependency management - -### Step 3: Set Up Your Dockerfile -- Delete unused reference files - ```bash - > rm Dockerfile.ubuntu Dockerfile.python_slim Dockerfile.uv - ``` - -- Create your working Dockerfile - ```bash - > cp Dockerfile.ubuntu Dockerfile - ``` - -- Add your dependencies - ```bash - > echo "numpy\npandas\nscikit-learn" > requirements.in - > pip-compile requirements.in > requirements.txt - ``` - -### Step 4: Keep Customization Minimal -- Only modify what's necessary for your project -- Use `requirements.txt` for all Python packages (don't edit Dockerfile for - this) -- Keep `bashrc` and `etc_sudoers` as-is unless you need custom shell setup -- Keep base image and Python version unless you have specific requirements - -## Understanding the Dockerfile Flow -Each Dockerfile follows the same structure. Here are the key stages: - -### Stage 1: Base Image and System Setup -```dockerfile -FROM ubuntu:24.04 # or python:3.12-slim, depending on your requirement -ENV DEBIAN_FRONTEND noninteractive -RUN apt-get -y update && apt-get -y upgrade -``` - -- **Purpose**: Start with a clean base image and disable interactive - installation prompts - -- **When to customize**: Only change the base image or version if your project - has specific requirements (different Ubuntu version, specific Python version, - etc.) - -### Stage 2: System Utilities (Ubuntu-based Dockerfiles Only) -```dockerfile -RUN apt install -y --no-install-recommends \ - sudo \ - curl \ - systemctl \ - gnupg \ - git \ - vim -``` - -- **Purpose**: Install essential system tools for development and container - management - -- **When to customize**: Add only if needed for your project - - `postgresql-client`: for database connections - - `graphviz`: for graph visualizations - - `ffmpeg`: for media processing - -- **Best practice**: Use `--no-install-recommends` to keep the image small - -### Stage 3: Python and Build Tools (Ubuntu-based Dockerfiles Only) -```dockerfile -RUN apt-get update && apt-get install -y --no-install-recommends \ - build-essential \ - python3 \ - python3-pip \ - python3-dev \ - python3-venv \ - && rm -rf /var/lib/apt/lists/* -``` - -- **Purpose**: Install Python 3, pip, and build tools needed for compiled - packages - -- **Why venv**: Creates an isolated Python environment separate from system - Python - -- **When to customize**: Rarely. Only change if you need a specific Python - version (e.g., `python3.11` instead of `python3`) - -### Stage 4: Virtual Environment Setup -```dockerfile -RUN python3 -m venv /opt/venv -ENV PATH="/opt/venv/bin:$PATH" -RUN python -m pip install --upgrade pip -``` - -- **Purpose**: Create and activate an isolated virtual environment for your - project - -- **Why this matters**: Ensures reproducibility and prevents dependency - conflicts across projects - -- **When to customize**: Never. This is a standard best practice - -### Stage 5: Jupyter Installation -```dockerfile -RUN pip install jupyterlab jupyterlab_vim -``` - -- **Purpose**: Install JupyterLab and the Vim keybinding extension for - interactive development - - `jupyterlab`: the main IDE for running notebooks in the browser - - `jupyterlab_vim`: adds Vim-style navigation to notebook cells - -- **Why in Dockerfile, not requirements.txt**: These are infrastructure - packages (the IDE itself), not project-specific dependencies - - Do NOT add `jupyterlab`, `jupyterlab-vim`, or `ipywidgets` to - `requirements.txt`; they are already installed here - -- **When to customize**: - - **Remove** this line if your project doesn't use Jupyter - - **Add more extensions** if needed (e.g., `jupyterlab-git`, - `jupyterlab-variableinspector`) - -### Stage 6: Project Dependencies -```dockerfile -COPY requirements.txt /install/requirements.txt -RUN pip install --no-cache-dir -r /install/requirements.txt -``` - -- **Purpose**: Install your project-specific Python packages - -- **When to customize**: This is the primary place to customize. Define all your - dependencies in `requirements.txt` - -- **Best practice**: - - **Pin all versions**: `numpy==1.24.0` (not `numpy>=1.20.0`) - - **Use `--no-cache-dir`**: Reduces image size by skipping pip cache - - **For complex dependencies**: Use `requirements.in` with `pip-tools` or - `pip-compile` - -- **Example requirements.txt**: - ```text - numpy==1.24.0 - pandas==2.0.0 - scikit-learn==1.2.2 - tensorflow==2.13.0 - ``` - -### Stage 7: Configuration -```dockerfile -COPY etc_sudoers /etc/sudoers -COPY bashrc /root/.bashrc -``` - -- **Purpose**: Apply custom bash configuration and sudo permissions - -- **When to customize**: - - **Edit `bashrc`**: to add aliases, environment variables, or custom prompt - - **Edit `etc_sudoers`**: if additional users need passwordless sudo access - -### Stage 8: Version Logging -```dockerfile -ADD version.sh /install/ -RUN /install/version.sh 2>&1 | tee version.log -``` - -- **Purpose**: Document the exact versions of Python, pip, Jupyter, and all - installed packages - -- **What it logs**: - - Python 3 version - - Pip version - - Jupyter version - - Complete list of all installed Python packages - -- **Why it matters**: Creates a detailed record of your container's environment - for troubleshooting and reproducibility - -- **How to use**: After building, review `version.log` to verify all - dependencies installed correctly - ```bash - > docker build -t my-project . - > cat version.log - ``` - -- **Extending it**: If you need to log additional tools (MongoDB, Node.js, - etc.), add them to `version.sh`: - ```bash - > echo "# mongo" - > mongod --version - ``` - -### Stage 9: Port Declaration -```dockerfile -EXPOSE 8888 -``` - -- **Purpose**: Declare that the container uses port 8888 (informational for - Docker) - -- **When to customize**: Add additional ports if your application needs them - (e.g., `EXPOSE 8888 5432 3000`) - -## Best Practices: Keep It Simple - -### The Core Principle -Only change what's necessary for your project. Everything else should inherit -from the template. - -This approach: - -- Makes Dockerfiles easier to understand and maintain -- Keeps images smaller and faster to build -- Simplifies future updates from the template -- Ensures consistency across similar projects - -### How to Do It Right -| What | Where | Example | -| :--------------------------- | :--------------------------- | :------------------------------ | -| Project Python packages | `requirements.txt` | `numpy==1.24.0` | -| Jupyter + Vim (always there) | Dockerfile Stage 5 | `jupyterlab jupyterlab_vim` | -| System tools | Dockerfile `apt-get` section | `postgresql-client` | -| Shell aliases | `bashrc` | `alias jlab="jupyter lab"` | -| Custom scripts | `scripts/` directory | Setup or initialization scripts | -| User permissions | `etc_sudoers` | Grant passwordless sudo | - -- **Do NOT add to `requirements.txt`**: `jupyterlab`, `jupyterlab-vim`, - `jupyterlab_vim`, or `ipywidgets` — these are Jupyter infrastructure packages - and are already installed in Stage 5 of the Dockerfile - -### Wrong Vs. Right Approach -- **Wrong**: Embed everything in the Dockerfile - ```dockerfile - RUN pip install my-package && python my_setup.py && npm install - ``` - -- **Right**: Use separate files and keep Dockerfile clean - ```dockerfile - COPY requirements.txt /install/ - RUN pip install -r /install/requirements.txt - COPY scripts/setup.sh /install/ - RUN /install/setup.sh - ``` - -## .Dockerignore Policy - -### Why It Matters -The `.dockerignore` file prevents unnecessary files from being added to the -Docker build context: - -- **Reduces build time**: Fewer files to transfer to Docker daemon -- **Reduces image size**: Only necessary files are included -- **Improves security**: Prevents leaking sensitive data - -### What to Exclude: Category Breakdown -- Python Artifacts (Always Exclude) - ```verbatim - __pycache__/ - *.pyc - *.pyo - *.pyd - ``` - - Why: Compiled bytecode generated at runtime. Regenerated in container, adds - bloat - -- Virtual Environments (Always Exclude) - ```verbatim - venv/ - .venv/ - env/ - .env/ - ``` - - Why: Local venvs aren't portable to containers. The Dockerfile creates its - own - -- Jupyter Checkpoints (Always Exclude) - ```verbatim - .ipynb_checkpoints/ - ``` - - Why: Auto-generated by Jupyter, not needed in the image - -- Git and Version Control (Always Exclude) - ```verbatim - .git/ - .gitignore - .gitattributes - ``` - - Why: Repository history not needed at runtime - -- Docker Build Scripts (Always Exclude) - ```verbatim - docker_build.sh - docker_push.sh - docker_clean.sh - docker_exec.sh - docker_cmd.sh - docker_bash.sh - docker_jupyter.sh - docker_name.sh - Dockerfile.* - ``` - - Why: Local development scripts don't run inside the container - -- Large Data Files (Recommended) - ```verbatim - data/ - *.csv - *.pkl - *.h5 - *.parquet - ``` - - Why: Don't ship large training and test data in the image. Mount via volume - instead - - Best practice: `bash > docker run -v /path/to/data:/data my-image ` - -- Test Files (Project-Dependent) - ```verbatim - tests/ - tutorials/ - ``` - - Why: Exclude if tests don't run in the container - - When to include: If CI and CD runs tests inside the container - -- Documentation (Recommended) - ```verbatim - README.md - docs/ - *.md - ``` - - Why: Not needed at runtime - - Exception: Only keep if your app reads these files at runtime - -- Generated Files (Always Exclude) - ```verbatim - *.log - *.tmp - *.cache - build/ - dist/ - ``` - - Why: Generated at runtime, not needed in the image - -## Workflow: From Template to Your Project - -### Complete Setup Checklist -- Copy the template - ```bash - > cp -r project_template my-new-project - > cd my-new-project - ``` - -- Keep all reference Dockerfiles - ```verbatim - Dockerfile.ubuntu_24_04 - Dockerfile.python_slim - Dockerfile.uv - ``` - -- Create your working Dockerfile - ```bash - > cp Dockerfile.ubuntu_24_04 Dockerfile - ``` - -- Add your dependencies - ```bash - > pip freeze > requirements.txt - ``` - -- Configure `.dockerignore`: Review the template `.dockerignore` and add your - project-specific exclusions (e.g., data directories) - -- Test the build - ```bash - > docker build -t my-project:latest . - > docker run -it my-project:latest bash - ``` - -- Test Jupyter (if using) - ```bash > ./docker_jupyter.sh -p 8888 ``` -- Document customizations in your project README: - - Base image chosen and why - - Key dependencies - - Any Dockerfile modifications - - How to build and run - -## Maintaining Your Setup - -### Document Any Changes -- If you modify the Dockerfile, add explanatory comments: - ```dockerfile - # Custom: PostgreSQL client for database access - postgresql-client \ - - # Custom: Node.js for frontend builds - nodejs \ - ``` - -### Monitor Package Versions -- After each build, review `version.log`: - ```bash - > docker build -t my-project . - > cat version.log - ``` - -### Keep `.dockerignore` Updated -- If you add new directories or files, update `.dockerignore`. Add to - `.dockerignore` if the directory shouldn't be in the image: - ```verbatim - data/ - cache/ - .temp/ - ``` - -### Contribute Improvements Back -When you improve your project's Docker setup: - -- Test thoroughly in your project -- Document the improvement clearly -- Submit back to `project_template` -- Other projects can adopt it when they update - -Example improvements: - -- Better way to install TensorFlow with GPU support -- Optimized `.dockerignore` for data science projects -- Security hardening (non-root user setup) +After opening Jupyter in a browser, running the following notebooks (.ipynb) -## Troubleshooting +1. DataPrep.API +- Introduces basic DataPrep uses and documentation +- Shows how to use get_report() to generate data summary +- Shows how to clean data and plot using dataprep -### Build Is Slow -- Check `.dockerignore`: Ensure large directories (data/, .git/) are excluded -- Check Docker daemon: Verify Docker is running properly -- Check layer caching: Docker reuses cached layers; avoid changing early layers -### Image Is Too Large -- Check layer sizes: - ```bash - > docker history my-project:latest - ``` - -- Remove unnecessary packages or use `python_slim` base image - -### Package Not Found Error -- Verify package name in PyPI (packages are case-sensitive) -- Check Python version compatibility -- Pin specific version if needed - -### Permission Issues in Container -- Check `etc_sudoers`: Ensure user has appropriate permissions -- Check file ownership: Ensure COPY doesn't create root-only files - -### Jupyter Won't Connect -- Run Jupyter - ```bash - > ./docker_jupyter.sh -p 8888 - ``` - -- Verify http://localhost:8888 (not https). Check firewall if remote access - needed - -### Vim Keybindings Not Working -- If `run_jupyter.sh` exits with `ERROR: jupyterlab_vim is not installed`, it - means `jupyterlab_vim` is missing from the container image -- Make sure `jupyterlab_vim` is installed in the Dockerfile: - ```dockerfile - RUN pip install jupyterlab jupyterlab_vim - ``` -- Rebuild the image after adding the package: - ```bash - > ./docker_build.sh - ``` +2. DataPrep.example +- loads California Housing Data +- exploratory analyses using Dataprep summary visualizations +- feature engineering for strong model performance +- LinearRegression model trained and evaluated +- More feature engineering according to data spreads as shown in DataPrep visualizations +- LinearRegression 2nd model (attempt higher accuracy) +- RandomForest model deployment and evaluation +- Compare and contrast model performance From fc9f2909b5ed6eb4ed76ed2e5ecd4590d04800ac Mon Sep 17 00:00:00 2001 From: jbaffoeb Date: Fri, 8 May 2026 14:22:45 -0400 Subject: [PATCH 3/8] Add workflow section to README Updated README to reflect workflow section. --- .../README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/README.md b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/README.md index 5cd5df9fe..fb953db22 100644 --- a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/README.md +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/README.md @@ -1,7 +1,8 @@ # DataPrep Tutorial This project demonstrates how to use DataPrep (Python) for data analysis, specifically to predict the California Housing Dataset target variable (MedHouseVal) -Quick Start +# Workflow + From the directory, build the docker image ```bash > ./docker_build.sh From 7f59fc69006b0610232e8c01612749261e966131 Mon Sep 17 00:00:00 2001 From: jbaffoeb Date: Fri, 8 May 2026 16:36:32 -0400 Subject: [PATCH 4/8] Added notebooks --- .../DataPrep.API.ipynb | 207 + .../DataPrep.example.ipynb | 5119 +++++++++++++++++ 2 files changed, 5326 insertions(+) create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.API.ipynb create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.example.ipynb diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.API.ipynb b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.API.ipynb new file mode 100644 index 000000000..089abd721 --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.API.ipynb @@ -0,0 +1,207 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2399a1bb", + "metadata": {}, + "source": [ + "DataPrep lets you prepare your data using a single library with a few lines of code.\n", + "\n", + "Currently, you can use DataPrep to:\n", + "\n", + "Collect data from common data sources (through dataprep.connector)\n", + "Do your exploratory data analysis (through dataprep.eda)\n", + "Clean and standardize data (through dataprep.clean)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "130ec487", + "metadata": {}, + "outputs": [], + "source": [ + "Installation\n", + "pip install -U dataprep\n", + "EDA\n", + "DataPrep.EDA is the fastest and the easiest EDA (Exploratory Data Analysis) tool in Python. It allows you to understand a Pandas/Dask DataFrame with a few lines of code in seconds.\n", + "\n", + "Create Profile Reports, Fast\n", + "You can create a beautiful profile report from a Pandas/Dask DataFrame with the create_report function. DataPrep.EDA has the following advantages compared to other tools:\n", + "\n", + "10X Faster: DataPrep.EDA can be 10X faster than Pandas-based profiling tools due to its highly optimized Dask-based computing module.\n", + "Interactive Visualization: DataPrep.EDA generates interactive visualizations in a report, which makes the report look more appealing to end users.\n", + "Big Data Support: DataPrep.EDA naturally supports big data stored in a Dask cluster by accepting a Dask dataframe as input.\n", + "The following code demonstrates how to use DataPrep.EDA to create a profile report for the titanic dataset.\n", + "\n", + "from dataprep.datasets import load_dataset\n", + "from dataprep.eda import create_report\n", + "df = load_dataset(\"titanic\")\n", + "create_report(df).show_browser()" + ] + }, + { + "attachments": { + "Screenshot%202026-05-08%20at%203.56.37%E2%80%AFAM.png": { + "image/png": "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EEAAAQQQQAABBBBAAIGMKJAjI1aaOiOQkQQuv/xy+++//0JVzp49u5UpU8Zq1qxpl1xyiWXLli00bl8vkpKSbMOGDX6yggUL7mvydB2/detWvx158uSx3Llzx132zz//bM8995xNmTLF1q9fb8cdd5xddtllduutt9rhhx/u59u+fbtt2bLFcuTIYfnz54+7rOgRseZ79dVXbcKECXbFFVdYq1atomfZ6316LGOvhTIAAQQQQACBgyCQlc4phg4dah988IEVLVrU3nnnnXTRHT9+vHXv3t1OOeUUe+qpp1K0zE8//dTee+89q1WrlnXs2DHuPBs3brRdu3b5cx2d61EQQCBBBdwFVYqK+4dO2rFjR5K7CEr6+++/UzQPEyGAQFKSCxgkuX//mD9nn3120l9//ZVipl9//TW0nBTPlE4TXnfddX7dnTt3jrvEH374Ialw4cJ+unz58iUdeeSRofo2aNAg6d9///Xz9unTxw+vV69e3GXFGhFrvmuuucYv64knnog1y17D0mMZey2UAQgggAACCBwEgax0TvHss8/643upUqXSTbZXr15+mTonSWl56aWX/DwXX3xxsrOccMIJfjp3UybZ6RiJAAJpE1AsQjEJxSYUo0htoQlMggamqFbmE7j77rtt9OjR9uGHH9pNN93kMz8mT55s99xzT6bZWN1VWbdunTVs2NDWrFljq1evti+//NJneihLY+LEiem+rW+++aZf54MPPrjfy06PZez3ypkRAQQQQACBVApkhXOKVJKkaPI2bdr4c4YRI0akaHomQgCBzCdAACTz7VO2KEEFlG7ZpEkTu+qqq+ytt94yd0fB17R///6mZiMqy5cvt3bt2lnZsmXNZU9YxYoV7f777zc1P1EK5pVXXumn069zzjnHevTo4d8nN58m0Pz33nuvVahQwY466iirXLmyuUwOc5FTP79+/fLLL9a6dWs78cQT7dRTT7UOHTrYtm3b/Hg1YRk7dqx/rXRUrXvz5s3+ffivpUuX+rdFihSxXLly+dfuLou98sorfn1HHHGETzlVExmV+fPn+2VNmzbNv9eyzzzzTCtevLgdc8wxdu655/rmLRqpVNVY8ynocumll9qgQYP8MpYsWeKbwxx//PFWrFgxn7Lar18/Py6ly9DEMnXZJd4saMaj+gZl3Lhx1qhRI1/PY4891i644AKbNWtW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gAACCCCAAAIIIIAAAggggEBYBJxhbjUI4vw48x40+KHHf6AAiO7A6eriPBL4UBUaAggggAACCCCAAAIIIIAAAgjcj4Az1K0T9HAe72df7ts8cADE2ZkTAHGe84gAAggggAACCCCAAAIIIIAAAgjcr0BEBT6c48d0Jh70MaJP7EHPh+0RQAABBBBAAAEEEEAAAQQQQAABRyC6M8EjAggggAACCCCAAAIIIIAAAggg4K8CBED89ZXluhBAAAEEEEAAAQQQQAABBBBAwCVAAMRFwQQCCCCAAAIIIIAAAggggAACCPirAAEQf31luS4EEEAAAQQQQAABBBBAAAEEEHAJEABxUTCBAAIIIIAAAggggAACCCCAAAL+KkAAxF9fWa4LAQQQQAABBBBAAAEEEEAAAQRcAgRAXBRMIIAAAggggAACCCCAAAIIIICAvwoQAPHXV5brQgABBBBAAAEEEEAAAQQQQAABlwABEBcFEwgggAACCCCAAAIIIIAAAggg4K8CBED89ZXluhBAAAEEEEAAAQQQQAABBBBAwCVAAMRFwQQCCCCAAAIIIIAAAggggAACCPirAAEQf31luS4EEEAAAQQQQAABBBBAAAEEEHAJEABxUTCBAAIIIIAAAggggAACCCCAAAL+KkAAxF9fWa4LAQQQQAABBBBAAAEEEEAAAQRcAgRAXBRMIIAAAggggAACCCCAAAIIIICAvwoQAPHXV5brQgABBBBAAAEEEEAAAQQQQAABlwABEBcFEwgggAACCCCAAAIIIIAAAggg4K8CBED89ZXluhBAAAEEEEAAAQQQQAABBBBAwCVAAMRFwQQCCCCAAAIIIIAAAggggAACCPirAAEQf31luS4EEEAAAQQQQAABBBBAAAEEEHAJEABxUTCBAAIIIIAAAggggAACCCCAAAL+KkAAxF9fWa4LAQQQQAABBBBAAAEEEEAAAQRcAgRAXBRMIIAAAggggAACCCCAAAIIIICAvwoQAPHXV5brQgABBBBAAAEEEEAAAQQQQAABlwABEBcFEwgggAACCCCAAAIIIIAAAggg4K8CBED89ZXluhBAAAEEEEAAAQQQQAABBBBAwCVAAMRFwQQCCCCAAAIIIIAAAggggAACCPirAAEQf31luS4EEEAAAQQQQAABBBBAAAEEEHAJEABxUTCBAAIIIIAAAggggAACCCCAAAL+KkAAxF9fWa4LAQQQQAABBBBAAAEEEEAAAQRcAgRAXBRMIIAAAggggAACCCCAAAIIIICAvwoQAPHXV5brQgABBBBAAAEEEEAAAQQQQAABlwABEBcFEwgggAACCCCAAAIIIIAAAggg4K8CBED89ZXluhBAAAEEEEAAAQQQQAABBBBAwCVAAMRFwQQCCCCAAAIIIIAAAggggAACCPirAAEQf31luS4EEEAAAQQQQAABBBBAAAEEEHAJEABxUTCBAAIIIIAAAggggAACCCCAAAL+KkAAxF9fWa4LAQQQQAABBBBAAAEEEEAAAQRcAgRAXBRMIIAAAggggAACCCCAAAIIIICAvwoQAPHXV5brQgABBBBAAAEEEEAAAQQQQAABlwABEBcFEwgggAACCCCAAAIIIIAAAggg4K8CBED89ZXluhBAAAEEEEAAAQQQQAABBBBAwCVAAMRFwQQCCCCAAAIIIIAAAggggAACCPirAAEQf31luS4EEEAAAQQQQAABBBBAAAEEEHAJEABxUTCBAAIIIIAAAggggAACCCCAAAL+KkAAxF9fWa4LAQQQQAABBBBAAAEEEEAAAQRcAgRAXBRMIIAAAggggAACCCCAAAIIIICAvwoQAPHXV5brQgABBBBAAAEEEEAAAQQQQAABlwABEBcFEwgggAACCCCAAAIIIIAAAggg4K8CBED89ZXluhBAAAEEEEAAAQQQQAABBBBAwCVAAMRFwQQCCCCAAAIIIIAAAggggAACCPirAAEQf31luS4EEEAAAQQQQAABBBBAAAEEEHAJEABxUTCBAAIIIIAAAggggAACCCCAAAL+KkAAxF9fWa4LAQQQQAABBBBAAAEEEEAAAQRcAgRAXBRMIIAAAggggAACCCCAAAIIIICAvwoQAPHXV5brQgABBBBAAAEEEEAAAQQQQAABl0BM11QUm9i5c6eMGjXK46rbtm0rqVKl8pjnPLl27Zp06tRJ7ty548ySF154QZ5++mnX84ie+P333+XHH3907bZWrVpSvHhx1/P7mbh9+7Z06NDBtWnSpEmlffv2ruf3mti4caNMnDjRtVrVqlWlVKlSrudMIIAAAggggAACCCCAAAIIIPA4CkTZAEhgYKD06NHD4zXJnj27tGrVymOe82TJkiXSvXt356l91ADIw2w7duzwOMdEiRJFSADE/bpTpkwZrgDI5s2b7zonAiAP87eAfSOAAAIIIIAAAggggAACCESEQJTtApM8eXKpVKmSh+G0adM8nrs/+emnn9yfSvr06eWpp57ymMcTBBBAAAEEEEAAAQQQQAABBBB4PAWibAaIvhz169eX+fPnu14ZnT579qxotxD3dvPmTRk/frz7LHnppZckWrRoHvMi+okGWbTbi9M0Q4WGAAIIIIAAAggggAACCCCAAALhF4jSAZBq1ardJaZBkEaNGnnMX7VqlVy4cMFjXt26dT2eP4wn5cuXF/2hIYAAAggggAACCCCAAAIIIIDAgwlE6QBImjRp5LnnnpPly5e7FLXoqHcAZMaMGa7lOqGZGe7FT/fs2SM//PCDrF27Vv7++2+5ePGiaBebzJkzS5UqVaR27doeWSUHDhyQsWPHuvZZuXJlu7+pU6fa+bt27ZJ27dpJyZIlZfr06a71NBjiXQT11KlTotstWLBADh06JKdPn5YECRJIunTppGzZsvbYYckc0eMsXLhQtPBqjBgxpFixYtK8efP77ubz22+/2XNat26d6PUUKFDA7rNMmTIh7nP//v0yZcoU+3o4jvoa6flrvZUKFSpIzJhR+lfW9bvABAIIIIAAAggggAACCCCAQDgFzKgmUboNHDhQh3Xx+Ll06ZLL5NatW3dMoVCP5WbUFLvcjKhyx4yo4rHMe1/63ARM7mzZssW1z2XLlnls06VLlzv16tXzmPfxxx/fMaPUeMzT9dybqUvisdzXsXXe5MmTXZvduHHDY5uECRPeeeeddzzmue+nd+/erm114l7npHZt2rQJcX+67/79+3vsU5+YIFOo2+h2JUqUuHPu3Lm7tmUGAggggAACCCCAAAIIIIAAAvcSiLJFUM0Xattq1KjhTLoef/nlF9f0+vXr5cSJE67nOuF0f/nmm2+kW7duHsv0iWaIuDfNzHjrrbfcZ3lMf/rppxJaAVaPlf95ot1y3OuDOOt4H1vnN2zYUC5fvuys4vGoXXsGDBjgMc/9iQ4NvHjxYvdZIU6bXzZRzz59+oS4ji5499135bPPPnOtoxkxmiXj3kxgRvTHva1cuVJatmzpPotpBBBAAAEEEEAAAQQQQAABBMIkEOUDIBkzZpQiRYp4YLl3O5k5c6bHMg0wFC5c2M4bMWKExzINiJgMCNsNZs2aNR7LtJvN+fPnPeb5eqJf+rV7jQ55G1qbOHGix2LttnPy5El77OPHj0vOnDk9lq9YscLjufeTDz74wHY90f1mzZrVY3Hr1q1FC8Heq40bN07cg0d6DtqlRYcQNlkhHpubbBbbZUdnep+byUgRk+lhf3TYXfem+/Oux+K+nGkEEEAAAQQQQAABBBBAAAEEfAlQUMGoaH0Jrd/hNP2SPXToUIkVK5at7eHM18cXX3zRjv6io8UEBARI/vz57eJkyZKJfnHXbbRpUMV0nfHIHtFMkpACGxpY0cCLE1zRfYwePVoffLZjx465jq0rfP7555IiRQq7rh5X64fs3r3bte2RI0dc094TpruNdO3a1TVb66JoDRGn6X5MFx6PuifOMudRsz+0bonTNJCjdUCcEXVKly4tadOmFQ20OE0zT7p37y5bt251ZtlHzQjRYFHixIntNWq9FM14cZou884OcZbxiAACCCCAAAIIIIAAAggggIAvAQIgRqVmzZoeX941w0CzEgIDA0ULc7o3p/uLfrH3zk7QLIm//vpLtCjqpEmTPIIf7vvwNa1dYNyDH77WcZ9n6nq4PxUNQGiAZe/evTbjYuTIkR7LQ3uiXVLcmwYqNOtj8ODBrtl6Te6FX10L/pk4fPiwx/UWKlTorswOJxjibKvFZTUA8uSTTzqz7OOsWbMkSZIkUqdOHSlVqpQtntq4cWMKoHoo8QQBBBBAAAEEEEAAAQQQQCA8AgRAjFaOHDkkT548sn37dpeddn3RAIh70ywN7+4yOsqJKQwqS5cu9djefbt7TWtXkaJFi95rtbuWa22Rb7/9VhYtWiRaH+N+ml5TqlSp7trU+zp1JJfQmrudrqce+hNaO3r0qF2sASgNrmzYsMFjdc2IcbojacaHBmU0y8TJdPFYmScIIIAAAggggAACCCCAAAIIhCIQ5WuAODZNmjRxJu2jDms7fvx4j3lO9xdnZufOnW1ARDMlvAMA4emikStXLmeXYX7UoEeGDBnkiy++uO/ghx4spC453sPNak2O0Jp2CQpv00yba9eu2XPQOiFaUFYDMr6arqvZIpoRcj/H8rVP5iGAAAIIIIAAAggggAACCEQdAQIg/7zW3iOqaHcS76CGdslwmmYrdOrUyXlqH7UGyPz58+XPP/+0X9K1lkZYmnb3CE/TrjZOVxxnu2rVqsnUqVPtOV+9etUGRpxloT3+/fffYobzvWsVLaTq3jRLJrTmvdwMWStmuN9Qf7RGSJw4cexuNRBjhhe2RVy1u43W/XjllVfuqvWhr4leJw0BBBBAAAEEEEAAAQQQQACB8AjQBeYfLa1DoaOfeNf8cDC1sKh7txD98u7eOnToIF999ZX7LBsI8ZgRQU80COA+EkqxYsVEu+xEj/5vPEtrkYSl6X40m6RixYoeq2sAwr15jyrjvkynvZfrfjUI4n5Out6cOXNcGRxaa0Sbjp6j3Xm0aeaMZtZkz55dmjVrJoMGDZJWrVp5FKPduHGjXZd/EEAAAQQQQAABBBBAAAEEEAirwL/fmMO6hR+v17Rp0xCvTrMR3L/Ma4aIe9MRS9ybftF3vtS7z4+IaR3u1r3psd3P7eDBg+JdJNV9fe/pN9980xZvdeZ/+eWXdtQX57k+ehcqdV+m0wkSJJBKlSq5ZuuoMZoh44w+c+PGDTuyTvXq1W1gQ4MbGnjRpkMG9+3b1/7osdevX+/aT7x48e4qDusdbHGtzAQCCCCAAAIIIIAAAggggAACIQiQAeIGo8U4NfvAV3Pv/qLLvQMC2n3j8uXLdqhX7R4zfPjwu3ajyyOiacFW96bdbpo3b26HvtVipWPGjPHIENF1L1265L6Jx7RmvWTKlMlmbGj3E+/gzmeffWaH9PXYyMcTHdbWPTjRpUsX0R8tcKr7dc9a0c2d0WcqV67sEbApU6aMLXiq+9Ihcvv06eNxNM0soSGAAAIIIIAAAggggAACCCAQHgECIG5a+kVdi3B6Z25o9xfvUVrKlSt317ohBU+cQ3gHFpz54X1MkyaNHSLWGSFFtx89erT9CWlfIR1bu5w4gQlfI8loEOLDDz8Mabce87UOiI6Io8EY9+Y9uosu06FuU6dObVfTzJuff/5ZpkyZYp/r+WjBU1/t/fff9+iK5Gsd5iGAAAIIIIAAAggggAACCCDgLUAXGDeRaNGiifdoMLr45Zdf9uhiovOSJk0qCxYskNKlS+tTj6ZBhSFDhsjXX3/tMX/16tX2eaxYsTzm388TDTS8+uqrPjdt06aNLcbqvlALkmrTa3Rvzz//vOh5aZDHu+n+tTuKdm8Ja9OuQjt37pQKFSr43KRKlSp21BrtCuM09dARd3r16mXrsDjz3R81ENO/f3/p2bOn+2ymEUAAAQQQQAABBBBAAAEEEAiTQLQ7poVpTVYKUeDAgQOidTdu3bplv8BrFon3MLIhbvyAC7QeyL59+yQoKMh2Y8mSJYsEBATc1151Xzt27LDnnj9//nAFPnwdUOt+7N27V9QnMDDQnp8+htZ0RBq11FFoTp8+LcmTJ7eZIpkzZw5tM5YhgAACCCCAAAIIIIAAAgggEKoAAZBQeViIAAIIIIAAAggggAACCCCAAAL+IEAXGH94FbkGBBBAAAEEEEAAAQQQQAABBBAIVYAASKg8LEQAAQQQQAABBBBAAAEEEEAAAX8QIADiD68i14AAAggggAACCCCAAAIIIIAAAqEKEAAJlYeFCCCAAAIIIIAAAggggAACCCDgDwIEQPzhVeQaEEAAAQQQQAABBBBAAAEEEEAgVAECIKHysBABBBBAAAEEEEAAAQQQQAABBPxBgACIP7yKXAMCCCCAAAIIIIAAAggggAACCIQqQAAkVB4WIoAAAggggAACCCCAAAIIIICAPwgQAPGHV5FrQAABBBBAAAEEEEAAAQQQQACBUAUIgITKw0IEEEAAAQQQQAABBBBAAAEEEPAHgZgRdRF37tyJqF2xHwQQQAABBBBAAAEEEEAAAQQQiOIC0aJFi1CBBw6AOIEP78cIPUt2hgACCCCAAAIIIIAAAggggAACUULAO/Dh/fx+ER4oAKJBD18/ejJOQOR+T4ztEEAAAQQQQAABBBBAAAEEEEAg6gg4gQ59dP9RAWfZg2jcdwDECXzcvn1b9Mc5uRgxYkj06JQWeZAXhW0RQAABBBBAAAEEEEAAAQQQiIoCToxBYw46rfEFJ8bwoEGQ+wqAuAc/bt26JRr0iBnzvnYVFV9PrhkBBBBAAAEEEEAAAQQQQAABBHwIuAc8bt68KRpz0BYRQZBwRy0Ifvh4hZiFAAIIIIAAAggggAACCCCAAAIRKuAkWkRUECRcARDv4IdGYJwTitCrZGcIIIAAAggggAACCCCAAAIIIBDlBTTmoLGIiAiChLtYhx7Y6ZMTK1asKP9iAIAAAggggAACCCCAAAIIIIAAAg9PQGMPThxCYxL328IcAHGyP5wAiNP/5n4PzHYIIIAAAggggAACCCCAAAIIIIBAWAQ0BqFBEPfYRFi2c18nzAEQZyM9mBYi0cKnNAQQQAABBBBAAAEEEEAAAQQQ8G+BC5dviPPzX12pxiA0FqExiftt91UDRPveUPvjfsnZDgEEEEAAAQQQQAABBBBAAIHHX0CDHkdOXpQLl657nGzC+LElbWACSRjv0ZXF0BiExiKcDJD7GRI3XAEQvWI9mFN8xEOAJwgggAACCCCAAAIIIIAAAggg4BcCR05dkiMnLvq8Fg2I7Lp0RtKmTCBpU8T3uc7DmOkEQO533/cVANF+NzQEEEAAAQQQQAABBBBAIKoI7Nq1S6ZMmSI3btywl5whQwYpW7as6GNkHhxi69atMmvWLGncuLFkzpzZ4+UcPny46F32V155JVJfo8dF8SRMAjbzwyv4ocEObe5BEZ1OGC/2I8sEcWqAhOkifKwU7hoguo8H6XPj4xyYhQACCCCAAAIIIIAAAgg81gLHjx+XpUuXyp49e+TixYuyfPlyefXVV2XevHn2vPU70qVLl+yP+4Xo/CtXrsi1a9fcZ9tp3c/Vq1c95usXPO/5etfbCbxcvnzZFoJ0NtL96z6c+devX3ct132dP39edJ7TtIaC7kuX6fkeOXJEli1bJmfPnrWrOPN1vdWrV9sfegA4elHnUbu9eLfgQEds79m2i8xdMx/SjAeNRYQ7A+QhXQe7RQABBBBAAAEEEEAAAQQee4Hy5ctLkyZNRDMnOnToICtWrJBy5crJ/PnzZcOGDfZmcc6cOaVKlSqSIkUKmTBhgmj2iI5gUaRIEalataoEBQXJokWLZOPGjRI7dmx59tlnpXTp0nagiUmTJtl9a1bJ888/b+dr4GX37t22DuNff/0lWbJkkRo1akhgYKBs2bJFZs6cacsU6P537NghNWvWlESJEonu6+jRo5IkSRKpXr265M2bVxYvXiwHDx60znpOGTNmdJnrl0vdZtu2bZI6dWobWIkbN65rORNRR8C75kdoV67rasbIo6wHEtr5hLbsvjJAQtshyxBAAAEEEEAAAQQQQAABfxXQbArNqjhw4IDNoggICJDt27fLxIkTJV68eJI2bVo7rYGJNWvW2G4z6dOntwGKQYMG2YDE2rVr7fyiRYvabcaPH2/3N3v2bBswiRMnjpw7d0569+4tmzZtkp07d9r1NQtFR8LQrjgapNCAxXfffWePr11VdFqzOTSrY9SoUTJ37lxJly6d/Pnnn/LNN9/YETR0Xxrk+Omnn+7KSvn1119lzJgxcvLkSdm3b58cO3bMX19GrisUAQ1m+GsjA8RfX1muCwEEEEAgSgisWrUqSlwnF4kAAv4hULx48Uh/IRro0ACEZk/Ejx9f6tevLxrg+Oijj2zGxPr16+3jmTNnbLcS7c6i2SJaL+S1116T5MmT2wCKLl+5cqWUKFFCGjZsKGnSpJFevXrZLI9ChQqJLt+8ebMsWbJENAtDMzratWsnp06dsgENDWQUKFDAZpc0b95cGjVqJIMHD7ZdcjTrQ5dnzZrVZn1oFxnNUNHuO9qSJk0qn376qRQsWFAWLFjgek00AKPZInotiRMnlgYNGriWMYHAhcv/dqWKrBoEQCLrK8d5I4AAAgggYAT84csELyQCCCAQmQS0u4r+7dUuIvny5RPNAFm3bp307dvXBha024t2a9FWsmRJ0S4re/fuldGjR4tmenzxxReiAQ7tkqJdY8aNGyfTp0+XDz/80FVDRDMxtAuMdmnRwIh2mdEAiGZ5aOBFs0C07d+/3z5qxoi2ZMmS2UfNUtG6HRoI0a42miny9NNP2211BQ3C6I9302CNDjWaIEECey3O/rzX43nUFHAvfuotEBm6v+g50wXG+5XjOQIIIIAAAggggAACCCAQgkDu3Llt/Q0NTmjwQ4ML2l1EMzNatGhhszK0yKjO1+4r2pVFgx2lTY0P7Vqi3VE0cKHBhrp160qlSpXsfN3eCaiUKlXKBk80G+PJJ58M4UxEMptRWzT4od1epk6dKj///LNdV4MwmuWhgRg9hgZctGuO1g7RpkEUDaZ4Nz2+Zp7MmTNHpk2bZq/Jex2e+7+ABjMSxr+72KnOc0aCcVfwta778sdpmgyQx+nV4FwQQAABBBBAAAEEEEAgUgloICFHjhw2o6Jr1642M0SDDydOnJDChQvLyJEjbbFTDYhkypTJdnnRAIh2UdFaIM722l3liSeekMOHD9uuLLp+/vz5bQ2PkEA0QNKqVSv5/vvvZcaMGXb/OpqLdl958cUXpWfPntK5c2e7uQZhNLsjtKbbaHcdLdyqtUN0iF9a1BRIG5hAdl0643HxIQU6dN3I0qKZ/7HuhOVkdTUdEkmjmRcuXLAVh8OyHesggAACCCCAAAIIIIAAAv4uoMPcarZHypQpPS5Vvz9pUEO7rWhQQbMvtOn6hw4dsl1dNDvDCU5o1xXNFNEuMNoFxVemhnMAXVdrjmh3Fu0qo8EWzQbRQIwGZfT7mx5Du89osCQsTYe/1SCKbuN0rQnLdqzjfwJHTplhkk/cPRyu+5VqRkjaFPHdZz3Uaf1/I2HChPb/j5AymUI7gdBDgKFtyTIEEEAAAQQQQAABBBBAAAEroMEC7+CHLtBAhnZV8W66frZs2bxn20CJ1hcJS9OgihYx1YwSLciq9Ua0RomTuaFfEN2HuQ3LPjUQo8Pr0hDQwEbCeLHlyMmL4j0sru0OYzI/IkvtD+fVJAPEkeARAQQQQAABBBBAAAEEEIhkAlo7ZMeOHTb7RIuXarFTzd6gIRDRAu7D4/5XgY8HzQAhABLRvxXsDwEEEEAAAQQQQAABBBBAAAEEIlzgQQMgdIGJ8JeEHUYWgRmz58n5Cxel6Qt1XX0xH/W5nzf1dKbP+llKlXxWMmd8tEWm1m/cIlt37LSXHC2aSY/MkE6eLVLI9PUMrvg8efosyZg+nRQr8nSYWMK7fph2albSvqvzFi2RzX9sl3hx40qNKhUka5ZMYd2c9R5zgd1798vGLVslQ7o08mzRwq5+zqt+XysnTp2WooWekrSpU3lcxeo16yVHtiySInnwUH8eC3mCAAIIIIAAAggggEAIAgRAQoBhtn8LHDl2XN5r30numC/XWTNnlJLPFv1PLvjipcsy7ac59svcgwZAajVqLqlTBcqwfj3CdC0LlyyTId+OkXjx4sn1G9fl5o2bksVYjP92oKRLm0bmzl9svpAWCjEAsmTZSmneuq38PG2cPJErxz3XD+2kQjp3LcL10mvvyqrf19lzO3M2SPoN/Va+HdBLypYqGdouw70spHMI947YIMwCU2bMlo86drFBjh279sjzJYrJgJ5dpN0nX8h0E6DUwMeJk6dkzLD+rt/DZSt/k2at3pGhfbtLlYplw3ysqLbi4aPHZJH5f1zbC3VrmWEa49jpX1eulgMH/5Z0plBe+TLP2Xn8gwACj0bgT/P/3rHjJ+x7q/sRNQgcYGpB6HuptrNB58z73lqJEzuOlHm+hKkHEVww030bph+9gHYz0ZsyWnyRhgACvgW05szjXjiXAIjv1465fi6gQYfYsWJKEjNE2FTzJcwJgOgHjlu3bsvtO7dlx87gL2R5cueUPfv+lD+27ZC8T+SSX35dIblzZrcfSpRpxpx5kjtHdtm7/4AkTZLYfFErJHMXLJaDfx+y65d5rrgdB/6nufMlmam+rV/y1qzfKIePHJNy5kt8s8YNJFOG9LL/wF+yftMW82WwoMxbuERy58ouT+V/0mSIzDMZKtGkXq1qNgPipLkrrvvXYED2rFmkWqVy8tva9XLq9BnRgMGS5atEj3lax3Cf/4s9dqVypW1wxNfL+uvP0yS5qTC++Nfl8vr/PpQve/S1Xy7r165uviQF33nfuXuvvW7dXgMPqVOllOWrfrcBpIW/LDPbJxVn/aBz50WDK0WeLiBLzblEjx7DLAs+d7XVcz/w19/ypLEsbc5z9Zp1d527c55jJ0yVlb+tlb7dO0udGlXk0uXLUtsEer7uM8gVAPlt7QbrljploFSvXMFmsOjrtemPbVK3RlX7wVGPmcoU80qUKKF9HZ8qkE/mm6yS9OnSmm3K2w+a3n7OOfD48ASmz5wrtatVlt7dPpfZ8xbJ2+9/LO+83lymTJ8tvb7qJA3M7+Arb7wnvfoPkanfj5DnKtWWv/4+/PBOyI/2rP8PdOzS015RYIrkUrViOTvdoVM387fnqJR67lkCIH70enMpj7+AvnfXb9ZSopuMy7W//uw6YX2Pe7Hl2za7UQPA+lmgwUutTIZbcvv/qr5ffT+8v2t9Jv47gblz59qbRhUrVvzvToIjI/CYC1y6dMmORvQ4nyYBkMf51eHcHpqA3nkuV/o58wU4jXxvvmRfMpkY8ePHk5HjJslqk22gAQ79kNLTfPGaMHKw+dK80wYGcufMZruqdDdfwD9q85a82fJl+bRzdxv40IDEu2+8KkNHfi/bd+6S4s8UkUHDR0uDOtWl8ycf2IBHG5N10vfrzvau9+stmslps027j7+QIX2/NoWrLkj7Tl2loAl63DEBmG7fDJCc2bPaL+lLV6ySbTt2Scf2baVK3RdtdxXtmvJe+47y16HDksBU/dbggA5XvdPcSc+VI5tUq9/MPl65clX6DflWZk8Ze1dXAgdY7y5VLFtKniv+jAlIrLezO3/dWyqVL22GVUsmNRq+LDWrVrTDtfUZNMJ+GNMvWNq2mvPSrjzO+o3r17bXpFkk6rtm/SbZZO5u6ZfcV99qK1tMIOmZwk/JgKHfSatXmkrKwBQe567BG6dplokGWzT4oS2+yVaZOXmMXL9+3T4fNGK09Bk4XCqb8xw/6UcZ+f1E+WniKNEsAT2fGiYgEiNGHOnas78Ncqlnl559JXuWzDY6rUGty1euiBq5+7mfgz0Q/zwUgWom+NRv8LcyatxEk0H0i1Q1wTztlqZNA1ra0qVJLROmzbC/21916iCavfXhp1/aZfxzb4Ho5v/tWT8vtAEQ/X3X4EeMmDE8NtRgpi7Tu896t1nb1avXXIFcDaDo//+JzF1PDfjmyp5Ndu3ZJ8dPnLT7zZA+rcf+eIIAAp4CmjXw7oef2Rss0WP+m82hgff3PuooiRMmcG3Qe8BQe1Nk2rhv7Xvn1Blz5IL5u5jQbR3Xykw8UoHjx49LqlSpKC76SNU5WGQTuHgx9CFzH4fr+fev8ONwNpwDAo9AQLMvDpo01NrVK0vNKhXtl9/Z8xa6jqwf8qeMHS6Txw6T9OZLvGYhaNPuMtq9RFPvG9atKd+NneDaJqGpuL1h+QJ5xgQllq1YLX26fWFT+du3fVvG/jBFNCvijRYv2YyOdz/41AQmsss7Jljiq/Xq2lHGmW4oGswoX/Z5GTm4t5QuWVy2bN0ht00GhQYSunRsbzNN4gYEyB5TQ+HlJg1sDQXNUNGgjH6h1DHj336tubz3VisT4LkkP0ye7utwHvMCzR0nDWbohzWnnTx52gYcrl69ajMsxpo7UU/kziHNm75gV9H9ayaKd2vRrJFMHjPMZLw8Y4Ie2+35a0DjG3N9Q/p8ba7jC5s54n3u7vs5feasJEvmOWa9XnNiU9lcz3HAsJHyWvMXZeA3X8nooX1l6/adsmjpCvdd3DWthppR8tPE0RI3XlxzXtvv8rtrI2Y8FAH9Hb967Zr8smyVzZiKEzu2zabS4NlnXXpIx649RTOnbt28ZX4Hb9gAXZGnCz6Uc/HXnRY3dVU0a00DfD8v/MUGFN3/f/2690B5u90nNsCqjxrc1da6bQfp0W+w+f/sjg3kvtX2YztfA75NW71tA44aWH3hlTfs3yq7kH8QQMCnwIChI2030xcb1nUtt0ER83mgQd0aktPctHDaMhOQTGsCvw1ees3+DXy+ZDGCHw4OjwgggEAECBAAiQBEdhG5BDS9Xlunr3rJG++1t9OaEeK0tKbbh/Zf0wCCFgHVOzRO0y9m2jJlTG+yN866PvhrrQwtHqoprtq0a4U2LeyoX/JOnT5tu2IUzJfXztcMjZhm3HZfTbuT6Jd8bUkSBw9hFi9ugNwyX/g1W+HL7n3kHfNFZf7iX22fYV/7OHb8pLmDe1XGT/5RJv8403YX0bu4oTU9zz9MAEGvWa/faYWeym8zVG6b5R+aeg3NW7cRLVx5r5btn0KlmuFx3dQXOXbihN0k0z/FXiua4E7DOjVC3Y0WO9U+0xcvXnKtp1kyVeq9aLN2rly+4rLWbBNtJ00fXafdunXLTl69dtWZZR91v5r1ksJY3zDnRnv0AprF06VnP3nJdAHT9G4NYP1ousRoX/gZE0bajIPkSZPKC/VqmSBYUvv/16M/y8h/xJrVKtlsjkVLlpsAyBLb5Uu71GnT/680Y62h+QLWuEEdm83x7Zgf7N8ZDWBqsLdsqRISGJhcdu/79/957Zo35fvhprtSC5tRotlvNAQQ8C2gWZVjJ06RAb262vcdZ62Bw0eZ98Yb8v7bbzizbGD//PkLsmbdRnvTJHOmjKLBR31PpyGAAAIIRIzAv99yImZ/7AWBx1pAAwhaa0DrWHz8/ru2G4t2r1hrumlozQ5t2tVkn6nn8fehI7aORJ5/ipLpsplz5ts7qYuXLrfdZDRIoi1mzODeZJqBEdPUFpltUs6vXbsHT6csAABAAElEQVRuanAslqRJk9h01rUbNtkuNpXKl5FJ035y1dSwOwjjPytWr7HBh9FD+kp70wXn2j9dQXTzaCZooQUjNQijX1D0zrpmgHzxcTvTdSSu5M+b2+dR1EPP58027WWXqfXhZHY4K2tdFM2C6WqyThbMmChXTXcRHUFGj6dtr+kKo9d6V/vHxkSA7CJ3G80yaWoKWWpARZv7udsZ//zzqvkSpsfTc9NuLdrlZZIJ6DyRM4e9I5Yta2Y7Qsz/2TsPACeKLo7/kd57kw5SRYoISK+CgBQbVQERBBEUQVTUT1FRRIpSBOm9F5HeFOmC9N57b0fn6N/7T27DJpc7cscBSe49SLI7OzM789tkb+fNe29ors9rQ6GSyTIVZjwUmvefPXtficU8MeQfJaRpZjusNpiD+hblBGLGjIWY8h06cPCQsTCi8o1Clw3OfHLFn0ayQhPjyXDlH5XIEWB8oYIFnkU/sZbaf+AQqBCxhKvs0LJtzdqNRll6RSzFGBj1mliLjJ4wxbis0YLN+r1Y5bJndazCROUmRZWIFhn9VAKhCcyev8goG2vWbYzBI8bhjEyq1GnQDDPEuo3xtV6sWAMbNm01cal+EKVwMokl9pK4pPK3+F7TRvL7uiVxyO4rIEOfQVOUgBJQAkogIgQco7aIlNC8SsCPCXBlEz7c022CS25SGO+DS9HSz5bCgKDN235iBguWS8mMOQvMMeZr36mzUWoM7usIMGgOhLxx1Yqunb9AZ7Eu6dVvoFmms8/P3+OWBCftILE+ShV/AYP6/Iz3PvwUHf/3PYb262Uv/sBtxs7goOMVeZBKK590vaF7DaW8LKXbR8xsqSxg3JL1ElCVcUBix46NqpXKoWCI9Yn7Sb7t2tMoILgazlefthN3kLouWQo8m89Yw5SuUhtxxEWBprp1XqkmaRKnQeJz0BplnJzvQcJYDozh0PnHnuj12yA8XzA/PmnrmPmyt53BLi1h8Lf+v3Q1ZbjyB+Ul6UvnLzqY7V9++tYEzsxTpIy0LTY6dWiL557NK+bDaY1lyAdixp8/Xx5jsWMKhPMWVhvCKaKHHoIALXB6/tgZX37XFbkKlzbf0zZiUVBKYuc0bVQXP/boa4LdMi7NZ+0+eIgzaVEGmuXvnJZrBfPncwLJLLE7aF3D336X/32GOeIiwwEZLbYYiLm7uKsxEG3Dd135W4pfWo2pKAElED6BhuL2wvsYhYr6ZTKR0aFtS2NpSaUjpbu4myVPmgyv1apu/qYvX7XaPINwgoKTKjlzZDf59M0/CFwOvu2cYLl5+y7i2OK+2Hsg4d44I2Oep5geS6zz4sV5SmLQOSZpbkjZG7eYyTFhc+fOPZlwcxwzibY39/MkjBtTJhkceVnu6k2HRSyL3BJX4NjyN9iT8Jxxbe1NECemWCzfr+e6tIcWwRS6SPLvgWmuJDE1pOmm/zweM6Qs+5ZA2mTJ1eA7uGP7G8I2WnlZzrJUZH739iaJf3/4eu3GHdyW/J7kDuux2icZXNor+/FiP+W8Nrfl/NdsjNzrc+fLui2+pJPY1qZL18Sy2PNlkolL4SvXOCxJJIysvl+X9tySdlEsVBZf02VJtPLa6+OpY8v3JF5sB2/mvXz9tvPasK/WNWW5W3LNY9uuub0ufv/iCidLEsWT9lmNsBL98DOGPMB4/ta4dYbZ6K9ITfRlmb1NLSsqqCiBQCNAxQetKP4cP9wsQ5dCrDcojPfBoJq71i/HdXEtSSqridjdRNw58LdCs/BUEkA0qoUrvVh1u7eBv08KlR4UWrzwj5PlUmMSI/lGRQvPbe8T7wu0NIlI/VwJ5uq1qyagor0p7m23H+M2Ay4y2CuD1boLV7xJKiv62N2KeA2CLlwwCi33/GHtP6gNYZXT9MgT4HWimxndvahgs4RWPbweljWPla6f3hH4R2IRNZElpCdKHB4qOIpVqIEPWjRFx4/ex8uvNTSK1FGyvDAtpBicmZZjjDvQq+s3shLV8xLbo6UJjErXOa6WtV8sdbauXowCJSqBcQyobOQKWlTsrl48R5Sh+kzg3ZXRXNGZACdGxk+e7rIKDHnQ6o0TClwFhrGvWsizyPqNW4zr3zedOqChuKipPHkC3bt3N0FQGzduHGZj9p64io37L5rBNjNxcM6BMgelHHBxMEq9BPfNIFY2rOElB6El86ZA2mRxcUWUKCu2n8fFq47nOkdZqStk8MlxMTetsrekMioZWC8la7qEKJbT8Qz7z7ZzOH3e4QrMejiojmMpNWQ/RkibWI7tZT2WpEkWD+XypzTn2n38KjYfuN83KjCMgkEyO9pn6xvT5LjV3vgycC6aMznSSd8oE5cdc7aVHO7JPysvdT7Uz7Bv7u1l2ULPJEOu9AmNUmDBhtOujELKMh/bx2dgi5G9vTyeKU18PJ8jmVH4HDh1DWt2BznbZOfLNlgKD5Jxby8VN5ULpkHShLFwUZQf89edYvVGTD2yZSHldYodsmOY2drL/ZJ5UyJTqni4LoqStXuCcMJ23XheFmUb7PWaemzHeOJ0KeKjVN7k5ru34+gVc92sqyr6DsOX+4IId4RyLPv3StI9tZf1ZkmbEMVzOb5X3Pckx48fx9NPO0IBeDoeFWlnzpyR58PEZrxjhS2ISL33VWgRKaV5lUCAEmDMAZqE84ZpKT/Y1UQy6ObggOlc6vZBwh+jXVHwoPwROU53G8v03L2cpfiw0ulGEFVixSOx1xcZ5Qpn/hlo1l3c2+5+PG3IqiDu6dyn1Y678Bp4SnfPZ99/UBvseXU7agjwOnn6PseLFxd8qUSOAC2aDm3/z1n44NbVzu1508Y5tzkzzSU5gy5cdLnnMRA0lSK839l/F1SCWMKlr/lSUQJKwDsC7du0BF/uwt+bJYwDNm3sUBOQnH/DLRdb67h++jYBKgSoYOCA2ZK7HK2GCAeWHOBTnANSx65YQNzPx5E/lRE3bWWZjYPVsMSyFuDxkPGsyUrLB/d6rH3m4yDYLtYxptkPsb3sl3UelmXdzGP6Im8yx+UiVntju/WDZax6WIB1Wcz4bEkrBbtYbaIyyZq7Zxme2DrG/Kae+8YuknK/Hh6z2msN8FmGYspJX+R/mGK/jlZ+Zo5vs8phur1v7IvVXqvisNprFGXsk4j5kDcqTHh9WC/Fna8j1ZHf6jazmldIGfaV/XLyleO3rMwheW+GcIpBvm4Q7O11P2ad398+VQHib1dM2/tICXT77kuP9TMQI18qSkAJKIFAI8AHNLvCl/1jmifFVKD1XfujBHyVgKeJAl9tq7Yr6glwEO0+cI76s2iNSiB6ErCsgqJn77XXSkAJKAEloASUgBJQAkpACSgBJaAElEC0IKAKkGhxmbWTSkAJKAEloASUgBJQAkpACSgBJaAEojcBVYBE7+uvvVcCSkAJKAEloASUgBJQAkpACSgBJRAtCGgMkGhxmbWTSkAJKAEloASUgBJQAkpACfgqAcaeDLriWPXlOpd3tQWqjGibr9+4i1MXbphiN62oqxGtRPLflGiZrIdBOC/JUqruAVO9rZIBONm3kLicka6HsVG4pKvVt1u3mRI5CZaVVs5cuGmWjL14VZaujaTwup29fBPBwuqqXLfICntyQVb9iS2ryvCaWUsgR7Q+1sO2nJa+8bpdvh75NkX03P6SXxUg/nKltJ1KQAkoASWgBJSAElACSkAJBCSBW7I+6bYjl81ysAyAGvwQiouTQcE4L4Nyyg37kh8RJMcB+b+7gkyp27IECZeSjYxwQL/9sPQtZPmVu5Gsh8UOnLyGo2ccy/pevxm5wT17cfriDaNw4OLB7FskmwRet02yPDBXAGK/rNVWIsqJ13zX0cvYK6vjcfsm16uNHG6ck2v/767z0gSuSnTXtCui7Qnk/KoACeSrq31TAkpACSgBJaAElIASUAJKwOcJcKwbLAN6DsSNpYRlLhGJlnPQawbQUpZWAJEVDuavBDusIx6iGrMMa2SVFe5tp2VEZK0j7HVxqd1bD2NmE1IZr9c1m+VHZDmxnutilSKL1pqaH+a6sW9X7txXDj1MXXZmgbKtCpBAuZLaj1AEVq5cGSpNE5SAElACvkygZMmSEW6e3usijEwLKAEl8AQJROY+97DNvXHjBmLGjIlYse4PfW7duoXg4GDEjx/fJf1hz6XllYAS8G0C9+8Cvt1ObZ0SiDCBJ/EHNsKN1AJKQAkogYckoPe6hwSoxZWAEghoAnfv3sX48eNRqlQp5MyZ0/T12LFjWLhwIYKCgpAsWTI0aNAA8eLFC2gO2jkloAQcBHQVGP0mKAEloASUgBJQAkpACSgBJRBwBFasWIEffvgB06dPx6lTp0z/GF9hxIgReEpiLZQuXRrr1q3DqlWrAq7vUdEhuuWoKIFAI6AWIIF2RbU/SkAJKAEloASUgBJQAkpACRjXlty5c2P37t1OGkePHsWGDRvQunVrJE+eHLly5QKtRFSUgBKIHgRUARI9rrP2UgkoASWgBJSAElACSkAJRCsCxYsXB19Llixx9nv//v0mHki/fv1w7tw5ZM2a1bjAODPIBuOD7Ny5E+fPcyUNhxw4cAAXLlzAnj17kDlzZivZ5fP27cgvp2oqUpMLF56hd/wNkL+1NzRxe8odURQyno6/iypA/P0KavuVgBJQAkpACSgBJaAElIAS8IoAlR7Xrl1DuXLlkCZNGgwZMsTECGnXrp2zPAd5S5cuxY4dO5xpW7ZsQYIECfDss88iderUznT7xs1bVICEPeh1P+Ky77ITbjX2Uz7Sba5oYm+WfdvlQJS2wuUsUVfzI6o26hroVtMTaW/4J7195zauX7/u1lD/21UFiP9dM22xElACSkAJKAEloASUgBJQApEgwKCniRMnNpYhcePGRaFChbBp0yaXmhIlSoQPPvjAJa179+5ImzYtGjZs6JJu3zkffE12OUPueSDprlBw2ecOxSrqctBx6Em/uzTJZScqWxZexeEde0AbHqLoA2oO5/BDnPQhiobToAccCv+kcWPHMUGDw6uEykVfFw2C6utXSNunBJSAElACSkAJKAEloASUQJQQoEsMY36sWbPGuLgwUGrBggWjpG6tRAkoAd8noBYgvn+NtIVKQAkoASWgBJSAElACSkAJRJJApkyZQKsOSsKECdGmTRuMHTvWmPPnz58f9erVi2TNWkwJKAF/I6AKEH+7YtreqCMwbjJw6RLw3juQtdCirt6I1HThIjBuElC1EpAje0RKPnze5bLk2+atwLuNATEBNTJ6gjwZJABeqxV2/Qv/Bs5KULAGb4Sd52GPzJoHbNsOfNYe2CBmqdt2AjWqAsmTOWpetQaIIWZ6LxZ17A8YAqQRf9zXaz/smbX8kyBw9Dhw+AhQsvj9s/Ma794LlJBrnCunI53B5eYuBC5fAapUBFKlvJ/f2jon380F8h3l97jaS0Ds2I4j3nyPrDoC4PPYiZNYtHip6Um912ojXjzHb3zJilU4eOgIMqRPj8oVymDSHzOROWMG+Sk9H2avvckTZmE9oASUgJPAqjXrkDNHNrl1pXCm6cbjIfD555+7nIjL3z7//PMm2GmSJEnkkYKm/ypKQAlEBwJPaNQXHdBqH32awJFjwDutgLafACGDhCfSXg7kRo+Xwd/Rhz99qcpAXVFmeCvTZgAffQpcswUz6vIz8Otv4ddAxcnMOeHneZijHOS2/hi4c9eh/KgvCqpNW4A333bUyuMdOgHP2BRGMWNK2hfAw0Zff5h2a9nIEeD3r7n4WfOaW/JjD6BCdeCH7kDhUsC8RY4jr7wJNG4hirH/AYVKAsdOWCUcn6fPOPJ3/BJo2lIUi3XEl1qcqan88OZ75FqbX+/t2XcAX3fpbl5/L13u7Eunb7qatFETRAEsMmf+X/Lz2uY87mnDmzyeymmaElAC9wksXfEv6jdthf/WbbyfqFtPlAADmiZNmlSVH0/0KujJlcDjJ6AWII+fuZ7RFwiMEUuHODIzLOu/Y5QoICqVd7SKypA7dyDOoQ7riJcqAgWfA3bsAvjQUrgARwxA/mcds8ssNX4K8Fw+Rx7O6pQrDUz9E9h/UAZpkv9lUUxwEDZhqsxYy3HWSSWCzMIaq4ZWzYHs2YA9e4GVa4AyJQCZlcVzco5iL0j9MlB5SmYm3mrgmNU+eQqg8uLsOSBPLuANGeQtkQHOqTOybpsoBzhY5Dk5GGQ+nrtWDciUr6OP3r6zX/nzAlvEEuOEDDRlFhnZskCmjYHnCzlqIafJfwBHRaFU42Vg9VqgYjlg7z6HYoVWG1evAVOmS79kwJo964Pb9fcSOd9JoJGYo86YDZQvA3zeHsicx3HOQcOBV2u6zv6TwUcdHdzefNXbHmq+J01g4FBRZnzt+I48K981ypWrQLdeQGdRaPG615bvwXddAVow/PUPsHQ+UCA/kFP8tfv9DnT91hQzb7QECr4B7Nss1iN7xEJIfmsywDe/LW++R/drCpitp2I+hZliNVO9SiVs2bYDx46fQMxYojAMkTfqvCK3hrS4cPESFsr9r+jzBfHPspViFBdTbi01kCB+fPl05Nl/8LDcBjejWJFCmLdwMfLkfkZuifnldjVP8scQAyxH/umz5yFH1ixyC8srt7mjWCP3zlfknrR56w5cDw4W45z4WLt+k9x2y4iBTmzMX7QYmTNlEIOdijoQsS6MfgYUgTKijD3MiRcVJaAElIASeOIEYj3xFmgDlMCTIDByHFBdBuxZMwO/y6Dpck8gcSIZUA0Ui5BlDoUG3WK+7iLm9KJEWL8R6PiVKARE0UFXlS+/k9lpGbh1bAe06QBQ8UGFxJdiUdKzD7BRLBYqlHUM5Bo3BHr/LFYehx1WJyNk0NbyQ7FYkNfZs47Z7wkjgKALwPtSX7EiDgVMp85APhn0s43zRamxQers+SPwgtRLRUJZmRnnLPeBg4CYb+KKWJNQ2bFlK8DBZDFRRLC9jMb8fTdRTvwDyCDDa2G/OOjM9YzDAqO/cNorM+lUQNB1RgY7+KA9QGUSFSxDRsrx/aKEGA8MH+1QYlABQi6c4R85yOGO8KB2yeDLXIssmaS9GYFJ0xyDWCqJZJAGXrslc127kUIUWU8/DRlpiaWIKkBc4fjw3kuVRKmWFfj5V8f3hE3l95lWIfx+U6hQ7Czf+62iiIstf7Lo9kRTZbpsuFsuMI8M4M33p0hhIFFCx+8hp3yHvfkeOc4YUO8lRYn6tyhIr8p9YK64r6VLm0ZmPOV+ESLf/dQLVSuXF4+2Ovjki2+R4en0yCjKUiotNsrvvFfXzrDy5MudC59/84PodfPLreYuuvbsK7eH7JL/afyzfCW2iaL4p2+/xFffdUOjuq8ZBQhnu1lvmRLFMVauweKlK5BHrgdddAYMHYX06dIiidx716zdgN7dv0cdKlJVlECAEfjxm044LpMXn371fYD1TLujBJSAEvA/AjLCU1EC0YwArS/2yUC94ZtAvdccgy1aMViSLKkoQeYAf88GsojygbPKFGPtMEoGUjLQb/qWKDUGONL5zgHF8d2OQRvjD1DJMUbK/djZUf58EPDJRw7lxttiwk/FxBeiLPEkQ36TOAfSHiozalYDpouCoWplsUDZ4LBOGS7n7dfTMTCMnwDYvksUJ81FUZLFYaFCpQwVORwkcgb9f587lCNDRng6W/hpxV9wsOgkyhDGaKAywxK67wwfI/V/BoyVmfxfRMnyIPGmXWK6LyMqR021qss1el0UG2JZMmEE8JP0+6PWwLDRMgAuJ9ewmVi93HLkzSgKEFrRqPgPgexZJZZHJcio/H6bqQikhMSsgFggiNkAcEaUhYxVY/lpx5N0K6+jhGPfKsc05meeiHyPrLoC5LOWKCGDxSpmkSh254rVBi0xaK0RljR7u77c4gaK/qk4NjMOjwfpIcrfMUP6yS3qHipXLIth/XuhfOmSxsLDQ3aXpLhx4mDiyN/xTaf2uCgKza86fmTOl0iUVVvEQkRFCQQigTIS36ioZTkZiB3UPikBJaAE/IhALD9qqzZVCUQNAVoQUNrJwJ2xIyijJK3Z245tWklYQVHp8kFXEksyi1UCJUdWhzKASgoKZ6njxQNOnnbs02qDQgUK87AOWikULQIwuOOz+YBYYfz8UqeC2J07yrMMRfxUjWsO3Uk++dKhjOE548s5Pcmx4+IKIIPGQSMcR6uJJYZ9kMlUWrxQONvO4KJ0/aGCI2d2RzrfreCT6dI50m6GKBu4R6UOy2TLyj0HE8eW450xPCjBUr8l3rSLvGSQZITXoU1LxzZdhlauFqucThLwNKu43YjCqboosOgyQwURmdFCRMW/CTwd8l2zlG38pKsarYH4/acyhN/7c5Iulgcukl7K7j/gSGI8GAY5Zp6IfI9cKvT/nSzCrWCBZ0UnOkzQHMKv3b7DitX/hdmxHLzniaSR+9DBMGITpZT7Unze70SShViTJJBrcodK4hCxtoNv3LCSzGdyUTA/JdfDXp7BBxmk1SrjUkB3lIASUAJKQAkoASUQhQRkdKGiBKIRAQ6gpoh1RfUqYk3wrcONpWFdQIKTOQdO4uOOXTK4lsEC1qx3xBuwEDGOB2MUzJ7vsOKwZqNpmk9hzA9uT5JzUAHB2Bd0j+FMN89BCwjxpzcuInMWmCIRevvrH7H42CmxMSZJ279xxDuwKuCsLmNnMEYILTeui+JBZlllxONwBaBrgF0YX4RCNx/GEKFbDweMxYs60vkuVRqxFD0hu+aDiiK63jDOCPs6WfpqCdMZg4GvidOsVO/alTOHI6bI/VKOrS/len3/P4fFBxUvVOAkTuwYEDMHVxLhAFjFvwnQkomKRrpa0cVlovzmGL+jbEmH9Ufv/o7v6ypRhjH9XxnMt2rn+K5xX1wuTKyQPgMkKO4dh3LSTuRB3yN73gDZplvJbnFPy5JZlCG0PgtPrHuap998eOVsxxLLUpPrJPDsUQlS+9c/cm9RUQJKQAkoASWgBJSAjxBQBYiPXAhtxmMiwOCkVGB83MbhWkH3is8+dpycwVApqVNLwM9GYv1QSKwbZDAmJtpOGTdRLDkyiavFPqBPd2eyc4NKgf6/OuKAJJGZ5wV/ySovgx3BSZu1dsQFmTzaoQRpIW04f8FZ1KsNBhKlJQeDO5Z72eF6ExTkKEorCPGjlzDzEmOkmQQKrSUuN+XFoqOAQxlC6xO7MD4H45islwFj5ZqOGAltWzlcdez5wtrmrPpvPUUZNE8UIdLXlaLgsaSp8ONs8LPFHEvYWunetItxT7iU6aXLVilI2HxHHxgXIkliR8wRtlkCOkokRcfqLxJs0cSFuF9Kt/yRAC2jfpff0NKVEs9DrJw4IP+ps8Maqcv/gG9/dHxf6TpDq61de4ChI+W7cBIQ9w3jNvbyq+JiJgoz8bs37mYWhwd9j6x8AfZJt5cY8nutWU0Uv49Bmoh74XqJg1S22qsmyOljOKWeQgkoASWgBJSAElACXhGIIT6897zJyWx3ZUBzS/ztL1++LGNEGSSqKIFAI/C6DNxpRbFikWMQniqlo4ecTeYyq5dkwM2gonQZoQIgLOHgnzELJOBglAtjXpwVBUFa+Q26t+HmTcfpLBcSWrxwAGm51ITVGLropInkb5ouCTwvV4Lh0qQMgvrKy440KpssNx77ucNrF+vL9qwMer+TWCtyPSg0xWcfrOvBNPKldQ0Z0CLn1QZiBSDKHMv9iHlU/JcArXyoCHP/XtLaiN8R/gbDkgsXHfE/3F3EHvQ9Cqs+TY8wgavyG48hVmlcRUZFCSgBJRAIBLp37460adOicePGYXbnwMlrWL07CLfveh5e0VjXOiSbRqycdgM8c0zevBulhW4O67LK2rfdc4Z3jHkf2F5pPNsfte2NYWJMubeV+3SZDG/oGl5/eIyNNe01Db7PyNO5wkuzn8e+zTIhpzHFH1d77ef01G57G93z2vf5d/ue9QX1UNEz6RLixTzJPRy5n3T8+HFZl+Dp+wmPYOvMmTNiBJ7YTLLQrZacIyIy1aaiBJSAk0Aqib9B5QV/SPbBtph0mxgE/H1x0P0g4aD8USg/eF5ZNhKybKVHsRQf1sGEEjvEG3EfZHpTxsrDQSZfp045GFmDTrYlhbw8SXjtYvn2bRyxPSwFiJjuhxLGSrFEVrcwVi+q/LCI+P8n4/N4+l4y9kRI/IkwO8lAxp7kQd8jT2U0LVIEEob3G49UjVpICSgBJaAElIASUAIPT0AVIA/PUGsIJAIDe3vuDU3trSCpnnNoKgOm7t8SNRw+/Thi9TDOiYoSUAJKQAkoASWgBJSAElACSiAcAuHY8IdTSg8pASWgBJSAElACSkAJKAEloASUgBJQAkrAjwioAsSPLpY2VQkoASWgBJSAElACSkAJKAEloASUgBKIHAFVgESOm5ZSAkpACSgBJaAElIASUAJKQAkoASWgBPyIgCpA/OhiaVOVgBJQAkpACSgBJaAElIASUAJKQAkogcgR0CCokeOmpfyAwMqVK/2gldpEJaAElMB9AiVLylLSERS910UQmGZXAkrgiRKIzH3uiTZYT64ElEBAEVAFSEBdTu2MnYD+gbXT0G0loAQClYDe6wL1ymq/lIASUAJKQAkogagmoC4wUU1U61MCSkAJKAEloASUgBJQAkpACSgBJaAEfI6AKkB87pJog5SAElACSkAJKAEloASUgBJQAkpACSiBqCagCpCoJqr1KQEloASUgBJQAkpACSgBJRAlBBjn6MyZM7h9+3ak62PZu3fvupS/desWbty4ESrdJZPuKAElEHAENAZIwF1S7ZASUAJKQAkoASWgBJSAEggMAkePHsX8+fNRsGBBlChRAunSpUOMGDG87hwVHzNmzEDhwoWRLVs2U27Hjh1Yu3Ytrl27hgwZMqBy5cqIFy+e13VqRiWgBPyXgFqA+O+105YrASWgBJSAElACSkAJKIGAJvDGG2+gfv36uHz5MoYNG2aUId5ag6xbtw79+/fHmDFjcOzYMcOJlh+//fab2c6YMSOmTp2K1atXBzTDyHbuXmQLajkl4MME1ALEhy+ONk0JKAEloASUgBJQAkpACURnAk899RTy5s1rrDdouUElyMKFC9GmTRunRUdYfOjikjhxYsSPH9+ZZe/evbh69apRqsSKFQsHDhzAkiVLUK5cOWce3VACSiBwCagCJHCvrfZMCSgBJaAElIASUAJKQAn4NYERI0YYC41z586ZmB1JkyZF+vTp0bdvX7z22mvgUuBUkngSHuNrzZo1zsNUpgwfPtzE/jh79iw2bNiABg0aOI9z486dOybuyPXr153p58+fN+dhmeTJkzvT7Rt0t3koq4mHKmxviW4rgagncPfePfPbiPqaH2+NqgB5vLz1bD5AYPb8RTh77jxyPZMDJYoVMS26JGaVf8yca7ZrVK2M80EXsGrNWtR/vQ7ixo3jdat3790fqXJen0AzKoEAI3Dg0BGs3bAJWTNnRNHnCwVY755cd46dOIlFi5eaBtR7rbb4tsc120tWrMJBYZ5BBg+VK5SJUAP1/hYhXJpZCTgJ3LhxE4uXrkCwWCO8WLQI0qVNbY6dPnMWK/79T/bTyP2vIGiNYMmJU6dx7PgJvFC4oJUUbT9z5MiBBAkSIHfu3MbigxYdjAGya9cuLFq0yMQGYVpEhBYgK1asAAOsFi1aFGXLlnUpfuXKFQwcOBCbNm1ypu/fv1+eCeMaa5J69eo50+0b167fkd2wtRjuR1z2XXbCrcZ+yofbdj+ne21ux112XXbcC0Zw36Uulx3XimQAHq6Edzi8Y+FW6uGg13V5nTH0SR6iaKjKvK4r/Iw3b93EhQsXQlXvbwn377T+1nJtrxKIJIFBw8di4+atogDJjoUzJppa5i36B1936W62C+TPBz6UTP1zNl6tWS1CCpADhw5Hqlwku6LFlIBfE+CDf9NW7ZA2TSpwwN7mvWbo0LalX/fJVxq/Z98B5z0tdaqUqF6lkmlap2+6mkFVuTIlIqwA0fubr1xdbYc/EbgeHIxadZvg2vVgpEqZAp06d8Wkkb8jpig76jZ+DwkTJsDFS5dRstgLGNKvh7EwYJlPvvgWZ86ew4I/J/hTdx9JW2/evInNmzejQIECJg4Ig6Lmy5cPWbJkQenSpREnjvcTVWzgPRlE06qESpAaNWqY4Kh25RPz0Mrkm2++4aZTunfvjrRp06Jx48bONPeNS7euIQaCJNnzQJKhW+1HXPatuK5WBpeD7meKov0HncPtuMuuy85DtselLpcd14oZ/DY8JUg4ReXCuMJ3rTlie17X5XXG0Od/iKKhKvO6rvAzxosTFylTerZ+ss55/Phxa9NnP1UB4rOXRhv2KAk8FfMpcDaTLypC5i1cLA8jMXHnNjX3QM4c2fF2gzcRTzT9nLmZNW8hjhw7jkwZnkbNai+ZP7Y7d+/F30uWm/wVy5VGnlzPuJSbPnsecouVya49+3Dq9BkzAMmU8WmTf9WadUYJU7bUi9i7/6BpQ97cOc0xfVMC0YXAr/0Ho/gLhTFmSD8MHD4GPXoPQPMmDZA0SZLoguCR95P3uplzF5r7z5ZtO4zyg/c6S4KDb2DOgr9w6MhRUFFSq3oVMW+9i0X/LEP+vLnB+xKt5hInSuRyf1u9dgM4SEuYID7Wrt+ESuXLIHbs2Ji/aDEyZ8qAai9VNIO6hWKFUqZEcTPjTUufs2fPo3SJYpgr+YoUKoBlK1cb65TXa9fA7HmLcFwUYbVqVBULlXRWE/VTCfg1ga3bd5pnjeUL/gSfASrXqou5C//G0eMnkTJFcvw1cxK27tiF2vWaigXpOuw/eAg/9OiD69euI3fOHH7d96hqPIOU0uKCK7hcunQJ48ePR7FixVCzZk1j/RHR8+zZswerVq3CF198gdSpU5sZbVp2RNSKJKLn1fxKQAn4BgHPDnO+0TZthRJ4ZAQKPJvPzLpwYHD16jXzEM6HcktW/7fezL5ckWNf/9Ad3fsMML6iP//a38zeHD56DDVlRmffgUPYvnO32d4v2/ZyX33XDW+1aIOxE6eh94AhqNe0lZl1+HP2fNSXbQ4Gvvj2J3SQWR4ONlSUQHQjQOVg8aLPm26XELNwzvLtP3g4umF4pP3lrDIVtVdlqUcOumhq/0z2bM5ztm7fCT/37i/3t3v4bdAIfND+CyRLmgQz5izAO60/xpiJU01a7NixXO5vYydNQ9tPvsTPv/TH6AlT8cbbLdCq3Wf4S871frvP8eec+UaZwVnsHbv3mPNNmDIdP/bqizPigsj0pq0+wt9Ll+PTr75HheqvY4pY3VER1rBZa2f7dEMJ+DuBfLlz4Zkc2dCj7wAMGDJS4kqcw0sVyuKc/A6oAKHlQcan05turtu4GeVKl8DA3t3wYoiLrr/3PyraHzNmTGN5QUsPKiw+//xzzJ492zyXeVt/ElGsW5Yi27dvx8WLF/HZZ5+hWbNmeOedd9CzZ09vq9J8SkAJ+DkBtQDx8wuozY8cAfrDV61UXmZGF8isZjbcvXcXNcREfMmyVaEqpA/uzZu3kDxZUnTt3ElmcDKYBxgO1oJlBrRmtSpoVO91jyZhhQvkF5PWnuah56de/UxsEQ4oShR/AUN/6yUzpJdQqNRLoc6pCUog0AkwUNyly1ecLmZWjAqagqtEHQFaUyxftUbigSwTBchivPJyZaxY/Z/zBM3ero9EiRIa5Szjg+zet9/41vfo8j9UqV0fX4qStsU7b0m8pBckdshRZzluxJXByEQx5aeVx3ttO+K3nj8a6478xStgy9YdyCWWdOFJ8yaN0LjBG3j5tYZIICs0jB7UB4NGjMEPP/fGlStXTbvCK6/HlIA/ELgs3+UUyZJhw6atxgIqXrx4xh3m5ZcqgBMln3z1HQ6I4peWWdfE6iOzPGPwNWX6bARJPDIVGOuPiRMnmlVaqACh8uKaKHX5SiTWad5I165dndnq1KkDvlSUgBKIngRUARI9r7v2WghwYDBtxhz0/X2oMdFOJgoOT9Lzx28wYuwkTP5jlrH2qFyxLIb07YEBv/5kTMs//boLbt66ZR7e3ctnz5rFJKVJncp83rp121ic0EScQrPyOGI2rqIEohsBRuxPIy4XQUEXTdcZeJiSLo0jOKDZ0beHJpAlU0YULPAs+g0cBlqp/drtO6cChH7woydMMdZoZUu+KO7R9P11SKqUKY2y98LFS3g2Ty4r2eWTSmFex/gyoKPQcoSBCanMuiMKLkss10K629glVYgfMcsnE397ChUhlDt3He6IZkfflIAfE5j0xwxs2b4Da5fMM0q95m0/Qc++v2Pa2KFIlSKF+f21erexWFp1wtPq+uXxSpcqVUqsdhNi3bp1+Pvvv8GVWapXr27SPBbQRCWgBJRAOATUBSYcOHoosAmUKVlcljFLZnxz6fceltByI4XkmzN1DBq8WcfMpjJ446jxU/DD159jwfQJCJbgZus2bA5VBQcDFA40LCkmMQ/+WbYSk/6Yie+6/SJWJK6DAiuffiqBQCdQongRE19n+649GD1+sgRDTY0c2RxKw0Dv++PsX50aL5v7XBZZaaegBHm2hKtMMP7RZx+3Qa+unWWVBYfygcd/HzYKjHPE+Ebf/NgDzBtRoYKXsvzfNca1aa2Y96sogehGgLElOElC9z6uOHf4yDGjNKS7V5+BQ9Gy2dsmjUrDamIVohKaABUeDFj6/PPP491338Unn3xilr+1nrFCl9AUJaAElEDYBPzOAuT27ds4dOiQS49oDkffvugil+UP6OnTp02wpjRp0oTqNl0zjhw5EubxUAWiaUIs8SnlkreTZXaG7jB8SPck9Mf96vtuGDZ6AoJk6ad2rVuYQQT/8JauUtv4lObKmQN1XqlmlrnzVIc97ZO2rcw69mNk5rVq5Qry3U0c5vr19nK6rQQCjUDHD1ujmcSZqPZqQ/M76PPz9yaQZqD180n3h24vVLbSXc8uaeVvZ9EihfA/ub/1kThFtMK4LG5JjGv0S79B+PD9d/Hu2w0kaGM9E7OjhtQTEWHAxwplS2G43Du5zDgDqh4/eSoiVWheJeD3BOjmxUDBNes2NhZSDLz+7ZefmN/b9FlzUbRcNdACtXe3700gYr/v8CPoQJcuXbBjxw7zvHVLlElZs2ZFkSJF0KhRo0dwNq1SCSiBQCcQQ2am709Nh9NbZqPPNm88HIBT6fAkhAP7zJkzhzp1oUKFzJJWBQsG/nrpo0ePNktw8cY/ZsyYUCy2bt2K5557zvxh8HQ8VAFNeCABKt7OngsyJt5WrAIWonk4j3FpO29l/OTpWLZqNb7/6lMz0HireRsMlqXvqlQs520Vmk8JBBSBc+fPy28rGWLKiiUqj5cA/7ZzqU26s3AVl0chdG+iopdKZxUlEF0JMOB68I0bJvCpnQHvfymSJzfKEXu6bt8n0KZNGxOslM/4p06dAldxOXfunLECuZ/r0W95swzugZPXsHp3EG5LYGlP8lQMSNw5xxHZNGLlDDEaNqu8mmPy5t0oLaQi2wfrssrat21ZzGZ4x5jBftxje6XxbH/UtjeGi+W0aWjIGycfwxu62ttrL8dtHmNjTXtDOmMxcs/7oH37eezbLBdyGlPF42qv/Zye2m5vo3te+34M+YLes76gHip6Jl1CvJjnwcvgPv20Y9VLD1VESdKZM2fMRD+fW+iKG1FrML+zALGocX1uaoTv3LmDNWvWYNy4cahbty527twZYQhWnfqpBMIiwCjt6dKGVvrR5z2iUrZUcUydMRvFKlQ3/r/vN2+CyrKEpIoSiK4EUoofvMqTIcCHBitG0aNqAV0IVZRAdCeQMGECs/qcOwe9/7kTCb1fokQJbNy4Efnz5wcHVo96cBW6BZqiBJRAIBHwWwUIoz5TI2zJf//9h927d+Po0aNInz49+vTpgwULFpj1wrNnz4527drhhRdeMNknT54MWlFQe5w1a1ZzrGjRomYmv0ePHli0aJFZjpFWJZ06dTL1seDevXtB7S81z88++yw6duxorFF4U+b5qIBZunSpWVs8d+7c+P57MWcMsZQZPHgwpk2bJmaOydCqVSuMHDkSVatWNZGtWffChQsxfPhwiRB+FqVLl8ann34qgeTiYcKECaYfbH/fvn0lZkVyY93BMnYZNGgQpk+fbup//fXX7Yd028cIZJDl7qaMHmw02BHVWPpYV7Q5SkAJKAEloASUgBJ4pASCgoIwZ84crF+/Hnw2pyKEz+GJEyd+pOfVypWAEghMAgFhb0xzOJrCcDBJyxAqJjp06GCUBbVq1cKsWbNQuXJl477zzz//GEUFAyrVrFkTK1euRPny5U35H374wSg8cubMadIGDhyI2rVrmyu/a9cuc9OlcoQKlrFjx6J48eKmHGOSUHlRv359zJ07F/v37wfLUmlBoeLivffeM7FLaEnw5ptvmvy0XKHQTYXKkIMHDyK+RMCnZcsrr7xijq1evdrkZTtGjRqFY8eOmXT7G5U2LVu2xIEDB8SEPKbZth/Xbd8koMoP37wu2ioloASUgBJQAkrAdwhwwpOTl3zODg4OxrBhw1wmQX2npdoSJaAE/IGA31qAUOmRL18+4wJDBcQN8atkZGgGQ33xxRfRv39/tGjRwlhyTJo0CRs2bDDWIXSRoSRIkAAvv/wyqCCh5Qj9yRhgiZIqVSrja1ilShVjkcHYJ999951ZdosKFCpAaG1BRcbvv/+OAgUKmHLUSvM4rTho+WEpOGgdwuW7Vq1aZRQ0tNagwsKSzz77DHnz5jVl6cf08ccfo1+/fli2bJmVBbly5cL27duNgoTWK3bp2bOnsfzg+agNp3LmrbfesmfRbSWgBJSAElACSkAJKAEl4HcEaLFNC2tr+ds33njDTHL6XUe0wUpACfgEAb9VgNDSIVOmTAZisWLFULZsWaMAYQItOLp164ZevXqZ1VDsgd2oPaZFCF8zZswwCokGDRqgWrVqoCKCShBaYPDFYKtcaotKiU2bNpkgsO4BWLdt2+ZUgLAdFCpQUqZMaZbs4j4VNFRg0DqFwmW8LKGy5Pjx4+bFpdLswrotocKE1iHuwoC0J0+eRJkyZZymgFQAqSgBJaAElIASUAJKQAkoAX8nQHdwKkE4Wcln4X379hnLaQb8V1ECSkAJRJSA37rAUMkwf/5886JFBK09qKjgzZHKjMWLF2Po0KHmhlleXFwsoaUIFSMnTpww5nRZsmQxVhx0YWF8Dlp20JWElh0XL17Ehx9+aAKrcrlZuiz8+++/5sbLmy+VIlS0WMKYHZbY3RsYrIl1sj4KrVEs4TnjxImDHDlyOOulRQrrpoWJJcznSRgLhX8M7K4xVIioKAEloASUgBJQAkpACSgBfyewefNmY9nMiUZacFesWBFDhgwxsfv8vW/afiWgBB4/Ab9VgISFigoOWlXQ2oJWF1u2bMHy5ctNdrqyMN4GA5TSTaRSpUp46aWXzDG6zlDZkSdPHmM18uqrrzotO3iMliNUrvz6669GUdG7d28ULlzYRfEQVpuaNWuGa9euoWTJkmjSpImxNLHyMiYIg5ZSocI2MdBq69atjRLHrkSx8rt/Mg/byrgjtGD5+++/TRwT93y6rwSUgBJQAkpACSgBJaAE/I0Ag57SLfzWrVtmMpKu51evXjVx+PytL9peJaAEnjwBv3WBCQsdrTDotsLVWhirI1u2bCZaNJUgtIx4//33TSwO5mnfvr0JGsp4GbS24EowXMmF7jQUxtNgfA1acDRv3ty4snCfpnhM4zmo1Pjzzz/Dao5J/+qrr0wMEAZIpYJmwIABRqFCNx4Kg6QyqFPnzp2Nmw1jmzDgaQovl4a0XH1+/vlnMCAqA67a44eYk0TDNwa4VVECSkAJ+BMB/k2JqOi9LqLENL8SUAJPkkBE73PvvPMOOPFIC2o+23M1Rrq3h2Ud/ST7pudWAkrA9wnEEKuGe940k9loQUHtK+NOWMu7elP2SeQ5f/68sbrIkCGD0Ra7t+HSpUs4ffo06NpCCw+7MMAqNcss6x6X4/bt20aRkjFjRnuRcLd50+bSXVSEMD4JFSdc5pZL41KxYgmtRK5cuWLaZKVF5JOWL1QA0S1GRQkoASWgBJSAElACSkAJ+DsBPhvTYvq///6DFR+Pse+4FO7jFD6/p02bFo0bNw7ztAdOXsPq3UG4fdfz8OqpGIB1SDaNWDnFqNuxLwlmU968G6U5ytnfWZdV1r5tz8Pt8I65Hw9pHlzaKzvcj9r2xjBW9zy/u9DyPbyha3j94TE21rQ3pDMWI/fzPGjffh77NsuFnMZU8bjaaz+np7bb2+ie174fQ76g96wvqIeKnkmXEC/mSe7hyP0kxrakocCjFK7+SkMFKkIZAsMbrwl7ewLOAsTqHK0nwrOgoNLDXfFhleXNLSzhDTgiyg/WQ6UHl+adOXOmCdxKX8ZSpUqhUaNGLqehXyNfkRXGRVFRAkpACSgBJaAElIASUAKBQoArOx4+fNi4qdO9nS4xj3qAFSjstB9KQAmEJhCwCpDQXX1yKdWrVzdL7c6ZM8cEbKLGmoFZLReYJ9cyPbMSUAJKQAkoASWgBJSAEvBdAh06dMD27duxZs0ajBs3zrm64sCBA3230doyJaAEfJaAKkAe06XJmjWrCW76mE6np1ECSkAJKAEloASUgBJQAn5PgBOGXPKWr6ZNm2LWrFlm8QBf7BjdK/gKFLG7RwRKn7QfSkAVIPodUAJKQAkoASWgBJSAElACSsAnCXCFwzt37hg38kyZMhkrai5AwAUEGPtORQkoASUQEQKqAIkILc2rBJSAElACSkAJKAEloASUwGMlsHHjRsyePdssxMBFGRj0UF3JH+sl0JMpgYAhoAoQLy4lAy9xhZXnn3/ei9yOLMeOHTOrxRQpUsTrMppRCSgBJaAElIASUAJKQAkogfsEypYtC76o9Dh37px5vs6SJYtZAeJ+rohvWauJRHQFiYifyX9LBJI7j/9eBW15VBNQBYgXRI8ePYodO3ZESAHCpboWLlwIVYB4AVizKAEloASUgBJQAkpACSgBDwR69OhhgqAWKFDA6QbDpTavXr2KZMmSIX78+BFeBvPIkSPYtWsXbt26Bcbpy5s3r4cza5ISUAKBSMDvFCC0xrhw4QJOnDgBrgv+6quvmvV/V69ejQwZMpglas+fP48tW7agXLlyJlBSwYIFMX/+fBQtWhSpU6c2JnS1a9dGmjRpzDU9ffo06EvIZXNr1qyJOHHigCu20OJj5cqVKFasmHN5WmqLeezixYuoUaMGkiZNam6e9E/cv38/SpcubYI0BeKXJVD6NHv+Ipw9dx65nsmBEsUcFjqXLl/GHzPnmi7WqFoZ54MuYNWataj/eh3EjRvH667v3rs/UuU8nWD/wcMYMnIsOnfqgLPng7Dy3/9QpHBBZMuSyWQ/feasnGsdateoavaXr1qDDZu3om3LZp6q0zQl4JMEDhw6grUbNiFr5owo+nwhj21ct2Ez9h86jCIFn0P2bFlMnuvi+z1/0T/I8HQ6Zznen4ePmYh33qoX4Ydhjyf248TtO3fjv/UbQ/WgRLEX5N6XPVS6JigBJfDoCNyW+BWLl66QAfs1lC31IlIkT/boThaANSdJkgSFCxcGl8A9efIkhg0bhsSJEyNdunTmub5+/frO53Rvus94IlxaN3PmzPKMFxeTJ09Gly5ddGldb+BpHiUQAASe8rc+rFq1yigp/v33XyxZsgSVKlUyXRg8eDDWrVtntg8cOABqiykdO3bE+++/b5QmVatWRePGjXH9+nUTQGnnzp24du0aKlasCCpNeAOkYoTyxRdfoG7duqAry4oVKzB06FCTXqFCBaOF3rt3L9566y2T1qdPH0yZMsVooZm2b98+k65vvklg0PCx+LpLd3n97GzgPBlIOdK648ix4zggg62pf87GjZs3nHm82YhsOU919+gzAAdlcHj37j281uhdUOHBzytXrprs3XsPcHmISp82DXr2+R179x/wVJ2mKQGfI7BClHpVatdH7/6DUbdJS/TsG3pJwz6/D8UbjVugz4AhqFKnARYvW2n68WHH/2H9pi3o+NX3RhHIRCoxz8q9XM2ZYZQf3X75Ddbrmx97mnvcBmGmogSUwOMl0OS9D8F71g/de5t73slTZx5vA/z8bFwC96WXXjITj1wFhs/ofJbnJGiJEiXMxGVEusiJVD7Hv/baa2ZccPPmzSh7dueqKXypKAEl4LsE/M4ChChLlSqFb775xlCl9pea3PDkk08+MQqPRYsW4Z133kG9evWM2RsDKm3duhVUarz99tvmVa1aNezZs8dU9+OPPxqLjokTJ5p9msolT57cKFWYMGrUKNy+fdv4JTZv3hy0TmF06qVLl5p8ppC++SSBp2I+BVpr8MXZ0HkLFyNmrJi4c9vxXcqZIzvebvAm4snMwI0bNzFr3kKjGMmU4WnUrPaS+WO7c/de/L1kuelfxXKlkSfXM7CXmz57HnKLlcmuPftw6vQZVK9SCZkyPm3y03Jjo1hrcCZo7/6Dpg15c+d0sqKSY+HfS9G1cycz802rpNYtmmL6rHmmzfHjxzNWLGVKFneWyZE9K57Nm1tmwCfhh68/c6brhhLwVQK/iuKj+AuFMWZIPwwcPgY9RKnXvEkDJJXZPspVUVD3HzwCHdq2Qpv33sE773+MX34bhAplSuLf/9Zh4Z+OezMVIYUL5Mew0RMwccTvvtrdx9quJg3rgi/KytX/4a0WbZEzZ068IvcvCu9L/yxfhdQpU5h7U7x4cU2+O3fuIlHCBNgj96W6r9bE/gOH8Jfc53gPerlyeaRNk9qUpyJq85btYgWZGK+8/BJSST0qSkAJhCZAa1JaaE4bOxR58+RE6Sp15O/0BHTq0DZ0Zk3xSKBMmTIYPXo0OnXqZCyvs2XLZp6/+UxOy+6ISsqUKc39sFu3bsYChOU9xfljsFW7cJ8vWhuqot1ORreVgH8R8EsFSNq0aZ2UY8eOHUoBQqsOuxQq5DCrZl7eNCmxYsUyriuM1bFp0yZ8/fXXJp1uMk895TCMyZ07t0mz3mh1Qj9BS2hNQpk7dy4+/fRTE+/DKmvl0U/fJFDg2XzYs28/Zs5diFbN3saylatRukQxLFm2yjR49X/r8fk3P6CSKDY4g7pkxSozGPj51/4ySFiLj1o3R826TVCrehVRkNyQQdlgzP9jHFav3eAs99V3/MMaB9klUNe2nbswctxkrFj4J2bMWSAzQV+hcoUyoOXJth27TH12BQhdWTgjQaVK2tQpcfHCRRnwrcfps+eMyX/H/32PLz/5KBRc5qdiRUUJ+AMBDsJbNG1kmlqiaBHznafrF5UZlMNHjsksXzBeLOoIQP2iuKz16utQcDydPh1W/LsGO3buQbEihTFk1DjUe70WEsrgXeU+AboYtWr3OZInS4ph/XshYYIEWLR4GVq3/1zuQWWxSZQYYyZOxdQxQzBM3Ie2bd+FIJkdLVe6BKjwbSwz1+R/UdwEaZU2a/IobNi0Fe2/6Iz3320iVjfzMHTUeCyZO835t/P+2XVLCSgBTpbEih0Lzxd6zgyaC+bPhx27HRNtSsc7Am+++aZ51ufEZKpUqYwbOt3YqQCJjNDqmxOYjB1C5S5Xk2FMkDx58jirY57OnTtj7dq1zrRTp06Z8QOtw1u0aOFMt29cuiwKEvkXltiP2LdNfvcE9/2wKvWU7m3ZB+WzHbdtOs4YKsFTQ7xMc6nLZce1AlE+hSvhHQ7vWLiVejhor8u+7Z7VF9vr3kb7/gPae/3GdZw+fctewi+3/VIB4ok0/QMZGZpCRYVd7FpaK+KzdZxuMVSYDBgwwGh1W7dubXwKreP2z/Lly2PgwIFG88tBL+OFzJgxA3379gUDpfIGqkFP7cR8d5uznVUrlRcFyAKx2siGu/fuooZYaFgKEHvLjx0/IQOzW2YAQYuMTBkzW7AwygAAQABJREFU4MyZc2awxjXoa1argkb1XkfKlKH/EHMgN6RfTwwYMhI/9epnYotwsFGi+AsY+lsvXLx0CYVKOWZk7ec8dOSo2U2fLi1SpkiOnj92NlYoPbp8je279iC9KAFZtlb9pogbOw5++elbZMyQHunEDWbuwr/tVem2EvBJApxFu3T5ijPGDn+TlIuXLjvba23HlQdUCi2ygoNvGKusPj9/j3GT/0D1qhVFAVIIg0aMwe+/dsNbzdvgwsVL+OSj91FeBvHRWRjbqFnrj40SaeTvvyODKI0ovQcMNkqjhm++KvFTCqKzuMdQsUs5HxSEv2ZONveTJq0+Qv58uTF6cF8whsGLFWqYGCu09rgrliKUNi3fMdYfvJ46AWCQ6JsScCHA+1gc+TttPYvyXnf8xCmXPLoTPgHeW/h8TYUHA58mEEUuJyw5mRkZWbZsGYLkXvfbb78ZBcgPP/xg4vvZFSCMC0gXd7t0794dnIS1JkDtx6ztq3evIcaJINn1PCqme4x1hNsUa9/pO2Ml2DM7snr/7m3ZB+WzHecmxWqeaa9zx3Es0u+28ziciMKoOIZkDG+Q7lKPW2vCO+aW9YG79rrs2+4FfbG97m207z+gvfHjxpcYmqHHO/YqGKDY1yVydw4f7BVjb1B5wVgcVIZ4K4z/MXLkSFARQu0vXWESJkzosTiX3KpSpYpxeaEi5d133zXa4+rVqxs/Qj4A8gbN4EwdOnTwWIcm+g6BWhI8dNqMOegrMQbKlCguMVySemxczx+/wYixkzD5j1lgYMHKFctiSN8eGPDrT8aC5NOvu+CmRBEfPcj1DyUry541i6kzTepU5vPWrdsmCFrmTBnMfuJEieTBKLbZtr9ZijrrGK1F+KJ5OuOADO7bHR+0/wIftWpufP2pVPm8fRv5PsYThd51ky+muPmoKAFfJcAH2jSpUspD6EXTRAYepqQLcbHgtuVucV4sEii0TEiWNIlRmuTOmQPffvGJSf/i2674sOW7mDBlOvKIKxmtuX7pNyhaK0CosHhfLD/owtJblEWFJYCsJYw/QCXR2EnTTFL1qpVEecEnOCBHtqxG+cFtKnrpWkeJJQr+9OnSSNpZfCGm+/HjxcOif5ZhkLgupUubGjMmjjRKYpNZ35SAEnASSCsuGoxXQeUtlR+81/E3o+I9AbqwT5o0ySg++BxO6wyu/hJZoeUHF1I4e/asWQCB9eXIkSOy1Wk5JaAE/IyA3ylAGL+DL0uotKDQd4+WH7yhJZJBpSVcvtaSmTNnWpvo3bu3c3vs2LFiznPaWHDQL5DC+CCW2M9JczgGVmXUaEvzTAUKo1LTLI9pDK7EG3OdOnWsKvTTBwkwfkZyicTOOCDvN28SZgtpuZEvTy7MmToGnTr/iD8kDgeDN44aPwX9e3U11iEvVqwBrlRhxS6wKrNmfCyFBtOLScwDDtQm/THTKFT4UOQu2bJkNkknTp2WSOf3v88Tp/2JCmVLggoVxkdInDihMfk/J6vEUE6cPC1/zJPLd1mVHwaIvvk0gRLFixjLppriSjZ6/GSj8Mghq7z8/Otvxs/73cYNxOUrPcZMmCbKklTGfYzWU3bZs+8ADh0+ahSE9LXnbzCxKLGDxUovOgvvW4w7UCB/XmPqPWX6LIMjX97cKCSWaQcOHcJ3X3bEUQn6TNeXvLlzmeM01beEFmwLFy81MYyCxA1v5+594vZX1bjz0ax/rMRuoRshXfpotUY3GxUloARcCTDOkZh/GDe9IoUKmGeF/33WzjWT7oVLgJOb7dq1w8GDB40lDV1RBg0ahA8++CDccmEdZEDVzZs3m4lTWpTQPb5p06ZhZdd0JaAEAozA/SedAOmYXfkRkS5ZS+J6U8aThQiDsVryMFppqw79fPQEOKPJJW8n/zHDuMMsl3gCnoS+8F99380EWOQMdLvWLUAfXio3Slepbcwnc8lsdJ1Xqpll7jzVYU/7RAI60oVqzIQpqFq5glgsJQ5lOk63HNbPGAjWkpVUeIyZMBVTxgw21dV7vba062eZVQpGvx4/mrTDMggp9Nyz9tPpthLwWQIdP2xtXDSqvdrQ/A7o1sJYTdNnzTexblq+8xZ++vYLtP3kS7wseZ6R34V74MCuPfsa6yd2klZdbTp8gVnzF6Fxgzd8tt+Po2GbNm8zp9m8dQc6fPGt85TtPmiBbz5vL3FBPsMLZV823Nu2amYsa5yZQjbat22JfQcPobi4vlBeebkymjaqi31iVTJy3CQULV9NFLHXxQ2pkrjK3PedDymuH0pACQgBLt39WbvW6C4xdBhondac9V/XCbKIfDno+nLxosNakO7mXN3xvffeM6sxJk0accUrn6+4QELLli3NxCndWtSFLyJXRPMqAf8mEENmpsNwsnLtGLPRxeOWmPpfFr/iyERddq1R95SA/xBgsKyz54LMIMGKVcDW04ycxyKyAsL4ydOxbNVqfP/Vp8YChDELBvfrgSoVy7kAadqqnVnmtlfXziad/vwXL152riTDRKYxLgKDeHGGtmi5auj23Zd4vbZjwGIK6psS8HEC52jOnDRZmJZLdP26cPGCxMNxXWmEf5N2SiDVfLYVlLhqEwMI2y2nfLz7T6x5vH/RDe9BFmO8z9C6MYGYjVvCZ4IzEpSZ98MkiRNbyfqpBJRAGAR4bwq+ERzKUjSM7JpsI7B+/XpYVty01njmmWdM7D7G6IhsIFRb9V5vehMD5MDJa1i9Owi373oeXtHb0DrkcDy8H1ND9DJGODIzm/Lm3SgtdBdYl1XWvu2eM7xjzGs/HtI8ZwwQHuMOe2qO2c7JshERl/PITljDUyqvwjrG89nrcT8/jznbaxp8n5F73gft289j32a5kNOYKh5Xe+3n9NR2exvd89r3Y8gX9J71BfVQ0TPpEuLFPMk9HLmfxBggTz/tWPXyfmrUbp05c0ae8xKbSTMqL8k5IhJwFiAR6bzmVQLeEuDDvyefXcYjiKiULVUcU2fMRrEK1ZFKBnR0v6lcvkyoalo2e9tYnlDpyFlxDjLcBxr2fa5Uw2Vwa8ssuIoS8CcC7ooN97ZzgO4pD//o2ZUfLMeVl/hSeTABb+9f9vuMVSsfNqzYRlaafioBJRA2Ab03hc3mQUdoeV27dm0sX77cvFasWIFXXnnFuEo+qKweVwJKQAm4E1AFiDsR3VcCj5gAYxpMGT3YaLDD01iWkCU//5o5yevW1KnxMvhSUQJKQAkoASWgBJRAoBBgrL3KlSubmB20/KPQFSa8Z6hA6bv2QwkogagnoJESo56p1qgEvCKgf7i9wqSZlIASUAJKQAkogWhMoFSpUvjzzz+xZ88eXLp06YETSNEYlXZdCSgBLwioBYgXkDSLElACSkAJKAEloASUgBJQAo+HAOM8cPlgugDTFZgLDIwbN04CNyeR2EPxzMot1atXfzyN0bMoASUQUARUARJQl1M7owSUgBJQAkpACSgBJaAE/JsAg1nPnTsXOXLkMPE/KlSogAuyEh9fZ8+eNQsy+HcPtfVKQAk8KQKqAHlS5PW8SkAJKAEloASUgBJQAkpACYQiwFgfp06dQsqUKU2sj40bNxrXl/Lly5vP8FYCCVWZJigBJaAEbAQ0BogNhm4qASWgBJSAElACSkAJKAEl4FsEuOzl/v37TaMYQ42rgKkoASWgBCJDQC1AIkNNy/gFgZUrV/pFO7WRSkAJKAGLQMmSJa1Nrz/1Xuc1Ks2oBJSADxCIzH3OB5qtTVACSiBACKgCJEAupHYjNAH9AxuaiaYoASUQeAT0Xhd411R7pASUABAcHIwFCxaYlV+OHTuGxIkT+zyWe9JCvlSUgBLwXQI+pwAJun4L209exolLN3yXmg+1LH2SuMiXLjGSx4/tQ63SpigBJaAElIASUAJKQAkogcgRiBs3LmrUqIGlS5di0aJF2LlzJ2LFioXt27ejcOHCKFKkCPLkyRO5yrWUElAC0ZqATylAqPz4a/dZFM6YFCWzpUCMaH1pHtx5apj3n7tmmFXKlUqVIA9GpjmUgBJQAkpACSgBJaAEfJwAY3zkzp3bvNhUrgqza9cubNmyBTt27MD69evRs2dPH++FNk8JKAFfJOBTChBaflD5kSNlAl9k5XNtooLIYkV2pURppKIElIASUAJKQAkoASWgBAKJQJw4cfDcc8+ZF/t1+/btQOqez/aFYw116fHZy/PYGxYo3wWfCqFMt5fsqvyI8JeZzNRlKMLYtIASUAJKQAkoASWgBJSAHxKgO4wvChUGasHui1dG2xQVBO4FiDrMpxQgvDB604j411OZRZyZllACSkAJKAEloASUgBJQAkpACSiB6EXA5xQg0Qu/9lYJKAEloASUgBJQAkpACSgBJaAElIASeBwEVAHyOCjrOZSAElACSkAJKAEloASUgBJQAkpACSiBJ0rA7xUg8+bNM8thFShQAOXKlTORoUm0cuXKUQr2l19+wbPPPmvOVahQIXz00Ue4fPlyuOcYOnRomMdPnDiBt99+G4cPH8a7774bZj49EPUEZs9fhD9mzn1gxcdPnsLEqX/i3PkgjBo/BRu3bAuzzCX5LowcNwkHDx8JM48eUAJKIDSBA4eOYPL0Wfhv/cbQBzUl0gS279xt7km8L9lfu/fuj3SdES04aMQYzFu42BT7e8lyzF3wN+7eveusZvrseThz9pzZv3fvHr7t2hM7du1xHtcNJRAoBG7fuYOFi5di+qx5OB90wWO3gi5cBH8TC/5e4hLgc+v2nZg2Yw4uXrrkLLduw2as37jFua8bSkAJKAEl4D0Bv1aA8EGqdevWmD9/PjZv3oyvv/4aLVq0ML0/duyY+eSyWe5y69Yt96QH7gcFBRmlx4YNG7BmzRokSpQIbdu2dSnnXq/78lx2hUnatGnRu3dv80fu5MmTznquXr3q8oDoPKAbUUZg0PCx6D1gSLj1nTx1BqVeqoWxk6bJQ8dleWiZix07w34wv3L1Gqb+ORvHT5zEtevXkTV/cYwYOzHcc+hBJRDdCaz49z9UqV0fvfsPRt0mLdGz78DojiTK+k+FUrdffnO+vvmxJ77u0h0bNj2eQRMVLT9274OUKZNj2OgJ5kVFV5/fHRMDh44cxYQpfyJ1qpSmzzFixMCZc+fx26DhUcZAK1ICvkKgyXsf4sOO/8MP3Xubex6fMexy7vx5VK3TAF26/Yp2n32NBs1ag0pBKj9at++EbaLQfO/DT00RKlO+7dYLWbNksleh20pACSgBJeAlAb9WgHCN8NixYxsFyMWLF1GpUiVMmzbNdP2O/IH49NNPUatWLVSrVs0oFbhkVr169fDaa6+hTp062LhxIz7++GNTnoW4vNaCBQtM+ZIlS7po4E1iyBuX4vr222/xxx9/gEqPffv24a233kL9+vXxzjvvGMuQ4cOHg0qYrl27YsmSJShdujSaNGlirEiY//jx42jUqJG9WjRu3NjUU6JECWc/XDLoTpQTWLn6PyxbuRqr127Ab4NHgLMqnJHs8/sQ3L1zFzWqVkbaNKnQqO5rKPhcPly4eMnMVtPSgwoOWoZQ4ZFEFGJvN3gTWTJlxKx5i3BPlHPrN23Fth27TJt37dmHgcPHmFmc4OAbUd4PrVAJ+COBX0XxUfyFwli+4E983r4tfh86ymWW0x/75CttbtKwLrb/t8S8hvTrgaeeioE8uXPilWovmSZ6uidZ90MqSSb9MdPk23/gEAaPGCtWJJNx6vT9QdviZStFcTXE3AfPiuLCXWhllzFDehR9vhBWrVmHN+q8gjflxXss5ade/fBZu9YuxerUeBmzF/zlch6XDLqjBPyQwKo1a7F81RqMGdwXS+ZNw11RbAwfM8GlJ/x93bhxA0vmTsOE4b9jjTyT/LN8Fdas24gSxV5Am/fecf52xk6cimqVKyBF8mQudehOxAlQybRt2zasXLky4oW1hBJQAn5LwK8VIKRO649Vq1ahYMGCxgVm79695mJQAfLee++BLjJXrlzBoUOHMHfuXKPkmDlzplFgdOvWDdWrVzd1HDlyxGjb//rrL+zevRvZsmVDeEts8Vj27NnBcgMGDDDnmjp1qlF0zJgxwyhCMmTIgE6dOuHMmTMYO3YseLxq1ar4+++/TRvta5izvStWrMDPP/+M2bNny6yZY1bMZNS3R0Zg2JiJaPPJl+jctQfGTJiK199ugR2792Dv/oPmnFtk9uXGjZv47OsfMP+vf4yFxydffIuGzT7AHDHn/vqH7vjqu25m5pLpm7Zux6Yt203Zw0eO4ejxE1i0eBlq1m0s6dvMDHfDdx0zO4+sU1qxEvATAhyEFy/6vGltiaJFQIu9/QcP+0nr/aOZdDFq1e5zJE+WFMP690LCBAnCvCfxfvjp/7qY2ee//llmFBdVX22IpSv+xdQZs1G5Vj3QcoNm/O9+0B43ZQLgj5nz8GrDZqEsF1evXY/cOXMYSBmeTocNm7di7YZNyCxKYn4+JRYfhQs+5wIxT65njOJ5y7adLum6owT8mcDO3XsRK3YsPF/oOSSIHx8F8+czzxn2Pu3cvQ/58+VBwoQJUCB/XiSQ3+lOcQd7On067N67D0tEGZIlc0aZYLuCyX/MQrO3G9iL63YkCdANfdCgQc6J0EhWo8WUgBLwMwJ+rQC5cOGC0Zj3798fBw8exE8//WSsMKhFp4LimWeeMZcjY8aMuCS+k3PmzAEtOyhUmPz7778oX768+Vy4cKGxGGHarFmzjIWIyRjO26lTp0BXlkWLFqF79+6oXbs2pk+fbqw77MVSpEiBli1bmjrXrl3r0bIkZsyYoMsMlTYVKlSA3S3GXpduRz0BulLNmTIG/X/paiw3+IBR//Xa5kRfdvzI4yxLs7frY9LIgShbqjg2b3MoPKyWfdnxQ7NZq3oVVK1UXtxtBqNYkcJo+OaraN6kgZnFWbl6rZVdP5VAtCTA390l+a3FjRvH9D9evLjmky5nKlFDgLGJmrX+GNevB2NI3x7IIIMpSnj3pPPi7rloxiQM7P0zfh82SgZluTFaZq6njR2KuGL9OFyUJFTs0kKO0qblO+jTvUsoBQgVJenTpTV5Pv6ghShe4ptr3fGj941bTkex/uj41feo9nojY33HjOnSpgZdYfbLhIWKEggUArynxYkdx3y32Sfe6y5edL3PMb5H3LiOeyDz8L7IclUqlgWfJahA7N+rK/qJi1jzJg0xYep0VH/9LbTp8IXHZ0rWoRI+gWvXruGff/4Bn79pTa6iBJRA9CEQy5+7yngZr7/+ujFdS5IkiQlQyk9aVtA9xl3Kli1rlB0VK1bEli1bkC5dOnPTy5IlC0aNGoXJkydjwoQJmDJlitMVxr0Oa58uLgyGmjBhQpQpUwavvvoqWO/SpUsRHBxssvFBjtKuXTujVMmcOTNatWoFWnu4C2/EdI1ZvHixUebQUoTuOiqPnkA28aPltUqTOpU52a1btx940hzZspg8LHPw8NFw89PXl64zjCdCqV61kjFHD7eQHlQCAU6A9+g0Ev8hKOii6akVGDBdmtQB3vPH0z3GCXhfLD/owtL75+9drC3CuyflyJbVuK6wlWfOnEOO7Fm5iVgySEifLo2kncUXHdoifrx4WCRWIoPEtY+KixkTRxorE5NZ3sSyXAZ9jkFFUvm7/Gm7D8yhGXMWyAx3PpyQINMMeDpl9GAULvUSmjaqa2bHOXlx+fJVqxr9VAJ+TyBt6tSihLwuz4Y3jPKD9zr+ZuySVu57h0KeJfjbvSyWy8zD++Q7b9U3WY+J4pHWUx9/8B4KlKiIdUvn460WbbFcYimVL13CXp1ue0GAbvDnzp1DkSJFjJW4exFab/OZ3e4ew+d7XhNOZn722WfuRcz+edFt0c0pLLEfsW+b/O4J7vthVeop3duyD8hn70qorKESPDXEyzSXulx2XCuwN8j1iGMvnKII75inusJLs9Xl3iTbIccfQy/rCZXNpaJQRyOWYKvLtmnqcNl374zbWa5du25CPLglu+xa41+XRB/b8WsFCF1MqFwoVqwYnn76aeNq0rFjR6OU8MS5Zs2aeP/9943ShMoGmr1RmE7Xk9TyR4rWF9QIM8ipu3Tp0sW4uzDuB11khg0bZrJ88MEH+PLLLzFw4ECcl0BWY8aMMempUqUy52vYsKEJ1kpLELrjMP6Hu9DckaZ4b7zxhgwIgkx+9zy6/4gIhCiqzBO7t6cIp8xTMRzKt8NHjxlz1UIF8uOAzGh+92VHHD12HDQzz5s7l7dn0nxKIGAJlCheRGLmLERNmeEcPX6yxNtJDUu5GLCdfkwdY4wNxh2gOT0nBaZIAFJKvry5Ed49iab6lhSWexdXrmDsD65QQTP9WtWrmnggNOsfO6QfZs5dKMEdvzKuMXSzsYSK5ROnTlu75pMuTgOHjca4Yb+Z2AaJEycyihQ+b7GNtD7h39c0qdUF1AWc7vg1AcY5klkWDBk1DkUKFTBWoP/7rJ1ZxWXSHzPwXtO3ULJYEfktLTC/WQY8vXP7Dl4Ut0C7/CRBjTt+1Nr8Vu6IBR3dZRLJS+OK2Sl5t3369GmMHj3ajCGoCOH9h8qNeKLYtYRjArqu24XW3rT8Zsy+sOTGyWuIcToozIEvp0atAadjmvT+PtwT7JnDOmFY6d6WfVA+23FuUqz2m/Y6dxzHIv1uO4/8YOxnca2Sz9/hDdLDKRpeta4n8WLPdh73JtkOmd++z7XXjW5E2ptArDkzZEgRLiBP49xwCzyBg/efdJ7AyaPilM2bNwdfVBokT57cWeWOHTuc2+PHj3du84ZHawsqHCyhgoIvChUofLnLd999B748SZ48ecxNkhr++OLfaQmDn9Idh2aNPEYTO3tcEbrdUBjzg8JVYZifmjMGWlXxTwI0by1R/AUMl5UPEomF0Deftxcf/M/wQtmXkSRJYrRt1QzJkibxz85pq5VAFBLo+GFr46JRTeJM8LfRRywV1BQ5agBv2rzNVLR56w50kPhElrQTdxRv70nt27bEvoOHULxCDVP8lZcrG0uNfWJVwqV1i5avhqsyG0SrNsYvsEuuZ7KD57YL3WderVkNtAgpKYEdu/bsi3pNWqFq5fImzVrWs9Bzz9qL6bYS8GsC2cVilAF/u/cZYBQblSuUETfbOpghCo/xk6ejdo2qeL12Dfy9dCUavfsBnor5FNq3aQnGxLFko8QQuy4D9BdDYibRvbZe01aimLyAMiWKWdn000sCfO7mszmtO3bu3GkmUBkzkAskqCgBJRD4BGJIBGSvdHfMRp9tzs5wOVdqRqNapmw6gTcKpo/qaqNFfcrO9y4zZ2U4mIspDzMUusEkFssia9/3WqwtUgJPhgCXgEyWNJn+Nh4zfm/vSYwlQuU9AzhawmcCrphFhW+SxImtZOcnA0LXrtcUS+f/gcwZM5h0Br3NnjWzU8nFZwpalqRM4Zi86CJLhM5ftBjL5k931qMbSiBQCDCgevCNYKPsC6tP/K0xXogVE8nKd+zESWMtZV/55dx5mfgTqytPLt9WOf30TODAgQOgFQiFsf+4UAJXceRqkOGJNxYg+8UCZPXuINy563l4JQtyiYuM4yyceadYOWlJYPYlwWzKm3ejNEc5+7vdKsG+bc/D7fCOuR/32F5pK9sfte2NIf22qLAV94WTxGEdY67w+sNjbKxpb0hnwjjN/ROGsWU/j32b2UNOY0o+rvbaz+mpyfY2uue178eQL+g96wvqoaLs6RKgZJ4HW4DQM+NRCl3UEsuzB8dZvAdG1O3G7y1AHiVcrVsJPAwB9wcYtfp4GJpaNpAJpBT3QJXHT8Dbe5InBQcfNqy4SZ5azpUuONO9eOkKcEleirUqjJWfDy2W8oMPtGvWbTAz39Zx/VQCgUSAgU2toM9h9cvTb415rQDG9nLWb8eeptveEciWLZtxZWduLjrAmIIPUn54V7PmUgJKwB8I+JwCxKlF9Ad6PtJGzzpSH2mcNkMJKAEloASiJYEh/Xp63W8qVGZMGOF1fs2oBJSAEogKAlzBkS8VJaAEog8Bh22+j/Q3fZK42H/umo+0xn+aQWZkp6IElIASUAJKQAkoASWgBJSAElACSkAJeCbgUwqQfOkSY8PRi9gnA3q1avB8weypZERWZEZ2KkpACSgBJaAElIASUAJKQAkoASWgBJSAZwI+5QKTPH5sVMqVCttPXjaDes9N1lQ7AVp+kBnZqSgBJaAElIASUAJKQAkoASWgBJSAElACngn4lAKETeRAvlQ2DYjn+XJpqhJQAkpACSgBJaAElIASUAJKQAkoASUQGQI+5QITmQ5oGSWgBJSAElACSkAJKAEloASUgBJQAkpACTyIgM9ZgDyowXpcCXhLYOXKld5m1XxKQAkoAZ8gULJkyQi3Q+91EUamBZSAEniCBCJzn3uCzdVTPwYCMRBD4j9qBMjHgFpPIQRUAaJfg4AloH9gA/bSaseUgBKwEdB7nQ2GbioBJaAElIASUAJKIBwC6gITDhw9pASUgBJQAkpACSgBJaAElIASUAJKQAkEBgFVgATGddReKAEloASUgBJQAkpACSgBJaAElIASUALhEFAFSDhw9JASUAJKQAkoASWgBJSAElACSiA6EogRHTutfQ54AqoACfhLrB1UAkpACSgBJaAElIASUAJKQAn4JgENgOqb1yVQW6UKkEC9stovJaAElIASUAJKQAkoASWgBJSAElACSsBJQBUgThS6oQSUgBJQAkpACSgBJaAElIASUAJKQAmEJhAYTlGqAAl9ZTVFCSgBJaAElIASUAJKQAkoASWgBJSAEgghECiKg0Dph34xlYDXBGbPX4Q/Zs59YP7jJ09h4tQ/ce58EEaNn4KNW7aFWebS5csYOW4SDh4+EmaeBx0YNGIM5i1cbLJt3b4T02bMwcVLl5zF1m3YjPUbt5j9e/fu4duuPbFj1x7ncd1QAv5I4MChI5g8fRb+W78xzObzu888+w8ccua5HhyM6bPmuZTj72LY6AngZ3SXYydOmnvSlm07nCjIceS4yc79R7GxdMW/mD573qOoWutUAn5L4PadO1i4eKm5Z50PuuC3/dCGKwEloAQCgYAqQALhKmofIkRg0PCx6D1gSLhlTp46g1Iv1cLYSdNECXFZHlrmYsfOsJUNV65ew9Q/Z+O4DDquXb+OrPmLY8TYieGew35w9979+LF7H6RMmRxUfrRu3wnbdu7Gex9+arLx4enbbr2QNUsmsx8jRgycOXcevw0abq9Gt5WAXxFY8e9/qFK7Pnr3H4y6TVqiZ9+Bodrf5/eheKNxC/SR32yVOg2weNlKk+fDjv/D+k1b0PGr77FqzTqTRsXm2fPnwd9HdJc9+w7g6y7d0ard56CyiDL/r3/wzY89ohSN+/1uzbqNWPT30ig9h1amBPydQJP3PgTvWT90723ueXzGUFECSkAJKIEnQ0AVIE+Gu57VRwisXP0flq1cjdVrN+C3wSPAGdIzZ8+hz+9DcPfOXdSoWhlp06RCo7qvoeBz+XDh4iUzE01LDyo4aBnCAUCSRInwdoM3kSVTRsyatwj37t6VwdlWbNuxy/R01559GDh8jLHqCA6+Ear3HLhlzJAeRZ8vBA4gShR7AW3ee8e0h5nHTpyKapUrIEXyZM6ydWq8jNkL/sKp0/og5YSiG35F4FdRfBR/oTCWL/gTn7dvi9+HjnKxerp67Rr6y++yQ9tWWDZ/OsqULI5ffhtk+vjvf+vQunlTlC31olGE8HdF648PJE3lPoGjx47j198G30+wbYV1X6JCacCQkeb+9efs+U5LM1qc/Z+9swCs4uii8CUEDcGDBHenUNzdi5VSaLFCKbQUihQp8qOlaCne4lLc3d3d3TW4uwT+OTfs60tIIJCEvCRn2rC7s7OzM9++t2/n7L13kA9RyrLY8Xm/wzWqWL60WJY9Dx481DOiztXrNum6b+d99uy5isj4TEBMfv78uV1LuUoCIZfA1h27ZNPWHTJp1BBZv2yOvDIWauMmTQu5HWLLSYAESCCEE6AAEsIvIJsfMAJjJ02Xpq07Stde/WXStNlSrc4PcvTESTl15pxWfNBYY+DBvF3nnvr2FBYerTt0k28b/CxLVqyRzj37SafufdQaA/n7Dx2R/QeP6LEXLl6WSx5XZNXajVLx67om/7C+4f72+yZvmehv37VH0qVJpce5J0wgJ06dlvWbtkqypIkFA4iZcxdJgzrf6H7rn/RpU6tIc/DwMSuLSxIIUQQwEM6T63Ntc75cOXTQe+bcBVsf8B168uSp5H1TJm/uHHL8xCndj+/J5m071DILwuPoiVOkRrVK4uIS1XY8V0RKlygqoyZMlmNvuFlM/LovQfCo+d2PsmvvfunQrbf8au5rq9ZtlL3G2qZC9Tpy7OQpOWfclqrXaaQCrc/7Hazm+g/6W+9xuCfC6gSpVfuuer38Oi/upf0G/y2vjHjcd+Bwad+1lx7Hf0ggpBPAd885grN8ni2LRI0SRT7LnFGfM0J6v9h+EiABEgipBCiAhNQrx3YHGgE8cC+ZNUmG/9VLLTcgONSsVlnr79imuTerC+ukDerUlBkTRpi3z3nkwGEvwcPa17HNL7paybwFLWMGH4P+HiW5c2SXb6tXlYb1vtFBw5btu6ziujx/8ZIkTBBf10sXLyw4du+BQzJ8QC8ZatxcGtb7VqbNniflq9WWpr92kJcvX0qC+G5q6n/m/H9xEbxVyg0ScGAC+N7dN9+1SJEiaisjR46kS7icWclajxTxTZlIkQSWHhAlB/ftYb57R6V8meLm+5VNVqxZLyWKFpLaDZvKF9XryjojIDKJ1K/9taRPk9oICn/om2eLiV/3pUnG2ixfnpwyZtgAmThykHi+8tRD3OLG1bzmPzaUbFkzq8Bx6sxZ8Xm/s+pPmTypZMqQzlyXDXLEuPNBPK5YrpSf98PLRix+/vyFxIoZQ3p1bS8/fl/XqopLEgjRBHAfixghos01D/e6e/f+u8+F6M6F4MYjVtTNmzfl8uXLKryG4K6w6SRAAh9IwPkDy7M4CYQ6AilMXA3EDIjnFlf79uLFy/f2MVWKZFoGx5y7cOmd5eHrC9cZvBlFKl+mhDg5eY9RgJiNESNE0P1OTk5m0FJT1zEowJvYlj83kqz5isvuDcul9g/NZJOJnVDEmP47OzsbC5FHWpb/kEBIIoDPeby4ceTOnXvabCswYIJ4brZuxH+zfvuuV9DAO2YZM0Z0FU1gMdWtQ2st26FbL/ml8fcybdY8SZ8ujRTMl1v+GjpSihbMZ6srrK44OYWXXt06SOWa9Y0Icc2Gwa/70iMTzyhpkkRaztW49ln3pQuXLknL37qopVra1Clt9bxrBULuQBO7BWJIIveEkv2zLOLXef/8o4txK5yh1m4QTEoaIXj0kMCNV/KutnIfCQQVgfhubsaS7YmKtxA/cK/DCwym4CMA8WPmzJkye/ZsbUT69Omlc+fOEj58+OBrFM9MAiTwyQjQAuSToeaJHJaAFTARKoR/0zuOcQrn9bW6cOmyuq/gbSnecnfv2EYafVdLRYsM6dJ6OxNEmCvXrnvLw0bvv4ZJm+ZN1OLD07wxh3l/NPOHt+C379yRFy9eGOEmzlvHMYMEQgKBfHlymJg5K+WIiS3x79SZJt6Om0Bc7DtwmMbMSZLYXQfOk6bN0TgUC5asUOsE+74h2Od5I0KWLFZIMHhHPB5XFxd5+uztWDv2x4WldZjc1/3mKyM+/HeP8eu+lNvEZFlnAs3OmLtQuvf5S+81YDV34TKJEjmyTB//j8ZGsvj5vN9Z+VjC4uPJ4ycmNstUqVC2hO7y67y9BwxVa7slsyfJN9WraMwEzuZjT5PrIZUA4hyZtyzqpodYOIg1lt9YWTEFH4Fr167JokWLpE+fPjJ+/Hi5ZATepUvfPztg8LWYZyYBEghMAhRAApMm6yIBQwBveGBCPs4EZETg0y6/tZLIkSJLzsJlpW7j5pIlU3p9i20PC29UEe/APmHaXczegPgH0aK5qDtNDeObf+3GDSlk3nCfv+BVPluWTPaHcZ0EQgyBNr800UF1uarfygYTjLhP944SwVhCzVu03MTO2SDO5m1cb2O9sMPEyClrysBSq/2vzbz1r9efQ0wA1aaaV6lCGROkeKG0NxYhdWpW81YurG+0NUKqZVEDFn7dl1qbgLNVK5YzMZFmiZux0Ike3dVYrDlJKWORccvMsJOnWAVBoNJwJg+WbT7vd/acLasPuCxVLFtad/l13iLGWgezc+UrUVGnKW/xU0Oby4B9nVwngZBGIKURddu1aCIDho7Q+DpFCuY1brZVQlo3QlV7Dx48KLFjx5bkyZNLFBOXJWPGjLJ3795Q1Ud2hgRIwG8C4cwbFn+99kYx+GzjjfODBw/EzZj0MZEACfhNAFYaGMyFD++lM2KwAJNya9v+SARPrVzjO9mwfK4kTexlfn7Z+Mzjjav9zC+3bt9RH3kMSH430+ktX7VWZ8ewr4vrJBDSCGBgHTNGTF+/G+iLp5mR6e69uxLHPLDaJ/wmHTOBVDMatxcrYbCNGURcXaNZWVy+g4DP+9LUmfNk49bt0qNTW43dgZgqo4b2l9LFi+iMV7iv2d+TrKp93u+sfL+WPs+LcohtdPPWHRWIIawwkUBoIoB709NnTyVG9OihqVshsi9jxozR2B9we0GaPn267NmzRy1CrA7dunVLfvvtN9mxY4eVJbfNbxXcZOrWrStNmjSx5duvXLn3Wk5c9zQxl7xysbT3esaoy2j5mqwRmG37TUWWk7S3stjn81hT0Cprf5636n3TFus85idV3jyaokpv9drXo7t8ntNkWvXgWOv8b5XVDLuydvVgl/15fLYX+1CvdR5v7cVJ7fbZ14N8b8ze1GM10n6fb2WRZ53TZ73229pee/aGJ47DnzYP50UHTPKtb9bnwdd9OMjuWFs9Wpnf9frs2/vaq23wrb0+zmMes8xLEGR6pYTRnSR9ArsMa4fdEs9m7u7udjmBv3rDvAx2dXXVcRbGRHhB9iGJMUA+hBbLksAHEPD5AI/YBX4lmKjDhH/ths1S79uvtVgiM8uFzxQndizNgiC5Y/deadW0sc8i3CaBEEfAp7DhswMQDX0rgx89e/EDx8HdzAqs6rMebr9NwOd9CYGdZy9YLLmLlZe4RnD6qWE9KWmCyyJhBgv8+ZZ83u98K2Of5/O82IeYRoyNYE+J66GJAO9NjnM1I5mA2vfuecWfQqueGmvbRIm8Xj5ZrYwTJ46MGjXK2tRlv379JH78+CqAeNtht5HAPLqlSPJSA0Uj++XL18aa0QzOfBmfYWCPcZs1IPb0fO21jQwziNZB7JuxJga4L83+CM6+VGTO8+LlK7Pvv4Hpa3NwuDcV4zhtw5t2PnvxSiJF+K/sm2xdPDf7Ivqx7xXqNA22xpporxO2TVVoH/6swTIGzp4mIwL67kvy2Sb77ReGmX0/nz83bYroe3ufPveUyBF9j92CNqCttvaa9mt7gdeX9mKKantO9s322SZVOt507QWui10/38Xw2QtPw9739oJBeHPNrPbq9UcjfGmvJ3aa/8PbndfWXpOvbbL7rKA86kZ6bvhGtNv37vZ6/6zEiOL8VhxD23nfrHh4ePjMcrhtCiAOd0nYoLBKYPTQP/3ddfwALZg23t/lWZAESIAE/EMAbiuz/h2lD+8f+kbFP/WzDAmQAAkENwG4vCxbtkzumsDacIE5cuSIlCpVKtCaFTMqh1eBBhMVubyjNpcI79jpiLtCWnsdkWHA28RvaMAZsgYSIAESIAESCFUEKH6EqsvJzpAACdgRyJo1q2TIkEEGDx5sYqxF0zhHOXLksCvBVRIggdBMgAJIaL667BsJkAAJkAAJkAAJkAAJkICNANztfvrpJzl27JjmpUqVSmLF8nIxthXiCgmQQKglQAEk1F5adowESIAESIAESIAESIAESMAnAcwCkz9/fp/Z3CYBEggDBCiAhIGLzC6SAAmQAAmQAAmQAAmQAAl8PIGIESPK4cOHZcGCBR9fCY8kgVBOIF68eEE+C0xAEVIACShBHk8CJEACJEACJEACJEACJBCqCRQvXlzmzZsn27ZtC9X9ZOdIICAEAjOgcEDa8a5jw5npNM1kOe9PKIZ5fV+8eCEPHjwQNze39x/EEiQQjAS2bNkSjGfnqUmABEjgwwl8jEk273UfzplHkAAJBB+Bj7nPBV9reWYSIAFHI3Djxg1xdXWVCBEiaBDjDw3cTgHE0a4o20MCJEACJEACJEACJEACJEACJEACJPAWgYAKIE5v1cgMEiABEiABEiABEiABEiABEiABEiABEghlBCiAhLILyu6QAAmQAAmQAAmQAAmQAAmQAAmQAAm8TYACyNtMmEMCJEACJEACJEACJEACJEACJEACJBDKCFAACWUXlN0hARIgARIgARIgARIgARIgARIgARJ4mwAFkLeZMIcESIAESIAESIAESIAESIAESIAESCCUEaAAEsouKLtDAiRAAiRAAiRAAiRAAiRAAiRAAiTwNgEKIG8zYQ4JkAAJkAAJkAAJkAAJkAAJkAAJkEAoIxC+q0n+7dPr16/l1atX8vz5c3FxcfHvYSxHAg5FYPHyVbJ1xy558uSpJEnkrm27/+CBTJs9X/YfPCyJ3RNK1KhRHKbNlz2uyPjJM2TpyrXicfWapEqZXCJEiCAbNm+TvQcPSfq0qR2mrWwICXwMgSvXrsvxk6fEPWEC2+E79+yTTVt3SETzWY8TO5Yt31p58vSprF67Uc6cvyDx4saVSJEiWrt0uXvvAVm5dr2kS5NKIjg7y63bd2Tm3IVy7sJFSZMqpfw7baZ+3/GdP3j4qNy7d1+SJHaXcOHCeasnpG5cvnJV5i5cIuGdnCR+PDc7JhskW5ZMQdatoLwvvXjxQrr1HqCfExeXqLJ42Sp58PChJHrzucEzyrhJ0yVb1kx6HXG/7PXnECmQN7c4m88AEwkEF4GXnp6yev0mvdfEc4srUaJEfqspd+7ek+Wr18mFS5clWZLE4mS+u0iHjhzTe6F7wvgSOVIkzcP97aq5byZMEF+3+Y9jEMAY6fTp0/Ls2TNxdXUN1ka9fPlSTp06JWfOnJHYsWPrc6PVIA8PD7ly5YrEihXL9puH+yfy7969K9GjR7flW8cE5dLTfD927dolCRIksH3u79y5I5cvX1aO4cOH19OjjefOnRPsixkz5idrI9q3b98+va72bO7du6fXG3yt7ysaCoZoZ4wYMcRqe1DyQ91PnjyRs2fP6vjc/vcOv5sHDx4095woEjnyf/cdtPHChQve+AZ1GwOz/sePH5vnvkjKF89tH/rsxieCwLwarCtEEBg5brLsO3BI0qZOKSsXTNc2L1u1Tjr/3k/Xs2bOKHHjxHaIvmCw9kX1ujoATJEsqUydOVemzZonc6eMkx2798k5M/irUqGsQ7SVjSCBjyEAIaN1h25y4+YtWTF/mlaBQes/Yyaah6F4cu3aDen7+//k66oVbdU/Nj/0lWt8J1ev35CIESNIVPPDPmfyGHGLG8dWZuXaDfL36AlSrlRxefnipdT+oalc9rgqU8cOFzwY4vsePbqrHvPgwUO5fuOmNKz3rfyvXUtbHSF55eTps9rHxEbkXbVwukQxDz4YXI0cP1nqfVs90LqGa5ExV1Hp2r6VfFerRpDel6bOmi+z5i2S9r82k1/a/M8M/uLJwOGjpFfXDpIvdw4j+CyVm7dv2x6EEhjhZ5URyTKmTyu1a1QLtD6zIhL4UAL1Gv0ie/YfkmhGuPu970BZNPNfSRDfS5hEXbfM57bcl7X1JSO+U5kypJMZE0bI4aPHpUmr9lKqeBGZPmeBTB//j0BM6dZngIz/e+CHNoPlg5DArVu3ZOTIkXLbXEsMzlKmTClNmjTRgWcQntbXqiHE9OvXTwUNDIYhJPTu3Vvix48vw4cPl0uXLungEQJIo0aNVEwYMWKEHDt2TO+fUaNGlY4dO0q0aNF8rT8wMzFw/+uvv3TwnjlzZh2kT506VTZs2KCDcwxs0RYIDGPHjpWLFy9qGyEwNWvWTMWdwGyPz7r27t0rAwcOlOTJk+u5a9WqJcWLF5f169fLrFmzVOQAz1atWkmGDBlk3LhxsmfPHmUKweGnn35SYcdnvYG5fejQIRk2bJiKH/j8ffXVV1KuXDnZsWOHjB8/Xtzc3MxLnntSuXJlKVq0qLIFY4hIEJPat28vKVKkCMwmOXxddIFx+EvEBgYFAafwTnLi1Bn9Q/3LjHVFeGcvhdk6Hx5IJk6dJROmzDRvWm5o9plzF2SmeQA/f/GSjBj7r6zfvFVgPYIy/06bJXhwsdK2nXtk2KjxMnv+YqMaP9fsLdt3ysYt22Xv/oMydtI0rQsWHkgQO1D3o0ePdRv/rFm/WTA4GzvMPOz8M1B6d+uo+66YN5uF8ueRiuVLC9RdHGf/d+zEKS3nWx90B/8hAQcggO9M9oKl9e2m1ZynT5/JqAmTpV3Ln2X7msVSuGBemTlnobVbl/MXLRcM8JfMmiQbls2VR4+f6HfQW6E3G/hO1vuxuVy6fEUmjx6qAwur3BdlS8qaRTNlx7olalm11wijoS1duuwhA4eN8rVbx0+elhHjJsmcBUsE3K20dcduFY8w+Jq/eLkcPX5Sd2EJUWnwP2MEFjpIi4wVxmvzsI3BHcpb96Wz573uZ7h/IaHO1es26bpv58U9EvdKCBpYwtLUZ0I7y5curmLOtp27pUnD76Rwgbzm3Ae1/WP/nSY/mzwr4YEZ90hYhTCRQHARgMUprNkmjRoi65fNkVdqqeQl9lptwjMErAbWL50j08b9Izt27ZV1m7aqoJgvd05p2qi+wOoDafL02VKuZDGJHSumdTiXDkDg8OHDAkuBzp07S//+/eXEiROCwXNwJFhynDx5Urp3765tSZUqlaxatUrb89BYzfXp00cHvbjPHjhwQM6fP6/LTp06Sd++fdU6ZM2aNUHedPBauHChcrNOBsuUadOmqejRq1cvY5EdVWbPnq3WLBjEY7CO9uNFxrZt26zDgmQJcWbChAlSv3596dq1qzRt2lSFGDx3QwCpXr26/P777yosTJ8+XSBEwNoCYhPKR4wYMcjbiI7j2ubKlUtFry+++EKZPnr0SFauXCk1atSQbt26aRs3btyoggdEGvQJHLNmzSqjRvn+jBAkUB2kUgogDnIh2IxPSyBrpoxGKY0qC5euVMEBokTBfLltjYDpdMlKNWXJitU6OCj/VW11P9luRA28rcbbR7jS1GvUXL6q/YOsNw8qXf7oL92NeTYShI/aDZvK0WMn5M8hI+TLWt/rzXqseRBv+7/f5ZsGTWTL9l3Srdefgod2JAgqfw0d6c39Bm+BoH5/+/3P0rlnP903e9JoSZwooUyeMUf6D/pbXpgfgblmYIA/bKN9m7ft1Pb61gc9Gf8hAQcgUKRgPhkxqI/kNW/vrQT3rh1rl0itGl/qG8/jJ05LyeKFrd26xFt+iJiw+HAxD0cxY0SXPfu8BgfeCpqNpr921IFDj/+1lSyZMnjbDREUAw8MuiFE1v0m8CwjvJ0oGDdKlyiqgpIlilpNgWVExa/rqhsQ7lHfft9EYF4MwaPmdz/Krr37pUO33vKruZ+sWrdRRdsK1evIMeOqdM6IG9XrNFKu+w8e0SovXLwslwxD676EunAvgtUJUqv2Xc19aYdaZPh2Xtzf+g3+W9+A9x04XNp37aXHWf9AoDlw+IhxaUqtWXCXQn1Hj51Ud4HRE6dIjWqV9L5uHYMlXARPGbHMXli23891EghqAvjuOUdwls+zZVFrtc+MlenRE16ionXuY+Y+lzljev38Zs2cQQd9x4zgiM/5iVOn9RkjWdLE+kJk5txF0qDON9ahXDoIAbiaJEqUSK0W4G6AdbgYBEeCm8avv/6qLi6wBoG7A6w9IIwkS5ZMB+awoIgbN65aNUAEgXVIvHjx1DIkY8aMag0S1G3fvXu3MqpTp47tVHAhgktJ0qRJ1W0nderUalGBtqO96AfEbXd3dxVq8FsTVOnGjRvmO/dAYN0DoeP48eOSJUsWFWxgaQGrCTyjQ3xAWXBEu9FGfAbQRvQnqFOaNGlUeJkxY4Zad+TMmVOvOQQu7EMbcX0hiuAzif5ky5ZNm/XZZ5/ptcbnJCwlCiBh6WqzrzYCkSNHkjJmYLBw6Qr1y331+pVUKF3Ctn+csc7ADQNvXVr8/IPeNKbMmGvb379nZ5lk3ibjxovB2djhA6Rowfxy4NBRfYAfMmKsNKpfS4b++YdabsCHd9Wbt5+3jbnZqgUzZPSQ/oI30IuNyOLp+UpWrFkvX1Yqr+e1TpQnZ3b517w1glsO3oo2atbGCDM11FzWKgPz/ynGrB9m4ffN29bcObKruff7+mAdzyUJBBeBpIkTSZEC+QQ+8VYKb4QNuKC9MG4reON/7/59iWTcXOxTyaKFdLNBk5bStHVHweAbViC+pVNnz+lgAi41eGtjn65cvW4ssrYJrLVevXotB833NLSl+rW/lvRGNGjf9Q9982z1b9Dfo/Re8W31qsb15xsVMyDKTjJvl/PlySljjNXZxJGDxPOVpx7iZh48kdf8x4YmxkZmvfedOnNWOrb5RfdXMpYWuKdaKWXypGpts2LNBjlihGAPE5OkYrlS4td5IUA9f/5CYsWMYVxa2suP39e1qtIl9nu+9DQDQq+YB4P79jCCyFEpX6a46Uc2vX+WMJ8LCM9wG8Tbc6SE8ePp8sy587rkPyTwqQncu//AxDKKaPttx/PHvXsPvDVD73PGn91KiGmE40qb5wt8t2CdNnxALxk6cpy66k2bPU/KV6ttBN4O+nLFOo7L4CNw7do1dUGwWgC3A1j1BEeCAJIpUybjQnpNunTpovfrsmXL6qAYcRPwfAvXGMSowCD53DmveBVWWxMnTqwxJaztoFjevHlTrSjgqmHvamPFJrHOCVEGA/fr16/rb7kVUwNiCNoelAN3tBHiEeKTFC5cWJdww4EVDaxDYJ2CBMEGPMEbwoeV4GICS5WgTviswQ0HliAQacATbQQbixdid6KNcCHCZ8CKBwKRBs9GPp+PgrrNwV2/c3A3gOcngeAiUKlCGR1gDTHm3IXy5TG+cDFsTYHLy1MTmwBvM5GKFynoLb4AgjLCpx4Jb5+RopqgZp7mZvPYDMSemD/43iPBWgPphrmRIqVKkdyWV71KRRPXY57g7eXNm8Zvr0oFLWP9s3TFGrllBJNRQ/rpTRSDky49+xvrkzVWEV1evOQh3/3UQgcHo4f1Nze3iOq2864+eKuAGyTgIATgXgax7/u636i/e8/+g+SP/oMFA3WYkyJlSJdG5pk4OAuXrZDkSZNo/BDfAqWi7D8D++jgu32XP6SPsSzo1KY5sjUVMe41iB+BBGusMROmGLcKxNxxjBhA2rAA/uPkFF56desglWvWNxyu2WrDPe6uCfxq3ePKlylh3qqFU0uJpEkSaTlX8xCFILRIF8zDVcvfumhQWcRP8k/CwG3g36MFYkgiE1w6+2dZ9L7k23n//KOLBnvG220IJhCWIRJb6bV4veWDhRASgtt269Ba1zt06yW/NP5e4yOlN58NWPPBmq6osTCy7tMIlspEAsFBIL4ZnGCwBCsmiB+379z1Fv8DbUKg4vMXLmnzEOMDn1fECMGb7vq1a2o+REBYZrX8uZFkzVdcdm9YbmIbNZNNxuITn3Wm4CWAwfB9I9hbCeJHcMVVwMs5xNBYsGCB4A0/4lZgIIxBLwb02I8/PCNiAIyBPuJ/WAlxIWApEpTpyJEjcvXqVYHrEGJmoF1wabGEBOvcYJo2bVoVlyAwQFBAXzBghwhiDfCt8oG5RN0Qi9q0aaMiB7YnT56sbYG4AOsQtAEc8XwCqx9YAlkJsWCSJElibQbJEtcRMUoaNGigcT/ghtOhQwdlhpvUx3wAAEAASURBVHZZAgw+j7BMsYQ5CCQQSsA9YcKEKooESQMdtFJagDjohWGzgp4AfNVjGR9amMHjQd0+ZTdvOJ+amwUsQPCQ7WJmhcmaKb19ET/Xo0Vz0XgCy1at1QeeBcakHMmaeQGmsFbKkT2rJE+WRAYM+Udyfv6ZDuasfVgePHpMOvXoq4H/rt24qT9YyI8T+z/fXwwm6jRqpnFG+nTvaOKQPBVEkw9IH3AOJhIIDgLO5gFj8D9jNTbF6TPnZOfu/fojDQuP37r0NDO7bDB+8Xvlp5a/SYkihSSjGfBiUFCxbClfm4v9EE/wfR89frK6h1kFYQEC3/w1ZnaG3SaOBOIARY7kJWxaZULDEib3db/5SmeNsPoDKw4Ipd07tpFG39XSh84M6dJKbmN1tm7jFplhZszp3ucvvYfhmLkLl6mYgCCMFcqUtKoRp3BejxGYueLBA+8iAyw+IAaP/XeqVCjrZWHn13l7DxiqMQ2WzJ4k31SvotcFD3ZWgrVQODMYxDWzT4gFg4FjyWKFVLyJbh7oXM2bLty/kTDDEBIGoUwkEBwEYMlpRlH6ogOxcBDLI7+xstqz76De086cPS/5jRsgXLxwPxozcapaO+XN9Z9rINrd+69h0qZ5Ex3Q4GUL3HgRVBXCClPwE8AgHW/hMWDHoBJxNYJaRPCr17CWmDRpklSqVEmqVq2qA3QMgDFAhysJBsZoI9w2MPNKjhw51HoBx2FgjBlPENAzKBPYFChQQH97IPRZKX369BpIFvwgHEIogUsHXEsg1MD1BH2B1QrEm6BMEAZgJYNzQXDBuWHVASEEwgfaCCFk3bp12hYwA1+UA0dYWyRPnjwom2gTstAmxFSBEIPfTsvKA7Fo0Ea0BdYpcCmC+xNilVhxVBAHJKyl/0ZiYa3n7G+YJ4CBFh7kZ85doKbbm4w/uZXq1KymMQUqfFVHfRDLlCgin2XJJPDT9U/6q3c3NU1Nn6OQuRlFUPcUn/EHrHq+rFheBgwdIV9V/sLKsi2bNW6g/vatO/XQQIMYoH1Xu4YJBFjC+Nav13KYwvOsCc6KVK1WQ13ibS5MxBEXwWcftAD/IQEHJQBLAcwogplgho0Yp29GB/XproNbWEvBXaZFkx+MYJhVatRrrIP4BnVqSjkTHPNdqU+PTlK6ck2NRbFgxgQtunbDZsEf4onAkmRov546qHhXPSF1X1szcEKw5+tmth2kLr+1kh9btJOchcvqbDjNfmyg1mytm/2oD5eTTIDaMiWL6T48nJYyFhnzFy+TPMUqSApj0QExAuIr3mjDZWaciWUUzQgP9smy+kDQ54plvURmv86LeDCdevTRmEh3zIM5rjHevFkJD3XJTQwECC32CZ+T31o11SxY9cElYJGJzwTBBwkWRRCl0WYmEggOAilTJJN2LZpojBu4cUGsq1mtiiwwLri4p1U2n9tqlSvImg1bpJaJ94X7Uaumjb1Ncb/v4GHBjFl5c32uXYC7WQ0TqwfflUJ28cuCo388pxcBiAg7d+6UHj16qGsGXFAwE0xwpK1bt2qsBwQTRVwIpM8//1yqVaumbhwIdgprOri6IEAqLAEwCEacC1hgoN2IdRGUCQKIJRBBjIGIkDdvXrVSqVmzpiAAKlx54LqRP39+FSC2bNmiQVrRLogfQd1GWEt8+eWXOsMK3FwgHH399dfKrlixYjJnzhxZsWKFikktWrRQkQZtAl+0HcekS5cuKDGqlRgsfJYsWSIIXIv4HpjtBbE/4F4Ei5W1a9fq73qVKlUkTpw4UrduXZk4caLMmzdPubZu7WVNGaQNdbDKwxmV6L9XLO9oHIpBQYICBpMffCiYSCC0E8AMEngIt8yoP7S/mIUF6jHEFt8SZpGZNG2OBvPDjBeurtF8K6aDP7jCYFpHyw3A14K+ZAa0D75UySwSCHICMAO/Y0zFEQ/EfiBsf2L4zeO7+aHfCfs6wvo6RAy4uiD2ChIGZBu3bpcendqqKwpiaowa2t/EIiiis1zhbbNvs08gHw/UVj3v4+rzvCiPt1E3b91RIQbCis+EQNEIWrt55Xz9TOCZ5JiZyQZWPlbCbDLwC7fupYgHkj5daun/e2erCJckECwE8Nl8+uypxDADI78SZpVDvBCfn//LJoYO7nX2371bt+9ozBz7t+d+1cv8T0MAlgl40w4rAfxBTAiOhLEa/uwT2oLfSuQjzgbGdRARLLdC5MMlBeVg3WDl29cRVOtoC9hZ8UlgyYCBPCxAYKGCfCS0EXzhyoNx6KdoI35nMO6FZQfagmd6fOeQD0sPiDcQkqy243fMsgBB/qd4PkFbECcFbYTwgrgpsAhBPtxwYKkCCxqISfZth5UKgqPaxy0Jqmsc2PXCegmWLPgMoE9+PSf6dV4KIH6RYT4JfAICjX5pK1eNySGmcyxbsugnOCNPQQIkQAJ+E0CcgebtOmvQxbjm7VXViuWkrXl77QiDLLjYfGFmrhnav+dbM/r41iPERsJb8sljhkkK42rIRAIkQAIkQAIkEPIJUAAJ+deQPSABEiABEiABhyKAN3If+kbFoTrAxpAACZAACZAACYRKAgEVQLxsXkMlGnaKBEiABEiABEjgYwhQ/PgYajyGBEiABEiABEjA0QlQAHH0K8T2kQAJkAAJkAAJkAAJkAAJkAAJkAAJBJgABZAAI2QFJEACJEACJEACJEACJEACJEACJEACjk6AAoijXyG2jwRIgARIgARIgARIgARIgARIgARIIMAEgmd+pgA3mxWQwPsJYL5wJhIgARIISQTy58//wc3lve6DkfEAEiCBYCTwMfe5YGwuT00CJBDKCHAa3FB2QdkdEiABEiABEiABEiABEiABEgguAhs3bhRPT089fZw4cSRz5swhbmaxW7duyZUrV7Tt9hxfvnwp+/fvl+zZszvEFPH2bQsr6wGdBYYWIGHlk8J+kgAJkAAJkAAJkAAJkAAJkEAQEvDw8JA+ffpItmzZVPS4evWquLi4SNu2bcXd3T0Izxy4VUPEOXz48FsCyIEDB2ThwoWSI0eOwD0ha/tkBCiAfDLUPBEJkAAJkAAJkAAJkAAJkAAJhF4CO3bskKxZs8rvv/+unXz+/Lk0adJErl+/LjFixBAICLdv35Z48eKpuBAlShS5fPmyHDt2TJ49e6bCQvz48bU88u7cuSNp06aV9OnTy+vXr1WUuHTpkkSPHl2tMHD88ePHBeeBxQamcc+bN6+4urrKuXPndB/OGzVqVEmRIoXmX7hwQc8XPnx4yZ07t+adOHFCsH3x4kXJkiWLLpMnT67nxPnQFtRx9OhRSZ06dei9gGGgZxRAwsBFZhdJgARIgARIgARIgARIgARIIKgJ7Nq1S9KkSSOvXr2S+/fvy4oVKyRu3LgqPsyZM0ddYyBOzJo1SyBeoOyUKVNU5IC4cPDgQWncuLEeB8EBdWB/y5YtZffu3bJ9+3Y9BkLLvXv3pEyZMjJu3Dg9R9KkSdU6A0IJxI558+YJ8lDn2bNn5ddff5VHjx7J+PHjVcSA2IH2Nm/eXBYsWKBiS8qUKQXCB9ws8uTJI3CFGTFihNZz7do1OXTokLRq1SqoMbL+ICRAASQI4bJqEiABEiABEiABEiABEiABEggrBPbt2ycQJ2bPnq3WGIkTJ1bBIHLkyPLZZ59JunTpBG4xKIN4Gps2bVKrjpo1a0rRokV1Hywutm7dKo0aNZKMGTMKtp8+fSqrVq2Sdu3aqfUHBIvTp0+r0AKRokGDBpIqVSoVKGA1AnGjUKFCkitXLtmzZ49AvEAb/vnnHylcuLD+nTp1SoWVevXqyc2bN6VKlSry+eefqyUJYpggfsnkyZNVcEH7YL2yfv167UNYuZ6hsZ8UQELjVWWfSIAESIAESIAESIAESIAESOATEoBQ8fDhQ5k2bZqKFBEiRBD8IcHtBGLH0KFDxdnZWQOIwhIE7iQQO3777TeB60unTp1UOIFY0rdvX4kWLZrUrVtXLTJQBwQQpBcvXkjZsmXVJSVmzJgqUsD95fz58yq0QNCA+IJzwbUF63C1QWwPLNFGiBwQWO7evStubm7alkiRIuk22g3RZcmSJTJ16lRBPlKiRIkE52MKuQQogITca8eWkwAJkAAJkAAJkAAJkAAJkIBDEIALS5IkSSRBggTe2oPYHggcCouKv//+WzZs2CCbN2/W4KgzZ85U1xRYbSBuyJkzZ1SYgLgBqwuUh7UIjoU1B1xhEEMEriiINTJ37lwVP5ycnNSFBdYlEDtg9QGBAyIGhBe408D9BfFAIMJgH9qBYKaI/xExYkQVW+A+A/cXlEdcEVipQGx58OCB9gHCDFPIJkABJGRfP7aeBEiABEiABEiABEiABEiABIKdAAKFYnpYnwmiAv4gWliBSmGhAWFh7dq1Gp8DcUIQfwMuMogPAgsNxPF4/PixfPHFF7ocO3asWoU8efJEy0G82Lt3r1SrVk1PCQEGFhpwhYE1yZgxY9QSBTPTlCxZUjJlyqQiB4QWxB+BBUqBAgW0TRBY4CKDdsKKBCIOrFMQDwSz2kBUgcsN3HKYQjaBcOYiv/ZPF1AMwWwsBQxmQkwkQAIkQAIkQAIkQAIkQAIkQAIkgIClcDfBtLc+E1xjICxA6IDQAIsKjCeRD6sP5GMbLi+oB2IDBAoIE3A5gcUG4nhgZheIERAo4JaC+B8oBwsOWHtAHIE1CKxOMHaFW8zIkSOlVq1aKrBAeEEdqBPT8sLSAyILykEUQUKbUAf2wTIF5TFrDdqN2Wcstx6ffeT2pyEACx1cc1wHXCdcuw9JFEA+hBbLkgAJkAAJkAAJkAAJkAAJkAAJOCQBvLRfvXq1xhUpXbq0us9AKKHlhkNero9qVEAFELrAfBR2HkQCJEACJEACJEACJEACJEACJOBIBGANkDNnTrXqOHz4sLq9FClSxJGayLYEMwFagATzBeDpSYAESIAESIAESIAESIAESIAESIAE3k8goBYgTu8/BUuQAAmQAAmQAAmQAAmQAAmQAAmQAAmQQMgmECAXmKVz54Ts3rP1JEACJEACJEACJEACJEACJEACJEACDk+gXNUvA9zGAAkggdGAAPeAFZAACZAACZAACZAACZAACZAACZAACZDAewjQBeY9gLibBEiABEiABEiABEiABEiABEiABEgg5BOgABLyryF7QAIkQAIkQAIkQAIkQAIkQAIkQAIk8B4CFEDeA4i7SYAESIAESIAESIAESIAESIAESIAEQj4BCiAh/xqyByRAAiRAAiRAAiRAAiRAAiRAAiRAAu8hEKAgqO+pm7tJgARIgARIgARIgARIgARIgARIgARCCYEHj1/YeuIaNYJtPaSsUAAJKVeK7SQBEiABEiABEiABEiABEiABEiCBYCAA4cPjxkN58Oi5t7O7ukQUd7doElLEEAog3i4fN0iABEiABEiABEiABEiABEiABEiABCwCHjcficf1h9amtyUEkeOPbot7vGjiHtfF2z5H3KAA4ohXhW0iARIgARIgARIgARIgARJwOAIPHz6U2bNny4YNG+T58+eSMWNG+fbbbyVp0qQSLly4ALe3R48eEi9ePGnUqFGA6tu8ebOsWrVK2rZtK1GiRAlwu1hB2CWglh8+xA+IHUj2ogjWXaNGdHhLEAZBDbufZfacBEiABEiABEiABEiABEjgAwhA/Jg5c6YkS5ZMPvvsM9m0aZMMGjRIbt68KS9evJCnT5/K69ev9e/Zs2ea9+rVK8E6lijz5MkTLYdtJE9PT9t2pEiRJGLEiLa6rKZZdWMb9T969Eju3btn7bYtHz9+rPvOnTsnGzduVJHGtpMrJPARBOD24jN5CR0RfWari8xbmQ6WQQsQB7sgbA4JkAAJkAAJkAAJkAAJkIBjEti9e7fEjh1batasKWnSpFELkDt37qi4sWjRIsH+X375Ra0uhg8fLgkSJJBixYrJlClTJG3atLJv3z495tChQ1K9enXJkiWLwFoDFiU//PCDCiEQS9auXat/LVu2lBgxYsicOXPEw8NDWrVqpWWXLl2qokry5MmlQYMG4urqKqtXrxbkQ0CxBBfHpMhWhSQCPmN+vKvtKAuLEUeOB0ILkHddQe4jARIgARIgARIgARIgARIggTcEcuTIIRcuXFDXko4dO6rwUblyZXVbOX36tOzYsUMtPCBA7NmzR44ePSoPHjyQvXv3CgQRWGZEjhxZLl26JOvXr5eXL1/KunXr5O7du+Ls7Cz79++X48ePq4gBkQRWHLAuwRIuNrdv31aLE1iNQICZN2+ejB07Vk6cOGFbRosWTc8DqxEmEggIAfsZXwJSjyMdSwHEka4G20ICJEACJEACJEACJEACJOCwBBDvAxYeiRMnVqEC7i+wyjh//vx721ymTBmZMGGClC1bVsWLnTt3qqUGRJKsWbNKrFixbHVky5ZN4sSJo1YgV65ckevXr6slCY6Bm02iRIk07gisUXD8li1b5NatW/Lbb79J69atJW/evLa6uEICgU3gwWNYenifDSawzxFU9dEFJqjIsl4SIAESIAESIAESIAESIIFQRQBuJm5ubvLnn3+q4LB48WKZNWuWHDlyRC040FlYZ/jmggIXGFhxwAIE8UPg+gIrEJTPlCmTODn9924abi+5c+dWC4/t27dL/Pjxxd3d3WbZcfHiRY0TkjNnTnWzQR2IKRIzZky1HoGYEj58+FDFnp1xHAL2wU99tsqR3V/QVgogPq8Yt0mABEiABEiABEiABEiABEjAFwKI1XHs2DG14kidOrWKIJhlBYIFZm+B28n8+fNV1IBbi32yFyTgShM9enQZM2aMII5HunTp7IvqOixFZsyYIStWrJBy5cpp7JHMmTNLhAgR1AIEAsmyZcsEgVNRR9SoUWX8+PFSqFAhgWgCUYSJBAJCAGKGq0tE8RkHBHn48ymEIM/R038yo6O3lO0jARIgARIgARIgARIgARIggWAk0Lx5cxUfpk+fLn/88YesWbNGqlatKrDEKF26tIogCxYsUJcYCBV+JQRHRQBUBFCFGIK4HT5TypQpJUOGDGo1AuEDwU2R9/XXX+t5u3fvrrE/Pv/8c7UWgYsNhI/Ro0frMRBGmEggoATc3d7+bPoldPhWNqDnD+zjw5lplF77p1IUs6ZuQiAfmH4xkQAJkAAJkAAJkAAJkAAJkEBYIgDLCgQjffjwobqfwALEShgzYazk4uISZC4oOAemwMV0uhBS4FZjJcvqBK4wTCQQWAQ8bj56y9rDZ93u8aKJe1wXn9mBvn3jxg2d9QgCI9zG7D///jkZBRD/UGIZEiABEiABEiABEiABEiABEiABEgijBDAjjMeNh766w8Dy41PF/gioAMIYIGH0A8xukwAJkAAJkAAJkAAJkAAJkAAJkIB/CEDgSJfMa6Yi++lxP5Xw4Z82+qcMBRD/UGIZEiABEiABEiABEiABEiABEiABEiCBT2btERSoGQQ1KKiyThIgARIgARIgARIgARIgARIgARIgAYciQAsQh7ocbAwJkAAJkAAJkAAJkAAJkIAjEti6datgNhYmEiABvwlgumdMyeyoiQKIo14ZtosESIAESIAESIAESIAESMBhCHTs2FEWL17sMO1hQ0jAEQlgJiIKII54ZdgmEiABEiABEiABEiABEiABEvAnAQ8PD7Gf8tafh7EYCYQpAnfu3HHo/jIGiENfHjaOBEiABEiABEiABEiABEiABEiABEggMAhQAAkMiqyDBEiABEiABEiABEiABEiABEiABEjAoQlQAHHoy8PGkQAJkAAJkAAJkAAJkAAJkAAJkAAJBAYBCiCBQZF1kAAJkAAJkAAJkAAJkAAJkAAJkAAJODQBzgLj0JeHjSMBEiABEiABEiABEiABEnBUAievP5BrD546avNCVbtiR40oGRLGkHChqlfszKcmQAHkUxPn+UiABEiABEiABEiABEiABEIFgTbTdsv2kzdCRV8cvRMZk8SU5a1LirMTJRBHv1aO3D4KII58ddg2EiABEiABEiABEiABEiABhyXg+eq1eL5+5bDtC00Ne2VYM5FAQAkwBkhACfJ4EiABEiABEiABEiABEiABEiABEiABhydAAcThLxEbSAIkQAIkQAIkQAIkQAIkQAIkQAIkEFACFEACSpDHkwAJkAAJkAAJkAAJkAAJkAAJkAAJODwBCiAOf4nYQBIgARIgARIgARIgARIgARIgARIggYASoAASUII8ngRIgARIgARIgARIgARIgARIgARIwOEJUABx+EvEBpIACZAACZAACZAACZAACZAACZAACQSUAKfBDShBHk8CJEACJEACJEACJEACJBBsBF69eiWPHz+WFy9eaBvChw8vUaNGFWdnZ3n9+rU8fPhQl66urhIuXDgtg2Nu3bolLi4uWjbYGs8TkwAJfFICFEA+KW6ejARIgARIgARIgARIgARIIDAJQMgYP368nDlzRquNFy+e1KlTR1KnTi1z5syRbdu2qQBStmxZKVmypNy9e1dmzJgh586dU9GkSpUqUqBAgY9q0vOXrz7qOB5EAiQQPAQogAQPd56VBEiABEiABEiABEiABEggEAjcuXNHokSJIt27d5eYMWOqlQesQI4fPy5Tp06VwYMHqxVIx44dJVu2bLJr1y65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Xxv8Oj/zSYAESIAESIAESIAEPh2BF57+em//6RrEM4VIAhRAQuRlY6MDk0AN4wKCP58pTaoUsnX1fzPF+NzPbRIgARIgARIgARIgARIggU9DwJ+OC5+mMTxLiCXgf/v1ENtFNpwESIAESIAESIAESIAESIAESIAESCCsE6AAEtY/Aew/CZAACZAACZAACZAACZAACZAACYQBAhRAwsBFZhdJgARIgARIgARIgARIgARIgARIIKwToAAS1j8B7D8JkAAJkAAJkAAJkAAJkAAJkAAJhAECFEDCwEVmF0mABEiABEiABEiABEiABEiABEggrBPgLDBh/RMQCvu/ZcuWUNgrdokESIAESIAESIAEQi6B/Pnzh9zGs+UkQAKhhgAFkFBzKdkRiwB/YC0SXJIACZAACZAACZAACZAACZAACVgE6AJjkeCSBEiABEiABEiABEiABEggRBN4/fq14M8++ZaH/a9evXqrrP1xXCcBEgh9BGgBEvquKXtEAiRAAiRAAiRAAiRAAmGSwIYNGyRcuHBSuHBh7f/p06fl+PHjKnRkzZpVkiRJIs+fP5cTJ07IyZMnxcXFRZCfIEGCMMmLnSaBsEaAFiBh7YqzvyRAAiRAAiRAAiRAAiQQCgns379fRowYIbt27dLeXb9+XQYNGiTXrl2TixcvytChQ+XRo0dy6NAhmTVrlgohEEj+/fdfuXv3bigkwi6RAAn4JEABxCcRbpMACZAACZAACZAACZAACYQoAhA7IGTkzp1bLUDQ+I0bN0rUqFGldu3aUr9+ffHw8BAEy4dQkj59evnqq6+kRo0aKpCcOnUqRPWXjSUBEvg4AnSB+ThuPIoESIAESIAESIAESIAESMABCMClZerUqVK+fHm5c+eOXLhwQVsFFxcIHREiRNDtRIkSqesLyidLlkzChw8vkSNHFldX17csQF6+fClPnjzxFiMEMUMePHggkSJFstXpPdqIA8AI5U14jbgt4fgOP5Rf5iDtHgWQIMXLykmABEiABEiABEiABEiABIKKAESJTZs2yYsXLyRVqlSCGCBPnz6Vx48fq6iROHFi26khdDg5OakbDJZIiBcSLVo0zbcVNCvbt2+X/v37y/37923ZsDL5+uuvpVGjRlKwYEHN93zx0rafK0FLwNPTU27euiXOTuGC9kSsPVQToAASqi8vO0cCJEACJEACJEAC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" + } + }, + "cell_type": "markdown", + "id": "04511c0d", + "metadata": {}, + "source": [ + "![Screenshot%202026-05-08%20at%203.56.37%E2%80%AFAM.png](attachment:Screenshot%202026-05-08%20at%203.56.37%E2%80%AFAM.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "621adc79", + "metadata": {}, + "outputs": [], + "source": [ + "DataPrep.EDA is the only task-centric EDA system in Python. It is carefully designed to improve usability.\n", + "\n", + "Task-Centric API Design: You can declaratively specify a wide range of EDA tasks in different granularity with a single function call. All needed visualizations will be automatically and intelligently generated for you.\n", + "Auto-Insights: DataPrep.EDA automatically detects and highlights the insights (e.g., a column has many outliers) to facilitate pattern discovery about the data.\n", + "How-to Guide: A how-to guide is provided to show the configuration of each plot function. With this feature, you can easily customize the generated visualizations.\n", + "Learn DataPrep.EDA in 2 minutes:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb25b42e", + "metadata": {}, + "outputs": [], + "source": [ + "from dataprep.eda import plot_correlation\n", + "plot_correlation(df)" + ] + }, + { + "attachments": { + "image.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "id": "dd262c08", + "metadata": {}, + "source": [ + "![image.png](attachment:image.png)" + ] + }, + { + "cell_type": "markdown", + "id": "fc01f1cd", + "metadata": {}, + "source": [ + "Clean\n", + "DataPrep.Clean contains about 140+ functions designed for cleaning and validating data in a DataFrame. It provides\n", + "\n", + "A Convenient GUI: incorporated into Jupyter Notebook, users can clean their own DataFrame without any coding (see the video below).\n", + "A Unified API: each function follows the syntax clean_{type}(df, 'column name') (see an example below).\n", + "Speed: the computations are parallelized using Dask. It can clean 50K rows per second on a dual-core laptop (that means cleaning 1 million rows in only 20 seconds)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9264eabd", + "metadata": {}, + "outputs": [], + "source": [ + "The following example shows how to clean and standardize a column of country names.\n", + "\n", + "from dataprep.clean import clean_country\n", + "import pandas as pd\n", + "df = pd.DataFrame({'country': ['USA', 'country: Canada', '233', ' tr ', 'NA']})\n", + "df2 = clean_country(df, 'country')\n", + "df2\n", + " country country_clean\n", + "0 USA United States\n", + "1 country: Canada Canada\n", + "2 233 Estonia\n", + "3 tr Turkey\n", + "4 NA NaN" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b8a492d", + "metadata": {}, + "outputs": [], + "source": [ + "Type validation is also supported:\n", + "\n", + "from dataprep.clean import validate_country\n", + "series = validate_country(df['country'])\n", + "series\n", + "0 True\n", + "1 False\n", + "2 True\n", + "3 True\n", + "4 False\n", + "Name: country, dtype: bool" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66b9528d", + "metadata": {}, + "outputs": [], + "source": [ + "Database\n", + "\n", + "from dataprep.connector import read_sql\n", + "read_sql(\"postgresql://username:password@server:port/database\", \"SELECT * FROM lineitem\")" + ] + }, + { + "cell_type": "markdown", + "id": "33859879", + "metadata": {}, + "source": [ + "Connector\n", + "Connector now supports loading data from both web API and databases.\n", + "\n", + "Web API\n", + "Connector is an intuitive, open-source API wrapper that speeds up development by standardizing calls to multiple APIs as a simple workflow.\n", + "\n", + "Connector provides a simple wrapper to collect structured data from different Web APIs (e.g., Twitter, Spotify), making web data collection easy and efficient, without requiring advanced programming skills.\n", + "\n", + "Do you want to leverage the growing number of websites that are opening their data through public APIs? Connector is for you!\n", + "\n", + "Let's check out the several benefits that Connector offers:\n", + "\n", + "A unified API: You can fetch data using one or two lines of code to get data from tens of popular websites.\n", + "Auto Pagination: Do you want to invoke a Web API that could return a large result set and need to handle it through pagination? Connector automatically does the pagination for you! Just specify the desired number of returned results (argument _count) without getting into unnecessary detail about a specific pagination scheme.\n", + "Speed: Do you want to fetch results more quickly by making concurrent requests to Web APIs? Through the _concurrency argument, Connector simplifies concurrency, issuing API requests in parallel while respecting the API's rate limit policy." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.example.ipynb b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.example.ipynb new file mode 100644 index 000000000..f1629851c --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.example.ipynb @@ -0,0 +1,5119 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a1a30fca", + "metadata": {}, + "source": [ + "## AutoGen: An Introduction to Autogen\n", + "This notebook shows a common use case of DataPrep, such as:\n", + "\n", + "Feature Visualization: uses create_report().show_browser to show distribution of all columns (mean, std dev, hist)\n", + "Missing Value Handling: automatically reports the number of missing cells in each column within the report \n", + "Plotting: uses .plot() from dataprep.eda to create quick plots of data\n", + "\n", + "\n", + "Workflow Description\n", + "In this notebook, we are using the California Housing Dataset from Scikit-Learn. First the data is fetched then converted to a dataframe for feature engineering and model deployment. The models in this example are LinearRegression and RandomForest. DataPrep was heavily used to get a better understanding of features and inform ways to improve model performance. \n", + "\n", + "The 2 cells below import the required libraries and install Dataprep for execution. Please add your API key as required." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24c90101", + "metadata": {}, + "outputs": [], + "source": [ + "pip install -U dataprep" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "5cdcdfc2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(20640, 8) (20640,)\n" + ] + } + ], + "source": [ + "#get california housing data from sklearn\n", + "from sklearn.datasets import fetch_california_housing\n", + "housing = fetch_california_housing(as_frame=True)\n", + "print(housing.data.shape, housing.target.shape)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "0cf4ab6b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "sklearn.utils._bunch.Bunch" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(housing) #need to conv to dF" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "4ceea88b", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "from dataprep.eda import create_report\n", + "\n", + "df = housing.frame\n", + "create_report(df).show_browser() #opens report in another Tab" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "6b587d52", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 20640 entries, 0 to 20639\n", + "Data columns (total 9 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 MedInc 20640 non-null float64\n", + " 1 HouseAge 20640 non-null float64\n", + " 2 AveRooms 20640 non-null float64\n", + " 3 AveBedrms 20640 non-null float64\n", + " 4 Population 20640 non-null float64\n", + " 5 AveOccup 20640 non-null float64\n", + " 6 Latitude 20640 non-null float64\n", + " 7 Longitude 20640 non-null float64\n", + " 8 MedHouseVal 20640 non-null float64\n", + "dtypes: float64(9)\n", + "memory usage: 1.4 MB\n" + ] + } + ], + "source": [ + "df.info()" + ] + }, + { + "cell_type": "raw", + "id": "d37408d8", + "metadata": {}, + "source": [ + "Each row is a block/neighborhood \n", + "Population: population of the block\n", + "MedianIncome (tens of thousands of dollars)\n", + "MedianHouseValue (Hundreds of thousands of dollars)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "64a15ddf", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
MedIncHouseAgeAveRoomsAveBedrmsPopulationAveOccupLatitudeLongitudeMedHouseVal
08.325241.06.9841271.023810322.02.55555637.88-122.234.526
18.301421.06.2381370.9718802401.02.10984237.86-122.223.585
27.257452.08.2881361.073446496.02.80226037.85-122.243.521
35.643152.05.8173521.073059558.02.54794537.85-122.253.413
43.846252.06.2818531.081081565.02.18146737.85-122.253.422
54.036852.04.7616581.103627413.02.13989637.85-122.252.697
63.659152.04.9319070.9513621094.02.12840537.84-122.252.992
73.120052.04.7975271.0618241157.01.78825337.84-122.252.414
82.080442.04.2941181.1176471206.02.02689137.84-122.262.267
93.691252.04.9705880.9901961551.02.17226937.84-122.252.611
\n", + "
" + ], + "text/plain": [ + " MedInc HouseAge AveRooms AveBedrms Population AveOccup Latitude \\\n", + "0 8.3252 41.0 6.984127 1.023810 322.0 2.555556 37.88 \n", + "1 8.3014 21.0 6.238137 0.971880 2401.0 2.109842 37.86 \n", + "2 7.2574 52.0 8.288136 1.073446 496.0 2.802260 37.85 \n", + "3 5.6431 52.0 5.817352 1.073059 558.0 2.547945 37.85 \n", + "4 3.8462 52.0 6.281853 1.081081 565.0 2.181467 37.85 \n", + "5 4.0368 52.0 4.761658 1.103627 413.0 2.139896 37.85 \n", + "6 3.6591 52.0 4.931907 0.951362 1094.0 2.128405 37.84 \n", + "7 3.1200 52.0 4.797527 1.061824 1157.0 1.788253 37.84 \n", + "8 2.0804 42.0 4.294118 1.117647 1206.0 2.026891 37.84 \n", + "9 3.6912 52.0 4.970588 0.990196 1551.0 2.172269 37.84 \n", + "\n", + " Longitude MedHouseVal \n", + "0 -122.23 4.526 \n", + "1 -122.22 3.585 \n", + "2 -122.24 3.521 \n", + "3 -122.25 3.413 \n", + "4 -122.25 3.422 \n", + "5 -122.25 2.697 \n", + "6 -122.25 2.992 \n", + "7 -122.25 2.414 \n", + "8 -122.26 2.267 \n", + "9 -122.25 2.611 " + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head(10) " + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "038b9a1c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'Population', 'AveOccup',\n", + " 'Latitude', 'Longitude', 'MedHouseVal'],\n", + " dtype='object')" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "raw", + "id": "a5eaf259", + "metadata": {}, + "source": [ + "DataPrep Report shows: \n", + "\n", + "1) many features are not very correlated with house price --> avg model performance\n", + "\n", + "2) Median Income is heavily skewed to the right\n", + "\n", + "3) Number of rooms is not strongly correlated with house price (combine w/bedrooms)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "8119af51", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
MedIncHouseAgeAveRoomsAveBedrmsPopulationAveOccupLatitudeLongitudeMedHouseValbedrooms_per_roomincome_per_room
02.23272041.06.9841271.023810322.02.55555637.88-122.234.5260.1465910.319685
12.23016521.06.2381370.9718802401.02.10984237.86-122.223.5850.1557970.357505
22.11111052.08.2881361.073446496.02.80226037.85-122.243.5210.1295160.254715
31.89357952.05.8173521.073059558.02.54794537.85-122.253.4130.1844580.325505
41.57819552.06.2818531.081081565.02.18146737.85-122.253.4220.1720960.251231
....................................
206350.94012425.05.0454551.133333845.02.56060639.48-121.090.7810.2246250.186331
206361.26886118.06.1140351.315789356.03.12280739.49-121.210.7710.2152080.207533
206370.99325217.05.2055431.1200921007.02.32563539.43-121.220.9230.2151730.190807
206381.05333618.05.3295131.171920741.02.12320939.43-121.320.8470.2198920.197642
206391.22041716.05.2547171.1622641387.02.61698139.37-121.240.8940.2211850.232252
\n", + "

20640 rows × 11 columns

\n", + "
" + ], + "text/plain": [ + " MedInc HouseAge AveRooms AveBedrms Population AveOccup \\\n", + "0 2.232720 41.0 6.984127 1.023810 322.0 2.555556 \n", + "1 2.230165 21.0 6.238137 0.971880 2401.0 2.109842 \n", + "2 2.111110 52.0 8.288136 1.073446 496.0 2.802260 \n", + "3 1.893579 52.0 5.817352 1.073059 558.0 2.547945 \n", + "4 1.578195 52.0 6.281853 1.081081 565.0 2.181467 \n", + "... ... ... ... ... ... ... \n", + "20635 0.940124 25.0 5.045455 1.133333 845.0 2.560606 \n", + "20636 1.268861 18.0 6.114035 1.315789 356.0 3.122807 \n", + "20637 0.993252 17.0 5.205543 1.120092 1007.0 2.325635 \n", + "20638 1.053336 18.0 5.329513 1.171920 741.0 2.123209 \n", + "20639 1.220417 16.0 5.254717 1.162264 1387.0 2.616981 \n", + "\n", + " Latitude Longitude MedHouseVal bedrooms_per_room income_per_room \n", + "0 37.88 -122.23 4.526 0.146591 0.319685 \n", + "1 37.86 -122.22 3.585 0.155797 0.357505 \n", + "2 37.85 -122.24 3.521 0.129516 0.254715 \n", + "3 37.85 -122.25 3.413 0.184458 0.325505 \n", + "4 37.85 -122.25 3.422 0.172096 0.251231 \n", + "... ... ... ... ... ... \n", + "20635 39.48 -121.09 0.781 0.224625 0.186331 \n", + "20636 39.49 -121.21 0.771 0.215208 0.207533 \n", + "20637 39.43 -121.22 0.923 0.215173 0.190807 \n", + "20638 39.43 -121.32 0.847 0.219892 0.197642 \n", + "20639 39.37 -121.24 0.894 0.221185 0.232252 \n", + "\n", + "[20640 rows x 11 columns]" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Feature engineer (only run once) \n", + "#DataPrep signal shows weak correlations, combining features for better signal\n", + "\n", + "#MedInc: skewed right (log-transform for better spread)\n", + "df[\"MedInc\"] = np.log1p(df[\"MedInc\"])\n", + "\n", + "#New Col: Avg number of bedrooms per room (percent)\n", + "df[\"bedrooms_per_room\"] = df[\"AveBedrms\"] / df[\"AveRooms\"] \n", + "\n", + "#df[\"bedrooms_per_room\"].describe()\n", + "\n", + "df[\"income_per_room\"] = df[\"MedInc\"] / df[\"AveRooms\"]\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "1082da97", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Avg House Price: 1.92\n", + "Mean Abs Error: 0.49\n", + "R-Squared Val: 0.57\n" + ] + } + ], + "source": [ + "#LR Model 1\n", + "\n", + "from sklearn.linear_model import LinearRegression\n", + "from sklearn.preprocessing import StandardScaler\n", + "from sklearn.metrics import mean_absolute_error\n", + "from sklearn.model_selection import train_test_split\n", + "from sklearn.metrics import r2_score\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "X = df.drop(columns=['MedHouseVal'])\n", + "y = df['MedHouseVal'] #target\n", + "\n", + "#train/test split\n", + "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = .2, random_state = 42) \n", + "\n", + "scaler = StandardScaler()\n", + "X_train_scaled = scaler.fit_transform(X_train)\n", + "X_test_scaled = scaler.transform(X_test)\n", + "\n", + "model = LinearRegression()\n", + "model.fit(X_train_scaled, y_train) #training\n", + "y_pred = model.predict(X_test_scaled)\n", + "\n", + "mae = mean_absolute_error(y_test, y_pred)\n", + "\n", + "print(f\"Avg House Price: {round(y_test.mean(), 2)}\")\n", + "print(f\"Mean Absolute Error: {round(mae, 2)}\") # avg error \n", + "\n", + "r2 = r2_score(y_test, y_pred)\n", + "print(f\"R-Squared Val: {round(r2, 2)}\")" + ] + }, + { + "cell_type": "raw", + "id": "df60bd3e", + "metadata": {}, + "source": [ + "Dataprep shows huge spike at MedHouseVal = 5\n", + "Houses that cost over $500,000 are all grouped into the 5 bin (could be hurting the model)" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "ecea0a84", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
MedIncHouseAgeAveRoomsAveBedrmsPopulationAveOccupLatitudeLongitudeMedHouseValbedrooms_per_roomincome_per_room
02.23272041.06.9841271.023810322.02.55555637.88-122.234.5260.1465910.319685
12.23016521.06.2381370.9718802401.02.10984237.86-122.223.5850.1557970.357505
22.11111052.08.2881361.073446496.02.80226037.85-122.243.5210.1295160.254715
31.89357952.05.8173521.073059558.02.54794537.85-122.253.4130.1844580.325505
41.57819552.06.2818531.081081565.02.18146737.85-122.253.4220.1720960.251231
....................................
206350.94012425.05.0454551.133333845.02.56060639.48-121.090.7810.2246250.186331
206361.26886118.06.1140351.315789356.03.12280739.49-121.210.7710.2152080.207533
206370.99325217.05.2055431.1200921007.02.32563539.43-121.220.9230.2151730.190807
206381.05333618.05.3295131.171920741.02.12320939.43-121.320.8470.2198920.197642
206391.22041716.05.2547171.1622641387.02.61698139.37-121.240.8940.2211850.232252
\n", + "

19648 rows × 11 columns

\n", + "
" + ], + "text/plain": [ + " MedInc HouseAge AveRooms AveBedrms Population AveOccup \\\n", + "0 2.232720 41.0 6.984127 1.023810 322.0 2.555556 \n", + "1 2.230165 21.0 6.238137 0.971880 2401.0 2.109842 \n", + "2 2.111110 52.0 8.288136 1.073446 496.0 2.802260 \n", + "3 1.893579 52.0 5.817352 1.073059 558.0 2.547945 \n", + "4 1.578195 52.0 6.281853 1.081081 565.0 2.181467 \n", + "... ... ... ... ... ... ... \n", + "20635 0.940124 25.0 5.045455 1.133333 845.0 2.560606 \n", + "20636 1.268861 18.0 6.114035 1.315789 356.0 3.122807 \n", + "20637 0.993252 17.0 5.205543 1.120092 1007.0 2.325635 \n", + "20638 1.053336 18.0 5.329513 1.171920 741.0 2.123209 \n", + "20639 1.220417 16.0 5.254717 1.162264 1387.0 2.616981 \n", + "\n", + " Latitude Longitude MedHouseVal bedrooms_per_room income_per_room \n", + "0 37.88 -122.23 4.526 0.146591 0.319685 \n", + "1 37.86 -122.22 3.585 0.155797 0.357505 \n", + "2 37.85 -122.24 3.521 0.129516 0.254715 \n", + "3 37.85 -122.25 3.413 0.184458 0.325505 \n", + "4 37.85 -122.25 3.422 0.172096 0.251231 \n", + "... ... ... ... ... ... \n", + "20635 39.48 -121.09 0.781 0.224625 0.186331 \n", + "20636 39.49 -121.21 0.771 0.215208 0.207533 \n", + "20637 39.43 -121.22 0.923 0.215173 0.190807 \n", + "20638 39.43 -121.32 0.847 0.219892 0.197642 \n", + "20639 39.37 -121.24 0.894 0.221185 0.232252 \n", + "\n", + "[19648 rows x 11 columns]" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2 = df[df['MedHouseVal'] < 5]\n", + "df2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "628834ae", + "metadata": {}, + "outputs": [], + "source": [ + "#LR Model 2 (excluding MedHouseVal >= 5)\n", + "\n", + "X_new = df2.drop(columns=['MedHouseVal'])\n", + "y_new = df2['MedHouseVal'] #target\n", + "\n", + "X_train_new, X_test_new, y_train_new, y_test_new = train_test_split(X_new, y_new, test_size = .2, random_state = 42) \n", + " \n", + "scaler = StandardScaler()\n", + "X_train_scaled_new = scaler.fit_transform(X_train_new)\n", + "X_test_scaled_new = scaler.transform(X_test_new)\n", + "\n", + "new_model = LinearRegression()\n", + "new_model.fit(X_train_scaled_new, y_train_new) #training\n", + "y_pred_new = new_model.predict(X_test_scaled_new)\n", + "\n", + "mae_new = mean_absolute_error(y_test_new, y_pred_new)\n", + "\n", + "print(f\"Avg House Price: {round(y_test_new.mean(), 2)}\")\n", + "print(f\"Mean Absolute Error: {round(mae_new, 2)}\") # avg error in dollars\n", + "\n", + "r2_new = r2_score(y_test_new, y_pred_new)\n", + "print(f\"R-Squared Val: {round(r2_new, 2)}\")" + ] + }, + { + "cell_type": "raw", + "id": "5ce528a5", + "metadata": {}, + "source": [ + "Excluding Houses greater than or equal to 500,000 did NOT improve model\n", + "\n", + "Dataset may be better suited to RandomForest model" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "60eeff9c", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/judebaffoe-bonnie/opt/anaconda3/lib/python3.9/site-packages/dask/dataframe/core.py:7365: FutureWarning: Meta is not valid, `map_partitions` and `map_overlap` expects output to be a pandas object. Try passing a pandas object as meta or a dict or tuple representing the (name, dtype) of the columns. In the future the meta you passed will not work.\n", + " warnings.warn(\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " 0%| | 0/9 [00:00\n", + "\n", + "\n", + " DataPrep.EDA Report \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "
\n", + "
\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + "
'scatter.sample_size': 1000
\n", + "
Number of points to randomly sample per partition
\n", + "
\n", + " \n", + "
\n", + "
'height': 400
\n", + "
Height of the plot
\n", + "
\n", + " \n", + "
\n", + "
'width': 450
\n", + "
Width of the plot
\n", + "
\n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + "
\n", + " \n", + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + "
'hexbin.tile_size': 0.2881396020884052
\n", + "
Tile size, measured from the middle of the hexagon to the left or right corner
\n", + "
\n", + " \n", + "
\n", + "
'height': 400
\n", + "
Height of the plot
\n", + "
\n", + " \n", + "
\n", + "
'width': 450
\n", + "
Width of the plot
\n", + "
\n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + "
\n", + " \n", + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + "
'box.bins': 50
\n", + "
Number of bins
\n", + "
\n", + " \n", + "
\n", + "
'height': 400
\n", + "
Height of the plot
\n", + "
\n", + " \n", + "
\n", + "
'width': 450
\n", + "
Width of the plot
\n", + "
\n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + " \n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from dataprep.eda import plot\n", + "import pandas as pd\n", + "\n", + "results = pd.DataFrame({'Predicted': y_pred_new, 'Actual': y_test_new,})\n", + "\n", + "#actual vs pred\n", + "plot(results, \"Predicted House Price\",\"Actual House Price \")" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "id": "b26adbaf", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
MedIncHouseAgeAveRoomsAveBedrmsPopulationAveOccupLatitudeLongitudeMedHouseValbedrooms_per_roomincome_per_room
02.23272041.06.9841271.023810322.02.55555637.88-122.234.5260.1465910.319685
12.23016521.06.2381370.9718802401.02.10984237.86-122.223.5850.1557970.357505
22.11111052.08.2881361.073446496.02.80226037.85-122.243.5210.1295160.254715
31.89357952.05.8173521.073059558.02.54794537.85-122.253.4130.1844580.325505
41.57819552.06.2818531.081081565.02.18146737.85-122.253.4220.1720960.251231
....................................
206350.94012425.05.0454551.133333845.02.56060639.48-121.090.7810.2246250.186331
206361.26886118.06.1140351.315789356.03.12280739.49-121.210.7710.2152080.207533
206370.99325217.05.2055431.1200921007.02.32563539.43-121.220.9230.2151730.190807
206381.05333618.05.3295131.171920741.02.12320939.43-121.320.8470.2198920.197642
206391.22041716.05.2547171.1622641387.02.61698139.37-121.240.8940.2211850.232252
\n", + "

20640 rows × 11 columns

\n", + "
" + ], + "text/plain": [ + " MedInc HouseAge AveRooms AveBedrms Population AveOccup \\\n", + "0 2.232720 41.0 6.984127 1.023810 322.0 2.555556 \n", + "1 2.230165 21.0 6.238137 0.971880 2401.0 2.109842 \n", + "2 2.111110 52.0 8.288136 1.073446 496.0 2.802260 \n", + "3 1.893579 52.0 5.817352 1.073059 558.0 2.547945 \n", + "4 1.578195 52.0 6.281853 1.081081 565.0 2.181467 \n", + "... ... ... ... ... ... ... \n", + "20635 0.940124 25.0 5.045455 1.133333 845.0 2.560606 \n", + "20636 1.268861 18.0 6.114035 1.315789 356.0 3.122807 \n", + "20637 0.993252 17.0 5.205543 1.120092 1007.0 2.325635 \n", + "20638 1.053336 18.0 5.329513 1.171920 741.0 2.123209 \n", + "20639 1.220417 16.0 5.254717 1.162264 1387.0 2.616981 \n", + "\n", + " Latitude Longitude MedHouseVal bedrooms_per_room income_per_room \n", + "0 37.88 -122.23 4.526 0.146591 0.319685 \n", + "1 37.86 -122.22 3.585 0.155797 0.357505 \n", + "2 37.85 -122.24 3.521 0.129516 0.254715 \n", + "3 37.85 -122.25 3.413 0.184458 0.325505 \n", + "4 37.85 -122.25 3.422 0.172096 0.251231 \n", + "... ... ... ... ... ... \n", + "20635 39.48 -121.09 0.781 0.224625 0.186331 \n", + "20636 39.49 -121.21 0.771 0.215208 0.207533 \n", + "20637 39.43 -121.22 0.923 0.215173 0.190807 \n", + "20638 39.43 -121.32 0.847 0.219892 0.197642 \n", + "20639 39.37 -121.24 0.894 0.221185 0.232252 \n", + "\n", + "[20640 rows x 11 columns]" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#use original df without log-transformed MedInc and new cols\n", + "\n", + "df = housing.frame\n", + "\n", + "df[\"bedrooms_per_room\"] = df[\"AveBedrms\"] / df[\"AveRooms\"] \n", + "\n", + "df[\"income_per_room\"] = df[\"MedInc\"] / df[\"AveRooms\"]\n", + "\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "id": "01ddb74e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Random Forest R2: 0.8011\n", + "Random Forest Mean Abs Error: 0.3313\n" + ] + } + ], + "source": [ + "from sklearn.ensemble import RandomForestRegressor\n", + "\n", + "X = df.drop(columns=['MedHouseVal'])\n", + "y = df['MedHouseVal'] #target\n", + "\n", + "#new train/test split\n", + "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = .2, random_state = 42) \n", + "\n", + "rf_model = RandomForestRegressor(n_estimators=100, random_state=42)\n", + "rf_model.fit(X_train, y_train) \n", + "\n", + "#model eval\n", + "rf_preds = rf_model.predict(X_test)\n", + "rf_r2 = r2_score(y_test, rf_preds)\n", + "rf_mae = mean_absolute_error(y_test, rf_preds)\n", + "\n", + "print(f\"Random Forest R2: {round(rf_r2, 4)}\")\n", + "print(f\"Random Forest Mean Abs Error: {round(rf_mae, 4)}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "id": "da5d9aa3", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/judebaffoe-bonnie/opt/anaconda3/lib/python3.9/site-packages/dask/dataframe/core.py:7365: FutureWarning: Meta is not valid, `map_partitions` and `map_overlap` expects output to be a pandas object. Try passing a pandas object as meta or a dict or tuple representing the (name, dtype) of the columns. In the future the meta you passed will not work.\n", + " warnings.warn(\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " 0%| | 0/9 [00:00\n", + "\n", + "\n", + " DataPrep.EDA Report \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "
\n", + "
\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + "
'scatter.sample_size': 1000
\n", + "
Number of points to randomly sample per partition
\n", + "
\n", + " \n", + "
\n", + "
'height': 400
\n", + "
Height of the plot
\n", + "
\n", + " \n", + "
\n", + "
'width': 450
\n", + "
Width of the plot
\n", + "
\n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + "
\n", + " \n", + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + "
'hexbin.tile_size': 0.18063439999999958
\n", + "
Tile size, measured from the middle of the hexagon to the left or right corner
\n", + "
\n", + " \n", + "
\n", + "
'height': 400
\n", + "
Height of the plot
\n", + "
\n", + " \n", + "
\n", + "
'width': 450
\n", + "
Width of the plot
\n", + "
\n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + "
\n", + " \n", + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + "
'box.bins': 50
\n", + "
Number of bins
\n", + "
\n", + " \n", + "
\n", + "
'height': 400
\n", + "
Height of the plot
\n", + "
\n", + " \n", + "
\n", + "
'width': 450
\n", + "
Width of the plot
\n", + "
\n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + " \n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 67, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from dataprep.eda import plot\n", + "import pandas as pd\n", + "\n", + "rf_results = pd.DataFrame({'Predicted House Price': rf_preds, 'Actual House Price': y_test})\n", + "\n", + "plot(rf_results, \"Predicted House Price\",\"Actual House Price\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "696764fa", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From d2745c07242ed292b9d8e48f324629a975a3b464 Mon Sep 17 00:00:00 2001 From: jbaffoeb Date: Fri, 8 May 2026 16:57:29 -0400 Subject: [PATCH 5/8] Delete class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.example.ipynb --- .../DataPrep.example.ipynb | 5119 ----------------- 1 file changed, 5119 deletions(-) delete mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.example.ipynb diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.example.ipynb b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.example.ipynb deleted file mode 100644 index f1629851c..000000000 --- a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.example.ipynb +++ /dev/null @@ -1,5119 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "a1a30fca", - "metadata": {}, - "source": [ - "## AutoGen: An Introduction to Autogen\n", - "This notebook shows a common use case of DataPrep, such as:\n", - "\n", - "Feature Visualization: uses create_report().show_browser to show distribution of all columns (mean, std dev, hist)\n", - "Missing Value Handling: automatically reports the number of missing cells in each column within the report \n", - "Plotting: uses .plot() from dataprep.eda to create quick plots of data\n", - "\n", - "\n", - "Workflow Description\n", - "In this notebook, we are using the California Housing Dataset from Scikit-Learn. First the data is fetched then converted to a dataframe for feature engineering and model deployment. The models in this example are LinearRegression and RandomForest. DataPrep was heavily used to get a better understanding of features and inform ways to improve model performance. \n", - "\n", - "The 2 cells below import the required libraries and install Dataprep for execution. Please add your API key as required." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "24c90101", - "metadata": {}, - "outputs": [], - "source": [ - "pip install -U dataprep" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "5cdcdfc2", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(20640, 8) (20640,)\n" - ] - } - ], - "source": [ - "#get california housing data from sklearn\n", - "from sklearn.datasets import fetch_california_housing\n", - "housing = fetch_california_housing(as_frame=True)\n", - "print(housing.data.shape, housing.target.shape)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "0cf4ab6b", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "sklearn.utils._bunch.Bunch" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "type(housing) #need to conv to dF" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "4ceea88b", - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import numpy as np\n", - "from dataprep.eda import create_report\n", - "\n", - "df = housing.frame\n", - "create_report(df).show_browser() #opens report in another Tab" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "6b587d52", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "RangeIndex: 20640 entries, 0 to 20639\n", - "Data columns (total 9 columns):\n", - " # Column Non-Null Count Dtype \n", - "--- ------ -------------- ----- \n", - " 0 MedInc 20640 non-null float64\n", - " 1 HouseAge 20640 non-null float64\n", - " 2 AveRooms 20640 non-null float64\n", - " 3 AveBedrms 20640 non-null float64\n", - " 4 Population 20640 non-null float64\n", - " 5 AveOccup 20640 non-null float64\n", - " 6 Latitude 20640 non-null float64\n", - " 7 Longitude 20640 non-null float64\n", - " 8 MedHouseVal 20640 non-null float64\n", - "dtypes: float64(9)\n", - "memory usage: 1.4 MB\n" - ] - } - ], - "source": [ - "df.info()" - ] - }, - { - "cell_type": "raw", - "id": "d37408d8", - "metadata": {}, - "source": [ - "Each row is a block/neighborhood \n", - "Population: population of the block\n", - "MedianIncome (tens of thousands of dollars)\n", - "MedianHouseValue (Hundreds of thousands of dollars)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "64a15ddf", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
MedIncHouseAgeAveRoomsAveBedrmsPopulationAveOccupLatitudeLongitudeMedHouseVal
08.325241.06.9841271.023810322.02.55555637.88-122.234.526
18.301421.06.2381370.9718802401.02.10984237.86-122.223.585
27.257452.08.2881361.073446496.02.80226037.85-122.243.521
35.643152.05.8173521.073059558.02.54794537.85-122.253.413
43.846252.06.2818531.081081565.02.18146737.85-122.253.422
54.036852.04.7616581.103627413.02.13989637.85-122.252.697
63.659152.04.9319070.9513621094.02.12840537.84-122.252.992
73.120052.04.7975271.0618241157.01.78825337.84-122.252.414
82.080442.04.2941181.1176471206.02.02689137.84-122.262.267
93.691252.04.9705880.9901961551.02.17226937.84-122.252.611
\n", - "
" - ], - "text/plain": [ - " MedInc HouseAge AveRooms AveBedrms Population AveOccup Latitude \\\n", - "0 8.3252 41.0 6.984127 1.023810 322.0 2.555556 37.88 \n", - "1 8.3014 21.0 6.238137 0.971880 2401.0 2.109842 37.86 \n", - "2 7.2574 52.0 8.288136 1.073446 496.0 2.802260 37.85 \n", - "3 5.6431 52.0 5.817352 1.073059 558.0 2.547945 37.85 \n", - "4 3.8462 52.0 6.281853 1.081081 565.0 2.181467 37.85 \n", - "5 4.0368 52.0 4.761658 1.103627 413.0 2.139896 37.85 \n", - "6 3.6591 52.0 4.931907 0.951362 1094.0 2.128405 37.84 \n", - "7 3.1200 52.0 4.797527 1.061824 1157.0 1.788253 37.84 \n", - "8 2.0804 42.0 4.294118 1.117647 1206.0 2.026891 37.84 \n", - "9 3.6912 52.0 4.970588 0.990196 1551.0 2.172269 37.84 \n", - "\n", - " Longitude MedHouseVal \n", - "0 -122.23 4.526 \n", - "1 -122.22 3.585 \n", - "2 -122.24 3.521 \n", - "3 -122.25 3.413 \n", - "4 -122.25 3.422 \n", - "5 -122.25 2.697 \n", - "6 -122.25 2.992 \n", - "7 -122.25 2.414 \n", - "8 -122.26 2.267 \n", - "9 -122.25 2.611 " - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head(10) " - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "038b9a1c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Index(['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'Population', 'AveOccup',\n", - " 'Latitude', 'Longitude', 'MedHouseVal'],\n", - " dtype='object')" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.columns" - ] - }, - { - "cell_type": "raw", - "id": "a5eaf259", - "metadata": {}, - "source": [ - "DataPrep Report shows: \n", - "\n", - "1) many features are not very correlated with house price --> avg model performance\n", - "\n", - "2) Median Income is heavily skewed to the right\n", - "\n", - "3) Number of rooms is not strongly correlated with house price (combine w/bedrooms)" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "8119af51", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
MedIncHouseAgeAveRoomsAveBedrmsPopulationAveOccupLatitudeLongitudeMedHouseValbedrooms_per_roomincome_per_room
02.23272041.06.9841271.023810322.02.55555637.88-122.234.5260.1465910.319685
12.23016521.06.2381370.9718802401.02.10984237.86-122.223.5850.1557970.357505
22.11111052.08.2881361.073446496.02.80226037.85-122.243.5210.1295160.254715
31.89357952.05.8173521.073059558.02.54794537.85-122.253.4130.1844580.325505
41.57819552.06.2818531.081081565.02.18146737.85-122.253.4220.1720960.251231
....................................
206350.94012425.05.0454551.133333845.02.56060639.48-121.090.7810.2246250.186331
206361.26886118.06.1140351.315789356.03.12280739.49-121.210.7710.2152080.207533
206370.99325217.05.2055431.1200921007.02.32563539.43-121.220.9230.2151730.190807
206381.05333618.05.3295131.171920741.02.12320939.43-121.320.8470.2198920.197642
206391.22041716.05.2547171.1622641387.02.61698139.37-121.240.8940.2211850.232252
\n", - "

20640 rows × 11 columns

\n", - "
" - ], - "text/plain": [ - " MedInc HouseAge AveRooms AveBedrms Population AveOccup \\\n", - "0 2.232720 41.0 6.984127 1.023810 322.0 2.555556 \n", - "1 2.230165 21.0 6.238137 0.971880 2401.0 2.109842 \n", - "2 2.111110 52.0 8.288136 1.073446 496.0 2.802260 \n", - "3 1.893579 52.0 5.817352 1.073059 558.0 2.547945 \n", - "4 1.578195 52.0 6.281853 1.081081 565.0 2.181467 \n", - "... ... ... ... ... ... ... \n", - "20635 0.940124 25.0 5.045455 1.133333 845.0 2.560606 \n", - "20636 1.268861 18.0 6.114035 1.315789 356.0 3.122807 \n", - "20637 0.993252 17.0 5.205543 1.120092 1007.0 2.325635 \n", - "20638 1.053336 18.0 5.329513 1.171920 741.0 2.123209 \n", - "20639 1.220417 16.0 5.254717 1.162264 1387.0 2.616981 \n", - "\n", - " Latitude Longitude MedHouseVal bedrooms_per_room income_per_room \n", - "0 37.88 -122.23 4.526 0.146591 0.319685 \n", - "1 37.86 -122.22 3.585 0.155797 0.357505 \n", - "2 37.85 -122.24 3.521 0.129516 0.254715 \n", - "3 37.85 -122.25 3.413 0.184458 0.325505 \n", - "4 37.85 -122.25 3.422 0.172096 0.251231 \n", - "... ... ... ... ... ... \n", - "20635 39.48 -121.09 0.781 0.224625 0.186331 \n", - "20636 39.49 -121.21 0.771 0.215208 0.207533 \n", - "20637 39.43 -121.22 0.923 0.215173 0.190807 \n", - "20638 39.43 -121.32 0.847 0.219892 0.197642 \n", - "20639 39.37 -121.24 0.894 0.221185 0.232252 \n", - "\n", - "[20640 rows x 11 columns]" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "#Feature engineer (only run once) \n", - "#DataPrep signal shows weak correlations, combining features for better signal\n", - "\n", - "#MedInc: skewed right (log-transform for better spread)\n", - "df[\"MedInc\"] = np.log1p(df[\"MedInc\"])\n", - "\n", - "#New Col: Avg number of bedrooms per room (percent)\n", - "df[\"bedrooms_per_room\"] = df[\"AveBedrms\"] / df[\"AveRooms\"] \n", - "\n", - "#df[\"bedrooms_per_room\"].describe()\n", - "\n", - "df[\"income_per_room\"] = df[\"MedInc\"] / df[\"AveRooms\"]\n", - "df" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "id": "1082da97", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Avg House Price: 1.92\n", - "Mean Abs Error: 0.49\n", - "R-Squared Val: 0.57\n" - ] - } - ], - "source": [ - "#LR Model 1\n", - "\n", - "from sklearn.linear_model import LinearRegression\n", - "from sklearn.preprocessing import StandardScaler\n", - "from sklearn.metrics import mean_absolute_error\n", - "from sklearn.model_selection import train_test_split\n", - "from sklearn.metrics import r2_score\n", - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "X = df.drop(columns=['MedHouseVal'])\n", - "y = df['MedHouseVal'] #target\n", - "\n", - "#train/test split\n", - "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = .2, random_state = 42) \n", - "\n", - "scaler = StandardScaler()\n", - "X_train_scaled = scaler.fit_transform(X_train)\n", - "X_test_scaled = scaler.transform(X_test)\n", - "\n", - "model = LinearRegression()\n", - "model.fit(X_train_scaled, y_train) #training\n", - "y_pred = model.predict(X_test_scaled)\n", - "\n", - "mae = mean_absolute_error(y_test, y_pred)\n", - "\n", - "print(f\"Avg House Price: {round(y_test.mean(), 2)}\")\n", - "print(f\"Mean Absolute Error: {round(mae, 2)}\") # avg error \n", - "\n", - "r2 = r2_score(y_test, y_pred)\n", - "print(f\"R-Squared Val: {round(r2, 2)}\")" - ] - }, - { - "cell_type": "raw", - "id": "df60bd3e", - "metadata": {}, - "source": [ - "Dataprep shows huge spike at MedHouseVal = 5\n", - "Houses that cost over $500,000 are all grouped into the 5 bin (could be hurting the model)" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "id": "ecea0a84", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
MedIncHouseAgeAveRoomsAveBedrmsPopulationAveOccupLatitudeLongitudeMedHouseValbedrooms_per_roomincome_per_room
02.23272041.06.9841271.023810322.02.55555637.88-122.234.5260.1465910.319685
12.23016521.06.2381370.9718802401.02.10984237.86-122.223.5850.1557970.357505
22.11111052.08.2881361.073446496.02.80226037.85-122.243.5210.1295160.254715
31.89357952.05.8173521.073059558.02.54794537.85-122.253.4130.1844580.325505
41.57819552.06.2818531.081081565.02.18146737.85-122.253.4220.1720960.251231
....................................
206350.94012425.05.0454551.133333845.02.56060639.48-121.090.7810.2246250.186331
206361.26886118.06.1140351.315789356.03.12280739.49-121.210.7710.2152080.207533
206370.99325217.05.2055431.1200921007.02.32563539.43-121.220.9230.2151730.190807
206381.05333618.05.3295131.171920741.02.12320939.43-121.320.8470.2198920.197642
206391.22041716.05.2547171.1622641387.02.61698139.37-121.240.8940.2211850.232252
\n", - "

19648 rows × 11 columns

\n", - "
" - ], - "text/plain": [ - " MedInc HouseAge AveRooms AveBedrms Population AveOccup \\\n", - "0 2.232720 41.0 6.984127 1.023810 322.0 2.555556 \n", - "1 2.230165 21.0 6.238137 0.971880 2401.0 2.109842 \n", - "2 2.111110 52.0 8.288136 1.073446 496.0 2.802260 \n", - "3 1.893579 52.0 5.817352 1.073059 558.0 2.547945 \n", - "4 1.578195 52.0 6.281853 1.081081 565.0 2.181467 \n", - "... ... ... ... ... ... ... \n", - "20635 0.940124 25.0 5.045455 1.133333 845.0 2.560606 \n", - "20636 1.268861 18.0 6.114035 1.315789 356.0 3.122807 \n", - "20637 0.993252 17.0 5.205543 1.120092 1007.0 2.325635 \n", - "20638 1.053336 18.0 5.329513 1.171920 741.0 2.123209 \n", - "20639 1.220417 16.0 5.254717 1.162264 1387.0 2.616981 \n", - "\n", - " Latitude Longitude MedHouseVal bedrooms_per_room income_per_room \n", - "0 37.88 -122.23 4.526 0.146591 0.319685 \n", - "1 37.86 -122.22 3.585 0.155797 0.357505 \n", - "2 37.85 -122.24 3.521 0.129516 0.254715 \n", - "3 37.85 -122.25 3.413 0.184458 0.325505 \n", - "4 37.85 -122.25 3.422 0.172096 0.251231 \n", - "... ... ... ... ... ... \n", - "20635 39.48 -121.09 0.781 0.224625 0.186331 \n", - "20636 39.49 -121.21 0.771 0.215208 0.207533 \n", - "20637 39.43 -121.22 0.923 0.215173 0.190807 \n", - "20638 39.43 -121.32 0.847 0.219892 0.197642 \n", - "20639 39.37 -121.24 0.894 0.221185 0.232252 \n", - "\n", - "[19648 rows x 11 columns]" - ] - }, - "execution_count": 47, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df2 = df[df['MedHouseVal'] < 5]\n", - "df2" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "628834ae", - "metadata": {}, - "outputs": [], - "source": [ - "#LR Model 2 (excluding MedHouseVal >= 5)\n", - "\n", - "X_new = df2.drop(columns=['MedHouseVal'])\n", - "y_new = df2['MedHouseVal'] #target\n", - "\n", - "X_train_new, X_test_new, y_train_new, y_test_new = train_test_split(X_new, y_new, test_size = .2, random_state = 42) \n", - " \n", - "scaler = StandardScaler()\n", - "X_train_scaled_new = scaler.fit_transform(X_train_new)\n", - "X_test_scaled_new = scaler.transform(X_test_new)\n", - "\n", - "new_model = LinearRegression()\n", - "new_model.fit(X_train_scaled_new, y_train_new) #training\n", - "y_pred_new = new_model.predict(X_test_scaled_new)\n", - "\n", - "mae_new = mean_absolute_error(y_test_new, y_pred_new)\n", - "\n", - "print(f\"Avg House Price: {round(y_test_new.mean(), 2)}\")\n", - "print(f\"Mean Absolute Error: {round(mae_new, 2)}\") # avg error in dollars\n", - "\n", - "r2_new = r2_score(y_test_new, y_pred_new)\n", - "print(f\"R-Squared Val: {round(r2_new, 2)}\")" - ] - }, - { - "cell_type": "raw", - "id": "5ce528a5", - "metadata": {}, - "source": [ - "Excluding Houses greater than or equal to 500,000 did NOT improve model\n", - "\n", - "Dataset may be better suited to RandomForest model" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "id": "60eeff9c", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/judebaffoe-bonnie/opt/anaconda3/lib/python3.9/site-packages/dask/dataframe/core.py:7365: FutureWarning: Meta is not valid, `map_partitions` and `map_overlap` expects output to be a pandas object. Try passing a pandas object as meta or a dict or tuple representing the (name, dtype) of the columns. In the future the meta you passed will not work.\n", - " warnings.warn(\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - " 0%| | 0/9 [00:00\n", - "\n", - "\n", - " DataPrep.EDA Report \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - "\n", - "\n", - "\n", - "
\n", - "
\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
\n", - " \n", - "
\n", - " \n", - " \n", - "
\n", - " \n", - "
\n", - " \n", - " \n", - "
\n", - " \n", - "
\n", - "
'scatter.sample_size': 1000
\n", - "
Number of points to randomly sample per partition
\n", - "
\n", - " \n", - "
\n", - "
'height': 400
\n", - "
Height of the plot
\n", - "
\n", - " \n", - "
\n", - "
'width': 450
\n", - "
Width of the plot
\n", - "
\n", - " \n", - " \n", - "
\n", - "
\n", - " \n", - " \n", - " \n", - "
\n", - "
\n", - " \n", - "
\n", - " \n", - "
\n", - " \n", - " \n", - "
\n", - " \n", - "
\n", - "
'hexbin.tile_size': 0.2881396020884052
\n", - "
Tile size, measured from the middle of the hexagon to the left or right corner
\n", - "
\n", - " \n", - "
\n", - "
'height': 400
\n", - "
Height of the plot
\n", - "
\n", - " \n", - "
\n", - "
'width': 450
\n", - "
Width of the plot
\n", - "
\n", - " \n", - " \n", - "
\n", - "
\n", - " \n", - " \n", - " \n", - "
\n", - "
\n", - " \n", - "
\n", - " \n", - "
\n", - " \n", - " \n", - "
\n", - " \n", - "
\n", - "
'box.bins': 50
\n", - "
Number of bins
\n", - "
\n", - " \n", - "
\n", - "
'height': 400
\n", - "
Height of the plot
\n", - "
\n", - " \n", - "
\n", - "
'width': 450
\n", - "
Width of the plot
\n", - "
\n", - " \n", - " \n", - "
\n", - "
\n", - " \n", - " \n", - " \n", - "
\n", - "
\n", - " \n", - " \n", - "
\n", - "
\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 54, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from dataprep.eda import plot\n", - "import pandas as pd\n", - "\n", - "results = pd.DataFrame({'Predicted': y_pred_new, 'Actual': y_test_new,})\n", - "\n", - "#actual vs pred\n", - "plot(results, \"Predicted House Price\",\"Actual House Price \")" - ] - }, - { - "cell_type": "code", - "execution_count": 60, - "id": "b26adbaf", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
MedIncHouseAgeAveRoomsAveBedrmsPopulationAveOccupLatitudeLongitudeMedHouseValbedrooms_per_roomincome_per_room
02.23272041.06.9841271.023810322.02.55555637.88-122.234.5260.1465910.319685
12.23016521.06.2381370.9718802401.02.10984237.86-122.223.5850.1557970.357505
22.11111052.08.2881361.073446496.02.80226037.85-122.243.5210.1295160.254715
31.89357952.05.8173521.073059558.02.54794537.85-122.253.4130.1844580.325505
41.57819552.06.2818531.081081565.02.18146737.85-122.253.4220.1720960.251231
....................................
206350.94012425.05.0454551.133333845.02.56060639.48-121.090.7810.2246250.186331
206361.26886118.06.1140351.315789356.03.12280739.49-121.210.7710.2152080.207533
206370.99325217.05.2055431.1200921007.02.32563539.43-121.220.9230.2151730.190807
206381.05333618.05.3295131.171920741.02.12320939.43-121.320.8470.2198920.197642
206391.22041716.05.2547171.1622641387.02.61698139.37-121.240.8940.2211850.232252
\n", - "

20640 rows × 11 columns

\n", - "
" - ], - "text/plain": [ - " MedInc HouseAge AveRooms AveBedrms Population AveOccup \\\n", - "0 2.232720 41.0 6.984127 1.023810 322.0 2.555556 \n", - "1 2.230165 21.0 6.238137 0.971880 2401.0 2.109842 \n", - "2 2.111110 52.0 8.288136 1.073446 496.0 2.802260 \n", - "3 1.893579 52.0 5.817352 1.073059 558.0 2.547945 \n", - "4 1.578195 52.0 6.281853 1.081081 565.0 2.181467 \n", - "... ... ... ... ... ... ... \n", - "20635 0.940124 25.0 5.045455 1.133333 845.0 2.560606 \n", - "20636 1.268861 18.0 6.114035 1.315789 356.0 3.122807 \n", - "20637 0.993252 17.0 5.205543 1.120092 1007.0 2.325635 \n", - "20638 1.053336 18.0 5.329513 1.171920 741.0 2.123209 \n", - "20639 1.220417 16.0 5.254717 1.162264 1387.0 2.616981 \n", - "\n", - " Latitude Longitude MedHouseVal bedrooms_per_room income_per_room \n", - "0 37.88 -122.23 4.526 0.146591 0.319685 \n", - "1 37.86 -122.22 3.585 0.155797 0.357505 \n", - "2 37.85 -122.24 3.521 0.129516 0.254715 \n", - "3 37.85 -122.25 3.413 0.184458 0.325505 \n", - "4 37.85 -122.25 3.422 0.172096 0.251231 \n", - "... ... ... ... ... ... \n", - "20635 39.48 -121.09 0.781 0.224625 0.186331 \n", - "20636 39.49 -121.21 0.771 0.215208 0.207533 \n", - "20637 39.43 -121.22 0.923 0.215173 0.190807 \n", - "20638 39.43 -121.32 0.847 0.219892 0.197642 \n", - "20639 39.37 -121.24 0.894 0.221185 0.232252 \n", - "\n", - "[20640 rows x 11 columns]" - ] - }, - "execution_count": 60, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "#use original df without log-transformed MedInc and new cols\n", - "\n", - "df = housing.frame\n", - "\n", - "df[\"bedrooms_per_room\"] = df[\"AveBedrms\"] / df[\"AveRooms\"] \n", - "\n", - "df[\"income_per_room\"] = df[\"MedInc\"] / df[\"AveRooms\"]\n", - "\n", - "df" - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "id": "01ddb74e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Random Forest R2: 0.8011\n", - "Random Forest Mean Abs Error: 0.3313\n" - ] - } - ], - "source": [ - "from sklearn.ensemble import RandomForestRegressor\n", - "\n", - "X = df.drop(columns=['MedHouseVal'])\n", - "y = df['MedHouseVal'] #target\n", - "\n", - "#new train/test split\n", - "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = .2, random_state = 42) \n", - "\n", - "rf_model = RandomForestRegressor(n_estimators=100, random_state=42)\n", - "rf_model.fit(X_train, y_train) \n", - "\n", - "#model eval\n", - "rf_preds = rf_model.predict(X_test)\n", - "rf_r2 = r2_score(y_test, rf_preds)\n", - "rf_mae = mean_absolute_error(y_test, rf_preds)\n", - "\n", - "print(f\"Random Forest R2: {round(rf_r2, 4)}\")\n", - "print(f\"Random Forest Mean Abs Error: {round(rf_mae, 4)}\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 67, - "id": "da5d9aa3", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/judebaffoe-bonnie/opt/anaconda3/lib/python3.9/site-packages/dask/dataframe/core.py:7365: FutureWarning: Meta is not valid, `map_partitions` and `map_overlap` expects output to be a pandas object. Try passing a pandas object as meta or a dict or tuple representing the (name, dtype) of the columns. In the future the meta you passed will not work.\n", - " warnings.warn(\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - " 0%| | 0/9 [00:00\n", - "\n", - "\n", - " DataPrep.EDA Report \n", - " \n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - "\n", - "\n", - "\n", - "
\n", - "
\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
\n", - " \n", - "
\n", - " \n", - " \n", - "
\n", - " \n", - "
\n", - " \n", - " \n", - "
\n", - " \n", - "
\n", - "
'scatter.sample_size': 1000
\n", - "
Number of points to randomly sample per partition
\n", - "
\n", - " \n", - "
\n", - "
'height': 400
\n", - "
Height of the plot
\n", - "
\n", - " \n", - "
\n", - "
'width': 450
\n", - "
Width of the plot
\n", - "
\n", - " \n", - " \n", - "
\n", - "
\n", - " \n", - " \n", - " \n", - "
\n", - "
\n", - " \n", - "
\n", - " \n", - "
\n", - " \n", - " \n", - "
\n", - " \n", - "
\n", - "
'hexbin.tile_size': 0.18063439999999958
\n", - "
Tile size, measured from the middle of the hexagon to the left or right corner
\n", - "
\n", - " \n", - "
\n", - "
'height': 400
\n", - "
Height of the plot
\n", - "
\n", - " \n", - "
\n", - "
'width': 450
\n", - "
Width of the plot
\n", - "
\n", - " \n", - " \n", - "
\n", - "
\n", - " \n", - " \n", - " \n", - "
\n", - "
\n", - " \n", - "
\n", - " \n", - "
\n", - " \n", - " \n", - "
\n", - " \n", - "
\n", - "
'box.bins': 50
\n", - "
Number of bins
\n", - "
\n", - " \n", - "
\n", - "
'height': 400
\n", - "
Height of the plot
\n", - "
\n", - " \n", - "
\n", - "
'width': 450
\n", - "
Width of the plot
\n", - "
\n", - " \n", - " \n", - "
\n", - "
\n", - " \n", - " \n", - " \n", - "
\n", - "
\n", - " \n", - " \n", - "
\n", - "
\n", - "" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 67, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from dataprep.eda import plot\n", - "import pandas as pd\n", - "\n", - "rf_results = pd.DataFrame({'Predicted House Price': rf_preds, 'Actual House Price': y_test})\n", - "\n", - "plot(rf_results, \"Predicted House Price\",\"Actual House Price\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "696764fa", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.7" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From 895e01e366656e980925d720aab35b82b0c53e18 Mon Sep 17 00:00:00 2001 From: jbaffoeb Date: Fri, 8 May 2026 21:14:23 -0400 Subject: [PATCH 6/8] Add files via upload --- .../DataPrep.example.ipynb | 437 ++++++++++++++++++ 1 file changed, 437 insertions(+) create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.example.ipynb diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.example.ipynb b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.example.ipynb new file mode 100644 index 000000000..3bf299ac5 --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.example.ipynb @@ -0,0 +1,437 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a1a30fca", + "metadata": {}, + "source": [ + "This notebook shows a common use case of DataPrep, such as:\n", + "\n", + "Feature Visualization: uses create_report().show_browser to show distribution of all columns (mean, std dev, hist)\n", + "Missing Value Handling: automatically reports the number of missing cells in each column within the report \n", + "Plotting: uses .plot() from dataprep.eda to create quick plots of data\n", + "\n", + "\n", + "Workflow Description\n", + "In this notebook, we are using the California Housing Dataset from Scikit-Learn. First the data is fetched then converted to a dataframe for feature engineering and model deployment. The models in this example are LinearRegression and RandomForest. DataPrep was heavily used to get a better understanding of features and inform ways to improve model performance. \n", + "\n", + "The 2 cells below import the required libraries and install Dataprep for execution. Please add your API key as required." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "08943fd3-8edc-42af-be99-8d3d481ef5f8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting dataprep\n", + " Downloading dataprep-0.4.1-py3-none-any.whl.metadata (14 kB)\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.12/site-packages (2.4.4)\n", + "Requirement already satisfied: pandas in /usr/local/lib/python3.12/site-packages (3.0.2)\n", + "Requirement already satisfied: matplotlib in /usr/local/lib/python3.12/site-packages (3.10.9)\n", + "Collecting scikit-learn\n", + " Downloading scikit_learn-1.8.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl.metadata (11 kB)\n", + "Collecting scipy\n", + " Downloading scipy-1.17.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl.metadata (62 kB)\n", + "Requirement already satisfied: seaborn in /usr/local/lib/python3.12/site-packages (0.13.2)\n", + "Collecting aiohttp<4.0,>=3.6 (from dataprep)\n", + " Downloading aiohttp-3.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl.metadata (8.1 kB)\n", + "Collecting bokeh<3,>=2 (from dataprep)\n", + " Downloading bokeh-2.4.3-py3-none-any.whl.metadata (14 kB)\n", + "Collecting bottleneck<2.0,>=1.3 (from dataprep)\n", + " Downloading bottleneck-1.6.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl.metadata (8.2 kB)\n", + "Collecting dask<3.0,>=2.25 (from dask[array,dataframe,delayed]<3.0,>=2.25->dataprep)\n", + " Downloading dask-2.30.0-py3-none-any.whl.metadata (3.4 kB)\n", + "Collecting flask<2.0.0,>=1.1.4 (from dataprep)\n", + " Downloading Flask-1.1.4-py2.py3-none-any.whl.metadata (4.6 kB)\n", + "Collecting flask_cors<4.0.0,>=3.0.10 (from dataprep)\n", + " Downloading Flask_Cors-3.0.10-py2.py3-none-any.whl.metadata (5.4 kB)\n", + "Collecting ipywidgets<8.0,>=7.5 (from dataprep)\n", + " Downloading ipywidgets-7.8.5-py2.py3-none-any.whl.metadata (1.9 kB)\n", + "Collecting jinja2<3.0,>=2.11 (from dataprep)\n", + " Downloading Jinja2-2.11.3-py2.py3-none-any.whl.metadata (3.5 kB)\n", + "Collecting jsonpath-ng<2.0,>=1.5 (from dataprep)\n", + " Downloading jsonpath_ng-1.8.0-py3-none-any.whl.metadata (18 kB)\n", + "Collecting levenshtein<0.13.0,>=0.12.0 (from dataprep)\n", + " Downloading levenshtein-0.12.0.tar.gz (54 kB)\n", + " Installing build dependencies ... \u001b[?25ldone\n", + "\u001b[?25h Getting requirements to build wheel ... \u001b[?25ldone\n", + "\u001b[?25h Preparing metadata (pyproject.toml) ... \u001b[?25ldone\n", + "\u001b[?25hCollecting metaphone<0.7,>=0.6 (from dataprep)\n", + " Downloading Metaphone-0.6.tar.gz (14 kB)\n", + " Installing build dependencies ... \u001b[?25ldone\n", + "\u001b[?25h Getting requirements to build wheel ... \u001b[?25ldone\n", + "\u001b[?25h Preparing metadata (pyproject.toml) ... \u001b[?25ldone\n", + "\u001b[?25hCollecting nltk<4.0,>=3.5 (from dataprep)\n", + " Downloading nltk-3.9.4-py3-none-any.whl.metadata (3.2 kB)\n", + "Collecting numpy\n", + " Downloading numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.metadata (62 kB)\n", + "Collecting pandas\n", + " Downloading pandas-1.5.3.tar.gz (5.2 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m5.2/5.2 MB\u001b[0m \u001b[31m10.0 MB/s\u001b[0m \u001b[33m0:00:00\u001b[0meta \u001b[36m0:00:01\u001b[0m\n", + "\u001b[?25h Installing build dependencies ... \u001b[?25ldone\n", + "\u001b[?25h Getting requirements to build wheel ... \u001b[?25lerror\n", + " \u001b[1;31merror\u001b[0m: \u001b[1msubprocess-exited-with-error\u001b[0m\n", + " \n", + " \u001b[31m×\u001b[0m \u001b[32mGetting requirements to build wheel\u001b[0m did not run successfully.\n", + " \u001b[31m│\u001b[0m exit code: \u001b[1;36m1\u001b[0m\n", + " \u001b[31m╰─>\u001b[0m \u001b[31m[20 lines of output]\u001b[0m\n", + " \u001b[31m \u001b[0m Traceback (most recent call last):\n", + " \u001b[31m \u001b[0m File \"/usr/local/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py\", line 389, in \n", + " \u001b[31m \u001b[0m main()\n", + " \u001b[31m \u001b[0m File \"/usr/local/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py\", line 373, in main\n", + " \u001b[31m \u001b[0m json_out[\"return_val\"] = hook(**hook_input[\"kwargs\"])\n", + " \u001b[31m \u001b[0m ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " \u001b[31m \u001b[0m File \"/usr/local/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py\", line 143, in get_requires_for_build_wheel\n", + " \u001b[31m \u001b[0m return hook(config_settings)\n", + " \u001b[31m \u001b[0m ^^^^^^^^^^^^^^^^^^^^^\n", + " \u001b[31m \u001b[0m File \"/tmp/pip-build-env-h491go59/overlay/lib/python3.12/site-packages/setuptools/build_meta.py\", line 333, in get_requires_for_build_wheel\n", + " \u001b[31m \u001b[0m return self._get_build_requires(config_settings, requirements=[])\n", + " \u001b[31m \u001b[0m ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " \u001b[31m \u001b[0m File \"/tmp/pip-build-env-h491go59/overlay/lib/python3.12/site-packages/setuptools/build_meta.py\", line 301, in _get_build_requires\n", + " \u001b[31m \u001b[0m self.run_setup()\n", + " \u001b[31m \u001b[0m File \"/tmp/pip-build-env-h491go59/overlay/lib/python3.12/site-packages/setuptools/build_meta.py\", line 520, in run_setup\n", + " \u001b[31m \u001b[0m super().run_setup(setup_script=setup_script)\n", + " \u001b[31m \u001b[0m File \"/tmp/pip-build-env-h491go59/overlay/lib/python3.12/site-packages/setuptools/build_meta.py\", line 317, in run_setup\n", + " \u001b[31m \u001b[0m exec(code, locals())\n", + " \u001b[31m \u001b[0m File \"\", line 19, in \n", + " \u001b[31m \u001b[0m ModuleNotFoundError: No module named 'pkg_resources'\n", + " \u001b[31m \u001b[0m \u001b[31m[end of output]\u001b[0m\n", + " \n", + " \u001b[1;35mnote\u001b[0m: This error originates from a subprocess, and is likely not a problem with pip.\n", + "\u001b[31mERROR: Failed to build 'pandas' when getting requirements to build wheel\u001b[0m\u001b[31m\n", + "\u001b[0m\u001b[?25h" + ] + } + ], + "source": [ + "!pip install dataprep numpy pandas matplotlib scikit-learn scipy seaborn" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5cdcdfc2", + "metadata": {}, + "outputs": [], + "source": [ + "#get california housing data from sklearn\n", + "from sklearn.datasets import fetch_california_housing\n", + "housing = fetch_california_housing(as_frame=True)\n", + "print(housing.data.shape, housing.target.shape)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0cf4ab6b", + "metadata": {}, + "outputs": [], + "source": [ + "type(housing) #need to conv to dF" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ceea88b", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "from dataprep.eda import create_report\n", + "\n", + "df = housing.frame\n", + "create_report(df).show_browser() #opens report in another Tab" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b587d52", + "metadata": {}, + "outputs": [], + "source": [ + "df.info()" + ] + }, + { + "cell_type": "raw", + "id": "d37408d8", + "metadata": {}, + "source": [ + "Each row is a block/neighborhood \n", + "Population: population of the block\n", + "MedianIncome (tens of thousands of dollars)\n", + "MedianHouseValue (Hundreds of thousands of dollars)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64a15ddf", + "metadata": {}, + "outputs": [], + "source": [ + "df.head(10) " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "038b9a1c", + "metadata": {}, + "outputs": [], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "raw", + "id": "a5eaf259", + "metadata": {}, + "source": [ + "DataPrep Report shows: \n", + "\n", + "1) many features are not very correlated with house price --> avg model performance\n", + "\n", + "2) Median Income is heavily skewed to the right\n", + "\n", + "3) Number of rooms is not strongly correlated with house price (combine w/bedrooms)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8119af51", + "metadata": {}, + "outputs": [], + "source": [ + "#Feature engineer (only run once) \n", + "#DataPrep signal shows weak correlations, combining features for better signal\n", + "\n", + "#MedInc: skewed right (log-transform for better spread)\n", + "df[\"MedInc\"] = np.log1p(df[\"MedInc\"])\n", + "\n", + "#New Col: Avg number of bedrooms per room (percent)\n", + "df[\"bedrooms_per_room\"] = df[\"AveBedrms\"] / df[\"AveRooms\"] \n", + "\n", + "#df[\"bedrooms_per_room\"].describe()\n", + "\n", + "df[\"income_per_room\"] = df[\"MedInc\"] / df[\"AveRooms\"]\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1082da97", + "metadata": {}, + "outputs": [], + "source": [ + "#LR Model 1\n", + "\n", + "from sklearn.linear_model import LinearRegression\n", + "from sklearn.preprocessing import StandardScaler\n", + "from sklearn.metrics import mean_absolute_error\n", + "from sklearn.model_selection import train_test_split\n", + "from sklearn.metrics import r2_score\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "X = df.drop(columns=['MedHouseVal'])\n", + "y = df['MedHouseVal'] #target\n", + "\n", + "#train/test split\n", + "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = .2, random_state = 42) \n", + "\n", + "scaler = StandardScaler()\n", + "X_train_scaled = scaler.fit_transform(X_train)\n", + "X_test_scaled = scaler.transform(X_test)\n", + "\n", + "model = LinearRegression()\n", + "model.fit(X_train_scaled, y_train) #training\n", + "y_pred = model.predict(X_test_scaled)\n", + "\n", + "mae = mean_absolute_error(y_test, y_pred)\n", + "\n", + "print(f\"Avg House Price: {round(y_test.mean(), 2)}\")\n", + "print(f\"Mean Absolute Error: {round(mae, 2)}\") # avg error \n", + "\n", + "r2 = r2_score(y_test, y_pred)\n", + "print(f\"R-Squared Val: {round(r2, 2)}\")" + ] + }, + { + "cell_type": "raw", + "id": "df60bd3e", + "metadata": {}, + "source": [ + "Dataprep shows huge spike at MedHouseVal = 5\n", + "Houses that cost over $500,000 are all grouped into the 5 bin (could be hurting the model)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ecea0a84", + "metadata": {}, + "outputs": [], + "source": [ + "df2 = df[df['MedHouseVal'] < 5]\n", + "df2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "628834ae", + "metadata": {}, + "outputs": [], + "source": [ + "#LR Model 2 (excluding MedHouseVal >= 5)\n", + "\n", + "X_new = df2.drop(columns=['MedHouseVal'])\n", + "y_new = df2['MedHouseVal'] #target\n", + "\n", + "X_train_new, X_test_new, y_train_new, y_test_new = train_test_split(X_new, y_new, test_size = .2, random_state = 42) \n", + " \n", + "scaler = StandardScaler()\n", + "X_train_scaled_new = scaler.fit_transform(X_train_new)\n", + "X_test_scaled_new = scaler.transform(X_test_new)\n", + "\n", + "new_model = LinearRegression()\n", + "new_model.fit(X_train_scaled_new, y_train_new) #training\n", + "y_pred_new = new_model.predict(X_test_scaled_new)\n", + "\n", + "mae_new = mean_absolute_error(y_test_new, y_pred_new)\n", + "\n", + "print(f\"Avg House Price: {round(y_test_new.mean(), 2)}\")\n", + "print(f\"Mean Absolute Error: {round(mae_new, 2)}\") # avg error in dollars\n", + "\n", + "r2_new = r2_score(y_test_new, y_pred_new)\n", + "print(f\"R-Squared Val: {round(r2_new, 2)}\")" + ] + }, + { + "cell_type": "raw", + "id": "5ce528a5", + "metadata": {}, + "source": [ + "Excluding Houses greater than or equal to 500,000 did NOT improve model\n", + "\n", + "Dataset may be better suited to RandomForest model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60eeff9c", + "metadata": {}, + "outputs": [], + "source": [ + "from dataprep.eda import plot\n", + "import pandas as pd\n", + "\n", + "results = pd.DataFrame({'Predicted': y_pred_new, 'Actual': y_test_new,})\n", + "\n", + "#actual vs pred\n", + "plot(results, \"Predicted House Price\",\"Actual House Price \")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b26adbaf", + "metadata": {}, + "outputs": [], + "source": [ + "#use original df without log-transformed MedInc and new cols\n", + "\n", + "df = housing.frame\n", + "\n", + "df[\"bedrooms_per_room\"] = df[\"AveBedrms\"] / df[\"AveRooms\"] \n", + "\n", + "df[\"income_per_room\"] = df[\"MedInc\"] / df[\"AveRooms\"]\n", + "\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "01ddb74e", + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.ensemble import RandomForestRegressor\n", + "\n", + "X = df.drop(columns=['MedHouseVal'])\n", + "y = df['MedHouseVal'] #target\n", + "\n", + "#new train/test split\n", + "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = .2, random_state = 42) \n", + "\n", + "rf_model = RandomForestRegressor(n_estimators=100, random_state=42)\n", + "rf_model.fit(X_train, y_train) \n", + "\n", + "#model eval\n", + "rf_preds = rf_model.predict(X_test)\n", + "rf_r2 = r2_score(y_test, rf_preds)\n", + "rf_mae = mean_absolute_error(y_test, rf_preds)\n", + "\n", + "print(f\"Random Forest R2: {round(rf_r2, 4)}\")\n", + "print(f\"Random Forest Mean Abs Error: {round(rf_mae, 4)}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "da5d9aa3", + "metadata": {}, + "outputs": [], + "source": [ + "from dataprep.eda import plot\n", + "import pandas as pd\n", + "\n", + "rf_results = pd.DataFrame({'Predicted House Price': rf_preds, 'Actual House Price': y_test})\n", + "\n", + "plot(rf_results, \"Predicted House Price\",\"Actual House Price\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "696764fa", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 463177d8fb37a8bbeeb46e1f059ce29c73ae2aef Mon Sep 17 00:00:00 2001 From: jbaffoeb Date: Sun, 10 May 2026 23:23:02 -0400 Subject: [PATCH 7/8] Added DataPrep description --- .../Dataprep_Project_Description.md | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dataprep_Project_Description.md diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dataprep_Project_Description.md b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dataprep_Project_Description.md new file mode 100644 index 000000000..8d876212a --- /dev/null +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/Dataprep_Project_Description.md @@ -0,0 +1,84 @@ +# Dataprep + +## Description +- Dataprep is an open-source library designed to simplify the data preparation + process for machine learning projects. +- It provides a user-friendly interface to clean, transform, and visualize + datasets, making it accessible for users with varying levels of expertise. +- Key features include automated data cleaning, visualization tools to explore + data distributions, and the ability to handle missing values effectively. +- Dataprep supports integration with popular data science libraries like Pandas + and Scikit-learn, facilitating seamless transitions from data preparation to + model building. +- The tool is particularly useful for exploratory data analysis (EDA), feature + engineering, and data validation, ensuring that datasets are ready for machine + learning tasks. + +## Project Objective +The goal of this project is to develop a machine learning model that predicts +housing prices based on various features such as location, size, and amenities. +The project will focus on optimizing the model's accuracy and interpretability +using the Dataprep library for data preparation. + +## Dataset Suggestions +1. **Kaggle Housing Prices Dataset** + - **Source:** Kaggle + - **URL:** + [Housing Prices - Advanced Regression Techniques](https://www.kaggle.com/c/house-prices-advanced-regression-techniques) + - **Data Contains:** Features of houses (e.g., size, number of rooms, + location) and their sale prices. + - **Access Requirements:** Free account on Kaggle for download. + +2. **Zillow Home Value Index** + - **Source:** Zillow + - **URL:** [Zillow API](https://www.zillow.com/howto/api/APIOverview.htm) + - **Data Contains:** Historical home values, property characteristics, and + market trends. + - **Access Requirements:** No authentication required for basic access. + +3. **OpenStreetMap Data** + - **Source:** OpenStreetMap + - **URL:** [Overpass API](http://overpass-api.de/) + - **Data Contains:** Geospatial data related to housing, amenities, and + infrastructure in specific areas. + - **Access Requirements:** Publicly accessible API with no authentication + needed. + +4. **UCI Machine Learning Repository - California Housing** + - **Source:** UCI + - **URL:** + [California Housing Data Set](https://archive.ics.uci.edu/ml/datasets/California+Housing+Prices) + - **Data Contains:** Housing data from California, including features like + median income, housing age, and house prices. + - **Access Requirements:** Direct download without authentication. + +## Tasks +- **Data Loading:** Use Dataprep to load the selected dataset and explore its + structure and features. +- **Data Cleaning:** Apply automated data cleaning techniques to handle missing + values, outliers, and data type conversions. +- **Feature Engineering:** Utilize Dataprep's visualization tools to identify + important features and create new features that may improve model performance. +- **Model Training:** Split the dataset into training and testing sets, and + train a regression model (e.g., Linear Regression) using Scikit-learn. +- **Model Evaluation:** Evaluate the model's performance using metrics such as + Mean Absolute Error (MAE) and R-squared, and visualize the results. +- **Reporting:** Create a comprehensive report summarizing the data preparation + steps, model performance, and insights gained from the analysis. + +## Bonus Ideas +- Experiment with different regression algorithms (e.g., Decision Trees, Random + Forests) and compare their performances. +- Implement hyperparameter tuning to optimize model parameters for better + accuracy. +- Create interactive visualizations using libraries like Plotly or Streamlit to + present findings and model predictions. +- Explore the impact of additional features from the OpenStreetMap dataset on + housing prices. + +## Useful Resources +- [Dataprep Documentation](https://dataprep.readthedocs.io/en/latest/) +- [Scikit-learn Documentation](https://scikit-learn.org/stable/documentation.html) +- [Kaggle API Documentation](https://www.kaggle.com/docs/api) +- [Zillow API Overview](https://www.zillow.com/howto/api/APIOverview.htm) +- [UCI Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php) From 884f3f55db2784a4e250e4680fe1441f6c4fbc5b Mon Sep 17 00:00:00 2001 From: jbaffoeb Date: Sun, 10 May 2026 23:53:46 -0400 Subject: [PATCH 8/8] Add files via upload updated .example notebook --- .../DataPrep.example.ipynb | 4990 ++++++++++++++++- 1 file changed, 4882 insertions(+), 108 deletions(-) diff --git a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.example.ipynb b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.example.ipynb index 3bf299ac5..5f8960e14 100644 --- a/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.example.ipynb +++ b/class_project/data605/Spring2026/projects/UmdTask467_DATA605_Spring2026_DataPrep_Housing_Prediction/DataPrep.example.ipynb @@ -20,7 +20,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "08943fd3-8edc-42af-be99-8d3d481ef5f8", "metadata": {}, "outputs": [ @@ -28,96 +28,62 @@ "name": "stdout", "output_type": "stream", "text": [ - "Collecting dataprep\n", - " Downloading dataprep-0.4.1-py3-none-any.whl.metadata (14 kB)\n", - "Requirement already satisfied: numpy in /usr/local/lib/python3.12/site-packages (2.4.4)\n", - "Requirement already satisfied: pandas in /usr/local/lib/python3.12/site-packages (3.0.2)\n", - "Requirement already satisfied: matplotlib in /usr/local/lib/python3.12/site-packages (3.10.9)\n", "Collecting scikit-learn\n", - " Downloading scikit_learn-1.8.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl.metadata (11 kB)\n", - "Collecting scipy\n", - " Downloading scipy-1.17.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl.metadata (62 kB)\n", - "Requirement already satisfied: seaborn in /usr/local/lib/python3.12/site-packages (0.13.2)\n", - "Collecting aiohttp<4.0,>=3.6 (from dataprep)\n", - " Downloading aiohttp-3.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl.metadata (8.1 kB)\n", - "Collecting bokeh<3,>=2 (from dataprep)\n", - " Downloading bokeh-2.4.3-py3-none-any.whl.metadata (14 kB)\n", - "Collecting bottleneck<2.0,>=1.3 (from dataprep)\n", - " Downloading bottleneck-1.6.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl.metadata (8.2 kB)\n", - "Collecting dask<3.0,>=2.25 (from dask[array,dataframe,delayed]<3.0,>=2.25->dataprep)\n", - " Downloading dask-2.30.0-py3-none-any.whl.metadata (3.4 kB)\n", - "Collecting flask<2.0.0,>=1.1.4 (from dataprep)\n", - " Downloading Flask-1.1.4-py2.py3-none-any.whl.metadata (4.6 kB)\n", - "Collecting flask_cors<4.0.0,>=3.0.10 (from dataprep)\n", - " Downloading Flask_Cors-3.0.10-py2.py3-none-any.whl.metadata (5.4 kB)\n", - "Collecting ipywidgets<8.0,>=7.5 (from dataprep)\n", - " Downloading ipywidgets-7.8.5-py2.py3-none-any.whl.metadata (1.9 kB)\n", - "Collecting jinja2<3.0,>=2.11 (from dataprep)\n", - " Downloading Jinja2-2.11.3-py2.py3-none-any.whl.metadata (3.5 kB)\n", - "Collecting jsonpath-ng<2.0,>=1.5 (from dataprep)\n", - " Downloading jsonpath_ng-1.8.0-py3-none-any.whl.metadata (18 kB)\n", - "Collecting levenshtein<0.13.0,>=0.12.0 (from dataprep)\n", - " Downloading levenshtein-0.12.0.tar.gz (54 kB)\n", - " Installing build dependencies ... \u001b[?25ldone\n", - "\u001b[?25h Getting requirements to build wheel ... \u001b[?25ldone\n", - "\u001b[?25h Preparing metadata (pyproject.toml) ... \u001b[?25ldone\n", - "\u001b[?25hCollecting metaphone<0.7,>=0.6 (from dataprep)\n", - " Downloading Metaphone-0.6.tar.gz (14 kB)\n", - " Installing build dependencies ... \u001b[?25ldone\n", - "\u001b[?25h Getting requirements to build wheel ... \u001b[?25ldone\n", - "\u001b[?25h Preparing metadata (pyproject.toml) ... \u001b[?25ldone\n", - "\u001b[?25hCollecting nltk<4.0,>=3.5 (from dataprep)\n", - " Downloading nltk-3.9.4-py3-none-any.whl.metadata (3.2 kB)\n", - "Collecting numpy\n", - " Downloading numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.metadata (62 kB)\n", - "Collecting pandas\n", - " Downloading pandas-1.5.3.tar.gz (5.2 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m5.2/5.2 MB\u001b[0m \u001b[31m10.0 MB/s\u001b[0m \u001b[33m0:00:00\u001b[0meta \u001b[36m0:00:01\u001b[0m\n", - "\u001b[?25h Installing build dependencies ... \u001b[?25ldone\n", - "\u001b[?25h Getting requirements to build wheel ... \u001b[?25lerror\n", - " \u001b[1;31merror\u001b[0m: \u001b[1msubprocess-exited-with-error\u001b[0m\n", - " \n", - " \u001b[31m×\u001b[0m \u001b[32mGetting requirements to build wheel\u001b[0m did not run successfully.\n", - " \u001b[31m│\u001b[0m exit code: \u001b[1;36m1\u001b[0m\n", - " \u001b[31m╰─>\u001b[0m \u001b[31m[20 lines of output]\u001b[0m\n", - " \u001b[31m \u001b[0m Traceback (most recent call last):\n", - " \u001b[31m \u001b[0m File \"/usr/local/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py\", line 389, in \n", - " \u001b[31m \u001b[0m main()\n", - " \u001b[31m \u001b[0m File \"/usr/local/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py\", line 373, in main\n", - " \u001b[31m \u001b[0m json_out[\"return_val\"] = hook(**hook_input[\"kwargs\"])\n", - " \u001b[31m \u001b[0m ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " \u001b[31m \u001b[0m File \"/usr/local/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py\", line 143, in get_requires_for_build_wheel\n", - " \u001b[31m \u001b[0m return hook(config_settings)\n", - " \u001b[31m \u001b[0m ^^^^^^^^^^^^^^^^^^^^^\n", - " \u001b[31m \u001b[0m File \"/tmp/pip-build-env-h491go59/overlay/lib/python3.12/site-packages/setuptools/build_meta.py\", line 333, in get_requires_for_build_wheel\n", - " \u001b[31m \u001b[0m return self._get_build_requires(config_settings, requirements=[])\n", - " \u001b[31m \u001b[0m ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " \u001b[31m \u001b[0m File \"/tmp/pip-build-env-h491go59/overlay/lib/python3.12/site-packages/setuptools/build_meta.py\", line 301, in _get_build_requires\n", - " \u001b[31m \u001b[0m self.run_setup()\n", - " \u001b[31m \u001b[0m File \"/tmp/pip-build-env-h491go59/overlay/lib/python3.12/site-packages/setuptools/build_meta.py\", line 520, in run_setup\n", - " \u001b[31m \u001b[0m super().run_setup(setup_script=setup_script)\n", - " \u001b[31m \u001b[0m File \"/tmp/pip-build-env-h491go59/overlay/lib/python3.12/site-packages/setuptools/build_meta.py\", line 317, in run_setup\n", - " \u001b[31m \u001b[0m exec(code, locals())\n", - " \u001b[31m \u001b[0m File \"\", line 19, in \n", - " \u001b[31m \u001b[0m ModuleNotFoundError: No module named 'pkg_resources'\n", - " \u001b[31m \u001b[0m \u001b[31m[end of output]\u001b[0m\n", - " \n", - " \u001b[1;35mnote\u001b[0m: This error originates from a subprocess, and is likely not a problem with pip.\n", - "\u001b[31mERROR: Failed to build 'pandas' when getting requirements to build wheel\u001b[0m\u001b[31m\n", - "\u001b[0m\u001b[?25h" + " Downloading scikit_learn-1.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.metadata (18 kB)\n", + "Requirement already satisfied: pandas in /usr/local/lib/python3.9/site-packages (2.3.3)\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.9/site-packages (2.0.2)\n", + "Requirement already satisfied: matplotlib in /usr/local/lib/python3.9/site-packages (3.9.4)\n", + "Collecting scipy>=1.6.0 (from scikit-learn)\n", + " Downloading scipy-1.13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.metadata (60 kB)\n", + "Collecting joblib>=1.2.0 (from scikit-learn)\n", + " Downloading joblib-1.5.3-py3-none-any.whl.metadata (5.5 kB)\n", + "Collecting threadpoolctl>=3.1.0 (from scikit-learn)\n", + " Downloading threadpoolctl-3.6.0-py3-none-any.whl.metadata (13 kB)\n", + "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.9/site-packages (from pandas) (2.9.0.post0)\n", + "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.9/site-packages (from pandas) (2026.2)\n", + "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.9/site-packages (from pandas) (2026.2)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.9/site-packages (from matplotlib) (1.3.0)\n", + "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.9/site-packages (from matplotlib) (0.12.1)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.9/site-packages (from matplotlib) (4.60.2)\n", + "Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.9/site-packages (from matplotlib) (1.4.7)\n", + "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.9/site-packages (from matplotlib) (26.2)\n", + "Requirement already satisfied: pillow>=8 in /usr/local/lib/python3.9/site-packages (from matplotlib) (11.3.0)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.9/site-packages (from matplotlib) (3.3.2)\n", + "Requirement already satisfied: importlib-resources>=3.2.0 in /usr/local/lib/python3.9/site-packages (from matplotlib) (6.5.2)\n", + "Requirement already satisfied: zipp>=3.1.0 in /usr/local/lib/python3.9/site-packages (from importlib-resources>=3.2.0->matplotlib) (3.23.1)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.9/site-packages (from python-dateutil>=2.8.2->pandas) (1.17.0)\n", + "Downloading scikit_learn-1.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (12.7 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m12.7/12.7 MB\u001b[0m \u001b[31m29.4 MB/s\u001b[0m \u001b[33m0:00:00\u001b[0m eta \u001b[36m0:00:01\u001b[0m\n", + "\u001b[?25hDownloading joblib-1.5.3-py3-none-any.whl (309 kB)\n", + "Downloading scipy-1.13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (33.7 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m33.7/33.7 MB\u001b[0m \u001b[31m31.1 MB/s\u001b[0m \u001b[33m0:00:01\u001b[0mm0:00:01\u001b[0m00:01\u001b[0m\n", + "\u001b[?25hDownloading threadpoolctl-3.6.0-py3-none-any.whl (18 kB)\n", + "Installing collected packages: threadpoolctl, scipy, joblib, scikit-learn\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m4/4\u001b[0m [scikit-learn][0m [scikit-learn]\n", + "\u001b[1A\u001b[2KSuccessfully installed joblib-1.5.3 scikit-learn-1.6.1 scipy-1.13.1 threadpoolctl-3.6.0\n", + "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager, possibly rendering your system unusable. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv. Use the --root-user-action option if you know what you are doing and want to suppress this warning.\u001b[0m\u001b[33m\n", + "\u001b[0mNote: you may need to restart the kernel to use updated packages.\n" ] } ], "source": [ - "!pip install dataprep numpy pandas matplotlib scikit-learn scipy seaborn" + "%pip install scikit-learn pandas numpy dataprep matplotlib" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "5cdcdfc2", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(20640, 8) (20640,)\n" + ] + } + ], "source": [ "#get california housing data from sklearn\n", "from sklearn.datasets import fetch_california_housing\n", @@ -127,10 +93,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "0cf4ab6b", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "sklearn.utils._bunch.Bunch" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "type(housing) #need to conv to dF" ] @@ -138,24 +115,84 @@ { "cell_type": "code", "execution_count": null, - "id": "4ceea88b", + "id": "e435eeae", "metadata": {}, "outputs": [], + "source": [ + "#result folder setup\n", + "OUTPUT_DIR = Path(\"results\")\n", + "OUTPUT_DIR.mkdir(exist_ok=True)\n", + "\n", + "print(f\"All outputs will be saved to: {OUTPUT_DIR.absolute()}\")\n", + "print(f\"Folder created: {OUTPUT_DIR}\")\n", + "\n", + "def save_fig(fig=None, name=\"figure\", dpi=300):\n", + " \"\"\"Helper to save matplotlib figures\"\"\"\n", + " if fig is None:\n", + " fig = plt.gcf()\n", + " filepath = OUTPUT_DIR / f\"{name}.png\"\n", + " fig.savefig(filepath, dpi=dpi, bbox_inches='tight')\n", + " print(f\"Figure saved: {filepath}\")\n", + " return filepath" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ceea88b", + "metadata": {}, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'dataprep'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[6], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpandas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mpd\u001b[39;00m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mnumpy\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mnp\u001b[39;00m\n\u001b[0;32m----> 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mdataprep\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01meda\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m create_report\n\u001b[1;32m 5\u001b[0m df \u001b[38;5;241m=\u001b[39m housing\u001b[38;5;241m.\u001b[39mframe\n\u001b[1;32m 6\u001b[0m create_report(df)\u001b[38;5;241m.\u001b[39mshow_browser() \u001b[38;5;66;03m#opens report in another Tab\u001b[39;00m\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'dataprep'" + ] + } + ], "source": [ "import pandas as pd\n", "import numpy as np\n", "from dataprep.eda import create_report\n", "\n", "df = housing.frame\n", - "create_report(df).show_browser() #opens report in another Tab" + "create_report(df).show_browser() #opens report in another Tab\n", + "report.save(OUTPUT_DIR / \"dataprep_full_report.html\")" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "6b587d52", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 20640 entries, 0 to 20639\n", + "Data columns (total 9 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 MedInc 20640 non-null float64\n", + " 1 HouseAge 20640 non-null float64\n", + " 2 AveRooms 20640 non-null float64\n", + " 3 AveBedrms 20640 non-null float64\n", + " 4 Population 20640 non-null float64\n", + " 5 AveOccup 20640 non-null float64\n", + " 6 Latitude 20640 non-null float64\n", + " 7 Longitude 20640 non-null float64\n", + " 8 MedHouseVal 20640 non-null float64\n", + "dtypes: float64(9)\n", + "memory usage: 1.4 MB\n" + ] + } + ], "source": [ "df.info()" ] @@ -173,20 +210,221 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "64a15ddf", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
MedIncHouseAgeAveRoomsAveBedrmsPopulationAveOccupLatitudeLongitudeMedHouseVal
08.325241.06.9841271.023810322.02.55555637.88-122.234.526
18.301421.06.2381370.9718802401.02.10984237.86-122.223.585
27.257452.08.2881361.073446496.02.80226037.85-122.243.521
35.643152.05.8173521.073059558.02.54794537.85-122.253.413
43.846252.06.2818531.081081565.02.18146737.85-122.253.422
54.036852.04.7616581.103627413.02.13989637.85-122.252.697
63.659152.04.9319070.9513621094.02.12840537.84-122.252.992
73.120052.04.7975271.0618241157.01.78825337.84-122.252.414
82.080442.04.2941181.1176471206.02.02689137.84-122.262.267
93.691252.04.9705880.9901961551.02.17226937.84-122.252.611
\n", + "
" + ], + "text/plain": [ + " MedInc HouseAge AveRooms AveBedrms Population AveOccup Latitude \\\n", + "0 8.3252 41.0 6.984127 1.023810 322.0 2.555556 37.88 \n", + "1 8.3014 21.0 6.238137 0.971880 2401.0 2.109842 37.86 \n", + "2 7.2574 52.0 8.288136 1.073446 496.0 2.802260 37.85 \n", + "3 5.6431 52.0 5.817352 1.073059 558.0 2.547945 37.85 \n", + "4 3.8462 52.0 6.281853 1.081081 565.0 2.181467 37.85 \n", + "5 4.0368 52.0 4.761658 1.103627 413.0 2.139896 37.85 \n", + "6 3.6591 52.0 4.931907 0.951362 1094.0 2.128405 37.84 \n", + "7 3.1200 52.0 4.797527 1.061824 1157.0 1.788253 37.84 \n", + "8 2.0804 42.0 4.294118 1.117647 1206.0 2.026891 37.84 \n", + "9 3.6912 52.0 4.970588 0.990196 1551.0 2.172269 37.84 \n", + "\n", + " Longitude MedHouseVal \n", + "0 -122.23 4.526 \n", + "1 -122.22 3.585 \n", + "2 -122.24 3.521 \n", + "3 -122.25 3.413 \n", + "4 -122.25 3.422 \n", + "5 -122.25 2.697 \n", + "6 -122.25 2.992 \n", + "7 -122.25 2.414 \n", + "8 -122.26 2.267 \n", + "9 -122.25 2.611 " + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "df.head(10) " ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "038b9a1c", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'Population', 'AveOccup',\n", + " 'Latitude', 'Longitude', 'MedHouseVal'],\n", + " dtype='object')" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "df.columns" ] @@ -207,10 +445,239 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "8119af51", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
MedIncHouseAgeAveRoomsAveBedrmsPopulationAveOccupLatitudeLongitudeMedHouseValbedrooms_per_roomincome_per_room
02.23272041.06.9841271.023810322.02.55555637.88-122.234.5260.1465910.319685
12.23016521.06.2381370.9718802401.02.10984237.86-122.223.5850.1557970.357505
22.11111052.08.2881361.073446496.02.80226037.85-122.243.5210.1295160.254715
31.89357952.05.8173521.073059558.02.54794537.85-122.253.4130.1844580.325505
41.57819552.06.2818531.081081565.02.18146737.85-122.253.4220.1720960.251231
....................................
206350.94012425.05.0454551.133333845.02.56060639.48-121.090.7810.2246250.186331
206361.26886118.06.1140351.315789356.03.12280739.49-121.210.7710.2152080.207533
206370.99325217.05.2055431.1200921007.02.32563539.43-121.220.9230.2151730.190807
206381.05333618.05.3295131.171920741.02.12320939.43-121.320.8470.2198920.197642
206391.22041716.05.2547171.1622641387.02.61698139.37-121.240.8940.2211850.232252
\n", + "

20640 rows × 11 columns

\n", + "
" + ], + "text/plain": [ + " MedInc HouseAge AveRooms AveBedrms Population AveOccup \\\n", + "0 2.232720 41.0 6.984127 1.023810 322.0 2.555556 \n", + "1 2.230165 21.0 6.238137 0.971880 2401.0 2.109842 \n", + "2 2.111110 52.0 8.288136 1.073446 496.0 2.802260 \n", + "3 1.893579 52.0 5.817352 1.073059 558.0 2.547945 \n", + "4 1.578195 52.0 6.281853 1.081081 565.0 2.181467 \n", + "... ... ... ... ... ... ... \n", + "20635 0.940124 25.0 5.045455 1.133333 845.0 2.560606 \n", + "20636 1.268861 18.0 6.114035 1.315789 356.0 3.122807 \n", + "20637 0.993252 17.0 5.205543 1.120092 1007.0 2.325635 \n", + "20638 1.053336 18.0 5.329513 1.171920 741.0 2.123209 \n", + "20639 1.220417 16.0 5.254717 1.162264 1387.0 2.616981 \n", + "\n", + " Latitude Longitude MedHouseVal bedrooms_per_room income_per_room \n", + "0 37.88 -122.23 4.526 0.146591 0.319685 \n", + "1 37.86 -122.22 3.585 0.155797 0.357505 \n", + "2 37.85 -122.24 3.521 0.129516 0.254715 \n", + "3 37.85 -122.25 3.413 0.184458 0.325505 \n", + "4 37.85 -122.25 3.422 0.172096 0.251231 \n", + "... ... ... ... ... ... \n", + "20635 39.48 -121.09 0.781 0.224625 0.186331 \n", + "20636 39.49 -121.21 0.771 0.215208 0.207533 \n", + "20637 39.43 -121.22 0.923 0.215173 0.190807 \n", + "20638 39.43 -121.32 0.847 0.219892 0.197642 \n", + "20639 39.37 -121.24 0.894 0.221185 0.232252 \n", + "\n", + "[20640 rows x 11 columns]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "#Feature engineer (only run once) \n", "#DataPrep signal shows weak correlations, combining features for better signal\n", @@ -229,10 +696,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "1082da97", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Avg House Price: 2.06\n", + "Mean Absolute Error: 0.54\n", + "R-Squared Val: 0.6\n" + ] + } + ], "source": [ "#LR Model 1\n", "\n", @@ -278,10 +755,239 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "ecea0a84", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
MedIncHouseAgeAveRoomsAveBedrmsPopulationAveOccupLatitudeLongitudeMedHouseValbedrooms_per_roomincome_per_room
02.23272041.06.9841271.023810322.02.55555637.88-122.234.5260.1465910.319685
12.23016521.06.2381370.9718802401.02.10984237.86-122.223.5850.1557970.357505
22.11111052.08.2881361.073446496.02.80226037.85-122.243.5210.1295160.254715
31.89357952.05.8173521.073059558.02.54794537.85-122.253.4130.1844580.325505
41.57819552.06.2818531.081081565.02.18146737.85-122.253.4220.1720960.251231
....................................
206350.94012425.05.0454551.133333845.02.56060639.48-121.090.7810.2246250.186331
206361.26886118.06.1140351.315789356.03.12280739.49-121.210.7710.2152080.207533
206370.99325217.05.2055431.1200921007.02.32563539.43-121.220.9230.2151730.190807
206381.05333618.05.3295131.171920741.02.12320939.43-121.320.8470.2198920.197642
206391.22041716.05.2547171.1622641387.02.61698139.37-121.240.8940.2211850.232252
\n", + "

19648 rows × 11 columns

\n", + "
" + ], + "text/plain": [ + " MedInc HouseAge AveRooms AveBedrms Population AveOccup \\\n", + "0 2.232720 41.0 6.984127 1.023810 322.0 2.555556 \n", + "1 2.230165 21.0 6.238137 0.971880 2401.0 2.109842 \n", + "2 2.111110 52.0 8.288136 1.073446 496.0 2.802260 \n", + "3 1.893579 52.0 5.817352 1.073059 558.0 2.547945 \n", + "4 1.578195 52.0 6.281853 1.081081 565.0 2.181467 \n", + "... ... ... ... ... ... ... \n", + "20635 0.940124 25.0 5.045455 1.133333 845.0 2.560606 \n", + "20636 1.268861 18.0 6.114035 1.315789 356.0 3.122807 \n", + "20637 0.993252 17.0 5.205543 1.120092 1007.0 2.325635 \n", + "20638 1.053336 18.0 5.329513 1.171920 741.0 2.123209 \n", + "20639 1.220417 16.0 5.254717 1.162264 1387.0 2.616981 \n", + "\n", + " Latitude Longitude MedHouseVal bedrooms_per_room income_per_room \n", + "0 37.88 -122.23 4.526 0.146591 0.319685 \n", + "1 37.86 -122.22 3.585 0.155797 0.357505 \n", + "2 37.85 -122.24 3.521 0.129516 0.254715 \n", + "3 37.85 -122.25 3.413 0.184458 0.325505 \n", + "4 37.85 -122.25 3.422 0.172096 0.251231 \n", + "... ... ... ... ... ... \n", + "20635 39.48 -121.09 0.781 0.224625 0.186331 \n", + "20636 39.49 -121.21 0.771 0.215208 0.207533 \n", + "20637 39.43 -121.22 0.923 0.215173 0.190807 \n", + "20638 39.43 -121.32 0.847 0.219892 0.197642 \n", + "20639 39.37 -121.24 0.894 0.221185 0.232252 \n", + "\n", + "[19648 rows x 11 columns]" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "df2 = df[df['MedHouseVal'] < 5]\n", "df2" @@ -289,10 +995,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "628834ae", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Avg House Price: 1.92\n", + "Mean Absolute Error: 0.49\n", + "R-Squared Val: 0.57\n" + ] + } + ], "source": [ "#LR Model 2 (excluding MedHouseVal >= 5)\n", "\n", @@ -333,23 +1049,2162 @@ "execution_count": null, "id": "60eeff9c", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/judebaffoe-bonnie/opt/anaconda3/lib/python3.9/site-packages/dask/dataframe/core.py:7365: FutureWarning: Meta is not valid, `map_partitions` and `map_overlap` expects output to be a pandas object. Try passing a pandas object as meta or a dict or tuple representing the (name, dtype) of the columns. In the future the meta you passed will not work.\n", + " warnings.warn(\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " 0%| | 0/9 [00:00\n", + "\n", + "\n", + " DataPrep.EDA Report \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "
\n", + "
\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + "
'scatter.sample_size': 1000
\n", + "
Number of points to randomly sample per partition
\n", + "
\n", + " \n", + "
\n", + "
'height': 400
\n", + "
Height of the plot
\n", + "
\n", + " \n", + "
\n", + "
'width': 450
\n", + "
Width of the plot
\n", + "
\n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + "
\n", + " \n", + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + "
'hexbin.tile_size': 0.2881396020884052
\n", + "
Tile size, measured from the middle of the hexagon to the left or right corner
\n", + "
\n", + " \n", + "
\n", + "
'height': 400
\n", + "
Height of the plot
\n", + "
\n", + " \n", + "
\n", + "
'width': 450
\n", + "
Width of the plot
\n", + "
\n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + "
\n", + " \n", + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + "
'box.bins': 50
\n", + "
Number of bins
\n", + "
\n", + " \n", + "
\n", + "
'height': 400
\n", + "
Height of the plot
\n", + "
\n", + " \n", + "
\n", + "
'width': 450
\n", + "
Width of the plot
\n", + "
\n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + " \n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from dataprep.eda import plot\n", "import pandas as pd\n", "\n", - "results = pd.DataFrame({'Predicted': y_pred_new, 'Actual': y_test_new,})\n", + "results = pd.DataFrame({'Predicted House Price': y_pred_new, 'Actual House Price': y_test_new,})\n", "\n", "#actual vs pred\n", - "plot(results, \"Predicted House Price\",\"Actual House Price \")" + "plot = plot(results, \"Predicted House Price\",\"Actual House Price\")\n", + "\n", + "plot.save(OUTPUT_DIR / \"rf_actual_vs_predicted.html\")" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "id": "b26adbaf", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
MedIncHouseAgeAveRoomsAveBedrmsPopulationAveOccupLatitudeLongitudeMedHouseValbedrooms_per_roomincome_per_room
02.23272041.06.9841271.023810322.02.55555637.88-122.234.5260.1465910.319685
12.23016521.06.2381370.9718802401.02.10984237.86-122.223.5850.1557970.357505
22.11111052.08.2881361.073446496.02.80226037.85-122.243.5210.1295160.254715
31.89357952.05.8173521.073059558.02.54794537.85-122.253.4130.1844580.325505
41.57819552.06.2818531.081081565.02.18146737.85-122.253.4220.1720960.251231
....................................
206350.94012425.05.0454551.133333845.02.56060639.48-121.090.7810.2246250.186331
206361.26886118.06.1140351.315789356.03.12280739.49-121.210.7710.2152080.207533
206370.99325217.05.2055431.1200921007.02.32563539.43-121.220.9230.2151730.190807
206381.05333618.05.3295131.171920741.02.12320939.43-121.320.8470.2198920.197642
206391.22041716.05.2547171.1622641387.02.61698139.37-121.240.8940.2211850.232252
\n", + "

20640 rows × 11 columns

\n", + "
" + ], + "text/plain": [ + " MedInc HouseAge AveRooms AveBedrms Population AveOccup \\\n", + "0 2.232720 41.0 6.984127 1.023810 322.0 2.555556 \n", + "1 2.230165 21.0 6.238137 0.971880 2401.0 2.109842 \n", + "2 2.111110 52.0 8.288136 1.073446 496.0 2.802260 \n", + "3 1.893579 52.0 5.817352 1.073059 558.0 2.547945 \n", + "4 1.578195 52.0 6.281853 1.081081 565.0 2.181467 \n", + "... ... ... ... ... ... ... \n", + "20635 0.940124 25.0 5.045455 1.133333 845.0 2.560606 \n", + "20636 1.268861 18.0 6.114035 1.315789 356.0 3.122807 \n", + "20637 0.993252 17.0 5.205543 1.120092 1007.0 2.325635 \n", + "20638 1.053336 18.0 5.329513 1.171920 741.0 2.123209 \n", + "20639 1.220417 16.0 5.254717 1.162264 1387.0 2.616981 \n", + "\n", + " Latitude Longitude MedHouseVal bedrooms_per_room income_per_room \n", + "0 37.88 -122.23 4.526 0.146591 0.319685 \n", + "1 37.86 -122.22 3.585 0.155797 0.357505 \n", + "2 37.85 -122.24 3.521 0.129516 0.254715 \n", + "3 37.85 -122.25 3.413 0.184458 0.325505 \n", + "4 37.85 -122.25 3.422 0.172096 0.251231 \n", + "... ... ... ... ... ... \n", + "20635 39.48 -121.09 0.781 0.224625 0.186331 \n", + "20636 39.49 -121.21 0.771 0.215208 0.207533 \n", + "20637 39.43 -121.22 0.923 0.215173 0.190807 \n", + "20638 39.43 -121.32 0.847 0.219892 0.197642 \n", + "20639 39.37 -121.24 0.894 0.221185 0.232252 \n", + "\n", + "[20640 rows x 11 columns]" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "#use original df without log-transformed MedInc and new cols\n", "\n", @@ -364,10 +3219,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "id": "01ddb74e", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Random Forest R2: 0.8011\n", + "Random Forest Mean Abs Error: 0.3313\n" + ] + } + ], "source": [ "from sklearn.ensemble import RandomForestRegressor\n", "\n", @@ -394,14 +3258,1924 @@ "execution_count": null, "id": "da5d9aa3", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/judebaffoe-bonnie/opt/anaconda3/lib/python3.9/site-packages/dask/dataframe/core.py:7365: FutureWarning: Meta is not valid, `map_partitions` and `map_overlap` expects output to be a pandas object. Try passing a pandas object as meta or a dict or tuple representing the (name, dtype) of the columns. In the future the meta you passed will not work.\n", + " warnings.warn(\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " 0%| | 0/9 [00:00\n", + "\n", + "\n", + " DataPrep.EDA Report \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "
\n", + "
\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + "
'scatter.sample_size': 1000
\n", + "
Number of points to randomly sample per partition
\n", + "
\n", + " \n", + "
\n", + "
'height': 400
\n", + "
Height of the plot
\n", + "
\n", + " \n", + "
\n", + "
'width': 450
\n", + "
Width of the plot
\n", + "
\n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + "
\n", + " \n", + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + "
'hexbin.tile_size': 0.18063439999999958
\n", + "
Tile size, measured from the middle of the hexagon to the left or right corner
\n", + "
\n", + " \n", + "
\n", + "
'height': 400
\n", + "
Height of the plot
\n", + "
\n", + " \n", + "
\n", + "
'width': 450
\n", + "
Width of the plot
\n", + "
\n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + "
\n", + " \n", + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
\n", + "
'box.bins': 50
\n", + "
Number of bins
\n", + "
\n", + " \n", + "
\n", + "
'height': 400
\n", + "
Height of the plot
\n", + "
\n", + " \n", + "
\n", + "
'width': 450
\n", + "
Width of the plot
\n", + "
\n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "
\n", + " \n", + " \n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from dataprep.eda import plot\n", "import pandas as pd\n", "\n", "rf_results = pd.DataFrame({'Predicted House Price': rf_preds, 'Actual House Price': y_test})\n", "\n", - "plot(rf_results, \"Predicted House Price\",\"Actual House Price\")" + "rf_plot = plot(rf_results, \"Predicted House Price\",\"Actual House Price\")\n", + "\n", + "rf.plot.save('OUTPUT_DIR / \"rf_actual_vs_predicted.html')" ] }, { @@ -429,7 +5203,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.7" + "version": "3.9.25" } }, "nbformat": 4,