<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rafael Poyiadzi</title>
    <description>The latest articles on DEV Community by Rafael Poyiadzi (@rafael_poyiadzi_85c2eed09).</description>
    <link>https://dev.to/rafael_poyiadzi_85c2eed09</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3715709%2F0db14f09-0ff5-4e6a-ae76-9e62c5dac145.png</url>
      <title>DEV Community: Rafael Poyiadzi</title>
      <link>https://dev.to/rafael_poyiadzi_85c2eed09</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rafael_poyiadzi_85c2eed09"/>
    <language>en</language>
    <item>
      <title>Stop Writing Regex for Data You Should Be Describing in English</title>
      <dc:creator>Rafael Poyiadzi</dc:creator>
      <pubDate>Tue, 10 Feb 2026 11:08:53 +0000</pubDate>
      <link>https://dev.to/rafael_poyiadzi_85c2eed09/stop-writing-regex-for-data-you-should-be-describing-in-english-4f07</link>
      <guid>https://dev.to/rafael_poyiadzi_85c2eed09/stop-writing-regex-for-data-you-should-be-describing-in-english-4f07</guid>
      <description>&lt;p&gt;You have a spreadsheet of job postings and you need to filter it down to roles that are remote-friendly, senior-level, and have a disclosed salary. Sounds straight-forward except the data looks like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;company&lt;/th&gt;
&lt;th&gt;post&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Airtable&lt;/td&gt;
&lt;td&gt;Async-first team, 8+ yrs exp, $185-220K base&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vercel&lt;/td&gt;
&lt;td&gt;Lead our NYC team. Competitive comp, DOE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Notion&lt;/td&gt;
&lt;td&gt;In-office SF. Staff eng, $200K + equity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linear&lt;/td&gt;
&lt;td&gt;Bootcamp grads welcome! $85K, remote-friendly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Descript&lt;/td&gt;
&lt;td&gt;Work from anywhere. Principal architect, $250K&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now try writing deterministic rules for that.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Remote-friendly" could be "remote", "work from anywhere", "async-first", or implied by the absence of an office mention.&lt;/li&gt;
&lt;li&gt;"Senior-level" might be "8+ yrs", "Staff", "Principal", or "Lead" — but "Lead" could also be a junior team lead.&lt;/li&gt;
&lt;li&gt;"Salary disclosed" means actual numbers, not "Competitive comp" or "DOE."&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What if you could just describe what you want?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://everyrow.io/" rel="noopener noreferrer"&gt;everyrow&lt;/a&gt; lets you define fuzzy, qualitative logic in natural language and apply it to every row of a dataframe. The SDK handles LLM orchestration, structured outputs, and scaling with the user specifying judgment criteria in plain English.&lt;/p&gt;

&lt;p&gt;Here's the job screening example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;everyrow.ops&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt;

&lt;span class="n"&gt;jobs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;company&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Airtable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Async-first team, 8+ yrs exp, $185-220K base&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;company&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Vercel&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Lead our NYC team. Competitive comp, DOE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;company&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Notion&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;In-office SF. Staff eng, $200K + equity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;company&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Linear&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bootcamp grads welcome! $85K, remote-friendly&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;company&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Descript&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Work from anywhere. Principal architect, $250K&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JobScreenResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;qualifies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;True if meets ALL criteria&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        Qualifies if ALL THREE are met:
        1. Remote-friendly
        2. Senior-level (5+ yrs exp OR Senior/Staff/Principal in title)
        3. Salary disclosed (specific numbers, not &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;competitive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; or &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DOE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;)
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;JobScreenResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. No regex, no threshold tuning, no parsing logic. The &lt;code&gt;screen&lt;/code&gt; operation evaluates every row against your natural-language criteria using an LLM and returns structured results via a Pydantic model.&lt;/p&gt;

&lt;p&gt;The output:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;company&lt;/th&gt;
&lt;th&gt;qualifies&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Airtable&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vercel&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Notion&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linear&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Descript&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Airtable qualifies:&lt;/em&gt; async-first (remote-friendly), 8+ years (senior), $185-220K (salary disclosed).&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Descript qualifies:&lt;/em&gt; work from anywhere (remote), principal architect (senior), $250K (salary disclosed).&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The rest fail on at least one criterion: Vercel has no real salary, Notion is in-office, Linear isn't senior-level.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sessions: Track Everything in a Dashboard
&lt;/h2&gt;

&lt;p&gt;Every operation runs within a grouping of related operations that appears in the &lt;a href="https://everyrow.io/" rel="noopener noreferrer"&gt;everyrow.io&lt;/a&gt; web UI. These sessions are created automatically, but for multi-step pipelines you'll want to create one explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;everyrow&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_session&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;everyrow.ops&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;create_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Lead Qualification&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;View at: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_url&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;screened&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Has a company email domain (not gmail, yahoo, etc.)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;leads&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ScreenResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;ranked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Score by likelihood to convert&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;screened&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;field_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;conversion_score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The session URL gives you a live dashboard where you can monitor progress and inspect results while your script runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background Jobs for Large Datasets
&lt;/h2&gt;

