<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Under the Null]]></title><description><![CDATA[Economics, Statistics, Machine Learning, Artificial Intelligence, and whatever newfangled word they come up with next to describe looking at data and learning what it means. ]]></description><link>https://www.underthenull.com</link><image><url>https://substackcdn.com/image/fetch/$s_!nZSI!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8f763ca-d387-4b79-8be8-0585c1264985_1280x1280.png</url><title>Under the Null</title><link>https://www.underthenull.com</link></image><generator>Substack</generator><lastBuildDate>Fri, 26 Jun 2026 15:56:48 GMT</lastBuildDate><atom:link href="https://www.underthenull.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Zach Flynn]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[zachflynn@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[zachflynn@substack.com]]></itunes:email><itunes:name><![CDATA[Zach Flynn]]></itunes:name></itunes:owner><itunes:author><![CDATA[Zach Flynn]]></itunes:author><googleplay:owner><![CDATA[zachflynn@substack.com]]></googleplay:owner><googleplay:email><![CDATA[zachflynn@substack.com]]></googleplay:email><googleplay:author><![CDATA[Zach Flynn]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Reinventing the Wheel #1: Personal Finance Software]]></title><description><![CDATA[A fun little side project (inspired by matrimony) that has become my main personal finance tool]]></description><link>https://www.underthenull.com/p/reinventing-the-wheel-1-personal</link><guid isPermaLink="false">https://www.underthenull.com/p/reinventing-the-wheel-1-personal</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Tue, 23 Jun 2026 07:31:20 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1564939558297-fc396f18e5c7?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOXx8YWNjb3VudGluZ3xlbnwwfHx8fDE3ODIxNTMzMjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1564939558297-fc396f18e5c7?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOXx8YWNjb3VudGluZ3xlbnwwfHx8fDE3ODIxNTMzMjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1564939558297-fc396f18e5c7?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOXx8YWNjb3VudGluZ3xlbnwwfHx8fDE3ODIxNTMzMjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1564939558297-fc396f18e5c7?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOXx8YWNjb3VudGluZ3xlbnwwfHx8fDE3ODIxNTMzMjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1564939558297-fc396f18e5c7?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOXx8YWNjb3VudGluZ3xlbnwwfHx8fDE3ODIxNTMzMjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1564939558297-fc396f18e5c7?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOXx8YWNjb3VudGluZ3xlbnwwfHx8fDE3ODIxNTMzMjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1564939558297-fc396f18e5c7?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOXx8YWNjb3VudGluZ3xlbnwwfHx8fDE3ODIxNTMzMjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="5202" height="3465" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1564939558297-fc396f18e5c7?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOXx8YWNjb3VudGluZ3xlbnwwfHx8fDE3ODIxNTMzMjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3465,&quot;width&quot;:5202,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;white Canon cash register&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="white Canon cash register" title="white Canon cash register" srcset="https://images.unsplash.com/photo-1564939558297-fc396f18e5c7?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOXx8YWNjb3VudGluZ3xlbnwwfHx8fDE3ODIxNTMzMjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1564939558297-fc396f18e5c7?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOXx8YWNjb3VudGluZ3xlbnwwfHx8fDE3ODIxNTMzMjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1564939558297-fc396f18e5c7?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOXx8YWNjb3VudGluZ3xlbnwwfHx8fDE3ODIxNTMzMjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1564939558297-fc396f18e5c7?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxOXx8YWNjb3VudGluZ3xlbnwwfHx8fDE3ODIxNTMzMjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@stellrweb">StellrWeb</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>Today, we&#8217;re breaking from this blog&#8217;s usual topic (statistics, economics, etc) to indulge in a far more important topic: a hobby project I built seven years ago. Aside from being a trip down memory lane, it&#8217;s possible this blog has a point.  Two of them, in fact:</p><ol><li><p>Doing things <em>just</em> <em>because</em> is a perfectly good reason to do things, and </p></li><li><p>Extensible double-entry accounting apps are a valid form of artistic expression.</p></li></ol><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>It was the Fall of 2018, and I was to be wed in the Spring. I did not have much in the way of savings in those ancient days, and weddings cost money. I needed to budget for it. </p><p>Naturally, I needed to write an extensible double-entry accounting system to do this. It had to be programmable in Scheme, of course. I cannot overemphasize how much all of these requirements were unavoidable design constraints. It is impossible to budget for a wedding without Lisp.</p><p>And so, <strong>leas</strong> was born. <strong>L</strong>eas is an <strong>e</strong>xtensible <strong>a</strong>ccounting <strong>s</strong>ystem that you can use interactively in the terminal. It&#8217;s extensible with Scheme, a full programming language, embedded in the app.</p><p><em>[I wrote it without thinking about LLMs&#8212;it was 2018&#8212;but now that we are in the new world, these tools do make it even more useful. &#8220;Codex, write me a script in Guile Scheme to update my home value based on whatever Zillow says it is and record the incremental value as home equity gains&#8221; just works like magic. Try getting a web app to do that.]</em></p><div><hr></div><p>The initial idea was to make a tool that fit in between two kinds of accounting tools.</p><ol><li><p><strong><a href="https://ledger-cli.org/">ledger</a>. </strong>A tool that produces reports from specially-formatted text files. It&#8217;s very UNIX-y. I like <strong>ledger</strong>. It is highly extensible because you just need a script that modifies a text file. Easy. I actually first toyed with the idea of making <strong>leas</strong> an interactive tool to modify <strong>ledger</strong> files, but I didn&#8217;t like the result, and I didn&#8217;t find <strong>ledger</strong> very convenient to use in its natural state. I wanted something more interactive that was still extensible.</p></li><li><p><strong>GUI-tools like <a href="https://gnucash.org/">GNUCash</a>. </strong>I used GNUCash in grad school, but it was a separate GUI app that I&#8217;d always forget to open. I wanted something quick and easy from the terminal. GNUCash had some extensibility (in Scheme, too) but not super easy to use.</p></li></ol><p>I also just thought the idea of an Emacs-like personal finance tool was neat-o.</p><p>So, I came up with this little structure:</p><ul><li><p>Interactive C-based command line app.</p></li><li><p>The prompt was just a Scheme interpreter that called various Scheme/C functions exposed to Scheme.</p></li></ul><p>My first critical design decision: I realized right away that I did not want to type parentheses all the time:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;60d56679-8c8b-4498-b175-4ac1791f850f&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">(command arg1 arg2)</code></pre></div><p>So, I made the interpreter insert the outer parenthesis automatically so that this Just Works (tm):</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;4d1c9f9f-9c99-47b4-91ce-ad233697753a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">command arg1 arg2</code></pre></div><p>But, I wanted the program to be more&#8230; interactive. I didn&#8217;t want to have to type full commands. So, I settled on a UX like this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;7ecdfdc4-6205-427e-889d-faebccbd3671&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">&gt; spend
5: Groceries
6: Rent
...
To Account: 5
1: Checking
...
From Account: 1
Amount: 109.23
Description: Walgreens
Year: 2026
Month: 6
Day: 22
&gt;</code></pre></div><p>Of course, I could just code this interaction in C, but I wanted to make the interactive system sort of &#8220;universal&#8221; and something you could use in Scheme extensions to add new interactive commands. So I came up with this system for making any Scheme function interactive, and also added some special data types like this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;025a8b9e-b452-4c83-b076-14bdae00669f&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">(define add-record
  (lambda ()
    (leas/call "leas/at"
               (list
                (cons "Account" "current_account")
                (cons "Amount" "real")
                (cons "Description" "string")
                (cons "Day" "day")))))
