<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://ameen-cet.github.io/ameenudeen/feed.xml" rel="self" type="application/atom+xml"/><link href="https://ameen-cet.github.io/ameenudeen/" rel="alternate" type="text/html" hreflang="en"/><updated>2026-08-19T11:30:54+00:00</updated><id>https://ameen-cet.github.io/ameenudeen/feed.xml</id><title type="html">blank</title><subtitle>A simple, whitespace theme for academics. Based on [*folio](https://github.com/bogoli/-folio) design. </subtitle><entry><title type="html">Simpson’s Paradox: When the Same Data Tells Two Different Stories</title><link href="https://ameen-cet.github.io/ameenudeen/blog/2026/simpsons-paradox/" rel="alternate" type="text/html" title="Simpson’s Paradox: When the Same Data Tells Two Different Stories"/><published>2026-07-12T12:00:00+00:00</published><updated>2026-07-12T12:00:00+00:00</updated><id>https://ameen-cet.github.io/ameenudeen/blog/2026/simpsons-paradox</id><content type="html" xml:base="https://ameen-cet.github.io/ameenudeen/blog/2026/simpsons-paradox/"><![CDATA[<blockquote> <p>“Sometimes the numbers are correct, but the conclusion is wrong.”</p> </blockquote> <p>This article is inspired by the philosophy of explanation in Michael Nielsen’s essay, <a href="https://michaelnielsen.org/reinventing_explanation/"><em>Reinventing Explanation</em></a>, on building intuition rather than merely presenting facts. So instead of jumping straight to the definition, let’s start by feeling why Simpson’s Paradox is surprising — and only then explain it.</p> <h2 id="have-you-ever-seen-this-happen">Have you ever seen this happen?</h2> <figure> <picture> <source class="responsive-img-srcset" srcset="/ameenudeen/assets/img/simpsons-paradox-classroom-480.webp 480w,/ameenudeen/assets/img/simpsons-paradox-classroom-800.webp 800w,/ameenudeen/assets/img/simpsons-paradox-classroom-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/ameenudeen/assets/img/simpsons-paradox-classroom.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> <div class="caption"> College students appearing for a competitive examination, all preparing for the same kind of exam. </div> <p>Imagine two coaching institutes preparing students for the GATE examination.</p> <p>The newspaper reports the overall pass percentage:</p> <table> <thead> <tr> <th>Institute</th> <th>Overall pass %</th> </tr> </thead> <tbody> <tr> <td>Institute A</td> <td>76%</td> </tr> <tr> <td>Institute B</td> <td>70%</td> </tr> </tbody> </table> <p>Most people would immediately say, “Institute A is clearly better.”</p> <p>Now suppose someone shows another table — this time splitting students by category:</p> <table> <thead> <tr> <th>Student category</th> <th>Institute A</th> <th>Institute B</th> </tr> </thead> <tbody> <tr> <td>Students with a strong academic background</td> <td>95%</td> <td>98%</td> </tr> <tr> <td>Students needing extra support</td> <td>50%</td> <td>55%</td> </tr> </tbody> </table> <p>Now things get confusing. Institute B performs <em>better</em> in both categories. Yet when all students are combined, Institute A still has the higher overall pass percentage.</p> <p>How can that be? Did someone make a mistake? Did the newspaper calculate the percentages wrongly? Can both tables be correct at the same time?</p> <p>Take a minute before reading further.</p> <p>Most people — including many professors the first time they see it — feel that this should be impossible. But it isn’t. This is called <strong>Simpson’s Paradox</strong>.</p> <h2 id="the-surprise">The surprise</h2> <p>Simpson’s Paradox is one of those ideas that changes how you look at data forever. It teaches a simple lesson:</p> <p>The overall average does not always tell the real story. Sometimes the data inside different groups tells one story. When those groups are merged together, the story changes completely.</p> <p>The mathematics is perfectly correct. Our intuition is what fails.</p> <h2 id="why-does-this-happen">Why does this happen?</h2> <p>Imagine there are only two kinds of students: those who are already very strong, and those who need more help.</p> <p>Now suppose Institute A admits mostly strong students, while Institute B admits many more weaker students. Even if Institute B teaches both groups slightly better, its overall result can still come out lower — because a much larger fraction of its students started out at a disadvantage.</p> <p>Think of cricket. Suppose two batsmen play on different pitches — one mostly bats on flat, easy batting tracks, the other usually bats on difficult green pitches. Simply comparing their overall batting averages may not tell you who actually bats better under similar conditions. The mix of situations matters. That hidden mix is what creates Simpson’s Paradox.</p> <h2 id="a-simple-visual-way-to-think-about-it">A simple visual way to think about it</h2> <p>Imagine two baskets of mangoes. Basket A contains mostly ripe mangoes. Basket B contains mostly unripe mangoes.</p> <p>Now compare two farmers. Farmer B actually grows slightly better mangoes than Farmer A — in <em>both</em> baskets. But Farmer B happened to send many more unripe mangoes to the market. Overall, Farmer A’s mangoes may appear better.</p> <p>The problem isn’t the quality. The problem is that we mixed together two very different groups.</p> <h2 id="example-from-an-indian-college">Example from an Indian college</h2> <figure> <picture> <source class="responsive-img-srcset" srcset="/ameenudeen/assets/img/simpsons-paradox-programming-lab-480.webp 480w,/ameenudeen/assets/img/simpsons-paradox-programming-lab-800.webp 800w,/ameenudeen/assets/img/simpsons-paradox-programming-lab-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/ameenudeen/assets/img/simpsons-paradox-programming-lab.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> <div class="caption"> A programming lab — exactly the kind of class in this example. </div> <p>Suppose two teachers teach Programming. Teacher A teaches one section, Teacher B teaches another. The final university results are:</p> <table> <thead> <tr> <th>Teacher</th> <th>Overall pass rate</th> </tr> </thead> <tbody> <tr> <td>Teacher A</td> <td>82%</td> </tr> <tr> <td>Teacher B</td> <td>78%</td> </tr> </tbody> </table> <p>So everyone says, “Teacher A is better.”</p> <p>Now the principal separates students based on their Class 12 mathematics marks:</p> <p><strong>Students with strong mathematics</strong></p> <table> <thead> <tr> <th>Teacher</th> <th>Pass rate</th> </tr> </thead> <tbody> <tr> <td>A</td> <td>92%</td> </tr> <tr> <td>B</td> <td>95%</td> </tr> </tbody> </table> <p><strong>Students with weaker mathematics</strong></p> <table> <thead> <tr> <th>Teacher</th> <th>Pass rate</th> </tr> </thead> <tbody> <tr> <td>A</td> <td>60%</td> </tr> <tr> <td>B</td> <td>65%</td> </tr> </tbody> </table> <p>Teacher B performs better in <em>both</em> groups. So why is Teacher A’s overall result higher? Because Teacher A happened to receive many more students who already had strong mathematics backgrounds, while Teacher B had a much larger number of weaker students. The overall percentage is therefore influenced by who entered the class — not only by how well they were taught.</p> <h2 id="another-everyday-example">Another everyday example</h2> <p>Suppose two hospitals perform surgeries. Hospital A mostly receives patients with minor health problems. Hospital B receives many complicated emergency cases.</p> <p>Even if Hospital B performs better for both easy and difficult surgeries separately, its overall success rate could still look lower — simply because it treats far more difficult cases. Without knowing the type of patients each hospital receives, comparing only the overall success rate would be misleading.</p> <h2 id="what-is-really-happening">What is really happening?</h2> <p>A hidden variable changes everything. In our examples, the hidden variable was: academic background, patient condition, exam difficulty, starting ability.</p> <p>When we ignore these factors and simply average everything together, we may reach the wrong conclusion. Statisticians call these hidden influences <strong>confounding variables</strong>. You don’t need to remember the term — just remember the idea:</p> <p>Always ask whether different kinds of data have been mixed together.</p> <h2 id="does-this-mean-averages-are-bad">Does this mean averages are bad?</h2> <p>Not at all. Averages are useful. But averages answer only one question — they do not explain <em>why</em> the average looks the way it does.</p> <p>Whenever you see an average, ask yourself:</p> <ul> <li>Who is included?</li> <li>Are all people similar?</li> <li>Are different groups being mixed?</li> <li>Would the conclusion change if I looked at each group separately?</li> </ul> <p>These four questions can save you from many wrong conclusions.</p> <h2 id="where-does-simpsons-paradox-appear">Where does Simpson’s Paradox appear?</h2> <p>It appears surprisingly often. Researchers encounter it in medicine, education, economics, sports, machine learning, public policy, and business analytics. Whenever data from different groups is combined, Simpson’s Paradox becomes possible.</p> <h2 id="what-should-you-learn-from-this">What should you learn from this?</h2> <p>After reading this article, here are the ideas to remember.</p> <p><strong>1. Bigger numbers do not always tell the complete story.</strong> An overall percentage can hide important details.</p> <p><strong>2. Always look inside the groups.</strong> If possible, examine the data separately before combining everything.</p> <p><strong>3. Ask what has been mixed together.</strong> Different student backgrounds. Different hospitals. Different departments. Different states. Different years. Mixing different populations can completely change the conclusion.</p> <p><strong>4. Statistics is not only about calculation.</strong> It is also about asking good questions. Sometimes the most important question is not “What is the average?” — instead it is “Average of whom?”</p> <h2 id="a-small-thought-experiment">A small thought experiment</h2> <p>Suppose your college announces: “The placement percentage has increased this year.” Before celebrating, ask:</p> <ul> <li>Did all departments improve?</li> <li>Or did one department become much larger?</li> <li>Did weaker departments shrink?</li> <li>Were more students eligible this year?</li> </ul> <p>The overall number may be true. But the complete story may still be hidden. That is exactly the lesson of Simpson’s Paradox.</p> <h2 id="conclusion">Conclusion</h2> <p>Simpson’s Paradox reminds us that data can be honest while our interpretation is mistaken. It teaches an important habit that every engineer, scientist, economist, and manager should develop: never stop at the overall average. Look inside the data. Understand the groups. Ask what has been combined. Only then can numbers reveal the truth instead of hiding it.</p> <p>As the famous statistician John Tukey once said, “The greatest value of a picture is when it forces us to notice what we never expected to see.” Simpson’s Paradox does exactly that — it forces us to question our first impression and think more carefully about what the data is really saying.</p>]]></content><author><name></name></author><category term="statistics"/><category term="data"/><summary type="html"><![CDATA[An intuitive introduction to Simpson's Paradox — how averages can lie to you without any of the numbers being wrong.]]></summary></entry><entry><title type="html">Visual Information Theory, Part 2: Joint Entropy, Mutual Information, and Stochastic Processes</title><link href="https://ameen-cet.github.io/ameenudeen/blog/2026/visual-information-theory-part-2/" rel="alternate" type="text/html" title="Visual Information Theory, Part 2: Joint Entropy, Mutual Information, and Stochastic Processes"/><published>2026-07-12T00:00:00+00:00</published><updated>2026-07-12T00:00:00+00:00</updated><id>https://ameen-cet.github.io/ameenudeen/blog/2026/visual-information-theory-part-2</id><content type="html" xml:base="https://ameen-cet.github.io/ameenudeen/blog/2026/visual-information-theory-part-2/"><![CDATA[<h2 id="recap">Recap</h2> <p><a href="/ameenudeen/blog/2026/visual-information-theory-part-1/">Part 1</a> built up the vocabulary for a single random variable: the information content \(\log_2 \frac{1}{p(x)}\) of an outcome, entropy \(H(X)\) as its probability-weighted average, redundancy, cross-entropy, and KL divergence. All of it concerned one variable at a time. Most interesting questions, though, involve <em>relationships</em> between variables: how much does today’s weather tell us about tomorrow’s? How much do two random variables share? This post extends entropy to two (or more) variables, following the same two sources as Part 1 — Olah’s essay <d-cite key="olah2015visual"></d-cite> and Pinkard &amp; Waller’s tutorial <d-cite key="pinkard2022visual"></d-cite> — and ends with the entropy rate, which generalizes entropy to sequences that are not independent and identically distributed.</p> <h2 id="joint-entropy">Joint entropy</h2> <p>The simplest extension is to ask how much information is needed to communicate the outcome of <em>two</em> variables together. If we flatten the joint distribution \(p(x,y)\) over the product space \(\mathcal{X} \times \mathcal{Y}\) and treat it as a distribution over a single combined variable, entropy applies unchanged:</p> \[H(X,Y) = \sum_{x \in \mathcal{X}} \sum_{y \in \mathcal{Y}} p(x,y) \log_2 \frac{1}{p(x,y)} \, .\] <p>This is the <strong>joint entropy</strong> — the average number of bits needed to communicate both \(X\) and \(Y\) using a code built for their joint distribution <d-cite key="pinkard2022visual"></d-cite><d-cite key="olah2015visual"></d-cite>. When \(X\) and \(Y\) are independent, \(p(x,y) = p(x)p(y)\), and substituting this in shows \(H(X,Y) = H(X) + H(Y)\): independent information simply adds. When they are dependent, the joint entropy is <em>less</em> than the sum of the individual entropies — some information is shared, and we shouldn’t have to pay for it twice. Quantifying exactly how much is shared is the job of mutual information, below.</p> <h2 id="conditional-entropy">Conditional entropy</h2> <p>Suppose you already know \(Y\). How much <em>more</em> information do you need, on average, to also learn \(X\)? This is the <strong>conditional entropy</strong> \(H(X \mid Y)\): the uncertainty remaining in \(X\) once \(Y\) is known.</p> <p>Start at a single point: if we already know \(Y = y\), the information needed to learn \(X\) is the entropy of the conditional distribution \(p(x \mid y)\),</p> \[H(X \mid y) = \sum_{x \in \mathcal{X}} p(x \mid y) \log_2 \frac{1}{p(x \mid y)} \, .\] <p>Averaging over all possible values of \(y\), weighted by how likely each is, gives the conditional entropy in its usual form:</p> \[H(X \mid Y) = \sum_{y \in \mathcal{Y}} p(y) \sum_{x \in \mathcal{X}} p(x \mid y) \log_2 \frac{1}{p(x \mid y)} = \sum_{x,y} p(x,y) \log_2 \frac{1}{p(x \mid y)} \, .\] <p>A concrete example makes this tangible. Pinkard and Waller consider drawing objects with both a color (\(X\)) and a shape (\(Y\)) at random <d-cite key="pinkard2022visual"></d-cite>. Suppose that, conditioned on the shape being a particular one (say \(\bullet\)), the color is equally likely to be green, yellow, or blue. Then \(H(X \mid Y = \bullet) = \log_2 3 \approx 1.58\) bits: three equally probable outcomes remain even after learning the shape. If instead conditioning on a different shape narrows the color down to a single possibility, the conditional entropy for that value of \(Y\) is exactly zero — no uncertainty is left.</p> <p>Conditional entropy can never exceed the unconditional entropy: \(H(X \mid Y) \le H(X)\), with equality iff \(X\) and \(Y\) are independent. Combined with joint entropy, this gives a clean chain of inequalities,</p> \[H(X,Y) \ge H(X) \ge H(X \mid Y) \ge 0 \, ,\] <p>and an identity that will anchor the next section: \(H(X,Y) = H(Y) + H(X \mid Y)\) — the information in both variables is the information in one, plus whatever’s left in the other after conditioning on it.</p> <h2 id="mutual-information">Mutual information</h2> <p>Joint entropy measures the total information in \(X\) and \(Y\) together; conditional entropy measures what’s left in one after learning the other. The information they have <em>in common</em> — how much observing \(Y\) reduces our uncertainty about \(X\) — is the <strong>mutual information</strong>:</p> \[I(X;Y) = H(X) + H(Y) - H(X,Y) \, .\] <p>The intuition is a counting argument: \(H(X) + H(Y)\) counts the shared information twice (once as part of \(X\), once as part of \(Y\)), while \(H(X,Y)\) counts it once. The difference is exactly one copy of what’s shared <d-cite key="olah2015visual"></d-cite>.</p> <h3 id="pointwise-mutual-information">Pointwise mutual information</h3> <p>Just as entropy has a pointwise predecessor (information content), mutual information has a pointwise version. For a specific pair of outcomes \((x,y)\), the <strong>pointwise mutual information</strong> is</p> \[\log_2 \frac{p(x,y)}{p(x)p(y)} = \log_2\frac{1}{p(x)} - \log_2\frac{1}{p(x\mid y)} \, ,\] <p>the surprise of \(x\) on its own, minus the (typically smaller) surprise of \(x\) once \(y\) is already known <d-cite key="pinkard2022visual"></d-cite>. Averaging this quantity over the joint distribution recovers the usual definition,</p> \[I(X;Y) = \sum_{x \in \mathcal{X}} \sum_{y \in \mathcal{Y}} p(x,y) \log_2 \frac{p(x,y)}{p(x)\,p(y)} \, .\] <p>This expression is worth pausing on, because it is <em>exactly</em> the KL divergence from Part 1 — specifically, the KL divergence between the true joint distribution \(p(x,y)\) and the “naive” product-of-marginals distribution \(p(x)p(y)\) that we’d get by (incorrectly) assuming independence <d-cite key="olah2015visual"></d-cite>. Mutual information is the number of bits you save by understanding the real relationship between \(X\) and \(Y\), instead of assuming they’re independent. Two useful properties follow immediately: mutual information is symmetric, \(I(X;Y) = I(Y;X)\), and it is always non-negative (since KL divergence is), with \(I(X;Y) = 0\) exactly when \(X\) and \(Y\) are independent.</p> <h3 id="how-the-pieces-fit-together">How the pieces fit together</h3> <p>Joint entropy, conditional entropy, and mutual information are not independent concepts — they are different ways of partitioning the same total information, and it helps to see all four quantities laid out together, with area representing bits.</p> <div class="l-body"> <svg viewBox="0 0 520 210" xmlns="http://www.w3.org/2000/svg" style="max-width:100%; height:auto;"> <style>
    .box { stroke: currentColor; stroke-width: 1.5; }
    .lbl { font-family: sans-serif; font-size: 13px; fill: currentColor; text-anchor: middle; }
    .side { font-family: sans-serif; font-size: 12px; fill: currentColor; text-anchor: start; }
  </style> <rect x="20" y="15" width="480" height="34" class="box" fill="#5470C6" fill-opacity="0.12"/> <text x="260" y="36" class="lbl">Joint entropy &#160; H(X,Y) = 3 bits</text> <rect x="20" y="65" width="320" height="34" class="box" fill="#91CC75" fill-opacity="0.18"/> <text x="180" y="86" class="lbl">Entropy &#160; H(X) = 2 bits</text> <rect x="340" y="65" width="160" height="34" class="box" fill="#EE6666" fill-opacity="0.18"/> <text x="420" y="86" class="lbl" font-size="12">H(Y|X) = 1</text> <rect x="20" y="115" width="160" height="34" class="box" fill="#EE6666" fill-opacity="0.18"/> <text x="100" y="136" class="lbl" font-size="12">H(X|Y) = 1</text> <rect x="180" y="115" width="320" height="34" class="box" fill="#91CC75" fill-opacity="0.18"/> <text x="340" y="136" class="lbl">Entropy &#160; H(Y) = 2 bits</text> <rect x="180" y="165" width="160" height="34" class="box" fill="#FAC858" fill-opacity="0.35"/> <text x="260" y="186" class="lbl">I(X;Y) = 1 bit</text> <text x="20" y="209" class="side" font-size="11">Width is proportional to bits, in a worked example with H(X) = H(Y) = 2, I(X;Y) = 1.</text> </svg> </div> <div class="caption"> The relationships between joint entropy, entropy, conditional entropy, and mutual information, for a worked example with H(X) = H(Y) = 2 bits and I(X;Y) = 1 bit. Note how the H(X) bar (row 2) and H(Y) bar (row 3) overlap exactly over the mutual information region. Redrawn after the summary figures in <d-cite key="pinkard2022visual"></d-cite> (Fig. 7) and <d-cite key="olah2015visual"></d-cite>. </div> <p>Reading the diagram: \(H(X,Y) = H(X) + H(Y\mid X) = H(Y) + H(X \mid Y)\), and the mutual information is exactly the amount by which \(H(X)\) and \(H(Y)\) overlap. All three of the following are algebraically equivalent expressions for mutual information, and each has its own reading:</p> \[I(X;Y) = H(X) - H(X\mid Y) = H(Y) - H(Y \mid X) = H(X) + H(Y) - H(X,Y) \, .\] <p>The first says mutual information is how much \(Y\) shrinks our uncertainty about \(X\); the second is the same statement with the roles reversed (consistent with symmetry); the third is the counting argument from before.</p> <h2 id="variation-of-information">Variation of information</h2> <p>If mutual information measures what two variables <em>share</em>, its complement measures what they <em>don’t</em>: the <strong>variation of information</strong>,</p> \[V(X,Y) = H(X,Y) - I(X;Y) \, .\] <p>Variation of information is a genuine metric — symmetric, non-negative, and satisfying the triangle inequality — on the space of jointly distributed variables <d-cite key="olah2015visual"></d-cite>. It is zero exactly when knowing one variable tells you the other completely, and it grows as the variables become more independent. It’s worth contrasting this with KL divergence from Part 1: KL divergence measures distance <em>between two distributions</em> over the same variable(s); variation of information measures distance <em>between two jointly distributed variables</em>, within a single distribution.</p> <h2 id="fractional-bits-revisited">Fractional bits, revisited</h2> <p>Part 1 flagged something odd: optimal codeword lengths are frequently fractional, which seems meaningless for a single message. Consider a distribution with two outcomes, \(a\) (probability 71%) and \(b\) (probability 29%). The ideal codeword lengths are \(\log_2\frac{1}{0.71}\approx 0.49\) bits for \(a\) and \(\log_2\frac{1}{0.29}\approx 1.79\) bits for \(b\) — neither a whole number <d-cite key="olah2015visual"></d-cite>.</p> <p>If we must send a single symbol, we’re forced to round, giving an average length of 1 bit (using codewords <code class="language-plaintext highlighter-rouge">0</code> and <code class="language-plaintext highlighter-rouge">1</code>) rather than the entropy \(H \approx 0.87\) bits. But if we encode <em>two</em> draws jointly, something better happens. The four two-symbol outcomes have probabilities \(p(aa) = 0.504\), \(p(ab) = p(ba) = 0.206\), and \(p(bb) = 0.084\); assigning shorter codewords to the more probable pairs and rounding gives an average of about 1.8 bits for <em>two</em> symbols — 0.9 bits per symbol, already better than sending them independently (2 bits for two symbols) <d-cite key="olah2015visual"></d-cite>. As the number of jointly-encoded symbols \(N \to \infty\), the rounding overhead per symbol vanishes and the achievable rate approaches the entropy exactly. This is a special case of the AEP from Part 1: block-encoding the typical set of a large-\(N\) sequence gets arbitrarily close to the entropy bound.</p> <p>(In practice, Huffman coding — essentially the scheme sketched here — needs this kind of symbol-grouping to approach the entropy limit gracefully; arithmetic coding handles fractional bits natively and is asymptotically optimal without grouping <d-cite key="olah2015visual"></d-cite>.)</p> <h2 id="entropy-rate-of-a-stochastic-process">Entropy rate of a stochastic process</h2> <p>Everything so far has assumed a sequence of <em>independent and identically distributed</em> random variables. Real sequences — text, weather, stock prices — are rarely independent: today’s value constrains tomorrow’s. An ordered sequence of random variables \(\mathbf{X} = X_1, X_2, \ldots\), without an independence assumption, is called a <strong>stochastic process</strong> <d-cite key="pinkard2022visual"></d-cite>.</p> <h3 id="two-equivalent-definitions">Two equivalent definitions</h3> <p>In the i.i.d. case, entropy is additive: \(H(X_1, \ldots, X_N) = N \cdot H(X)\), so the <strong>entropy rate</strong> — entropy per symbol — is just \(H(X)\). For a general stochastic process, we need a definition that doesn’t assume this factorization. There are two natural candidates.</p> <p>The first treats entropy rate as the average uncertainty per draw, over all \(N\) draws jointly:</p> \[\frac{1}{N} H(X_1, X_2, \ldots, X_N) \, .\] <p>The second treats it as the uncertainty about the <em>next</em> draw, given everything before it:</p> \[H(X_{N+1} \mid X_N, X_{N-1}, \ldots, X_1) \, .\] <p>For a <strong>stationary</strong> process — one whose joint distribution is shift-invariant, \(p_{X_1,\ldots,X_N} = p_{X_{1+k},\ldots,X_{N+k}}\) for any \(k\) — both definitions converge to the same value as \(N \to \infty\) <d-cite key="pinkard2022visual"></d-cite>.</p> <p>Consider a “magical urn” version of our marble example: the first draw is uniform over four colors (\(H(X_1) = 2\) bits), but every draw after that is more likely to repeat the previous color — \(p(\text{same color}) = \tfrac58\), and \(\tfrac18\) for each of the other three colors, independent of \(N\) (a first-order <strong>Markov chain</strong>). Because each color is still marginally uniform, \(H(X_k) = 2\) bits for every \(k\) in isolation — but the <em>joint</em> entropy of consecutive draws is less than the sum of their individual entropies, because knowing \(X_N\) substantially reduces uncertainty about \(X_{N+1}\) <d-cite key="pinkard2022visual"></d-cite>. Concretely,</p> \[H(X_{N+1} \mid X_N) = -\left(\tfrac58 \log_2 \tfrac58 + 3 \cdot \tfrac18 \log_2 \tfrac18\right) \approx 1.549 \text{ bits} \, ,\] <p>constant for every \(N \ge 1\), well below the unconditional 2 bits of the first draw. The two definitions of entropy rate — averaging the joint entropy, and the conditional entropy of the next draw given the past — both converge to this same \(\approx 1.549\) bits as \(N\) grows, exactly as stationarity predicts:</p> <div class="l-body"> <svg viewBox="0 0 620 340" xmlns="http://www.w3.org/2000/svg" style="max-width:100%; height:auto; font-family: sans-serif;"> <style>.axis{stroke:currentColor;stroke-width:1;opacity:0.4;} .grid{stroke:currentColor;stroke-width:1;opacity:0.12;} .lbl{font-size:12px;fill:currentColor;} .lbl2{font-size:11px;fill:currentColor;} .legend{font-size:12px;fill:currentColor;}</style> <line x1="55" y1="295.0" x2="565" y2="295.0" class="grid"/> <text x="47" y="299.0" text-anchor="end" class="lbl2">1.4</text> <line x1="55" y1="254.2" x2="565" y2="254.2" class="grid"/> <text x="47" y="258.2" text-anchor="end" class="lbl2">1.5</text> <line x1="55" y1="213.5" x2="565" y2="213.5" class="grid"/> <text x="47" y="217.5" text-anchor="end" class="lbl2">1.6</text> <line x1="55" y1="172.7" x2="565" y2="172.7" class="grid"/> <text x="47" y="176.7" text-anchor="end" class="lbl2">1.7</text> <line x1="55" y1="131.9" x2="565" y2="131.9" class="grid"/> <text x="47" y="135.9" text-anchor="end" class="lbl2">1.8</text> <line x1="55" y1="91.2" x2="565" y2="91.2" class="grid"/> <text x="47" y="95.2" text-anchor="end" class="lbl2">1.9</text> <line x1="55" y1="50.4" x2="565" y2="50.4" class="grid"/> <text x="47" y="54.4" text-anchor="end" class="lbl2">2.0</text> <text x="55.0" y="315" text-anchor="middle" class="lbl2">1</text> <text x="111.7" y="315" text-anchor="middle" class="lbl2">2</text> <text x="168.3" y="315" text-anchor="middle" class="lbl2">3</text> <text x="225.0" y="315" text-anchor="middle" class="lbl2">4</text> <text x="281.7" y="315" text-anchor="middle" class="lbl2">5</text> <text x="338.3" y="315" text-anchor="middle" class="lbl2">6</text> <text x="395.0" y="315" text-anchor="middle" class="lbl2">7</text> <text x="451.7" y="315" text-anchor="middle" class="lbl2">8</text> <text x="508.3" y="315" text-anchor="middle" class="lbl2">9</text> <text x="565.0" y="315" text-anchor="middle" class="lbl2">10</text> <line x1="55" y1="30" x2="55" y2="295" class="axis"/> <line x1="55" y1="295" x2="565" y2="295" class="axis"/> <text x="14" y="162.5" text-anchor="middle" class="lbl" transform="rotate(-90 14 162.5)">Entropy rate (bits)</text> <text x="310.0" y="332" text-anchor="middle" class="lbl">N</text> <path d="M 55.0 50.4 L 111.7 142.4 L 168.3 173.0 L 225.0 188.3 L 281.7 197.6 L 338.3 203.7 L 395.0 208.0 L 451.7 211.3 L 508.3 213.9 L 565.0 215.9" fill="none" stroke="#5470C6" stroke-width="2.5"/><circle cx="55.0" cy="50.4" r="3.5" fill="#5470C6"/><circle cx="111.7" cy="142.4" r="3.5" fill="#5470C6"/><circle cx="168.3" cy="173.0" r="3.5" fill="#5470C6"/><circle cx="225.0" cy="188.3" r="3.5" fill="#5470C6"/><circle cx="281.7" cy="197.6" r="3.5" fill="#5470C6"/><circle cx="338.3" cy="203.7" r="3.5" fill="#5470C6"/><circle cx="395.0" cy="208.0" r="3.5" fill="#5470C6"/><circle cx="451.7" cy="211.3" r="3.5" fill="#5470C6"/><circle cx="508.3" cy="213.9" r="3.5" fill="#5470C6"/><circle cx="565.0" cy="215.9" r="3.5" fill="#5470C6"/> <path d="M 55.0 50.4 L 111.7 234.3 L 168.3 234.3 L 225.0 234.3 L 281.7 234.3 L 338.3 234.3 L 395.0 234.3 L 451.7 234.3 L 508.3 234.3 L 565.0 234.3" fill="none" stroke="#EE6666" stroke-width="2.5"/><circle cx="55.0" cy="50.4" r="3.5" fill="#EE6666"/><circle cx="111.7" cy="234.3" r="3.5" fill="#EE6666"/><circle cx="168.3" cy="234.3" r="3.5" fill="#EE6666"/><circle cx="225.0" cy="234.3" r="3.5" fill="#EE6666"/><circle cx="281.7" cy="234.3" r="3.5" fill="#EE6666"/><circle cx="338.3" cy="234.3" r="3.5" fill="#EE6666"/><circle cx="395.0" cy="234.3" r="3.5" fill="#EE6666"/><circle cx="451.7" cy="234.3" r="3.5" fill="#EE6666"/><circle cx="508.3" cy="234.3" r="3.5" fill="#EE6666"/><circle cx="565.0" cy="234.3" r="3.5" fill="#EE6666"/> <line x1="55" y1="10" x2="75" y2="10" stroke="#5470C6" stroke-width="2.5"/> <text x="81" y="14" class="legend">Average entropy: H(X1,...,Xn)/N</text> <line x1="305" y1="10" x2="325" y2="10" stroke="#EE6666" stroke-width="2.5"/> <text x="331" y="14" class="legend">Conditional entropy: H(Xn+1 | Xn, ..., X1)</text> </svg> </div> <div class="caption"> The two definitions of entropy rate for the marble Markov chain, computed exactly. The conditional definition drops immediately to ≈1.549 bits (the first draw aside, every subsequent conditional entropy is identical by stationarity); the averaged-joint-entropy definition decreases more gradually toward the same limit, since the high-entropy first draw is diluted over more terms as N grows. Reproduces the qualitative behavior of Fig. 8d in <d-cite key="pinkard2022visual"></d-cite> with values computed directly from the stated transition probabilities. </div> <h3 id="redundancy-of-a-stochastic-process">Redundancy of a stochastic process</h3> <p>Moving from an i.i.d. sequence to a general stochastic process also forces us to revisit redundancy from Part 1, since it can no longer be defined variable-by-variable. The general definition accounts for the <em>joint</em> entropy against the maximum entropy of the full product space <d-cite key="pinkard2022visual"></d-cite>:</p> \[W(\mathbf{X}) = H_{\max}(\mathcal{X} \times \mathcal{X} \times \cdots) - H(X_1, X_2, \ldots) \, .\] <p>In the marble-urn example, every individual draw is marginally uniform, so \(H(X_k) = H_{\max}(\mathcal{X})\) for each \(k\) in isolation — there is no redundancy variable-by-variable. But the <em>joint</em> distribution is far from the maximum-entropy (independent, uniform) joint distribution, because the outcome of one draw is highly informative about its neighbor. This is exactly why we can guess the next color far better than chance, given the previous one: the redundancy lives in the higher-order dependencies between draws, not in any single draw’s marginal distribution.</p> <h2 id="conclusion">Conclusion</h2> <p>We’ve now built, from first principles, the core quantities of information theory: information content and entropy (Part 1); cross-entropy and KL divergence (Part 1); joint entropy, conditional entropy, and mutual information (this post); and the entropy rate of a stochastic process (this post). Two threads run through all of it. First, every one of these quantities has a coding interpretation — the expected length of some code under some scenario — which is what makes entropy feel inevitable rather than an arbitrary formula. Second, KL divergence quietly underlies more than it first appears to: cross-entropy is entropy plus a KL term, and mutual information <em>is</em> a KL divergence, between a joint distribution and the product of its marginals.</p> <p>This is deliberately not the whole of information theory. Both source texts continue well beyond what we’ve covered here: Pinkard and Waller extend these ideas to continuous random variables and differential entropy, and go on to channel capacity and lossy compression — the second of the “two key problems” their tutorial sets out to address <d-cite key="pinkard2022visual"></d-cite>. Olah’s essay closes with pointers to error-correcting codes and the surprising appearances of entropy in quantum information, thermodynamics, and gambling <d-cite key="olah2015visual"></d-cite>. For those directions, Shannon’s original paper <d-cite key="shannon1948mathematical"></d-cite> and Cover &amp; Thomas’s <em>Elements of Information Theory</em> <d-cite key="cover2006elements"></d-cite> — the standard reference recommended by both of our sources — are the natural next stop.</p>]]></content><author><name>Ameenudeen P E</name></author><category term="information-theory"/><category term="entropy"/><category term="tutorial"/><summary type="html"><![CDATA[Extending entropy to two or more variables — joint entropy, conditional entropy, mutual information, fractional bits, and the entropy rate of a stochastic process.]]></summary></entry><entry><title type="html">Visual Information Theory, Part 1: Probability, Codes, and Entropy</title><link href="https://ameen-cet.github.io/ameenudeen/blog/2026/visual-information-theory-part-1/" rel="alternate" type="text/html" title="Visual Information Theory, Part 1: Probability, Codes, and Entropy"/><published>2026-07-11T00:00:00+00:00</published><updated>2026-07-11T00:00:00+00:00</updated><id>https://ameen-cet.github.io/ameenudeen/blog/2026/visual-information-theory-part-1</id><content type="html" xml:base="https://ameen-cet.github.io/ameenudeen/blog/2026/visual-information-theory-part-1/"><![CDATA[<h2 id="why-information-theory">Why information theory</h2> <p>In the 1940s, Claude Shannon gave the informal idea of “information” a precise mathematical footing<d-cite key="shannon1948mathematical"></d-cite>. The resulting theory answers questions that feel intuitive but are hard to pin down without it: How uncertain am I about an outcome? How much does knowing one thing tell me about another? How different are two beliefs about the world?</p> <p>This two-part post builds up the core machinery of information theory — entropy, cross-entropy, KL divergence, joint and conditional entropy, mutual information, and the entropy rate of a stochastic process — visually and rigorously at the same time. It closely follows two sources. The first is Christopher Olah’s essay <em>Visual Information Theory</em>, which builds intuition for entropy and related quantities through codes and areas rather than through the sums directly <d-cite key="olah2015visual"></d-cite>. The second is Pinkard and Waller’s <em>A visual introduction to information theory</em>, a more recent, notation-careful tutorial that formalizes many of the same ideas with figures grounded in a simple marble-drawing experiment <d-cite key="pinkard2022visual"></d-cite>. Part 1 (this post) covers single-variable quantities: information content, entropy, redundancy, typical sequences, cross-entropy, and KL divergence. <a href="/ameenudeen/blog/2026/visual-information-theory-part-2/">Part 2</a> covers quantities involving two or more variables — joint entropy, conditional entropy, mutual information — and closes with the entropy rate of a stochastic process.</p> <p>Throughout, we assume only familiarity with basic probability: random variables, joint and conditional distributions, and expectation.</p> <h2 id="information-reducing-uncertainty">Information: reducing uncertainty</h2> <p>Gaining information means having your uncertainty about something reduced. If I tell you the outcome of a coin flip you haven’t seen, I’ve resolved all your uncertainty about it. If I tell you something you already knew for certain, I’ve given you no information at all.</p> <p>Consider drawing a marble at random from an urn containing marbles of four colors, with replacement, where</p> \[p(\texttt{blue}) = \tfrac{1}{2}, \quad p(\texttt{gray}) = \tfrac{1}{4}, \quad p(\texttt{yellow}) = \tfrac{1}{8}, \quad p(\texttt{green}) = \tfrac{1}{8}.\] <p>Suppose you learn that the marble drawn is <em>not</em> blue. That single fact rules out half of the probability mass, leaving a distribution renormalized over the remaining three colors. Learning a fact that was less likely to be true rules out <em>more</em> probability mass, and hence carries more information — this is precisely why rare events are more informative than common ones <d-cite key="pinkard2022visual"></d-cite>.</p> <p>We can make this quantitative. If ruling out half the probability mass corresponds to one unit of information, then the information content of an outcome \(x\) with probability \(p(x)\) is</p> \[I(x) = \log_2 \frac{1}{p(x)} \, ,\] <p>measured in <strong>bits</strong>. An outcome with probability \(\tfrac12\) carries exactly 1 bit; an outcome with probability \(\tfrac18\) carries 3 bits, because learning it happened is equivalent to eliminating three successive halvings of the probability mass. The <strong>entropy</strong> of a random variable \(X\) is the probability-weighted average information content of its outcomes:</p> \[H(X) = \sum_{x \in \mathcal{X}} p(x) \log_2 \frac{1}{p(x)} \, .\] <p>Entropy is the expected number of bits of surprise you get, on average, from observing \(X\). It is maximized when probability is spread as evenly as possible across outcomes, and it is zero exactly when the outcome is certain in advance (\(p(x) = 1\) for some \(x\)) <d-cite key="pinkard2022visual"></d-cite>.</p> <div class="l-body"> <svg viewBox="0 0 620 320" xmlns="http://www.w3.org/2000/svg" style="max-width:100%; height:auto; font-family: sans-serif;"> <style>.axis{stroke:currentColor;stroke-width:1;opacity:0.4;} .grid{stroke:currentColor;stroke-width:1;opacity:0.12;} .lbl{font-size:12px;fill:currentColor;} .lbl2{font-size:11px;fill:currentColor;} .legend{font-size:12px;fill:currentColor;}</style> <line x1="55" y1="270.0" x2="565" y2="270.0" class="grid"/> <text x="45" y="274.0" text-anchor="end" class="lbl2">0.00</text> <line x1="55" y1="210.0" x2="565" y2="210.0" class="grid"/> <text x="45" y="214.0" text-anchor="end" class="lbl2">0.25</text> <line x1="55" y1="150.0" x2="565" y2="150.0" class="grid"/> <text x="45" y="154.0" text-anchor="end" class="lbl2">0.50</text> <line x1="55" y1="90.0" x2="565" y2="90.0" class="grid"/> <text x="45" y="94.0" text-anchor="end" class="lbl2">0.75</text> <line x1="55" y1="30.0" x2="565" y2="30.0" class="grid"/> <text x="45" y="34.0" text-anchor="end" class="lbl2">1.00</text> <text x="575" y="274.0" text-anchor="start" class="lbl2">0</text> <text x="575" y="214.0" text-anchor="start" class="lbl2">1</text> <text x="575" y="154.0" text-anchor="start" class="lbl2">2</text> <text x="575" y="94.0" text-anchor="start" class="lbl2">3</text> <text x="575" y="34.0" text-anchor="start" class="lbl2">4</text> <line x1="55" y1="30" x2="55" y2="270" class="axis"/> <line x1="565" y1="30" x2="565" y2="270" class="axis"/> <line x1="55" y1="270" x2="565" y2="270" class="axis"/> <text x="18" y="150.0" text-anchor="middle" class="lbl" transform="rotate(-90 18 150.0)">Probability</text> <text x="606" y="150.0" text-anchor="middle" class="lbl" transform="rotate(-90 606 150.0)">Codeword length (bits)</text> <rect x="74.1" y="150.0" width="40.8" height="120.0" fill="#5470C6" fill-opacity="0.75"/> <rect x="122.6" y="210.0" width="40.8" height="60.0" fill="#EE6666" fill-opacity="0.75"/> <text x="118.8" y="288" text-anchor="middle" class="lbl">dog (p=0.5)</text> <rect x="201.6" y="210.0" width="40.8" height="60.0" fill="#5470C6" fill-opacity="0.75"/> <rect x="250.1" y="150.0" width="40.8" height="120.0" fill="#EE6666" fill-opacity="0.75"/> <text x="246.2" y="288" text-anchor="middle" class="lbl">cat (p=0.25)</text> <rect x="329.1" y="240.0" width="40.8" height="30.0" fill="#5470C6" fill-opacity="0.75"/> <rect x="377.6" y="90.0" width="40.8" height="180.0" fill="#EE6666" fill-opacity="0.75"/> <text x="373.8" y="288" text-anchor="middle" class="lbl">fish (p=0.125)</text> <rect x="456.6" y="240.0" width="40.8" height="30.0" fill="#5470C6" fill-opacity="0.75"/> <rect x="505.1" y="90.0" width="40.8" height="180.0" fill="#EE6666" fill-opacity="0.75"/> <text x="501.2" y="288" text-anchor="middle" class="lbl">bird (p=0.125)</text> <rect x="55" y="6" width="12" height="12" fill="#5470C6" fill-opacity="0.75"/> <text x="73" y="16" class="legend">Probability</text> <rect x="185" y="6" width="12" height="12" fill="#EE6666" fill-opacity="0.75"/> <text x="203" y="16" class="legend">Optimal codeword length (bits)</text> </svg> </div> <div class="caption"> Probability and optimal codeword length for four events. The area of each bar (probability × length) is that event's contribution to the entropy; the total area is the entropy itself, 1.75 bits. Data from Olah's dog/cat/fish/bird example <d-cite key="olah2015visual"></d-cite>. </div> <h2 id="visualizing-joint-distributions">Visualizing joint distributions</h2> <p>Before going further, it helps to have a way of picturing distributions over <em>two</em> variables at once <d-cite key="olah2015visual"></d-cite>. Suppose we track the weather (sunny 75% of the time, raining 25%) and clothing (t-shirt 62% of the time, coat 38%). If the two are independent — knowing the weather tells us nothing about clothing choice — the joint distribution factors as \(p(x,y) = p(x)\,p(y)\), and a grid of the joint probabilities looks like a simple product of the two marginals: every row is a scaled copy of every other row.</p> <div class="l-body"> <svg viewBox="0 0 460 230" xmlns="http://www.w3.org/2000/svg" style="max-width:100%; height:auto;"> <style>
    .gridlabel { font-family: sans-serif; font-size: 12px; fill: currentColor; }
    .gridtitle { font-family: sans-serif; font-size: 14px; font-weight: 600; fill: currentColor; }
  </style> <text x="120" y="18" text-anchor="middle" class="gridtitle">Independent</text> <rect x="20" y="30" width="124" height="120" fill="#5470C6" fill-opacity="0.55" stroke="currentColor"/> <rect x="144" y="30" width="76" height="120" fill="#5470C6" fill-opacity="0.30" stroke="currentColor"/> <rect x="20" y="150" width="124" height="40" fill="#5470C6" fill-opacity="0.30" stroke="currentColor"/> <rect x="144" y="150" width="76" height="40" fill="#5470C6" fill-opacity="0.15" stroke="currentColor"/> <text x="82" y="95" text-anchor="middle" class="gridlabel">sun, t-shirt</text> <text x="182" y="95" text-anchor="middle" class="gridlabel">sun, coat</text> <text x="82" y="174" text-anchor="middle" class="gridlabel">rain, t-shirt</text> <text x="182" y="174" text-anchor="middle" class="gridlabel">rain, coat</text> <text x="120" y="210" text-anchor="middle" class="gridlabel">p(x,y) = p(x)&#183;p(y)</text> <text x="350" y="18" text-anchor="middle" class="gridtitle">Correlated</text> <rect x="250" y="30" width="149.3" height="120" fill="#91CC75" fill-opacity="0.5" stroke="currentColor"/> <rect x="399.3" y="30" width="50.7" height="120" fill="#91CC75" fill-opacity="0.15" stroke="currentColor"/> <rect x="250" y="150" width="48.0" height="40" fill="#91CC75" fill-opacity="0.15" stroke="currentColor"/> <rect x="298.0" y="150" width="152.0" height="40" fill="#91CC75" fill-opacity="0.65" stroke="currentColor"/> <text x="324" y="95" text-anchor="middle" class="gridlabel">sun, t-shirt</text> <text x="424" y="95" text-anchor="middle" class="gridlabel" font-size="10">sun, coat</text> <text x="274" y="174" text-anchor="middle" class="gridlabel" font-size="10">rain, t-shirt</text> <text x="374" y="174" text-anchor="middle" class="gridlabel">rain, coat</text> <text x="350" y="210" text-anchor="middle" class="gridlabel">boundary shifts per row</text> </svg> </div> <div class="caption"> Left: independent variables produce a grid where the t-shirt/coat boundary sits at the same place in every row — a single straight line top to bottom, since the split doesn't depend on the weather. Right: correlated variables (it's more likely to be a coat on a rainy day) shift that boundary row by row — the "rain, coat" cell swells at the expense of "sun, coat", and the split is no longer a single straight line. </div> <p>When the variables interact, some cells of the grid swell with extra probability (it’s more likely to wear a coat when it’s raining) at the expense of others. The fundamental identity connecting joint and conditional probability, \(p(x,y) = p(x)\cdot p(y\mid x)\), lets us factor any joint distribution one variable at a time — and it is the seed from which joint entropy and conditional entropy (Part 2) will grow.</p> <h2 id="entropy-the-cost-of-encoding">Entropy: the cost of encoding</h2> <p>Entropy has a second, equally important interpretation: it is the <em>shortest possible average length</em>, in bits, of a code for a sequence of outcomes from a distribution <d-cite key="pinkard2022visual"></d-cite><d-cite key="olah2015visual"></d-cite>. This is worth deriving carefully, because the derivation is what makes the formula feel inevitable rather than arbitrary.</p> <p>Suppose we want to communicate a sequence of words drawn from a small vocabulary — say, an imaginary friend who only ever says “dog,” “cat,” “fish,” or “bird,” with probabilities \(\tfrac12, \tfrac14, \tfrac18, \tfrac18\) <d-cite key="olah2015visual"></d-cite>. A <strong>code</strong> assigns each word a binary codeword; to send a message we concatenate the codewords for each word in sequence.</p> <h3 id="prefix-codes-and-the-space-of-codewords">Prefix codes and the space of codewords</h3> <p>If every codeword has the same length, decoding is trivial — split the bitstream every \(k\) bits. But we’d like common words (like “dog”) to get <em>short</em> codewords, so the average message is short. This creates a subtlety: with variable-length codewords, how does the receiver know where one codeword ends and the next begins?</p> <p>The answer is the <strong>prefix property</strong>: no codeword may be a prefix of another. A code with this property is called a <strong>prefix code</strong>, and it is always uniquely decodable — you can read a bitstream left to right and unambiguously identify each codeword as soon as its pattern is complete.</p> <p>The prefix property has a cost. Choosing the codeword <code class="language-plaintext highlighter-rouge">01</code> forbids every longer codeword that starts with <code class="language-plaintext highlighter-rouge">01</code> — <code class="language-plaintext highlighter-rouge">010</code>, <code class="language-plaintext highlighter-rouge">0110101</code>, and so on — because they would be ambiguous with it. A quarter of all possible bitstrings begin with <code class="language-plaintext highlighter-rouge">01</code>, so choosing it as a codeword “spends” a quarter of the total space of possible codewords. In general, a codeword of length \(L\) costs \(2^{-L}\) of the total space <d-cite key="olah2015visual"></d-cite>.</p> <p>The following binary tree shows one valid prefix code for the four-word vocabulary: <code class="language-plaintext highlighter-rouge">0</code> for dog, <code class="language-plaintext highlighter-rouge">10</code> for cat, <code class="language-plaintext highlighter-rouge">110</code> for fish, <code class="language-plaintext highlighter-rouge">111</code> for bird. Every codeword is a leaf, and no codeword is an ancestor of another — that’s the prefix property, drawn as a tree.</p> <div class="l-body"> <svg viewBox="0 0 500 220" xmlns="http://www.w3.org/2000/svg" style="max-width:100%; height:auto;"> <style>
    .node { fill: none; stroke: currentColor; stroke-width: 1.5; }
    .leaf { fill: #5470C6; fill-opacity: 0.15; stroke: currentColor; stroke-width: 1.5; }
    .lbl { font-family: sans-serif; font-size: 13px; fill: currentColor; text-anchor: middle; }
    .elbl { font-family: sans-serif; font-size: 12px; fill: currentColor; text-anchor: middle; }
  </style> <circle cx="60" cy="20" r="4" fill="currentColor"/> <line x1="60" y1="20" x2="60" y2="90" class="node"/> <line x1="60" y1="20" x2="320" y2="90" class="node"/> <line x1="320" y1="90" x2="230" y2="150" class="node"/> <line x1="320" y1="90" x2="410" y2="150" class="node"/> <line x1="410" y1="150" x2="350" y2="200" class="node"/> <line x1="410" y1="150" x2="450" y2="200" class="node"/> <text x="35" y="58" class="elbl">0</text> <text x="185" y="50" class="elbl">1</text> <text x="265" y="118" class="elbl">0</text> <text x="375" y="118" class="elbl">1</text> <text x="368" y="175" class="elbl">0</text> <text x="442" y="175" class="elbl">1</text> <rect x="30" y="90" width="60" height="34" rx="6" class="leaf"/> <text x="60" y="111" class="lbl">dog: 0</text> <rect x="195" y="150" width="70" height="34" rx="6" class="leaf"/> <text x="230" y="171" class="lbl">cat: 10</text> <rect x="310" y="192" width="80" height="26" rx="6" class="leaf"/> <text x="350" y="209" class="lbl" font-size="12">fish: 110</text> <rect x="410" y="192" width="80" height="26" rx="6" class="leaf"/> <text x="450" y="209" class="lbl" font-size="12">bird: 111</text> </svg> </div> <div class="caption"> A prefix code for {dog, cat, fish, bird}. Each word sits at a leaf; the path from the root spells out its codeword. Because every codeword is a leaf, none is a prefix of another. </div> <h3 id="the-optimal-codeword-length">The optimal codeword length</h3> <p>Think of building a code as spending a fixed budget: buying a codeword of length \(L\) costs \(2^{-L}\) of the total space of codewords, and using it costs us \(p(x) \cdot L\) extra bits in our average message length, since it’s used a \(p(x)\) fraction of the time. The natural strategy — spend a fraction \(p(x)\) of the budget on the codeword for \(x\) — turns out to be <em>optimal</em>, not merely reasonable <d-cite key="olah2015visual"></d-cite>. Olah proves this with a marginal argument: at the natural allocation, the benefit-to-cost ratio of shortening any single codeword is exactly 1, the same for every codeword; perturbing away from it (spending \(\epsilon\) more on one codeword and \(\epsilon\) less on another) unbalances the ratios and creates an incentive to shift back. Since this holds for every pair of codewords, the natural allocation cannot be improved.</p> <p>If we spend \(p(x)\) of the budget on the codeword for \(x\), and a codeword of length \(L\) costs \(2^{-L}\), then solving \(2^{-L} = p(x)\) for \(L\) gives the optimal codeword length:</p> \[L(x) = \log_2 \frac{1}{p(x)} \, .\] <p>This is exactly the information content of \(x\) from the previous section — no coincidence. The optimal code assigns each outcome a codeword whose length equals its information content in bits.</p> <h3 id="putting-it-together">Putting it together</h3> <p>The average codeword length under the optimal code is, by definition, the entropy:</p> \[H(X) = \sum_{x} p(x)\, L(x) = \sum_{x} p(x) \log_2 \frac{1}{p(x)} \, .\] <p>For our dog/cat/fish/bird example this works out to \(\tfrac12(1) + \tfrac14(2) + \tfrac18(3) + \tfrac18(3) = 1.75\) bits — and no code, however clever, can do better on average <d-cite key="olah2015visual"></d-cite>. This is a genuine lower bound: <strong>entropy is the shortest possible average encoding length for a sequence of outcomes from a given distribution</strong>, a fact known as the source coding theorem.</p> <p>One wrinkle: optimal codeword lengths are frequently <em>fractional</em> (e.g. \(\log_2 \tfrac{1}{0.71} \approx 0.49\) bits), which is meaningless for a single codeword — you can’t send half a bit. But if you encode <em>several</em> draws jointly, ideal lengths add, and the rounding overhead per event shrinks toward zero as the number of jointly-encoded events grows <d-cite key="olah2015visual"></d-cite>. There is a real sense in which fractional bits are achievable on average, even though no single message can have a fractional length; we will use this idea again in Part 2.</p> <h2 id="redundancy-and-maximum-entropy">Redundancy and maximum entropy</h2> <p>Entropy is maximized when probability is spread as evenly as possible over the outcome space \(\mathcal{X}\). In that case,</p> \[H_{\max}(\mathcal{X}) = \log_2 |\mathcal{X}| \, ,\] <table> <tbody> <tr> <td>where $$</td> <td>\mathcal{X}</td> <td>$$ is the number of possible outcomes <d-cite key="pinkard2022visual"></d-cite>. The gap between this ceiling and the actual entropy of a variable is its <strong>redundancy</strong>:</td> </tr> </tbody> </table> \[W(X) = H_{\max}(\mathcal{X}) - H(X) \, .\] <p>Redundancy quantifies how much shorter our messages become because the distribution is <em>not</em> uniform — the more concentrated the probability mass, the larger the redundancy, and the more compressible the source. A deterministic variable (\(p(x)=1\) for one outcome) has zero entropy and maximum possible redundancy; a uniform variable has zero redundancy, because there is nothing left to exploit.</p> <h2 id="typical-sequences-and-the-aep">Typical sequences and the AEP</h2> <p>Entropy governs a length-\(N\) i.i.d. sequence too: the total information content of \(N\) independent draws is \(N \cdot H(X)\) on average. But individual sequences vary enormously in <em>actual</em> information content — an all-<code class="language-plaintext highlighter-rouge">blue</code> sequence (the single most probable outcome) can be far cheaper to encode than a “typical” one, and far more expensive than a maximally rare one <d-cite key="pinkard2022visual"></d-cite>.</p> <p>A <strong>typical sequence</strong> is one whose information content is close to this average: for small \(\epsilon &gt; 0\),</p> \[H(X) - \epsilon \ \le\ -\frac{1}{N}\log p(x_1, \ldots, x_N) \ \le\ H(X) + \epsilon \, .\] <p>As \(N \to \infty\), the <strong>asymptotic equipartition property (AEP)</strong> kicks in: almost all of the probability mass concentrates onto the typical set, regardless of how small \(\epsilon\) is, and every typical sequence has probability \(\approx 2^{-NH(X)}\). Since probabilities sum to 1, there must be \(\approx 2^{NH(X)}\) typical sequences. This is precisely what makes lossless compression at rate \(H(X)\) achievable: a scheme that assigns a unique length-\(NH(X)\) binary string to every typical sequence, and ignores the (vanishingly probable) rest, is lossless in the limit — and no scheme can reliably do better <d-cite key="pinkard2022visual"></d-cite>.</p> <h2 id="cross-entropy">Cross-entropy</h2> <p>Now suppose two people communicate using the <em>same</em> words but <em>different</em> frequencies. Bob mostly talks about dogs; his wife Alice mostly talks about cats. Bob’s code — optimized for his own distribution \(p\) — is suboptimal when Alice uses it to encode her distribution \(q\), because it assigns short codewords to words Alice rarely uses <d-cite key="olah2015visual"></d-cite>.</p> <p>The average message length when encoding events from \(q\) using the code optimized for \(p\) is the <strong>cross-entropy</strong>:</p> \[H_p(q) = \sum_x q(x) \log_2 \frac{1}{p(x)} \, .\] <p>Cross-entropy is not symmetric — \(H_p(q) \neq H_q(p)\) in general — and this asymmetry is not a technicality; it is the whole point. \(H_q(p)\) is large exactly when there’s an outcome common under \(p\) but rare under \(q\): that outcome gets an unnecessarily long codeword, which hurts badly because \(p\) uses it often. Whether the “large” direction is \(H_p(q)\) or \(H_q(p)\) depends on which distribution is doing the frequent using and which one built the code.</p> <p>Cross-entropy is always at least the entropy of the distribution being encoded, \(H_p(q) \ge H(q)\), with equality iff \(p = q\). This makes it a natural, if asymmetric, measure of how different two distributions are — and it is why cross-entropy is the workhorse loss function for classification in machine learning: minimizing \(H_p(q)\) where \(q\) is the true label distribution and \(p\) is the model’s predicted distribution directly penalizes the model for being confidently wrong <d-cite key="olah2015visual"></d-cite>.</p> <h2 id="kl-divergence">KL divergence</h2> <p>The excess length caused by using the wrong code — the gap between cross-entropy and entropy — is the <strong>Kullback–Leibler (KL) divergence</strong>:</p> \[D_q(p) = H_q(p) - H(p) = \sum_x p(x) \log_2 \frac{p(x)}{q(x)} \, .\] <p>KL divergence is zero exactly when \(p = q\) and grows as the two distributions diverge, which is why it behaves like a “distance” between distributions (though it is not symmetric and does not satisfy the triangle inequality, so it is not a metric in the strict sense) <d-cite key="olah2015visual"></d-cite>. It shows up constantly whenever we want one distribution to be close to another — variational inference, information geometry, and, again, machine learning, where minimizing \(D_q(p)\) between a predicted and target distribution is equivalent to minimizing cross-entropy alone (since \(H(p)\) doesn’t depend on the model).</p> <h2 id="whats-next">What’s next</h2> <p>We now have the vocabulary for a single random variable: information content, entropy, redundancy, cross-entropy, and KL divergence. <a href="/ameenudeen/blog/2026/visual-information-theory-part-2/">Part 2</a> extends all of this to <strong>two or more variables</strong> — joint entropy, conditional entropy, and mutual information — and finishes with the <strong>entropy rate</strong> of a stochastic process, the natural generalization of entropy to sequences that aren’t independent and identically distributed.</p> <p>For a fuller treatment than either source attempts, Shannon’s original paper remains remarkably readable <d-cite key="shannon1948mathematical"></d-cite>, and Cover &amp; Thomas’s <em>Elements of Information Theory</em> is the standard graduate reference <d-cite key="cover2006elements"></d-cite>.</p>]]></content><author><name>Ameenudeen P E</name></author><category term="information-theory"/><category term="entropy"/><category term="tutorial"/><summary type="html"><![CDATA[A visual and mathematically rigorous introduction to information content, entropy, cross-entropy, and KL divergence — for readers who want the intuition and the derivations.]]></summary></entry><entry><title type="html">എന്റെ ആദ്യ മലയാളം ബ്ലോഗ്</title><link href="https://ameen-cet.github.io/ameenudeen/blog/2026/malayalam-sample-post/" rel="alternate" type="text/html" title="എന്റെ ആദ്യ മലയാളം ബ്ലോഗ്"/><published>2026-07-08T00:00:00+00:00</published><updated>2026-07-08T00:00:00+00:00</updated><id>https://ameen-cet.github.io/ameenudeen/blog/2026/malayalam-sample-post</id><content type="html" xml:base="https://ameen-cet.github.io/ameenudeen/blog/2026/malayalam-sample-post/"><![CDATA[<div style="font-family: 'Noto Sans Malayalam', sans-serif;"> നമസ്കാരം! ഇത് എന്റെ ബ്ലോഗിലെ ആദ്യത്തെ മലയാളം പോസ്റ്റാണ്. ഇവിടെ ഞാൻ എന്റെ ഗവേഷണം, പഠനം, കൂടാതെ മറ്റ് വിഷയങ്ങളെക്കുറിച്ചും മലയാളത്തിൽ എഴുതാൻ ഉദ്ദേശിക്കുന്നു. #### എന്തുകൊണ്ട് മലയാളത്തിൽ? - കൂടുതൽ ആളുകളിലേക്ക് എത്തിച്ചേരാൻ - എന്റെ മാതൃഭാഷയിൽ ആശയങ്ങൾ വ്യക്തമായി പങ്കുവയ്ക്കാൻ - മലയാളം എഴുത്തുകാരെ പ്രോത്സാഹിപ്പിക്കാൻ നന്ദി വായനയ്ക്ക്! </div>]]></content><author><name></name></author><category term="sample-posts"/><category term="malayalam"/><category term="sample"/><summary type="html"><![CDATA[മലയാളത്തിൽ എഴുതിയ ഒരു സാമ്പിൾ ബ്ലോഗ് പോസ്റ്റ്]]></summary></entry><entry><title type="html">Family Photo Gallery</title><link href="https://ameen-cet.github.io/ameenudeen/blog/2026/children/" rel="alternate" type="text/html" title="Family Photo Gallery"/><published>2026-06-24T00:00:00+00:00</published><updated>2026-06-24T00:00:00+00:00</updated><id>https://ameen-cet.github.io/ameenudeen/blog/2026/children</id><content type="html" xml:base="https://ameen-cet.github.io/ameenudeen/blog/2026/children/"><![CDATA[<h2 id="gallery">Gallery</h2> <p><a href="/ameenudeen/assets/img/gallery/1.png" data-lightbox="family"> <img src="/ameenudeen/assets/img/gallery/1.png" width="250"/> </a></p> <p><a href="/ameenudeen/assets/img/gallery/2.png" data-lightbox="family"> <img src="/ameenudeen/assets/img/gallery/2.png" width="250"/> </a></p> <p><a href="/ameenudeen/assets/img/gallery/3.png" data-lightbox="family"> <img src="/ameenudeen/assets/img/gallery/3.png" width="250"/> </a></p>]]></content><author><name></name></author><category term="sample-posts"/><category term="formatting"/><category term="images"/><summary type="html"><![CDATA[My personal photo collection]]></summary></entry><entry><title type="html">Google Gemini updates: Flash 1.5, Gemma 2 and Project Astra</title><link href="https://ameen-cet.github.io/ameenudeen/blog/2024/google-gemini-updates-flash-15-gemma-2-and-project-astra/" rel="alternate" type="text/html" title="Google Gemini updates: Flash 1.5, Gemma 2 and Project Astra"/><published>2024-05-14T00:00:00+00:00</published><updated>2024-05-14T00:00:00+00:00</updated><id>https://ameen-cet.github.io/ameenudeen/blog/2024/google-gemini-updates-flash-15-gemma-2-and-project-astra</id><content type="html" xml:base="https://ameen-cet.github.io/ameenudeen/blog/2024/google-gemini-updates-flash-15-gemma-2-and-project-astra/"><![CDATA[<p>Gemini breaks new ground with a faster model, longer context, AI agents and moreLearn more:Learn more:Learn more:Models &amp; ResearchProductsInfrastructure &amp; cloudTechnology Learn more: ProductsPlatformsDevices Learn more: Outreach &amp; initiativesLeadershipInside Google Learn more: May 14, 2024 We’re introducing a series of updates across the Gemini family of models, including the new 1.5 Flash, our lightweight model for speed and efficiency, and Project Astra, our vision for the future of AI assistants. Demis HassabisCEO of Google DeepMind, on behalf of the Gemini teamIn December, we launched our first natively multimodal model Gemini 1.0 in three sizes: Ultra, Pro and Nano. Just a few months later we released 1.5 Pro, with enhanced performance and a breakthrough long context window of 1 million tokens.Developers and enterprise customers have been putting 1.5 Pro to use in incredible ways and finding its long context window, multimodal reasoning capabilities and impressive overall performance incredibly useful.We know from user feedback that some applications need lower latency and a lower cost to serve. This inspired us to keep innovating, so today, we’re introducing Gemini 1.5 Flash: a model that’s lighter-weight than 1.5 Pro, and designed to be fast and efficient to serve at scale.Both 1.5 Pro and 1.5 Flash are available in public preview with a 1 million token context window in Google AI Studio and Vertex AI. And now, 1.5 Pro is also available with a 2 million token context window via waitlist to developers using the API and to Google Cloud customers.We’re also introducing updates across the Gemini family of models, announcing our next generation of open models, Gemma 2, and sharing progress on the future of AI assistants, with Project Astra.Context lengths of leading foundation models compared with Gemini 1.5’s 2 million token capability1.5 Flash is the newest addition to the Gemini model family and the fastest Gemini model served in the API. It’s optimized for high-volume, high-frequency tasks at scale, is more cost-efficient to serve and features our breakthrough long context window.While it’s a lighter weight model than 1.5 Pro, it’s highly capable of multimodal reasoning across vast amounts of information and delivers impressive quality for its size.The new Gemini 1.5 Flash model is optimized for speed and efficiency, is highly capable of multimodal reasoning and features our breakthrough long context window.1.5 Flash excels at summarization, chat applications, image and video captioning, data extraction from long documents and tables, and more. This is because it’s been trained by 1.5 Pro through a process called “distillation,” where the most essential knowledge and skills from a larger model are transferred to a smaller, more efficient model.Read more about 1.5 Flash in our updated Gemini 1.5 technical report, on the Gemini technology page, and learn about 1.5 Flash’s availability and pricing.Over the last few months, we’ve significantly improved 1.5 Pro, our best model for general performance across a wide range of tasks.Beyond extending its context window to 2 million tokens, we’ve enhanced its code generation, logical reasoning and planning, multi-turn conversation, and audio and image understanding through data and algorithmic advances. We see strong improvements on public and internal benchmarks for each of these tasks.1.5 Pro can now follow increasingly complex and nuanced instructions, including ones that specify product-level behavior involving role, format and style. We’ve improved control over the model’s responses for specific use cases, like crafting the persona and response style of a chat agent or automating workflows through multiple function calls. And we’ve enabled users to steer model behavior by setting system instructions.We added audio understanding in the Gemini API and Google AI Studio, so 1.5 Pro can now reason across image and audio for videos uploaded in Google AI Studio. And we’re now integrating 1.5 Pro into Google products, including Gemini Advanced and in Workspace apps.Read more about 1.5 Pro in our updated Gemini 1.5 technical report and on the Gemini technology page.Gemini Nano is expanding beyond text-only inputs to include images as well. Starting with Pixel, applications using Gemini Nano with Multimodality will be able to understand the world the way people do — not just through text, but also through sight, sound and spoken language.Read more about Gemini 1.0 Nano on Android.Today, we’re also sharing a series of updates to Gemma, our family of open models built from the same research and technology used to create the Gemini models.We’re announcing Gemma 2, our next generation of open models for responsible AI innovation. Gemma 2 has a new architecture designed for breakthrough performance and efficiency, and will be available in new sizes.The Gemma family is also expanding with PaliGemma, our first vision-language model inspired by PaLI-3. And we’ve upgraded our Responsible Generative AI Toolkit with LLM Comparator for evaluating the quality of model responses.Read more on the Developer blog.As part of Google DeepMind’s mission to build AI responsibly to benefit humanity, we’ve always wanted to develop universal AI agents that can be helpful in everyday life. That’s why today, we’re sharing our progress in building the future of AI assistants with Project Astra (advanced seeing and talking responsive agent).To be truly useful, an agent needs to understand and respond to the complex and dynamic world just like people do — and take in and remember what it sees and hears to understand context and take action. It also needs to be proactive, teachable and personal, so users can talk to it naturally and without lag or delay.While we’ve made incredible progress developing AI systems that can understand multimodal information, getting response time down to something conversational is a difficult engineering challenge. Over the past few years, we’ve been working to improve how our models perceive, reason and converse to make the pace and quality of interaction feel more natural.Building on Gemini, we’ve developed prototype agents that can process information faster by continuously encoding video frames, combining the video and speech input into a timeline of events, and caching this information for efficient recall.By leveraging our leading speech models, we also enhanced how they sound, giving the agents a wider range of intonations. These agents can better understand the context they’re being used in, and respond quickly, in conversation.With technology like this, it’s easy to envision a future where people could have an expert AI assistant by their side, through a phone or glasses. And some of these capabilities are coming to Google products, like the Gemini app and web experience, later this year.We’ve made incredible progress so far with our family of Gemini models, and we’re always striving to advance the state-of-the-art even further. By investing in a relentless production line of innovation, we’re able to explore new ideas at the frontier, while also unlocking the possibility of new and exciting Gemini use cases.Learn more about Gemini and its capabilities.Collection Sign up for our newsletters with product updates, event information, special offers, and more. Done. Just one step more. Check your inbox to confirm your subscription.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>You can also subscribe with a different email address.
  
        Your information will be used in accordance with Google's privacy policy. You may opt out at any time.