&lt;p&gt;All the operations above are already &lt;code&gt;async/await&lt;/code&gt;. The &lt;code&gt;_async&lt;/code&gt; variants are different — they're fire-and-forget: they submit work to the server and return immediately so your script can continue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;everyrow.ops&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;screen_async&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;create_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Background Screening&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;screen_async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Remote-friendly, senior-level, salary disclosed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;large_dataframe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Task ID: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# do other work...
&lt;/span&gt;    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;await_result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your script crashes, recover the result later using the task ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;everyrow&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;fetch_task_data&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch_task_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;12345678-1234-1234-1234-123456789abc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Beyond Screening: What Else Can You Do?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;screen&lt;/code&gt; is just one of several operations:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Screen&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Filter rows by criteria that require judgment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rank&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Score rows by qualitative factors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dedupe&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Deduplicate when fuzzy string matching isn't enough&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Merge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Join tables when keys don't match exactly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Research&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Run web agents to research each row&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each operation takes a natural-language task description and a dataframe, and returns structured results. Same pattern, different capability.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use This (and When Not To)
&lt;/h2&gt;

&lt;p&gt;everyrow is designed for cases where the logic is easy to describe but hard to code: screening, ranking, deduplication, and enrichment tasks where the criteria require judgment.&lt;/p&gt;

&lt;p&gt;It's not a replacement for deterministic transformations. If you can write a reliable &lt;code&gt;df[df["salary"] &amp;gt; 100000]&lt;/code&gt;, you should. Use everyrow for the columns where the values are natural language, inconsistent, or require world knowledge to interpret.&lt;/p&gt;

&lt;p&gt;The tradeoff is latency and cost: LLM-based operations are slower and not free. For the job screening example above, processing 5 rows takes a few seconds and costs a fraction of a cent. For 10,000 rows, you'd want the async variants and should expect minutes rather than milliseconds. The &lt;a href="https://everyrow.io/docs/getting-started" rel="noopener noreferrer"&gt;docs&lt;/a&gt; cover scaling patterns for larger datasets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;everyrow
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EVERYROW_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_key_here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get a free API key at &lt;a href="https://everyrow.io/api-key" rel="noopener noreferrer"&gt;everyrow.io/api-key&lt;/a&gt; - comes with $20 free credit.&lt;/p&gt;

&lt;p&gt;Full docs and more examples: &lt;a href="https://everyrow.io/docs/getting-started" rel="noopener noreferrer"&gt;everyrow.io/docs/getting-started&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Resources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://everyrow.io/docs/getting-started" rel="noopener noreferrer"&gt;Getting Started Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/futuresearch/everyrow-sdk" rel="noopener noreferrer"&gt;everyrow SDK on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://everyrow.io/api-key" rel="noopener noreferrer"&gt;API Key (with $20 free credit)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>dataengineering</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Stop Writing Regex for Data You Should Be Describing in English</title>
      <dc:creator>Rafael Poyiadzi</dc:creator>
      <pubDate>Tue, 10 Feb 2026 11:08:53 +0000</pubDate>
      <link>https://dev.to/rafael_poyiadzi_85c2eed09/stop-writing-regex-for-data-you-should-be-describing-in-english-204l</link>
      <guid>https://dev.to/rafael_poyiadzi_85c2eed09/stop-writing-regex-for-data-you-should-be-describing-in-english-204l</guid>
      <description>&lt;p&gt;You have a spreadsheet of job postings and you need to filter it down to roles that are remote-friendly, senior-level, and have a disclosed salary. Sounds straight-forward except the data looks like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;company&lt;/th&gt;
&lt;th&gt;post&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Airtable&lt;/td&gt;
&lt;td&gt;Async-first team, 8+ yrs exp, $185-220K base&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vercel&lt;/td&gt;
&lt;td&gt;Lead our NYC team. Competitive comp, DOE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Notion&lt;/td&gt;
&lt;td&gt;In-office SF. Staff eng, $200K + equity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linear&lt;/td&gt;
&lt;td&gt;Bootcamp grads welcome! $85K, remote-friendly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Descript&lt;/td&gt;
&lt;td&gt;Work from anywhere. Principal architect, $250K&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now try writing deterministic rules for that.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Remote-friendly" could be "remote", "work from anywhere", "async-first", or implied by the absence of an office mention.&lt;/li&gt;
&lt;li&gt;"Senior-level" might be "8+ yrs", "Staff", "Principal", or "Lead" — but "Lead" could also be a junior team lead.&lt;/li&gt;
&lt;li&gt;"Salary disclosed" means actual numbers, not "Competitive comp" or "DOE."&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What if you could just describe what you want?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://everyrow.io/" rel="noopener noreferrer"&gt;everyrow&lt;/a&gt; lets you define fuzzy, qualitative logic in natural language and apply it to every row of a dataframe. The SDK handles LLM orchestration, structured outputs, and scaling with the user specifying judgment criteria in plain English.&lt;/p&gt;

