<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Text-Processing on Max Halford</title><link>https://maxhalford.github.io/tags/text-processing/</link><description>Recent content in Text-Processing on Max Halford</description><generator>Hugo</generator><language>en-US</language><managingEditor>maxhalford25@gmail.com (Max Halford)</managingEditor><webMaster>maxhalford25@gmail.com (Max Halford)</webMaster><lastBuildDate>Tue, 21 Jul 2026 21:18:41 +0200</lastBuildDate><atom:link href="https://maxhalford.github.io/tags/text-processing/index.xml" rel="self" type="application/rss+xml"/><item><title>Text classification with Python 3.14's zstd module</title><link>https://maxhalford.github.io/blog/text-classification-zstd/</link><pubDate>Fri, 06 Feb 2026 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/text-classification-zstd/</guid><description>&lt;p&gt;Python 3.14 &lt;a href="https://docs.python.org/3/whatsnew/3.14.html#whatsnew314-zstandard"&gt;introduced&lt;/a&gt; the &lt;a href="https://docs.python.org/3/library/compression.zstd.html"&gt;&lt;code&gt;compression.zstd&lt;/code&gt;&lt;/a&gt; module. It is a standard library implementation of Facebook&amp;rsquo;s &lt;a href="https://en.wikipedia.org/wiki/Zstd"&gt;Zstandard (Zstd)&lt;/a&gt; compression algorithm. It was developed a decade ago by Yann Collet, who holds a &lt;a href="https://fastcompression.blogspot.com/"&gt;blog&lt;/a&gt; devoted to compression algorithms.&lt;/p&gt;
&lt;p&gt;I am not a compression expert, but Zstd caught my eye because it supports incremental compression. You can feed it data to compress in chunks, and it will maintain an internal state. It&amp;rsquo;s particularly well &lt;a href="https://facebook.github.io/zstd/"&gt;suited&lt;/a&gt; for compressing small data. It&amp;rsquo;s perfect for the classify text via compression trick, which I described in &lt;a href="https://maxhalford.github.io/blog/text-classification-by-compression/"&gt;a previous blog post&lt;/a&gt; 5 years ago.&lt;/p&gt;</description></item><item><title>Parsing garment descriptions with GPT-3</title><link>https://maxhalford.github.io/blog/garment-parsing-gpt3/</link><pubDate>Sun, 20 Nov 2022 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/garment-parsing-gpt3/</guid><description>&lt;h2 id="the-task"&gt;The task&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll have heard of GPT-3 if you haven&amp;rsquo;t been hiding under a rock. I&amp;rsquo;ve recently been impressed by Nat Friedman &lt;a href="https://twitter.com/natfriedman/status/1575631194032549888"&gt;teaching&lt;/a&gt; GPT-3 to use a browser, and SeekWell &lt;a href="https://blog.seekwell.io/gpt3"&gt;generating&lt;/a&gt; SQL queries from free-text. I think the most exciting usecases are yet to come. But GPT-3 has a good chance of changing the way we approach mundane tasks at work.&lt;/p&gt;
&lt;p&gt;I wrote an &lt;a href="https://maxhalford.github.io/blog/carbonfact-nlp-open-problem"&gt;article&lt;/a&gt; a couple of months ago about a boring task I have to do at work. I got a few interesting suggestions by email. Raphaël suggested a &lt;a href="https://huggingface.co/tasks/question-answering"&gt;question-answering&lt;/a&gt; model &lt;a href="https://raphaelsty.github.io/blog/qa/"&gt;here&lt;/a&gt;. I&amp;rsquo;ve slowly become convinced that GPT-3 might be the perfect tool for the job. It&amp;rsquo;s cold and miserable where I am, so I thought it would be opportune to take GPT-3 for a spin 🧙&lt;/p&gt;</description></item><item><title>NLP at Carbonfact: how would you do it?</title><link>https://maxhalford.github.io/blog/carbonfact-nlp-open-problem/</link><pubDate>Tue, 06 Sep 2022 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/carbonfact-nlp-open-problem/</guid><description>&lt;h2 id="the-task"&gt;The task&lt;/h2&gt;
&lt;p&gt;I work at a company called &lt;a href="https://www.carbonfact.com/"&gt;Carbonfact&lt;/a&gt;. Our core value proposal is computing the &lt;a href="https://en.wikipedia.org/wiki/Carbon_footprint"&gt;carbon footprint&lt;/a&gt; of clothing items, expressed in &lt;a href="https://en.wikipedia.org/wiki/Carbon_Dioxide_Equivalent"&gt;carbon dioxide equivalent&lt;/a&gt; &amp;ndash; $kgCO_2e$ in short. For instance, we started by measuring the footprint of shoes &amp;ndash; no pun intended. We do these measurements with &lt;a href="https://en.wikipedia.org/wiki/Life-cycle_assessment"&gt;life cycle analysis (LCA)&lt;/a&gt; software we built ourselves. We use these analyses to fuel higher-level tasks for our clients, such as &lt;a href="https://en.wikipedia.org/wiki/Carbon_accounting"&gt;carbon accounting&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Sustainable_procurement"&gt;sustainable procurement&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A life cycle analysis is essentially a recipe, the output of which is a carbon footprint assessment. Like any recipe, an LCA necessitates ingredients. In a &lt;a href="https://en.wikipedia.org/wiki/Life-cycle_assessment#/Cradle-to-gate"&gt;cradle-to-gate&lt;/a&gt; scenario, this includes everything that is needed to make the product: the materials, the mass, the manufacturing methods, the transport between factories, etc. In our experience, the biggest impact on a product&amp;rsquo;s footprint come from the materials which it is made of.&lt;/p&gt;</description></item><item><title>Fuzzy regex matching in Python</title><link>https://maxhalford.github.io/blog/fuzzy-regex-matching-in-python/</link><pubDate>Mon, 04 Apr 2022 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/fuzzy-regex-matching-in-python/</guid><description>&lt;h2 id="fuzzy-string-matching-in-a-nutshell"&gt;Fuzzy string matching in a nutshell&lt;/h2&gt;
&lt;p&gt;Say we&amp;rsquo;re looking for a pattern in a blob of text. If you know the text has no typos, then determining whether it contains a pattern is trivial. In Python you can use the &lt;code&gt;in&lt;/code&gt; function. You can also write a regex pattern with the &lt;code&gt;re&lt;/code&gt; module from the standard library. But what about if the text contains typos? For instance, this might be the case with user inputs on a website, or with OCR outputs. This is a much harder problem.&lt;/p&gt;</description></item><item><title>OCR spelling correction is hard</title><link>https://maxhalford.github.io/blog/ocr-spelling-correction-is-hard/</link><pubDate>Sun, 06 Mar 2022 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/ocr-spelling-correction-is-hard/</guid><description>&lt;p&gt;I recently saw &lt;a href="https://news.ycombinator.com/item?id=30576435"&gt;SymSpell&lt;/a&gt; pop up on Hackernews. It claims to be a million times faster than &lt;a href="https://norvig.com/spell-correct.html"&gt;Peter Norvig&amp;rsquo;s spelling corrector&lt;/a&gt;. I think it&amp;rsquo;s great that there&amp;rsquo;s a fast open source solution for spelling correction. But in my experience, the most challenging aspect of spelling correction is not necessarily speed.&lt;/p&gt;
&lt;p&gt;When I &lt;a href="https://maxhalford.github.io/blog/one-year-at-alan"&gt;worked at Alan&lt;/a&gt;, I mostly wrote logic to extract structured information from medical documents. After some months working on the topic, I have to admit I hadn&amp;rsquo;t cracked the problem. The goal was to process &amp;gt;80% of documents with no human interaction, but when I left we had only reached 35%. However, I developed a good understanding of what made this task so difficult.&lt;/p&gt;</description></item><item><title>Homoglyphs: different characters that look identical</title><link>https://maxhalford.github.io/blog/homoglyphs/</link><pubDate>Thu, 19 Aug 2021 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/homoglyphs/</guid><description>&lt;h2 id="a-wild-homoglyph-appears"&gt;A wild homoglyph appears&lt;/h2&gt;
&lt;p&gt;For instance, can you tell if there&amp;rsquo;s a difference between &lt;code&gt;H&lt;/code&gt; and &lt;code&gt;Η&lt;/code&gt;? How about &lt;code&gt;N&lt;/code&gt; and &lt;code&gt;Ν&lt;/code&gt;? These characters may seem identical, but they are actually different. You can try this out for yourself in Python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;H&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Η&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;N&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Ν&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Indeed, these all represent different Unicode characters:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;H&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Η&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;919&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;N&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;ord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Ν&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;78&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;925&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Η&lt;/code&gt; in fact represents the capital &lt;a href="https://en.wikipedia.org/wiki/Eta"&gt;Eta&lt;/a&gt; letter, while &lt;code&gt;Ν&lt;/code&gt; is a capital &lt;a href="https://en.wikipedia.org/wiki/Nu_(letter)"&gt;Nu&lt;/a&gt;. In fact, entering &lt;code&gt;H&lt;/code&gt; or &lt;code&gt;Η&lt;/code&gt; in Google will produce different results. The same goes for &lt;code&gt;N&lt;/code&gt; and &lt;code&gt;Ν&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Automated document processing at Alan</title><link>https://maxhalford.github.io/blog/medium-document-processing/</link><pubDate>Thu, 10 Jun 2021 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/medium-document-processing/</guid><description/></item><item><title>Text classification by data compression</title><link>https://maxhalford.github.io/blog/text-classification-by-compression/</link><pubDate>Tue, 08 Jun 2021 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/text-classification-by-compression/</guid><description>&lt;p&gt;&lt;strong&gt;Edit&lt;/strong&gt; &amp;ndash; &lt;em&gt;I posted this &lt;a href="https://news.ycombinator.com/item?id=27440093"&gt;on Hackernews&lt;/a&gt; and got some valuable feedback. Many brought up the fact that you should be able to reuse the internal state of the compressor instead of recompressing the training data each time a prediction is made. There&amp;rsquo;s also some insightful references to data compression theory and its ties to statistical learning&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edit (2025-06-29)&lt;/strong&gt; &amp;ndash; *Python 3.14 introduces &lt;a href="https://docs.python.org/3/library/compression.zstd.html#compression.zstd.train_dict"&gt;&lt;code&gt;compression.zstd&lt;/code&gt;&lt;/a&gt;, which implement&amp;rsquo;s Facebook&amp;rsquo;s Zstandard compression algorithm, as discussed in the comments section below.&lt;/p&gt;</description></item><item><title>Reducing the memory footprint of a scikit-learn text classifier</title><link>https://maxhalford.github.io/blog/sklearn-text-classifier-memory-footprint-reduction/</link><pubDate>Sun, 11 Apr 2021 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/sklearn-text-classifier-memory-footprint-reduction/</guid><description>&lt;h2 id="context"&gt;Context&lt;/h2&gt;
&lt;p&gt;This week at Alan I&amp;rsquo;ve been working on parsing &lt;a href="https://www.wikiwand.com/fr/Ordonnance_(m%C3%A9decine)"&gt;French medical prescriptions&lt;/a&gt;. There are three types of prescriptions: lenses, glasses, and pharmaceutical prescriptions. Different information needs to be extracted depending on the prescription type. Therefore, the first step is to classify the prescription. The prescriptions we receive are pictures taken by users with their phone. We run each image through an OCR to obtain a text transcription of the image. We can thus use the text transcription to classify the prescription.&lt;/p&gt;</description></item><item><title>Converting Amazon Textract tables to pandas DataFrames</title><link>https://maxhalford.github.io/blog/textract-table-to-pandas/</link><pubDate>Thu, 14 Jan 2021 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/textract-table-to-pandas/</guid><description>&lt;p&gt;I&amp;rsquo;m currently doing a lot of document processing at work. One of my tasks is to extract tables from PDF files. I evaluated &lt;a href="https://aws.amazon.com/textract/?nc1=h_ls"&gt;Amazon Textract&lt;/a&gt;&amp;rsquo;s &lt;a href="https://docs.aws.amazon.com/textract/latest/dg/how-it-works-tables.html"&gt;table extraction&lt;/a&gt; capability as part of this task. It&amp;rsquo;s very well documented, as is the rest of Textract. I was slightly disappointed by &lt;a href="https://docs.aws.amazon.com/textract/latest/dg/examples-blocks.html"&gt;the examples&lt;/a&gt;, but nothing serious.&lt;/p&gt;
&lt;p&gt;I wanted to write this short blog post to share a piece of code I use to convert tables extracted through Amazon Textract to &lt;a href="https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html"&gt;&lt;code&gt;pandas.DataFrame&lt;/code&gt;&lt;/a&gt;s. I&amp;rsquo;ll be using the following anonymised image as an example:&lt;/p&gt;</description></item><item><title>Unsupervised text classification with word embeddings</title><link>https://maxhalford.github.io/blog/unsupervised-text-classification/</link><pubDate>Sat, 03 Oct 2020 00:00:00 +0000</pubDate><author>maxhalford25@gmail.com (Max Halford)</author><guid>https://maxhalford.github.io/blog/unsupervised-text-classification/</guid><description>&lt;div align="center" &gt;
 &lt;img height="300px" src="https://maxhalford.github.io/img/blog/document-classification/morpheus.jpg" alt="morpheus"&gt;
 &lt;br&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Edit&lt;/strong&gt; &amp;ndash; &lt;em&gt;since writing this article, I have discovered that the method I describe is a form of &lt;a href="https://en.wikipedia.org/wiki/Zero-shot_learning"&gt;zero-shot learning&lt;/a&gt;. So I guess you could say that this article is a tutorial on zero-shot learning for NLP.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edit&lt;/strong&gt; &amp;ndash; &lt;em&gt;I stumbled on a &lt;a href="https://www.aclweb.org/anthology/P19-1036/"&gt;paper&lt;/a&gt; entitled &amp;ldquo;Towards Unsupervised Text Classification Leveraging Experts and Word Embeddings&amp;rdquo; which proposes something very similar. The paper is rather well written, so you might want to check it out. Note that they call the &lt;code&gt;tech -&amp;gt; technology&lt;/code&gt; trick &amp;ldquo;label enrichment&amp;rdquo;.&lt;/em&gt;&lt;/p&gt;</description></item></channel></rss>