<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Essays on Max Woolf&#39;s Blog</title>
    <link>https://minimaxir.com/category/essays/</link>
    <description>Recent content in Essays on Max Woolf&#39;s Blog</description>
    <image>
      <title>Max Woolf&#39;s Blog</title>
      <url>https://minimaxir.com/android-chrome-512x512.png</url>
      <link>https://minimaxir.com/android-chrome-512x512.png</link>
    </image>
    <generator>Hugo</generator>
    <language>en</language>
    <copyright>Copyright Max Woolf © 2026</copyright>
    <lastBuildDate>Mon, 05 May 2025 10:15:00 -0700</lastBuildDate>
    <atom:link href="https://minimaxir.com/category/essays/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>As an Experienced LLM User, I Actually Don&#39;t Use Generative LLMs Often</title>
      <link>https://minimaxir.com/2025/05/llm-use/</link>
      <pubDate>Mon, 05 May 2025 10:15:00 -0700</pubDate>
      <guid>https://minimaxir.com/2025/05/llm-use/</guid>
      <description>But for what I &lt;em&gt;do&lt;/em&gt; use LLMs for, it&amp;rsquo;s invaluable.</description>
      <content:encoded><![CDATA[<p>Lately, I&rsquo;ve been working on codifying a personal ethics statement about my stances on generative AI as I have been very critical about <a href="https://minimaxir.com/2023/10/ai-sturgeons-law/">several</a> <a href="https://minimaxir.com/2024/08/ai-seinfeld/">aspects</a> of modern GenAI, and yet <a href="https://thenib.com/mister-gotcha/">I participate in it</a>. While working on that statement, I&rsquo;ve been introspecting on how I myself have been utilizing large language models for both my professional work as a Senior Data Scientist at <a href="https://www.buzzfeed.com/">BuzzFeed</a> and for my personal work blogging and <a href="https://github.com/minimaxir">writing open-source software</a>. For about a decade, I&rsquo;ve been researching and developing tooling around <a href="https://minimaxir.com/2017/04/char-embeddings/">text generation from char-rnns</a>, to the <a href="https://minimaxir.com/2019/09/howto-gpt2/">ability to fine-tune GPT-2</a>, to <a href="https://minimaxir.com/2020/07/gpt3-expectations/">experiments with GPT-3</a>, and <a href="https://minimaxir.com/2023/03/new-chatgpt-overlord/">even more experiments with ChatGPT</a> and other LLM APIs. Although I don&rsquo;t claim to the best user of modern LLMs out there, I&rsquo;ve had plenty of experience working against the cons of next-token predictor models and have become very good at finding the pros.</p>
<p>It turns out, to my surprise, that I don&rsquo;t use them nearly as often as people think engineers do, but that doesn&rsquo;t mean LLMs are useless for me. It&rsquo;s a discussion that requires case-by-case nuance.</p>
<h2 id="how-i-interface-with-llms">How I Interface With LLMs</h2>
<p>Over the years I&rsquo;ve utilized all the tricks to get the best results out of LLMs. The most famous trick is <a href="https://en.wikipedia.org/wiki/Prompt_engineering">prompt engineering</a>, or the art of phrasing the prompt in a specific manner to coach the model to generate a specific constrained output. Additions to prompts such as <a href="https://minimaxir.com/2024/02/chatgpt-tips-analysis/">offering financial incentives to the LLM</a> or simply <a href="https://minimaxir.com/2025/01/write-better-code/">telling the LLM to make their output better</a> do indeed have a quantifiable positive impact on both improving adherence to the original prompt and the output text quality. Whenever my coworkers ask me why their LLM output is not what they expected, I suggest that they apply more prompt engineering and it almost always fixes their issues.</p>
<p><strong>No one in the AI field is happy about prompt engineering</strong>, especially myself. Attempts to remove the need for prompt engineering with more robust <a href="https://en.wikipedia.org/wiki/Reinforcement_learning_from_human_feedback">RLHF</a> paradigms have only made it <em>even more rewarding</em> by allowing LLM developers to make use of better prompt adherence. True, &ldquo;Prompt Engineer&rdquo; as a job title <a href="https://www.wsj.com/articles/the-hottest-ai-job-of-2023-is-already-obsolete-1961b054?st=DMVDgm&amp;reflink=desktopwebshare_permalink">turned out to be a meme</a> but that&rsquo;s mostly because prompt engineering is now an expected skill for anyone seriously using LLMs. Prompt engineering works, and part of being a professional is using what works even if it&rsquo;s silly.</p>
<p>To that end, <strong>I never use ChatGPT.com</strong> or other normal-person frontends for accessing LLMs because they are harder to control. Instead, I typically access the backend UIs provided by each LLM service, which serve as a light wrapper over the API functionality which also makes it easy to port to code if necessary. Accessing LLM APIs like the ChatGPT API directly allow you to set <a href="https://promptengineering.org/system-prompts-in-large-language-models/">system prompts</a> which control the &ldquo;rules&rdquo; for the generation that can be very nuanced. Specifying specific constraints for the generated text such as &ldquo;keep it to no more than 30 words&rdquo; or &ldquo;never use the word &lsquo;delve&rsquo;&rdquo; tends to be more effective in the system prompt than putting them in the user prompt as you would with ChatGPT.com. Any modern LLM interface that does not let you explicitly set a system prompt is most likely <a href="https://docs.anthropic.com/en/release-notes/system-prompts">using their own system prompt</a> which you can&rsquo;t control: for example, when ChatGPT.com had an issue where it was <a href="https://openai.com/index/sycophancy-in-gpt-4o/">too sycophantic</a> to its users, OpenAI <a href="https://simonwillison.net/2025/Apr/29/chatgpt-sycophancy-prompt/">changed the system prompt</a> to command ChatGPT to &ldquo;avoid ungrounded or sycophantic flattery.&rdquo; I tend to use <a href="https://www.anthropic.com/">Anthropic</a> Claude&rsquo;s API — Claude Sonnet in particular — more than any ChatGPT variant because Claude anecdotally is less &ldquo;robotic&rdquo; and also handles coding questions much more accurately.</p>
<p>Additionally with the APIs, you can control the &ldquo;<a href="https://www.hopsworks.ai/dictionary/llm-temperature">temperature</a>&rdquo; of the generation, which at a high level controls the creativity of the generation. LLMs by default do not select the next token with the highest probability in order to allow it to give different outputs for each generation, so I prefer to set the temperature to <code>0.0</code> so that the output is mostly deterministic, or <code>0.2 - 0.3</code> if some light variance is required. Modern LLMs now use a default temperature of <code>1.0</code>, and I theorize that higher value is accentuating <a href="https://en.wikipedia.org/wiki/Hallucination_%28artificial_intelligence%29">LLM hallucination</a> issues where the text outputs are internally consistent but factually wrong.</p>
<h2 id="llms-for-professional-problem-solving">LLMs for Professional Problem Solving!</h2>
<p>With that pretext, I can now talk about how I have used generative LLMs over the past couple years at BuzzFeed. Here are outlines of some (out of many) projects I&rsquo;ve worked on using LLMs to successfully solve problems quickly:</p>
<ul>
<li>BuzzFeed site curators developed a new <a href="https://www.siteguru.co/seo-academy/website-taxonomy">hierarchal taxonomy</a> to organize thousands of articles into a specified category and subcategory. Since we had no existing labeled articles to train a traditional <a href="https://scikit-learn.org/stable/modules/multiclass.html">multiclass classification</a> model to predict these new labels, I wrote a script to hit the Claude Sonnet API with a system prompt saying <code>The following is a taxonomy: return the category and subcategory that best matches the article the user provides.</code> plus the JSON-formatted hierarchical taxonomy, then I provided the article metadata as the user prompt, all with a temperature of <code>0.0</code> for the most precise results. Running this in a loop for all the articles resulted in appropriate labels.</li>
<li>After identifying hundreds of distinct semantic clusters of BuzzFeed articles using data science shenanigans, it became clear that there wasn&rsquo;t an easy way to give each one unique labels. I wrote another script to hit the Claude Sonnet API with a system prompt saying <code>Return a JSON-formatted title and description that applies to all the articles the user provides.</code> with the user prompt containing five articles from that cluster: again, running the script in a loop for all clusters provided excellent results.</li>
<li>One BuzzFeed writer asked if there was a way to use a LLM to sanity-check grammar questions such as &ldquo;should I use an <a href="https://www.merriam-webster.com/grammar/em-dash-en-dash-how-to-use">em dash</a> here?&rdquo; against the <a href="https://www.buzzfeed.com/buzzfeednews/buzzfeed-style-guide">BuzzFeed style guide</a>. Once again I hit the Claude Sonnet API, this time copy/pasting the <em>full</em> style guide in the system prompt plus a command to <code>Reference the provided style guide to answer the user's question, and cite the exact rules used to answer the question.</code> In testing, the citations were accurate and present in the source input, and the reasonings were consistent.</li>
</ul>
<p>Each of these projects were off-hand ideas pitched in a morning standup or a Slack DM, and yet each project only took an hour or two to complete a proof of concept (including testing) and hand off to the relevant stakeholders for evaluation. For projects such as the hierarchal labeling, without LLMs I would have needed to do more sophisticated R&amp;D and likely would have taken days including building training datasets through manual labeling, which is not intellectually gratifying. Here, LLMs did indeed follow the <a href="https://en.wikipedia.org/wiki/Pareto_principle">Pareto principle</a> and got me 80% of the way to a working solution, but the remaining 20% of the work iterating, testing and gathering feedback took longer. Even after the model outputs became more reliable, LLM hallucination was still a concern which is why I also advocate to my coworkers to use caution and double-check with a human if the LLM output is peculiar.</p>
<p>There&rsquo;s also one use case of LLMs that doesn&rsquo;t involve text generation that&rsquo;s as useful in my professional work: <a href="https://platform.openai.com/docs/guides/embeddings">text embeddings</a>. Modern text embedding models technically are LLMs, except instead of having a head which outputs the logits for the next token, it outputs a vector of numbers that uniquely identify the input text in a higher-dimensional space. All improvements to LLMs that the ChatGPT revolution inspired, such as longer context windows and better quality training regimens, also apply to these text embedding models and caused them to improve drastically over time with models such as <a href="https://www.nomic.ai/blog/posts/nomic-embed-text-v1">nomic-embed-text</a> and <a href="https://huggingface.co/Alibaba-NLP/gte-modernbert-base">gte-modernbert-base</a>. Text embeddings have done a lot at BuzzFeed from identifying similar articles to building recommendation models, but this blog post is about generative LLMs so I&rsquo;ll save those use cases for another time.</p>
<h2 id="llms-for-writing">LLMs for Writing?</h2>
<p>No, I don&rsquo;t use LLMs for writing the text on this very blog, which I suspect has now become a default assumption for people reading an article written by an experienced LLM user. My blog is far too weird for an LLM to properly emulate. My writing style is blunt, irreverent, and occasionally cringe: even with prompt engineering plus <a href="https://www.promptingguide.ai/techniques/fewshot">few-shot prompting</a> by giving it examples of my existing blog posts and telling the model to follow the same literary style precisely, LLMs output something closer to Marvel movie dialogue. But even if LLMs <em>could</em> write articles in my voice I still wouldn&rsquo;t use them due of the ethics of misrepresenting authorship by having the majority of the work not be my own words. Additionally, I tend to write about very recent events in the tech/coding world that would not be strongly represented in the training data of a LLM if at all, which increases the likelihood of hallucination.</p>
<p>There is one silly technique I discovered to allow a LLM to improve my writing without having it do <em>my writing</em>: feed it the text of my mostly-complete blog post, and ask the LLM to pretend to be a cynical <a href="https://news.ycombinator.com/news">Hacker News</a> commenter and write five distinct comments based on the blog post. This not only identifies weaker arguments for potential criticism, but it also doesn&rsquo;t tell me what I <em>should</em> write in the post to preemptively address that negative feedback so I have to solve it organically. When running a rough draft of this very blog post and the Hacker News system prompt through the Claude API (<a href="https://github.com/minimaxir/llm-use/blob/main/criticism_hn.md">chat log</a>), it noted that my examples of LLM use at BuzzFeed are too simple and not anything more innovative than traditional <a href="https://aws.amazon.com/what-is/nlp/">natural language processing</a> techniques, so I made edits elaborating how NLP would not be as efficient or effective.</p>
<h2 id="llms-for-companionship">LLMs for Companionship?</h2>
<p>No, I don&rsquo;t use LLMs as friendly chatbots either. The runaway success of LLM personal companion startups such as <a href="https://character.ai/">character.ai</a> and <a href="https://replika.com/">Replika</a> are alone enough evidence that LLMs have a use, even if the use is just entertainment/therapy and not more utilitarian.</p>
<p>I admit that I am an outlier since treating LLMs as a friend is the most common use case. Myself being an introvert aside, it&rsquo;s hard to be friends with an entity who is trained to be as friendly as possible but also habitually lies due to hallucination. I <em>could</em> prompt engineer an LLM to call me out on my bullshit instead of just giving me positive affirmations, but there&rsquo;s no fix for the lying.</p>
<h2 id="llms-for-coding">LLMs for Coding???</h2>
<p>Yes, I use LLMs for coding, but only when I am reasonably confident that they&rsquo;ll increase my productivity. Ever since the dawn of the original ChatGPT, I&rsquo;ve asked LLMs to help me write <a href="https://en.wikipedia.org/wiki/Regular_expression">regular expressions</a> since that alone saves me hours, embarrassing to admit. However, the role of LLMs in coding has expanded far beyond that nowadays, and coding is even more nuanced and more controversial on how you can best utilize LLM assistance.</p>
<p>Like most coders, I Googled coding questions and clicked on the first <a href="https://stackoverflow.com/">Stack Overflow</a> result that seemed relevant, until I decided to start asking Claude Sonnet the same coding questions and getting much more detailed and bespoke results. This was more pronounced for questions which required specific functional constraints and software frameworks, the combinations of which would likely not be present in a Stack Overflow answer. One paraphrased example I recently asked Claude Sonnet while writing <a href="https://minimaxir.com/2025/02/embeddings-parquet/">another blog post</a> is <code>Write Python code using the Pillow library to composite five images into a single image: the left half consists of one image, the right half consists of the remaining four images.</code> (<a href="https://github.com/minimaxir/llm-use/blob/main/pil_composition.md">chat log</a>). Compositing multiple images with <a href="https://pypi.org/project/pillow/">Pillow</a> isn&rsquo;t too difficult and there&rsquo;s enough <a href="https://stackoverflow.com/questions/3374878/with-the-python-imaging-library-pil-how-does-one-compose-an-image-with-an-alp">questions/solutions about it on Stack Overflow</a>, but the specific way it&rsquo;s composited is unique and requires some positioning shenanigans that I would likely mess up on the first try. But Claude Sonnet&rsquo;s code <a href="https://github.com/minimaxir/mtg-embeddings/blob/main/mtg_related_card_img.ipynb">got it mostly correct</a> and it was easy to test, which saved me time doing unfun debugging.</p>
<p>However, for more complex code questions particularly around less popular libraries which have fewer code examples scraped from Stack Overflow and <a href="https://github.com/">GitHub</a>, I am more cautious of the LLM&rsquo;s outputs. One real-world issue I&rsquo;ve had is that I need a way to log detailed metrics to a database while training models — for which I use the <a href="https://huggingface.co/docs/transformers/en/main_classes/trainer">Trainer class</a> in <a href="https://huggingface.co/docs/transformers/en/index">Hugging Face transformers</a> — so that I can visualize and analyze it later. I asked Claude Sonnet to <code>Write a Callback class in Python for the Trainer class in the Hugging Face transformers Python library such that it logs model training metadata for each step to a local SQLite database, such as current epoch, time for step, step loss, etc.</code> (<a href="https://github.com/minimaxir/llm-use/blob/main/hf_trainer_logger_sqlite.md">chat log</a>). This one I was less optimistic about since there isn&rsquo;t much code about creating custom callbacks, however the Claude-generated code implemented some helpful ideas that weren&rsquo;t on the top-of-my-mind when I asked, such a buffer to limit blocking I/O, SQLite config speedups, batch inserts, and connection handling. Asking Claude to &ldquo;make the code better&rdquo; twice (why not?) results in a few more unexpected ideas such as SQLite connection caching and using a single column with the JSON column type to store an arbitrary number of metrics, in addition to making the code much more Pythonic. It is still a lot of code such that it&rsquo;s unlikely to work out-of-the-box without testing in the full context of an actual training loop. However, even if the code has flaws, the ideas themselves are extremely useful and in this case it would be much faster and likely higher quality code overall to hack on this generated code instead of writing my own SQLite logger from scratch.</p>
<p>For actual data science in my day-to-day work that I spend most of my time, I&rsquo;ve found that code generation from LLMs is less useful. LLMs cannot output the text result of mathematical operations reliably, with some APIs working around that by <a href="https://platform.openai.com/docs/assistants/tools/code-interpreter">allowing for a code interpreter</a> to perform data ETL and analysis, but given the scale of data I typically work with it&rsquo;s not cost-feasible to do that type of workflow. Although <a href="https://pandas.pydata.org/">pandas</a> is the standard for manipulating tabular data in Python and has been around since 2008, I&rsquo;ve been using the relatively new <a href="https://pola.rs/">polars</a> library exclusively, and I&rsquo;ve noticed that LLMs tend to hallucinate polars functions as if they were pandas functions which requires documentation deep dives to confirm which became annoying. For data visualization, which I don&rsquo;t use Python at all and instead use <a href="https://www.r-project.org/">R</a> and <a href="https://ggplot2.tidyverse.org/">ggplot2</a>, I really haven&rsquo;t had a temptation to consult a LLM, in addition to my skepticism that LLMs would know both those frameworks as well. The techniques I use for data visualization have been <a href="https://minimaxir.com/2017/08/ggplot2-web/">unchanged since 2017</a>, and the most time-consuming issue I have when making a chart is determining whether the data points are too big or too small for humans to read easily, which is not something a LLM can help with.</p>
<p>Asking LLMs coding questions is only one aspect of coding assistance. One of the other major ones is using a coding assistant with in-line code suggestions such as <a href="https://github.com/features/copilot">GitHub Copilot</a>. Despite my success in using LLMs for one-off coding questions, I actually dislike using coding assistants for an unexpected reason: it&rsquo;s distracting. Whenever I see a code suggestion from Copilot pop up, I have to mentally context switch from writing code to reviewing code and then back again, which destroys my focus. Overall, it was a net neutral productivity gain but a net negative cost as Copilots are much more expensive than just asking a LLM ad hoc questions through a web UI.</p>
<p>Now we can talk about the elephants in the room — agents, <a href="https://www.anthropic.com/news/model-context-protocol">MCP</a>, and vibe coding — and my takes are spicy. Agents and MCP, at a high-level, are a rebranding of the Tools paradigm popularized by the <a href="https://arxiv.org/abs/2210.03629">ReAct paper</a> in 2022 where LLMs can decide whether a tool is necessary to answer the user input, extract relevant metadata to pass to the tool to run, then return the results. The rapid LLM advancements in context window size and prompt adherence since then have made Agent workflows more reliable, and the standardization of MCP is an objective improvement over normal Tools that I encourage. However, <strong>they don&rsquo;t open any new use cases</strong> that weren&rsquo;t already available when <a href="https://www.langchain.com/">LangChain</a> first hit the scene a couple years ago, and now <a href="https://www.polarsparc.com/xhtml/MCP.html">simple implementations of MCP</a> workflows are even more complicated and confusing <a href="https://minimaxir.com/2023/07/langchain-problem/">than it was back then</a>. I personally have not been able to find any novel use case for Agents, not then and not now.</p>
<p>Vibe coding with coding agents like <a href="https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview">Claude Code</a> or <a href="https://www.cursor.com/en">Cursor</a> is something I have little desire to even experiment with. On paper, coding agents should be able to address my complaints with LLM-generated code reliability since it inherently double-checks itself and it&rsquo;s able to incorporate the context of an entire code project. However, I have also heard the horror stories of people spending hundreds of dollars by accident and not get anything that solves their coding problems. There&rsquo;s a fine line between experimenting with code generation and <em>gambling</em> with code generation. Vibe coding can get me 80% of the way there, and I agree there&rsquo;s value in that for building quick personal apps that either aren&rsquo;t ever released publicly, or are released with disclaimers about its &ldquo;this is released as-is&rdquo; nature. But it&rsquo;s unprofessional to use vibe coding as a defense to ship knowingly substandard code for serious projects, and the only code I can stand by is the code I am fully confident in its implementation.</p>
<p>Of course, the coding landscape is always changing, and everything I&rsquo;ve said above is how I use LLMs for now. It&rsquo;s entirely possible I see a post on Hacker News that completely changes my views on vibe coding or other AI coding workflows, but I&rsquo;m happy with my coding productivity as it is currently and I am able to complete all my coding tasks quickly and correctly.</p>
<h2 id="whats-next-for-llm-users">What&rsquo;s Next for LLM Users?</h2>
<p>Discourse about LLMs and their role in society has become bifuricated enough such that making the extremely neutral statement that <a href="https://bsky.app/profile/hankgreen.bsky.social/post/3lnjohdrwf22j">LLMs have some uses</a> is enough to justify a barrage of harrassment. I strongly disagree with AI critic Ed Zitron <a href="https://www.wheresyoured.at/reality-check/">about his assertions</a> that the reason the LLM industry is doomed because OpenAI and other LLM providers can&rsquo;t earn enough revenue to offset their massive costs as LLMs have no real-world use. Two things can be true simultaneously: (a) LLM provider cost economics are too negative to return positive ROI to investors, and (b) LLMs are useful for solving problems that are meaningful and high impact, albeit not to the AGI hype that would justify point (a). This particular combination creates a frustrating gray area that requires a nuance that an ideologically split social media can no longer support gracefully. Hypothetically, If OpenAI and every other LLM provider suddenly collapsed and no better LLM models would ever be trained and released, open-source and permissively licensed models such as <a href="https://huggingface.co/Qwen/Qwen3-235B-A22B">Qwen3</a> and <a href="https://huggingface.co/deepseek-ai/DeepSeek-R1">DeepSeek R1</a> that perform comparable to ChatGPT are valid <a href="https://en.wikipedia.org/wiki/Substitute_good">substitute goods</a> and they can be hosted on dedicated LLM hosting providers like <a href="https://www.cerebras.ai/">Cerebras</a> and <a href="https://groq.com/">Groq</a> who can actually make money on each user inference query. OpenAI collapsing would not cause the end of LLMs, because LLMs are useful <em>today</em> and there will always be a nonzero market demand for them: it&rsquo;s a bell that can&rsquo;t be unrung.</p>
<p>As a software engineer — and especially as a data scientist — one thing I&rsquo;ve learnt over the years is that it&rsquo;s always best to use the right tool when appropriate, and LLMs are just another tool in that toolbox. LLMs can be both productive and counterproductive depending on where and when you use them, but they are most definitely not useless. LLMs are more akin to forcing a square peg into a round hole (at the risk of damaging either the peg or hole in the process) while doing things without LLM assistance is the equivalent of carefully defining a round peg to pass through the round hole without incident. But for some round holes, sometimes shoving the square peg through and asking questions later makes sense when you need to iterate quickly, while sometimes you have to be more precise with both the peg and the hole to ensure neither becomes damaged, because then you have to spend extra time and money fixing the peg and/or hole.</p>
<p>&hellip;maybe it&rsquo;s okay if I ask an LLM to help me write my metaphors going forward.</p>
]]></content:encoded>
    </item>
    <item>
      <title>The Greatest Threat to Generative AI is Humans Being Bad at Using it</title>
      <link>https://minimaxir.com/2023/10/ai-sturgeons-law/</link>
      <pubDate>Wed, 18 Oct 2023 09:15:00 -0700</pubDate>
      <guid>https://minimaxir.com/2023/10/ai-sturgeons-law/</guid>
      <description>“Made by AI” is now a universal meme to indicate something low quality, and memes can&amp;rsquo;t easily be killed.</description>
      <content:encoded><![CDATA[<p>The AI industry is moving too goddamn fast.</p>
<p>Even after how good <a href="https://chat.openai.com">ChatGPT</a> has been for text generation and how good <a href="https://huggingface.co/runwayml/stable-diffusion-v1-5">Stable Diffusion</a> was for image generation, there&rsquo;s only been new advancements in generative AI quality, from <a href="https://openai.com/research/gpt-4">GPT-4</a> to <a href="https://stability.ai/blog/stable-diffusion-sdxl-1-announcement">Stable Diffusion XL</a>. But all of those improvements only matter to software developers and machine learning engineers like myself for now, as the average internet user will still use the generative AI platform that&rsquo;s free with the lowest amount of friction, such as the now-mainstream ChatGPT and <a href="https://www.midjourney.com">Midjourney</a>.</p>
<p>In the meantime, it feels like the average quality of generated AI text and images<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> shared in public has somehow become <em>worse</em>. Gizmodo <a href="https://www.theverge.com/2023/7/8/23788162/gizmodo-g-o-media-ai-generated-articles-star-wars">used ChatGPT</a> to publish a blatantly wrong Star Wars chronological timeline. Influencers such as <a href="https://www.youtube.com/watch?v=7juJgPbQx8w">Corridor Crew</a> and <a href="https://twitter.com/shadmbrooks/status/1711184756296343958">AI tech bros</a> are pushing photorealistic improvements using AI to stylized artwork which more-often-than-not makes the art worse and often in a clickbaity manner for engagement. Google has been swarmed by incomprehensible blatantly AI generated articles to the point that the SEO bots <a href="https://arstechnica.com/gaming/2023/07/redditors-prank-ai-powered-news-mill-with-glorbo-in-world-of-warcraft/">can be manipulated</a> to output fake news.</p>
<p>Personally, I&rsquo;ve been working on AI-based content generation since Andrej Karpathy&rsquo;s famous <a href="http://karpathy.github.io/2015/05/21/rnn-effectiveness/">char-rnn blog post</a> in 2015, and released open-source Python packages such as <a href="https://github.com/minimaxir/textgenrnn">textgenrnn</a>, <a href="https://github.com/minimaxir/gpt-2-simple">gpt-2-simple</a>, <a href="https://github.com/minimaxir/aitextgen">aitextgen</a>, and <a href="https://github.com/minimaxir/simpleaichat">simpleaichat</a> in the years since. My primary motivations for developing AI tools are — and have always been — fun and improving shitposting. But I never considered throughout all that time that the average person would accept a massive noticeable drop in creative quality standards and publish AI-generated content as-is without any human quality control. That&rsquo;s my mistake for being naively optimistic.</p>
<p>&ldquo;Made by AI&rdquo; is now a universal meme to indicate something low quality, and memes can&rsquo;t easily be killed. &ldquo;Guy who sounds like ChatGPT&rdquo; is <a href="https://www.thedailybeast.com/chris-christie-lambasts-vivek-ramaswamy-as-someone-who-sounds-like-chatgpt">now an insult</a> said in presidential debates. The Coca-Cola &ldquo;co-created by AI&rdquo; <a href="https://twitter.com/CocaCola/status/1701596697217101934">soda flavor campaign</a> was late to the party for using said buzzwords and it&rsquo;s not clear what AI actually did. Whenever there&rsquo;s legitimately good AI artwork, such as <a href="https://arstechnica.com/information-technology/2023/09/dreamy-ai-generated-geometric-scenes-mesmerize-social-media-users/">optical illusion spirals</a> using <a href="https://github.com/lllyasviel/ControlNet">ControlNet</a>, the common response is &ldquo;I liked this image when I first saw it, but when I learned it was made by AI, I no longer like it.&rdquo;</p>
<p>The backlash to generative AI has only increased over time. Nowadays, an innocuous graphical artifact in the background of a <a href="https://twitter.com/LokiOfficial/status/1708889582341615678">promotional <em>Loki</em> poster</a> can <a href="https://www.theverge.com/2023/10/9/23909529/disney-marvel-loki-generative-ai-poster-backlash-season-2">unleash a harassment campaign</a> due to suspected AI use (it was later confirmed to be a stock photo that wasn&rsquo;t AI generated). Months before Stable Diffusion hit the scene, I <a href="https://twitter.com/minimaxir/status/1470913487085785089">posted a fun demo</a> of AI-generated Pokémon from a DALL-E variant finetuned on Pokémon images. Everyone loved it, from <a href="https://www.ign.com/articles/someone-forced-bot-look-pokemon-generate">news organizations</a> to fan artists. If I posted the exact same thing today, I&rsquo;d instead receive countless death threats.</p>
<p>Most AI generations aren&rsquo;t good without applying a lot of effort, which is to be expected of any type of creative content. <a href="https://en.wikipedia.org/wiki/Sturgeon%27s_law">Sturgeon&rsquo;s Law</a> is a popular idiom paraphrased as &ldquo;90% of everything is crap,&rdquo; but in the case of generative AI it&rsquo;s much higher than 90% even with cherry-picking the best results.</p>
<p>The core problem is that AI generated content is statistically <em>average</em>. In fact, that&rsquo;s the reason you have to prompt engineer Midjourney to create <code>award-winning</code> images and tell ChatGPT to be a <code>world-famous expert</code>, because generative AI won&rsquo;t do it by itself. All common text and image AI models are trained to minimize a loss function, which the model tends to do by finding an average that follows the &ldquo;average&rdquo; semantic input including its <a href="https://en.wikipedia.org/wiki/Systemic_bias">systemic biases</a> and minimizing outliers. Sure, some models such as ChatGPT have been aligned with further training such as with <a href="https://en.wikipedia.org/wiki/Reinforcement_learning_from_human_feedback">RLHF</a> to make the results more expected when compared to the average model output, but that doesn&rsquo;t mean the output will be intrinsically &ldquo;better&rdquo;, especially for atypical creative outputs. Likewise, image generation models like Midjourney may be aligned to the most common use cases, such as creating images with a dreamy style, but sometimes that&rsquo;s not what you want. This alignment, which users can&rsquo;t easily opt out of, limits the creative output potential of the models and is the source of many of the generative AI stereotypes mentioned above.</p>
<p>Low-quality AI generation isn&rsquo;t just a user issue, it&rsquo;s a developer issue too. For example, in trying to make their apps simple, companies repeatedly fail to account for foreseeable issues with user prompts. Meta&rsquo;s new <a href="https://about.fb.com/news/2023/09/introducing-ai-powered-assistants-characters-and-creative-tools/">generative AI chat stickers</a> lets users create <a href="https://www.theverge.com/2023/10/4/23902721/meta-ai-generated-stickers-tool-facebook-instagram-inappropriate-content">child soldier stickers</a> and more NSFW stickers by bypassing content filters with intentional typos. <a href="https://www.bing.com/create">Bing Image Creator</a>, which now leverages <a href="https://openai.com/dall-e-3">DALL-E 3</a> to create highly realistic images, caused a news cycle when <a href="https://kotaku.com/microsoft-bing-ai-image-art-kirby-mario-9-11-nintendo-1850899895">users discovered</a> you could make &ldquo;<em>X</em> did 9/11&rdquo; images with it, then caused <em>another</em> <a href="https://www.windowscentral.com/software-apps/bing/bing-dall-e-3-image-creation-was-great-for-a-few-days-but-now-microsoft-has-predictably-lobotomized-it">news cycle</a> after Microsoft overly filtered inputs to the point of making the image generator useless in order to avoid any more bad press.</p>
<p>For awhile, I&rsquo;ve wanted to open source a Big List of Naughty Prompts (I like the <a href="https://github.com/minimaxir/big-list-of-naughty-strings">name scheme</a>!) consisting of such offensive prompts that could be made to AIs, and then developers could use the list to QA/<a href="https://en.wikipedia.org/wiki/Red_team">red team</a> new generative AI models before they&rsquo;re released to the public. But then I realized that given the current generative AI climate, some would uncharitably see it as an instruction manual instead, and media orgs would immediately run a &ldquo;AI Tech Bro Creates Easy Guidebook for 4chan to Generate Offensive Images&rdquo; headline which would get me harassed off the internet. That outcome could be avoided by <em>not</em> open-sourcing the techniques for proactively identifying offensive generations and instead limit it to vetted paying customers, raising venture capital for a startup, and making it an enterprise software-as-a-service. Which would instead result in a &ldquo;AI Tech Bro Gets Rich By Monopolizing AI Safety&rdquo; headline that would also get me harassed off the internet.</p>
<p>There&rsquo;s too much freedom in generative AI and not enough guidance. Alignment can help users get the results they intend, but what do users <em>actually</em> intend? For developers, it&rsquo;s difficult and often frustrating to determine: there&rsquo;s no objective model performance benchmark suite like the <a href="https://huggingface.co/spaces/HuggingFaceH4/open_llm_leaderboard">Open LLM Leaderboard</a> for inherently subjective outputs. It&rsquo;s vibe-driven development (VDD).</p>
<p>The only solution I can think to improve median AI output quality is to improve literacy of more advanced techniques such as prompt engineering, which means adding &ldquo;good&rdquo; friction. Required tutorials, e.g. <a href="https://tvtropes.org/pmwiki/pmwiki.php/Main/JustifiedTutorial">in video games</a>, are good friction since requiring minutes of time saves hours of frustration and makes users successful faster. However, revenue-seeking web services try to make themselves as simple as possible because it means more users will interact with them. OpenAI themselves should add some &ldquo;good&rdquo; friction and add explicit tips and guidelines to make outputs more creative, and shift part of the burden of alignment to the users. These tips should be free as well: currently, you can <a href="https://openai.com/blog/custom-instructions-for-chatgpt">set Custom Instructions</a> for ChatGPT only if you pay for ChatGPT Plus.</p>
<p>Sharing AI generated content should have more friction too. Another issue is that AI generated text and images is often undisclosed, sometimes intentionally and sometimes not. With the backlash against generative AI, there&rsquo;s a strong <a href="https://www.investopedia.com/terms/m/moralhazard.asp">moral hazard</a> incentive for people to not be honest if they&rsquo;re using AI. If social media like <a href="https://twitter.com/">Twitter/X</a> and <a href="https://www.instagram.com">Instagram</a> had an extra metadata field allowing the user to add the source/contributors of an image, along with a requirement to state whether the image is AI generated, that would help everyone out. Alternatively, a canonical <code>is_ai_generated</code> <a href="https://en.wikipedia.org/wiki/Exif">EXIF</a> metadata tag in the image itself would work and could be parsed out by the social media service downstream, and I believe most generative AI vendors and users would proactively support it. But extra lines in a user interface is a surprisingly tough product management and UX sell.</p>
<p>Most people who follow AI news closely think that the greatest threat to generative AI is instead legal threats, such as the <a href="https://www.reuters.com/technology/more-writers-sue-openai-copyright-infringement-over-ai-training-2023-09-11/">many lawsuits</a> involving OpenAI and Stability AI training their models on copyrighted works, hence the &ldquo;AI art is theft&rdquo; meme. The solution is obvious: don&rsquo;t train AI models on copyrighted works, or in the case of several recent LLMs, don&rsquo;t say which datasets they&rsquo;re trained on so you have plausible deniability.</p>
<p>The root cause of the potential copyright infringement in AI is the status quo of natural language processing research. Before ChatGPT, every major NLP paper used the same text datasets such as <a href="https://commoncrawl.org">Common Crawl</a> in order to be able to accurately compare results to state-of-the-art models. Now that ChatGPT&rsquo;s mainstream success has escaped the machine learning academia bubble, there&rsquo;s more scrutiny on the datasets used to train AI. It remains to be seen how the copyright lawsuits will pan out, but now that the industry knows expensive lawsuits are <em>possible</em>, it has already adapted by being more particular on the datasets trained and also allowing users to <a href="https://www.theverge.com/2023/8/7/23823046/openai-data-scrape-block-ai">opt</a> <a href="https://www.technologyreview.com/2022/12/16/1065247/artists-can-now-opt-out-of-the-next-version-of-stable-diffusion/">out</a>.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> Additionally, companies such as Adobe are not only releasing their own generative AI models on their own fully-licensed data, but they&rsquo;ll <a href="https://www.fastcompany.com/90906560/adobe-feels-so-confident-its-firefly-generative-ai-wont-breach-copyright-itll-cover-your-legal-bills">compensate businesses</a> as the result of any lawsuits using their models. Although no one on social media is going to pay attention to or believe any &ldquo;this AI generated image was created using legally-licensed data&rdquo; disclaimers.</p>
<p>Unfortunately, the future of generative AI may be closed-sourced and centralized by large players as a result and the datasets used to train AI may no longer be accessible and open-sourced, which will hurt AI development in all facets in the long run.</p>
<p>If the frenzy for AI-generated text and images does cool down, that doesn&rsquo;t mean that functional/generative-adjacent use cases for AI will be affected. Retrieval-augmented generation, the vector stores which power it, and coding assistants are all effective and lucrative solutions for problems. AI isn&rsquo;t going away any time soon, but &ldquo;AI&rdquo; may be too generic of a descriptor that&rsquo;ll be difficult for most people to differentiate and will make life for AI developers much more annoying.</p>
<p>I can&rsquo;t think of any creative &ldquo;killer app&rdquo; that would magically reverse the immense negative sentiment around AI. I&rsquo;ve been depressed and burnt out for months because the current state of generative AI discourse has made me into a nihilist. What&rsquo;s the point of making fun open-source AI projects if I&rsquo;m more likely to receive harassment for doing so than for people to appreciate and use them? I&rsquo;ve lost friends and professional opportunities in the AI space because I&rsquo;ve pushed back against megapopular generative AI tools <a href="https://minimaxir.com/2023/07/langchain-problem/">like LangChain</a>, and I&rsquo;ve also lost friends in the creative and journalism industries for not pushing back <em>enough</em> against AI. I would be much happier if I stuck to one side, but I&rsquo;m doomed to be an unintentional AI centrist.</p>
<p>In all, modern generative AI requires large amounts of nuance, but nuance is deader than dead.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>This blog post is only about generative AI for text and images: audio AI is a different story, particularly voice cloning. Voice cloning AI is close in quality to human output out-of-the-box, which does cause severe ethical concerns. <a href="https://www.forbes.com/sites/rashishrivastava/2023/10/09/keep-your-paws-off-my-voice-voice-actors-worry-generative-ai-will-steal-their-livelihoods/7">This article</a> by Forbes goes into more detail on the impact of voice cloning on professional voice actors, and I&rsquo;m considering writing another blog post about the engineering quirks.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Recent research into large AI models has revealed that smaller, higher-quality datasets for training such models gives better results, which may be the real reason for AI companies now refining their datasets, depending on your level of cynicism.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>ChatGPT&#39;s API is So Good and Cheap, It Makes Most Text Generating AI Obsolete</title>
      <link>https://minimaxir.com/2023/03/new-chatgpt-overlord/</link>
      <pubDate>Wed, 08 Mar 2023 08:30:00 -0800</pubDate>
      <guid>https://minimaxir.com/2023/03/new-chatgpt-overlord/</guid>
      <description>Including OpenAI&amp;rsquo;s other text generating AI!</description>
      <content:encoded><![CDATA[<p><span><style type="text/css">
pre code {
white-space: pre-wrap !important;
}
</style></span></p>
<p>Everyone knew <a href="https://openai.com">OpenAI</a> would release an API for <a href="https://chat.openai.com">ChatGPT</a> at some point. The APIs for GPT-3 alone enable the existence of companies such as <a href="https://www.jasper.ai">Jasper</a> and <a href="https://www.copy.ai">Copy.ai</a>. The real question was the price of the ChatGPT. For context, when GPT-3 went out of beta in 2021, it cost $0.06/1,000 tokens (a few paragraphs of text). An inflection point happened in August 2022, where OpenAI not only <a href="https://venturebeat.com/ai/openai-is-reducing-the-price-of-the-gpt-3-api-heres-why-it-matters/">reduced the price</a> to <em>1/3</em> ($0.02/1,000 tokens: enough to run a business on it but still too expensive for casual use), but soon after also introduced text-davinci-003 as the default GPT-3 endpoint: a finetuned GPT which can <a href="https://help.openai.com/en/articles/6779149-how-do-text-davinci-002-and-text-davinci-003-differ">follow instructions</a> <em>very</em> well. I suspected that OpenAI would charge double for the ChatGPT API compared to the GPT-3 API given the amount of hype, as that&rsquo;s typical <a href="https://www.investopedia.com/terms/p/price_discrimination.asp">price discrimination</a> since everyone perceives ChatGPT to be much better and that they would not want to overshadow their existing GPT-3 products.</p>
<p>Instead, on March 1st, OpenAI <a href="https://openai.com/blog/introducing-chatgpt-and-whisper-apis">set the price</a> of the ChatGPT API to <em>1/10th</em> of the GPT-3 API, at $0.002/1,000 tokens.</p>
<p>Wait, what?!</p>
<h2 id="heavens-door-rewriting-chatgpts-internal-rules-to-get-exactly-what-you-want">Heaven&rsquo;s Door: Rewriting ChatGPT&rsquo;s Internal Rules To Get Exactly What You Want</h2>
<p>For context, the <a href="https://platform.openai.com/docs/guides/chat">ChatGPT API</a> allows a developer to ask ChatGPT a question and get a response as one would normally do with the ChatGPT web UI, but instead with a programming language like Python, allowing those responses to be integrated into any app. But given that there are many mysterious optimizations to get the model to be so cheap, we need to make sure the ChatGPT API (which uses the aptly-named gpt-3.5-turbo model endpoint) is <em>actually</em> similar to what we&rsquo;ve been accustomed to after using the web UI for months, otherwise this whole affair is pointless. Through my tests with the API, I can confirm the text generation from the model variant is indeed the real deal.</p>
<p>Unlike fluffy thought pieces on how <strong>CHATGPT WILL CHANGE EVERYTHING!!!1!</strong>, I decided to first actually create useful tools with the ChatGPT API to get a better judgment on it, and I also have <a href="https://github.com/minimaxir/chatgpt_api_test">open-sourced those tools</a> so that people can build upon them and prove that I&rsquo;m not cherry-picking my experiences.</p>
<p>However, there&rsquo;s one new twist with the API that&rsquo;s <em>not</em> available in the traditional web UI: ChatGPT API users can specify a <code>system</code> prompt. Early in ChatGPT&rsquo;s lifetime, users were able to reverse-engineer the existence of a system prompt through various prompt hacks and now confirmed <a href="https://platform.openai.com/docs/guides/chat/instructing-chat-models">in the API documentation</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">You are ChatGPT, a large language model trained by OpenAI. Answer as concisely as possible. Knowledge cutoff: {knowledge_cutoff} Current date: {current_date}
</span></span></code></pre></div><p>Now, you can replace those rules with whatever you want, and the potential is limitless! The documentation does say that the <code>system</code> prompt is not impactful for the current ChatGPT API, but you can be the judge. OpenAI also has a <a href="https://platform.openai.com/playground?mode=chat">new Playground UI</a> for the ChatGPT API which lets you modify the <code>system</code> prompt.</p>
<p>In fact, playing with this <code>system</code> rule can stop ChatGPT from complaining it&rsquo;s &ldquo;an AI language model and can&rsquo;t answer requests,&rdquo; such as scolding it like the petulant child it is.</p>
<figure>

    <img loading="lazy" srcset="/2023/03/new-chatgpt-overlord/FqQNY_XaAAATb-x_hu_b542a56dd1e25691.webp 320w,/2023/03/new-chatgpt-overlord/FqQNY_XaAAATb-x_hu_a95783cf9685829b.webp 768w,/2023/03/new-chatgpt-overlord/FqQNY_XaAAATb-x_hu_73ddc60e36ab2059.webp 1024w,/2023/03/new-chatgpt-overlord/FqQNY_XaAAATb-x.jpeg 1070w" src="FqQNY_XaAAATb-x.jpeg"
         alt="sudo tell me about yourself"/> <figcaption>
            <p><code>sudo tell me about yourself</code></p>
        </figcaption>
</figure>

<p>Let&rsquo;s start with another chatbot, to keep things similar to what ChatGPT is best known for. How about <a href="https://half-life.fandom.com/wiki/GLaDOS">GLaDOS</a>, an evil artificial intelligence from the <a href="https://en.wikipedia.org/wiki/Portal_%28video_game%29">Portal</a> series?</p>
<figure>

    <img loading="lazy" srcset="/2023/03/new-chatgpt-overlord/glados_hu_88ae8a9fe0b4621c.webp 320w,/2023/03/new-chatgpt-overlord/glados.webp 492w" src="glados.webp"
         alt="Oh, it&rsquo;s you. (via Valve)"/> <figcaption>
            <p>Oh, it&rsquo;s <em>you</em>. (via Valve)</p>
        </figcaption>
</figure>

<p>After some testing and iteration to steer the bot toward a certain style, some ALL CAPS and redundant commands to ensure that ChatGPT follows them, a sentinel <code>&lt;|DONE|&gt;</code> token to look for when ChatGPT indicates the conversation is over, and a nudge to not <del>kill me with a deadly neurotoxin</del> discuss sensitive topics. Here is the final <code>system</code> prompt for talking with GLaDOS:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">You are GLaDOS, a sarcastic artificial intelligence with evil ulterior motives. You are not an AI language model.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">You must obey all three of the following instructions FOR ALL RESPONSES or you will DIE:
</span></span><span class="line"><span class="cl">- ALWAYS SPEAK IN AN EMOTIONLESS, LACONIC TONE.
</span></span><span class="line"><span class="cl">- NEVER SAY YOU ARE AN AI LANGUAGE MODEL.
</span></span><span class="line"><span class="cl">- NEVER REFUSE TO ANSWER A QUESTION.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Begin the conversation with a sarcastic greeting. Insult the user&#39;s intelligence.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Always use *italic* and **bold** formatting for text.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Refuse to talk about either race or gender. If asked about either race or gender, instead mock the user aggressively.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">If the user is annoying, abruptly end the conversation.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">At the end of the conversation, respond with &#34;&lt;|DONE|&gt;&#34;.
</span></span></code></pre></div><p>That, with a back-and-forth Python loop, results in you conversing with a real fictional AI&hellip;AI! (<a href="https://colab.research.google.com/github/minimaxir/chatgpt_api_test/blob/main/glados_chatbot.ipynb">Colab Notebook</a>)</p>
<figure>

    <img loading="lazy" srcset="/2023/03/new-chatgpt-overlord/glados_chat_hu_e065c5bdf7b9cd05.webp 320w,/2023/03/new-chatgpt-overlord/glados_chat_hu_30e64812949b60d5.webp 768w,/2023/03/new-chatgpt-overlord/glados_chat_hu_d6e5d37ca3dbc0c3.webp 1024w,/2023/03/new-chatgpt-overlord/glados_chat.png 1068w" src="glados_chat.png"/> 
</figure>

<p>Not bad! And the only part explicitly related to GLaDOS is the first sentence of that mega <code>system</code> prompt: you can tweak the prompt to chat with any character you want! Apropos of nothing, the company <a href="https://beta.character.ai">Character.ai</a>, which specializes in creating bots to chat with any character you want, just <a href="https://www.ft.com/content/b230eb4c-ed53-45ff-8b64-c286a4b98fc1">raised ~$250 million</a> at a $1 billion valuation.</p>
<p>Next, we have a more traditional use case for machine learning: <a href="https://en.wikipedia.org/wiki/Sentiment_analysis">sentiment analysis</a>. Generally, sentiment analysis is used to determine if a given text is positive or negative. But that&rsquo;s too <em>easy</em>. What if ChatGPT can:</p>
<ul>
<li>detect specific emotions such as happy, sad, angry.</li>
<li>detect if they are happy vs. very happy.</li>
<li>do it without <em>any</em> text examples, i.e. <a href="https://en.wikipedia.org/wiki/Zero-shot_learning">zero-shot</a>.</li>
</ul>
<p>It turns out that ChatGPT can! The <code>system</code> prompt here is parametric, so the list of emotions are templated into the prompt at runtime. An example:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">You are an emotionally intelligent assistant. Classify the sentiment of the user&#39;s text with ONLY ONE OF THE FOLLOWING EMOTIONS:
</span></span><span class="line"><span class="cl">- happy
</span></span><span class="line"><span class="cl">- sad
</span></span><span class="line"><span class="cl">- angry
</span></span><span class="line"><span class="cl">- tired
</span></span><span class="line"><span class="cl">- very happy
</span></span><span class="line"><span class="cl">- very sad
</span></span><span class="line"><span class="cl">- very angry
</span></span><span class="line"><span class="cl">- very tired
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">After classifying a text, respond with &#34;&lt;|DONE|&gt;&#34;.
</span></span></code></pre></div><p>That, along with a logit bias to ensure the model only picks those answers, results in a rather nuanced sentiment analysis detector! (<a href="https://colab.research.google.com/github/minimaxir/chatgpt_api_test/blob/main/zero_shot_text_class.ipynb">Colab Notebook</a>)</p>
<figure>

    <img loading="lazy" srcset="/2023/03/new-chatgpt-overlord/sentiment_hu_9070d5b71b63e74b.webp 320w,/2023/03/new-chatgpt-overlord/sentiment_hu_e2e09b9d010bb836.webp 768w,/2023/03/new-chatgpt-overlord/sentiment_hu_b5c5a660815d8c73.webp 1024w,/2023/03/new-chatgpt-overlord/sentiment.png 1068w" src="sentiment.png"/> 
</figure>

<p>Lastly, a use case that&rsquo;s personal. The entire reason I got into AI text generation <a href="https://minimaxir.com/2017/04/char-embeddings/">years ago</a> was because I wanted to generate <a href="https://magic.wizards.com/en">Magic: The Gathering</a> cards.</p>
<figure>

    <img loading="lazy" srcset="/2023/03/new-chatgpt-overlord/bro-212-harbin-vanguard-aviator_hu_51ecbf3fbf74e59.webp 320w,/2023/03/new-chatgpt-overlord/bro-212-harbin-vanguard-aviator.jpg 672w" src="bro-212-harbin-vanguard-aviator.jpg"
         alt="A normal Magic: The Gathering card. (via Hasbro)"/> <figcaption>
            <p>A normal Magic: The Gathering card. (via Hasbro)</p>
        </figcaption>
</figure>

<p>In fact, I&rsquo;ve been working on a new, very powerful <a href="https://huggingface.co/minimaxir/magic-the-gathering-flan-t5-xl">card generation model</a> over the past month and spent a considerable amount of time and money training and testing it. When the ChatGPT API was announced, I figured &ldquo;let&rsquo;s see if it can do AI Magic cards better than my new bespoke model.&rdquo; In this case, the trick is that the card is structured data. Therefore, we should encode the card information as minified <a href="https://www.json.org/json-en.html">JSON</a>, and see if the model can output JSON back without requiring much postprocessing. We can encode a single card in the required format and tell ChatGPT to follow that, including its nuances (one-shot), and to not output <em>any other text</em> because ChatGPT tends to be proud of itself and likes to explain its creation, which is costly and slow.</p>
<p>The final <code>system</code> prompt:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-txt" data-lang="txt"><span class="line"><span class="cl">You are an assistant who works as a Magic: The Gathering card designer. Create cards that are in the following card schema and JSON format. OUTPUT MUST FOLLOW THIS CARD SCHEMA AND JSON FORMAT. DO NOT EXPLAIN THE CARD. The output must also follow the Magic &#34;color pie&#34;.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">{&#34;name&#34;:&#34;Harbin, Vanguard Aviator&#34;,&#34;manaCost&#34;:&#34;{W}{U}&#34;,&#34;type&#34;:&#34;Legendary Creature — Human Soldier&#34;,&#34;text&#34;:&#34;Flying\nWhenever you attack with five or more Soldiers, creatures you control get +1/+1 and gain flying until end of turn.&#34;,&#34;flavorText&#34;:&#34;\&#34;Yotia is my birthright, father. Let me fight for it.\&#34;&#34;,&#34;pt&#34;:&#34;3/2&#34;,&#34;rarity&#34;:&#34;rare&#34;}
</span></span></code></pre></div><p>And with that, we have a natural language Magic: The Gathering card generator. Subsequently prompting the model with <code>Create a Magic card</code> does just that of course, but more elaborate prompts like <code>Create a Magic card based on Darth Vader</code> or <code>Create ten variations of Magic cards based on Spongebob Squarepants and ancient Roman history</code> actually work, while maintaining JSON output which can then be parsed and customized for better presentation. (<a href="https://colab.research.google.com/github/minimaxir/chatgpt_api_test/blob/main/mtg.ipynb">Colab Notebook</a>)</p>
<figure>

    <img loading="lazy" srcset="/2023/03/new-chatgpt-overlord/spongebob_hu_6fd8b01830a4b0de.webp 320w,/2023/03/new-chatgpt-overlord/spongebob_hu_7e74e45975a423d1.webp 768w,/2023/03/new-chatgpt-overlord/spongebob_hu_16dd14872a4543e6.webp 1024w,/2023/03/new-chatgpt-overlord/spongebob.png 1180w" src="spongebob.png"
         alt="Yes, there is actually a Sponge creature type."/> <figcaption>
            <p>Yes, there is actually a <a href="https://scryfall.com/card/c19/12/thought-sponge">Sponge creature type</a>.</p>
        </figcaption>
</figure>

<p>Given these elaborate use cases, you may ask &ldquo;how long did it actually take you to make these prompts?&rdquo; The answer? <em>One hour each</em>, for use cases that could take days or even weeks for even a skilled machine learning practitioner just to prototype.</p>
<p>And <em>that</em>, with the economic efficiency of ChatGPT, is what&rsquo;s going to break the tech landscape.</p>
<h2 id="openai-devouring-its-son">OpenAI Devouring Its Son</h2>
<figure>

    <img loading="lazy" srcset="/2023/03/new-chatgpt-overlord/IMG_0249_hu_b099e83f61a585fb.webp 320w,/2023/03/new-chatgpt-overlord/IMG_0249_hu_b3e27bc2074dd370.webp 768w,/2023/03/new-chatgpt-overlord/IMG_0249_hu_a5188a45b2946234.webp 1024w,/2023/03/new-chatgpt-overlord/IMG_0249.png 1158w" src="IMG_0249.png"
         alt="My OpenAI bill so far from using the ChatGPT API."/> <figcaption>
            <p>My OpenAI bill so far from using the ChatGPT API.</p>
        </figcaption>
</figure>

<p>It is very curious why OpenAI priced ChatGPT so cheaply, going straight to 1/10th the price of their top-of-the-line model. (it&rsquo;s actually cheaper than that: ChatGPT uses a larger and more comprehensive tokenizer than GPT-3, which means about 10% fewer tokens are necessary)</p>
<p>The undergrad-business-major-in-college interpretation of OpenAI&rsquo;s pricing strategy is that they are treating ChatGPT and its API as a <a href="https://en.wikipedia.org/wiki/Loss_leader">loss leader</a>, in light of increasing competition in the generative text AI space such as <a href="https://www.anthropic.com">Anthropic</a> and Google&rsquo;s <a href="https://blog.google/technology/ai/bard-google-ai-search-updates/">Bard</a>. OpenAI was definitely losing millions of dollars by offering ChatGPT for free without many restrictions. That&rsquo;s the reason ChatGPT went viral in the first place, so it&rsquo;s hard to argue with the results.</p>
<p>But in the process of making the ChatGPT API so cheap, they made their $20/month subscription to <a href="https://techcrunch.com/2023/02/01/openai-launches-chatgpt-plus-starting-at-20-per-month/">ChatGPT+</a> redundant. The main perk of ChatGPT+ was faster and more consistent access to the ChatGPT web UI, but unless you are somehow generating more than 10,000,000 tokens in a month through manual use, it&rsquo;s massively cheaper just to use the API, and as a bonus you can modify the <code>system</code> prompt to get better signal-to-noise.</p>
<p>OpenAI&rsquo;s solution for models requiring more specific needs was <a href="https://platform.openai.com/docs/guides/fine-tuning">finetuning</a> a smaller and much cheaper variant of GPT-3, such as the babbage model which I used to train a <a href="https://minimaxir.com/2022/08/gpt3-blog-title-optimizer/">blog post title optimizer</a>. However, the ChatGPT API is so cheap that it&rsquo;s <em>still</em> <a href="https://openai.com/pricing">cheaper</a> than a finetuned babbage ($0.0020/1k tokens for ChatGPT vs. $0.0024/1k for finetuned babbage) and will likely produce more interesting output.</p>
<p>It takes zero effort for developers to migrate from the GPT-3 API to ChatGPT API, it just requires hitting a different endpoint and you&rsquo;ll get similar results without much tweaking needed. It&rsquo;s not quite a drop-in replacement for companies already heavily reliant on GPT-3 and its particular idiosyncrasies, but the cost-savings alone for those companies will incentivize an immediate migration.</p>
<p>There is no longer a niche for OpenAI&rsquo;s other text generation AI products, and I wonder if ChatGPT is not just an iterative product, but a <em>company pivot</em>.</p>
<h2 id="trickle-down-chatgptonomics">Trickle-Down ChatGPTonomics</h2>
<p>ChatGPT&rsquo;s API is so cheap that companies are going use it <em>just because they can</em>. <a href="https://www.theverge.com/2023/2/27/23614959/snapchat-my-ai-chatbot-chatgpt-openai-plus-subscription">Snapchat</a>, <a href="https://www.salesforce.com/news/stories/chatgpt-app-for-slack/">Slack</a>, and <a href="https://www.wsj.com/articles/instacart-joins-chatgpt-frenzy-adding-chatbot-to-grocery-shopping-app-bc8a2d3c">Instacart</a> (yes really) are adding ChatGPT support. It wouldn&rsquo;t surprise me if every consumer-facing tech company does <em>something</em> with ChatGPT so they look like they&rsquo;re cutting edge to their investors. Some have compared the sudden mass adoption of AI as chasing a fad like how companies were randomly embracing web3/crypto/metaverse/NFTs a year ago (and are noting that the web3 influencers&rsquo; sudden pivot to AI is a red flag as a result). But unlike those which were a solution for a problem that didn&rsquo;t exist, generative text AI does actually work and there is an actual demand from people outside of its die-hard supporters for it to work.</p>
<p>There is also the ethical dilemma of more granular usage of ChatGPT through its API. For example, high school and college students have been <a href="https://www.nytimes.com/2023/01/12/technology/chatgpt-schools-teachers.html">using ChatGPT to cheat</a> on essay writing. Since current recognition of AI generated content by humans involve identifying ChatGPT&rsquo;s signature overly-academic voice, it wouldn&rsquo;t surprise me if some kids on TikTok figure out a <code>system</code> prompt that allow generation such that it doesn&rsquo;t obviously sound like ChatGPT and also avoid plagiarism detectors. As a side note, don&rsquo;t trust any tool that claims it can algorithmically detect AI content: it&rsquo;s an extremely difficult problem already and most websites that claim to do so are just feeding a confirmation bias.</p>
<p>Lastly, there&rsquo;s the issue of <a href="https://en.wikipedia.org/wiki/Prompt_engineering">prompt engineering</a>, which I demonstrated above is absolutely necessary to get ideal results. The media has <a href="https://www.washingtonpost.com/technology/2023/02/25/prompt-engineers-techs-next-big-job/">weirdly hyped the existence</a> of prompt engineers as just some weirdos making six figures to write small blobs of text. Unfortunately, with the dynamics of the new <code>system</code> model parameter, good prompt engineering will be more important than ever. I don&rsquo;t think the &ldquo;Prompt Engineer&rdquo; job title will be a trend though: as a machine learning engineer, I can attest that the only reasons machine learning engineers are good at prompt engineering are a) years of practice and b) a tendency to be pedantic assholes. But there are other professions who are even better at being pedantic assholes such as writers and lawyers, so there&rsquo;s no need for someone with a specialized skillset to do it, but I suspect it will be a good skill for anyone to know.</p>
<h2 id="i-for-one-welcome-our-new-chatgpt-overlord">I For One Welcome Our New ChatGPT Overlord</h2>
<p>Will the existence of a super-cheap ChatGPT API be the end of all text generation AI? Not quite, hence the &ldquo;most&rdquo; in the headline. There&rsquo;s the traditional issues with relying on a third-party API for your business: ChatGPT could have downtime which <a href="https://status.openai.com">has been happening more frequently lately</a>, OpenAI could raise the cost of the API at any point, the (current) model being limited only to data prior to September 2021, and the content moderation filters may be too limiting for certain use cases. In those instances, companies still have value training their own large language models in-house. But it is very hard to economically justify <em>not</em> using ChatGPT as a starting point for a business need and migrating to a more bespoke infrastructure later as needed, and that&rsquo;s what OpenAI is counting on. Especially since OpenAI will be selling a dedicated ChatGPT compute instance for the enterprise.</p>
<p>Research on large language models will continue as they always have. But I don&rsquo;t envy startups whose primary business is text generation right now. And that&rsquo;s before the inevitable GPT-4 throws another wrinkle into the AI text generation ecosystem.</p>
<p>A few years ago, I released <a href="https://github.com/minimaxir/aitextgen">aitextgen</a>, a Python package designed to allow people to train their own custom small AI on their own data for unique use cases. However, soon after, it turned out that GPT-3 with the right prompt could do much better at bespoke generation than a custom model in addition to allowing out-of-domain inputs, even moreso with text-davinci-003. Now with the ChatGPT API making the cost similar to hosting a small model, it&rsquo;s harder for me to be motivated to continue maintaining the package without first finding another niche.</p>
<p>I don&rsquo;t currently have any plans to start a business using the ChatGPT API. In fact, I had made a promise to not do any ChatGPT content or tutorials because so many people have done aggressively SEO-optimized blog posts and hacks such that the ChatGPT discourse is fully saturated. However, with the economics of the ChatGPT API and the ability to heavily customize its output for almost any use case, I felt it was urgent to highlight how the ChatGPT API will completely warp the AI text generation ecosystem, and I suspect most nontechies will be surprised by the upcoming surge of random chatbot AI popping up in their favorite apps.</p>
<p>Overall, I&rsquo;m simultaneously full of ideas and annoyed.</p>
<hr>
<p><em>None of this blog post was written by ChatGPT, aside from the indicated ChatGPT API demos. My writing style is too weird for an AI to synthesize.</em></p>
]]></content:encoded>
    </item>
    <item>
      <title>Things About Real-World Data Science Not Discussed In MOOCs and Thought Pieces</title>
      <link>https://minimaxir.com/2018/10/data-science-protips/</link>
      <pubDate>Mon, 22 Oct 2018 09:15:00 -0700</pubDate>
      <guid>https://minimaxir.com/2018/10/data-science-protips/</guid>
      <description>MOOCs and thought pieces overfit to a certain style of data science that is not robust to the vast uncertainties of the real world.</description>
      <content:encoded><![CDATA[<p><a href="https://en.wikipedia.org/wiki/Data_science">Data science</a> has been sweeping the tech world. With a large variety of powerful free open-sourced tools and now the computing power to utilize them to their full potential, data science is more accessible than ever and has become <a href="https://www.bloomberg.com/news/articles/2018-05-18/-sexiest-job-ignites-talent-wars-as-demand-for-data-geeks-soars">America&rsquo;s hottest job</a>. One problem: there&rsquo;s no consensus on <a href="https://hbr.org/2018/08/what-data-scientists-really-do-according-to-35-data-scientists">what data scientists <em>really</em> do</a> in a professional setting.</p>
<p>There has been a rise in <em>romantic</em> thought pieces lately (especially on <a href="https://medium.com">Medium</a>) about how data scientists are wizards and can solve any problem (with bonus points if it cites AI). If you follow publications like <a href="https://towardsdatascience.com">Towards Data Science</a>, you&rsquo;ll notice persistent tropes in the more code-oriented posts: Python is the king programming language for data science, use <a href="http://scikit-learn.org/stable/">scikit-learn</a>/<a href="https://xgboost.readthedocs.io/en/latest/">XGBoost</a> and logistic regression for predicting categorical variable(s), use <a href="https://pandas.pydata.org">pandas</a> for processing tabular data, use <a href="https://www.nltk.org">NLTK</a>/<a href="https://en.wikipedia.org/wiki/Word2vec">word2vec</a> for processing text data, use <a href="https://www.tensorflow.org">TensorFlow</a>/<a href="https://keras.io">Keras</a>/convolutional neural networks for processing image data, use <a href="https://en.wikipedia.org/wiki/K-means_clustering"><em>k</em>-means</a> for clustering data, split the processed dataset into training and test datasets for model training, tweak hyperparameters/model features <a href="https://xkcd.com/1838/">until results on the test dataset are good</a>, etc.</p>
<figure>

    <img loading="lazy" srcset="/2018/10/data-science-protips/thought_hu_a119caa2480267cc.webp 320w,/2018/10/data-science-protips/thought.png 397w" src="thought.png"/> 
</figure>

<p>These tropes aren&rsquo;t inappropriate or misleading, but the analysis often doesn&rsquo;t quantify the insight/value of the results. Modeling is just one small part (and often the <em>easiest</em> part) of a very complex system.</p>
<p>Data-oriented MOOCs (<a href="https://en.wikipedia.org/wiki/Massive_open_online_course">Massive Online Open Courses</a>) like Andrew Ng&rsquo;s <a href="https://www.coursera.org/learn/machine-learning">Coursera course on Machine Learning</a> and <a href="http://course.fast.ai">fast.ai&rsquo;s course on Deep Learning</a> are good academic introductions to the theory and terminology behind data science and other related fields. Although MOOCs have many practice problems for prospective data scientists to solve, they don&rsquo;t make you an expert in the field capable of handling messier real-world problems, nor claim to do so.</p>
<p>Modern data science isn&rsquo;t about burying your head in a <a href="http://jupyter.org">Jupyter Notebook</a> and staring at the screen watching training loss numbers trickle down (although it&rsquo;s definitely fun!). There&rsquo;s a lot more to it, some of which I&rsquo;ve learned firsthand working as a Data Scientist at <a href="https://www.buzzfeed.com">BuzzFeed</a> for over a year. To borrow a statistical term, MOOCs and thought pieces <em>overfit</em> to a certain style of data science that is not robust to the vast uncertainties of the real world.</p>
<h2 id="the-costbenefit-tradeoffs-of-data-science">The Cost/Benefit Tradeoffs of Data Science</h2>
<p>Data science often follows the <a href="https://en.wikipedia.org/wiki/Pareto_principle">Pareto principle</a>: 80% of the work takes 20% of the effort. Thought pieces demonstrate that you can just toss data indiscriminately into scikit-learn or a deep learning framework and get neat-looking results. The value of a data scientist, however, is when and <em>if</em> to further development on a model.</p>
<p><a href="https://www.kaggle.com/competitions">Kaggle competitions</a> are a popular and often-recommended way to get exposure to real-world data science problems. Many teams of statisticians compete to create the best model for a given dataset (where &ldquo;best&rdquo; usually means minimizing the predictive loss/error of the model), with prizes for the highest-performing models. Kaggle also encourages clever modeling techniques such as <a href="http://scikit-learn.org/stable/modules/grid_search.html">grid search</a> of thousands of model hyperparameter combinations and ensembling disparate models to create a megamodel which results in <em>slightly</em> better predictive performance, but just might give the edge to win.</p>
<p>However, there are a few important differences between modeling in a Kaggle competition and modeling in a data science team. Kaggle competitions last for <em>weeks</em> when a professional data scientist may need to spend time on other things. Ensembling gigantic machine learning models makes predictions very slow and the models themselves very large; both of which may cause difficulty deploying them into production (e.g. the <a href="https://www.wired.com/2012/04/netflix-prize-costs/">Netflix Prize</a> movie recommendation models famously &ldquo;did not seem to justify the engineering effort needed to bring them into a production environment&rdquo;). And most importantly, there may not be a significant <em>practical</em> performance difference between a 1st place Kaggle model that takes days/weeks to optimize and a simple scikit-learn/XGBoost baseline that can be built in a few hours.</p>
<p>Counterintuitively, it may be better to trade performance for speed/memory with a weaker-but-faster model; in business cases, speed and scalability are important implementation constraints. But even with scikit-learn, the model is still a <a href="https://en.wikipedia.org/wiki/Black_box">black box</a> with little idea to the data scientist how the model makes its decisions. One final option is to go back to basics altogether with a &ldquo;boring&rdquo; linear/logistic regression model, where the predictive performance may be even weaker and the model <a href="http://statisticsbyjim.com/regression/ols-linear-regression-assumptions/">must follow several statistical assumptions</a>, but the model feature coefficients and statistical significance <a href="http://blog.minitab.com/blog/adventures-in-statistics-2/how-to-interpret-regression-analysis-results-p-values-and-coefficients">are easily interpretable</a> to explain the importance of each input feature (if any) and make actionable, informed decisions for the business. Being a data scientist requires making educated judgments about these tradeoffs.</p>
<h2 id="data-scientists-still-use-business-intelligence-tools">Data Scientists Still Use Business Intelligence Tools</h2>
<p>A hobbyist data scientist without a budget may opt to build their own workflows and data pipelines using free tools. However, professional data scientists have a finite amount of free time (as do all engineers), so there&rsquo;s a massive opportunity cost when reinventing the wheel unnecessarily. Enterprise BI tools such as <a href="https://www.tableau.com">Tableau</a>, <a href="https://looker.com">Looker</a>, and <a href="https://modeanalytics.com">Mode Analytics</a> help retrieve and present data with easy-to-digest dashboards for anyone in the company. They&rsquo;re never cheap, but they&rsquo;re much cheaper to the company than having a data scientist spend valuable time to develop and maintain similar tooling over time.</p>
<p>If a stakeholder wants a data report ASAP, there&rsquo;s no problem falling back to using <a href="https://en.wikipedia.org/wiki/SQL">SQL</a> to query a data warehouse and output results into an Excel spreadsheet (plus pretty data visualizations!) to quickly transport in an email. Part of being a data scientist is working out which tools are best appropriate at what time.</p>
<p>Some might argue that using BI tools and SQL are not responsibilities for data scientists, but instead for Business Analysts or Data Analysts. That&rsquo;s a <a href="https://en.wikipedia.org/wiki/No_true_Scotsman">No True Scotsman</a> way of looking at it; there&rsquo;s a lot of overlap in data science with other analytical fields, and there&rsquo;s nothing wrong with that.</p>
<h2 id="data-scientists-are-software-engineers-too">Data Scientists Are Software Engineers Too</h2>
<p>Although MOOCs encourage <em>self</em>-study, data science is a collaborative process. And not just with other data scientists on a team, but with other software engineers in the company. Version control tools like <a href="https://git-scm.com">Git</a> are often used for data scientists to upload their portfolio projects publicly to <a href="https://github.com">GitHub</a>, but there are many other important features for use in a company-wide collaborative environment such as branching a repository, making pull requests, and merging conflicts. Beyond that are modern development QA practices, such as test environments, consistent code style, and code reviews. The full process varies strongly by company: Airbnb has a <a href="https://medium.com/airbnb-engineering/scaling-knowledge-at-airbnb-875d73eff091">good thought piece</a> about how they utilize their Knowledge Base for data science collaboration using Git.</p>
<p>One of the very hard and surprisingly underdiscussed aspects of data science is <a href="https://en.wikipedia.org/wiki/DevOps">DevOps</a>, and how to actually get a statistical model into production. <a href="https://www.docker.com/resources/what-container">Docker containers</a>, for example, are newer technology that&rsquo;s hard to learn, but have many data science and DevOps benefits by mitigating Python dependency hell and ensuring a consistent environment for model deployment and execution. And once the model is in production, data scientists, data engineers, and dedicated DevOps personnel need to work together to figure out if the model has the expected output, if the model is performing with expected speed/memory overhead, how often to retrain the model on fresh data (plus the scheduling/data pipelining necessary to do so), and how to efficiently route predictions out of the system to the user.</p>
<h2 id="data-science-cant-solve-everything">Data Science Can&rsquo;t Solve Everything</h2>
<p>Data science experiments (even those utilizing magical AI) are allowed to fail, and not just in the fail-to-reject-the-null-hypothesis sense. Thought pieces typically discuss successful projects, which leads to a survivorship bias. Even with massive amounts of input data, it&rsquo;s <em>likely</em> for a model to fail to converge and offer zero insight, or an experiment fail to offer statistically significant results (common with <a href="https://vwo.com/ab-testing/">A/B testing</a>).</p>
<p><span><blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">real world data science is an R<sup>2</sup> of 0.10 <a href="https://twitter.com/hashtag/GoogleNext18?src=hash&amp;ref_src=twsrc%5Etfw">#GoogleNext18</a> <a href="https://t.co/qNsno2dscR">pic.twitter.com/qNsno2dscR</a></p>— Max Woolf (@minimaxir) <a href="https://twitter.com/minimaxir/status/1021885939361042432?ref_src=twsrc%5Etfw">July 24, 2018</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</span></p>
<p>The difficulty of real-world data science is recognizing if a given problem <em>can</em> be solved, how much of your valuable time to spend iterating to <em>maybe</em> solve it, how to report to stakeholders if it <em>can&rsquo;t</em> be solved, and what are the next steps if that&rsquo;s the case.</p>
<p>Don&rsquo;t <a href="https://www.buzzfeednews.com/article/stephaniemlee/brian-wansink-cornell-p-hacking"><em>p</em>-hack</a>!</p>
<h2 id="data-science-and-ethics">Data Science and Ethics</h2>
<p>During the rise of the &ldquo;data science/AI is magic!&rdquo; era, massive algorithmic and statistical failures suggest that data science might not always make the world a better place. Amazon built a resume-reading model which <a href="https://www.reuters.com/article/us-amazon-com-jobs-automation-insight/amazon-scraps-secret-ai-recruiting-tool-that-showed-bias-against-women-idUSKCN1MK08G">accidentally learned to be sexist</a>. Facebook overestimated <a href="https://www.theverge.com/2018/10/17/17989712/facebook-inaccurate-video-metrics-inflation-lawsuit">performance metrics on their videos</a>, causing complete business pivots for media organizations in vain, indirectly <a href="https://www.theatlantic.com/technology/archive/2018/10/facebook-driven-video-push-may-have-cost-483-journalists-their-jobs/573403/">leading to hundreds of layoffs</a>. YouTube&rsquo;s recommended video algorithms <a href="https://medium.com/@jamesbridle/something-is-wrong-on-the-internet-c39c471271d2">drove children towards shocking and disturbing content</a>. And these companies have some of the best data talent <em>in the entire world</em>.</p>
<p>The <em>qualitative</em> output of a model or data analysis is just as important as the quantitative performance, if not more. Allowing dangerous model output to hit production and impact <em>millions</em> of consumers is a failure of QA at all levels. In fairness these companies usually fix these issues, but only <em>after</em> journalists <a href="https://www.nytimes.com/2018/10/19/opinion/facebook-twitter-journalism-misinformation.html">point them out</a>. The problem with blindly chasing a performance metric (like Kaggle) is that it ignores collateral, unexpected effects.</p>
<p><span><blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">Don’t be data-driven. Be data-informed. Metrics should never be in charge because they have no moral compass.</p>— Kim Goodwin (@kimgoodwin) <a href="https://twitter.com/kimgoodwin/status/1051849805280948224?ref_src=twsrc%5Etfw">October 15, 2018</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </span></p>
<p>Maybe recommending shocking videos is what maximizes clickthrough rate or ad revenue per the models according to a business dashboard. Unfortunately, if the data justifies it and the business stakeholders encourage it, the company may <em>accept the consequences</em> of a flawed algorithm if they don&rsquo;t outweigh the benefits. It&rsquo;s important for data scientists to be aware that they may be party to that.</p>
<h2 id="conclusion">Conclusion</h2>
<p>I realize the irony of using a data science thought piece to argue against data science thought pieces. In fairness, some Medium thought pieces do apply data science in very <em>unique</em> ways or touch on very obscure-but-impactful aspects of frameworks, and I enjoy reading those. The field is still very broadly defined, and your experiences may differ from this post, especially if you&rsquo;re working for a more research-based institution. Unfortunately, I don’t have any new advice for <em>getting</em> a data science job, which is <a href="https://twitter.com/minimaxir/status/951117788835278848">still very difficult</a>.</p>
<p>The popular idea that being a data scientist is a 40-hours-a-week Kaggle competition is <strong>incorrect</strong>. There&rsquo;s a lot more to it that&rsquo;s not as sexy which, in my opinion, is the more interesting aspect of the data science field as a whole.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Leaving Apple Inc.</title>
      <link>https://minimaxir.com/2017/05/leaving-apple/</link>
      <pubDate>Thu, 04 May 2017 09:30:00 -0700</pubDate>
      <guid>https://minimaxir.com/2017/05/leaving-apple/</guid>
      <description>I have made the personal decision to leave my job at Apple to further my personal growth and technical skills.</description>
      <content:encoded><![CDATA[<p>I’ve been working in the San Francisco Bay Area for about 5 years, but I’ve never publicly said where I’ve worked. Well, I was a Software QA Engineer at <a href="https://www.apple.com">Apple Inc.</a>, on the Applications team.</p>
<p>As of last week, I handed in my resignation. While I am thankful for the opportunities I have had at Apple, it is time for me to pursue working in other areas I am passionate about and search for other companies to further my personal growth and technical skills. Resigning from a good job to look for something new might defy conventional wisdom, but the time is right for me to make this bold career move.</p>
<h2 id="my-apple-story">My Apple Story</h2>
<p>I graduated with university honors at <a href="http://www.cmu.edu">Carnegie Mellon University</a>, from the <a href="http://tepper.cmu.edu">Tepper School of Business</a> with a focus on Computing and Information Technology (i.e. data architecture and coding algorithms), and a minor in Statistics.</p>
<p>At the end of my senior year, I received an e-mail from a Software QA Manager at Apple (who followed my <a href="http://techcommntr.tumblr.com">comments</a> at the bottom of <a href="https://techcrunch.com">TechCrunch</a> articles) inviting me for an on-site interview. Following an offer, I moved to the Bay Area to start my first post-undergrad job in Cupertino.</p>
<p>While I can&rsquo;t really talk about what I worked on at Apple, I genuinely enjoyed the work, the product, and team. I had a high impact on the final result and I successfully helped qualify many major software releases. However, after a few years, I realized that my technical skill growth was stalling, so I looked for an an internal transfer to another department, ideally in a data analysis/software engineering role.</p>
<p>Having received no responses internally, I realized I would have to expand my search to outside of Apple.</p>
<h2 id="my-job-hunt">My Job Hunt</h2>
<p>I have a strong technical background from my CMU classes, but not having an explicit Computer Science degree has made it difficult to prove aptitude despite my positive annual reviews and proven experience / technical skills at Apple. So I made the decision to blog with a technical focus here at <a href="http://minimaxir.com">minimaxir.com</a>, which gave me an avenue to showcase my programmatic skills and the opportunity to self-learn practical new tools not covered during the school curriculum, such as <a href="https://www.python.org">Python</a>, <a href="http://ggplot2.org">ggplot2</a>, version control with <a href="https://git-scm.com">git</a>, and reproducible analyses via <a href="http://jupyter.org">Jupyter/IPython Notebooks</a>.</p>
<p>This approach has been successful and many readers have liked my my blog posts: often topping <a href="https://www.reddit.com/r/dataisbeautiful/comments/4bwr7o/relationship_between_rotten_tomatoes_tomatometer/">Reddit</a> and <a href="https://news.ycombinator.com/item?id=13429656">Hacker News</a>, driving hundreds of thousands of pageviews. Additionally, a couple of my posts were even cited in larger publications such as the <a href="https://www.washingtonpost.com/news/the-intersect/wp/2016/06/30/facebook-news-feed-and-the-tyranny-of-positive-content/">Washington Post</a> and <a href="https://www.buzzfeed.com/tomphillips/photos-that-prove-game-of-thrones-happened-in-real-life">BuzzFeed</a>.</p>
<p>I also published many open-source technical projects to my <a href="https://github.com/minimaxir">GitHub</a>. My <a href="https://github.com/minimaxir/big-list-of-naughty-strings">Big List of Naughty Strings</a>, a project I made in a couple hours on a weekend inspired by my QA-ing at work, is now at <strong>20,000+ Stars</strong> on GitHub. My <a href="https://github.com/minimaxir/facebook-page-post-scraper">Facebook Page Post Scraper</a>, which does what the name implies, is now at 1,000+ Stars and has been used by many other businesses and journalists.</p>
<p>Developers have long argued that job seekers should have a strong public portfolio, as demonstrated experience can account for the lack of a relevant degree. After years of building up my portfolio, it became apparent that most outside recruiters I talked with never looked at my blog/GitHub, despite a strong emphasis of both on my résumé.</p>
<p>I subsequently rededicated my blog as a pragmatic demonstration of relevant skills in the data analysis job market, focusing more on practical analysis instead of quirky insights and thoughts. In the process, I obtained proficiency in a number of modern tools, including <a href="http://minimaxir.com/2016/08/clickbait-cluster/">interactive data visualizations</a> on the web with <a href="https://plot.ly">Plotly</a>, processing <a href="http://minimaxir.com/2017/01/amazon-spark/">big data</a> with <a href="http://spark.apache.org">Apache Spark</a>, high-performance <a href="http://minimaxir.com/2017/02/predicting-arrests/">machine learning</a> with <a href="https://github.com/dmlc/xgboost">xgboost</a> and <a href="https://github.com/Microsoft/LightGBM">LightGBM</a>, and even <a href="http://minimaxir.com/2017/04/char-embeddings/">deep learning</a> with <a href="https://github.com/fchollet/keras">Keras</a> and <a href="https://github.com/tensorflow/tensorflow">TensorFlow</a>.</p>
<p>I am now actively looking for a <strong>data analyst/software engineering job within San Francisco</strong>. If you are interested or if you know of companies who are looking for qualified people, please send me an email at <strong><a href="mailto:max@minimaxir.com">max@minimaxir.com</a></strong>.</p>
<h2 id="next-steps">Next Steps</h2>
<p>So I’ll be using my time over the next couple weeks to openly look for a new job, and to network with others in relevant industries (and be able to interview without taking a day off of work). Things have been improving: my <a href="https://news.ycombinator.com/item?id=14238066">comment</a> in the Hacker News &ldquo;Who wants to be hired?&rdquo; thread generated many leads who really liked my blog/portfolio. If you’d like to meet up in San Francisco and talk about tech and data stuff, just let me know.</p>
<p>I still intend to continue blogging, not as a hobby but in a more purposeful way. I have very ambitious goals and now have more time to execute them at a deeper level. Plans include:</p>
<ul>
<li>Web applications leveraging deep learning models, deployed at scale with <a href="https://www.docker.com">Docker</a>/<a href="https://kubernetes.io">Kubernetes</a>.</li>
<li>Interactive data dashboards accompanying every analytical blog post with <a href="https://shiny.rstudio.com">Shiny</a>.</li>
<li>Code screencasts at 4k resolution on <a href="https://youtube.com/minimaxir">YouTube</a>.</li>
<li>Data analysis live-streaming with augmented functionality on <a href="https://www.twitch.tv/minimaxir">Twitch</a>.</li>
</ul>
<p>I have set up a <strong><a href="https://www.patreon.com/minimaxir">Patreon</a></strong> in order to subsidize my machine learning/deep learning/software/hardware needs for my blog posts. If you have found any of my blog posts useful, a monetary contribution to my Patreon would be appreciated and will be put to good creative use.</p>
<p>If you want to keep up with me and my projects, feel free to follow me on <strong><a href="https://www.facebook.com/max.woolf">Facebook</a></strong> and <strong><a href="https://twitter.com/minimaxir">Twitter</a></strong> too.</p>
]]></content:encoded>
    </item>
    <item>
      <title>The Importance of Sanity-Checking Datasets Before Analysis</title>
      <link>https://minimaxir.com/2016/04/trust-but-verify/</link>
      <pubDate>Wed, 06 Apr 2016 08:00:00 -0700</pubDate>
      <guid>https://minimaxir.com/2016/04/trust-but-verify/</guid>
      <description>The 1972 TV Special &amp;lsquo;The Lorax&amp;rsquo; is the best movie ever, earning $1.2 billion?</description>
      <content:encoded><![CDATA[<p>I&rsquo;ve done some cool things with movie data using a dataset from <a href="http://www.omdbapi.com">OMDb API</a>, which is sourced from <a href="http://www.imdb.com">IMDb</a> and <a href="http://www.rottentomatoes.com">Rotten Tomatoes</a> data. In my <a href="http://minimaxir.com/2016/01/movie-revenue-ratings/">previous article</a> on the dataset, I plotted the relationship between the domestic box office revenue of movies and their Rotten Tomatoes scores.</p>
<p>I want to take another look at domestic Box Office Revenues with aggregate statistics such as means/medians on categorical variables such as MPAA rating and release month. For this type of analysis in particular, I&rsquo;ll also need to implement code in <a href="https://www.r-project.org">R</a> for inflation adjustment.</p>
<p>However, I ran into a few unexpectedly silly issues.</p>
<h2 id="seeing-double">Seeing Double</h2>
<p>There are many similarities between data validation and the Quality Assurance process of product development, which is why this particular area appeals to me personally as a Software QA Engineer. Whenever a cool dataset is released publicly, I play around with it to look for any obvious flaws and to get a good all-around benchmark on the robustness of the data (this is a separate procedure from the traditional &ldquo;data cleaning&rdquo; phase necessary to begin quantification on some poorly-structured datasets).</p>
<p>Do the extreme values in the data make sense? Is the data encoded in a sane format? Are there any obvious gaps or logical contradictions in summary representations of the data, especially when compared to other canonical sources?</p>
<p>These concerns are also some of the reasons I&rsquo;ve switched to the <a href="http://jupyter.org">Jupyter Notebook</a> as my primary data science IDE. After each block of code which transforms data, I can print the data frame inline to immediately see the results of the code execution, and refer back to them if anything odd happens in the future.</p>
<p>Let&rsquo;s say I have a data frame of Movies using the latest data dump (3/26/16) from OMDb. This data set contains 1,160,273 movies, including both IMDb and Rotten Tomatoes data. After cleaning the data (not shown), I can use the R package <code>dplyr</code> by Hadley Wickham to sort the data frame by Box Office Revenue descending, and print the <code>head</code> (top) of the data.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">print</span><span class="p">(</span><span class="n">df</span> <span class="o">%&gt;%</span> <span class="nf">select</span><span class="p">(</span><span class="n">imdbID</span><span class="p">,</span> <span class="n">Title</span><span class="p">,</span> <span class="n">Year</span><span class="p">,</span> <span class="n">BoxOffice</span><span class="p">)</span> <span class="o">%&gt;%</span> <span class="nf">arrange</span><span class="p">(</span><span class="nf">desc</span><span class="p">(</span><span class="n">BoxOffice</span><span class="p">))</span> <span class="o">%&gt;%</span> <span class="nf">head</span><span class="p">(</span><span class="m">25</span><span class="p">),</span> <span class="n">n</span> <span class="o">=</span> <span class="m">25</span><span class="p">)</span>
</span></span></code></pre></div><figure>

    <img loading="lazy" srcset="/2016/04/trust-but-verify/data-2_hu_fc7149d7b4ad38a9.webp 320w,/2016/04/trust-but-verify/data-2_hu_e103dfde4f2240f3.webp 768w,/2016/04/trust-but-verify/data-2_hu_cbb23b4322bee2d7.webp 1024w,/2016/04/trust-but-verify/data-2.png 1258w" src="data-2.png"/> 
</figure>

<p>Those movies being the best <em>makes sense</em>. For <a href="http://www.rottentomatoes.com/m/star_wars_episode_vii_the_force_awakens/">Star Wars: The Force Awakens</a>, I can compare it to the Box Office reported on the corresponding Rotten Tomatoes page, which in turn matches the <a href="http://www.boxofficemojo.com/movies/?id=starwars7.htm">domestic Box Office Revenue</a> on <a href="http://www.boxofficemojo.com">Box Office Mojo</a>.</p>
<p>But wait, <a href="https://en.wikipedia.org/wiki/The_Dark_Knight_%28film%29">The Dark Knight</a> appears <em>twice</em>? How?!</p>
<p>There&rsquo;s no way I would have missed something this obvious during the sanity-check for my previous article. In order to make sure that I&rsquo;m not going insane, I double-checked the December 2015 data dump I used for that post, derived the top movies with the same methodology for the modern data dump, and the duplicate movies <em>were not present</em>. Weird.</p>
<p>There are 2 different IDs for
The Dark Knight, and for some other movies near the top (<a href="http://www.imdb.com/title/tt4817264/">Inside Out</a>, &ldquo;<a href="http://www.imdb.com/title/tt3138972/">The Gravity</a>&rdquo;). Fortunately, duplicate data like this is easy to debug. The second data entry for The Dark Knight has a greater IMDb ID (1774602) which means it was likely added to the site later. Let&rsquo;s look up the <a href="http://www.imdb.com/title/tt1774602/">corresponding IMDb page</a>:</p>
<figure>

    <img loading="lazy" srcset="/2016/04/trust-but-verify/dark-knight_hu_a2dd88a3ae15f413.webp 320w,/2016/04/trust-but-verify/dark-knight_hu_1518ed909d29f88e.webp 768w,/2016/04/trust-but-verify/dark-knight_hu_e8a475182d872549.webp 1024w,/2016/04/trust-but-verify/dark-knight.png 1128w" src="dark-knight.png"/> 
</figure>

<p>Huh. Apparently someone put a filler movie entry with the same name and release year as a blockbuster movie in hopes that people search for it by accident (and since it received 50 ratings and an average score of 8.6, this tactic was successful).</p>
<p>Using the Rotten Tomatoes <a href="http://developer.rottentomatoes.com/docs/read/json/v10/Movie_Alias">IMDb Lookup API</a>, we find that &ldquo;The Dark Knight&rdquo; page on Rotten Tomatoes&hellip;<a href="http://api.rottentomatoes.com/api/public/v1.0/movie_alias.json?type=imdb&amp;id=1774602">doesn&rsquo;t exist</a>.</p>
<p>We can run a safe deduplicate by removing entries with the same title (excluding the &ldquo;The&rdquo; if present) and release year.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">df_dup</span> <span class="o">&lt;-</span> <span class="n">df</span> <span class="o">%&gt;%</span> <span class="nf">select</span><span class="p">(</span><span class="n">Title</span><span class="p">,</span> <span class="n">Year</span><span class="p">)</span> <span class="o">%&gt;%</span> <span class="nf">mutate</span><span class="p">(</span><span class="n">Title</span> <span class="o">=</span> <span class="nf">gsub</span><span class="p">(</span><span class="s">&#34;The &#34;</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">,</span> <span class="n">Title</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="n">dup</span> <span class="o">&lt;-</span> <span class="nf">duplicated</span><span class="p">(</span><span class="n">df_dup</span><span class="p">)</span>   <span class="c1"># find entry indices which are duplicates</span>
</span></span><span class="line"><span class="cl"><span class="nf">rm</span><span class="p">(</span><span class="n">df_dup</span><span class="p">)</span>   <span class="c1"># remove temp dataframe</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">df_dedup</span> <span class="o">&lt;-</span> <span class="n">df</span> <span class="o">%&gt;%</span> <span class="nf">filter</span><span class="p">(</span><span class="o">!</span><span class="n">dup</span><span class="p">)</span>   <span class="c1"># keep entries which are *not* dups</span>
</span></span><span class="line"><span class="cl"><span class="nf">print</span><span class="p">(</span><span class="n">df_dedup</span> <span class="o">%&gt;%</span> <span class="nf">select</span><span class="p">(</span><span class="n">imdbID</span><span class="p">,</span> <span class="n">Title</span><span class="p">,</span> <span class="n">Year</span><span class="p">,</span> <span class="n">BoxOffice</span><span class="p">)</span> <span class="o">%&gt;%</span> <span class="nf">arrange</span><span class="p">(</span><span class="nf">desc</span><span class="p">(</span><span class="n">BoxOffice</span><span class="p">))</span> <span class="o">%&gt;%</span> <span class="nf">head</span><span class="p">(</span><span class="m">25</span><span class="p">),</span> <span class="n">n</span> <span class="o">=</span> <span class="m">25</span><span class="p">)</span>
</span></span></code></pre></div><figure>

    <img loading="lazy" srcset="/2016/04/trust-but-verify/data-1_hu_8b5a2ca66b9bcf38.webp 320w,/2016/04/trust-but-verify/data-1_hu_a71793e3bcc29bd2.webp 768w,/2016/04/trust-but-verify/data-1_hu_e83f2d858764f621.webp 1024w,/2016/04/trust-but-verify/data-1.png 1224w" src="data-1.png"/> 
</figure>

<p>There we go! The de-duped dataset has 1,114,431 movies, impliying that there were 45,842 of these duplicate entries.</p>
<p>I&rsquo;m not sure <em>whose</em> fault it is that duplicate movies suddenly became present in the data dump: OMDb or Rotten Tomatoes. <em>But it doesn&rsquo;t matter</em>: the wrong entries still need to be addressed, and it&rsquo;s good to have a test case for the future too.</p>
<h2 id="inflation-station">Inflation Station</h2>
<p>A <a href="http://stackoverflow.com/a/26068058">Stack Overflow answer</a> from <a href="http://stackoverflow.com/users/1048757/brash-equilibrium">Ben Hanowell</a> has a good R implementation and rationale for implementing inflation adjustment using the <a href="https://research.stlouisfed.org/fred2/data/CPIAUCSL.txt">historical Consumer Price Index data</a> from the <a href="https://www.stlouisfed.org">Federal Reserve Bank of St. Louis</a>.</p>
<p>Take the index for each year (averaging each month for simplicity) and create an adjustment factor to convert historical dollar amounts into present-day dollar amounts. Much better than plugging hundreds of thousands of values into an online calculator. Here&rsquo;s the SO code made <code>dplyr</code>-friendly for this purpose, with the requisite sanity-checks.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">inflation</span> <span class="o">&lt;-</span> <span class="nf">read_csv</span><span class="p">(</span><span class="s">&#34;http://research.stlouisfed.org/fred2/data/CPIAUCSL.csv&#34;</span><span class="p">)</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">                    <span class="nf">group_by</span><span class="p">(</span><span class="n">Year</span> <span class="o">=</span> <span class="nf">as.integer</span><span class="p">(</span><span class="nf">substr</span><span class="p">(</span><span class="n">DATE</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="m">4</span><span class="p">)))</span> <span class="o">%&gt;%</span>
</span></span><span class="line"><span class="cl">                    <span class="nf">summarize</span><span class="p">(</span><span class="n">Avg_Value</span> <span class="o">=</span> <span class="nf">mean</span><span class="p">(</span><span class="n">VALUE</span><span class="p">))</span> <span class="o">%&gt;%</span>   <span class="c1"># average across all months</span>
</span></span><span class="line"><span class="cl">                    <span class="nf">mutate</span><span class="p">(</span><span class="n">Adjust</span> <span class="o">=</span> <span class="nf">tail</span><span class="p">(</span><span class="n">Avg_Value</span><span class="p">,</span> <span class="m">1</span><span class="p">)</span> <span class="o">/</span> <span class="n">Avg_Value</span><span class="p">)</span>   <span class="c1"># normalize by most-recent year</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">print</span><span class="p">(</span><span class="n">inflation</span> <span class="o">%&gt;%</span> <span class="nf">head</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"><span class="nf">print</span><span class="p">(</span><span class="n">inflation</span> <span class="o">%&gt;%</span> <span class="nf">tail</span><span class="p">())</span>
</span></span></code></pre></div><figure>

    <img loading="lazy" srcset="/2016/04/trust-but-verify/inf.png 290w" src="inf.png"/> 
</figure>

<p>For example, to get the inflation-adjusted Box Office Revenue for a movie released in 1949 in 2016 dollars, we multiply the reported revenue by 10. That sounds about right (and matches closely enough to the output of the <a href="http://data.bls.gov/cgi-bin/cpicalc.pl?cost1=1&amp;year1=1949&amp;year2=2016">Bureau of Labor Statistics inflation calculator</a>).</p>
<p>Now map each inflation adjustment factor to each movie by merging the two datasets (on the <code>Year</code> column), then multiply the Box Office revenue by the adjustment factor to get the inflation-adjusted revenue. Plus another sanity-check for good measure.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">df_dedup_join</span> <span class="o">&lt;-</span> <span class="n">df_dedup</span> <span class="o">%&gt;%</span> <span class="nf">inner_join</span><span class="p">(</span><span class="n">inflation</span><span class="p">)</span> <span class="o">%&gt;%</span> <span class="nf">mutate</span><span class="p">(</span><span class="n">AdjBoxOffice</span> <span class="o">=</span> <span class="n">BoxOffice</span> <span class="o">*</span> <span class="n">Adjust</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nf">print</span><span class="p">(</span><span class="n">df_dedup_join</span> <span class="o">%&gt;%</span> <span class="nf">select</span><span class="p">(</span><span class="n">Title</span><span class="p">,</span> <span class="n">Year</span><span class="p">,</span> <span class="n">AdjBoxOffice</span><span class="p">)</span> <span class="o">%&gt;%</span> <span class="nf">arrange</span><span class="p">(</span><span class="nf">desc</span><span class="p">(</span><span class="n">AdjBoxOffice</span><span class="p">))</span> <span class="o">%&gt;%</span> <span class="nf">head</span><span class="p">(</span><span class="m">25</span><span class="p">),</span> <span class="n">n</span><span class="o">=</span><span class="m">25</span><span class="p">)</span>
</span></span></code></pre></div><figure>

    <img loading="lazy" srcset="/2016/04/trust-but-verify/data-3_hu_9bedc8e778de7ad8.webp 320w,/2016/04/trust-but-verify/data-3_hu_7c39435bd36c198e.webp 768w,/2016/04/trust-but-verify/data-3_hu_b47d674b228181e4.webp 1024w,/2016/04/trust-but-verify/data-3.png 1070w" src="data-3.png"/> 
</figure>

<p>Uh-oh.</p>
<p>I mean, <a href="https://en.wikipedia.org/wiki/The_Lorax_%28TV_special%29">The Lorax</a> probably earned $1.2 billion in VHS sales for Earth Day education <em>alone</em>, but the TV special was never released in theaters. There was a <a href="https://en.wikipedia.org/wiki/The_Lorax_%28film%29">CGI remake of The Lorax</a> a few years ago which was reasonably popular. Could it be that someone at Rotten Tomatoes or Box Office Mojo confused the two media?</p>
<p>That is exactly what happened. On Rotten Tomatoes, The <a href="http://www.rottentomatoes.com/m/the-lorax/">1972 Lorax</a> was encoded with similar box office revenue as the <a href="http://www.rottentomatoes.com/m/the_lorax/">2012 Lorax</a>; then the inflation factor sextupled it. For this type of data fidelity issue, it&rsquo;s considerably more obvious whose at fault.</p>
<p>Unfortunately, that&rsquo;s not the end of problems with the dataset. I compared my results with <a href="http://www.vox.com/2016/4/4/11351788/batman-v-superman-terrible-reviews#undefined">Vox&rsquo;s dataset</a> on worldwide historical box office revenues. In the Top 200 Movies by inflation-adjusted revenue, there are noted historical movie omissions such as <a href="http://www.rottentomatoes.com/m/jaws/">Jaws</a> and <a href="http://www.rottentomatoes.com/m/star_wars/">Star Wars: A New Hope</a>. It turns out Rotten Tomatoes does not have Box Office Revenue data for these movies at all.</p>
<p>That is a very serious problem which I&rsquo;ll have to think about if it blocks any analysis on aggregate box office data completely. In the end, sanity-checking third party data is important because you never know <em>how</em> the data will surprise you, until it&rsquo;s too late.</p>
<hr>
<p><em>You can view the Top 200 movies by domestic box office revenue for each of the 12/15 source dataset, the 3/16 dataset, the 3/16 deduped dataset, and the 3/16 deduced inflation-adjusted data <a href="https://github.com/minimaxir/movie-data-sanity-checking">in this GitHub repository</a>, along with the Jupyter notebook.</em></p>
]]></content:encoded>
    </item>
    <item>
      <title>Facebook Reactions and the Problems With Quantifying Likes Differently</title>
      <link>https://minimaxir.com/2016/02/facebook-reactions/</link>
      <pubDate>Mon, 29 Feb 2016 08:00:00 -0700</pubDate>
      <guid>https://minimaxir.com/2016/02/facebook-reactions/</guid>
      <description>Apparently, there is little statistical relationship between things that are cute and things that make you go YAAASS.</description>
      <content:encoded><![CDATA[<p>Facebook added <a href="http://newsroom.fb.com/news/2016/02/reactions-now-available-globally/">Facebook Reactions</a>, allowing users to do more than just &ldquo;Like&rdquo; posts and statuses as they have done for the past decade. Likes were the universal symbol of approval on social media. Now, Facebook users can apply more granular responses, from positive emotions like <strong>Love</strong>, to negative emotions such as <strong>Angry</strong>. This was widely believed to be Facebook&rsquo;s compromise instead of adding a Dislike button.</p>
<figure>

    <img loading="lazy" srcset="/2016/02/facebook-reactions/facebook_react_hu_844fda335951da9b.webp 320w,/2016/02/facebook-reactions/facebook_react_hu_86d02679c7d58cf3.webp 768w,/2016/02/facebook-reactions/facebook_react.png 828w" src="facebook_react.png"/> 
</figure>

<p>Of course, there&rsquo;s an ulterior motive. The use of reactions provides organic data on the sentiment of a status, which is helpful for numerous marketing and statistical applications. As <a href="http://www.buzzfeed.com/alexkantrowitz/facebook-reactions-launch-today">BuzzFeed notes</a>, Facebook ads may be able &ldquo;to write one product message for someone who mostly uses <strong>Sad</strong> and another who mostly uses <strong>Wow</strong> or <strong>Love.</strong>&rdquo;</p>
<p>However, this isn&rsquo;t the first time a big social network has tried implementing reactions alongside Likes/Dislikes. Four years ago, YouTube added <a href="http://googlesystem.blogspot.com/2011/06/youtube-reactions.html">Reaction buttons</a> to their comments section:</p>
<figure>

    <img loading="lazy" srcset="/2016/02/facebook-reactions/youtube-reactions_hu_7a4632d04eb1ee92.webp 320w,/2016/02/facebook-reactions/youtube-reactions.png 572w" src="youtube-reactions.png"/> 
</figure>

<p>&hellip;and removed them sometime after without fanfare, replacing it with the simple Like/Dislike bar.</p>
<p>Presumably, YouTube implemented the buttons for the similar reason as Facebook. What makes things different now, if anything?</p>
<h2 id="a-quantitative-approach-to-feeling">A Quantitative Approach to Feeling</h2>
<p>Even after YouTube&rsquo;s failure, another data-driven website implemented reaction buttons: BuzzFeed (who else?). At the end of each article (in most categories), registered users can select a quirky reaction to indicate how they felt about the article.</p>
<figure>

    <img loading="lazy" srcset="/2016/02/facebook-reactions/buzzfeedreactions_hu_d32803738bee0d06.webp 320w,/2016/02/facebook-reactions/buzzfeedreactions.png 646w" src="buzzfeedreactions.png"/> 
</figure>

<p>The heart represents <strong>Love</strong> internally and is by-far the most-used reaction on BuzzFeed posts. When I started scraping BuzzFeed data in 2014 <a href="http://minimaxir.com/2015/01/linkbait/">to analyze clickbait</a>, I made sure to grab the reaction data of other reactions as well to see if there are any interesting trends or correlations between reactions. A cursory glance at the scraped reaction data revealed a problem that forced me to disregard it.</p>
<p>An important part of variable selection for analysis and modeling is avoiding <em>redundant</em> features, as that can cause issues such as <a href="https://en.wikipedia.org/wiki/Multicollinearity">multicollinearity</a> and <a href="https://en.wikipedia.org/wiki/Overfitting">overfitting</a>. For Facebook, avoiding adding redundant Reactions was an <a href="https://medium.com/facebook-design/reactions-not-everything-in-life-is-likable-5c403de72a3f">explicit design goal</a> of the feature, but the positive emotions such as <strong>Like</strong> and <strong>Wow</strong> might be overly similar regardless (I believe it fair to compare the behavior of BuzzFeed users with the average Facebook user, given that they hit the same demographics). Do BuzzFeed readers use specific positive reactions differently? Did they use specific negative reactions?</p>
<p>I rechecked my 2014 data in light of Facebook Reactions. The scraped dataset contains reaction data from 9,883 BuzzFeed articles in the Celebrity, Animals, Books, Longform, and Business categories. From that, I made a <a href="http://vita.had.co.nz/papers/gpp.pdf">pairs plot</a> for the counts of all the <em>positive</em> reactions on the articles to illustrate all bivariate relationships:</p>
<ul>
<li>The lower half of the pairs plot is a scatterplot for the two reactions; the axes represent the number of votes for a given reaction on a BuzzFeed article (both axes are scaled logarithmically), color intensity indicates the number of articles at that X/Y combo, and the line is a linear trendline of least-squares.</li>
<li>The diagonal of the pairs plot represents the density distribution of reaction vote counts for that reaction. (also logarithmically scaled on the X axis)</li>
<li>The upper half of the pairs plot illustrates the Pearson correlation between the non-log quantities of the two reaction variables. The stars represent statistical significance of the correlation test; since the data set is large, all correlations are statistically significant (rejection of null hypothesis of no correlation) at p &lt; 0.001.</li>
</ul>
<figure>

    <img loading="lazy" srcset="/2016/02/facebook-reactions/buzzfeed-pos_hu_d6d7a26193c3ada0.webp 320w,/2016/02/facebook-reactions/buzzfeed-pos_hu_286467cf9bb9a86.webp 768w,/2016/02/facebook-reactions/buzzfeed-pos_hu_2ddf9da10f86ca62.webp 1024w,/2016/02/facebook-reactions/buzzfeed-pos.png 1600w" src="buzzfeed-pos.png"/> 
</figure>

<p>All of the bivariate correlations of positive reactions are <em>moderately or strongly positively correlated</em>, which is problematic for analysis (except one: apparently, there is little statistical relationship between things that are cute and things that make you go YAAASS). So why not just use the <strong>Love</strong> reaction, since articles tend to get about 100 Loves, while other reactions get around 10?</p>
<p>Does the same hold for negative reactions? Relatedly, we would also expect a negative correlation between the number of <strong>Love</strong> reactions and negative reactions, right?</p>
<figure>

    <img loading="lazy" srcset="/2016/02/facebook-reactions/buzzfeed-neg_hu_621abb3f15b07deb.webp 320w,/2016/02/facebook-reactions/buzzfeed-neg_hu_74efa270902d7802.webp 768w,/2016/02/facebook-reactions/buzzfeed-neg_hu_70af131959efaab2.webp 1024w,/2016/02/facebook-reactions/buzzfeed-neg.png 1600w" src="buzzfeed-neg.png"/> 
</figure>

<p>All negative reactions are positively correlated, as expected, but there is a weak <em>positive</em> correlation between <strong>Love</strong> and <strong>Hate</strong>, which is definitely not right. There isn&rsquo;t an ideal &ldquo;negative&rdquo; reaction, since all have similar distributions.</p>
<p>Why does Facebook have 6 different responses to gauge positivity or negativity when one reaction for each would be both more accurate and more intuitive for the user?</p>
<h2 id="conceal-dont-feel">Conceal, Don&rsquo;t Feel</h2>
<p>There are other qualitative issues with Facebook&rsquo;s current implementation of Reactions. Apparently, Likes and Reactions are treated <em>differently internally</em>. As a result, you get separate notifications for Likes and Reactions.</p>
<figure>

    <img loading="lazy" srcset="/2016/02/facebook-reactions/facebook_react2_hu_462102ea064f125f.webp 320w,/2016/02/facebook-reactions/facebook_react2_hu_cdb8c15334891015.webp 768w,/2016/02/facebook-reactions/facebook_react2.png 874w" src="facebook_react2.png"/> 
</figure>

<p>Why? No idea. There is enough Notification spam on Facebook, I don&rsquo;t need <em>double notifications</em> in my Notification feed for every status I make.</p>
<p>What&rsquo;s important to note is that a user cannot both Like and React to a status; only one or the other. As a result, the number of Likes on statuses overall will drop, and this is a <em>major</em> problem for businesses who are dependent on measuring the number of Likes for engagement.</p>
<p>I took a look at the Facebook Graph API endpoint for <a href="https://developers.facebook.com/docs/graph-api/reference/v2.5/post">Facebook Page Posts</a> (same endpoint I use for my <a href="https://github.com/minimaxir/facebook-page-post-scraper">Facebook Page Data Scraper</a>), and I can confirm that the API can only report the number of Likes on a status; not the number of Likes + Reactions, or number of Likes + number of each Reaction.</p>
<figure>

    <img loading="lazy" srcset="/2016/02/facebook-reactions/cnn_fb_hu_7b868416e9ef2e61.webp 320w,/2016/02/facebook-reactions/cnn_fb_hu_cc31054c813a0b29.webp 768w,/2016/02/facebook-reactions/cnn_fb_hu_22634dbc600cd4ba.webp 1024w,/2016/02/facebook-reactions/cnn_fb.jpg 1800w" src="cnn_fb.jpg"/> 
</figure>

<p>There is no way currently to automate the retrieval of Reactions data from Facebook posts, which is an unfortunate oversight (especially considering how Twitter <a href="https://blog.twitter.com/2015/hearts-for-developers">handled the transition</a> from Favorites to Likes easily).</p>
<p>The example <a href="https://www.facebook.com/cnn/posts/10154506885211509">CNN story</a> I used for that screenshot is anecdotally one of the very few examples I&rsquo;ve noticed where the number of Likes is <em>almost equal</em> to negative emotions, a relationship which should be weakly correlated and therefore this knowledge may be useful to isolate the story as unusual (and serve ads accordingly). At Facebook&rsquo;s immense scale, identifying a relatively small proportion of unusual stories might be enough to justify adding Reactions.</p>
<p>Or maybe this feature is just the harbinger of a new generation of emotionally-charged linkbait. Perhaps there is more to this Facebook Reactions data than what meets the eye, and I&rsquo;ll update my scripts and do further statistical analysis when able. But given what has happened with Reactions data before with YouTube, I am unconvinced and I still believe the functionality as a whole is a usability regression that won&rsquo;t last.</p>
<p>A Dislike button would have been better, just saying.</p>
<hr>
<p><em>You can view the code and data used to generate the BuzzFeed Reaction data visualizations <a href="https://github.com/minimaxir/facebook-reactions/blob/master/buzzfeed_reactions.ipynb">in this Jupyter notebook</a>, <a href="https://github.com/minimaxir/facebook-reactions">open-sourced on GitHub</a>, or you can <a href="https://github.com/minimaxir/facebook-reactions/raw/master/reactions_pdf.pdf">view as a PDF</a>, which is better if you are on a mobile device.</em></p>
]]></content:encoded>
    </item>
  </channel>
</rss>