</code></pre></div><p>So you can use <strong>leas/call</strong> to provide arguments to any non-interactive function using data types like &#8220;real&#8221; and &#8220;string&#8221; but also with some <strong>leas</strong> specific datatypes like &#8220;day&#8221; (for a date), &#8220;current_account&#8221; for the currently selected account, &#8220;account&#8221; for an account, &#8220;expense_account&#8221; (for an Expense account), &#8220;liability_account&#8221; (for a Liability account), and so on. So now we have some actual accounting data types.</p><p>This little structure let me write a small set of core routines and data types in C and then most of the interactive structure in Scheme (the UI, more or less) which was nice.</p><div><hr></div><p>The basic structure was:</p><ul><li><p>Book</p><ul><li><p>Account</p><ul><li><p>Transaction</p></li></ul></li></ul></li></ul><p>Each Account has a Type. One of:</p><ol><li><p>Asset</p></li><li><p>Liability</p></li><li><p>Income</p></li><li><p>Expense</p></li></ol><p>Buying a McDouble, taking out loans, paying them back, and earning money are all just transfers between accounts. You transfer funds from the Income account to the Asset account on payday. You transfer from a Liability to an Expense account when you pay with a credit card or from a Liability to an Asset account when you take out a loan.</p><p>There is this concept of the &#8220;current&#8221; account, a pointer that attaches to a certain account and marks it &#8220;active&#8221;. That makes it possible to use commands which just take the current account as their argument which makes it quicker to navigate around. For example, <strong>lt</strong> lists the last few transactions in the current account.</p><p>I use <strong>leas</strong> every day, so the thing has ended up having lots of niceties. There are commands for doing things like paying off a loan (two transfers: one from an asset account to an expense account to pay interest and one to the liability account to pay off the principal). </p><p>I&#8217;ve written Scheme scripts to automatically update the values of any funds/stocks/etc. I hold by scraping the internet. </p><div><hr></div><p>I should point out that this whole &#8220;budgeting&#8221; thing actually worked. Go figure. Keeping track of spending  did let me kind of thread the needle on the wedding. It reduced stress, increased confidence, and gave my skin a healthy glow.</p><div><hr></div><p>The whole thing is only about 2000 lines of code. Simple, but I&#8217;ve used it daily for a long time now. I don&#8217;t commit much to the repo anymore. The software is finished, more or less. I fixed an edge case in it a couple of weeks ago. I&#8217;m averaging a commit every two years since 2020. That&#8217;s the nice part about non-SaaS software. You can finish it. Nothing changes in the environment, and it&#8217;s not like any bug is a big deal. It&#8217;s running on your machine. You can&#8217;t steal someone else&#8217;s info if I make an error in the controller.</p><div><hr></div><p>Of course, there was really no point to this project. The number of budgeting and personal finance tools out there is endless. They are better documented, tested, and so on. I could&#8217;ve found something that worked well enough to not be worth the hours I spent on it.</p><p>But I had oodles of fun, and there&#8217;s the pride of making something useful.</p><p>I don&#8217;t know shit about fixing cars, so I have to find something else to do.</p><p>There&#8217;s this terrible piece of advice folks get. If someone&#8217;s already solved the problem, don&#8217;t re-solve it. Think about another problem worth solving. It&#8217;s bad advice. You can&#8217;t solve any problem until you learn enough about it.</p><p>The best way to learn how the wheel works is to reinvent it.</p><div><hr></div><p>Oh, and here&#8217;s the Github for this project: <a href="https://github.com/flynnzac/leas">leas.</a></p><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Please, subscribe! We even have a new logo! That means we&#8217;re a Real Newsletter! Please Subscribe!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Experiments and Gradient Descent]]></title><description><![CDATA[How to find the best version via iterative experiments via analogy to gradient descent]]></description><link>https://www.underthenull.com/p/experiments-and-gradient-descent</link><guid isPermaLink="false">https://www.underthenull.com/p/experiments-and-gradient-descent</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Fri, 19 Jun 2026 15:40:32 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1635776062360-af423602aff3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxncmFkaWVudHxlbnwwfHx8fDE3ODE4ODM0NzZ8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1635776062360-af423602aff3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxncmFkaWVudHxlbnwwfHx8fDE3ODE4ODM0NzZ8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1635776062360-af423602aff3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxncmFkaWVudHxlbnwwfHx8fDE3ODE4ODM0NzZ8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1635776062360-af423602aff3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxncmFkaWVudHxlbnwwfHx8fDE3ODE4ODM0NzZ8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1635776062360-af423602aff3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxncmFkaWVudHxlbnwwfHx8fDE3ODE4ODM0NzZ8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1635776062360-af423602aff3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxncmFkaWVudHxlbnwwfHx8fDE3ODE4ODM0NzZ8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1635776062360-af423602aff3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxncmFkaWVudHxlbnwwfHx8fDE3ODE4ODM0NzZ8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="5120" height="2880" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1635776062360-af423602aff3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxncmFkaWVudHxlbnwwfHx8fDE3ODE4ODM0NzZ8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2880,&quot;width&quot;:5120,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;abstract blurred dark and light gradient&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="abstract blurred dark and light gradient" title="abstract blurred dark and light gradient" srcset="https://images.unsplash.com/photo-1635776062360-af423602aff3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxncmFkaWVudHxlbnwwfHx8fDE3ODE4ODM0NzZ8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1635776062360-af423602aff3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxncmFkaWVudHxlbnwwfHx8fDE3ODE4ODM0NzZ8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1635776062360-af423602aff3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxncmFkaWVudHxlbnwwfHx8fDE3ODE4ODM0NzZ8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1635776062360-af423602aff3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxncmFkaWVudHxlbnwwfHx8fDE3ODE4ODM0NzZ8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@magicpattern">MagicPattern</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>This post will be about experimentation, but there&#8217;s a wind-up. </p><p>Today, we&#8217;re going to look at a class of experimentation problems that we might call &#8220;tuning.&#8221; A problem where there is a wide variety of plausible choices for a parameter, and we&#8217;re trying to find the best one among nearly infinite plausible choices.</p><p>Common parameters to optimize include:</p><ul><li><p>Price</p></li><li><p>Promotional Discounts</p></li><li><p>Hyperparameters of ML models (search, recommendations, etc.)</p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>Suppose you want to maximize a function <em>f(u,t)</em>. At any point in time, you know <em>f(u<sub>t</sub>, t),</em> but you can&#8217;t evaluate <em>f</em> at any other points but whatever <em>u</em> happens to be &#8220;active&#8221;. For example, you know your current prices (<em>u<sub>t</sub></em>) and you know revenue today, but you don&#8217;t know what revenue would be at other prices.</p><p>How do we learn the best <em>u</em> if we can only evaluate one <em>u</em> at a time?</p><p>Let&#8217;s think about it as an optimization problem:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\max f\\left(u, t\\right)&quot;,&quot;id&quot;:&quot;UKLCVRLJVC&quot;}" data-component-name="LatexBlockToDOM"></div><p>Suppose <em>f</em> is strictly concave in <em>u</em> and its gradient satisfies a Lipschitz condition (we&#8217;ve decided to be formal-ish today&#8212;suit and tie). Then, we could solve this problem via gradient descent, i.e.:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;u_{k+1} = u_{k} + a_{k} \\times D_{u} f\\left(u_{k}, t\\right)&quot;,&quot;id&quot;:&quot;SUMCJSLUPX&quot;}" data-component-name="LatexBlockToDOM"></div><p>For some suitable sequence of (a).</p><p>The problem is: we don&#8217;t know the derivative of <em>f,</em> and we don&#8217;t know how to evaluate <em>f</em> at other points.</p><p>The trick is that we can use experiments to iterate on the gradient descent problem. An experiment is just like computing the objective function and its gradient. It takes a few weeks to compute, though, and our data limits how many points we can compute at once.</p><p>The starting point is the relationship between treatment effects and derivatives in this context. Suppose <em>u</em> is a number (not a vector), and you expose half the population to <em>u</em> and the other half to <em>u+h</em>. Well, viola, you have an estimate of the derivative:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;D_{u} f = \\frac{f\\left(u+h, t\\right) - f\\left(u, t\\right)}{h} = \\frac{\\text{Treatment Effect}}{h}&quot;,&quot;id&quot;:&quot;LRKBPTVSPK&quot;}" data-component-name="LatexBlockToDOM"></div><p><em>[You can expand this to multi-dimensional u by adding more arms to the experiment or by adding structure to f that lets you learn other derivatives in a neighborhood of the current values of u you&#8217;re testing.]</em></p><div><hr></div><p>First, suppose <em>f</em> doesn&#8217;t depend on time, and also, for the sake of simplicity, <em>u</em> is not a vector. Then, the optimal <em>u </em>doesn&#8217;t change. It&#8217;s static. A stable target you&#8217;re trying to hit. Using the gradient descent analogy, we can try to find the best <em>u</em> like so:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;u_{t+1} = u_{t} + a \\times \\frac{f\\left(u_{t}+h\\right) - f\\left(u_{t}\\right)}{h}&quot;,&quot;id&quot;:&quot;DBVJUGFYWC&quot;}" data-component-name="LatexBlockToDOM"></div><p>When the treatment effect from increasing <em>u</em> is positive, increase <em>u</em>. When it is negative, decrease <em>u</em>, and so on.</p><p>There is a vast literature on step sizes that work for gradient descent with a strictly concave <em>f</em>. The key property we need is a method that doesn&#8217;t require us to evaluate the function at many points because experimentation limits the number of points we can evaluate. A straightforward approach to choose <em>a</em>, assuming <em>f</em> is strictly concave, using a modern &#8220;two-point&#8221; method from the literature that works for general concave functions, c/o <a href="https://arxiv.org/abs/2308.02261">Malitzky and Mischenko</a>:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;L_{t} = \\frac{|Df_{t} - Df_{t-1}|}{h}&quot;,&quot;id&quot;:&quot;PGXLOCXQTP&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;a_{t} = \\min\\left\\{ \\sqrt{\\frac{2}{3}  + \\frac{a_{t-1}}{a_{t-2}} } \\times a_{t-1}, \\frac{a_{t-1}}{\\sqrt{\\max\\left\\{2a_{t-1}^{2} L_{t}^{2} - 1, 0\\right\\}}} \\right\\}&quot;,&quot;id&quot;:&quot;GWQYAFQTVW&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>Where <em>Df<sub>t </sub></em>is the current derivative estimate, and <em>Df<sub>t-1</sub> </em>is the prior derivative estimate. I&#8217;ll call this the MM-rule. </p><p><em>[The MM-rule formula treats dividing by 0 as infinity, so you&#8217;ll always choose the other branch of the min{*,*}.]</em></p><p>The main advantage of making this choice instead of the classical gradient descent step size is that you don&#8217;t need to run experiments with a ton of arms to approximate the maximization problem:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\max_{0 \\le a \\le 1} f\\left(u + a D_{u}f\\right)&quot;,&quot;id&quot;:&quot;VJXCYWMCCD&quot;}" data-component-name="LatexBlockToDOM"></div><p>You&#8217;d operationalize this like so:</p><ol><li><p>Initially: Run an experiment with the status quo &#8220;champion&#8221; <em>u</em> vs a &#8220;challenger&#8221; <em>u + h</em>. Choose <em>h</em> large enough that you&#8217;ll see some real action statistically, but small enough that you&#8217;re reasonably approximating a derivative. Choose an arbitrary <em>a</em> to get a new challenger. The right choice here is a bit of an art, but it&#8217;s fine to just choose it so the treatment looks &#8220;reasonable.&#8221; This is just an initial condition.</p></li><li><p>Do this again to have enough initial conditions to start using the MM-rule.</p></li><li><p>Now, run the best arm of the previous experiment versus the new challenger generated by the MM-rule. </p></li><li><p>Keep iterating, using the MM-rule above. Repeat step 3 forever.</p></li></ol><p>The nice part about this method of experimentation is that it allows you to make careful, small but continuous iterations toward the truth instead of making large, costly attempts to jump to the optimal value (usually based on strong functional-form assumptions). You&#8217;re always testing your latest proposal against the data, so you can&#8217;t drift too far.</p><p>Practical issues you&#8217;ll run into: the formula for <em>a </em>might produce too small of a step size for you to see any real action. The treatments are too close together. It&#8217;s fine to put a lower bound on step size, even if it violates some guarantee of convergence. The precision the optimizers look for isn&#8217;t attainable if we&#8217;re estimating functions from noisy data.</p><div><hr></div><p>Now, what if the function&#8217;s value changes over time, i.e., we have <em>f(u,t)</em>? That&#8217;s why we&#8217;d run experiments in the first place, instead of choosing different <em>u</em>&#8217;s and trying them out to trace out the function. We need to run experiments because otherwise we&#8217;ll confuse variation in different <em>u&#8217;s</em> for variation in <em>t</em>.</p><p>When we experiment, we learn:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{treatment effect} = f\\left(u + h, t\\right) - f\\left(u, t\\right)&quot;,&quot;id&quot;:&quot;JAQBAURZTB&quot;}" data-component-name="LatexBlockToDOM"></div><p>So, we can trace out the derivative with respect to <em>u </em>from<em> </em>the data, as in the static function case, but the optimal <em>u</em> we&#8217;re chasing is changing as well.</p><p>I&#8217;m proposing using the same algorithm above to solve the problem when <em>t</em> changes the function (and so, the optimal <em>u</em>)&#8212;with a small twist. </p><p>Of course, if we&#8217;re completely general about how <em>t</em> changes <em>f,</em> this approach won&#8217;t work, because the optimal <em>u</em> could jump around wildly, but that&#8217;s not really what we think will happen.</p><p>Essentially, we&#8217;re going to assume that the optimal <em>u</em> varies &#8220;slow enough&#8221; with <em>t</em> that we can track it by accounting for changes in the gradient with respect to <em>u</em>.  </p><p>The main practical change is that the MM-rule now depends on function values that we can&#8217;t just keep in memory. We need to evaluate the gradients of <em>f(*,t),</em> not the gradients we previously computed of <em>f(*,t-1)</em>. So, here&#8217;s my simple, practical iteration strategy:</p><ol><li><p>Run a four-arm experiment. The experiment has <em>u<sub>t</sub> </em>(the current iteration)<em>, u<sub>t-1</sub> </em>(the previous iteration), <em>u<sub>t</sub> + h</em>, and <em>u<sub>t-1</sub> + h<sub> </sub> </em>(the h&#8217;s can be different if you&#8217;d like).</p></li><li><p>Use the results of this experiment to construct <em>L<sub>t</sub></em>.</p></li><li><p>Now, if you look at the formula, you&#8217;ll see that technically it depends on <em>a<sub>t</sub> </em>all the way back and prior <em>L<sub>t</sub>&#8217;s </em>that are function evaluations will have been evaluated on <em>f(*,t-2)</em>, for example, instead of <em>f(*,t)</em>. My sort of pragmatic approach here is to ignore that and use the old <em>a<sub>t</sub>&#8217;s </em>where they appear as they were when you computed them.</p></li></ol><p>I think this is a reasonable, practical tradeoff to avoid exploding the number of arms the experiment needs while still accounting for the fact that the function has changed, moving from <em>t-1</em> to <em>t.</em></p><div><hr></div><p>Experimentation can test more than button colors. We can use it to understand the models that drive the modern biz. Models that target certain customers with promotional offers or specifically tailored marketing strategies. The number of <em>reasonable</em> models is vast, and finding the right one requires forcing proposed models to confront the truth about their performance. Experiments provide the ground truth and structure the search. It&#8217;s a nice pairing.</p><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Please subscribe! You will be contributing to the maximization of my objective function. Is there any greater gift?</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Shocking Results Need Mundane Assumptions]]></title><description><![CDATA[The rule for persuasive analyses]]></description><link>https://www.underthenull.com/p/shocking-results-need-mundane-assumptions</link><guid isPermaLink="false">https://www.underthenull.com/p/shocking-results-need-mundane-assumptions</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Fri, 12 Jun 2026 14:13:23 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1754460916460-94693498b3d1?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyMXx8bXVuZGFuZXxlbnwwfHx8fDE3ODEyNzMwNDN8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1754460916460-94693498b3d1?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyMXx8bXVuZGFuZXxlbnwwfHx8fDE3ODEyNzMwNDN8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1754460916460-94693498b3d1?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyMXx8bXVuZGFuZXxlbnwwfHx8fDE3ODEyNzMwNDN8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1754460916460-94693498b3d1?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyMXx8bXVuZGFuZXxlbnwwfHx8fDE3ODEyNzMwNDN8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1754460916460-94693498b3d1?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyMXx8bXVuZGFuZXxlbnwwfHx8fDE3ODEyNzMwNDN8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1754460916460-94693498b3d1?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyMXx8bXVuZGFuZXxlbnwwfHx8fDE3ODEyNzMwNDN8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1754460916460-94693498b3d1?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyMXx8bXVuZGFuZXxlbnwwfHx8fDE3ODEyNzMwNDN8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="4096" height="4096" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1754460916460-94693498b3d1?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyMXx8bXVuZGFuZXxlbnwwfHx8fDE3ODEyNzMwNDN8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:4096,&quot;width&quot;:4096,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Building's facade with many windows and shadows.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Building's facade with many windows and shadows." title="Building's facade with many windows and shadows." srcset="https://images.unsplash.com/photo-1754460916460-94693498b3d1?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyMXx8bXVuZGFuZXxlbnwwfHx8fDE3ODEyNzMwNDN8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1754460916460-94693498b3d1?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyMXx8bXVuZGFuZXxlbnwwfHx8fDE3ODEyNzMwNDN8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1754460916460-94693498b3d1?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyMXx8bXVuZGFuZXxlbnwwfHx8fDE3ODEyNzMwNDN8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1754460916460-94693498b3d1?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyMXx8bXVuZGFuZXxlbnwwfHx8fDE3ODEyNzMwNDN8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@mikehindle">Mike Hindle</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>All analyses rely on assumptions to map datasets to conclusions. The data doesn&#8217;t speak for itself. You have to shape it. Ideally, the mold you fit the data into is based on a reasonable theory of how the world works. </p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/subscribe?"><span>Subscribe now</span></a></p><p>Analysis is a trick to, with enough data, reduce the world to two potential outcomes:</p><ol><li><p>The analysis&#8217;s conclusion is true.</p></li><li><p>OR: the assumptions of the analysis are wrong.</p></li></ol><p>This is <em>very</em> useful. It moves the conversation forward. Folks can&#8217;t just disagree with your conclusions. They have to disagree with your assumptions, too.</p><p>Therefore,<em>  </em>an analysis is persuasive only if your <em>assumptions</em> are more plausible than your conclusions. </p><p>If your assumptions are more plausible than your conclusions, then disagreeing with the conclusion becomes more difficult after the analysis. Before I could argue against the conclusion directly. Now, I have to argue against the assumptions, which are harder to dispute.</p><p>But if your assumptions are <em>less</em> plausible than your conclusions, then <strong>you haven&#8217;t convinced me. </strong>After the analysis, I know either the conclusion is true, or your assumptions are wrong. If I disagreed with the conclusion before, and it is even easier for me to disagree with your assumptions, it is just as easy to disagree with you as it was before your analysis*.</p><div><hr></div><p>There&#8217;s a famous paper in empirical labor economics that illustrates this. </p><p><a href="https://davidcard.berkeley.edu/papers/njmin-aer.pdf">Card and Krueger (1994) claim to show no effect of a minimum wage increase on unemployment.</a></p><p>They do so using a difference-in-differences analysis of bordering counties in Pennsylvania and New Jersey after New Jersey raised its minimum wage. The idea is that these counties are similar to each other and face similar shocks, except that the New Jersey counties received a higher minimum wage. Card and Krueger look at changes in employment and find a small, positive, but insignificant effect. The conclusion is that the minimum wage increase did not cause unemployment. Politicians frequently cite the paper to draw the much broader conclusion that minimum wage increases don&#8217;t, more generally, cause unemployment. </p><p>It isn&#8217;t a <em>persuasive</em> analysis. It&#8217;s further confirmation to the believer, but it won&#8217;t convert anyone. </p><p>Suppose that, prior to the analysis, I disagree with the idea that labor demand is flat or upward-sloping. Now, after the analysis, you tell me: either you have to believe that demand is flat or upward-sloping, <em>or</em> you can believe that these New Jersey and Pennsylvania counties are not really comparable.</p><p>Of course, I&#8217;m going to conclude that these counties aren&#8217;t really comparable. If I have to choose between &#8220;People don&#8217;t care how much they pay for things&#8221; and &#8220;These counties aren&#8217;t comparable in some subtle way. Maybe another policy or shock that happened at around the same time wasn&#8217;t distributed evenly across New Jersey and Pennsylvania counties. Maybe these counties are just wholly incomparable because of a long history of differences in policy and polity between the two states that change how they respond to various shocks. Maybe a silly shock that we&#8217;ll never understand happened. Maybe the unemployment effect is delayed because of adjustment frictions.&#8221; All of those explanations are more credible and convincing to me than &#8220;people don&#8217;t care about how much they pay for things.&#8221;</p><p>So, the study fails to convince anyone. Proponents of a higher minimum wage like the study, but they don&#8217;t need to be convinced by it. Sometimes academic economists who find themselves in policy roles where they need to pretend to like minimum wages might find it useful as air cover to explain away past writing that says minimum wages cause unemployment. &#8220;Oh, I used to think minimum wages were bad, but then I read Card and Kreuger.&#8221; Hot take: No true believer in downward-sloping demand curves has ever been convinced by this. It&#8217;s so much easier to conclude that parallel trends don&#8217;t really hold or the post period isn&#8217;t long enough to see the effect than to invalidate a simple, powerful economic theory on the basis of a diff-in-diff.</p><div><hr></div><p>This isn&#8217;t to argue about an economics paper from more than thirty years ago. It&#8217;s to demonstrate that:</p><p>Shocking results need mundane assumptions to convert new folks to your way of thinking.</p><p>We should be credibility-maxing?</p><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p><p>*This point isn&#8217;t about Bayes&#8217; rule. I understand how my joint prior over the assumptions and conclusions might cause my posterior beliefs about the conclusion to change, even if I view the assumption as less credible than the conclusion in terms of my prior&#8217;s marginal distributions. It&#8217;s an argument about how people are actually convinced, i.e., I don&#8217;t have a tightly constructed joint prior distribution over the likelihood of New Jersey and Pennsylvania counties being comparable and the slope of the labor demand curve. I weigh how plausible the assumptions are and how plausible I think the conclusion is, and that determines whether I end up convinced by the analysis to change my mind. </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Please subscribe!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Two Good Things: 2026-06-05]]></title><description><![CDATA[Bathhouses and AI IPOs]]></description><link>https://www.underthenull.com/p/two-good-things-2026-06-05</link><guid isPermaLink="false">https://www.underthenull.com/p/two-good-things-2026-06-05</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Fri, 05 Jun 2026 22:42:57 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1664580534860-2c0c909644d8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxsYWtlJTIwbWljaGlnYW58ZW58MHx8fHwxNzgwNjk5MTc5fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1664580534860-2c0c909644d8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxsYWtlJTIwbWljaGlnYW58ZW58MHx8fHwxNzgwNjk5MTc5fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1664580534860-2c0c909644d8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxsYWtlJTIwbWljaGlnYW58ZW58MHx8fHwxNzgwNjk5MTc5fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1664580534860-2c0c909644d8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxsYWtlJTIwbWljaGlnYW58ZW58MHx8fHwxNzgwNjk5MTc5fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1664580534860-2c0c909644d8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxsYWtlJTIwbWljaGlnYW58ZW58MHx8fHwxNzgwNjk5MTc5fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1664580534860-2c0c909644d8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxsYWtlJTIwbWljaGlnYW58ZW58MHx8fHwxNzgwNjk5MTc5fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1664580534860-2c0c909644d8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxsYWtlJTIwbWljaGlnYW58ZW58MHx8fHwxNzgwNjk5MTc5fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="8000" height="6000" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1664580534860-2c0c909644d8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxsYWtlJTIwbWljaGlnYW58ZW58MHx8fHwxNzgwNjk5MTc5fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:6000,&quot;width&quot;:8000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;a log on a beach&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="a log on a beach" title="a log on a beach" srcset="https://images.unsplash.com/photo-1664580534860-2c0c909644d8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxsYWtlJTIwbWljaGlnYW58ZW58MHx8fHwxNzgwNjk5MTc5fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1664580534860-2c0c909644d8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxsYWtlJTIwbWljaGlnYW58ZW58MHx8fHwxNzgwNjk5MTc5fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1664580534860-2c0c909644d8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxsYWtlJTIwbWljaGlnYW58ZW58MHx8fHwxNzgwNjk5MTc5fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1664580534860-2c0c909644d8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxsYWtlJTIwbWljaGlnYW58ZW58MHx8fHwxNzgwNjk5MTc5fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@mmhinton">Mary Hinton</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>Ever since <a href="https://www.underthenull.com/p/i-want-to-get-good">I decided to blog well</a>, I&#8217;ve been trying to figure out the right way to write a good &#8220;links&#8221; article. All the cool kids on Substack do it, and I read the Internet. I told myself I ought to be able to do it too. Two statistics blogs and one links blog a week sounded plausible.</p><p>Like most things, though, links blogs looked so easy to get right until I tried to do it. So, we&#8217;re experimenting with formats. I think I like this one. Two Good Things. Two stories or clips that I think our worth consuming this week. We&#8217;ll get there eventually.</p><p>This one has bathhouses and AI skeptics.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2>Bathhouses</h2><p><a href="https://residualthoughts.substack.com/p/bathhouse-economics">Joe Hovde has a great blog on this company called Bathhouse.</a> It&#8217;s a public sauna trying to become a third place&#8212;presumably, for the kinds of people who feel comfortable less-than-clothed around strangers: hot people. </p><p>A little trend. I&#8217;ve noticed that proposed Third Places end up getting accused of being cults&#8212;which is natural. They&#8217;re trying to replace the Church or the Bar. A Third Place has to have aspects of religion or addiction to satisfy the human need for connection via transcendence or dependency. </p><p>I don&#8217;t see it crossing generations, but fingers-crossed for them. That&#8217;s the key to a successful Third Place. There&#8217;s always the old guy at the Bar and the kids with fake ID&#8217;s. Church has Sunday school and funerals. Even coffee shops&#8212;when those were a bigger deal&#8212;cross generations. At least <a href="https://www.abathhouse.com/">the marketing makes it look like a young single thing</a>? </p><p>The website has an &#8220;AI Search&#8221; feature.</p><p>In any case, the article&#8217;s a great dive into the business and a category I didn&#8217;t know existed before. Check it out.</p><p>[<a href="https://residualthoughts.substack.com">I dig this blog in general, by the way.</a> It&#8217;s always got some interesting dive into an industry I either don&#8217;t know much about or don&#8217;t know enough about. Good place to learn stuff.]</p><div><hr></div><h2>&#8220;[LLM Companies] Shouldn&#8217;t Be Allowed to IPO&#8221;</h2><p><a href="https://www.youtube.com/watch?v=zbKDmkJPVvI">I thought this segment on Bloomberg with Ed Zitron where he hates on AI and AI companies was entertaining, if not persuasive.</a> </p><p>Mr. Zitron doesn&#8217;t like AI or AI companies, but he has much stronger arguments for the Company&#8217;s IPO prospects than the Product and he kind of mixes the two willy-nilly. </p><p>The part he&#8217;s probably right about is that no one has a great business model yet for how to make money by supplying LLMs (or maybe the market structure just isn&#8217;t right yet to do it: you can&#8217;t get enough of a margin), and the set of tasks LLMs are good at is much smaller than the AI-positive discourse admits. </p><p>Folks are allowed/encouraged/threatened to use AI, and, for many tasks, the price of the tokens is still way more than the value delivered by the LLM. That&#8217;s how you get places that had never used AI until a couple years ago, burning millions of dollars to let folks spin up questionable (but expensive) dashboards without knowing SQL or save some Engineer a few (very expensive) hours.</p><p>The part he&#8217;s (super?) wrong about is this whole idea he often puts out there that the LLM product itself is bad-to-useless.  There are <a href="https://www.underthenull.com/p/effort-post-automation-knowledge">nuanced takes on how LLMs can reduce productivity (by yours truly)</a> because workers will substitute towards the LLMs and away from effort even for tasks where effort is more productive than LLMs, but there are other tasks where LLMs absolutely deliver strong productivity gains. </p><p>I do not want to go back to debugging without LLMs. </p><p>I spent the last weekend debugging this side project (a Rails app), and it would have taken much longer and been so much worse if it had just been me searching for bugs, writing tests, etc, instead of using Codex. I think I spent around 20 hours debugging the app with Codex (i.e. not just prompting &#8220;fix all bugs, make no mistakes&#8221; like you hear from some portions of the internet&#8230;). It easily would have taken me a few weeks without it, and it probably wouldn&#8217;t have been done to the same quality because I&#8217;m human, and I miss stuff (edge-cases, various long strings of scenarios that cause odd state X, etc). </p><p>The LLMs are a little like chess computers when it comes to debugging. Humans miss possible moves in chess all the time&#8212;even grandmasters miss mates-in-one in short time control games. Finding all possible one-shot moves on an 8x8 grid is a trivial problem for a computer, though. Similarly, LLMs can come up with ways in which someone could get something funky by hitting a certain string of endpoints much better than my feeble, meatsack mind.</p><p>That being said, it is definitely true, and this is Ed&#8217;s main point: the value of debugging code, formatting docs, etcetera does not justify the stratospheric level of capital and debt being loaded into these AI Labs. They kind of have to create God or at least replace Raytheon. </p><p>I might like (very much) being able to type &#8220;replace all my poorly-formatted math in this doc with well-formatted math,&#8221; but I&#8217;m not willing to pay much for it. I doubt it drives significant company revenue. Or, for example, with the above experience, debugging a web app:</p><p>I did it all in Codex (Free).</p><p>Yeah, so it was free for me. It wasn&#8217;t close to free for OpenAI, I&#8217;m sure. How much would I have paid? Not much. It&#8217;s just a little side project. If it was a major potential revenue stream? I guess I&#8217;d pay a thou or so for access to debugging for a month or something? But I doubt I&#8217;d have to. Competition is still too intense. I&#8217;d just substitute to Gemini or Claude. So prices stay low&#8230;</p><p>Until the shakeout stage of the industry (<a href="https://www.jstor.org/stable/2118212">start here for industry lifecycle literature</a>).</p><p>I think two things are true:</p><ol><li><p>LLMs are super valuable.</p></li><li><p>LLMs are over-valued.</p></li></ol><p>But they won&#8217;t both be true when the market for Anthropic&#8217;s future dividends becomes liquid and well-informed&#8230; </p><p>I hope the S-1 becomes public in time for beach reading.</p><p>Yes, we do have beaches. Lake Michigan counts.</p><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Please, subscribe! My margins are negative&#8212;just like the LLMs! It&#8217;s free! </p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Good Metrics Maximize Surprise]]></title><description><![CDATA["Let it surprise you."]]></description><link>https://www.underthenull.com/p/good-metrics-maximize-surprise</link><guid isPermaLink="false">https://www.underthenull.com/p/good-metrics-maximize-surprise</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Wed, 03 Jun 2026 18:54:09 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1603792907191-89e55f70099a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxzdXJwcmlzZXxlbnwwfHx8fDE3ODA1MDk3OTR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1603792907191-89e55f70099a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxzdXJwcmlzZXxlbnwwfHx8fDE3ODA1MDk3OTR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1603792907191-89e55f70099a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxzdXJwcmlzZXxlbnwwfHx8fDE3ODA1MDk3OTR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1603792907191-89e55f70099a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxzdXJwcmlzZXxlbnwwfHx8fDE3ODA1MDk3OTR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1603792907191-89e55f70099a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxzdXJwcmlzZXxlbnwwfHx8fDE3ODA1MDk3OTR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1603792907191-89e55f70099a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxzdXJwcmlzZXxlbnwwfHx8fDE3ODA1MDk3OTR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1603792907191-89e55f70099a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxzdXJwcmlzZXxlbnwwfHx8fDE3ODA1MDk3OTR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="9338" height="6226" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1603792907191-89e55f70099a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxzdXJwcmlzZXxlbnwwfHx8fDE3ODA1MDk3OTR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:6226,&quot;width&quot;:9338,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;man in white dress shirt wearing black framed eyeglasses&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="man in white dress shirt wearing black framed eyeglasses" title="man in white dress shirt wearing black framed eyeglasses" srcset="https://images.unsplash.com/photo-1603792907191-89e55f70099a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxzdXJwcmlzZXxlbnwwfHx8fDE3ODA1MDk3OTR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1603792907191-89e55f70099a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxzdXJwcmlzZXxlbnwwfHx8fDE3ODA1MDk3OTR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1603792907191-89e55f70099a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxzdXJwcmlzZXxlbnwwfHx8fDE3ODA1MDk3OTR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1603792907191-89e55f70099a?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxzdXJwcmlzZXxlbnwwfHx8fDE3ODA1MDk3OTR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@krakenimages">krakenimages</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>A/B tests don&#8217;t have to be Experiments. You can use them for other purposes. Corporate political propaganda, for example. Like when politicians cite random studies they haven&#8217;t read on a &#8220;debate&#8221; stage, the point isn&#8217;t the study itself. It&#8217;s the conclusion. </p><p>No judgment. Politics has its place.</p><p>The difference between an Experiment and Propaganda is whether you want to learn something or convince someone. </p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/subscribe?"><span>Subscribe now</span></a></p><p>If you want to convince someone, you will choose metrics that are all but guaranteed to go in a certain direction.</p><p>For example, you might remove a screen from a checkout flow and make your metric &#8220;time spent in checkout.&#8221; Of course, the time spent will go down. You already knew that before running the experiment. You&#8217;re building up a case for your preferred product direction, the one that hits your OKR. Not running an Experiment.</p><p>If you were running an Experiment, you&#8217;d want to know: what do we lose by dropping that screen? What do we gain by dropping it? What metric can I develop that lets both the positives and negatives of dropping the screen shine through, their relative light depending only on how customers behave? Maybe the extra information from the extra screen is worth nothing. Maybe it is everything. The choice of metric should not assume either. It should allow for both cases and let customer behavior decide.</p><p>In other words: Experiment metrics <em>maximize surprise</em>. Propaganda metrics minimize it.</p><p>Suppose you want to learn something. How do you go about finding a metric? </p><p>In the screen-drop example&#8230; Suppose the extra screen asks the customer for a bit more information about why they purchased the product. Maybe that information feeds later personalization or targeted messages to get the customer to buy again or subscribe or otherwise take the next step in their journey. It&#8217;ll always be something like this. It&#8217;s not like the extra-screen was just thrown in there willy-nilly. The folks who added it did so for a reason. We should know why before we knock it down.</p><p>We don&#8217;t want to use the probability of making it to the end of checkout because, of course, taking away extra screens helps with that. </p><p>We also don&#8217;t want the metric to be a conversion rate of users to taking the next step. Of course that&#8217;s going to fall. The extra screen makes the ad-targeting better.</p><p>What we want is a metric that could go either way.</p><p>For example, the <em>joint</em> probability of both completing the checkout and taking the next step&#8212;not the conditional probability. </p><p>If the conditional probability of taking the next step falls, but the number of customers who take the next step increases, then dropping the screen makes sense. You&#8217;re improving the probability of checking out without dropping the probability that a top-of-funnel visitor gets to the final stage of the journeys, even though targeting gets worse. </p><p>If these two steps have different economic models associated with them (maybe the checkout is the Basic subscription and the extra-screen provides information used to market Premium to the user), then make the metric take that into account. Give each one a dollar value and try to maximize expected dollars. </p><p>The point is to get the tradeoff in there. We&#8217;re making a move that increases the pr(checkout) and decreases the pr(premium | checkout). So we want to know whether pr(checkout, premium) = pr(checkout) x pr(premium|checkout) increases. We&#8217;re surprised either way because, while we know pr(checkout) will increase and pr(premium | checkout) will decrease, we don&#8217;t know the net effect.</p><p>So, we&#8217;ve set up our experiment metrics to learn something, and, along the way, we&#8217;ve figured out exactly what we&#8217;re uncertain about on the product-side. That&#8217;s the right way to select metrics. Like most problems, it can be solved by the algorithm:</p><ol><li><p>Write down we know.</p></li><li><p>Write down what we don&#8217;t know.</p></li><li><p>Experiment to bridge the gap.</p></li></ol><p>When I was but a wee lad learning to shoot, my dad told me the trick was to &#8220;Let it surprise you.&#8221; If we anticipate what&#8217;ll happen when we pull the trigger, we won&#8217;t hit the target. </p><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Please subscribe! Subscribing maximizes the probability of seeing this post - which is (clearly) the most important Metric!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Effort Post: Automation, Knowledge Work, Uncertainty, and AI (Part 1)]]></title><description><![CDATA[A production model where LLMs act as pure, effort-saving automation machines (more models upcoming!)]]></description><link>https://www.underthenull.com/p/effort-post-automation-knowledge</link><guid isPermaLink="false">https://www.underthenull.com/p/effort-post-automation-knowledge</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Mon, 01 Jun 2026 02:11:03 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1527430253228-e93688616381?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxyb2JvdHxlbnwwfHx8fDE3ODAwODIwNzl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1527430253228-e93688616381?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxyb2JvdHxlbnwwfHx8fDE3ODAwODIwNzl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1527430253228-e93688616381?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxyb2JvdHxlbnwwfHx8fDE3ODAwODIwNzl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1527430253228-e93688616381?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxyb2JvdHxlbnwwfHx8fDE3ODAwODIwNzl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1527430253228-e93688616381?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxyb2JvdHxlbnwwfHx8fDE3ODAwODIwNzl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1527430253228-e93688616381?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxyb2JvdHxlbnwwfHx8fDE3ODAwODIwNzl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1527430253228-e93688616381?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxyb2JvdHxlbnwwfHx8fDE3ODAwODIwNzl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="6000" height="3368" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1527430253228-e93688616381?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxyb2JvdHxlbnwwfHx8fDE3ODAwODIwNzl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3368,&quot;width&quot;:6000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;blue plastic robot toy&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="blue plastic robot toy" title="blue plastic robot toy" srcset="https://images.unsplash.com/photo-1527430253228-e93688616381?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxyb2JvdHxlbnwwfHx8fDE3ODAwODIwNzl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1527430253228-e93688616381?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxyb2JvdHxlbnwwfHx8fDE3ODAwODIwNzl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1527430253228-e93688616381?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxyb2JvdHxlbnwwfHx8fDE3ODAwODIwNzl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1527430253228-e93688616381?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxyb2JvdHxlbnwwfHx8fDE3ODAwODIwNzl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@emilipothese">Emilipoth&#232;se</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>Production functions matter. They describe how firms or people turn raw inputs into outputs, i.e., technology. They constrain what&#8217;s possible, like demand determines what&#8217;s preferable.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/subscribe?"><span>Subscribe now</span></a></p><p>Most empirical work on production functions in economics looks at manufacturing, agriculture, or resource production because their inputs and outputs are easier to measure. But knowledge work is the first job class to be altered by the LLMs. Codex isn&#8217;t building bridges anytime soon. So, modeling how knowledge workers produce output and how LLMs affect production matters, but I don&#8217;t have any data to work with...</p><p>We can learn a lot from theory, though&#8230;</p><p>LLMs take context (human knowledge) and use it to generate output effortlessly. Without LLMs, humans would still provide their knowledge input, but they also need to supply elbow grease: effort. This blog will show that uncertainty about the best way to do things&#8212;and the option to apply effort to counteract that uncertainty&#8212;drives how LLMs influence technology choice, production, and the returns to more accurate beliefs.</p><p>The plan is for this to be a multi-part blog series with different models of how LLMs transform human context into output. </p><p>This post treats LLMs as pure automation machines. They take instructions from a human and act just like a human would, <em>but </em>they save the human significant effort.</p><p>The key part of the theory is the role of &#8220;uncertainty&#8221; in how best to do tasks. It turns out to be critical for understanding the role of LLMs in knowledge production work. We&#8217;ll show the following about how uncertainty changes the role of LLMs:</p><ul><li><p>For low-uncertainty tasks, workers will use LLMs, which will reduce the time it takes to complete a task or improve the quality of their output.</p></li><li><p>For moderate-uncertainty tasks, workers will use LLMs, which will <em>increase</em> the time it takes to complete a task or <em>reduce</em> the quality of their output. The worker&#8217;s preferred technology will not produce the best output.</p></li><li><p>For high uncertainty tasks, workers will NOT use LLMs. Instead, they will use more effort to counteract their uncertainty.</p></li></ul><h2>Production without LLMs</h2><p>Suppose a task can be completed in a certain amount of time, determined (without LLMs) by how smartly people decide to do the task, and the amount of effort they put in to get it done. </p><p><em>[You can think of &#8220;time&#8221; more abstractly as the inverse of &#8220;quality&#8221;, where lower time is equivalent to higher quality output, etc. But I&#8217;m going to stick to the strict time metaphor for ease of following the model.]</em></p><p><em>s</em> is the best way to do a task, but it is unknown. Knowledge workers have beliefs (knowledge) about how best to do things, given by:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;s \\sim N(m, v)&quot;,&quot;id&quot;:&quot;NKRMGYZJMY&quot;}" data-component-name="LatexBlockToDOM"></div><p>Without LLMs, the time it takes a knowledge worker to do a given task is given by:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;t = \\frac{(z - s)^{2} }{e}\n&quot;,&quot;id&quot;:&quot;ADQVKNDVQI&quot;}" data-component-name="LatexBlockToDOM"></div><p>Where <em>z</em> is the way the knowledge worker decides to do things, and <em>e</em> is the amount of effort they put in.</p><p>Knowledge workers care about doing a good job, but they also don&#8217;t like to put in effort. They choose their effort and the way they want to do the task to solve this problem:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\min_{z, e} \\frac{\\mathbb{E}[(z - s)^{2}] }{e} + \\frac{1}{2} e^{2}&quot;,&quot;id&quot;:&quot;IVNGFQCCSP&quot;}" data-component-name="LatexBlockToDOM"></div><p>The expectation is with respect to the knowledge worker&#8217;s subjective knowledge of the best way to do things. Because the expectation minimizes the square loss, the best <em>z</em> will always be <em>m</em>. By definition, <em>E[(s-m)<sup>2</sup>] = v</em>. Because this problem is convex for positive <em>e</em>, we can solve for the effort level from the first order conditions:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;-\\frac{v}{e^{2}} + e = 0 \\implies e^{3} = v \\implies e^{\\star} = v^{1/3}.&quot;,&quot;id&quot;:&quot;ZZICDNPHEJ&quot;}" data-component-name="LatexBlockToDOM"></div><p>So, at a high level, uncertainty defines effort. The more uncertain we are, the more effort humans supply to guard against unexpectedly large errors in the course of action they decide to take.</p><p>Therefore, the (objective) time it takes a given worker to do a task without an LLM is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;t = v^{-1/3} \\times (m - s)^{2}&quot;,&quot;id&quot;:&quot;JMOJYOSORI&quot;}" data-component-name="LatexBlockToDOM"></div><h2>LLMs as pure automation machines</h2><p>LLMs work by receiving context from humans. Humans can transmit their beliefs to LLMs as context, and then the LLM decides what to do with it, i.e., the LLM production technology is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;t = \\frac{(f(m,v) - s)^{2}}{a}&quot;,&quot;id&quot;:&quot;HJYVPPUZRI&quot;}" data-component-name="LatexBlockToDOM"></div><p>Where <em>a</em> gives the equivalent effort level of the LLM&#8217;s output. It measures the LLM&#8217;s accuracy or performance and might be captured directly by how long it takes to coach the LLM on exactly what you want it to do or on the quality of the output it produces.</p><p>Our first model of LLM production is what I&#8217;ll call &#8220;the pure automation model.&#8221; In this model, the LLM performs the task in the same way a knowledge worker would, but effortlessly. It doesn&#8217;t have its own beliefs. You tell it what you want done, and it does it. So: <em>f(m,v) = m</em>, because you&#8217;ll choose to tell it to minimize the expected time given your beliefs, and the (objective) time it takes to complete the task with an LLM is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;t_{LLM} = \\frac{(m - s)^{2}}{a}&quot;,&quot;id&quot;:&quot;XBZUJUKUUN&quot;}" data-component-name="LatexBlockToDOM"></div><p>It&#8217;s a simple model, but it actually has some semi-non-obvious predictions.</p><h2>Workers choose to use LLMs when they are MORE certain of the best way to do things</h2><p>Workers choose to use LLMs-as-automation when they are more certain about how to do things. </p><p>The result follows from effort substituting for uncertainty. Workers can put in more effort to mitigate their uncertainty when using the non-LLM technology, but the LLM technology doesn&#8217;t respond to their effort.</p><p>So, workers choose to use LLMs-as-automation whenever their uncertainty about the best way to do things is low enough:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;2v^{2/3} \\ge \\frac{v}{a} \\iff \\left(2a\\right)^{3} \\ge v&quot;,&quot;id&quot;:&quot;GAGROBASDW&quot;}" data-component-name="LatexBlockToDOM"></div><p>So, with the introduction of LLMs, only the more ambiguous tasks will be done by the effort technology, and, as the effectiveness of LLMs (<em>a</em>) increases, more and more ambiguous tasks will be done via LLM.</p><h2>The time to complete tasks increases for some workers when they have the LLM option</h2><p>This result is &#8220;obvious&#8221; when you write down a model like this, but not clear at all without actually writing down the math. The key idea is simple, though:</p><p>Workers want to avoid spending effort, so they will choose to use LLMs even if the effort technology is faster than the LLM technology.</p><p>We already have the rule for when workers will choose to use LLMs. So, to characterize when LLMs increase the time a task takes, we need to look at the conditions under which LLMs are slower:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;v^{-1/3} (s - m)^{2} \\le (s-m)^{2} a^{-1} \\iff a^{3} \\le v&quot;,&quot;id&quot;:&quot;OAWUMRSUVX&quot;}" data-component-name="LatexBlockToDOM"></div><p>So, for <em>v = 2a<sup>3</sup>, </em>the LLM method of production is <em>slower,</em> but workers choose to use it (because <em>2a<sup>3</sup> &lt; 8a<sup>3</sup></em>); otherwise, they have to pay the effort cost. Folks don&#8217;t just try to minimize time (equivalently, maximize output quality).</p><p>For a moderate level of uncertainty, i.e., for <em>a<sup>3</sup> &lt; v &lt; 8a<sup>3</sup>, </em>knowledge workers choose to use LLMs despite the longer task times (equivalently, lower-quality output) they entail.</p><p>This production model is static, but it implies something about dynamics. If AI quality (<em>a)</em> improves only slowly, some industries stall in this middle ground, where workers choose to use the LLM technology, but it gives worse/less output. Firms using the effort technology outcompete them. So, AI adoption is quick in industries defined by moderate ambiguity about how best to do things for firms that make it readily available to their workforce. AI adopters lose out to the Reactionaries: firms that force workers to use the effort technology and refuse to pay Anthropic or OpenAI.</p><h2>Automation LLMs decrease the returns to accuracy if uncertainty is low</h2><p>Do more skilled workers do better or worse with the option to use LLMs? Do LLMs compress the productivity distribution, allowing less-skilled (maybe early-career) workers to catch up to more skilled workers&#8212;or do they widen the gap between the skilled and the less-skilled?</p><p>Suppose everyone has the same level of uncertainty (the same <em>v</em>). Then we can define more skilled workers as those with a smaller <em>d = (m - s)<sup>2</sup>.</em></p><p>Shrinking <em>d</em> decreases time by <em>v<sup>(-1/3)</sup> </em>for the effort technology and by <em>a<sup>-1</sup> </em>for the LLM technology. So the reduction in time from more accurate prediction is greater for LLMs if:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;a^{-1} \\ge v^{-1/3} \\iff v \\ge a^{3}&quot;,&quot;id&quot;:&quot;GTIULFCWNG&quot;}" data-component-name="LatexBlockToDOM"></div><p>This is the same as the rule for when LLMs are slower. So, for highly uncertain tasks, the return to skill is greater for the LLM technology than for the effort technology. For low-uncertainty tasks, the return to skill is greater for the effort technology.</p><p>If we incorporate the choice constraint into this, we can partition the results like so:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{array}{c c c}\n&amp; \\text{Tech Choice} &amp; \\text{Return to Skill} \\\\\n\\hline\nv < a^{3} &amp; \\text{LLM} &amp; a^{-1}\\\\\na^{3} < v < 8a^{3} &amp; \\text{LLM} &amp; a^{-1}\\\\\nv > 8a^{3} &amp; \\text{Effort} &amp; v^{-1/3}\\\\\n\\hline\n\\end{array}&quot;,&quot;id&quot;:&quot;IHFVVTOKFU&quot;}" data-component-name="LatexBlockToDOM"></div><p>Without LLMs, the return to skill would always be <em>v<sup>-1/3</sup></em>. LLMs <em>increase</em> the return to skill for moderate uncertainty but do not affect it for high-uncertainty tasks (because workers choose effort over LLMs). For low-uncertainty tasks, LLMs are faster than the effort technology <em>and</em> reduce the return to skill. </p><p>So, moderate-ambiguity tasks will demand <em>more</em> skilled workers with LLM than they did with the effort technology. Less ambiguous tasks will demand less skilled workers.</p><h1>So&#8230;</h1><p>If we can compensate for our uncertainty about how best to do something by increasing effort, then we will only do tasks with low uncertainty via the LLM technology. Skill will matter less for low uncertainty tasks. And tasks with moderate uncertainty will now take <em>longer </em>(or be lower quality) than before (tell me you haven&#8217;t felt this at some point at work since LLMs came into their own) while demanding higher-skilled workers because of the increased return to skill.</p><p>In this model of LLM production, the knowledge worker provides a vital input: their own beliefs about how best to do things. LLMs don&#8217;t work without the worker. The model helps us isolate the effects of the automation component of LLMs, but, of course, LLMs do more than automate production (although for some applications&#8230; that is pretty close to their purpose).</p><p>In the next model of LLM production, we&#8217;ll allow the LLM to have beliefs of its own about how best to do things and open up the decision of whether to use a worker at all&#8230;</p><h1>Math&#8230;</h1><p>Although this model of production is relatively simple, it makes arguments that get bandied about in the AI discourse precise and concrete, with at least a plausible theory for what gets done by AI and what doesn&#8217;t. Writing down exactly what you are assuming about the structure of folks&#8217; decision-making process clarifies. Implications naturally follow from assumptions and structure. </p><p>You can do more than just say things.</p><p>Saying, &#8220;I think LLMs are great for generating quick queries or searching customer calls, but they&#8217;ve made docs less useful because they&#8217;re all AI-generated and very hard to parse,&#8221; is all well and good, but it&#8217;s just like your opinion, man. With a clear model, it starts to make sense. </p><p>Writing a good doc is a great example of a moderately uncertain task. It&#8217;s not untrod ground, but neither is it exactly obvious how to propose a new idea effectively in a way that accurately communicates what you want to do, why it&#8217;s a good idea, and what might go wrong. So, the degradation in quality with the LLM technology available makes sense. It follows from folks avoiding the effort cost to work on a moderately ambiguous problem.</p><p>On the other hand, a quick query or labeling customer calls is something you know exactly how to do. It would just take you a relatively long time to do it yourself. And the model says that low-uncertainty scenarios will be better with AI because you can get a baseline effort level without workers having to pay the effort cost for the exact kind of task where the returns to effort (from the worker&#8217;s perspective) are low.</p><p>The advantage of writing things down precisely in math language is that it makes it clear what assumptions drive your thinking, and it creates natural implications of those assumptions that you&#8217;ve not thought of before.</p><p>Writing, in both Human Language and Mathematics, is how humans think. Computers have RAM. We&#8217;ve got <a href="https://www.gnu.org/software/emacs/">Emacs</a>, Google Docs, <a href="https://www.amazon.com/Mead-Notebook-College-Assorted-73605/dp/B00YZXPH7E/">3x5 notebooks</a>, and <a href="https://news.mit.edu/2018/humans-speak-through-cave-art-0221">cave walls</a>.</p><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Please, subscribe! Although this was a moderate uncertainty task, I did it without AI. Think of my sacrifice and subscribe!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Stories from the SaaS Wars: 2026-05-23]]></title><description><![CDATA[Some stories I found interesting this week, mostly focused on the SaaS Wars.]]></description><link>https://www.underthenull.com/p/stories-from-the-saas-wars-2026-05</link><guid isPermaLink="false">https://www.underthenull.com/p/stories-from-the-saas-wars-2026-05</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Sat, 23 May 2026 19:35:10 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ZIcl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11a60f7a-86d5-4514-86c8-0774ab2e2833_1024x608.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZIcl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11a60f7a-86d5-4514-86c8-0774ab2e2833_1024x608.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZIcl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11a60f7a-86d5-4514-86c8-0774ab2e2833_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!ZIcl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11a60f7a-86d5-4514-86c8-0774ab2e2833_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!ZIcl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11a60f7a-86d5-4514-86c8-0774ab2e2833_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!ZIcl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11a60f7a-86d5-4514-86c8-0774ab2e2833_1024x608.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZIcl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11a60f7a-86d5-4514-86c8-0774ab2e2833_1024x608.png" width="1024" height="608" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/11a60f7a-86d5-4514-86c8-0774ab2e2833_1024x608.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:608,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZIcl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11a60f7a-86d5-4514-86c8-0774ab2e2833_1024x608.png 424w, https://substackcdn.com/image/fetch/$s_!ZIcl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11a60f7a-86d5-4514-86c8-0774ab2e2833_1024x608.png 848w, https://substackcdn.com/image/fetch/$s_!ZIcl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11a60f7a-86d5-4514-86c8-0774ab2e2833_1024x608.png 1272w, https://substackcdn.com/image/fetch/$s_!ZIcl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11a60f7a-86d5-4514-86c8-0774ab2e2833_1024x608.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">I have no idea what this image is, but I typed in SaaS Wars and received it from the Robots.</figcaption></figure></div><p>We&#8217;ve got a few stories from the SaaS wars&#8212;and takes, of course. We have an infinite supply of takes, far exceeding demand.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><ul><li><p><strong>Dispatch from the SaaS data access wars:</strong><br>Every week, there&#8217;s a new story about so-and-so blocking data access from such-and-such. This week, <a href="https://www.theinformation.com/articles/microsoft-opens-new-front-fight-data-ai-agents?rc=r6yx2h">Microsoft is supposedly blocking a certain kind of access from external tools to Power BI</a>. The article contains this haunting quote: &#8220;The friction centers on Power BI, a Microsoft product nearly all Fortune 500 firms use to analyze data about their operations in charts and other visual formats.&#8221; Really? Nearly all? <br><br>I&#8217;d like to take this chance to share a conspiracy theory. Power BI isn&#8217;t real. I hear about it all the time. It&#8217;s allegedly everywhere. And yet&#8230; I&#8217;ve never used it or seen it be used. I&#8217;m tech-old. I&#8217;ve been around lots of data environments. Sounds fake to me.</p></li><li><p><strong>Did you hear SpaceX is going to be IPO?<br></strong>No? I didn&#8217;t either. I couldn&#8217;t find a single article about it to share. See if you can find one somewhere on the internet.</p></li><li><p><strong>Customers demand shorter contracts over uncertainty of &#8220;what comes next&#8221;<br></strong><a href="https://www.theinformation.com/articles/anthropic-costs-mount-businesses-pressure-software-firms-shorten-contracts?rc=r6yx2h">There&#8217;s a story on</a><strong><a href="https://www.theinformation.com/articles/anthropic-costs-mount-businesses-pressure-software-firms-shorten-contracts?rc=r6yx2h"> </a></strong><a href="https://www.theinformation.com/articles/anthropic-costs-mount-businesses-pressure-software-firms-shorten-contracts?rc=r6yx2h">AI dollars crowding out traditional business software purchases. </a>The pool of dollars isn&#8217;t fixed, and if there is a large return to these AI products, why couldn&#8217;t these firms borrow to cover token purchases and repay the loans with excess profits? So, something is wrong here. Either credit markets (unlikely), the returns from AI spend are currently negative (plausible until companies learn the right way to deploy it at their firm), or there&#8217;s a principal-agent problem (highly likely). The person doing the buying has a fixed budget, so even though the company <em>could</em> just expand borrowing, there&#8217;s no cheap way for the agent to pass the information up the chain.<br><br>The second half of the story is more plausible, but speculative. Companies are worried that a wave of new, better products will emerge over the next few years and are reluctant to be locked into a long-term contract. That makes sense, but I really haven&#8217;t seen any evidence of useful AI-native business software, aside from the models and coding stuff coming from the primary labs. The AI components added to existing SaaS have been useful, but AI features are not really useful on their own. You need something that works well for all the more mundane features of the app first, and that turns out to be a hard problem.<br><br>It reminds me of every time I&#8217;ve seen what I think is an opportunity to exploit in an industry. I realize that, while I might be right about the opportunity, to actually profit from it, you&#8217;d have to launch a competitor that does all the other aspects of the industry right and then just <em>adds</em> the new insight. That&#8217;s very hard to do.</p></li><li><p><strong>Intuit moves to consumption-pricing.</strong><br><a href="https://www.theinformation.com/newsletters/applied-ai/ai-customers-negotiate-saas-escape-hatch?rc=r6yx2h">Everyone is doing it because it&#8217;s the only thing you </a><em><a href="https://www.theinformation.com/newsletters/applied-ai/ai-customers-negotiate-saas-escape-hatch?rc=r6yx2h">can</a></em><a href="https://www.theinformation.com/newsletters/applied-ai/ai-customers-negotiate-saas-escape-hatch?rc=r6yx2h"> do</a>, now that the Variable Cost Revolution is well underway. What is the Variable Cost Revolution, you ask? For a long time, one reason software companies were so profitable was that their costs were almost entirely fixed. Costs did not increase very much as they added more customers. So, with scale, they made oodles of money. But AI has changed that. If you run an AI feature in your software, you have a variable cost product. As demand for the product increases, your costs increase meaningfully. LLM-based features have changed the cost structure of the entire industry, and the pricing structure follows the cost structure.</p></li></ul><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Please, subscribe! We come in Peace!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Domain Specific Languages for Statistical Modeling]]></title><description><![CDATA[I'd like a STAN for moment-based models]]></description><link>https://www.underthenull.com/p/domain-specific-languages-for-statistical</link><guid isPermaLink="false">https://www.underthenull.com/p/domain-specific-languages-for-statistical</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Thu, 21 May 2026 14:01:34 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1558244661-d248897f7bc4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxNnx8YnVpbGRpbmclMjBibG9ja3N8ZW58MHx8fHwxNzc5MTgzNDI3fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1558244661-d248897f7bc4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxNnx8YnVpbGRpbmclMjBibG9ja3N8ZW58MHx8fHwxNzc5MTgzNDI3fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1558244661-d248897f7bc4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxNnx8YnVpbGRpbmclMjBibG9ja3N8ZW58MHx8fHwxNzc5MTgzNDI3fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1558244661-d248897f7bc4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxNnx8YnVpbGRpbmclMjBibG9ja3N8ZW58MHx8fHwxNzc5MTgzNDI3fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1558244661-d248897f7bc4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxNnx8YnVpbGRpbmclMjBibG9ja3N8ZW58MHx8fHwxNzc5MTgzNDI3fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1558244661-d248897f7bc4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxNnx8YnVpbGRpbmclMjBibG9ja3N8ZW58MHx8fHwxNzc5MTgzNDI3fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1558244661-d248897f7bc4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxNnx8YnVpbGRpbmclMjBibG9ja3N8ZW58MHx8fHwxNzc5MTgzNDI3fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="2957" height="3943" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1558244661-d248897f7bc4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxNnx8YnVpbGRpbmclMjBibG9ja3N8ZW58MHx8fHwxNzc5MTgzNDI3fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3943,&quot;width&quot;:2957,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;blue, red, and white artwork&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="blue, red, and white artwork" title="blue, red, and white artwork" srcset="https://images.unsplash.com/photo-1558244661-d248897f7bc4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxNnx8YnVpbGRpbmclMjBibG9ja3N8ZW58MHx8fHwxNzc5MTgzNDI3fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1558244661-d248897f7bc4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxNnx8YnVpbGRpbmclMjBibG9ja3N8ZW58MHx8fHwxNzc5MTgzNDI3fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1558244661-d248897f7bc4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxNnx8YnVpbGRpbmclMjBibG9ja3N8ZW58MHx8fHwxNzc5MTgzNDI3fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1558244661-d248897f7bc4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxNnx8YnVpbGRpbmclMjBibG9ja3N8ZW58MHx8fHwxNzc5MTgzNDI3fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@designedbyflores">Omar Flores</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>I&#8217;ve been thinking about the fact that statistical modeling doesn&#8217;t really have a standard declarative language for specifying a model&#8212;and how there&#8217;s nothing really preventing that from being so. I have this hope that were such a language to exist, people would finally understand the difference between an estimator and an estimand.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/subscribe?"><span>Subscribe now</span></a></p><p>I started thinking about this recently when I wrote a little something for a side project&#8212;coming soon&#8212;in <a href="https://mc-stan.org/">STAN</a>. </p><p><em>[I style the name in all-caps for unknown reasons. It&#8217;s not an acronym (I think).]</em> </p><p>If you&#8217;ve never used it before, STAN is a domain-specific language for likelihood models, primarily for Bayesian inference. The core idea is that you can specify the model in this declarative syntax, and the STAN program computes derivatives and the path for Markov Chain Monte Carlo iterations of the posterior distribution using automatic differentiation in a fairly well-optimized way (so, it&#8217;s nearly as fast as this sort of computationally-intensive thing can be). It&#8217;s super nifty.</p><p>To see what it looks like, here is an example of a STAN specification from a model I wrote for an old project. </p><p><em>[If you&#8217;re curious: the &#8220;old project&#8221; is an app that creates an &#8220;optimal&#8221; schedule for working towards a long-term goal based on your current, observed work behavior (i.e., you like to work on Tuesdays, you like to work in big chunks, you like to frontload or backload work relative to deadlines, etc).  You don&#8217;t enter your preferences. The app learns from your actual work behavior to help converge on an &#8220;ideal&#8221; work schedule across projects over time. It never really got any traction, but I liked the idea.]</em></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">data {
  int&lt;lower=0&gt; N; // number of days so far
  int&lt;lower=N+1&gt; T; // when the work has to be done
  array[N] real logit_remaining_share; // logit{W / (Y-work prior to W)}
  array[T] int G;
}