&lt;p&gt;Here's the job screening example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;everyrow.ops&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt;

&lt;span class="n"&gt;jobs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;company&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Airtable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Async-first team, 8+ yrs exp, $185-220K base&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;company&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Vercel&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Lead our NYC team. Competitive comp, DOE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;company&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Notion&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;In-office SF. Staff eng, $200K + equity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;company&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Linear&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bootcamp grads welcome! $85K, remote-friendly&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;company&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Descript&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Work from anywhere. Principal architect, $250K&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JobScreenResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;qualifies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;True if meets ALL criteria&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        Qualifies if ALL THREE are met:
        1. Remote-friendly
        2. Senior-level (5+ yrs exp OR Senior/Staff/Principal in title)
        3. Salary disclosed (specific numbers, not &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;competitive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; or &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DOE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;)
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;JobScreenResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. No regex, no threshold tuning, no parsing logic. The &lt;code&gt;screen&lt;/code&gt; operation evaluates every row against your natural-language criteria using an LLM and returns structured results via a Pydantic model.&lt;/p&gt;

&lt;p&gt;The output:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;company&lt;/th&gt;
&lt;th&gt;qualifies&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Airtable&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vercel&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Notion&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linear&lt;/td&gt;
&lt;td&gt;False&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Descript&lt;/td&gt;
&lt;td&gt;True&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Airtable qualifies:&lt;/em&gt; async-first (remote-friendly), 8+ years (senior), $185-220K (salary disclosed).&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Descript qualifies:&lt;/em&gt; work from anywhere (remote), principal architect (senior), $250K (salary disclosed).&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The rest fail on at least one criterion: Vercel has no real salary, Notion is in-office, Linear isn't senior-level.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sessions: Track Everything in a Dashboard
&lt;/h2&gt;

&lt;p&gt;Every operation runs within a grouping of related operations that appears in the &lt;a href="https://everyrow.io/" rel="noopener noreferrer"&gt;everyrow.io&lt;/a&gt; web UI. These sessions are created automatically, but for multi-step pipelines you'll want to create one explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;everyrow&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_session&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;everyrow.ops&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;create_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Lead Qualification&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;View at: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_url&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;screened&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Has a company email domain (not gmail, yahoo, etc.)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;leads&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ScreenResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;ranked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Score by likelihood to convert&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;screened&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;field_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;conversion_score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The session URL gives you a live dashboard where you can monitor progress and inspect results while your script runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background Jobs for Large Datasets
&lt;/h2&gt;

&lt;p&gt;All the operations above are already &lt;code&gt;async/await&lt;/code&gt;. The &lt;code&gt;_async&lt;/code&gt; variants are different — they're fire-and-forget: they submit work to the server and return immediately so your script can continue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;everyrow.ops&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;screen_async&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;create_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Background Screening&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;screen_async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Remote-friendly, senior-level, salary disclosed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;large_dataframe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Task ID: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# do other work...
&lt;/span&gt;    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;await_result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your script crashes, recover the result later using the task ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;everyrow&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;fetch_task_data&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch_task_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;12345678-1234-1234-1234-123456789abc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Beyond Screening: What Else Can You Do?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;screen&lt;/code&gt; is just one of several operations:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Screen&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Filter rows by criteria that require judgment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rank&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Score rows by qualitative factors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dedupe&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Deduplicate when fuzzy string matching isn't enough&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Merge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Join tables when keys don't match exactly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Research&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Run web agents to research each row&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each operation takes a natural-language task description and a dataframe, and returns structured results. Same pattern, different capability.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use This (and When Not To)
&lt;/h2&gt;

&lt;p&gt;everyrow is designed for cases where the logic is easy to describe but hard to code: screening, ranking, deduplication, and enrichment tasks where the criteria require judgment.&lt;/p&gt;

&lt;p&gt;It's not a replacement for deterministic transformations. If you can write a reliable &lt;code&gt;df[df["salary"] &amp;gt; 100000]&lt;/code&gt;, you should. Use everyrow for the columns where the values are natural language, inconsistent, or require world knowledge to interpret.&lt;/p&gt;

&lt;p&gt;The tradeoff is latency and cost: LLM-based operations are slower and not free. For the job screening example above, processing 5 rows takes a few seconds and costs a fraction of a cent. For 10,000 rows, you'd want the async variants and should expect minutes rather than milliseconds. The &lt;a href="https://everyrow.io/docs/getting-started" rel="noopener noreferrer"&gt;docs&lt;/a&gt; cover scaling patterns for larger datasets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;everyrow
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EVERYROW_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_key_here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get a free API key at &lt;a href="https://everyrow.io/api-key" rel="noopener noreferrer"&gt;everyrow.io/api-key&lt;/a&gt; - comes with $20 free credit.&lt;/p&gt;

