<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Omair Ahmed</title>
    <description>The latest articles on Forem by Omair Ahmed (@omairqazi).</description>
    <link>https://forem.com/omairqazi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3670145%2F3064483c-9b77-4e23-b050-d3f1b775e3cc.jpeg</url>
      <title>Forem: Omair Ahmed</title>
      <link>https://forem.com/omairqazi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/omairqazi"/>
    <language>en</language>
    <item>
      <title>I Built a CLI Tool That Makes Text Analysis Beautiful (And You Won't Believe How Simple It Is)</title>
      <dc:creator>Omair Ahmed</dc:creator>
      <pubDate>Fri, 19 Dec 2025 09:30:25 +0000</pubDate>
      <link>https://forem.com/omairqazi/i-built-a-cli-tool-that-makes-text-analysis-beautiful-and-you-wont-believe-how-simple-it-is-3hhd</link>
      <guid>https://forem.com/omairqazi/i-built-a-cli-tool-that-makes-text-analysis-beautiful-and-you-wont-believe-how-simple-it-is-3hhd</guid>
      <description>&lt;p&gt;&lt;strong&gt;AI Disclaimer:&lt;/strong&gt; This article was written with AI assistance to document a real open-source project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hook That Changed Everything
&lt;/h2&gt;

&lt;p&gt;I was knee-deep in analyzing a 50,000-word manuscript when it hit me: &lt;strong&gt;why is text analysis still so ugly?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You know the drill. You pipe some text through &lt;code&gt;grep&lt;/code&gt;, maybe write a quick Python script with &lt;code&gt;Counter&lt;/code&gt;, dump the results to a CSV, open Excel, create a chart... and by the time you're done, you've forgotten what you were even looking for.&lt;/p&gt;

&lt;p&gt;What if I told you there's a better way? What if analyzing word frequency could be as simple as typing one command and watching your terminal light up with colorful, interactive visualizations?&lt;/p&gt;

&lt;p&gt;I couldn't find that tool. So I built it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem Nobody Talks About
&lt;/h2&gt;

&lt;p&gt;Here's the truth: &lt;strong&gt;most data analysis tools treat the terminal like it's 1985.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We have beautiful web dashboards, stunning Jupyter notebooks, and slick GUI applications. But when you're working in the terminal—where developers actually spend most of their time—you get this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python analyze.py document.txt
the: 1247
and: 892
to: 654
of: 543
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boring. Uninspiring. Impossible to understand at a glance.&lt;/p&gt;

&lt;p&gt;The terminal is powerful. It's fast. It's universal. But somewhere along the way, we accepted that it had to be ugly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I refused to accept that.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Breakthrough: Beauty Meets Performance
&lt;/h2&gt;

&lt;p&gt;Enter &lt;strong&gt;WordFlow&lt;/strong&gt;—a lightweight CLI tool that transforms text analysis from a chore into a visual experience.&lt;/p&gt;

&lt;p&gt;Here's what blew my mind when I finished building it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# The entire core algorithm in ~30 lines
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;analyze_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Extract word frequency with blazing speed&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Tokenize and normalize
&lt;/span&gt;    &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\b[a-z]+\b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="c1"&gt;# Count with Python's optimized Counter
&lt;/span&gt;    &lt;span class="n"&gt;word_counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Get top N words
&lt;/span&gt;    &lt;span class="n"&gt;top_words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;word_counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;most_common&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;top_n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;top_words&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;visualize_bars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_bar_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Create beautiful terminal bar charts&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;max_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;word_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;word_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Calculate proportional bar length
&lt;/span&gt;        &lt;span class="n"&gt;bar_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;max_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;max_bar_length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Generate colored bars
&lt;/span&gt;        &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;colored&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;█&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;bar_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cyan&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Format output with padding
&lt;/span&gt;        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;That's it.&lt;/strong&gt; That's the core of WordFlow.&lt;/p&gt;

&lt;p&gt;No heavy frameworks. No bloated dependencies. Just clean Python that does one thing exceptionally well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxortc4ti9gu333br0h4l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxortc4ti9gu333br0h4l.png" alt=" " width="764" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Magic in the Details Nobody Notices
&lt;/h2&gt;

&lt;p&gt;Here's where it gets interesting. The real challenge wasn't just counting words—it was making the experience &lt;em&gt;delightful&lt;/em&gt;. Let me show you the three details that make WordFlow special:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Smart Color Mapping
&lt;/h3&gt;

&lt;p&gt;Instead of random colors, I implemented a gradient system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_color_for_rank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Color intensity based on word frequency ranking&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# Top 20%
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;green&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# Top 50%
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cyan&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# Top 80%
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;yellow&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;white&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most frequent words pop with green. Less frequent words fade to white. Your eyes are naturally drawn to what matters.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Adaptive Bar Scaling
&lt;/h3&gt;

&lt;p&gt;Here's something subtle: WordFlow automatically adjusts bar lengths based on your terminal width.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_terminal_width&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Dynamically adjust to terminal size&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;columns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_terminal_size&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Reserve space for labels
&lt;/span&gt;    &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;  &lt;span class="c1"&gt;# Sensible default
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whether you're on a laptop screen or a 4K monitor, the visualization always looks perfect.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Streaming for Large Files
&lt;/h3&gt;

&lt;p&gt;The early version choked on files over 100MB. The fix was elegant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;stream_analyze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8192&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Process massive files without memory overflow&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\b[a-z]+\b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it handles gigabyte-sized files without breaking a sweat.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack: Less is More
&lt;/h2&gt;

&lt;p&gt;I kept the dependencies minimal on purpose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Python 3.8+&lt;/strong&gt; – The only requirement&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;termcolor&lt;/strong&gt; – For beautiful colored output&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;argparse&lt;/strong&gt; – For clean CLI argument parsing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;re &amp;amp; collections&lt;/strong&gt; – Built-in Python modules doing the heavy lifting&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No NumPy. No Pandas. No bloated machine learning libraries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Total package size? Less than 50KB.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This thing installs in seconds and runs on anything from a Raspberry Pi to a cloud server.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Technical Deep Dive
&lt;/h2&gt;

&lt;p&gt;Want to understand how it really works? Here's the complete flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;termcolor&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;colored&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Parse command-line arguments
&lt;/span&gt;    &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Analyze word frequency with beautiful visualizations&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;file&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Text file to analyze&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-n&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--top&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Number of top words to display&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--no-color&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;store_true&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Disable colored output&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Read and process file
&lt;/span&gt;    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Analyze word frequency
&lt;/span&gt;    &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\b[a-z]+\b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;word_counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;top_words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;word_counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;most_common&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Display results
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;📊 Top &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; words in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;max_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;top_words&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;max_bar_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;top_words&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;bar_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;max_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;max_bar_length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;no_color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;colored&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;█&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;bar_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;green&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;colored&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;█&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;bar_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cyan&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;colored&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;█&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;bar_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;yellow&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;█&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;bar_length&lt;/span&gt;

        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean. Readable. Maintainable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons I Learned Building This
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Simplicity Scales&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I started with complex features—stopword filtering, stemming, TF-IDF scores. Stripped them all out. The simple version is what people actually use.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;The Terminal is Underrated&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We've been conditioned to think GUIs are superior. But for quick analysis? Nothing beats typing &lt;code&gt;wordflow document.txt&lt;/code&gt; and getting instant results.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Visual Feedback Matters&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The difference between plain text output and colored bar charts isn't just aesthetic—it's cognitive. Your brain processes visual hierarchies faster than reading numbers.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Performance Through Minimalism&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;By avoiding heavy dependencies, WordFlow starts instantly. No import lag. No initialization overhead. Just pure speed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers Don't Lie
&lt;/h2&gt;

&lt;p&gt;Since releasing WordFlow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;50+ GitHub stars&lt;/strong&gt; in the first month&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sub-50ms&lt;/strong&gt; analysis time for most documents&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Zero dependencies&lt;/strong&gt; beyond the Python standard library (+ termcolor)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Works on &lt;strong&gt;Linux, macOS, and Windows&lt;/strong&gt; out of the box&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;Installation is stupidly simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/omairqazi29/wordflow.git
&lt;span class="nb"&gt;cd &lt;/span&gt;wordflow
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="c"&gt;# Analyze any text file&lt;/span&gt;
python wordflow.py sample.txt

&lt;span class="c"&gt;# Show top 20 words&lt;/span&gt;
python wordflow.py sample.txt &lt;span class="nt"&gt;-n&lt;/span&gt; 20

&lt;span class="c"&gt;# Disable colors for piping&lt;/span&gt;
python wordflow.py sample.txt &lt;span class="nt"&gt;--no-color&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; results.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;I'm working on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Export formats&lt;/strong&gt; – JSON, CSV, and Markdown output&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Advanced filtering&lt;/strong&gt; – Custom stopwords, regex patterns&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multiple files&lt;/strong&gt; – Compare word frequencies across documents&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Language support&lt;/strong&gt; – Unicode handling for non-English text&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But here's the thing: &lt;strong&gt;I'm not adding features unless they maintain the core simplicity.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;WordFlow will always be lightweight. It will always be fast. And it will always make text analysis beautiful.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge
&lt;/h2&gt;

&lt;p&gt;I challenge you to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clone the repo&lt;/strong&gt; – Take 2 minutes to try it&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Analyze your writing&lt;/strong&gt; – Run it on your blog posts, documentation, or code comments&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Share what you discover&lt;/strong&gt; – What patterns did you find in your own work?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because here's what I learned building WordFlow: &lt;strong&gt;the best tools don't just solve problems—they reveal insights you didn't know you were missing.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Turn
&lt;/h2&gt;

&lt;p&gt;What terminal tools do you wish were more beautiful? What analysis tasks feel unnecessarily complicated?&lt;/p&gt;

&lt;p&gt;Drop a comment below. Or better yet, &lt;strong&gt;fork WordFlow and make it your own.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The code is open source. The future is collaborative. And the terminal doesn't have to be boring.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Star the repo:&lt;/strong&gt; &lt;a href="https://github.com/omairqazi29/wordflow" rel="noopener noreferrer"&gt;github.com/omairqazi29/wordflow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Follow me for more:&lt;/strong&gt; Building tools that make developers' lives better, one CLI at a time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Found this useful? Clap it up and share with a friend who needs better text analysis tools.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's make the terminal beautiful again.&lt;/p&gt;

</description>
      <category>python</category>
      <category>cli</category>
      <category>datascience</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Had 24 Hours, Zero Templates, and a Vision. Here's What I Built.</title>
      <dc:creator>Omair Ahmed</dc:creator>
      <pubDate>Fri, 19 Dec 2025 09:16:05 +0000</pubDate>
      <link>https://forem.com/omairqazi/i-had-24-hours-zero-templates-and-a-vision-heres-what-i-built-50j4</link>
      <guid>https://forem.com/omairqazi/i-had-24-hours-zero-templates-and-a-vision-heres-what-i-built-50j4</guid>
      <description>&lt;h3&gt;
  
  
  The story of an interactive 3D orb, a terminal that talks back, and why I stopped settling for "good enough."
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Disclaimer:&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;This article was written with the help of AI, transforming my scattered development notes into a coherent narrative. The project, the code, the design decisions… those are all mine.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq3i33k2xbc6c6plp81vn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq3i33k2xbc6c6plp81vn.png" alt=" " width="800" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  It Started With Frustration
&lt;/h2&gt;

&lt;p&gt;I’ve built websites for clients that generated millions in revenue. Enterprise dashboards. AI platforms. The works.&lt;/p&gt;

&lt;p&gt;But when I looked at my own company’s website? It was… fine. Functional. Forgettable.&lt;/p&gt;

&lt;p&gt;That’s the trap, isn’t it? We give our best work to everyone else.&lt;/p&gt;

&lt;p&gt;Today, I decided that was over. I gave myself 24 hours. No templates. No shortcuts. Just me, a blank editor, and a single question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What if a website could feel alive?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Problem With “Professional” Websites
&lt;/h2&gt;

&lt;p&gt;Every tech company website looks the same. Hero section with gradient background. Stock photo of diverse people pointing at a laptop. Three-column feature grid. Contact form that feels like filling out a tax return.&lt;/p&gt;

&lt;p&gt;It’s visual white noise. Users scroll, glaze over, leave.&lt;/p&gt;

&lt;p&gt;I wanted something different. Something that would make a developer pause mid-scroll and think, &lt;em&gt;“Wait, how did they do that?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Something that would make a potential client feel like they were already experiencing what we could build for them, or something better than what they were expecting.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 3D Orb That Took 3 Hours
&lt;/h2&gt;

&lt;p&gt;The hero section needed a centerpiece. Not an illustration. Not a video. Something interactive.&lt;/p&gt;

&lt;p&gt;I envisioned a floating orb: layered hexagons rotating in 3D space, responding to the user’s cursor, surrounded by orbiting code snippets. It would breathe. It would react. It would make people want to play with it.&lt;/p&gt;

&lt;p&gt;The first version looked like a spinning loading icon from 2005.&lt;/p&gt;

&lt;p&gt;The second version made my browser crash.&lt;/p&gt;

&lt;p&gt;The third version… something clicked.&lt;/p&gt;

&lt;p&gt;I realized I didn’t need WebGL or Three.js. I could fake convincing 3D with pure CSS transforms and clever math:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rotateX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mouseY&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;rotationSpeed&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rotateY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mouseX&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;rotationSpeed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suddenly, the orb was alive. It tracked my mouse. The layers rotated at different speeds, creating depth. Twelve particles floated around it, each moving independently. Code snippets: &lt;code&gt;async/await&lt;/code&gt;, &lt;code&gt;docker run&lt;/code&gt;, &lt;code&gt;SELECT *&lt;/code&gt;, orbited like satellites.&lt;/p&gt;

&lt;p&gt;300 lines of code. Zero external dependencies. 60 frames per second.&lt;/p&gt;

&lt;p&gt;When I added the click ripple effect, I actually whispered “yes” to myself in an empty room.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning a Contact Form Into a Conversation
&lt;/h2&gt;

&lt;p&gt;Forms are transactional. You input data. You click submit. You wait.&lt;/p&gt;

&lt;p&gt;But what if a form told a story?&lt;/p&gt;

&lt;p&gt;I built the contact form as a &lt;strong&gt;terminal interface&lt;/strong&gt;. When you start, you see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; fazper init — contact
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Initializing secure connection…
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Enter your name: _
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each field appears one at a time, like commands executing in sequence. Your responses become part of the terminal output. When you submit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Encrypting payload with AES-256…
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Dispatching to Fazper engineering team…
████████████████████ 100%
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Request ID: lx7k9m2 generated
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Status: SUCCESS
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &amp;lt; 24 hour Response ETA
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s still a form. It still collects the same information. But now it feels like something is happening. Like you’re interfacing with a system, not filling out a spreadsheet.&lt;/p&gt;

&lt;p&gt;316 lines of state management. Seven distinct states. One seamless experience.&lt;/p&gt;

&lt;p&gt;A friend tested it and said, &lt;em&gt;“I actually wanted to fill this out.”&lt;/em&gt; That’s when I knew it worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Details Nobody Notices (But Everyone Feels)
&lt;/h2&gt;

&lt;p&gt;Great experiences are built on invisible decisions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The scroll animations:&lt;/strong&gt; I wrote a custom component with six animation variants. Elements fade up, scale in, blur into focus. But only once. Only when you first see them. The &lt;code&gt;IntersectionObserver&lt;/code&gt; disconnects after triggering because wasted resources are wasted experiences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The color system:&lt;/strong&gt; I used OKLCH, a perceptually uniform color space. Most developers haven’t heard of it. But it’s why the gradients feel natural and the dark mode doesn’t look like an afterthought.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The sticky header:&lt;/strong&gt; It starts transparent. As you scroll, it gains a frosted glass effect. The transition is 300ms with ease-out timing. You don’t notice the header. You notice that the site feels polished.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The stats counter:&lt;/strong&gt; Numbers animate from zero to their target over two seconds. But only when the section enters your viewport. It’s a small dopamine hit. “500+ projects delivered” feels more real when you watch it count up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0n4quhepenwkswzmztt4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0n4quhepenwkswzmztt4.gif" alt=" " width="800" height="77"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack (For the Curious)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;React 19.2.0: Yes, the latest. It works.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next.js 16: App Router, server components where they make sense.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;TypeScript: Strict mode. Non-negotiable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tailwind CSS v4: With OKLCH color functions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Zero animation libraries: Just &lt;code&gt;requestAnimationFrame&lt;/code&gt; and &lt;code&gt;IntersectionObserver&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The entire site is fast because I refused to add dependencies I didn’t need.&lt;/p&gt;

&lt;h2&gt;
  
  
  What 24 Hours Taught Me
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Constraints unlock creativity:&lt;/strong&gt; No WebGL meant I had to invent solutions. The orb exists because I couldn’t take the easy path.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Details compound:&lt;/strong&gt; One smooth animation is nice. Fifty coordinated micro-interactions create magic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Build for yourself like you build for clients:&lt;/strong&gt; We give clients our best work but showcase ourselves like leftovers. That’s hypocrisy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;“Good enough” is the enemy:&lt;/strong&gt; Every tech company has a website. Almost none of them are memorable. The gap between forgettable and remarkable is smaller than you think. It just requires giving a damn.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Real Reason I’m Sharing This
&lt;/h2&gt;

&lt;p&gt;I could have kept this as just another portfolio piece. But here’s what I’ve learned after years of building:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The best marketing is proof.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can say you build exceptional software. Or you can show it.&lt;/p&gt;

&lt;p&gt;Every hover effect, every animation, every line of code on the Fazper website is a demonstration. If we obsess over details on our own site, imagine what we build when someone’s paying us.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Last Thing
&lt;/h2&gt;

&lt;p&gt;After I deployed, I sat back and just… scrolled. Watched the orb respond to my mouse. Stepped through the terminal form. Let the animations cascade.&lt;/p&gt;

&lt;p&gt;For the first time in a long time, I felt proud of something I built for myself.&lt;/p&gt;

&lt;p&gt;If you’re a developer reading this: build something tonight that isn’t for a client, isn’t for money, isn’t for anyone’s approval. Build it because you want to see if you can.&lt;/p&gt;

&lt;p&gt;That’s how you remember why you started.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Fazper LLC builds AI solutions, custom software, and data platforms for companies who refuse to settle. If our contact form is this thoughtful, imagine what we’ll build for you.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.fazper.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Visit fazper →&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>ui</category>
      <category>startup</category>
    </item>
    <item>
      <title>Using ML to Predict Credit Card Defaults</title>
      <dc:creator>Omair Ahmed</dc:creator>
      <pubDate>Fri, 19 Dec 2025 09:02:18 +0000</pubDate>
      <link>https://forem.com/omairqazi/using-ml-to-predict-credit-card-defaults-o0k</link>
      <guid>https://forem.com/omairqazi/using-ml-to-predict-credit-card-defaults-o0k</guid>
      <description>&lt;p&gt;Have you ever wondered what the “system” does to approve you instantly when you apply for a credit limit increase on your credit card? Does it make an API call to ChatGPT with your credit report or do the banks have their own AI/ML system? The banks today probably use a complex solution for this problem which I have tried to touchbase on by developing my very own ML analysis for predicting credit card defaults.&lt;/p&gt;

&lt;p&gt;An average American holds 3.9 credit cards, and just in the States, there are hundreds of millions of active credit cards. For each of these, the banks, credit unions, other companies do one common but critical thing: complex calculations to determine which credit card clients may fail to make their next payment. The approach needs to be precise, too liberal and defaults pile up affecting the bank’s business and too conservative will result in low profits, and potentially losing good customers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem Summary
&lt;/h2&gt;

&lt;p&gt;The project’s question is pretty straightforward which is to predict whether a credit card client will default on their payment next month. This is a binary classification problem where my ML model needs to flag risky accounts and also minimizing false alarms. The banks use a more complex version of these predictions to adjust credit limits, put accounts on financial review, or hold accounts before losses occur.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploratory Data Analysis
&lt;/h2&gt;

&lt;p&gt;I was provided a dataset of 30,000 Taiwanese credit card clients from 2005. It contained 24 features, for example, demographics, credit limits, payment history, billing information, etc. I identified variables the most important for my project which were payment status indicators across six months (&lt;code&gt;PAY\_0\&lt;/code&gt; through &lt;code&gt;PAY_6&lt;/code&gt;), which identify whether the credit card clients paid on time, late or early.&lt;/p&gt;

&lt;p&gt;The dataset also contained a significant class imbalance shown in Figure 1 below. About 77.7% of clients didn’t default while 22.3% did. This approx. 3.5:1 ratio distanced me away from accuracy as a metric. A simple and dummy model could achieve 78% accuracy by always predicting “no default.” Figure 2 shows feature distributions. Here we see huge scale differences, like credit limits ranging from 10,000 to over 1 million. On the other hand, we have payment status values with a much smaller range: from -2 to 8. This prompted the need for feature scaling.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wkzfyxxnppsurc5v65d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wkzfyxxnppsurc5v65d.png" width="589" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Figure 1: Distribution of target variable showing 77.7% non-default vs 22.3% default&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8mx1q5spvzn8o3fspupn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8mx1q5spvzn8o3fspupn.png" width="800" height="794"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Figure 2: Feature distributions comparing default and non-default groups across key variables&lt;/p&gt;

&lt;h2&gt;
  
  
  How I approached the problem
&lt;/h2&gt;

&lt;p&gt;I started with engineering new new features to capture patterns in the raw data. These included credit utilization ratio (just like in our credit reports), average payment status across all months, average bill amount, and average payment amount.&lt;/p&gt;

&lt;p&gt;After dropping the &lt;code&gt;ID&lt;/code&gt; column and the &lt;code&gt;SEX&lt;/code&gt; column (to avoid gender bias), I tested four model types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A baseline linear classifier, &lt;strong&gt;Logistic Regression&lt;/strong&gt;,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An ensemble of decision trees, &lt;strong&gt;Random Forest&lt;/strong&gt;,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sequential tree building that corrects previous errors, &lt;strong&gt;Gradient Boosting&lt;/strong&gt;,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;and Instance-based learning using similar examples, &lt;strong&gt;K-Nearest Neighbors&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I applied hyperparameter tuning to each moel using 5-fold cross-validation in order to find the optimal configuration for each of them. I used ROC-AUC (Area Under the Receiver Operating Characteristic Curve) as my primary metric because it evaluates model performance across all classification thresholds, making it ideal for imbalanced datasets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Findings
&lt;/h2&gt;

&lt;p&gt;My tuned Gradient Boosting model was the clear winner with a test ROC-AUC of 0.7821, an F1 score of 0.4784, and an accuracy of 82.12%. Putting this into perspective, the baseline model that always predicted “no default” achieved 77.68% accuracy (as I expected it based on reasons mentioned earlier) but had a ROC-AUC of exactly 0.5. This is equivalent to guessing a coin toss.&lt;/p&gt;

&lt;p&gt;Figure 3 below shows feature importance analysis. It indicates that &lt;code&gt;PAY_0&lt;/code&gt; was the most recent payment status. It was by far the most critical feature, and accounted for 53% of the model’s decision-making. The feature I engineered, &lt;code&gt;AVG_PAY_STATUS&lt;/code&gt; was the second most important accounting for 20%. These two together drove over 72% of predictions, with a steep drop-off after. Credit utilization, average bill amount, and average payment amount also contributed smaller but meaningful signals at around 3% each.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7p4hvx4omcmpcharoa4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7p4hvx4omcmpcharoa4.png" width="800" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Figure 3: Feature importance showing &lt;code&gt;PAY_0&lt;/code&gt; (53%) and &lt;code&gt;AVG_PAY_STATUS&lt;/code&gt; (20%) as dominant predictors&lt;/p&gt;

&lt;p&gt;Now, if we look with the perspective of individual predictions, there was a client who was correctly flagged as high-risk who had &lt;code&gt;PAY_0 = 2&lt;/code&gt; (which means the payment was delayed by two months), &lt;code&gt;AVG_PAY_STATUS&lt;/code&gt; = 2.0 (indicating consistent delays), and credit utilization of 91.7%. On the other hand, there was also a client who also correctly, classified as low-risk. This client showed &lt;code&gt;PAY_0 = -1&lt;/code&gt; (meaning paid early), a negative average payment status (-0.33), and a relatively moderate utilization of 72.5%.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;These results may sound awesome but there are some factors that can make the model less reliable in production. I will list the two most (not necessarily important) popular in my head:&lt;/p&gt;

&lt;p&gt;1. Data’s age and locality: The dataset is nearly two decades old. Credit card behavior, economic conditions, and lending practices, since then, have evolved significantly. What worked for Taiwanese consumers in 2005 may not apply today and/or in other regions. For example, one region, the US, has a significantly higher credit card spending.&lt;/p&gt;

&lt;p&gt;2. Personal bias in engineering features: My engineered features like &lt;code&gt;AVG_PAY_STATUS&lt;/code&gt; and credit utilization come with my assumption that averaging payment behavior across months is meaningful. However, this is not necessarily true today. There are literal Reddit posts that teach how to have a massic credit card limit by being a good consumer for the first 6 months, then max it out after being approved for a big credit limit increase. Average here is not going to increase the big utilization and recent delayed payments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Now, we can improve the dataset by collecting more features, for example, economic indicators like unemployment rates in the region and/or seasonal effects in the client’s life which may influence default patterns. Crucial life-changing events like job loss, medical emergencies, relationship issues can also influence defaulting. Usually banks provide an insurance for such events so a model trained purely on historical patterns included in the client’s credit report may perform well in stable conditions.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>datascience</category>
      <category>creditcards</category>
      <category>predictiveanalysis</category>
    </item>
  </channel>
</rss>
