{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "da1ba4ff",
   "metadata": {},
   "source": [
    "# 🚀 filoma demo\n",
    "\n",
    "Fast, multi-backend file analysis with a tiny API surface"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "3c9cfc6f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "filoma version: 1.7.3\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 155416 characters]",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 1,
     "metadata": {
      "image/png": {
       "width": 600
      }
     },
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.display import Image\n",
    "\n",
    "import filoma\n",
    "\n",
    "print(f\"filoma version: {filoma.__version__}\")\n",
    "Image(\"../images/flow.png\", width=600)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "415fb942",
   "metadata": {},
   "source": [
    "Let's start with something simple, like getting a handy dataclass for a single file:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7bd80bf4",
   "metadata": {},
   "source": [
    "# 🔍📄 File analysis "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d28adfe2",
   "metadata": {},
   "source": [
    "### 📄 Single file (any kind)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "71a9cf1f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Path: /home/kalfasy/repos/filoma/README.md\n",
      "Size: 10914\n",
      "Modified: 2025-09-13 16:01:30\n",
      "file_info: ['accessed', 'as_dict', 'created', 'from_report', 'get', 'group', 'inode', 'is_dir', 'is_file', 'is_symlink', 'items', 'keys', 'mode', 'mode_str', 'modified', 'nlink', 'owner', 'path', 'rights', 'sha256', 'size', 'target_is_dir', 'target_is_file', 'to_dict', 'values', 'xattrs']\n"
     ]
    }
   ],
   "source": [
    "from filoma import probe_file\n",
    "\n",
    "file_info = probe_file(\"../README.md\")\n",
    "print(f\"Path: {file_info.path}\")\n",
    "print(f\"Size: {file_info.size}\")\n",
    "print(f\"Modified: {file_info.modified}\")\n",
    "print(f\"file_info: {[i for i in dir(file_info) if not i.startswith('_')]}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a6b1fb2",
   "metadata": {},
   "source": [
    "or specifically for image files:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "10c8f485",
   "metadata": {},
   "source": [
    "### 🖼️ Image file analysis"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "c573a319",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Type of file: png, Type of img object: <class 'filoma.images.image_profiler.ImageReport'>\n",
      "Shape: (762, 628, 4)\n",
      "Data range: 0.0 - 255.0\n",
      "img info: {'path': '../images/logo.png', 'file_type': 'png', 'shape': (762, 628, 4), 'dtype': 'uint8', 'min': 0.0, 'max': 255.0, 'mean': 230.89027732500793, 'nans': 0, 'infs': 0, 'unique': 256, 'status': None}\n"
     ]
    }
   ],
   "source": [
    "from filoma import probe_image\n",
    "\n",
    "img = probe_image(\"../images/logo.png\")\n",
    "print(f\"Type of file: {img.file_type}, Type of img object: {type(img)}\")\n",
    "print(f\"Shape: {img.shape}\")\n",
    "print(f\"Data range: {img.min} - {img.max}\")\n",
    "print(f\"img info: {img.as_dict()}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cc9779c9",
   "metadata": {},
   "source": [
    "# 🔍📁 Directory Analysis"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ac938f14",
   "metadata": {},
   "source": [
    "Do you want to analyze a directory of files and extract metadata, text content, and other useful information?   \n",
    "`filoma` makes it super easy to do so with just a few lines of code."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "0b115872",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m2025-09-13 17:25:20.543\u001b[0m | \u001b[34m\u001b[1mDEBUG   \u001b[0m | \u001b[36mfiloma.directories.directory_profiler\u001b[0m:\u001b[36m__init__\u001b[0m:\u001b[36m343\u001b[0m - \u001b[34m\u001b[1mInteractive environment detected, disabling progress bars to avoid conflicts\u001b[0m\n",
      "\u001b[32m2025-09-13 17:25:20.543\u001b[0m | \u001b[1mINFO    \u001b[0m | \u001b[36mfiloma.directories.directory_profiler\u001b[0m:\u001b[36mprobe\u001b[0m:\u001b[36m430\u001b[0m - \u001b[1mStarting directory analysis of '../' using 🦀 Rust (Parallel) implementation\u001b[0m\n",
      "\u001b[32m2025-09-13 17:25:21.221\u001b[0m | \u001b[32m\u001b[1mSUCCESS \u001b[0m | \u001b[36mfiloma.directories.directory_profiler\u001b[0m:\u001b[36mprobe\u001b[0m:\u001b[36m446\u001b[0m - \u001b[32m\u001b[1mDirectory analysis completed in 0.68s - Found 67,430 items (63,126 files, 4,304 folders) using 🦀 Rust (Parallel)\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-style: italic\"> Directory Analysis: /home/kalfasy/repos/filoma (🦀  </span>\n",
       "<span style=\"font-style: italic\">              Rust (Parallel)) - 0.68s               </span>\n",
       "┏━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
       "┃<span style=\"font-weight: bold\"> Metric                   </span>┃<span style=\"font-weight: bold\"> Value                  </span>┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩\n",
       "│<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\"> Total Files              </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 63,126                 </span>│\n",
       "│<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\"> Total Folders            </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 4,304                  </span>│\n",
       "│<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\"> Total Size               </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 2,049.2219619750977 MB </span>│\n",
       "│<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\"> Average Files per Folder </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 14.66682156133829      </span>│\n",
       "│<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\"> Maximum Depth            </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 14                     </span>│\n",
       "│<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\"> Empty Folders            </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 53                     </span>│\n",
       "│<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\"> Analysis Time            </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 0.68s                  </span>│\n",
       "│<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\"> Processing Speed         </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 99,451 items/sec       </span>│\n",
       "└──────────────────────────┴────────────────────────┘\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[3m Directory Analysis: /home/kalfasy/repos/filoma (🦀  \u001b[0m\n",
       "\u001b[3m              Rust (Parallel)) - 0.68s               \u001b[0m\n",
       "┏━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
       "┃\u001b[1m \u001b[0m\u001b[1mMetric                  \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mValue                 \u001b[0m\u001b[1m \u001b[0m┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩\n",
       "│\u001b[1;36m \u001b[0m\u001b[1;36mTotal Files             \u001b[0m\u001b[1;36m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m63,126                \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;36m \u001b[0m\u001b[1;36mTotal Folders           \u001b[0m\u001b[1;36m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m4,304                 \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;36m \u001b[0m\u001b[1;36mTotal Size              \u001b[0m\u001b[1;36m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m2,049.2219619750977 MB\u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;36m \u001b[0m\u001b[1;36mAverage Files per Folder\u001b[0m\u001b[1;36m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m14.66682156133829     \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;36m \u001b[0m\u001b[1;36mMaximum Depth           \u001b[0m\u001b[1;36m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m14                    \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;36m \u001b[0m\u001b[1;36mEmpty Folders           \u001b[0m\u001b[1;36m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m53                    \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;36m \u001b[0m\u001b[1;36mAnalysis Time           \u001b[0m\u001b[1;36m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m0.68s                 \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;36m \u001b[0m\u001b[1;36mProcessing Speed        \u001b[0m\u001b[1;36m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m99,451 items/sec      \u001b[0m\u001b[37m \u001b[0m│\n",
       "└──────────────────────────┴────────────────────────┘\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from filoma.directories import DirectoryProfiler, DirectoryProfilerConfig\n",
    "\n",
    "# Create a profiler using the typed config dataclass\n",
    "config = DirectoryProfilerConfig(use_rust=True)\n",
    "dir_prof = DirectoryProfiler(config)\n",
    "\n",
    "analysis = dir_prof.probe(\"../\")\n",
    "dir_prof.print_summary(analysis)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e86a6d47",
   "metadata": {},
   "source": [
    "Want to quickly see a report of your findings? filoma has you covered."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "fb2f3a50",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-style: italic\"> Directory Analysis: /home/kalfasy/repos/filoma (🦀  </span>\n",
       "<span style=\"font-style: italic\">              Rust (Parallel)) - 0.68s               </span>\n",
       "┏━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
       "┃<span style=\"font-weight: bold\"> Metric                   </span>┃<span style=\"font-weight: bold\"> Value                  </span>┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩\n",
       "│<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\"> Total Files              </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 63,126                 </span>│\n",
       "│<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\"> Total Folders            </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 4,304                  </span>│\n",
       "│<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\"> Total Size               </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 2,049.2219619750977 MB </span>│\n",
       "│<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\"> Average Files per Folder </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 14.66682156133829      </span>│\n",
       "│<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\"> Maximum Depth            </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 14                     </span>│\n",
       "│<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\"> Empty Folders            </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 53                     </span>│\n",
       "│<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\"> Analysis Time            </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 0.68s                  </span>│\n",
       "│<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\"> Processing Speed         </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 99,451 items/sec       </span>│\n",
       "└──────────────────────────┴────────────────────────┘\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[3m Directory Analysis: /home/kalfasy/repos/filoma (🦀  \u001b[0m\n",
       "\u001b[3m              Rust (Parallel)) - 0.68s               \u001b[0m\n",
       "┏━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
       "┃\u001b[1m \u001b[0m\u001b[1mMetric                  \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mValue                 \u001b[0m\u001b[1m \u001b[0m┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩\n",
       "│\u001b[1;36m \u001b[0m\u001b[1;36mTotal Files             \u001b[0m\u001b[1;36m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m63,126                \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;36m \u001b[0m\u001b[1;36mTotal Folders           \u001b[0m\u001b[1;36m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m4,304                 \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;36m \u001b[0m\u001b[1;36mTotal Size              \u001b[0m\u001b[1;36m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m2,049.2219619750977 MB\u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;36m \u001b[0m\u001b[1;36mAverage Files per Folder\u001b[0m\u001b[1;36m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m14.66682156133829     \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;36m \u001b[0m\u001b[1;36mMaximum Depth           \u001b[0m\u001b[1;36m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m14                    \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;36m \u001b[0m\u001b[1;36mEmpty Folders           \u001b[0m\u001b[1;36m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m53                    \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;36m \u001b[0m\u001b[1;36mAnalysis Time           \u001b[0m\u001b[1;36m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m0.68s                 \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;36m \u001b[0m\u001b[1;36mProcessing Speed        \u001b[0m\u001b[1;36m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m99,451 items/sec      \u001b[0m\u001b[37m \u001b[0m│\n",
       "└──────────────────────────┴────────────────────────┘\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-style: italic\">         File Extensions          </span>\n",
       "┏━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━┓\n",
       "┃<span style=\"font-weight: bold\"> Extension </span>┃<span style=\"font-weight: bold\"> Count </span>┃<span style=\"font-weight: bold\"> Percentage </span>┃\n",
       "┡━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━┩\n",
       "│<span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\"> .lock     </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 8     </span>│<span style=\"color: #008000; text-decoration-color: #008000\"> 0.0%       </span>│\n",
       "│<span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\"> .rlib     </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 136   </span>│<span style=\"color: #008000; text-decoration-color: #008000\"> 0.2%       </span>│\n",
       "│<span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\"> .sample   </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 14    </span>│<span style=\"color: #008000; text-decoration-color: #008000\"> 0.0%       </span>│\n",
       "│<span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\"> .crt      </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 2     </span>│<span style=\"color: #008000; text-decoration-color: #008000\"> 0.0%       </span>│\n",
       "│<span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\"> .build    </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 6     </span>│<span style=\"color: #008000; text-decoration-color: #008000\"> 0.0%       </span>│\n",
       "│<span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\"> .h        </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 1,050 </span>│<span style=\"color: #008000; text-decoration-color: #008000\"> 1.7%       </span>│\n",
       "│<span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\"> .cmd      </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 2     </span>│<span style=\"color: #008000; text-decoration-color: #008000\"> 0.0%       </span>│\n",
       "│<span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\"> .po       </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 2     </span>│<span style=\"color: #008000; text-decoration-color: #008000\"> 0.0%       </span>│\n",
       "│<span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\"> .d        </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 212   </span>│<span style=\"color: #008000; text-decoration-color: #008000\"> 0.3%       </span>│\n",
       "│<span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\"> .fits     </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 2     </span>│<span style=\"color: #008000; text-decoration-color: #008000\"> 0.0%       </span>│\n",
       "└───────────┴───────┴────────────┘\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[3m         File Extensions          \u001b[0m\n",
       "┏━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━┓\n",
       "┃\u001b[1m \u001b[0m\u001b[1mExtension\u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mCount\u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mPercentage\u001b[0m\u001b[1m \u001b[0m┃\n",
       "┡━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━┩\n",
       "│\u001b[1;35m \u001b[0m\u001b[1;35m.lock    \u001b[0m\u001b[1;35m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m8    \u001b[0m\u001b[37m \u001b[0m│\u001b[32m \u001b[0m\u001b[32m0.0%      \u001b[0m\u001b[32m \u001b[0m│\n",
       "│\u001b[1;35m \u001b[0m\u001b[1;35m.rlib    \u001b[0m\u001b[1;35m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m136  \u001b[0m\u001b[37m \u001b[0m│\u001b[32m \u001b[0m\u001b[32m0.2%      \u001b[0m\u001b[32m \u001b[0m│\n",
       "│\u001b[1;35m \u001b[0m\u001b[1;35m.sample  \u001b[0m\u001b[1;35m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m14   \u001b[0m\u001b[37m \u001b[0m│\u001b[32m \u001b[0m\u001b[32m0.0%      \u001b[0m\u001b[32m \u001b[0m│\n",
       "│\u001b[1;35m \u001b[0m\u001b[1;35m.crt     \u001b[0m\u001b[1;35m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m2    \u001b[0m\u001b[37m \u001b[0m│\u001b[32m \u001b[0m\u001b[32m0.0%      \u001b[0m\u001b[32m \u001b[0m│\n",
       "│\u001b[1;35m \u001b[0m\u001b[1;35m.build   \u001b[0m\u001b[1;35m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m6    \u001b[0m\u001b[37m \u001b[0m│\u001b[32m \u001b[0m\u001b[32m0.0%      \u001b[0m\u001b[32m \u001b[0m│\n",
       "│\u001b[1;35m \u001b[0m\u001b[1;35m.h       \u001b[0m\u001b[1;35m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m1,050\u001b[0m\u001b[37m \u001b[0m│\u001b[32m \u001b[0m\u001b[32m1.7%      \u001b[0m\u001b[32m \u001b[0m│\n",
       "│\u001b[1;35m \u001b[0m\u001b[1;35m.cmd     \u001b[0m\u001b[1;35m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m2    \u001b[0m\u001b[37m \u001b[0m│\u001b[32m \u001b[0m\u001b[32m0.0%      \u001b[0m\u001b[32m \u001b[0m│\n",
       "│\u001b[1;35m \u001b[0m\u001b[1;35m.po      \u001b[0m\u001b[1;35m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m2    \u001b[0m\u001b[37m \u001b[0m│\u001b[32m \u001b[0m\u001b[32m0.0%      \u001b[0m\u001b[32m \u001b[0m│\n",
       "│\u001b[1;35m \u001b[0m\u001b[1;35m.d       \u001b[0m\u001b[1;35m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m212  \u001b[0m\u001b[37m \u001b[0m│\u001b[32m \u001b[0m\u001b[32m0.3%      \u001b[0m\u001b[32m \u001b[0m│\n",
       "│\u001b[1;35m \u001b[0m\u001b[1;35m.fits    \u001b[0m\u001b[1;35m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m2    \u001b[0m\u001b[37m \u001b[0m│\u001b[32m \u001b[0m\u001b[32m0.0%      \u001b[0m\u001b[32m \u001b[0m│\n",
       "└───────────┴───────┴────────────┘\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-style: italic\">                Common Folder Names                </span>\n",
       "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓\n",
       "┃<span style=\"font-weight: bold\"> Folder Name                       </span>┃<span style=\"font-weight: bold\"> Occurrences </span>┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━┩\n",
       "│<span style=\"color: #000080; text-decoration-color: #000080; font-weight: bold\"> 50                                </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 1           </span>│\n",
       "│<span style=\"color: #000080; text-decoration-color: #000080; font-weight: bold\"> datetimerange                     </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 2           </span>│\n",
       "│<span style=\"color: #000080; text-decoration-color: #000080; font-weight: bold\"> pydev_sitecustomize               </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 2           </span>│\n",
       "│<span style=\"color: #000080; text-decoration-color: #000080; font-weight: bold\"> it                                </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 4           </span>│\n",
       "│<span style=\"color: #000080; text-decoration-color: #000080; font-weight: bold\"> assets                            </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 3           </span>│\n",
       "│<span style=\"color: #000080; text-decoration-color: #000080; font-weight: bold\"> lib2to3                           </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 2           </span>│\n",
       "│<span style=\"color: #000080; text-decoration-color: #000080; font-weight: bold\"> mark                              </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 2           </span>│\n",
       "│<span style=\"color: #000080; text-decoration-color: #000080; font-weight: bold\"> requests_toolbelt-1.0.0.dist-info </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 2           </span>│\n",
       "│<span style=\"color: #000080; text-decoration-color: #000080; font-weight: bold\"> certifi-2025.6.15.dist-info       </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 2           </span>│\n",
       "│<span style=\"color: #000080; text-decoration-color: #000080; font-weight: bold\"> click                             </span>│<span style=\"color: #c0c0c0; text-decoration-color: #c0c0c0\"> 4           </span>│\n",
       "└───────────────────────────────────┴─────────────┘\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[3m                Common Folder Names                \u001b[0m\n",
       "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓\n",
       "┃\u001b[1m \u001b[0m\u001b[1mFolder Name                      \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOccurrences\u001b[0m\u001b[1m \u001b[0m┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━┩\n",
       "│\u001b[1;34m \u001b[0m\u001b[1;34m50                               \u001b[0m\u001b[1;34m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m1          \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;34m \u001b[0m\u001b[1;34mdatetimerange                    \u001b[0m\u001b[1;34m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m2          \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;34m \u001b[0m\u001b[1;34mpydev_sitecustomize              \u001b[0m\u001b[1;34m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m2          \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;34m \u001b[0m\u001b[1;34mit                               \u001b[0m\u001b[1;34m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m4          \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;34m \u001b[0m\u001b[1;34massets                           \u001b[0m\u001b[1;34m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m3          \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;34m \u001b[0m\u001b[1;34mlib2to3                          \u001b[0m\u001b[1;34m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m2          \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;34m \u001b[0m\u001b[1;34mmark                             \u001b[0m\u001b[1;34m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m2          \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;34m \u001b[0m\u001b[1;34mrequests_toolbelt-1.0.0.dist-info\u001b[0m\u001b[1;34m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m2          \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;34m \u001b[0m\u001b[1;34mcertifi-2025.6.15.dist-info      \u001b[0m\u001b[1;34m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m2          \u001b[0m\u001b[37m \u001b[0m│\n",
       "│\u001b[1;34m \u001b[0m\u001b[1;34mclick                            \u001b[0m\u001b[1;34m \u001b[0m│\u001b[37m \u001b[0m\u001b[37m4          \u001b[0m\u001b[37m \u001b[0m│\n",
       "└───────────────────────────────────┴─────────────┘\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-style: italic\">                             Empty Folders (showing 20 of 53)                             </span>\n",
       "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
       "┃<span style=\"font-weight: bold\"> Path                                                                                   </span>┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/notebooks/tests                                             </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/proc-macro2-fdcb222da4373f07/out         </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/pyo3-17c1b0b456a0c7e4/out                </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/crossbeam-utils-7b9bd07d9fad49b5/out     </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/serde_json-85cdf3d882972d5c/out          </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/pyo3-8813d706ead48d90/out                </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/pyo3-macros-backend-6807c5cda8b1462a/out </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/memoffset-f4a6c90d4e3f18eb/out           </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/rayon-core-03a79c366c595edc/out          </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/pyo3-macros-backend-3864f2b2dbf9644d/out </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/pyo3-264b9b4aa4d6a2b5/out                </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/portable-atomic-f4353affba5b92e8/out     </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/pyo3-ffi-747a9d93a69eb79b/out            </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/proc-macro2-4d577003447afa24/out         </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/pyo3-ffi-8e536f56d2d22bd8/out            </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/libc-9d68f4abca27c9af/out                </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/lock_api-96adb08174198570/out            </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/serde-6690732fba37d144/out               </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/parking_lot_core-d5ba795b49a036a8/out    </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> /home/kalfasy/repos/filoma/target/debug/build/pyo3-ffi-0b1b893f015622ee/out            </span>│\n",
       "│<span style=\"color: #808000; text-decoration-color: #808000\"> ... and 33 more                                                                        </span>│\n",
       "└────────────────────────────────────────────────────────────────────────────────────────┘\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[3m                             Empty Folders (showing 20 of 53)                             \u001b[0m\n",
       "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
       "┃\u001b[1m \u001b[0m\u001b[1mPath                                                                                  \u001b[0m\u001b[1m \u001b[0m┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/notebooks/tests                                            \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/proc-macro2-fdcb222da4373f07/out        \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/pyo3-17c1b0b456a0c7e4/out               \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/crossbeam-utils-7b9bd07d9fad49b5/out    \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/serde_json-85cdf3d882972d5c/out         \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/pyo3-8813d706ead48d90/out               \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/pyo3-macros-backend-6807c5cda8b1462a/out\u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/memoffset-f4a6c90d4e3f18eb/out          \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/rayon-core-03a79c366c595edc/out         \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/pyo3-macros-backend-3864f2b2dbf9644d/out\u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/pyo3-264b9b4aa4d6a2b5/out               \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/portable-atomic-f4353affba5b92e8/out    \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/pyo3-ffi-747a9d93a69eb79b/out           \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/proc-macro2-4d577003447afa24/out        \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/pyo3-ffi-8e536f56d2d22bd8/out           \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/libc-9d68f4abca27c9af/out               \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/lock_api-96adb08174198570/out           \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/serde-6690732fba37d144/out              \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/parking_lot_core-d5ba795b49a036a8/out   \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m/home/kalfasy/repos/filoma/target/debug/build/pyo3-ffi-0b1b893f015622ee/out           \u001b[0m\u001b[33m \u001b[0m│\n",
       "│\u001b[33m \u001b[0m\u001b[33m... and 33 more                                                                       \u001b[0m\u001b[33m \u001b[0m│\n",
       "└────────────────────────────────────────────────────────────────────────────────────────┘\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "dir_prof.print_report(analysis)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "448bc8d6",
   "metadata": {},
   "source": [
    "# 📁 Directory of files --> DataFrame --> Data Exploration"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "570832a2",
   "metadata": {},
   "source": [
    "Now that you saw what's up with your files, you might want to explore the data in a familiar format.   \n",
    "`filoma` can convert the analysis results into a Polars (or Pandas) DataFrame real quick.  \n",
    "**NOTE**: Pandas support requires the `pd` extra which you can install by running `uv sync --extra pd` in your terminal."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "9006315c",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m2025-09-13 17:25:21.238\u001b[0m | \u001b[34m\u001b[1mDEBUG   \u001b[0m | \u001b[36mfiloma.directories.directory_profiler\u001b[0m:\u001b[36m__init__\u001b[0m:\u001b[36m343\u001b[0m - \u001b[34m\u001b[1mInteractive environment detected, disabling progress bars to avoid conflicts\u001b[0m\n",
      "\u001b[32m2025-09-13 17:25:21.239\u001b[0m | \u001b[1mINFO    \u001b[0m | \u001b[36mfiloma.directories.directory_profiler\u001b[0m:\u001b[36mprobe\u001b[0m:\u001b[36m430\u001b[0m - \u001b[1mStarting directory analysis of '../' using 🐍 Python implementation\u001b[0m\n",
      "\u001b[32m2025-09-13 17:25:21.584\u001b[0m | \u001b[32m\u001b[1mSUCCESS \u001b[0m | \u001b[36mfiloma.directories.directory_profiler\u001b[0m:\u001b[36mprobe\u001b[0m:\u001b[36m446\u001b[0m - \u001b[32m\u001b[1mDirectory analysis completed in 0.35s - Found 385 items (323 files, 62 folders) using 🐍 Python\u001b[0m\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found 384 files\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div><style>\n",
       ".dataframe > thead > tr,\n",
       ".dataframe > tbody > tr {\n",
       "  text-align: right;\n",
       "  white-space: pre-wrap;\n",
       "}\n",
       "</style>\n",
       "<small>shape: (5, 18)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>path</th><th>depth</th><th>parent</th><th>name</th><th>stem</th><th>suffix</th><th>size_bytes</th><th>modified_time</th><th>created_time</th><th>is_file</th><th>is_dir</th><th>owner</th><th>group</th><th>mode_str</th><th>inode</th><th>nlink</th><th>sha256</th><th>xattrs</th></tr><tr><td>str</td><td>i64</td><td>str</td><td>str</td><td>str</td><td>str</td><td>i64</td><td>str</td><td>str</td><td>bool</td><td>bool</td><td>str</td><td>str</td><td>str</td><td>i64</td><td>i64</td><td>str</td><td>str</td></tr></thead><tbody><tr><td>&quot;../pyproject.toml&quot;</td><td>1</td><td>&quot;..&quot;</td><td>&quot;pyproject.toml&quot;</td><td>&quot;pyproject&quot;</td><td>&quot;.toml&quot;</td><td>1932</td><td>&quot;2025-09-13 17:16:30&quot;</td><td>&quot;2025-09-13 17:16:30&quot;</td><td>true</td><td>false</td><td>&quot;kalfasy&quot;</td><td>&quot;kalfasy&quot;</td><td>&quot;-rw-rw-r--&quot;</td><td>7579961</td><td>1</td><td>null</td><td>&quot;{}&quot;</td></tr><tr><td>&quot;../scripts&quot;</td><td>1</td><td>&quot;..&quot;</td><td>&quot;scripts&quot;</td><td>&quot;scripts&quot;</td><td>&quot;&quot;</td><td>4096</td><td>&quot;2025-09-05 20:26:25&quot;</td><td>&quot;2025-09-05 20:26:25&quot;</td><td>false</td><td>true</td><td>&quot;kalfasy&quot;</td><td>&quot;kalfasy&quot;</td><td>&quot;drwxrwxr-x&quot;</td><td>7603122</td><td>2</td><td>null</td><td>&quot;{}&quot;</td></tr><tr><td>&quot;../.pytest_cache&quot;</td><td>1</td><td>&quot;..&quot;</td><td>&quot;.pytest_cache&quot;</td><td>&quot;.pytest_cache&quot;</td><td>&quot;&quot;</td><td>4096</td><td>&quot;2025-07-05 22:28:03&quot;</td><td>&quot;2025-07-05 22:28:03&quot;</td><td>false</td><td>true</td><td>&quot;kalfasy&quot;</td><td>&quot;kalfasy&quot;</td><td>&quot;drwxrwxr-x&quot;</td><td>7604845</td><td>3</td><td>null</td><td>&quot;{}&quot;</td></tr><tr><td>&quot;../.vscode&quot;</td><td>1</td><td>&quot;..&quot;</td><td>&quot;.vscode&quot;</td><td>&quot;.vscode&quot;</td><td>&quot;&quot;</td><td>4096</td><td>&quot;2025-07-06 11:11:18&quot;</td><td>&quot;2025-07-06 11:11:18&quot;</td><td>false</td><td>true</td><td>&quot;kalfasy&quot;</td><td>&quot;kalfasy&quot;</td><td>&quot;drwxrwxr-x&quot;</td><td>7591635</td><td>2</td><td>null</td><td>&quot;{}&quot;</td></tr><tr><td>&quot;../Makefile&quot;</td><td>1</td><td>&quot;..&quot;</td><td>&quot;Makefile&quot;</td><td>&quot;Makefile&quot;</td><td>&quot;&quot;</td><td>2876</td><td>&quot;2025-09-13 12:14:25&quot;</td><td>&quot;2025-09-13 12:14:25&quot;</td><td>true</td><td>false</td><td>&quot;kalfasy&quot;</td><td>&quot;kalfasy&quot;</td><td>&quot;-rw-rw-r--&quot;</td><td>7603119</td><td>1</td><td>null</td><td>&quot;{}&quot;</td></tr></tbody></table></div>"
      ],
      "text/plain": [
       "shape: (5, 18)\n",
       "┌───────────────────┬───────┬────────┬────────────────┬───┬─────────┬───────┬────────┬────────┐\n",
       "│ path              ┆ depth ┆ parent ┆ name           ┆ … ┆ inode   ┆ nlink ┆ sha256 ┆ xattrs │\n",
       "│ ---               ┆ ---   ┆ ---    ┆ ---            ┆   ┆ ---     ┆ ---   ┆ ---    ┆ ---    │\n",
       "│ str               ┆ i64   ┆ str    ┆ str            ┆   ┆ i64     ┆ i64   ┆ str    ┆ str    │\n",
       "╞═══════════════════╪═══════╪════════╪════════════════╪═══╪═════════╪═══════╪════════╪════════╡\n",
       "│ ../pyproject.toml ┆ 1     ┆ ..     ┆ pyproject.toml ┆ … ┆ 7579961 ┆ 1     ┆ null   ┆ {}     │\n",
       "│ ../scripts        ┆ 1     ┆ ..     ┆ scripts        ┆ … ┆ 7603122 ┆ 2     ┆ null   ┆ {}     │\n",
       "│ ../.pytest_cache  ┆ 1     ┆ ..     ┆ .pytest_cache  ┆ … ┆ 7604845 ┆ 3     ┆ null   ┆ {}     │\n",
       "│ ../.vscode        ┆ 1     ┆ ..     ┆ .vscode        ┆ … ┆ 7591635 ┆ 2     ┆ null   ┆ {}     │\n",
       "│ ../Makefile       ┆ 1     ┆ ..     ┆ Makefile       ┆ … ┆ 7603119 ┆ 1     ┆ null   ┆ {}     │\n",
       "└───────────────────┴───────┴────────┴────────────────┴───┴─────────┴───────┴────────┴────────┘"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from filoma import probe_to_df\n",
    "\n",
    "df = probe_to_df(\"../\", max_depth=2, enrich=True)\n",
    "print(f\"Found {len(df)} files\")\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "34b6a71e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Type of df:\t<class 'pandas.core.frame.DataFrame'>, \n",
      "Shape of df:\t(384, 18)\n"
     ]
    }
   ],
   "source": [
    "print(f\"Type of df:\\t{type(df.to_pandas())}, \\nShape of df:\\t{df.to_pandas().shape}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e28af33",
   "metadata": {},
   "source": [
    "# ⚡ DataFrame enrichment"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e12bb3a5",
   "metadata": {},
   "source": [
    "You're probably wondering \"what is `enrich=True`?\"  \n",
    "Well, since `filoma` gathers the paths of your files in a DataFrame, why not enrich this DataFrame with additional metadata. Its own `DataFrame` class has convenience functions like: `add_path_components()`, `add_file_stats_cols()`, `add_depth_col()`  \n",
    "  \n",
    "Let's see it in action:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "a611ca15",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m2025-09-13 17:25:21.657\u001b[0m | \u001b[34m\u001b[1mDEBUG   \u001b[0m | \u001b[36mfiloma.directories.directory_profiler\u001b[0m:\u001b[36m__init__\u001b[0m:\u001b[36m343\u001b[0m - \u001b[34m\u001b[1mInteractive environment detected, disabling progress bars to avoid conflicts\u001b[0m\n",
      "\u001b[32m2025-09-13 17:25:21.657\u001b[0m | \u001b[1mINFO    \u001b[0m | \u001b[36mfiloma.directories.directory_profiler\u001b[0m:\u001b[36mprobe\u001b[0m:\u001b[36m430\u001b[0m - \u001b[1mStarting directory analysis of '../' using 🦀 Rust (Parallel) implementation\u001b[0m\n",
      "\u001b[32m2025-09-13 17:25:22.558\u001b[0m | \u001b[32m\u001b[1mSUCCESS \u001b[0m | \u001b[36mfiloma.directories.directory_profiler\u001b[0m:\u001b[36mprobe\u001b[0m:\u001b[36m446\u001b[0m - \u001b[32m\u001b[1mDirectory analysis completed in 0.90s - Found 67,432 items (63,128 files, 4,304 folders) using 🦀 Rust (Parallel)\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮\n",
       "│ Columns before enrich: <span style=\"font-weight: bold\">path</span>                                                                                     │\n",
       "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
       "</pre>\n"
      ],
      "text/plain": [
       "╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮\n",
       "│ Columns before enrich: \u001b[1mpath\u001b[0m                                                                                     │\n",
       "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">╭──────────────────────────────────────── DataFrame head (before enrich) ─────────────────────────────────────────╮\n",
       "│              path                                                                                               │\n",
       "│ ../pyproject.toml                                                                                               │\n",
       "│        ../scripts                                                                                               │\n",
       "│  ../.pytest_cache                                                                                               │\n",
       "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
       "</pre>\n"
      ],
      "text/plain": [
       "╭──────────────────────────────────────── DataFrame head (before enrich) ─────────────────────────────────────────╮\n",
       "│              path                                                                                               │\n",
       "│ ../pyproject.toml                                                                                               │\n",
       "│        ../scripts                                                                                               │\n",
       "│  ../.pytest_cache                                                                                               │\n",
       "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮\n",
       "│ New columns after enrich: <span style=\"font-weight: bold\">created_time, depth, group, inode, is_dir, is_file, mode_str, modified_time, name, </span>   │\n",
       "│ <span style=\"font-weight: bold\">nlink, owner, parent, sha256, size_bytes, stem, suffix, xattrs</span>                                                  │\n",
       "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
       "</pre>\n"
      ],
      "text/plain": [
       "╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮\n",
       "│ New columns after enrich: \u001b[1mcreated_time, depth, group, inode, is_dir, is_file, mode_str, modified_time, name, \u001b[0m   │\n",
       "│ \u001b[1mnlink, owner, parent, sha256, size_bytes, stem, suffix, xattrs\u001b[0m                                                  │\n",
       "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">╭───────────────────────────────────────── DataFrame head (after enrich) ─────────────────────────────────────────╮\n",
       "│              path parent           name          stem suffix  size_bytes       modified_time                    │\n",
       "│ created_time  is_file  is_dir   owner   group   mode_str   inode  nlink sha256 xattrs  depth                    │\n",
       "│ ../pyproject.toml     .. pyproject.toml     pyproject  .toml        1932 2025-09-13 17:16:30 2025-09-13         │\n",
       "│ 17:16:30     True   False kalfasy kalfasy -rw-rw-r-- 7579961      1   None     {}      1                        │\n",
       "│        ../scripts     ..        scripts       scripts               4096 2025-09-05 20:26:25 2025-09-05         │\n",
       "│ 20:26:25    False    True kalfasy kalfasy drwxrwxr-x 7603122      2   None     {}      1                        │\n",
       "│  ../.pytest_cache     ..  .pytest_cache .pytest_cache               4096 2025-07-05 22:28:03 2025-07-05         │\n",
       "│ 22:28:03    False    True kalfasy kalfasy drwxrwxr-x 7604845      3   None     {}      1                        │\n",
       "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n",
       "</pre>\n"
      ],
      "text/plain": [
       "╭───────────────────────────────────────── DataFrame head (after enrich) ─────────────────────────────────────────╮\n",
       "│              path parent           name          stem suffix  size_bytes       modified_time                    │\n",
       "│ created_time  is_file  is_dir   owner   group   mode_str   inode  nlink sha256 xattrs  depth                    │\n",
       "│ ../pyproject.toml     .. pyproject.toml     pyproject  .toml        1932 2025-09-13 17:16:30 2025-09-13         │\n",
       "│ 17:16:30     True   False kalfasy kalfasy -rw-rw-r-- 7579961      1   None     {}      1                        │\n",
       "│        ../scripts     ..        scripts       scripts               4096 2025-09-05 20:26:25 2025-09-05         │\n",
       "│ 20:26:25    False    True kalfasy kalfasy drwxrwxr-x 7603122      2   None     {}      1                        │\n",
       "│  ../.pytest_cache     ..  .pytest_cache .pytest_cache               4096 2025-07-05 22:28:03 2025-07-05         │\n",
       "│ 22:28:03    False    True kalfasy kalfasy drwxrwxr-x 7604845      3   None     {}      1                        │\n",
       "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from rich.console import Console\n",
    "from rich.panel import Panel\n",
    "\n",
    "console = Console()\n",
    "\n",
    "cfg = DirectoryProfilerConfig(build_dataframe=True, use_rust=True, return_absolute_paths=True)\n",
    "dprof = DirectoryProfiler(cfg)\n",
    "res = dprof.probe(\"../\")\n",
    "\n",
    "orig_cols = list(res.dataframe.columns)\n",
    "console.print(Panel(f\"Columns before enrich: [bold]{', '.join(orig_cols)}[/]\"))\n",
    "console.print(Panel(res.dataframe.head(3).to_pandas().to_string(index=False), title=\"DataFrame head (before enrich)\"))\n",
    "\n",
    "df = res.dataframe.enrich()\n",
    "new_cols = sorted(set(df.columns) - set(orig_cols))\n",
    "console.print(Panel(f\"New columns after enrich: [bold]{', '.join(new_cols)}[/]\"))\n",
    "console.print(Panel(df.head(3).to_pandas().to_string(index=False), title=\"DataFrame head (after enrich)\"))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "85423605",
   "metadata": {},
   "source": [
    "# 🤖 ML-ready splits (train, val, test)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "daabef4e",
   "metadata": {},
   "source": [
    "The next logical thing for `filoma` to serve in data science workflows is to provide easy ways to create ML-ready splits.  \n",
    "\n",
    "In a very simple case, you have a dataframe with a `split`/`label`/... column that you want to use to create the splits like so:  \n",
    "> train, val, test = df[df[\"split\"] == \"train\"], df[df[\"split\"] == \"val\"], df[df[\"split\"] == \"test\"]  \n",
    "\n",
    "But things are rarely that simple in practice.  \n",
    "\n",
    "When you're given data in the \"real world\", either in folders & files or in a dataframe, you often need to create the splits yourself.  \n",
    "  \n",
    ">*Many practicioners unfortunately often disregard the importance of the data splits and split their data randomly, which can lead to data leakage, overfitting issues and unrealistic performance metrics*  \n",
    "\n",
    "A minimum best practice is to split your data into 3 sets:  \n",
    "- *Training set*: used to train your model\n",
    "- *Validation set*: used to tune your model's hyperparameters\n",
    "- *Testing set*: used to evaluate the final performance of your model  \n",
    "\n",
    "Ideally, you'd want to use a validation set that is representative of your test set, and both should be representative of your real-world data. So, special care should be taken to ensure that the splits are done correctly.  "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "43ec30d9",
   "metadata": {},
   "source": [
    "##### 📚 traditional `sklearn` way"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d1b50845",
   "metadata": {},
   "source": [
    "A very popular (if not the most popular) way of splitting data, is to use `scikit-learn`'s function called `train_test_split` that can split your data into training and testing sets. It can do that for you rather easily, although you'll need to call it twice if you want a 3-way split.:  \n",
    "> from sklearn.model_selection import train_test_split  \n",
    "> train, temp = train_test_split(df, test_size=0.4)  \n",
    "> val, test = train_test_split(temp, test_size=0.5)  \n",
    "\n",
    "Isn't it confusing that you just wanted a 60/20/20 split but had to specify 40% and then 50%? Imagine doing this for a 70/20/10 split...\n",
    "> from sklearn.model_selection import train_test_split  \n",
    "> train, temp = train_test_split(df, test_size=0.3)  \n",
    "> val, test = train_test_split(temp, test_size=0.3333)  "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d84a82bf",
   "metadata": {},
   "source": [
    "##### 🧙‍♂️ filoma's `split` method"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1745d8d7",
   "metadata": {},
   "source": [
    "\n",
    "`filoma` takes this a step further by providing a function that can not only split your data into training, validation, and testing sets in one-go, but also do that based on features found in your file-names or directories.  \n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ba684adf",
   "metadata": {},
   "source": [
    "For example, your data might have subcategories encoded in filenames\n",
    "like `dog_bulldog_001.jpg`, `dog_bulldog_002.jpg`, `cat_siamese_001.jpg`, etc.\n",
    "You can use `filoma`'s `add_filename_features()` to extract these features into separate columns. Plus, you can name these columns whatever you want!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e68bd764",
   "metadata": {},
   "source": [
    "### Simple Random Split\n",
    "\n",
    "Let's start with a simple random split of our scanned files. This is useful when you don't need to group related files together."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee29ed35",
   "metadata": {},
   "source": [
    "## 🐶 Example: splitting pet images by breed\n",
    "##### Create a DataFrame with file paths"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "d9056ab4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Small sample of the DataFrame:\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div><style>\n",
       ".dataframe > thead > tr,\n",
       ".dataframe > tbody > tr {\n",
       "  text-align: right;\n",
       "  white-space: pre-wrap;\n",
       "}\n",
       "</style>\n",
       "<small>shape: (5, 1)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>path</th></tr><tr><td>str</td></tr></thead><tbody><tr><td>&quot;bird/sparrow_hatchling_090.jpg&quot;</td></tr><tr><td>&quot;dog/bulldog_white_031.jpg&quot;</td></tr><tr><td>&quot;cat/persian_white_062.jpg&quot;</td></tr><tr><td>&quot;dog/beagle_tricolor_052.jpg&quot;</td></tr><tr><td>&quot;cat/mainecoon_tabby_012.jpg&quot;</td></tr></tbody></table></div>"
      ],
      "text/plain": [
       "shape: (5, 1)\n",
       "┌────────────────────────────────┐\n",
       "│ path                           │\n",
       "│ ---                            │\n",
       "│ str                            │\n",
       "╞════════════════════════════════╡\n",
       "│ bird/sparrow_hatchling_090.jpg │\n",
       "│ dog/bulldog_white_031.jpg      │\n",
       "│ cat/persian_white_062.jpg      │\n",
       "│ dog/beagle_tricolor_052.jpg    │\n",
       "│ cat/mainecoon_tabby_012.jpg    │\n",
       "└────────────────────────────────┘"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from filoma import DataFrame\n",
    "\n",
    "breeds_by_species = {\n",
    "    \"dog\": [\"labrador\", \"beagle\", \"bulldog\", \"poodle\"],\n",
    "    \"cat\": [\"siamese\", \"mainecoon\", \"persian\", \"ragdoll\"],\n",
    "    \"bird\": [\"sparrow\", \"robin\", \"parrot\", \"crow\"],\n",
    "}\n",
    "\n",
    "colors_by_breed = {\n",
    "    \"labrador\": [\"black\", \"yellow\", \"chocolate\"],\n",
    "    \"beagle\": [\"tricolor\", \"brown\"],\n",
    "    \"bulldog\": [\"fawn\", \"white\"],\n",
    "    \"poodle\": [\"white\", \"black\"],\n",
    "    \"siamese\": [\"sealpoint\", \"bluepoint\"],\n",
    "    \"mainecoon\": [\"tabby\", \"brown\"],\n",
    "    \"persian\": [\"white\", \"silver\"],\n",
    "    \"ragdoll\": [\"colorpoint\", \"sealpoint\"],\n",
    "    \"sparrow\": [\"hatchling\", \"adult\"],\n",
    "    \"robin\": [\"adult\", \"juvenile\"],\n",
    "    \"parrot\": [\"green\", \"red\"],\n",
    "    \"crow\": [\"black\"],\n",
    "}\n",
    "\n",
    "# build all (species, breed, color) combos\n",
    "combos = []\n",
    "for species, breeds in breeds_by_species.items():\n",
    "    for breed in breeds:\n",
    "        colors = colors_by_breed.get(breed, [\"unknown\"])\n",
    "        for color in colors:\n",
    "            combos.append((species, breed, color))\n",
    "\n",
    "# generate 100 file paths cycling through combos and numbering files\n",
    "paths = []\n",
    "for i in range(1, 101):\n",
    "    species, breed, color = combos[(i - 1) % len(combos)]\n",
    "    paths.append(f\"{species}/{breed}_{color}_{i:03d}.jpg\")\n",
    "\n",
    "data = {\"path\": paths}\n",
    "\n",
    "df = DataFrame(data)\n",
    "print(\"Small sample of the DataFrame:\")\n",
    "df.sample(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6c4830a8",
   "metadata": {},
   "source": [
    "##### Add path components as columns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "2de1379e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><style>\n",
       ".dataframe > thead > tr,\n",
       ".dataframe > tbody > tr {\n",
       "  text-align: right;\n",
       "  white-space: pre-wrap;\n",
       "}\n",
       "</style>\n",
       "<small>shape: (100, 4)</small><table border=\"1\" class=\"dataframe\"><thead><tr><th>path</th><th>breed</th><th>color</th><th>number</th></tr><tr><td>str</td><td>str</td><td>str</td><td>str</td></tr></thead><tbody><tr><td>&quot;dog/labrador_black_001.jpg&quot;</td><td>&quot;labrador&quot;</td><td>&quot;black&quot;</td><td>&quot;001&quot;</td></tr><tr><td>&quot;dog/labrador_yellow_002.jpg&quot;</td><td>&quot;labrador&quot;</td><td>&quot;yellow&quot;</td><td>&quot;002&quot;</td></tr><tr><td>&quot;dog/labrador_chocolate_003.jpg&quot;</td><td>&quot;labrador&quot;</td><td>&quot;chocolate&quot;</td><td>&quot;003&quot;</td></tr><tr><td>&quot;dog/beagle_tricolor_004.jpg&quot;</td><td>&quot;beagle&quot;</td><td>&quot;tricolor&quot;</td><td>&quot;004&quot;</td></tr><tr><td>&quot;dog/beagle_brown_005.jpg&quot;</td><td>&quot;beagle&quot;</td><td>&quot;brown&quot;</td><td>&quot;005&quot;</td></tr><tr><td>&hellip;</td><td>&hellip;</td><td>&hellip;</td><td>&hellip;</td></tr><tr><td>&quot;bird/crow_black_096.jpg&quot;</td><td>&quot;crow&quot;</td><td>&quot;black&quot;</td><td>&quot;096&quot;</td></tr><tr><td>&quot;dog/labrador_black_097.jpg&quot;</td><td>&quot;labrador&quot;</td><td>&quot;black&quot;</td><td>&quot;097&quot;</td></tr><tr><td>&quot;dog/labrador_yellow_098.jpg&quot;</td><td>&quot;labrador&quot;</td><td>&quot;yellow&quot;</td><td>&quot;098&quot;</td></tr><tr><td>&quot;dog/labrador_chocolate_099.jpg&quot;</td><td>&quot;labrador&quot;</td><td>&quot;chocolate&quot;</td><td>&quot;099&quot;</td></tr><tr><td>&quot;dog/beagle_tricolor_100.jpg&quot;</td><td>&quot;beagle&quot;</td><td>&quot;tricolor&quot;</td><td>&quot;100&quot;</td></tr></tbody></table></div>"
      ],
      "text/plain": [
       "filoma.DataFrame with 100 rows\n",
       "shape: (100, 4)\n",
       "┌────────────────────────────────┬──────────┬───────────┬────────┐\n",
       "│ path                           ┆ breed    ┆ color     ┆ number │\n",
       "│ ---                            ┆ ---      ┆ ---       ┆ ---    │\n",
       "│ str                            ┆ str      ┆ str       ┆ str    │\n",
       "╞════════════════════════════════╪══════════╪═══════════╪════════╡\n",
       "│ dog/labrador_black_001.jpg     ┆ labrador ┆ black     ┆ 001    │\n",
       "│ dog/labrador_yellow_002.jpg    ┆ labrador ┆ yellow    ┆ 002    │\n",
       "│ dog/labrador_chocolate_003.jpg ┆ labrador ┆ chocolate ┆ 003    │\n",
       "│ dog/beagle_tricolor_004.jpg    ┆ beagle   ┆ tricolor  ┆ 004    │\n",
       "│ dog/beagle_brown_005.jpg       ┆ beagle   ┆ brown     ┆ 005    │\n",
       "│ …                              ┆ …        ┆ …         ┆ …      │\n",
       "│ bird/crow_black_096.jpg        ┆ crow     ┆ black     ┆ 096    │\n",
       "│ dog/labrador_black_097.jpg     ┆ labrador ┆ black     ┆ 097    │\n",
       "│ dog/labrador_yellow_098.jpg    ┆ labrador ┆ yellow    ┆ 098    │\n",
       "│ dog/labrador_chocolate_099.jpg ┆ labrador ┆ chocolate ┆ 099    │\n",
       "│ dog/beagle_tricolor_100.jpg    ┆ beagle   ┆ tricolor  ┆ 100    │\n",
       "└────────────────────────────────┴──────────┴───────────┴────────┘"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.add_filename_features(path_col=\"path\", sep=\"_\", token_names=[\"breed\", \"color\", \"number\"], inplace=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8984787c",
   "metadata": {},
   "source": [
    "##### Split by breed while preserving distribution"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "70351b88",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m2025-09-13 17:25:28.359\u001b[0m | \u001b[33m\u001b[1mWARNING \u001b[0m | \u001b[36mfiloma.ml\u001b[0m:\u001b[36msplit_data\u001b[0m:\u001b[36m460\u001b[0m - \u001b[33m\u001b[1mfiloma.ml.split_data: unique feature values differ across splits for '_feat_group' - counts train=8, val=3, test=1; examples missing_in_train=['poodle', 'labrador', 'beagle', 'bulldog'], missing_in_val=['crow', 'siamese', 'poodle', 'ragdoll', 'parrot'], missing_in_test=['crow', 'siamese', 'labrador', 'ragdoll', 'bulldog']\u001b[0m\n",
      "\u001b[32m2025-09-13 17:25:28.359\u001b[0m | \u001b[33m\u001b[1mWARNING \u001b[0m | \u001b[36mfiloma.ml\u001b[0m:\u001b[36m_maybe_log_ratio_drift\u001b[0m:\u001b[36m329\u001b[0m - \u001b[33m\u001b[1mfiloma.ml.split_data: achieved counts 60.0%,32.0%,8.0% ((60, 32, 8)) vs requested (70.0%,20.0%,10.0%) total=100 (grouped hashing can cause drift)\u001b[0m\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Shapes of train, val, test: (60, 5), (32, 5), (8, 5)\n"
     ]
    }
   ],
   "source": [
    "train, val, test = df.split_data(seed=42, train_val_test=(70, 20, 10), feature=\"breed\")\n",
    "print(f\"Shapes of train, val, test: {train.shape}, {val.shape}, {test.shape}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "92d29d3d",
   "metadata": {},
   "source": [
    "Note that `filoma` warns you of two things:  \n",
    "1. It found that some categories have very few samples, which led to splits that do not have all categories represented.\n",
    "2. It tried to preserve the distribution of your selected column(s) across the splits, but it couldn't do it perfectly because some categories had very few samples."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "96178b12",
   "metadata": {
    "vscode": {
     "languageId": "markdown"
    }
   },
   "source": [
    "## ✅ Conclusion\n",
    "\n",
    "So this is how you can use `filoma` to go from a scary dataset directory tree to a clean DataFrame with enriched metadata and ML-ready splits, all with just a few lines of code!"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "filoma (3.11.11)",
   "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.11.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