parameters {
  vector[6] dow;
  real&lt;lower=0.0&gt; sd;
  real weekday;
  real&lt;lower=0.0,upper=1.0&gt; r;
  real&lt;lower=-0.20,upper=0.20&gt; b;
}

transformed parameters {
  vector[7] K;
  for (i in 1:7) {
    if (i &lt;= 5) {
      K[i] = exp(dow[i] + weekday);
    }
    else {
      if (i==7) {
        K[i] = 1;
      }
      else {
        K[i] = exp(dow[i]);
      }
    }
  }
}

model {
  vector[N] future;
  vector[N] present;
  for (i in 1:6) {
    dow[i] ~ normal(0, 1);
  }
  weekday ~ normal(0, 1);
  r ~ beta(1,1);
  sd ~ gamma(1,1);
  b ~ uniform(-0.20,0.20);

  for (i in 1:N) {
    future[i] = 0.0;
    for (j in (i+1):T) {
      future[i] = future[i] + ((1+sqrt(j-i))^b)*(K[G[j]]^(1/r));
    }
    present[i] = K[G[i]]^(1/r);
  }

  for (i in 1:N) {
    logit_remaining_share[i] ~ normal(log(present[i])-log(future[i]), sd);
  }
}
</code></pre></div><p>The key idea here is that you can just describe the prior distributions [weekday ~ normal(0,1)] and the likelihoods [logit_remaining_share[i] ~ normal(log(present[i]) - log(future[i]), sd)] and then STAN simulates the posterior distribution using a fancy Monte Carlo. This makes it easy to specify flexible, realistic priors and likelihoods without relying on computational tricks (like <a href="https://en.wikipedia.org/wiki/Conjugate_prior">conjugate priors</a>). So you don&#8217;t specify models based on computational concerns, but on how well they describe the data-generating process. Plus&#8212;and I like this part a lot&#8212;the model&#8217;s description is fully separate from the details of how it&#8217;s estimated.</p><p><em>[Yes, I frequently write code without descriptive variable names. I think this is the good and proper way to write math code when you have a model you&#8217;ve written out somewhere in math, i.e., the names here match the LaTex, which is the source of truth, and the real documentation. But your mileage&#8212;and ability to get such things past engineers reviewing your PR&#8217;s&#8212;may vary.]</em></p><p>But I don&#8217;t do many Bayesian projects. I mostly work firmly in frequentist land. I<em> </em>don&#8217;t do much likelihood-based estimation either. Broadly, I use moment-based estimators, but I really like the idea of a domain-specific language for modeling that&#8217;s portable across R, Python, Fortran, Julia, whatever.</p><p>I&#8217;ve been sketching out what this would look like (I think the cool kids call this &#8220;building in public&#8221;). </p><p>Here&#8217;s my current draft:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;efe5105b-46bb-46ea-9914-0ec18b2acc12&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">data
  N;
  K;
  J;
  X[N,K];
  Y[N];
  Z[N,J];
  T[N];
end

parameters
  b[K];
  te[1];
end

latent
  # parameters can show up here
  Y{T} := start |T, t|
       Y if T = t else unobserved;
  end