&lt;p&gt;Full docs and more examples: &lt;a href="https://everyrow.io/docs/getting-started" rel="noopener noreferrer"&gt;everyrow.io/docs/getting-started&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Resources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://everyrow.io/docs/getting-started" rel="noopener noreferrer"&gt;Getting Started Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/futuresearch/everyrow-sdk" rel="noopener noreferrer"&gt;everyrow SDK on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://everyrow.io/api-key" rel="noopener noreferrer"&gt;API Key (with $20 free credit)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>dataengineering</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Is LLM Data Labeling Good Enough to Train On? We Tested It and the Answer Is Yes</title>
      <dc:creator>Rafael Poyiadzi</dc:creator>
      <pubDate>Mon, 09 Feb 2026 10:36:26 +0000</pubDate>
      <link>https://dev.to/rafael_poyiadzi_85c2eed09/is-llm-data-labeling-good-enough-to-train-on-we-tested-it-and-the-answer-is-yes-4pdh</link>
      <guid>https://dev.to/rafael_poyiadzi_85c2eed09/is-llm-data-labeling-good-enough-to-train-on-we-tested-it-and-the-answer-is-yes-4pdh</guid>
      <description>&lt;p&gt;You're building a classifier but data labeling is your bottleneck. Hiring annotators is slow, expensive, and hard to scale — and label quality varies across annotators. What if an LLM could label your data automatically, with structured outputs that guarantee valid labels, and match human accuracy?&lt;/p&gt;

&lt;p&gt;We built an automated data annotation pipeline using &lt;a href="https://github.com/futuresearch/everyrow-sdk" rel="noopener noreferrer"&gt;everyrow&lt;/a&gt; and tested whether LLM-generated labels are good enough to train a classifier. The answer: &lt;strong&gt;yes&lt;/strong&gt; — the LLM matches human-label performance at a fraction of the cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Data Labeling is Expensive
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Active_learning_(machine_learning)" rel="noopener noreferrer"&gt;Active learning&lt;/a&gt; reduces labeling costs by letting the model choose which examples to label next, focusing on the ones it's most uncertain about. But you still need an &lt;strong&gt;oracle&lt;/strong&gt; to provide those labels — traditionally a human annotator.&lt;/p&gt;

&lt;p&gt;We replaced the human annotator with an LLM oracle using &lt;code&gt;everyrow.agent_map&lt;/code&gt;, then ran a controlled experiment on &lt;a href="https://huggingface.co/datasets/fancyzhx/dbpedia_14" rel="noopener noreferrer"&gt;DBpedia-14&lt;/a&gt; (14-class text classification) to measure whether automated data labeling produces labels good enough to train on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building an LLM Data Labeling Pipeline with everyrow
&lt;/h2&gt;

&lt;p&gt;The core of the pipeline is &lt;code&gt;everyrow.agent_map&lt;/code&gt; with a Pydantic response model. The LLM can only return one of 14 valid categories — no parsing or cleanup needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DBpediaClassification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Company&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Educational Institution&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Artist&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Athlete&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Office Holder&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mean Of Transportation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Building&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Natural Place&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Village&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Animal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Plant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Album&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Film&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Written Work&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The DBpedia ontology category&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;query_llm_oracle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;texts_df&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;create_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Active Learning Oracle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;agent_map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Classify this text into exactly one DBpedia ontology category.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;texts_df&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
            &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DBpediaClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;effort_level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;EffortLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CATEGORY_TO_ID&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;category&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;iloc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;texts_df&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We used a TF-IDF + LightGBM classifier with entropy-based uncertainty sampling. Each iteration selects the 20 most uncertain examples, sends them to the LLM for annotation, and retrains. 10 iterations, 200 labels total.&lt;/p&gt;

&lt;p&gt;We ran &lt;strong&gt;10 independent repeats&lt;/strong&gt; with different seeds, each time running both a ground truth oracle (human labels) and the LLM oracle with the same seed — a direct, controlled comparison.&lt;/p&gt;

&lt;h2&gt;
  
  
  LLM Labels Match Human Accuracy — Within 0.1% Across 10 Runs
&lt;/h2&gt;

&lt;p&gt;Final test accuracies averaged over 10 repeats:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data Labeling Method&lt;/th&gt;
&lt;th&gt;Final Accuracy (mean ± std)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Human annotation (ground truth)&lt;/td&gt;
&lt;td&gt;80.6% ± 1.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LLM annotation (everyrow)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;80.7% ± 0.8%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The LLM oracle is within noise of the ground truth baseline — automated data labeling produces classifiers just as good as human-labeled data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Label Quality: 96% Agreement with Human Annotations
&lt;/h3&gt;

