NotesByLex

Text Preprocessing

For classical NLP, there are a number of text preprocessing techniques that are worth knowing.

Tokenisation

Tokenisation is the process of splitting text (or audio - Audio Tokenisation, or images Image Tokenisation) into discrete units called tokens.

Modern tokenisers, like the OpenAI's tiktoken, operate at the subword level, splitting text into small units called token, some of which are individual words, others parts of word, or even single character. In tiktoken's case, the algorithm is called Byte Pair Encoding, which operates across pairs of bytes.

import tiktoken

encoding = tiktoken.get_encoding("cl100k_base")
tokens = encoding.encode("hello world aaaaaaaaaaaa")
print(tokens)
[15339, 1917, 264, 70540, 33746]

for token_id in tokens:
    print(token_id, "->", encoding.decode([token_id]))
15339 -> hello
1917 ->  world
264 ->  a
70540 -> aaaaaaaa
33746 -> aaa

Subword tokenisers are not the only game in town for NLP.

Word Tokenisation

Word tokens, as you might expect, operate at the word limit. That means they're likely limited to a vocbulary, and any word outside of the voculablry might be replaced with a unknown word.

import nltk

tokens = nltk.word_tokenize("Hello world aaaaaaaaaaaa")
print(tokens)
['Hello', 'world', 'aaaaaaaaaaaa']

Sentence Segmentation

Sentence Segmentation is a technique for tokenisation where we split a text into sentences, typically using punctuation as split tokens.

Here's an example from nltk using the punkt_tab

import nltk, pprint
nltk.download("punkt_tab")
... ... ... ... ... ... ... [nltk_data] Downloading package punkt_tab to /Users/lex/nltk_data...
[nltk_data]   Package punkt_tab is already up-to-date!
True

text = """He never even had the makings of a varsity athlete. Your point being what, Junior? Oh, forget it, he's just breaking balls. All right, one thought I had in the interest of harmony, maybe there could be a power-sharing situation.

The Sopranos have two bosses."""
sentences = nltk.tokenize.sent_tokenize(text)
pprint.pprint(sentences)
['He never even had the makings of a varsity athlete.',
 'Your point being what, Junior?',
 "Oh, forget it, he's just breaking balls.",
 'All right, one thought I had in the interest of harmony, maybe there could '
 'be a power-sharing situation.',
 'The Sopranos have two bosses.']

We can see that the sentence tokeniser has split sentences based on punctuation.

Text Normalisation

Once a word has been tokenised, a number of other techniques exist for normalising tokens.

Stemming

Stemming is the process of converting a token like driving into its root form, in a very basic way by simply chopping off the end: driving - > drive. This is useful when using basic word normalisation, as it prevents the model from having to learn a entirely different representation for a very similar word. However, in practice this lack of sophistocation can still mean that similar words end up represented differently.

import nltk

from nltk.stem import PorterStemmer

stemmer = PorterStemmer()
print(stemmer.stem("driving"))
drive

Lemmatisation

Lemmatisation is the process of replacing synatically similar words with the same token. It tends to be a much more sophistocated algorithmn than a stemming algorithm, and often uses surrounding context of a word to determine synoms and such.

Example: "passing" → lemma "pass" + ING (present participle) Example: "were" → "to be" (past tense, second person plural)

In modern generative AI, both stemming and lemmatisation tend not to be used, in favour of a loss-less tokenisation algorithm like BPE, as they can throw away information that can be useful to a model. Although, on smaller NLP datasets trained from scratch, they still make a lot of sense.

import nltk

nltk.download('wordnet')

from nltk.stem import WordNetLemmatizer

lem = WordNetLemmatizer()
print(lem.lemmatize("driving"))
... ... ... ... ... ... ... [nltk_data] Downloading package wordnet to /Users/lex/nltk_data...
[nltk_data]   Package wordnet is already up-to-date!
driving