end

assumptions
  # no parameters or latent variables can appear on the right side of the := operator
  moment(Z @ (Y - X @ b)) := 0; # iv assumption to get b

  moment(te - (Y{1} - Y{0})) := 0; # define treatment effect
  moment(Y{T}) - moment(Y | T) := 0; # exogenous treatment assignment
  
  # alternatively, define some CIA-like assumption
  moment(Y{T} | X) := moment(Y | T, X)

end</code></pre></div><p>Another example for a discrete choice demand model:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;0baec6f8-3eb7-4ab0-948f-b3167fbf214d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">data
  J; # number of products
  K; # number of characteristics
  N; # number of customers
  X[J,K]; # product features
  B[N,J]; # dummies for whether each customer bought
end

parameters
  b[K]; # characteristic parameters
  a[J]; # product fixed effect
  choice_prob[N,J]; # customer probability of choosing each option
end

assumptions
  do i from 1 to N
    do j from 1 to J
      choice_prob[i,j] - 1/(1+exp(-1*cross(X[j,:], b) - a[j])) := 0;
    end
  end
  do j from 1 to J
    moment(choice_prob[:,j] - B[:,j]) := 0
  end
  moment((choice_prob - B) @ X) := 0
end
</code></pre></div><p>A key point here is that &#8220;moment(&#8230;)&#8221; is not just a function being applied to an input. It&#8217;s part of the language, and the language knows the properties of expectations. So it can, for example, know that:</p><ul><li><p>E[Y{1} | T = 1, X] := E[Y{1} | X] =&gt; E[Y{1}] = E[E[Y{1}|T=1, X]]</p></li></ul><p>You can also centralize moments with &#8220;central_moment(&#8230;)&#8221; and get higher order moments by using &#8220;moment(X, 2)&#8221; or &#8220;central_moment(X,2)&#8221; (i.e. the variance).</p><p>This isn&#8217;t a project I&#8217;ve written code for yet. I&#8217;m still trying to decide whether this makes sense and is useful enough to spend a decent chunk of time on, but in principle, I think having a declarative syntax for moment-based modeling makes sense. </p><p>The core, workhorse estimator behind it all would be the <a href="https://en.wikipedia.org/wiki/Generalized_method_of_moments">Generalized Method of Moments</a>, because it&#8217;s flexible enough to cover all of these cases. Maybe it can even include inequality restrictions&#8230;</p><p>Anywho, thank you for listening to me ramble about ideas I&#8217;ve been bouncing around to improve statistical programming. I really like the idea of more firmly decoupling the estimand from the estimator in the code itself, so I&#8217;ll probably take a shot at making this a reality once I&#8217;ve thought about the problem more precisely and have a good grasp of how to implement it right.</p><p>What do you think are the biggest gaps we have in statistical programming?</p><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Please, subscribe! It&#8217;s the same price as STAN. Free!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Prediction Markets and the Social Value of Information]]></title><description><![CDATA[There's appeal, but I don't think I like them very much]]></description><link>https://www.underthenull.com/p/prediction-markets-and-the-social</link><guid isPermaLink="false">https://www.underthenull.com/p/prediction-markets-and-the-social</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Tue, 19 May 2026 13:47:33 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1627764574958-fb54cd7d7448?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMnx8Zm9yZWNhc3R8ZW58MHx8fHwxNzc5MDEzNDA4fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1627764574958-fb54cd7d7448?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMnx8Zm9yZWNhc3R8ZW58MHx8fHwxNzc5MDEzNDA4fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1627764574958-fb54cd7d7448?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMnx8Zm9yZWNhc3R8ZW58MHx8fHwxNzc5MDEzNDA4fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1627764574958-fb54cd7d7448?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMnx8Zm9yZWNhc3R8ZW58MHx8fHwxNzc5MDEzNDA4fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1627764574958-fb54cd7d7448?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMnx8Zm9yZWNhc3R8ZW58MHx8fHwxNzc5MDEzNDA4fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1627764574958-fb54cd7d7448?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMnx8Zm9yZWNhc3R8ZW58MHx8fHwxNzc5MDEzNDA4fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1627764574958-fb54cd7d7448?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMnx8Zm9yZWNhc3R8ZW58MHx8fHwxNzc5MDEzNDA4fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="4868" height="2738" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1627764574958-fb54cd7d7448?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMnx8Zm9yZWNhc3R8ZW58MHx8fHwxNzc5MDEzNDA4fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2738,&quot;width&quot;:4868,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack" title="jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack jack" srcset="https://images.unsplash.com/photo-1627764574958-fb54cd7d7448?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMnx8Zm9yZWNhc3R8ZW58MHx8fHwxNzc5MDEzNDA4fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1627764574958-fb54cd7d7448?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMnx8Zm9yZWNhc3R8ZW58MHx8fHwxNzc5MDEzNDA4fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1627764574958-fb54cd7d7448?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMnx8Zm9yZWNhc3R8ZW58MHx8fHwxNzc5MDEzNDA4fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1627764574958-fb54cd7d7448?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMnx8Zm9yZWNhc3R8ZW58MHx8fHwxNzc5MDEzNDA4fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@m_malkovich">petr sidorov</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>I would have liked prediction markets if I&#8217;d thought about them much before I saw them in the wild. </p><p>I&#8217;m a fan of markets. Why not learn what people really think by having them put money on the line? I do like forcing pundits to bet. We should tax bullshit. It has negative externalities.</p><p>But now, we have data, and, unfortunately, we have to use it.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/subscribe?"><span>Subscribe now</span></a></p><p>Another argument I would have found convincing in the past: who cares if there&#8217;s insider trading? In fact, that will just make the markets <em>better</em> at predicting because all information, including that available to insiders, gets incorporated into the price.</p><p>The idea that information is valuable is central to economics and intuitive. The more information is reflected in prices, the better decisions we can make about capital allocation. <a href="http://klenow.com/MMTFP.pdf">The misallocation of capital is a major drag on productivity.</a></p><div><hr></div><p>A few things were missing from my model of the world:</p><ol><li><p>The value of information is heterogeneous.</p></li><li><p>The value of information does not correlate with market size.</p></li><li><p>Not all information is disperse and diverse, which is where markets shine.</p></li><li><p>There are, naturally, negative externalities to gambling. So, the market's social value does not start at 0.</p></li></ol><p>For example, one of the larger prediction markets was a bet on who would win the New York City mayoral race. What is the value of this information before the election concludes? Perhaps it provides a means to hedge against a certain candidate&#8217;s effect on asset prices if he wins? Or, aggregate information from this market&#8217;s outcome can be used to trade in the asset market. </p><p>Markets do not create information. They reveal and aggregate the information people bring to them. So, what additional information is the market aggregating here? It can&#8217;t come from public polls, which are, well, already public. It does generate a numerical index of the &#8220;vibes,&#8221; which are public knowledge but difficult to quantify. It&#8217;s not clear how predictive the vibes are, though, and, in any case, they are already reflected directly in asset prices. From insiders, it incorporates private polling data, which is probably the most useful information generated by the market.</p><p>But couldn&#8217;t those insiders use that private polling data to <em>directly</em> trade on assets that will (allegedly) be affected by a certain candidate&#8217;s win? Then, that information would already be in asset prices. </p><p><em>No</em>, is the answer, I think, but the reason for that is that political insiders are <em>small</em> in asset markets, so they can&#8217;t really move the price, but <em>large</em> in (some) prediction markets, given their current size. </p><p><em>[I have an armchair theory that media fascination with prediction markets is that polls report their results in terms of proportions, while prediction markets return results that give an implied probability of so-and-so winning. Of course, polls could also return probabilities of winning with some kind of Bayesian inference, but they don&#8217;t. An opportunity for a polling company.]</em></p><p>And therein lies the reality of the information value of prediction markets: it depends on people with meaningful information making up a sizeable enough percentage of the market that their private information gets reflected in prices. If the only people with meaningful information are insiders and insiders are small, then they earn profits by trading in the market because their bets don&#8217;t move the price, but we don&#8217;t learn any special information from the market that we don&#8217;t already know.</p><div><hr></div><p>The prediction markets that would be most useful are not political horse races or sports gambling, but predictions about events where the information is difficult to quantify and aggregate into a belief in the abstract, and where information is diverse and widely distributed. </p><p>For example, the market for apples aggregates information on the value of apples. Everyone has their own apple preferences, so the information is very diverse. No one else knows your preferences, so the information is widely distributed. Markets aggregate all this diverse and dispersed information into a price for apples, which summarizes how apples trade off versus any number of other goods.</p><div><hr></div><p>Markets like these are not popular topics on Kalshi. Look at the home page. I struggled to find topics where many individual people have meaningful, diverse information about them. I&#8217;ll discuss a few that were (arguably) close to that before jumping into what&#8217;s mostly there.</p><ul><li><p>&#8220;Will Americans receive stimulus checks?&#8221; Of course: how would any non-insider have useful information to contribute to the market here? But, it does, I suppose, operate as a hedge of some kind in case the government has to borrow to write stimulus checks, and so it might offer some idea of how exposed people are to the demand for treasuries or something (which is diverse, dispersed information)&#8230; but there are already so many ways to do this that have a market size of more than $1.5M.</p></li><li><p>And, sure, there are some markets here that are more or less just typical financial instruments. There&#8217;s one directly betting on when Bitcoin will cross $100k again, which is just a typical financial market that aggregates individual demand information. But, again, this isn&#8217;t and wasn&#8217;t really the pitch for prediction markets. This is just a normal financial market.</p></li><li><p>&#8220;More tech layoffs in 2026 than 2025?&#8221; While there&#8217;s some alpha from being an insider, it&#8217;s limited by the fact that you only know your company, and the market can effectively aggregate all these signals about the tech industry more generally.  Workers without direct knowledge of pending layoffs do have some information on them. You can usually tell when it&#8217;s coming, and such a market might be a hedge against the possibility you&#8217;re laid off. Others outside the tech companies might have some useful leading indicators worth aggregating as well, e.g., that it&#8217;s getting harder to close commercial real estate deals in the Bay Area.</p></li></ul><div><hr></div><p>The combined market size for these and a few other roughly information aggregative markets is dwarfed, of course, by the $293M market for &#8220;PGA Championship Winner,&#8221; which is what these sites are really about. </p><p><em>&#8220;For where your treasure is, there your heart will be also.&#8221;</em></p><div><hr></div><p>If you write down a typical model for a prediction market, you&#8217;ll start saying things like &#8220;each individual gets a signal <em>x</em>&#8230;&#8221; but they don&#8217;t really. Not in most of these. As much as I&#8217;d like to believe I have some signal about what&#8217;s going to happen with geopolitics, I don&#8217;t. My beliefs on the likelihood of various outcomes of the war in Iran are just an index of public information. I have no new signal to offer the market.</p><p>So, then, what&#8217;s left? If we don&#8217;t really draw signals, then we&#8217;re left with non-insiders really just placing bets on the events because they are risk-loving, either because they are in a relatively flat part of the wealth utility space and need to get a great outcome to move up a level, or because they have &#8220;an innate preference for risk.&#8221;</p><p>Go to Kalshi and ask yourself: what price in each of these markets would cause me to enter? Most of these, within a very broad, reasonable range, I would have no reason to think are mispriced, even if the price were like +/- 20% from what it is currently. I&#8217;d just assume the market had more information than I did.</p><p>The same isn&#8217;t true in the stock market. For example, if the price of Apple were 20% lower than it actually is, I could look at their financials, public roadmap, and go, &#8220;Wait a second. This is wrong. I am going to make a boatload of money. Can I take out a second mortgage on the house?&#8221;</p><div><hr></div><p>So, this is why I think prediction markets have failed in reaching their promise:</p><ol><li><p>For most of the predictions we want the markets to make, relevant information is highly concentrated.</p></li><li><p>There are very good substitutes for the more meaningful markets that directly focus on more traditional financial transactions and don&#8217;t rely on people with &#8220;innate preferences for risk&#8221; to get liquidity.</p></li></ol><p>I&#8217;m not sure that we should like a system that functions as a transfer payment to <a href="https://www.wsj.com/finance/regulation/government-prediction-markets-betting-2126dcb3">insiders</a> from people who think the key to improving their lives is to put it all on black.</p><div><hr></div><p>I&#8217;m not for banning prediction markets, of course. People should generally be free to do as they will. Many vices and antisocial behaviors are legal. </p><p>We still let people be Dodgers fans, among other things.</p><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Please, subscribe! I put $100k on you subscribing in a Kalshi market. That&#8217;s why I made subscribing free. I need you to subscribe so my investment/bet/reckless gamble pays off. Please, subscribe! </p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Round-up!: Thinking Machines are Expensive Now?]]></title><description><![CDATA[Stories from the Pricing, Monetization, and Data Science world from the past week (2026-05-15)]]></description><link>https://www.underthenull.com/p/thinking-machines-are-expensive-now</link><guid isPermaLink="false">https://www.underthenull.com/p/thinking-machines-are-expensive-now</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Fri, 15 May 2026 14:00:07 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!7JJ5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64945a5c-d810-4b0e-b7ba-9e828a2e21ef_700x1036.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7JJ5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64945a5c-d810-4b0e-b7ba-9e828a2e21ef_700x1036.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7JJ5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64945a5c-d810-4b0e-b7ba-9e828a2e21ef_700x1036.webp 424w, https://substackcdn.com/image/fetch/$s_!7JJ5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64945a5c-d810-4b0e-b7ba-9e828a2e21ef_700x1036.webp 848w, https://substackcdn.com/image/fetch/$s_!7JJ5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64945a5c-d810-4b0e-b7ba-9e828a2e21ef_700x1036.webp 1272w, https://substackcdn.com/image/fetch/$s_!7JJ5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64945a5c-d810-4b0e-b7ba-9e828a2e21ef_700x1036.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7JJ5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64945a5c-d810-4b0e-b7ba-9e828a2e21ef_700x1036.webp" width="700" height="1036" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/64945a5c-d810-4b0e-b7ba-9e828a2e21ef_700x1036.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1036,&quot;width&quot;:700,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:9077,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.underthenull.com/i/197794138?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64945a5c-d810-4b0e-b7ba-9e828a2e21ef_700x1036.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7JJ5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64945a5c-d810-4b0e-b7ba-9e828a2e21ef_700x1036.webp 424w, https://substackcdn.com/image/fetch/$s_!7JJ5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64945a5c-d810-4b0e-b7ba-9e828a2e21ef_700x1036.webp 848w, https://substackcdn.com/image/fetch/$s_!7JJ5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64945a5c-d810-4b0e-b7ba-9e828a2e21ef_700x1036.webp 1272w, https://substackcdn.com/image/fetch/$s_!7JJ5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64945a5c-d810-4b0e-b7ba-9e828a2e21ef_700x1036.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This was a strong week for pricing news, so I&#8217;m leaning into it with a round of a few choice pricing/monetization/data/statistics stories from the week. Maybe it&#8217;ll be a recurring thing (<em>actually </em>recurring, not &#8220;recurring&#8221; as in ARR). </p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><ol><li><p>Some <a href="https://www.theinformation.com/newsletters/applied-ai/anthropic-costs-unpredictable?rc=r6yx2h">Anthropic customers don&#8217;t like its pricing.</a> I heard not so long ago that AI was ending scarcity and <a href="https://www.axios.com/2025/05/28/ai-jobs-white-collar-unemployment-anthropic">replacing white collar work by 2030 at the latest</a>. Now, even the Silicon Gods have a price, and some folks think it is too much. Just imagine if the robots cost more than our<a href="https://www.salesforce.com/"> glorified address book</a>! That&#8217;s the contradiction of LLMs. They&#8217;re fantastic products&#8212;amazing, in fact, but if they were as good as the AI labs&#8217; frontmen say&#8230; they&#8217;d cost more. They&#8217;re more than worth it at current prices, of course. <a href="https://www.theinformation.com/articles/anthropic-flexes-pricing-power-customers-willingly-eat-cost?rc=r6yx2h">&#8220;Many technology firms and other large Anthropic customers say they plan to eat the soaring costs...&#8221;</a> Price competition is tough because of relatively low product differentiation between the top players, which should keep prices down&#8230; but even Google can&#8217;t light money on fire forever...</p></li><li><p>Speaking of the cool, currently cheap-enough AI&#8230; I haven&#8217;t had the chance to play around with it yet, but <a href="https://hex.tech/blog/introducing-generative-data-apps/">the demos of Hex&#8217;s new &#8220;generative apps&#8221; look snazzy</a>. If you don&#8217;t know Hex, it&#8217;s a notebook ala Jupyter that makes it easy to spin up web apps powered by the notebook for your stakeholders&#8217; consumption. It&#8217;s well-done, and the stylings of these new vibes-powered apps look fun. </p></li><li><p>Spotify is running this hilarious monetization play. If you open Spotify in the browser and switch tabs, the miniplayer pops up in the lower-right. If you are not on Spotify Premium, like me, it shows the miniplayer covered with a prompt reading, &#8220;You discovered a Premium feature. With Spotify Premium, you can make the miniplayer even smaller.&#8221; I had never noticed the size of the miniplayer before. It had never occurred to me that it was too big, but after I clicked &#8220;Not Now&#8221; and the player ballooned to its previously normal size, I saw how large it truly was. Like Adam in the Garden, I had tasted the fruit of a properly-sized miniplayer, and lost my innocence. I felt a sense of loss of what was once and what could be again&#8230; if only I didn&#8217;t refuse to pay $120/yr or whatever Spotify Premium is. I don&#8217;t mind ads. It&#8217;s nice to know what the fellow corporates are up to. <br><br>Seriously, a very clever surface to drive conversion on. I love it. <strong>I bet it works.</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mMeH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecd824c-ff9d-4921-9e54-fd982ee6d845_646x722.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mMeH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecd824c-ff9d-4921-9e54-fd982ee6d845_646x722.jpeg 424w, https://substackcdn.com/image/fetch/$s_!mMeH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecd824c-ff9d-4921-9e54-fd982ee6d845_646x722.jpeg 848w, https://substackcdn.com/image/fetch/$s_!mMeH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecd824c-ff9d-4921-9e54-fd982ee6d845_646x722.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!mMeH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecd824c-ff9d-4921-9e54-fd982ee6d845_646x722.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mMeH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecd824c-ff9d-4921-9e54-fd982ee6d845_646x722.jpeg" width="646" height="722" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/becd824c-ff9d-4921-9e54-fd982ee6d845_646x722.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:722,&quot;width&quot;:646,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:30129,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.underthenull.com/i/197794138?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecd824c-ff9d-4921-9e54-fd982ee6d845_646x722.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!mMeH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecd824c-ff9d-4921-9e54-fd982ee6d845_646x722.jpeg 424w, https://substackcdn.com/image/fetch/$s_!mMeH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecd824c-ff9d-4921-9e54-fd982ee6d845_646x722.jpeg 848w, https://substackcdn.com/image/fetch/$s_!mMeH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecd824c-ff9d-4921-9e54-fd982ee6d845_646x722.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!mMeH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbecd824c-ff9d-4921-9e54-fd982ee6d845_646x722.jpeg 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p></li><li><p>Slowly but surely, AI app pricing is matching the AI cost model. <a href="https://www.linkedin.com/posts/zlflynn_atlassian-and-hubspot-join-shift-from-ai-activity-7454774927057944577-1rZn?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAAA1Cj_QBJaocHeBYwwSlmgW6XnhFyfhc4zE">In the long run, cost structure sets pricing.</a> Take <a href="https://www.theinformation.com/briefings/figma-sees-revenue-growth-jump-new-ai-pricing-sticks?rc=r6yx2h">Figma</a>, for instance. They started capping how much customers can chatter with the Clankers for a flat rate, like the old cell phone plans. Now, you buy credits on top of the seat price once you cross a certain usage threshold. This always had to be the case, eventually.  <a href="https://www.theinformation.com/newsletters/applied-ai/servicenow-fedex-reflect-great-ai-pricing-divide?rc=r6yx2h">It&#8217;s not just Figma,</a> of course.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!14wJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d0a4d54-a775-46cc-aa50-518b46cbca5a_445x458.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!14wJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d0a4d54-a775-46cc-aa50-518b46cbca5a_445x458.jpeg 424w, https://substackcdn.com/image/fetch/$s_!14wJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d0a4d54-a775-46cc-aa50-518b46cbca5a_445x458.jpeg 848w, https://substackcdn.com/image/fetch/$s_!14wJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d0a4d54-a775-46cc-aa50-518b46cbca5a_445x458.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!14wJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d0a4d54-a775-46cc-aa50-518b46cbca5a_445x458.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!14wJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d0a4d54-a775-46cc-aa50-518b46cbca5a_445x458.jpeg" width="445" height="458" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1d0a4d54-a775-46cc-aa50-518b46cbca5a_445x458.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:458,&quot;width&quot;:445,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:62348,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.underthenull.com/i/197794138?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d0a4d54-a775-46cc-aa50-518b46cbca5a_445x458.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!14wJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d0a4d54-a775-46cc-aa50-518b46cbca5a_445x458.jpeg 424w, https://substackcdn.com/image/fetch/$s_!14wJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d0a4d54-a775-46cc-aa50-518b46cbca5a_445x458.jpeg 848w, https://substackcdn.com/image/fetch/$s_!14wJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d0a4d54-a775-46cc-aa50-518b46cbca5a_445x458.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!14wJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d0a4d54-a775-46cc-aa50-518b46cbca5a_445x458.jpeg 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p></li><li><p><a href="https://www.wsj.com/arts-culture/fine-art/mark-rothko-abstract-sells-for-85-8-million-dab34442?mod=style_lead_story">These rectangles sold for $85.8 million,</a> so next time, Just Monetize It (tm). <em>Someone</em> will buy it.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uzfI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335ea8e0-d344-4ecb-af62-ad2f301ee6b8_700x1036.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uzfI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335ea8e0-d344-4ecb-af62-ad2f301ee6b8_700x1036.webp 424w, https://substackcdn.com/image/fetch/$s_!uzfI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335ea8e0-d344-4ecb-af62-ad2f301ee6b8_700x1036.webp 848w, https://substackcdn.com/image/fetch/$s_!uzfI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335ea8e0-d344-4ecb-af62-ad2f301ee6b8_700x1036.webp 1272w, https://substackcdn.com/image/fetch/$s_!uzfI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335ea8e0-d344-4ecb-af62-ad2f301ee6b8_700x1036.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uzfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335ea8e0-d344-4ecb-af62-ad2f301ee6b8_700x1036.webp" width="700" height="1036" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/335ea8e0-d344-4ecb-af62-ad2f301ee6b8_700x1036.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1036,&quot;width&quot;:700,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:9077,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.underthenull.com/i/197794138?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335ea8e0-d344-4ecb-af62-ad2f301ee6b8_700x1036.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uzfI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335ea8e0-d344-4ecb-af62-ad2f301ee6b8_700x1036.webp 424w, https://substackcdn.com/image/fetch/$s_!uzfI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335ea8e0-d344-4ecb-af62-ad2f301ee6b8_700x1036.webp 848w, https://substackcdn.com/image/fetch/$s_!uzfI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335ea8e0-d344-4ecb-af62-ad2f301ee6b8_700x1036.webp 1272w, https://substackcdn.com/image/fetch/$s_!uzfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335ea8e0-d344-4ecb-af62-ad2f301ee6b8_700x1036.webp 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div></li></ol><p><a href="https://www.theinformation.com/?rc=r6yx2h">The Information</a> owes me a referral fee for dominating the links, but they had great stories this week. Nice job, folks!</p><div><hr></div><p><strong>Blog and Side Projects Updates</strong></p><ul><li><p>Crossed 100 subscribers this week. Super-Neat! Hope you enjoy reading!</p></li><li><p>Completed our first full week of the new, thrice-weekly posting schedule! <a href="https://www.underthenull.com/p/i-want-to-get-good?r=2jxml&amp;utm_campaign=post&amp;utm_medium=web&amp;triedRedirect=true">I want to write well, </a>and it turns out you have to practice. Go figure.</p></li><li><p>We made a small chunk of progress on the last main project area for my secret side project (a webapp for this Common Statistical Task). We got to write some <a href="https://mc-stan.org/">Stan</a> for the first time in a while.</p></li></ul><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Please, subscribe! We maximized our ARR (so you know we&#8217;re capitalists) <em>and</em> minimized our ARR (so you know we&#8217;re cool) simultaneously by pricing this subscription at the low-low price of $0! </p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Estimating Demand via Experiments (when They won't let you randomize price...)]]></title><description><![CDATA[A more customer-friendly way to experiment on price]]></description><link>https://www.underthenull.com/p/estimating-demand-via-experiments</link><guid isPermaLink="false">https://www.underthenull.com/p/estimating-demand-via-experiments</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Wed, 13 May 2026 13:39:52 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1605870445919-838d190e8e1b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxkaWNlfGVufDB8fHx8MTc3ODM4NDI3OHww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1605870445919-838d190e8e1b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxkaWNlfGVufDB8fHx8MTc3ODM4NDI3OHww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1605870445919-838d190e8e1b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxkaWNlfGVufDB8fHx8MTc3ODM4NDI3OHww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1605870445919-838d190e8e1b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxkaWNlfGVufDB8fHx8MTc3ODM4NDI3OHww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1605870445919-838d190e8e1b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxkaWNlfGVufDB8fHx8MTc3ODM4NDI3OHww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1605870445919-838d190e8e1b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxkaWNlfGVufDB8fHx8MTc3ODM4NDI3OHww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1605870445919-838d190e8e1b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxkaWNlfGVufDB8fHx8MTc3ODM4NDI3OHww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="4256" height="2832" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1605870445919-838d190e8e1b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxkaWNlfGVufDB8fHx8MTc3ODM4NDI3OHww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2832,&quot;width&quot;:4256,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;2 white dices on blue surface&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="2 white dices on blue surface" title="2 white dices on blue surface" srcset="https://images.unsplash.com/photo-1605870445919-838d190e8e1b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxkaWNlfGVufDB8fHx8MTc3ODM4NDI3OHww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1605870445919-838d190e8e1b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxkaWNlfGVufDB8fHx8MTc3ODM4NDI3OHww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1605870445919-838d190e8e1b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxkaWNlfGVufDB8fHx8MTc3ODM4NDI3OHww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1605870445919-838d190e8e1b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxkaWNlfGVufDB8fHx8MTc3ODM4NDI3OHww&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@edge2edgemedia">Edge2Edge Media</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>I&#8217;ve complained about the <a href="https://zachflynn.substack.com/p/price-testing">demonization of pricing experiments before</a>, but alas, there&#8217;s no arguing religion. Sometimes, you just have to accept that you can&#8217;t run price experiments, and still, They want you to estimate demand.</p><p>The trick, of course, is to convince Them to let you randomly send some folks a 10% off coupon for whatever you&#8217;re hawking. Often, the marketing/promo team has already done this, so you can just steal their data. This is best.</p><p>The idea here is that the promo introduces price variation, but you have to be careful with how you use the data to identify demand. So, thought I&#8217;d write a little post on how to do it. Price well!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>A simplified empirical demand model (ignoring all the nonsense you control for, etc) looks something like this:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\log Q_{jt} =  \\alpha + \\beta \\log P_{jt} + E&quot;,&quot;id&quot;:&quot;HKDBGZHBWX&quot;}" data-component-name="LatexBlockToDOM"></div><p>Where <em>j</em> indexes products and <em>t</em> indexes time. </p><p>The problem is that historical price changes are related to all the other factors that affect output (<em>E</em>). For example, often this equation more or less describes the price variable:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;P_{jt} = B_{j} + 1(t \\ge t_{0}) D_{j}&quot;,&quot;id&quot;:&quot;WOAEPOUWFQ&quot;}" data-component-name="LatexBlockToDOM"></div><p>i.e. the price increased at some point in time in the past. It is <em>extremely</em> unlikely that nothing else changed with demand before and after the price change. Demand is always changing.</p><p>So, you can&#8217;t just run the regression.</p><p>The standard solution to this problem is to use an instrument that is <em>uncorrelated</em> with the other factors that drive output (e.g., demand shocks), but is <em>correlated</em> with price, because then:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{cov}(Q, Z) = \\beta \\text{cov}(P, Z) + \\text{cov}(Z, E) = \\beta \\text{cov}(P, Z)&quot;,&quot;id&quot;:&quot;CRHUJHYFBE&quot;}" data-component-name="LatexBlockToDOM"></div><p>So, you can just solve for the elasticity <em>&#946;</em>.</p><p>But you don&#8217;t have any instruments. You know this. I know this. The supply of instruments is much lower than the demand, and, if you&#8217;re working in industry, it&#8217;s just extremely unlikely that some natural experiment exists for your particular company.</p><p>So, you have to make your own instruments. That&#8217;s what experiments do. Experiments are instrument factories. They make random variables that are uncorrelated with everything but what comes after being bucketed into the experiment.</p><div><hr></div><p>But the 10% off coupon mentioned earlier isn&#8217;t a valid instrument for this demand model, sadly.</p><p>It&#8217;s randomized across <em>users</em>, not products. So, there&#8217;s no reason to suspect it&#8217;s excluded from a direct shock to demand. The randomization ensures that variant assignment at the individual level is uncorrelated with other <em>user</em> characteristics, but this doesn&#8217;t solve the endogeneity problem, which is cross-product and time! </p><p>The problem is that this demand model is based on product-time variation. So, to use this instrument, we&#8217;ll need to build up a customer-level demand model and derive the aggregate demand for each product from the individual demand curves.</p><div><hr></div><p>A natural way to do this is with a discrete choice model. To save on notation, let&#8217;s suppose you&#8217;re hawking one product, so that this amounts to modeling the conversion rate. Here&#8217;s a pretty standard model, but you can use something more flexible:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{pr}_{i}(\\text{purchase}) = \\frac{1}{1+\\exp(-1 \\times [X_{i}^{\\top} b + a P_{i}])}&quot;,&quot;id&quot;:&quot;JDGMCQGEMY&quot;}" data-component-name="LatexBlockToDOM"></div><p>Where <em>X<sub>i</sub></em> are some customer characteristics and <em>P<sub>i</sub></em> is the final price of the product for customer <em>i</em>. Here, we&#8217;re allowing for other reasons a particular customer might have a lower price aside from access to the 10% discount. <em>P<sub>i</sub></em> is just whatever the customer&#8217;s final price ends up at.</p><p>Now, let <em>Z<sub>i</sub> = 1</em> if the customer gets the 10% promo and 0 otherwise. The key idea is to use this <em>Z<sub>i</sub></em> as an instrument for price.</p><p>For doing binary choice models with instrument variables, I usually use a little something I wrote circa 2017-2018: <a href="https://zflynn.com/papers/rlr_zf.pdf">repeated two-stage least squares</a>.</p><p>The basic idea is that you can show that doing the following procedure is a <a href="https://en.wikipedia.org/wiki/Contraction_mapping">contraction mapping</a>:</p><ol><li><p>Run two-stage least squares for the linear probability model of 1(purchase<sub>i</sub>) on (X, P) with (X, Z) as instruments. Call this estimate <em>c</em>.</p></li><li><p>Set k = 1.</p></li><li><p>For some initial guess of <em>a</em> and <em>b</em>, compute the predicted conversion rate. Run the same two-stage least squares estimation with the dependent variable being the predicted conversion rate. Call this estimate <em>c<sub>k</sub>.</em></p></li><li><p>Update: <em>[a<sub>k+1</sub>, b<sub>k+1</sub>] = [a<sub>k</sub>, b<sub>k</sub>] + c - c<sub>k</sub></em>.</p></li></ol><p>Under an assumption that the instrument has a &#8220;strong enough&#8221; relationship to (X,P), this procedure converges to the true <em>a</em> and <em>b</em> in a large enough sample. It&#8217;s also got standard normal, asymptotic inference because there&#8217;s an analogous <a href="https://en.wikipedia.org/wiki/Generalized_method_of_moments">GMM</a> estimator.</p><p>The key thing is that you can use these kinds of experiments to generate plausible instruments for demand estimation even when you don&#8217;t have the ability to do more direct price experimentation (for whatever reason).</p><div><hr></div><p>Once you have this model, you can simulate changes in price by just plugging in new prices, but identification here has its limits. All you&#8217;ve done is exogenously moved prices 10% for some customers. If you start looking at 30% price increases, you&#8217;re inferences will be based more on functional form than anything in the data. The real info you want to get is &#8220;Are we over/under-priced? Would a small increase/decrease help us?&#8221;</p><div><hr></div><p>A couple things to try to improve power and flexibility here:</p><ol><li><p>If you can get more promo depths (lower or higher discount %), that&#8217;s super useful because it will give you more instruments. Maybe you can get a more complex model of the pricing curve. With only the one 10% promo, we can&#8217;t introduce a P<sup>2</sup> term into the model because we don&#8217;t have a separate instrument for it. But if we have a few different treatments, we can get it in there.</p></li><li><p>If you can get them to send out the promo a few times where you re-randomize the recipients, this is good, because it generates additional variation in variant assignment, giving you more power.</p></li></ol><div><hr></div><p>There&#8217;s an <strong>important</strong> wrinkle here. The e-mail or notification that tells a customer they have a promo <em>itself</em> might be responsible for increased demand, i.e. aside from any discount the customer gets. </p><p>The trick to deal with this is to send promos to everyone but <em>vary</em> the discount level. Instead of doing 10% vs 0%, do 20% vs 10%. Then, you can send the same e-mail to everyone and just change the discount. This helps isolate just the pricing impact of the experiment.</p><div><hr></div><p>At this point, we might ask: &#8220;Well, if we&#8217;ve got this nifty trick to run a more palatable experiment, why would we ever want to run pricing experiments?&#8221; This is another case where it&#8217;s important to remember that the data&#8217;s only really informative in a neighborhood of actual prices people are seeing. This strategy only tests prices <em>below</em> the status quo, not higher. So, you&#8217;re not really getting direct evidence on what would happen at higher prices. You&#8217;re just assuming that the elasticities you see for the 10% lower price are roughly relevant when the price is 10% higher. That&#8217;s better than vibes and purely observational analyses, but it&#8217;s an assumption all the same. So, you have to be more cautious when increasing prices than decreasing them using this method.</p><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Subscribe, please! It&#8217;s free (We looked at the data and determined $0 is the revenue-maximizing price&#8212;so was $1,000, to be fair, but we took the minimum of the two)</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Surveys, Data, and Vibes]]></title><description><![CDATA[It's okay to ask people what they want and believe them]]></description><link>https://www.underthenull.com/p/when-to-run-surveys</link><guid isPermaLink="false">https://www.underthenull.com/p/when-to-run-surveys</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Mon, 11 May 2026 14:02:42 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1613963931023-5dc59437c8a6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxzdXJ2ZXl8ZW58MHx8fHwxNzc4MzYwNzQwfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1613963931023-5dc59437c8a6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxzdXJ2ZXl8ZW58MHx8fHwxNzc4MzYwNzQwfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1613963931023-5dc59437c8a6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxzdXJ2ZXl8ZW58MHx8fHwxNzc4MzYwNzQwfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1613963931023-5dc59437c8a6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxzdXJ2ZXl8ZW58MHx8fHwxNzc4MzYwNzQwfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1613963931023-5dc59437c8a6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxzdXJ2ZXl8ZW58MHx8fHwxNzc4MzYwNzQwfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1613963931023-5dc59437c8a6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxzdXJ2ZXl8ZW58MHx8fHwxNzc4MzYwNzQwfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1613963931023-5dc59437c8a6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxzdXJ2ZXl8ZW58MHx8fHwxNzc4MzYwNzQwfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="4584" height="3063" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1613963931023-5dc59437c8a6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxzdXJ2ZXl8ZW58MHx8fHwxNzc4MzYwNzQwfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3063,&quot;width&quot;:4584,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;black and white printed textile&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="black and white printed textile" title="black and white printed textile" srcset="https://images.unsplash.com/photo-1613963931023-5dc59437c8a6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxzdXJ2ZXl8ZW58MHx8fHwxNzc4MzYwNzQwfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1613963931023-5dc59437c8a6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxzdXJ2ZXl8ZW58MHx8fHwxNzc4MzYwNzQwfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1613963931023-5dc59437c8a6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxzdXJ2ZXl8ZW58MHx8fHwxNzc4MzYwNzQwfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1613963931023-5dc59437c8a6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxzdXJ2ZXl8ZW58MHx8fHwxNzc4MzYwNzQwfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@jontyson">Jon Tyson</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>I&#8217;ve become less skeptical of surveys. Economics, as a field, has a bias for revealed preferences&#8212;what people do&#8212;over what they say, and I mostly inherited the biases of the field because, by default, you believe whatever you read when you were twenty-three. </p><p>But I&#8217;m becoming a fan of surveys. </p><p>This post is about both sides of the revealed vs. stated-preference divide. I talk about the problems with using surveys to package and price products and ways to replace some common survey use cases with revealed preference methods. But also about why sometimes it pays to just ask people what they&#8217;d do, and believe them.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>The difference between saying &#8220;I&#8217;d pay $100&#8221; and writing a check for $100 is the difference between the plan to run a marathon and lacing up. This is the fundamental problem with surveys.</p><p>Conjoints don&#8217;t solve this problem. Artificially creating a realistic choice set doesn&#8217;t bridge the gap between stating and paying. </p><p><em>[My little take here is that for the narrow task of pricing (as opposed to understanding the determinants of demand), conjoints are worse than just asking &#8220;would you pay $5?&#8221; My evidence is classified, but I&#8217;ve seen many price elasticities from conjoints, and they are always wrong to the point of being useless, while I&#8217;ve seen decent-enough results from the &#8220;would you pay $X for ___?&#8221; question.]</em></p><p>The right argument for running a survey is that we don&#8217;t have a good answer to the question: &#8220;what else could we do?&#8221; When there&#8217;s nothing else to do, you run a survey. But there&#8217;s a temptation to throw in the towel early because (we imagine) a survey is a time-bound, well-defined task that we can probably ship in a week or two. </p><p>But you can learn a lot from <em>revealed preferences</em> before you have to resort to <em>stated preferences</em>.</p><p>It&#8217;s rare to launch a genuinely new product, a product that&#8217;s completely unrelated to whatever else your company does, so you don&#8217;t have any relevant data. Most new products are re-packaging your existing product or a small new add-on. You want to offer an all-you-can-eat subscription, alongside your current &#224; la carte, transactional business. You&#8217;re going to start charging for a type of product usage that was previously free. Etcetera.</p><p>When revealed preference data exists that answers the relevant question, it&#8217;s better because it represents real checks.  For example, it might look like you don&#8217;t have any data on how people will respond to a price for a previously free product, but you can triangulate.</p><ul><li><p>When you introduced this product, how many more people signed up for the subscription? </p></li><li><p>When you raised the price by $5 last year, how many fewer people did?</p></li></ul><p>Combining those two answers tells you something about how valuable customers find the feature. You can say things like &#8220;people value the feature like a $3 reduction in the product&#8217;s price, so&#8230;&#8221; [You <em>do</em> need both parts here: variation in the presence of the feature and variation in the price.]</p><p>The point is that, if you&#8217;re a wee bit creative, you can use data to answer a broad class of questions before you need to make your own data via surveys.</p><div><hr></div><p>Surveys are worse than behavioral data, but they are 1000x better than vibes (the 1000x, however, was measured by vibes). </p><p>Analysis is a competitive market. If there&#8217;s no data analysis or survey, decisions will be made via vibes. There&#8217;s always an outside option. People don&#8217;t have to use any evidence at all to make decisions. You can just decide things. Vibes are always a backup plan.</p><p><em>[This is why I lean towards &#8220;give stakeholders something&#8221; instead of &#8220;we don&#8217;t really have any ready data on that&#8221; or &#8220;oh, that&#8217;ll be involved, we might be able to work that into the next sprint&#8221; (at which point the data is, to a rough approximation, always useless: the decision&#8217;s been made). The question is: &#8220;Do you have something that&#8217;s probably better than vibes?&#8221; If so, ship it.]</em></p><p>The point of a survey is to create data where we don&#8217;t have it. The typical types of missing data are:</p><ol><li><p>We don&#8217;t have price variation. The price has never changed before. </p></li><li><p>We don&#8217;t have product variation. Either everyone has always had the product, or no one has ever had it. So we don&#8217;t know how much anyone will like it.</p></li><li><p>We have no way to connect the new product to an existing product (it&#8217;s not just a re-packaging of goods we&#8217;re already selling).</p></li></ol><div><hr></div><p>It&#8217;s surprising how many problems in statistics amount to missing data problems. Causal inference is all about the fact that we don&#8217;t observe the potential outcome for treatments that people never experienced. Pricing new products is the same kind of problem. We don&#8217;t know what people will pay for products they&#8217;ve never been offered.</p><p>This is the key frame to use when writing surveys: what data is missing? We don&#8217;t just want to run survey to run a survey. We have a goal. We&#8217;re trying to fill in the gaps in our data. Answering this question makes writing a focused, short survey easy and natural. We need to ask questions that extract the missing data.</p><p>We don&#8217;t have price variation? Then we need to ask people, &#8220;Would you buy it at price X?&#8221; and &#8220;Would you buy it at price Y?&#8221; Bam. Now the price varies between X and Y.</p><p>We don&#8217;t have product variation? Suppose we&#8217;re looking at adding a new feature to a bundled subscription. Then, we need to ask the questions &#8220;Would you buy it at price X if it included feature Z?&#8221; and &#8220;Would you buy it at price X if it didn&#8217;t?&#8221; i.e., we need to keep the pricing constant and vary the feature set.</p><p>Another kind of missing data we need to extract from a pricing survey: the respondent's size. If you&#8217;re selling, say, a B2B product, the size of the company purchasing the product will be relevant to how much this customer&#8217;s price sensitivity matters. If you&#8217;re doing seat-based pricing, then you need to know the number of seats the respondent represents. If you&#8217;re selling a transaction-based or usage-based consumer product, you have to get a sense of how many potential transactions or how much potential usage the respondent represents. The particulars of how to do this depend on how demand scales for the product, but it&#8217;ll usually be something like &#8220;how many times do you run workflow X&#8221; or &#8220;how many employees work at your company&#8221;.</p><p>From there, you can maximize revenue/profit (depending on your cost structure) weighted by the respondent&#8217;s demand size (a lot of survey tools don&#8217;t do this sadly: they&#8217;ll just maximize revenue for you without taking into account demand size&#8212;alas). The demand curve is just given to you by the highest prices that people say they&#8217;re willing to accept. </p><p>I like to solve a problem that looks like this:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;P(a) = \\arg \\max_{P} \\sum_{i=1}^{n} 1\\left(a \\text{WTP}_{i} > P\\right) \\times P \\times W_{i} &quot;,&quot;id&quot;:&quot;LFSOQRWVXR&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>Where P is the price, W(i) is the weight associated with the size of the respondent&#8217;s demand (maybe based on their answer to company size questions, etc), WTP(i) is the highest price folks say they&#8217;re willing to pay (the survey usually gives an upper and lower bound on WTP, so it makes sense to solve this at each of those extremes), <em>a </em>is a discount or premium on people&#8217;s stated willingness to pay. I like to check for  robustness to deviations between stated willingness to pay and true willingness to pay, or even just to downweight WTP if you&#8217;re trying to price for growth. So you can plot the optimal price as a function of <em>a </em>and find a price that doesn&#8217;t vary a lot for small deviations in <em>a</em>.</p><p>There&#8217;s a bit of an art to this.</p><div><hr></div><p>For a well-targeted survey, a very high percentage of responses to the &#8220;Any other thoughts?&#8221; prompt are <em>really</em> thoughtful. This isn&#8217;t a real quote, but it&#8217;s illustrative of responses you&#8217;ll get: &#8220;Seat-based pricing wouldn&#8217;t really track the value here. We&#8217;d really only need one seat because only one engineer needs to manage this. The usage option you presented makes more sense, but only if there&#8217;s some cap or it gets cheaper as we scale&#8230;&#8221; </p><p>Humans like being helpful, and even though it takes them time, and it doesn&#8217;t really affect whether they get the $25 gift card, respondents take surveys seriously. Because humans are generally good folks who like to help their fellow corporate drones out. Go figure. The kids call this a &#8220;white pill&#8221; (I think?).</p><div><hr></div><p>It&#8217;s not like you have to blindly roll out the survey&#8217;s optimal price.  A couple of in-depth interviews with potential customers can at least make sure you&#8217;re not going off the deep end. If someone says, &#8220;That sounds reasonable,&#8221; it probably is. If they say, &#8220;lol what?&#8221; something&#8217;s probably gone wrong.</p><p>You don&#8217;t have to completely discard vibes. Vibes contain useful data. They&#8217;re a statistic of past experience. So, you can use them to discipline the survey, while still basing pricing (or other decisions) on data. If some respondents&#8217; stated willingness to pay makes no economic sense, just drop them. If you&#8217;re worried people are overstating their willingness to pay&#8212;before they have to actually convince Finance to sign off on it&#8212;then just underprice it (set <em>a &lt;</em> 1 in the above problem). </p><p>The point is that you can build trust in survey results. You don&#8217;t have to treat them as a machine that takes responses and converts them to decisions. This makes them infinitely more usable, despite their limitations.</p><div><hr></div><p>I&#8217;ve been thinking a lot about surveys recently. There might be a few more survey-focused techniques in upcoming blogs (thinking through some issues). </p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Subscribe, please! I&#8217;ve modeled the newsletter&#8217;s revenue-maximizing price at $0 and priced it accordingly!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p>]]></content:encoded></item><item><title><![CDATA[I Want To Get Good]]></title><description><![CDATA[In which I try to get good at a new thing]]></description><link>https://www.underthenull.com/p/i-want-to-get-good</link><guid isPermaLink="false">https://www.underthenull.com/p/i-want-to-get-good</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Sat, 09 May 2026 17:48:33 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1554757387-fa0367573d09?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxub3RlYm9va3xlbnwwfHx8fDE3NzgyMTU3MjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1554757387-fa0367573d09?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxub3RlYm9va3xlbnwwfHx8fDE3NzgyMTU3MjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1554757387-fa0367573d09?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxub3RlYm9va3xlbnwwfHx8fDE3NzgyMTU3MjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1554757387-fa0367573d09?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxub3RlYm9va3xlbnwwfHx8fDE3NzgyMTU3MjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1554757387-fa0367573d09?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxub3RlYm9va3xlbnwwfHx8fDE3NzgyMTU3MjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1554757387-fa0367573d09?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxub3RlYm9va3xlbnwwfHx8fDE3NzgyMTU3MjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1554757387-fa0367573d09?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxub3RlYm9va3xlbnwwfHx8fDE3NzgyMTU3MjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="5236" height="3491" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1554757387-fa0367573d09?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxub3RlYm9va3xlbnwwfHx8fDE3NzgyMTU3MjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3491,&quot;width&quot;:5236,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;opened notebook&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="opened notebook" title="opened notebook" srcset="https://images.unsplash.com/photo-1554757387-fa0367573d09?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxub3RlYm9va3xlbnwwfHx8fDE3NzgyMTU3MjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1554757387-fa0367573d09?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxub3RlYm9va3xlbnwwfHx8fDE3NzgyMTU3MjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1554757387-fa0367573d09?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxub3RlYm9va3xlbnwwfHx8fDE3NzgyMTU3MjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1554757387-fa0367573d09?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxub3RlYm9va3xlbnwwfHx8fDE3NzgyMTU3MjR8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@ashleywedwards">Ashley West Edwards</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>I&#8217;ve decided to write well.</p><p>Now, I know the first step traditionally is to move to Paris or a small American town&#8212;you can get away with NYC if you&#8217;ve got old money&#8212;and preferably not be employed in B2B SaaS, but I don&#8217;t have that kind of dedication. I like money, I have suburban tastes, and I like my neighbors like I like my comments&#8212;anonymous.</p><p>So, I&#8217;m going to try another tactic: practice. </p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/subscribe?"><span>Subscribe now</span></a></p><p>I&#8217;ve been blogging once or twice a month on <em>statistics</em> (which you call &#8220;data science&#8221; when you&#8217;re trying to get a job) for a few years now, but I&#8217;m going to write more frequently now. My goal is to put out a blog three out of every seven days.</p><p>Of course, that doesn&#8217;t mean I&#8217;ll write up three experimentation techniques every week, like in the old blogs. I have a limited supply of these! But I realized I had a lot of thoughts about industry tools, practices, news, etc., and just listing the ideas in my little <a href="https://www.fizzy.do/">Kanban board</a> made it clear there was enough content to do it. </p><p>So, we&#8217;re broadening our horizons, limited by the following principles:</p><ol><li><p>I have to care about the topic.</p></li><li><p>I have to know enough about it to not sound stupid (hard!).</p></li></ol><p>Especially looking forward to doing more tools-of-the-trade reviews! I did one recently on <a href="https://zachflynn.substack.com/p/reviewing-ggsql-a-grammar-of-graphics">ggsql</a>. There&#8217;s a ton of products, tools, techniques, etc that I&#8217;ve never really used because they weren&#8217;t used at prior jobs&#8212;or, they&#8217;re new&#8212;and it&#8217;d be fun to take a look at them. </p><p>I&#8217;ve got some initial ideas, but feel free to pitch me on tools to review! Including ones you wrote! (With the warning that I will say what I think of it. My rate for lying about how great your tool is $1 million. So readers should know that either I think the tool is really good or you paid me $1 million.)</p><p>Looking forward to the challenge! My current plan is to write the posts mainly over the weekend and schedule them throughout the week, but we&#8217;ll see how it evolves&#8230;</p><div><hr></div><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Marginal Science! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Reviewing ggsql, a grammar of graphics for SQL]]></title><description><![CDATA[Reviewing an SQL-ish ggplot from Posit!]]></description><link>https://www.underthenull.com/p/reviewing-ggsql-a-grammar-of-graphics</link><guid isPermaLink="false">https://www.underthenull.com/p/reviewing-ggsql-a-grammar-of-graphics</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Mon, 27 Apr 2026 04:46:45 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1642516303080-431f6681f864?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1Mnx8Y2hhcnR8ZW58MHx8fHwxNzc3MjY0NDExfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1642516303080-431f6681f864?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1Mnx8Y2hhcnR8ZW58MHx8fHwxNzc3MjY0NDExfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1642516303080-431f6681f864?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1Mnx8Y2hhcnR8ZW58MHx8fHwxNzc3MjY0NDExfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1642516303080-431f6681f864?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1Mnx8Y2hhcnR8ZW58MHx8fHwxNzc3MjY0NDExfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1642516303080-431f6681f864?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1Mnx8Y2hhcnR8ZW58MHx8fHwxNzc3MjY0NDExfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1642516303080-431f6681f864?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1Mnx8Y2hhcnR8ZW58MHx8fHwxNzc3MjY0NDExfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1642516303080-431f6681f864?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1Mnx8Y2hhcnR8ZW58MHx8fHwxNzc3MjY0NDExfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="3800" height="2250" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1642516303080-431f6681f864?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1Mnx8Y2hhcnR8ZW58MHx8fHwxNzc3MjY0NDExfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2250,&quot;width&quot;:3800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;a very large group of trees that are very colorful&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="a very large group of trees that are very colorful" title="a very large group of trees that are very colorful" srcset="https://images.unsplash.com/photo-1642516303080-431f6681f864?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1Mnx8Y2hhcnR8ZW58MHx8fHwxNzc3MjY0NDExfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1642516303080-431f6681f864?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1Mnx8Y2hhcnR8ZW58MHx8fHwxNzc3MjY0NDExfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1642516303080-431f6681f864?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1Mnx8Y2hhcnR8ZW58MHx8fHwxNzc3MjY0NDExfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1642516303080-431f6681f864?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1Mnx8Y2hhcnR8ZW58MHx8fHwxNzc3MjY0NDExfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@maxberg">Maxim Berg</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>Posit released a new library for graphics programming (plotting) in a SQL-ish style language called <strong><a href="https://ggsql.org/">ggsql</a></strong>. It&#8217;s aiming to be like its ggplot project for R/Python, but with a SQL-ish syntax, which, I guess, is becoming more and more the language of everything (remember the NoSQL moment in the early 2010&#8217;s&#8230; yeah, that&#8217;s dead).</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/subscribe?"><span>Subscribe now</span></a></p><p></p><p>I gave it a spin over the weekend on some &#8220;ancient&#8221; data I re-discovered in an old Dropbox folder. In grad school, I scraped the internet for this data on radio station coverage and formed markets from sequences of intersecting stations for this paper I was working on. </p><p>The site was trying to stop scrapers, so I had a Perl script randomly cycle through a set of User Agents and switch Tor proxies frequently while downloading thousands of pages (it blocked every 1-5 and the algorithm tried to find the right combo of waiting + user agent switching + tor proxy restart that would unblock me). The site&#8217;s solution for stopping scraping was pretty good. It took my little eeePC netbook (remember those!) weeks to get all the data with all the switching, random pausing, and delays I threw in there to get past the detection automatically. I just kept the laptop open night and day. The big hole in their scraping-prevention technique was that they assumed the scraper valued their time and sanity more than paying them $100 (I think it was about that much to get a computer-readable form of the data). Their model of the world did not include a graduate student making ~$10k a year, who was perfectly content to parse HTML and wait weeks to save $100.</p><p>In any case, I haven&#8217;t looked at this data in forever, so it felt like the perfect laboratory to poke around with ggsql.</p><p>Funny coincidence: this paper was the last project I worked on, where I used <a href="https://cran.r-project.org/web/packages/lattice/index.html">lattice</a> for the graphs, not ggplot.</p><h2>What ggsql does (with a few examples)</h2><p>ggsql uses a &#8220;reader&#8221; that processes the pure SQL parts of the statement and the ggsql extensions. The easiest way for me to test things was with the DuckDBReader, which lets me visualize the output of DuckDB queries. I imagine there are other readers for different databases (or, there soon will be).  </p><p>ggsql outputs <a href="https://vega.github.io/">Vega</a> (a JSON format for graphics). Vega makes a lot of sense as an output target because it&#8217;s flexible, low-level, and plays nicely on the web side + it&#8217;s got some institutional support, and tools on top of this are sort of the key to making ggsql valuable. We can transform it directly on the web via the JavaScript library, so you can send the Vega output to the front end and render it on the fly. </p><p>To get a sense for what it looks like, here&#8217;s the syntax for plotting a histogram of the number of radio stations within each market.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;sql&quot;,&quot;nodeId&quot;:&quot;1c9d7475-c4e5-4f43-949e-e397495e67a0&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-sql">SELECT * FROM radio_markets
VISUALIZE Firms AS x
DRAW histogram
LABEL title =&gt; 'Radio Station Distribution Across Markets',
x =&gt; 'Radio Stations',
y =&gt; 'Markets'
</code></pre></div><p>This is what it looks like after rendering:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LJ_e!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F893dfa6d-5d40-4174-8760-4e88e7539136_1000x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LJ_e!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F893dfa6d-5d40-4174-8760-4e88e7539136_1000x600.png 424w, https://substackcdn.com/image/fetch/$s_!LJ_e!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F893dfa6d-5d40-4174-8760-4e88e7539136_1000x600.png 848w, https://substackcdn.com/image/fetch/$s_!LJ_e!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F893dfa6d-5d40-4174-8760-4e88e7539136_1000x600.png 1272w, https://substackcdn.com/image/fetch/$s_!LJ_e!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F893dfa6d-5d40-4174-8760-4e88e7539136_1000x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LJ_e!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F893dfa6d-5d40-4174-8760-4e88e7539136_1000x600.png" width="1000" height="600" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/893dfa6d-5d40-4174-8760-4e88e7539136_1000x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:1000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:50166,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://zachflynn.substack.com/i/194825798?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F893dfa6d-5d40-4174-8760-4e88e7539136_1000x600.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LJ_e!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F893dfa6d-5d40-4174-8760-4e88e7539136_1000x600.png 424w, https://substackcdn.com/image/fetch/$s_!LJ_e!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F893dfa6d-5d40-4174-8760-4e88e7539136_1000x600.png 848w, https://substackcdn.com/image/fetch/$s_!LJ_e!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F893dfa6d-5d40-4174-8760-4e88e7539136_1000x600.png 1272w, https://substackcdn.com/image/fetch/$s_!LJ_e!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F893dfa6d-5d40-4174-8760-4e88e7539136_1000x600.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The part preceding <code>VISUALIZE</code> is just standard SQL. You can add <code>WHERE</code>, <code>JOIN</code> stuff, etc.</p><p>After <code>VISUALIZE, </code>we enter ggsql mode and start providing (approximately) the ggplot arguments in this SQL-ish syntax.</p><p>If you&#8217;ve used ggplot before, there&#8217;s this concept of &#8220;aesthetics&#8221; where we define the x-axis, the y-axis, colors, etc. <code>VISUALIZE Firms AS x</code> puts the SQL variable <code>Firm</code> into the <code>x</code> part of the aesthetic. You can also do <code>VISUALIZE Firms As X, blah AS Y, blah2 AS color, etc, etc</code>.</p><p>The <code>DRAW</code> clause tells it what kind of visualization to make (you can have multiple DRAW layers, of course), and <code>LABEL</code>&#8230; labels things (it can also change the tick labels, not just the axes, and alter any legends, etc).</p><p>By the way, to actually run this, I wrote a Python script. That&#8217;s clearly not the vision for how to use this. The idea is more of a notebook or other UI that can parse Vega output automatically to show the visualizations as output from an SQL cell or as results in an SQL-running UI, like Databricks/BigQuery/etc. But for messing around with it, you can do something like this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;d686cf67-39c0-4748-b8e1-73defe1d934d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import ggsql
import pandas as pd
import duckdb