&lt;p&gt;The LLM agreed with ground truth labels &lt;strong&gt;96.1% ± 1.6%&lt;/strong&gt; of the time. Roughly 1 in 25 labels disagrees with the human annotation, but that doesn't hurt the downstream classifier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Labeling Cost: $0.26 per Run
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cost per run (200 labels)&lt;/td&gt;
&lt;td&gt;$0.26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost per labeled item&lt;/td&gt;
&lt;td&gt;$0.0013&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total (10 repeats)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$2.58&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;200 labels in under 5 minutes for $0.26, fully automated. Compare that to hiring human annotators — even at minimum wage, manual labeling of 200 items would take longer and cost more, with no guarantee of higher quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use LLM Data Labeling
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LLM annotation works.&lt;/strong&gt; On this task, the LLM matches human-label performance despite ~4% label disagreement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured outputs matter.&lt;/strong&gt; Pydantic response models guarantee valid labels — no post-hoc parsing or cleanup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's practical.&lt;/strong&gt; 200 labels in under 5 minutes for $0.26, fully automated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;: We tested on one dataset with well-separated categories. More ambiguous labeling tasks may see a gap between human and LLM annotation quality. We used a simple classifier (TF-IDF + LightGBM); neural models that overfit individual examples may be less noise-tolerant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it yourself&lt;/strong&gt;: Get a free API key from &lt;a href="https://everyrow.io/api-key" rel="noopener noreferrer"&gt;everyrow.io&lt;/a&gt; ($20 free credit) and run the &lt;a href="https://www.kaggle.com/code/rafaelpoyiadzi/active-learning-with-an-llm-oracle" rel="noopener noreferrer"&gt;companion notebook&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.kaggle.com/code/rafaelpoyiadzi/active-learning-with-an-llm-oracle" rel="noopener noreferrer"&gt;Companion notebook on Kaggle&lt;/a&gt; — Run the full data labeling pipeline yourself&lt;/li&gt;
&lt;li&gt;Experiment runner code — available on request&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/futuresearch/everyrow-sdk" rel="noopener noreferrer"&gt;everyrow SDK&lt;/a&gt; — Python SDK for running LLM operations over dataframes&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://everyrow.io/docs" rel="noopener noreferrer"&gt;everyrow.io/docs&lt;/a&gt; — Documentation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://everyrow.io/docs/getting-started" rel="noopener noreferrer"&gt;everyrow.io/docs/getting-started&lt;/a&gt; - Getting started&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://everyrow.io/api-key" rel="noopener noreferrer"&gt;everyrow.io/api-key&lt;/a&gt; For API keys ($20 free credit)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://huggingface.co/datasets/fancyzhx/dbpedia_14" rel="noopener noreferrer"&gt;DBpedia-14 dataset&lt;/a&gt; — The dataset used in this study&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dataannotation</category>
      <category>datalabelling</category>
      <category>ai</category>
      <category>datascience</category>
    </item>
    <item>
      <title>Introducing `everyrow.io/dedupe`: An LLM-based approach to semantic deduplication</title>
      <dc:creator>Rafael Poyiadzi</dc:creator>
      <pubDate>Thu, 22 Jan 2026 12:53:02 +0000</pubDate>
      <link>https://dev.to/rafael_poyiadzi_85c2eed09/introducing-everyrowiodedupe-an-llm-based-approach-to-semantic-deduplication-40kl</link>
      <guid>https://dev.to/rafael_poyiadzi_85c2eed09/introducing-everyrowiodedupe-an-llm-based-approach-to-semantic-deduplication-40kl</guid>
      <description>&lt;p&gt;Deduplicating records is a recurring problem in data engineering and several challenges make it difficult: scale, surface-level variation, context-dependent equivalence and world knowledge.&lt;/p&gt;

&lt;p&gt;Let's look at an example. We wanted to build a database of AI researchers from academic lab websites. Scraping produced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name variations&lt;/strong&gt;: "Julie Kallini" vs "J. Kallini", "Moscato, Vincenzo" vs "Vincenzo Moscato"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Typos&lt;/strong&gt;: "Namoi Saphra" vs "Naomi Saphra", "Bryan Wiledr" vs "Bryan Wilder"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Career changes&lt;/strong&gt;: Same person listed at "AUTON Lab" and later at "AUTON Lab (Former)" with different emails&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub handles&lt;/strong&gt;: Sometimes the only reliable link between records—"A. Butoi" and "Alexandra Butoi" sharing &lt;code&gt;butoialexandra&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Username-only names&lt;/strong&gt;: Researchers who listed their GitHub handle ("smirchan", "VSAnimator") instead of their real name&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We used a dataset of 200 researcher profiles scraped from academic lab websites. It was then manually reviewed to establish ground-truth clusters, which we used for evaluation.&lt;/p&gt;