</code></pre></div></div>]]></content><author><name></name></author><category term="external-posts"/><category term="google"/><summary type="html"><![CDATA[We’re sharing updates across our Gemini family of models and a glimpse of Project Astra, our vision for the future of AI assistants.]]></summary></entry><entry><title type="html">Displaying External Posts on Your al-folio Blog</title><link href="https://ameen-cet.github.io/ameenudeen/blog/2022/displaying-external-posts-on-your-al-folio-blog/" rel="alternate" type="text/html" title="Displaying External Posts on Your al-folio Blog"/><published>2022-04-23T23:20:09+00:00</published><updated>2022-04-23T23:20:09+00:00</updated><id>https://ameen-cet.github.io/ameenudeen/blog/2022/displaying-external-posts-on-your-al-folio-blog</id><content type="html" xml:base="https://ameen-cet.github.io/ameenudeen/blog/2022/displaying-external-posts-on-your-al-folio-blog/"><![CDATA[<h3>External Posts on Your al-folio Blog</h3> <p>If you prefer publishing blog posts on medium.com or other external sources, starting version v0.5.0, <a href="https://github.com/alshedivat/al-folio">al-folio</a> lets you to display your external posts in the blog feed of your website! 🎉🎉</p> <p>Configuring external sources of super simple. After upgrading to v0.5.0, just add the following section to your _config.yml:</p> <pre>external_sources:<br />  - name: medium.com  # name of the source (arbitrary string)<br />    rss_url: <a href="https://medium.com/@al-folio/feed">https://medium.com/@&lt;your-medium-username&gt;/feed</a></pre> <p>The example above adds your medium.com blog post feed as an external source. But you can add arbitrary RSS feeds as sources.</p> <p>Any questions or suggestions? 👉 Start <a href="https://github.com/alshedivat/al-folio/discussions">a discussion on GitHub</a>!</p> <p><img src="https://medium.com/_/stat?event=post.clientViewed&amp;referrerSource=full_rss&amp;postId=b60a1d241a0a" width="1" height="1" alt=""/></p>]]></content><author><name></name></author><category term="jekyll"/><category term="jekyll-themes"/><category term="personal-blog"/><category term="blog"/><category term="academic"/><category term="medium"/></entry></feed>