df = pd.read_csv("radio_market_selected_30.csv", sep=":")

with duckdb.connect("radio.db") as con:
    con.sql("CREATE OR REPLACE TABLE radio_markets AS SELECT * FROM df")
    
reader = ggsql.DuckDBReader("duckdb://radio.db")

viz_query = """
SELECT * FROM radio_markets
VISUALIZE Firms AS x
DRAW histogram
SCALE y
LABEL title =&gt; 'Radio Station Distribution Across Markets',
x =&gt; 'Radio Stations',
y =&gt; 'Markets'
"""

viz = reader.execute(viz_query)

writer = ggsql.VegaLiteWriter()
vegalite_json = writer.render(viz)
print(vegalite_json)</code></pre></div><p>And then, I just did:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:&quot;12e9365e-5a71-4986-9862-3a6d8a3091b4&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">python3 histogram.py | xclip -selection clipboard</code></pre></div><p>And rendered it in Vega&#8217;s online demo thing: <a href="https://vega.github.io/editor/">https://vega.github.io/editor/</a></p><p>[PS. Did you notice the source file is colon-separated lol? As best I can figure, given how long ago this was, I did it that way because the city names had commas in them (Peoria, IL), and I didn&#8217;t want to quote the strings :) ]</p><p>To show the SQL elements of this, here&#8217;s the same chart, deleting the long tail that starts at around 200 stations.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;sql&quot;,&quot;nodeId&quot;:&quot;abac966b-ce77-4ed2-9fa3-c51fc5a7b4b5&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-sql">SELECT * FROM radio_markets
WHERE Firms &lt;= 200
VISUALIZE Firms AS x
DRAW histogram
LABEL title =&gt; 'Radio Station Distribution Across Markets',
x =&gt; 'Radio Stations',
y =&gt; 'Markets'</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!U1N-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c1e55d3-2d71-4f8c-90df-2aa4a27903ff_1000x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!U1N-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c1e55d3-2d71-4f8c-90df-2aa4a27903ff_1000x600.png 424w, https://substackcdn.com/image/fetch/$s_!U1N-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c1e55d3-2d71-4f8c-90df-2aa4a27903ff_1000x600.png 848w, https://substackcdn.com/image/fetch/$s_!U1N-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c1e55d3-2d71-4f8c-90df-2aa4a27903ff_1000x600.png 1272w, https://substackcdn.com/image/fetch/$s_!U1N-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c1e55d3-2d71-4f8c-90df-2aa4a27903ff_1000x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!U1N-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c1e55d3-2d71-4f8c-90df-2aa4a27903ff_1000x600.png" width="1000" height="600" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5c1e55d3-2d71-4f8c-90df-2aa4a27903ff_1000x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:1000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:51748,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://zachflynn.substack.com/i/194825798?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c1e55d3-2d71-4f8c-90df-2aa4a27903ff_1000x600.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!U1N-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c1e55d3-2d71-4f8c-90df-2aa4a27903ff_1000x600.png 424w, https://substackcdn.com/image/fetch/$s_!U1N-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c1e55d3-2d71-4f8c-90df-2aa4a27903ff_1000x600.png 848w, https://substackcdn.com/image/fetch/$s_!U1N-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c1e55d3-2d71-4f8c-90df-2aa4a27903ff_1000x600.png 1272w, https://substackcdn.com/image/fetch/$s_!U1N-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c1e55d3-2d71-4f8c-90df-2aa4a27903ff_1000x600.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The best way to explore a new tool and figure out if it&#8217;s really a sensible system worth adopting is to just try to make something more involved from the basic getting-started examples, without referencing the docs until you absolutely have to. What you&#8217;re looking for is whether things work logically together. You start to intuit the logic of a system (or lack thereof) when you force yourself to try and figure it out instead of just Googling/LLM&#8217;ing for &#8220;how do I&#8230;&#8221;</p><p>ggsql definitely passes that test. It&#8217;s natural and intuitive. Here&#8217;s a slightly more involved example to see what I mean:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;sql&quot;,&quot;nodeId&quot;:&quot;053ff093-2f4e-49e8-8af7-d71b05297ccf&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-sql">SELECT * FROM radio_markets
WHERE Firms &lt;= 200
VISUALIZE Area AS x, Firms AS y
DRAW point
   MAPPING Population AS size
   SETTING fill =&gt; null