&lt;p&gt;The data covers name, position, organisation, email, university, and GitHub. GitHub handles are present in ~40% of rows and act as a high-precision but low-recall signal.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;row_id&lt;/th&gt;
&lt;th&gt;name&lt;/th&gt;
&lt;th&gt;position&lt;/th&gt;
&lt;th&gt;organisation&lt;/th&gt;
&lt;th&gt;email&lt;/th&gt;
&lt;th&gt;university&lt;/th&gt;
&lt;th&gt;github&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;A. Butoi&lt;/td&gt;
&lt;td&gt;PhD Student&lt;/td&gt;
&lt;td&gt;Rycolab&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:alexandra.butoi@personal.edu"&gt;alexandra.butoi@personal.edu&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;ETH Zurich&lt;/td&gt;
&lt;td&gt;&lt;code&gt;butoialexandra&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Alexandra Butoi&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Ryoclab&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;&lt;code&gt;butoialexandra&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;43&lt;/td&gt;
&lt;td&gt;Namoi Saphra&lt;/td&gt;
&lt;td&gt;Research Fellow&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;nsaphra@alumni&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nsaphra&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;47&lt;/td&gt;
&lt;td&gt;Naomi Saphra&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Harvard / BU / EleutherAI&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:nsaphra@fas.harvard.edu"&gt;nsaphra@fas.harvard.edu&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nsaphra&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;T. Gupta&lt;/td&gt;
&lt;td&gt;PhD Student&lt;/td&gt;
&lt;td&gt;AUTON Lab (Former)&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Carnegie Mellon&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tejus-gupta&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;td&gt;Tejus Gupta&lt;/td&gt;
&lt;td&gt;PhD Student&lt;/td&gt;
&lt;td&gt;AUTON Lab&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:tejusg@cs.cmu.edu"&gt;tejusg@cs.cmu.edu&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Carnegie Mellon&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tejus-gupta&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;55&lt;/td&gt;
&lt;td&gt;smirchan&lt;/td&gt;
&lt;td&gt;PhD Student&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:suvir@yahoo.com"&gt;suvir@yahoo.com&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Stanford University&lt;/td&gt;
&lt;td&gt;&lt;code&gt;smirchan&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;155&lt;/td&gt;
&lt;td&gt;Suvir Mirchandani&lt;/td&gt;
&lt;td&gt;PhD Student&lt;/td&gt;
&lt;td&gt;Stanford CRFM&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:suvir@cs.stanford.edu"&gt;suvir@cs.stanford.edu&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;&lt;code&gt;smirchan&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;98&lt;/td&gt;
&lt;td&gt;Vincenzo Moscato&lt;/td&gt;
&lt;td&gt;Full Professor&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:vincenzo.moscato@unina.it"&gt;vincenzo.moscato@unina.it&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;133&lt;/td&gt;
&lt;td&gt;Moscato, Vincenzo&lt;/td&gt;
&lt;td&gt;Full Professor&lt;/td&gt;
&lt;td&gt;University of Naples&lt;/td&gt;
&lt;td&gt;&lt;a href="mailto:vincenzo.moscato@yahoo.com"&gt;vincenzo.moscato@yahoo.com&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A go-to approach is fuzzy string matching using libraries like &lt;a href="https://github.com/seatgeek/thefuzz" rel="noopener noreferrer"&gt;&lt;code&gt;fuzzywuzzy&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://github.com/rapidfuzz/RapidFuzz" rel="noopener noreferrer"&gt;&lt;code&gt;rapidfuzz&lt;/code&gt;&lt;/a&gt;. However, these suffer from the threshold problem: set it too low and you catch false positives; set it too high and you miss semantic duplicates like "A. Butoi" ↔ "Alexandra Butoi" which have low character overlap despite being the same person. The alternative is manual review, but with 200 rows requiring ~5 comparisons each, that's hours of tedious work.&lt;/p&gt;