LABEL title =&gt; 'Radio Stations and Physical Area',
x =&gt; 'Radio Stations',
y =&gt; 'Land Area (sq. mi.)',
size =&gt; 'Population (100k)'</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9nL2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c930f67-f8c0-4059-93f7-4feb877a3682_1000x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9nL2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c930f67-f8c0-4059-93f7-4feb877a3682_1000x600.png 424w, https://substackcdn.com/image/fetch/$s_!9nL2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c930f67-f8c0-4059-93f7-4feb877a3682_1000x600.png 848w, https://substackcdn.com/image/fetch/$s_!9nL2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c930f67-f8c0-4059-93f7-4feb877a3682_1000x600.png 1272w, https://substackcdn.com/image/fetch/$s_!9nL2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c930f67-f8c0-4059-93f7-4feb877a3682_1000x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9nL2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c930f67-f8c0-4059-93f7-4feb877a3682_1000x600.png" width="1000" height="600" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0c930f67-f8c0-4059-93f7-4feb877a3682_1000x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:1000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:84033,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://zachflynn.substack.com/i/194825798?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c930f67-f8c0-4059-93f7-4feb877a3682_1000x600.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9nL2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c930f67-f8c0-4059-93f7-4feb877a3682_1000x600.png 424w, https://substackcdn.com/image/fetch/$s_!9nL2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c930f67-f8c0-4059-93f7-4feb877a3682_1000x600.png 848w, https://substackcdn.com/image/fetch/$s_!9nL2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c930f67-f8c0-4059-93f7-4feb877a3682_1000x600.png 1272w, https://substackcdn.com/image/fetch/$s_!9nL2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c930f67-f8c0-4059-93f7-4feb877a3682_1000x600.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h1>My Takes</h1><p>First off, this is super smooth, and I&#8217;ve always liked the &#8220;grammar of graphics&#8221; idea. It&#8217;s conceptually clear, easy to use, and easy to extend. It&#8217;s a great way to add plots to SQL. The part I&#8217;m stuck thinking about after playing with it is whether that&#8217;s what I want to do&#8230;</p><p>I can&#8217;t see this being very useful as a standalone thing. Even in a notebook, the utility seems limited. Being in SQL in-and-of-itself seems like it would only matter to the set of people who <em>can</em> be bothered to learn this new syntax but <em>can&#8217;t </em>be bothered to learn/don&#8217;t already know basic Python/R. I haven&#8217;t run a survey, but I&#8217;m pretty sure that&#8217;s an empty set. If I&#8217;m in a notebook, I already have access to ggplot/matplotlib/whatever, and I probably know how to use it.</p><p>One standalone use case that is valuable: it should make it easier to run visualizations on your main database compute engine, avoiding first loading the query results into your instance and then running Python/R/etc. You can return the Vega from the compute, plot it, and never touch the full dataset locally. That is super valuable if you&#8217;re plotting a larger dataset.</p><p>But the better use case really needs a full system where folks&#8212;or their Robots&#8212;write visualizations inline in a BI tool. ggsql (in its current state) isn&#8217;t a real replacement for the kind of viz you&#8217;d want in a BI tool, though. It&#8217;s not a language that can express (as far as I can tell) table viz, pivot tables, single value elements, layouts, etc. So, it&#8217;s got some of the elements, but not enough to replace a dashboard-like system. </p><p>On the other hand, it seems &#8220;right&#8221; to extend SQL with a declarative visualization layer on top of it. A good direction to go&#8212;and I have a feeling this is the plan&#8212;would be to add their <strong><a href="https://gt.rstudio.com/">grammar of tables</a> </strong>as well to get a fuller system for expressing visual output in SQL.</p><p>Another thing I noticed was that I don&#8217;t think the <code>VISUALIZE</code> syntax is exactly a SQL extension in the sense that I don&#8217;t think it really has the same semantics or processing. Here&#8217;s an example I stumbled upon because this old dataset still has the base-R-like periods substituting for spaces in variable names:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;d097d19c-f3b8-4d00-bd81-cc6ea92c89cf&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">import duckdb
import ggsql
import pandas as pd

df = pd.DataFrame({"numbers": [1,2], "variable": [3,4], "variable.dotted": [3, 4]})
with duckdb.connect("reproduce.db") as con:
    con.sql("CREATE OR REPLACE TABLE test AS SELECT * FROM df")

reader = ggsql.DuckDBReader("duckdb://reproduce.db")

## Quoting the dotted variable name works in DuckDB.

with duckdb.connect("reproduce.db") as con:
    print(con.sql("SELECT \"variable.dotted\" FROM test"))

### But not in ggsql
viz_query = """
SELECT * FROM test
VISUALIZE numbers AS x, "variable.dotted" AS y
DRAW line
LABEL title =&gt; 'variable ~ numbers'
"""
viz = reader.execute(viz_query)