&lt;p&gt;We benchmarked fuzzy string matching as a baseline. It compares all row pairs using token-sorted string similarity and groups rows exceeding a threshold using Union-Find clustering (a graph algorithm that efficiently merges items into equivalence classes by treating each match as an edge).&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Fuzzy (t=0.75)&lt;/th&gt;
&lt;th&gt;Fuzzy (t=0.90)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Row accuracy&lt;/td&gt;
&lt;td&gt;86%&lt;/td&gt;
&lt;td&gt;82%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cluster accuracy&lt;/td&gt;
&lt;td&gt;82%&lt;/td&gt;
&lt;td&gt;78%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Easy duplicates&lt;/td&gt;
&lt;td&gt;58% (7/12)&lt;/td&gt;
&lt;td&gt;17% (2/12)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hard duplicates&lt;/td&gt;
&lt;td&gt;70% (7/10)&lt;/td&gt;
&lt;td&gt;10% (1/10)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Distractor accuracy&lt;/td&gt;
&lt;td&gt;90% (18/20)&lt;/td&gt;
&lt;td&gt;100% (20/20)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Singletons&lt;/td&gt;
&lt;td&gt;90% (90/100)&lt;/td&gt;
&lt;td&gt;100% (100/100)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Processing time&lt;/td&gt;
&lt;td&gt;0.04s&lt;/td&gt;
&lt;td&gt;0.04s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At &lt;code&gt;t=0.75&lt;/code&gt; it catches more duplicates but risks false merges. At &lt;code&gt;t=0.90&lt;/code&gt; it avoids false merges but misses most semantic duplicates like "T. Gupta" ↔ "Tejus Gupta".&lt;/p&gt;

&lt;p&gt;We next wanted to try ChatGPT. We upload the CSV and asked it to deduplicate.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;ChatGPT&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Row accuracy&lt;/td&gt;
&lt;td&gt;56%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cluster accuracy&lt;/td&gt;
&lt;td&gt;45% (72/160)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Easy duplicates&lt;/td&gt;
&lt;td&gt;100% (12/12)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hard duplicates&lt;/td&gt;
&lt;td&gt;70% (7/10)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Distractor accuracy&lt;/td&gt;
&lt;td&gt;25% (5/20)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Singletons&lt;/td&gt;
&lt;td&gt;33% (33/100)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output rows&lt;/td&gt;
&lt;td&gt;72&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data loss (over-merged)&lt;/td&gt;
&lt;td&gt;88 clusters&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ChatGPT over-merged:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;88 clusters lost&lt;/strong&gt; — unique people incorrectly merged into other records&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only 33% of singletons preserved&lt;/strong&gt; — people with no duplicates were merged into unrelated records&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only 25% distractor accuracy&lt;/strong&gt; — people with the same first name but different identities (like "Rohan Saha" and "Rohan Chandra") were incorrectly merged&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's now present &lt;code&gt;everyrow.io/dedupe&lt;/code&gt;! Instead of relying on string similarity thresholds, it uses LLMs to make contextual judgments about whether two records represent the same entity.&lt;/p&gt;

&lt;p&gt;The system exposes a high-level deduplication operation that accepts a dataset and a natural-language equivalence definition. The equivalence relation can be as descriptive as needed and could also include examples.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;everyrow&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;create_session&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;everyrow.ops&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dedupe&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="n"&gt;input_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;researchers.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;create_client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;create_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Researcher Dedupe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;dedupe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;input_df&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;equivalence_relation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Two rows are duplicates if they represent the same person &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;despite different email/organization (career changes). &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Consider name variations like typos, nicknames (Robert/Bob), &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;and format differences (John Smith/J. Smith).&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deduplicated.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Accuracy was evaluated by comparing predicted equivalence classes against manually labeled ground truth. We report both row-level accuracy (whether a row is assigned to the correct cluster) and cluster-level accuracy (whether an entire entity cluster is correctly reconstructed).&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Fuzzy (t=0.75)&lt;/th&gt;
&lt;th&gt;Fuzzy (t=0.90)&lt;/th&gt;
&lt;th&gt;ChatGPT&lt;/th&gt;
&lt;th&gt;everyrow.io/dedupe&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Row accuracy&lt;/td&gt;
&lt;td&gt;86%&lt;/td&gt;
&lt;td&gt;82%&lt;/td&gt;
&lt;td&gt;56%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;98%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cluster accuracy&lt;/td&gt;
&lt;td&gt;82%&lt;/td&gt;
&lt;td&gt;78%&lt;/td&gt;
&lt;td&gt;45%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;97.5%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Easy duplicates&lt;/td&gt;
&lt;td&gt;58% (7/12)&lt;/td&gt;
&lt;td&gt;17% (2/12)&lt;/td&gt;
&lt;td&gt;100% (12/12)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100% (12/12)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hard duplicates&lt;/td&gt;
&lt;td&gt;70% (7/10)&lt;/td&gt;
&lt;td&gt;10% (1/10)&lt;/td&gt;
&lt;td&gt;70% (7/10)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100% (10/10)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Distractor accuracy&lt;/td&gt;
&lt;td&gt;90% (18/20)&lt;/td&gt;
&lt;td&gt;100% (20/20)&lt;/td&gt;
&lt;td&gt;25% (5/20)&lt;/td&gt;
&lt;td&gt;95% (19/20)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Singletons&lt;/td&gt;
&lt;td&gt;90% (90/100)&lt;/td&gt;
&lt;td&gt;100% (100/100)&lt;/td&gt;
&lt;td&gt;33% (33/100)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100% (100/100)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Processing time&lt;/td&gt;
&lt;td&gt;0.04s&lt;/td&gt;
&lt;td&gt;0.04s&lt;/td&gt;
&lt;td&gt;NA&lt;/td&gt;
&lt;td&gt;90s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;NA&lt;/td&gt;
&lt;td&gt;$0.42&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A few examples from &lt;code&gt;everyrow.io/dedupe&lt;/code&gt;. Starting with some found matches:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✓ Match: Name abbreviation + org typo&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Row 2:&lt;/strong&gt; "A. Butoi" — Rycolab, ETH Zurich, &lt;code&gt;butoialexandra&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Row 8:&lt;/strong&gt; "Alexandra Butoi" — Ryoclab (typo), &lt;code&gt;butoialexandra&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;✓ Match: Typo in first name&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Row 43:&lt;/strong&gt; "Namoi Saphra" — &lt;code&gt;nsaphra&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Row 47:&lt;/strong&gt; "Naomi Saphra" — Harvard/BU/EleutherAI, &lt;code&gt;nsaphra&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;✓ Match: Career transition&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Row 18:&lt;/strong&gt; "T. Gupta" — AUTON Lab (Former), &lt;code&gt;tejus-gupta&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Row 26:&lt;/strong&gt; "Tejus Gupta" — AUTON Lab, &lt;code&gt;tejus-gupta&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;✓ Match: Username-only name&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Row 55:&lt;/strong&gt; "smirchan" — Stanford University, &lt;code&gt;smirchan&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Row 155:&lt;/strong&gt; "Suvir Mirchandani" — Stanford CRFM, &lt;code&gt;smirchan&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;✗ Correctly identified as different people:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Row 6:&lt;/strong&gt; "Rohan Saha" — Alberta, &lt;code&gt;simpleParadox&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Row 141:&lt;/strong&gt; "Rohan Chandra" — UT Austin, &lt;code&gt;rohanchandra30&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the errors made:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠ Over-merged: Same institution&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Sarah Ball" and "Wen (Lavine) Lai" — both at MCML, PhD students&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;⚠ Over-merged: Co-authors&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Marwa Abdulhai" and "Tejus Gupta" — they co-authored a paper&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;⚠ Over-merged: Co-authors + username names&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Suvir Mirchandani", "Igor Oliveira", and "Vishnu Sarukkai" — all three co-authored the same paper; username-only names made disambiguation harder&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;The system implements a multi-stage deduplication pipeline designed to reduce pairwise comparisons while preserving semantic recall.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Semantic Item Comparison&lt;/strong&gt;: Each row is compared against others using an LLM that understands context—recognising that "A. Butoi" and "Alexandra Butoi" are likely the same person, or that "BAIR Lab (Former)" indicates a career transition rather than a different organisation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Association Matrix Construction&lt;/strong&gt;: Pairwise comparison results are assembled into a matrix of match/no-match decisions. To scale efficiently, items are first clustered by embedding similarity, so only semantically similar items are compared.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Equivalence Class Creation&lt;/strong&gt;: Connected components in the association graph form equivalence classes. If A matches B and B matches C, then A, B, and C form a single cluster representing one entity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Validation&lt;/strong&gt;: Each multi-member cluster is re-evaluated to catch false positives—cases where the initial comparison was too aggressive. Validation is necessary to mitigate error propagation introduced by transitive closure in the association graph.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Candidate Selection&lt;/strong&gt;: For each equivalence class, the most complete/canonical record is selected as the representative (e.g., preferring "Alexandra Butoi" over "A. Butoi").&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The tradeoff: fuzzy matching is 2000x faster and free, but has a 12-16% accuracy gap. For datasets where false merges are costly, the LLM-based approach may be worth the additional runtime and cost.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;98% row-level accuracy&lt;/strong&gt; on a dataset with conflicting signals&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;90 seconds processing time&lt;/strong&gt; and &lt;strong&gt;$0.42 LLM cost&lt;/strong&gt; for 200 records&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;4 false positive clusters&lt;/strong&gt; due to co-authorship signals and shared institution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach is most appropriate when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Semantic judgment is required&lt;/strong&gt;: Name variations, abbreviations, nicknames&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conflicting signals exist&lt;/strong&gt;: Same person with different emails/organisations over time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No single reliable key&lt;/strong&gt;: Can't rely on email or ID alone&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use it yourself!
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Obtain an API key at &lt;a href="https://everyrow.io" rel="noopener noreferrer"&gt;everyrow.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Install the SDK: &lt;code&gt;uv pip install everyrow&lt;/code&gt; or visit the github page: &lt;a href="https://github.com/futuresearch/everyrow-sdk" rel="noopener noreferrer"&gt;https://github.com/futuresearch/everyrow-sdk&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Define your equivalence relation in natural language&lt;/li&gt;
&lt;li&gt;Compare results against your ground-truth labels&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>data</category>
      <category>dataengineering</category>
      <category>llm</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