writer = ggsql.VegaLiteWriter()
vegalite_json = writer.render(viz) # errors</code></pre></div><p>I haven&#8217;t done a deep dive into the code base, but this very minor bug (?) suggests to me that ggsql sits outside the SQL engine and isn&#8217;t transparently working on the SQL elements. At least, that&#8217;s my first guess at why quoting wouldn&#8217;t work in its context.  I could be wrong here, and maybe it&#8217;s just a bug on the Writer side (I filed an issue with the GitHub project, so maybe that&#8217;ll be all it is). It&#8217;s a small thing anyway.</p><h1>Conclusion</h1><p>In general, this is a nice solution to the problem of wanting ggplot in SQL. It solves that problem fantastically. Very clean. Very intuitive if you already know ggplot. I could guess how to do things after an hour or two playing with it, and I was usually right. So, that&#8217;s an incredibly strong win.</p><p>I&#8217;m less convinced it&#8217;ll become anyone&#8217;s daily driver unless it delivers a full BI experience. In the short run, I see the main use case being to create visualizations for large datasets that you don&#8217;t want to pull into memory. That&#8217;s a real use case, but a bit narrower than I was hoping for when I started playing with it.</p><p>As of today, I think it&#8217;d be faster for me, in most cases, to just copy-paste the query output into Google Sheets and plot it there if I want a quick visualization, but we&#8217;ll see where things go!</p><p>Things are happening&#8212;even in SQL.</p><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect at: <a href="https://www.linkedin.com/in/zlflynn/">https://www.linkedin.com/in/zlflynn/</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Good Enough Statistics! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[New Things With Pseudo-True Estimators]]></title><description><![CDATA[Reading Club: Optimally-Transported GMM]]></description><link>https://www.underthenull.com/p/new-things-with-pseudo-true-estimators</link><guid isPermaLink="false">https://www.underthenull.com/p/new-things-with-pseudo-true-estimators</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Fri, 17 Apr 2026 06:40:42 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1535905557558-afc4877a26fc?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8Ym9va3xlbnwwfHx8fDE3Nzg0OTk0ODh8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1535905557558-afc4877a26fc?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8Ym9va3xlbnwwfHx8fDE3Nzg0OTk0ODh8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1535905557558-afc4877a26fc?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8Ym9va3xlbnwwfHx8fDE3Nzg0OTk0ODh8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1535905557558-afc4877a26fc?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8Ym9va3xlbnwwfHx8fDE3Nzg0OTk0ODh8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1535905557558-afc4877a26fc?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8Ym9va3xlbnwwfHx8fDE3Nzg0OTk0ODh8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1535905557558-afc4877a26fc?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8Ym9va3xlbnwwfHx8fDE3Nzg0OTk0ODh8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1535905557558-afc4877a26fc?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8Ym9va3xlbnwwfHx8fDE3Nzg0OTk0ODh8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="4000" height="6000" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1535905557558-afc4877a26fc?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8Ym9va3xlbnwwfHx8fDE3Nzg0OTk0ODh8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:6000,&quot;width&quot;:4000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;library shelf near black wooden ladder&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="library shelf near black wooden ladder" title="library shelf near black wooden ladder" srcset="https://images.unsplash.com/photo-1535905557558-afc4877a26fc?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8Ym9va3xlbnwwfHx8fDE3Nzg0OTk0ODh8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1535905557558-afc4877a26fc?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8Ym9va3xlbnwwfHx8fDE3Nzg0OTk0ODh8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1535905557558-afc4877a26fc?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8Ym9va3xlbnwwfHx8fDE3Nzg0OTk0ODh8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1535905557558-afc4877a26fc?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxMXx8Ym9va3xlbnwwfHx8fDE3Nzg0OTk0ODh8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@henry_be">enrico bet</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><h2>Reading Club! April Edition!</h2><p>I&#8217;m starting a new thing. I&#8217;m going to write about a recent paper that strikes my fancy  once a month. More as a commitment device for myself to keep up with the lit than anything. I won&#8217;t just dive into the paper. I&#8217;ll talk about the relevant literature beforehand so the post is more or less self-contained.</p><p>This month&#8217;s paper is from a little-known, small journal from the fringes of Economics academia: &#8220;Econometrica.&#8221; It&#8217;s about figuring out how best to use the data to inform model estimates when we&#8217;ve got enough evidence to know the model&#8217;s &#8220;wrong.&#8221;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/subscribe?"><span>Subscribe now</span></a></p><p>It&#8217;s one of those excuses you&#8217;ll hear. &#8220;I know the model&#8217;s wrong, but all models are wrong,&#8221; and you, the listener, who is both smarter and better-looking, think, &#8220;Well, yes, but, like, clearly there&#8217;s a limit to that. If it&#8217;s <em>really</em> wrong about important things, that matters!&#8221; Wouldn&#8217;t you know it? There is a whole literature about estimation when we know the model is sort of wrong. Here&#8217;s part of it and the links!</p><p>The Paper: March 2026, Econometrica: <a href="https://www.econometricsociety.org/publications/econometrica/2026/03/01/Optimally-Transported-Generalized-Method-of-Moments">https://www.econometricsociety.org/publications/econometrica/2026/03/01/Optimally-Transported-Generalized-Method-of-Moments</a> </p><p>Free ArXiv Link: <a href="https://arxiv.org/pdf/2511.05712">https://arxiv.org/pdf/2511.05712</a> </p><h2>Generalized Method of Moments</h2><p>To grok the paper, we have to start with the kind of estimation problem we&#8217;re looking at. It&#8217;s a Generalized Method of Moments problem, a very common method in economics, but the thing about statistics is that many fields teach it and they all do it a little differently&#8212;mostly by historical accident. I think I&#8217;d like this framework, even if I wasn&#8217;t brainwashed into liking it by my education, but I guess that counterfactual is unobserved&#8230; It&#8217;s a nice, flexible way to look at the empirical implications of a model.</p><p>Suppose we have a vector of parameters <em>b</em>. The Generalized Method of Moments (GMM) thinks about problems where the parameters are identified by &#8220;moment restrictions&#8221; like this:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;E[g(X, b)] = 0&quot;,&quot;id&quot;:&quot;YGBPQYSVON&quot;}" data-component-name="LatexBlockToDOM"></div><p>You can write a slew of common estimators like this. </p><ul><li><p>OLS: E[X(Y - X&#8217;b)] = 0</p></li><li><p>IV: E[Z(Y - X&#8217;b)] = 0</p></li><li><p>Maximum Likelihood: E[ (dlog f/db)(X, b)] = 0</p></li><li><p>Quantile regression: E[X (p - 1(Y &lt;= X&#8217;b))] = 0</p></li><li><p>Etc.</p></li></ul><p>The idea is that Models produce moments, so by finding the model parameters that satisfy the moment conditions, we identify the version of our model that matches the data.</p><p>For another example, in an older post, <a href="https://zachflynn.substack.com/p/accelerating-online-experiments-that-target-quantile-treatment-effects-2">I used GMM to build this estimator that reduces the variance of quantile treatment effects in experiments.</a></p><p>Usually, we estimate the model by solving some version of this problem:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\min_{b} \\hat{E}[g(X_{i}, b)]^{\\top} W \\hat{E}[g(X_{i}, b)]&quot;,&quot;id&quot;:&quot;KOKQHADAIH&quot;}" data-component-name="LatexBlockToDOM"></div><p>For some weighting matrix W. The estimator is consistent for any positive definite W, so the choice comes down to efficiency. </p><h2>Overidentification</h2><p>But sometimes models produce more moments than we need to estimate the parameters. This &#8220;overidentification&#8221; is useful because it allows us to use the extra moments to test whether the model is true. Intuition: a subset of the moment conditions pins down the model parameters, but we still have other moment conditions left over after fitting that we can plug the model parameters into to see whether all the restrictions can hold simultaneously.</p><p>But what if the model fails the test? What if it&#8217;s rejected by the data? It&#8217;s not terribly surprising that a model doesn&#8217;t hold exactly. So, how can we decide whether the model is wrong in the sense that it&#8217;s a simplification of a messy reality or if it&#8217;s wrong in the sense that we&#8217;re missing something critical?</p><p>One idea that emerged in the literature was: what if we could minimize the distance between our modeling assumptions and the data? We could capture some &#8220;pseudo-true&#8221; parameter, i.e., the most realistic parameter for the model given the data.</p><p>The parameter estimated by the GMM procedure above doesn&#8217;t really reflect that goal. It finds the parameter that minimizes the weighted norm of the moment conditions, which can have strong efficiency properties if the model is correctly specified. But if the model is wrong? Well, then the GMM estimator doesn&#8217;t really connect well with intuition about a parameter that minimizes the distance between the data and what the model requires. It&#8217;s just minimizing the norm of the moment conditions.</p><h2>Empirical Likelihood</h2><p>One idea in this vein is known as Empirical Likelihood, or EL. The empirical distribution assigns probability 1/n to each X(i), and we know this distribution doesn&#8217;t satisfy the moment conditions for any parameter b, but what if we take the mass points of the empirical distribution and tilt them until the moment conditions <em>are</em> satisfied for some b? What if we estimated the distribution of the data, subject to the constraint that it satisfies our model? </p><p>The empirical likelihood estimator does exactly like that. It maximizes the likelihood of the data subject to the moment condition:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\max \\sum \\log p_{i} \\quad st: \\quad \\sum p_{i} g(X_{i}, b) = 0, p_{i} >= 0, \\sum p_{i} = 1&quot;,&quot;id&quot;:&quot;IRXWTPYNKM&quot;}" data-component-name="LatexBlockToDOM"></div><p>Note that without the moment conditions, the solution to this problem is p(i) = 1/n, i.e., the empirical distribution. The non-negativity constraints can&#8217;t bind because the derivative of log approaches infinity as its argument approaches 0, so the first order condition is:</p><p>1/p(i) = lambda =&gt; all the p(i)&#8217;s are equal so p(i) = 1/n.</p><p>That means that if there were a <em>b</em> parameter that satisfied the moment conditions, we would just set p(i) = 1/n and not make any adjustments to the data. We&#8217;re effectively maximizing the log likelihood of the empirical distribution subject to the constraints of our model.</p><p>Even though there are <em>n + dimension(b)</em> number of parameters, there are nice tricks for computing the estimator from the first order conditions, i.e.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;1/p(i) - \\sum \\mu_{k} g_{k}(X_{i}, b) = \\lambda&quot;,&quot;id&quot;:&quot;TYXRGBDTRS&quot;}" data-component-name="LatexBlockToDOM"></div><p>So, </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;p_{i}(\\lambda + \\sum \\mu_{k} g_{k}(X_{i}, b)) = 1. &quot;,&quot;id&quot;:&quot;MLCXJAFKEU&quot;}" data-component-name="LatexBlockToDOM"></div><p>Summing across i gives (from sum p(i) = 1 and sum p(i) g_k(X(i),b) = 0:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\lambda = n&quot;,&quot;id&quot;:&quot;ODDRPAVTBK&quot;}" data-component-name="LatexBlockToDOM"></div><p>For any given &#8220;b&#8221;, we can then solve for mu via the equations:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\sum g(X_{i},b) / (n + \\mu&#8217;g(X_{i},b)) = 0&quot;,&quot;id&quot;:&quot;EJJXYHVVEN&quot;}" data-component-name="LatexBlockToDOM"></div><p>Define the solution as \mu(b).</p><p>So we have this lower-dimensional estimation problem:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\max -\\log(n + \\mu(b)&#8217;g(X_{i}, b))&quot;,&quot;id&quot;:&quot;UCRPLKHAEO&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><h2>Optimally-Transported GMM</h2><p>EL is what the maximum likelihood estimator of the empirical distribution would be if we added our model&#8217;s constraints, but this isn&#8217;t the only way to get at this problem. What if, instead of looking for the closest distribution to the empirical distribution by adjusting probabilities, we changed the mass points?</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\min_{Z,b} \\sum ||X_{i} - Z_{i}||^{2} \\quad st: \\quad \\sum g(Z_{i},b) = 0&quot;,&quot;id&quot;:&quot;CSLJBAJTCC&quot;}" data-component-name="LatexBlockToDOM"></div><p>So, now we&#8217;re keeping the empirical distribution's even weighting but perturbing the data points to make the moment conditions hold, minimizing the distance we travel to &#8220;transport&#8221; X to Z.</p><p>Like EL, this problem also has a convenient solution despite being a high-dimensional optimization problem, but this time based on successive linear approximation, see Algorithm 2.1 in the paper.</p><p>The estimator is intuitive. It finds a distribution of the data that minimizes change, as measured by a clear metric that satisfies the moment conditions. You get numbers for Z(i), so you can start asking questions like: if X(i) had to change that much, do I think I&#8217;m really on the right path in modeling this? Or: yeah, that seems like it&#8217;s just a little off&#8212;fine. It&#8217;s a nice way to quantify how bad a problem the misspecification is.</p><p>Empirical Likelihood can do something similar, but to me, anyway, I have a lot more intuition about variable-space than about probability weights&#8212;your mileage may vary. &#8220;You&#8217;re telling me I have to make revenue numbers twice as large&#8230; weird. I don&#8217;t know if I believe this. No, I don&#8217;t think I do.&#8221;</p><p>Downsides here are that I&#8217;m not sure E[||X-Z||^{2}] is really the loss function we have in mind when we&#8217;re thinking about minimizing how much we change covariates&#8212;I don&#8217;t think it&#8217;s crazy or anything, but I think we&#8217;re usually thinking about something a little less&#8230; &#8220;cardinal&#8221;, is maybe the word I&#8217;m looking for. There are some variables that I can&#8217;t imagine being mismeasured, so I&#8217;m suspicious of moving them around.  The method doesn&#8217;t really depend on the loss function here, but once you&#8217;re out of the least squares-ish world, you lose the nice computational trick, and you&#8217;ve got an n x dimension(X) parameter to optimize over&#8230;</p><p>One idea I had here was to make the problem a little more specific and, based on that, identify more intuitive restrictions for the particular problem. </p><p>For example, the overidentified linear IV model:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;E[W(Y - X&#8217;b)] = 0&quot;,&quot;id&quot;:&quot;EZDKAGZPPF&quot;}" data-component-name="LatexBlockToDOM"></div><p>And the misspecification we&#8217;re worried about is that some of the IV&#8217;s are invalid. So, write:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;Y = X&#8217;b + U, \\quad \\text{where U is the structural residual.}&quot;,&quot;id&quot;:&quot;LPPHNBPQUP&quot;}" data-component-name="LatexBlockToDOM"></div><p>And so, we&#8217;ve got:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;E[W(Y - X&#8217;b)] = E[WU] \\ne 0&quot;,&quot;id&quot;:&quot;ERCBUDBTXX&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>Maybe the misspecification problem is that U = E + U* where E is correlated with W but U* isn&#8217;t, so if instead the world had produced U* as the structural residual we wouldn&#8217;t have any misspecification. We could solve for the minimum &#8220;E&#8221; that solves the problem, like so:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\min_{E,b} \\sum |E(i)|^{2} \\quad st: \\sum W_{i}(Y_{i} - X_{i}&#8217;b - E_{i}) = 0&quot;,&quot;id&quot;:&quot;DNNDSYTYOV&quot;}" data-component-name="LatexBlockToDOM"></div><p>So now we have a structural interpretation of the error. If I had to give any modeling advice&#8230; knowing <em>what</em> the error is is the first step toward wisdom&#8230;</p><p>Anyway, I think there are many other interesting applications of this idea and Empirical Likelihood, but I don&#8217;t think I&#8217;ve ever seen it used in industry, despite seeing many examples of overidentified IV models rejected by the data. If you&#8217;ve got a GMM problem and the time, it&#8217;s worth taking a look at these methods to get a sense of the size of the misspecification problem, and, if it&#8217;s small, using pseudo-true estimates that balance the model and the data.</p><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Good Enough Statistics! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[The Death and Resurrection of the Two-Language Problem]]></title><description><![CDATA[A "Julia" for LLMs]]></description><link>https://www.underthenull.com/p/the-death-and-resurrection-of-the</link><guid isPermaLink="false">https://www.underthenull.com/p/the-death-and-resurrection-of-the</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Tue, 14 Apr 2026 06:46:16 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1506351541065-2de5d60265b3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw3fHx0d298ZW58MHx8fHwxNzc2MTI0MzUyfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1506351541065-2de5d60265b3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw3fHx0d298ZW58MHx8fHwxNzc2MTI0MzUyfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1506351541065-2de5d60265b3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw3fHx0d298ZW58MHx8fHwxNzc2MTI0MzUyfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1506351541065-2de5d60265b3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw3fHx0d298ZW58MHx8fHwxNzc2MTI0MzUyfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1506351541065-2de5d60265b3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw3fHx0d298ZW58MHx8fHwxNzc2MTI0MzUyfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1506351541065-2de5d60265b3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw3fHx0d298ZW58MHx8fHwxNzc2MTI0MzUyfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1506351541065-2de5d60265b3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw3fHx0d298ZW58MHx8fHwxNzc2MTI0MzUyfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="2633" height="1757" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1506351541065-2de5d60265b3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw3fHx0d298ZW58MHx8fHwxNzc2MTI0MzUyfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1757,&quot;width&quot;:2633,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;two giraffe illustration&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="two giraffe illustration" title="two giraffe illustration" srcset="https://images.unsplash.com/photo-1506351541065-2de5d60265b3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw3fHx0d298ZW58MHx8fHwxNzc2MTI0MzUyfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1506351541065-2de5d60265b3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw3fHx0d298ZW58MHx8fHwxNzc2MTI0MzUyfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1506351541065-2de5d60265b3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw3fHx0d298ZW58MHx8fHwxNzc2MTI0MzUyfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1506351541065-2de5d60265b3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw3fHx0d298ZW58MHx8fHwxNzc2MTI0MzUyfDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@vincentvanzalinge">Vincent van Zalinge</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>Once upon a time, there was a &#8220;Two-Language Problem&#8221; (which led to the creation of Julia; see the <a href="https://math.mit.edu/~edelman/publications/julia_a_fresh.pdf">old texts</a>). The problem was that while most analysis took place in high-level languages like Python or R, both were too slow, so most of the core logic of the various mathematical and statistical packages is not actually written in either language. It&#8217;s written in C (or in Fortran for many R packages). </p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/p/the-death-and-resurrection-of-the?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/p/the-death-and-resurrection-of-the?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p>One of the main selling points of Julia was that it avoided needing two languages by using a compiler with multiple dispatch to mimic a lot of the niceties of a dynamically-typed, flexible language while still being performant because it could act more like a compiled, statically-type language (each function is compiled once types are known, so the code generated knows the data type). </p><p>I like Julia because multiple dispatch and the language's more functional nature fit mathematics and statistics well. I was never bothered by using two languages in a project. It&#8217;s actually kind of a nice experience to write the parts of an analysis that need to be performant in Fortran, and handle the data cleaning, etc., in R.</p><p>But I admit to liking C and Fortran because they were the first two languages I learned to program in. So, I&#8217;m biased.</p><p>And yet&#8230; like when Nixon said &#8220;We&#8217;re all Keynesians now&#8221;, we&#8217;re all two-language people now. The dream of one language has been deferred. The new dual-language world is Natural Language and X, where X is one of those old programming languages that requires you to think logically and carefully about what you&#8217;re doing (lame). </p><p>Before, the distinction was between a language where you needed to think in bytes and data types and a language where you could be a little more loosey-goosey about such things. Now, the distinction is between a language where you need to think in syntax and semantics and structure, and a language where you don&#8217;t.</p><p>We won&#8217;t be able to ditch structured language entirely. Natural language is a lossy representation of computing, just as the flexible scripting languages before it were. But it loses precision that can&#8217;t be recovered by spending performance.</p><p>The lossyness of Python and Ruby hurt performance. The lossyness of Natural Language hits business logic.</p><p>I predict a language will emerge that solves the modern two-language &#8220;problem&#8221;.  It&#8217;ll be a more structured version of Natural Language that adds back some information, while still partially keeping the loosey-goosey feel of &#8220;build Spotify, make no mistakes.&#8221;</p><p>What I have in mind. Imagine you&#8217;re building a web app purely with AI today. You&#8217;re going to type lots of prompts to fix various things as you debug the app, but that doesn&#8217;t really scale for an app of any real complexity. Natural Language isn&#8217;t precise enough. In most cases, it&#8217;s quicker and better to just fix the code directly once the project is closer to being done.</p><p>But let&#8217;s say you defined things a little more precisely, then maybe you could keep it in Natural Language longer, i.e., in some kind of MVC-ish language:</p><ul><li><p>My app has a Model for users. They have passwords and emails and have to log in. Users can&#8217;t access other users&#8217; stuff unless it&#8217;s been shared with them.</p><ul><li><p>We need endpoints for users to sign-up, log-in, log-out,&#8230;</p></li></ul></li><li><p>My app has a Model for books. Users can write books or upload them as .epubs and share them with each other. There is an in-app reader for books.</p><ul><li><p>We need endpoints for &#8230;</p></li></ul></li><li><p>Etc</p></li></ul><p>So, I&#8217;m specifying the Model and a bit about the Controller components of MVC, and letting the LLM fill in what the views and controllers look like.</p><p>This scaffolding holds a lot more information than &#8220;clone Kindle.&#8221; I can add a model for pages read and mention that I want to bill by that metric rather than fixed prices, and I think the LLMs would do a decent job.</p><p>But this doesn&#8217;t really approach a maintainable language. I think we&#8217;ll get there. Someone will come up with a language that uses this newfangled LLM thing to both keep the expressiveness of Natural Language and recover some of the precision of structured language. </p><p>Or at least that&#8217;s where I hope it goes, because I doubt the old structured languages will ever gain market share.</p><p><em>(Alternatively, we&#8217;ll drown in endless AI slop, where nothing is built to last, and the past severs from the future, so that we exist in a never-ending present, neither returning nor progressing, until our souls, which yearn to plant some small monument, vanish into the void&#8230;)</em></p><p>I bet the language will look kind of like YAML, if I had to guess.</p><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Good Enough Statistics! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Emergency Blog: Big Arch Review]]></title><description><![CDATA[The blog's first food review!]]></description><link>https://www.underthenull.com/p/emergency-blog-big-arch-review</link><guid isPermaLink="false">https://www.underthenull.com/p/emergency-blog-big-arch-review</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Thu, 09 Apr 2026 03:51:47 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1567278526167-6290689c10d4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxtY2RvbmFsZHxlbnwwfHx8fDE3NzU3MDU2NDB8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1567278526167-6290689c10d4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxtY2RvbmFsZHxlbnwwfHx8fDE3NzU3MDU2NDB8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1567278526167-6290689c10d4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxtY2RvbmFsZHxlbnwwfHx8fDE3NzU3MDU2NDB8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1567278526167-6290689c10d4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxtY2RvbmFsZHxlbnwwfHx8fDE3NzU3MDU2NDB8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1567278526167-6290689c10d4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxtY2RvbmFsZHxlbnwwfHx8fDE3NzU3MDU2NDB8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1567278526167-6290689c10d4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxtY2RvbmFsZHxlbnwwfHx8fDE3NzU3MDU2NDB8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1567278526167-6290689c10d4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxtY2RvbmFsZHxlbnwwfHx8fDE3NzU3MDU2NDB8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="3024" height="4032" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1567278526167-6290689c10d4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxtY2RvbmFsZHxlbnwwfHx8fDE3NzU3MDU2NDB8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:4032,&quot;width&quot;:3024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;McDonald's sign post&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="McDonald's sign post" title="McDonald's sign post" srcset="https://images.unsplash.com/photo-1567278526167-6290689c10d4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxtY2RvbmFsZHxlbnwwfHx8fDE3NzU3MDU2NDB8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1567278526167-6290689c10d4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxtY2RvbmFsZHxlbnwwfHx8fDE3NzU3MDU2NDB8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1567278526167-6290689c10d4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxtY2RvbmFsZHxlbnwwfHx8fDE3NzU3MDU2NDB8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1567278526167-6290689c10d4?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwzfHxtY2RvbmFsZHxlbnwwfHx8fDE3NzU3MDU2NDB8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@andeeew">Andreeew Hoang</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>I love McDonald&#8217;s. I eat there 3-4 times a week&#8212;down from 5 pre-Covid, which is how we&#8217;re all marking time (from &#8220;since the birth of God&#8221; to &#8220;since the Plague&#8221;&#8230;). I couldn&#8217;t do that back in grad school (no money for such extravagances), but now that I have a real job... </p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/p/emergency-blog-big-arch-review?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/p/emergency-blog-big-arch-review?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p>I&#8217;ve eaten just about everything on the menu locally, but they add things&#8230; If you&#8217;ve seen the awkward vid of the McDonald&#8217;s CEO eating a hamburger, you might&#8217;ve caught that what he&#8217;s promoting is the Big Arch, a new burger. The idea, if you listen to this great segment from the WSJ (free on <a href="https://www.youtube.com/watch?v=rZxnFI2OW9k">YouTube</a>) with the CEO, is to try to capture a slice of the premium burger market. </p><p>It&#8217;s going to work. Now, I know it&#8217;s in keeping with this blog&#8217;s usual thing to do an actual analysis with some math and a little theory, but this time I&#8217;ve got a better, more convincing reason. I tried it tonight, and I have news to report:</p><p><strong>It tastes like the fruit must have tasted in the <a href="https://en.wikipedia.org/wiki/Garden_of_Eden">garden</a>.</strong> </p><p>Dear God.</p><p>Homer sang of the Lotus Eaters, a people who were lulled into a state of perfect apathy where they forgot their homes, their goals, and their loves upon tasting the fruit of the Lotus and desired only to eat it and bask in the bliss it offered for the rest of their days. I now understand why such a life might be desirable.</p><p>In a world where everyone&#8217;s out there making the robots write their CRUD apps, it&#8217;s a breath of fresh air to see true innovation in the wild.</p><p>Let&#8217;s get into specifics:</p><ul><li><p>The patty is truly big. Much larger and thicker than you&#8217;d expect from McDonald&#8217;s. A bit off-brand in this respect, but it&#8217;s so well done. Delectable.</p></li><li><p>They have these little fried onion things for some crunch. It crunches.</p></li><li><p>The sauce is very Big Mac-ish, so if you&#8217;re a fan of that (like me), you&#8217;ll dig it.</p></li><li><p>I was almost full before the fries (I eat in order: first burger, then fries. I&#8217;m not an animal).</p></li></ul><p>This is my true and honest review. Sadly, McDonald&#8217;s did not pay me for this. If they want to send money, I won&#8217;t decline. I am 100% for sale. I want to be clear on that.</p><p>The Big Arch will be my go-to for as long as they have it. Fabulous work, <span class="cashtag-wrap" data-attrs="{&quot;symbol&quot;:&quot;$MCD&quot;}" data-component-name="CashtagToDOM"></span> gang. </p><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Good Enough Statistics! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Rebranding Data Scientist]]></title><description><![CDATA[It involves Magic and Augury. Wait! Hear me out:]]></description><link>https://www.underthenull.com/p/rebranding-data-scientist</link><guid isPermaLink="false">https://www.underthenull.com/p/rebranding-data-scientist</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Fri, 03 Apr 2026 19:40:41 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!NGKX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67d29a0a-f837-4459-8b91-cb5ce76b03ee_400x300.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NGKX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67d29a0a-f837-4459-8b91-cb5ce76b03ee_400x300.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NGKX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67d29a0a-f837-4459-8b91-cb5ce76b03ee_400x300.gif 424w, https://substackcdn.com/image/fetch/$s_!NGKX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67d29a0a-f837-4459-8b91-cb5ce76b03ee_400x300.gif 848w, https://substackcdn.com/image/fetch/$s_!NGKX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67d29a0a-f837-4459-8b91-cb5ce76b03ee_400x300.gif 1272w, https://substackcdn.com/image/fetch/$s_!NGKX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67d29a0a-f837-4459-8b91-cb5ce76b03ee_400x300.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NGKX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67d29a0a-f837-4459-8b91-cb5ce76b03ee_400x300.gif" width="400" height="300" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/67d29a0a-f837-4459-8b91-cb5ce76b03ee_400x300.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:300,&quot;width&quot;:400,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:576726,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://zachflynn.substack.com/i/191876830?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67d29a0a-f837-4459-8b91-cb5ce76b03ee_400x300.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NGKX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67d29a0a-f837-4459-8b91-cb5ce76b03ee_400x300.gif 424w, https://substackcdn.com/image/fetch/$s_!NGKX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67d29a0a-f837-4459-8b91-cb5ce76b03ee_400x300.gif 848w, https://substackcdn.com/image/fetch/$s_!NGKX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67d29a0a-f837-4459-8b91-cb5ce76b03ee_400x300.gif 1272w, https://substackcdn.com/image/fetch/$s_!NGKX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67d29a0a-f837-4459-8b91-cb5ce76b03ee_400x300.gif 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We all know that Data Scientist is a silly name. What kind of science doesn&#8217;t use data? Vagueness is the first sin of good science, and we&#8217;re putting it right in the name!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/p/rebranding-data-scientist?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/p/rebranding-data-scientist?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p>I&#8217;m proposing a new job title: Table Reader. Now, I know what you&#8217;re thinking. &#8220;Table Reader is reductive. I don&#8217;t just read Tables! I do other things!&#8221; Okay. I&#8217;m sure you do. Really. I believe that is your truth.</p><p>By &#8220;Reader&#8221;, I do not mean a &#8220;Book Reader,&#8221; of course. I mean it in the Mystical sense. You aren&#8217;t &#8220;Analyzing&#8221; (vague and Latinate). You&#8217;re taking a Reading, tracing the palm lines of the Table and considering what the flight paths of birds might have to say (using weather as an instrument). Google Sheets has been missing a spiritual layer.</p><p>Data Scientist doesn&#8217;t say anything about what we actually do. Table Reader evokes.</p><p>A question arises. You consult the Tables for guidance, perform the Rites, Read the signs, and tell folks what the Tables say. </p><p>Each word is a strict improvement. Table is better than Data because it specifies the kind of data we look at. Data covers a lot more than tables, but the job doesn&#8217;t.</p><p>Reader is better than Scientist because it evokes Magic and Mysticism, which is both more inspiring <em>and</em> accurate. I&#8217;m not saying the Art has a <em>lot</em> in common with Divination, but it has more in common with that Practice than Chemistry. </p><p>For example, a computer is a Technology. If we both give it the same instructions, it&#8217;ll do the same thing. My nature and experience don&#8217;t affect the way it operates.</p><p>Magic is different. If the extensive literature on the working of Magic has established anything, it is that the Practice is particular to the individual. For example, Magic can be acquired via being born a wizard (Rowling, J.K. 1997), or you can be gifted powers by a strange lady who spends a lot of time in the woods (Map, Walter c. 1220), or be possessed by the Gods (Pythia, c. 1400BC), or learn to speak the language and meanings of the Nonmen, all but destroyed in the First Apocalypse, when the No-God, Mog-Pharau, rose millennia ago (Bakker, Scott R. 2004)&#8230;. we&#8217;re getting off track.</p><p>The point is that if we give the same Tables to two Table Readers, we&#8217;ll get different answers. It requires experience and intuition to know which signs are real and which are misleading, which models &#8220;make sense&#8221; and which don&#8217;t. So, Table Reading is an individual Art. </p><p>But, you say, &#8220;There is Math involved!&#8221; Sure, the Practice may use aspects of Science or Technology, like Mathematics, but consider: </p><p>If an Augur foretells the future by learning the biology necessary to identify the different parts of an animal&#8217;s entrails and from these gains insights into the length of Caesar&#8217;s reign, do we say he is doing Science? In part. But the Science is only necessary to construct the components of the Magic. The Science serves the Magic. So, clearly, Augury is a Magic.</p><p>In a similar way, the Science serves the Table Reader&#8217;s judgement as he or she divines whether the treatment is good or bad, whether to run this in logs or levels, whether we&#8217;re going to make next quarter&#8217;s targets or not, what kinds of fixed effects to use, and whether there are any plausible excuses to explain this product&#8217;s failure that should not obviously have been foreseen by you or your stakeholders (I kid, I kid).</p><p>So, we need a name that evokes Judgement and Practice, not Science: Table Reader.</p><p>I also considered &#8220;Table Teller&#8221;, but it sounded too authoritative, too crafted. In the good version of our profession, we merely read what the Tables tell <em>us. </em>We don&#8217;t instruct the tables, like the Medium doesn&#8217;t instruct the Spirits. We listen to Them.</p><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect on LinkedIn: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a>.</p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Good Enough Statistics! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[A workhorse method for measuring censored relationships]]></title><description><![CDATA[Without making distributional assumptions!]]></description><link>https://www.underthenull.com/p/a-workhorse-method-for-measuring</link><guid isPermaLink="false">https://www.underthenull.com/p/a-workhorse-method-for-measuring</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Fri, 06 Mar 2026 20:45:19 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1610337673044-720471f83677?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxjZW5zb3JlZHxlbnwwfHx8fDE3NzI4Mjk3NjF8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1610337673044-720471f83677?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxjZW5zb3JlZHxlbnwwfHx8fDE3NzI4Mjk3NjF8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1610337673044-720471f83677?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxjZW5zb3JlZHxlbnwwfHx8fDE3NzI4Mjk3NjF8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1610337673044-720471f83677?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxjZW5zb3JlZHxlbnwwfHx8fDE3NzI4Mjk3NjF8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1610337673044-720471f83677?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxjZW5zb3JlZHxlbnwwfHx8fDE3NzI4Mjk3NjF8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1610337673044-720471f83677?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxjZW5zb3JlZHxlbnwwfHx8fDE3NzI4Mjk3NjF8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1610337673044-720471f83677?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxjZW5zb3JlZHxlbnwwfHx8fDE3NzI4Mjk3NjF8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="4568" height="3434" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1610337673044-720471f83677?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxjZW5zb3JlZHxlbnwwfHx8fDE3NzI4Mjk3NjF8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3434,&quot;width&quot;:4568,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;purple and yellow abstract painting&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="purple and yellow abstract painting" title="purple and yellow abstract painting" srcset="https://images.unsplash.com/photo-1610337673044-720471f83677?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxjZW5zb3JlZHxlbnwwfHx8fDE3NzI4Mjk3NjF8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1610337673044-720471f83677?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxjZW5zb3JlZHxlbnwwfHx8fDE3NzI4Mjk3NjF8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1610337673044-720471f83677?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxjZW5zb3JlZHxlbnwwfHx8fDE3NzI4Mjk3NjF8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1610337673044-720471f83677?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwxfHxjZW5zb3JlZHxlbnwwfHx8fDE3NzI4Mjk3NjF8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@lazycreekimages">Michael Dziedzic</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>We&#8217;re going to talk mainly about the general problem of understanding censored relationships, but specifics make generality easier to grok&#8230; </p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/p/a-workhorse-method-for-measuring?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/p/a-workhorse-method-for-measuring?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p>Suppose we want to understand how the time until a Free/Basic Plan customer signs up for the Premium/Ultra/Mega Package varies with different actions or incentives the customer takes or receives. For customers that do eventually sign up for Premium, we observe the time it took them to do so from when they first signed up for the Free Plan. <em>But </em>for customers that <em>haven&#8217;t</em> signed up for Premium, the only thing we know about their Time to Premium is that it is greater than however long it&#8217;s been so far, i.e. we only have a lower bound on their Time to Premium. We&#8217;re missing data.</p><p>Most of causal inference is about making assumptions to fill in missing data. We don&#8217;t know what so-and-so would have done if they hadn&#8217;t been treated, so we find people who weren&#8217;t treated and say they&#8217;re kind of like so-and-so and fill in the treated subject&#8217;s missing outcome with theirs. In censored problems, like this one, we come up with an assumption about what the censored data would look like.</p><p>The classical methods <a href="https://zachflynn.substack.com/p/central-limit-theorems-and-the-deeper-naivete-2">(recall that &#8220;classical&#8221; is math-speak for &#8220;lame&#8221;</a>) use parametric assumptions&#8212;impose a functional form on the censored variable&#8217;s distribution&#8212;to make the censored variable informative about the full distribution.</p><p>The classical example looks like this:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;y = x^{\\top}b+ e, \\quad e \\sim N(0, s^{2})&quot;,&quot;id&quot;:&quot;HFJOUBXNXO&quot;}" data-component-name="LatexBlockToDOM"></div><p>Where we only observe <em>y* = max{y, 0} </em>and <em>y</em> is unobserved<em>. b </em>and <em>s </em>are the parameters to estimate.</p><p>The parametric assumption, that <em>y</em> is normally distributed, allows the uncensored data to be informative about the distribution of the censored data because we know:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;y* | x \\sim \\text{truncated normal}(x^{\\top} b, s^{2}, 0, \\infty)&quot;,&quot;id&quot;:&quot;HWJFTVBIMD&quot;}" data-component-name="LatexBlockToDOM"></div><p>And we can identify the parameters of this distribution just from data on (y*, x). The normality of e allows us to connect the error from the uncensored data to what the error would be on the censored data. But this is a very strong assumption and we&#8217;re essentially letting functional form tell us about the extent of the censoring problem. Not very satisfying!</p><p>What is the most we can identify without this kind of functional form assumption?</p><p>What can we learn about how the distribution of a latent, censored variable changes with a covariate without making distributional assumptions about what we can&#8217;t see?</p><p>Fundamentally, the question of how the distribution of <em>y</em> changes with <em>x</em> is a question about how quantiles change. So, write:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;y = f_{t}\\left(x\\right) + e_{t} \\quad \\forall t \\in \\left(0,1\\right), \\quad \\text{pr}\\left(e_{t} \\le 0 | x\\right) = t&quot;,&quot;id&quot;:&quot;ZRZGWOIASX&quot;}" data-component-name="LatexBlockToDOM"></div><p><em>f</em> is the conditional quantile of <em>y</em> given <em>x</em>.</p><p>Let <em>v</em> be a uniform random variable drawn on (0,1). Then, here&#8217;s a random variable that has the same distribution as <em>y</em> given <em>x = x</em>: </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;f_{v}(x)&quot;,&quot;id&quot;:&quot;RMFGERPXCL&quot;}" data-component-name="LatexBlockToDOM"></div><p>So, if we can identify this quantile function, we&#8217;ll know a lot about how <em>x</em> affects <em>y</em>.</p><p>The problem is that we don&#8217;t observe y, so we can&#8217;t just estimate the model using our favorite quantile regression method.</p><p>Instead, we observe <em>y*</em> = max{<em>y</em>, 0}. </p><p>What we&#8217;re going to do is show that for a certain set of (x,t) we <em>can</em> identify f(t,x). Maybe that set is good enough that we don&#8217;t need to make any other assumptions. We can answer whatever question we&#8217;re asking the data just from identified points of the quantile function. If we need more, then we can extrapolate, i.e. make the dirty parametric assumptions, but we can do so, starting from points that are identified <em>without</em> having to make such compromises.</p><p>Whenever I&#8217;m thinking about how to identify something, I start with the distribution function. The reason to start there is that it fully characterizes the information available in the data. So it gives you the most identifying power to play with. </p><p>The data we have available to us is (y*, x). So let&#8217;s do a little algebra and see what y* given x tells us.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{pr}\\left[y^{\\star} \\le u | x \\right] = \\text{pr}\\left[\\max\\left\\{f_{t}\\left(x\\right) + e_{t}, 0\\right\\} \\le u | x \\right]&quot;,&quot;id&quot;:&quot;YXFCXRMSWT&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;= \\text{pr}\\left[f_{t}\\left(x\\right) + e_{t} \\le u | x, f_{t}\\left(x\\right) + e_{t} \\ge 0\\right] \\text{pr}\\left[f_{t}\\left(x\\right) + e_{t} \\ge 0\\right]  &quot;,&quot;id&quot;:&quot;IMUPWEQJPY&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;+ 1\\left(0 \\le u\\right)\\left(1 - \\text{pr}\\left[f_{t}\\left(x\\right) + e_{t} \\ge 0 | x\\right]\\right)&quot;,&quot;id&quot;:&quot;HHYCPWCJMP&quot;}" data-component-name="LatexBlockToDOM"></div><p>Let p(x) = pr[f(x,t) + e(t) &#8805; 0 | x] be the probability of <em>not</em> being censored, conditional on <em>x</em>. The nice thing here is that we can estimate this function from the data because we know whether each observation is censored.</p><p>Let C be the event of an observation being censored. Then we can write the above as.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;pr\\left[y^{\\star} \\le u | x\\right] = pr\\left[f_{t}\\left(x\\right) + e_{t} \\le u |x, \\neg C\\right] p(X) + 1(0 &#8804; u) (1&#8202;&#8212;&#8202;p(x))&quot;,&quot;id&quot;:&quot;MNHYNIZJPK&quot;}" data-component-name="LatexBlockToDOM"></div><p>At all points on y*&#8217;s support, u is nonnegative because y* is nonnegative, so:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;pr\\left[y^{\\star} \\le u |x\\right] = pr\\left[f_{t}\\left(x\\right) + e_{t} \\le u |x, \\neg C\\right] p(x) + (1&#8202;&#8212;&#8202;p(x))&quot;,&quot;id&quot;:&quot;CPSLHMFTLY&quot;}" data-component-name="LatexBlockToDOM"></div><p>Let&#8217;s substitute in the true quantile function of <em>y</em> for <em>u</em> here:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{pr}\\left[y^{\\star} \\le f_{t}\\left(x\\right) | x\\right] = \\text{pr}\\left[y \\le f_{t}\\left(x\\right) | x, \\neg C\\right] p\\left(x\\right) + \\left(1 - p(x)\\right)&quot;,&quot;id&quot;:&quot;MPZCUYEHXG&quot;}" data-component-name="LatexBlockToDOM"></div><p>Because f is the conditional quantile function, we know:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;t = pr[y \\le f_{t}(x) |x] = pr[y \\le f_{t}(x)|x, \\neg C] p(x) + pr[y \\le f_{t}(x)|x, C] (1-p(x))&quot;,&quot;id&quot;:&quot;MGPPLNJMDN&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;t&#8202;&#8212;&#8202;pr[y \\le f_{t}(x)|x, C] (1-p(x)) = pr[y &#8804; f_{t}(x)|x, \\neg C] p(x)&quot;,&quot;id&quot;:&quot;EPFSMRYUXX&quot;}" data-component-name="LatexBlockToDOM"></div><p>So substitute for that term in the conditional CDF of y* expression:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;pr[y^{\\star} \\le f_{t}(x) |x] = t&#8202;&#8212;&#8202;pr[y \\le f_{t}(x) | x, C] (1-p(x)) + (1-p(x)) &quot;,&quot;id&quot;:&quot;GUWPFQWZDK&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;= t + (1&#8202;&#8212;&#8202;pr[y \\le f_{t}(x) | x, C]) (1-p(x))&quot;,&quot;id&quot;:&quot;NWHRPCQNFA&quot;}" data-component-name="LatexBlockToDOM"></div><p>Now, we&#8217;re cooking. We&#8217;ve got the true quantile that we want (<em>t)</em> plus a bias term introduced by the censoring. It turns out that we can actually identify the set of (x,t) where the bias term is 0.</p><p>Suppose that for a certain (x,t): p(x) = 1 - t + c where c &gt; 0.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;p(x) = \\text{pr}\\left[ f_{t}\\left(x\\right) + e_{t} \\ge 0|x\\right] = 1 - \\text{pr}\\left[e_{t} \\le -f_{t}\\left(x\\right)|x\\right] = 1 - t + c&quot;,&quot;id&quot;:&quot;BORUTWXLNR&quot;}" data-component-name="LatexBlockToDOM"></div><p>Because:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;1 - \\text{pr}\\left[e_{t}\\le 0 |x\\right] = 1 - t&quot;,&quot;id&quot;:&quot;YHJQILYCUA&quot;}" data-component-name="LatexBlockToDOM"></div><p>We must have that <em>f(t,x)</em> <em>&gt; 0</em> because <em>c &gt; 0</em>.</p><p>If the data is censored, then y &lt; 0. Because f(t,x) &gt; 0, the probability of y being less than f(t,x) <em>given</em> that y is censored is 100%. So:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;pr[y^{\\star} \\le u |x] = t + (1&#8202;&#8212;&#8202;pr[y \\le f_{t}(x) | x, C]) (1-p(x)) = t + \\left(1 - 1\\right)\\left(1 - p(x)\\right)&quot;,&quot;id&quot;:&quot;IMBXLCXZRG&quot;}" data-component-name="LatexBlockToDOM"></div><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;= t&quot;,&quot;id&quot;:&quot;TEEIZVRFVH&quot;}" data-component-name="LatexBlockToDOM"></div><p>So, for any (x,t) with sufficient probability of not being censored, we can identify the conditional quantile of <em>y</em> given <em>x</em> just from the conditional quantile of <em>y*</em> given <em>x</em>.</p><p>Cool. What does that buy us? This tells us the set of quantiles and covariate variables for which we do not face a real censoring problem and can identify the quantile function directly from data on (y*, x). </p><p>Unfortunately, this will usually not be enough. We&#8217;ll need to know how the quantile function responds at other (x,t) besides the ones that aren&#8217;t identified.</p><p>My preferred method for doing this is to do one of the following, depending on what you need: simply parameterize f(x,t; r) with a vector of parameters <em>r</em>. This form of parametric assumption is more natural and easier to motivate than assumptions about the functional forms of residual densities because you&#8217;re choosing how a response function varies as the quantile increases and as covariates change, and the shape is strongly informed by the actually-identified points instead of being a functional form assumption without strong justification, i.e. in a simplified example: suppose you had the following point-identified points and one non-identified point:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{array}{cc}\n x &amp; f_{0.5}(x)\\\\\n2 &amp; 3.0\\\\\n4 &amp; ? \\\\\n6 &amp; 4.9 \\\\\n8 &amp; 6.2\n\\end{array}&quot;,&quot;id&quot;:&quot;DHHLFRNZTL&quot;}" data-component-name="LatexBlockToDOM"></div><p>It seems sort of reasonable to think it&#8217;s roughly linear with x in this example so that x=4 should have a median around 4. The point is that you can use the nonparametrically-identified shapes to inform what parametric restrictions you put on the problem to identify the rest.</p><p>Anyway, this is just a tool that I think is less well-known than it deserves to be. So, I&#8217;m sharing it. Enjoy!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Good Enough Statistics! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Statistics and Compute]]></title><description><![CDATA[The key question for whether LLM capability plateaus]]></description><link>https://www.underthenull.com/p/statistics-and-compute</link><guid isPermaLink="false">https://www.underthenull.com/p/statistics-and-compute</guid><dc:creator><![CDATA[Zach Flynn]]></dc:creator><pubDate>Mon, 23 Feb 2026 02:01:45 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1693921289604-aa37858636e6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxjb21wdXRlciUyMG9sZHxlbnwwfHx8fDE3NzE3OTAyOTl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1693921289604-aa37858636e6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxjb21wdXRlciUyMG9sZHxlbnwwfHx8fDE3NzE3OTAyOTl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1693921289604-aa37858636e6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxjb21wdXRlciUyMG9sZHxlbnwwfHx8fDE3NzE3OTAyOTl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1693921289604-aa37858636e6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxjb21wdXRlciUyMG9sZHxlbnwwfHx8fDE3NzE3OTAyOTl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1693921289604-aa37858636e6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxjb21wdXRlciUyMG9sZHxlbnwwfHx8fDE3NzE3OTAyOTl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1693921289604-aa37858636e6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxjb21wdXRlciUyMG9sZHxlbnwwfHx8fDE3NzE3OTAyOTl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1693921289604-aa37858636e6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxjb21wdXRlciUyMG9sZHxlbnwwfHx8fDE3NzE3OTAyOTl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="5855" height="3896" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1693921289604-aa37858636e6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxjb21wdXRlciUyMG9sZHxlbnwwfHx8fDE3NzE3OTAyOTl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3896,&quot;width&quot;:5855,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;an old computer sitting on the floor next to a wall&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="an old computer sitting on the floor next to a wall" title="an old computer sitting on the floor next to a wall" srcset="https://images.unsplash.com/photo-1693921289604-aa37858636e6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxjb21wdXRlciUyMG9sZHxlbnwwfHx8fDE3NzE3OTAyOTl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1693921289604-aa37858636e6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxjb21wdXRlciUyMG9sZHxlbnwwfHx8fDE3NzE3OTAyOTl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1693921289604-aa37858636e6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxjb21wdXRlciUyMG9sZHxlbnwwfHx8fDE3NzE3OTAyOTl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1693921289604-aa37858636e6?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxjb21wdXRlciUyMG9sZHxlbnwwfHx8fDE3NzE3OTAyOTl8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@mattgyver">Matt Benson</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>Look. The first thing I&#8217;m going to do is hook you. I&#8217;m going to tell you this is about AI and LLMs. You have to believe me that we&#8217;ll get there. If, along the way, this starts to look like it&#8217;s about time series regressions (&#8220;boring shit&#8221;), just trust me. Believe me. Keep the faith.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/p/statistics-and-compute?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.underthenull.com/p/statistics-and-compute?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><h2>Computation and Statistics</h2><p>Suppose we have a time-series regression (remember: trust me) where we don&#8217;t know the lag structure.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;y_{t} = a + \\sum_{p=1}^{\\infty} r_{p} y_{t-p} + e_{t}&quot;,&quot;id&quot;:&quot;BIQNSNKSOU&quot;}" data-component-name="LatexBlockToDOM"></div><p>We find the &#8220;best&#8221; model for the time series in terms of out-of-sample prediction error by using the following computational procedure:</p><ol><li><p>Fix an L, require that <em>p</em> cannot be greater than <em>L</em>, i.e. for every <em>p</em> greater than <em>L</em>, <em>r<sub>p</sub> = 0.</em></p></li><li><p>For each of the 2<sup>L</sup> candidate models, compute the cross-validation score by leaving out future data and evaluating how well the model predicts it.</p></li></ol><p>The reason we fix an L is that 2<sup>L</sup> gets awfully large awfully fast. Computationally, we just can&#8217;t evaluate that many models. L models our computational constraint. We have two possible scenarios:</p><ol><li><p>The optimal model selected via this criterion has max{p} = L.</p></li><li><p>The optimal model selected via this criterion has max{p} &lt; L.</p></li></ol><p>In scenario 1, we are <em>computationally constrained</em>. If we could increase L and make our model more flexible, our predictions would improve. We just need to call up NVIDIA and get more, better chips.</p><p>In scenario 2, we are <em>statistically constrained</em>. The problem isn&#8217;t that we don&#8217;t have enough computational power. The problem is that, given the data available to us, the best models we can construct are less flexible. We need more data before we can improve the model. NVIDIA can&#8217;t help us. If we spend billions of dollars on compute, the return on it will be zip, zilch, nada.</p><h2>LLMs</h2><p>The key question of how much core AI capability will improve over the next few years is whether we are computationally or statistically constrained. </p><p>Until now, LLMs have been primarily computationally constrained. When we got better chips, when folks spent more on compute, the result was better models. But I think anyone who&#8217;s used the tech over the past few years has noticed the core technology leveling off.</p><p>The difference between GPT 3.5 and 4.0 was <em>enormous</em>. I recall asking 3.5 to explain statistical significance in a stakeholder-friendly way, and it responded with gibberish that was so bad it didn&#8217;t even rise to the level of being wrong&#8212;and to a simple, textbook question! 4.0 was so much better that it boggled the mind. But 5.x&#8230; It&#8217;s fine. I&#8217;m sure it&#8217;s better, but I hardly notice.</p><p>I have no inside info, but it does make me wonder whether we aren&#8217;t moving into the statistically constrained regime&#8212;or, at least, will be in the next couple of cycles. And if we are&#8230; it&#8217;ll be very difficult to improve the core model. Throwing more parameters and more compute into the mix won&#8217;t change the mathematics.</p><p>Unlike other technologies, the returns to more data are not increasing. They decrease <em>rapidly</em>. <a href="https://projecteuclid.org/journals/annals-of-statistics/volume-10/issue-4/Optimal-Global-Rates-of-Convergence-for-Nonparametric-Regression/10.1214/aos/1176345969.full">You need exponential increases in data to generate </a><em><a href="https://projecteuclid.org/journals/annals-of-statistics/volume-10/issue-4/Optimal-Global-Rates-of-Convergence-for-Nonparametric-Regression/10.1214/aos/1176345969.full">sublinear</a></em><a href="https://projecteuclid.org/journals/annals-of-statistics/volume-10/issue-4/Optimal-Global-Rates-of-Convergence-for-Nonparametric-Regression/10.1214/aos/1176345969.full"> improvements in performance.</a></p><p>I think we&#8217;ll run into the statistical constraint sooner than the market&#8217;s priced in. Word prediction is a hard game. The difference between the right word and the wrong word is a big thing.</p><blockquote><p>The difference between the <em>almost right</em> word and the <em>right</em> word is really a large matter&#8212;'tis the difference between the lightning-bug and the lightning.</p><p><em>Mark Twain</em></p></blockquote><p>In math, the loss function is steep. Small errors are big errors. A steep loss function, combined with a very high dimensional, nonsmooth problem, implies we&#8217;ll need a lot of data. We&#8217;ll have to get it from somewhere.</p><p>I think I can see how it happens.</p><h2>Skills</h2><p>We <em>can&#8217;t</em> generate vast sums of additional, real data. The AI companies are already using as much as is plausibly available. So, we need to make <em>better</em> data, not just more. Structured data. We have to add single observations that are worth billions of unstructured rows. We need to generate data for LLMs rather than rely on data originally generated for other purposes.</p><p>This is where folks are going with &#8220;skills&#8221; and related ideas. Provide tight context in a structured format to give LLMs data that is worth a vast amount of unintentional data.</p><p>Going back to our time series example. Suppose we knew that there was a seasonal component that hit every four time units. So all the models that can&#8217;t capture that structure are right out. This tells us information that might take a long time series history to discover from the data alone.</p><p>In other words, <strong>skills are parameter restrictions.</strong> If the restrictions are true, they dramatically improve model performance. </p><p>In five years, I think the vast improvement in perceived LLM performance will come from these kinds of purpose-built skills, not from core model performance. The core model will soon run into statistical constraints, if it isn&#8217;t there already, but there will be skills that help it write better code, better emails, etc, by applying rules and logic that humans already know in a structured way.</p><p>Like in classical statistics, the way to learn more from a fixed data set is to make more credible assumptions about the data-generating process. Give the problem structure by applying what you know about how the world works, and stop requiring the data to learn everything.</p><p>The trick is to tell the data what to think when you know what it ought to think and to let it tell you what to think when you don&#8217;t. </p><p>Anyway, I think that&#8217;s why it&#8217;s going where it&#8217;s going.</p><p>Fewer chips, more context.</p><div><hr></div><p>Thanks for reading!</p><p>Zach</p><p>Connect at: <a href="https://linkedin.com/in/zlflynn">https://linkedin.com/in/zlflynn</a></p><p>Look at my website: <a href="https://zflynn.com">https://zflynn.com</a></p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.underthenull.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Good Enough Statistics! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><p></p>]]></content:encoded></item></channel></rss>