Natural Language Processing
Natürliche Sprachverarbeitung (Natural Language Processing, NLP) ist ein interdisziplinäres Forschungsfeld, das sich mit der Wechselwirkung zwischen Computern und menschlicher Sprache befasst. Das Hauptziel von NLP ist es, Computern die Fähigkeit zu verleihen, menschliche Sprache in all ihren Nuancen zu verstehen, zu interpretieren und darauf zu reagieren. Dies beinhaltet nicht nur die Erkennung von Wörtern und Grammatik, sondern auch die Analyse von Bedeutung, Kontext und sogar Emotionen, die in der menschlichen Sprache enthalten sein können.
NLP nutzt Methoden aus verschiedenen Bereichen wie Linguistik, Informatik und künstliche Intelligenz, um Modelle und Algorithmen zu entwickeln, die es Computern ermöglichen, natürliche Sprache effektiv zu verarbeiten. Zu den grundlegenden Aufgaben von NLP gehören die Textklassifikation, Named Entity Recognition (NER), maschinelles Übersetzen, Textgenerierung und Sentimentanalyse.
Text Processing
Im ersten Schritt der Natural Language Processing muss der Text so bearbeitet werden, dass Merkmale (Wörter, Features) des Textes von der Maschine besser verarbeitet werden können.
-
Reinigung Der erste Schritt in der Textverarbeitungspipeline beinhaltet die Reinigung des Texts, um unnötige Zeichen, Symbole oder Formatierungen zu entfernen. Dies erleichtert die folgenden Verarbeitungsschritte und verbessert die Konsistenz der Daten.
-
Normalisierung Normalisierung beinhaltet die Umwandlung von Text in eine einheitliche Form, z.B. die Umwandlung von Groß- und Kleinschreibung oder die Entfernung von Akzenten. Dies stellt sicher, dass der Text konsistent und vergleichbar ist.
-
Tokenisierung Tokenisierung teilt den Text in einzelne Wörter oder Token auf. Jedes Token repräsentiert eine bedeutungsvolle Einheit, was die spätere Analyse erleichtert.
-
Stoppwörter entfernen Stoppwörter wie “und”, “oder” oder “das” tragen oft wenig zur Bedeutung bei und werden entfernt, um den Fokus auf relevantere Inhalte zu legen.
-
Part of Speech Tagging (POS) In diesem Schritt werden den einzelnen Wörtern grammatische Kategorien zugeordnet, wie Substantive, Verben oder Adjektive. Dies hilft bei der Analyse der syntaktischen Struktur.
-
Named Entity Recognition (NER) Benannte Entitäten wie Personen, Orte oder Organisationen werden identifiziert und markiert, um wichtige Informationen im Text zu extrahieren.
-
Stemming und Lemmatisierung Der letzte Schritt ist das Stemming (fortgeschrittener: Lemmatisierung (mit Wörterbuch)), bei dem Wörter auf ihren Stamm zurückgeführt werden. Dies hilft, Varianten eines Wortes zu vereinheitlichen und die Analyse zu erleichtern.
Normalisierung
Als Normalisierung bezeichnet man die Konvertierung von Text in Kleinbuchstaben. Dies ist in den meisten Fällen der Textverarbeitung sinnvoll, muss jedoch nicht unbedingt geschehen. Außerdem kann auch die Entfernung der Satzzeichen unter der Normalisierung erfolgen.
## Konvertierung in Kleinbuchstabendf = pd.DataFrame({'tweets': [col.lower() for col in ['I am a dog', 'I am a cat', 'I am a fish']]}).
## Entfernung der Satzzeichenimport redf.tweets = [re.sub("[^a-z0-9 .]", '', col) for col in df.tweets]
Tokenisierung
Als Tokenisierung bezeichnet man die Aufteilung eines Textes in einzelne Wörter. Diese Wörter werden als Tokens bezeichnet.
import spacynlp = spacy.load("de_core_news_sm") ## en_core_web_smdoc = nlp("Steve Jobs, CEO von Apple, erwägt den Kauf eines österreichischen Startups um 6 Mio. Euro.")
for token in doc: print(f"{token.text:{20}}", f"{token.pos_:{10}}", f"{token.ent_type_:{10}}", f"{str(token.is_stop):{10}}", f"{token.lemma_:{20}}")
Text POS ENT_TYPE IS_STOP Lemma--------------------------------------------------------------------------Steve PROPN PER False SteveJobs PROPN PER False Jobs, PUNCT False --CEO PROPN False CEOvon ADP True vonApple PROPN ORG False Apple, PUNCT False --erwägt VERB False erwägenden DET True derKauf NOUN False Kaufeines DET True einösterreichischen ADJ MISC False österreichischStartups NOUN False Startupum ADP True um6 NUM False 6Mio. NOUN False Mio.Euro NOUN False Euro. PUNCT False --
Stoppwörter entfernen
Vieler Wörter jeder Sprache haben eine geringen Einfluss auf die Aussagekraft eines Textes. Diese Wörter werden als Stoppwörter bezeichnet. Im Normalfall können KI-Modelle besser trainiert werden, wenn die Stoppwörter aus dem Text entfernt werden.
import spacynlp = spacy.load("en_core_web_sm") ## de_core_news_sm
class NLP: def __init__(self, text): self.text = text
def remove_stopwords(self): doc = nlp(self.text) self.text = " ".join([token for token in doc if not token.is_stop]) return self.text
text = "How to develop a chatbot using Python"text = NLP(text).remove_stopwords()print(text) ## develop chatbot Python
Parts of Speech Tagging
Part-of-Speech-Tagging ist eine NLP-Technik, die jedem Wort in einem Text grammatikalische Kategorien zuweist, wie Nomen, Verben oder Adjektive. Diese Markierungen helfen bei der Analyse der Satzstruktur und unterstützen Aufgaben wie Textanalyse und Sentimentanalyse.
import spacynlp = spacy.load("de_core_news_sm") ## en_core_web_smdoc = nlp("Ich habe immer Hunger.")
for token in doc: print(f"{token.text:{20}}", f"{token.pos_:{10}}")
Text POS--------------------------------Ich PRONhabe AUXimmer ADVHunger NOUN. PUNCT
Named Entity Recognition
NER identifiziert und klassifiziert spezifische Entitäten wie Personen, Orte und Organisationen in einem Text. Diese Informationsextraktion ist entscheidend für Anwendungen wie Entitätenverknüpfung und Wissensgraphenaufbau.
import spacynlp = spacy.load("de_core_news_sm") ## en_core_web_smdoc = nlp("Marie Curie besuchte das Louvre-Museum in Paris.")
for token in doc: print(f"{token.text:{20}}", f"{token.ent_type_:{10}}")
Text ENT_TYPE--------------------------------Marie PERCurie PERbesuchtedasLouvre-Museum LOCinParis LOC.
Stemming & Lemmatisierung
Stemming und Lemmatisierung sind Techniken zur Textnormalisierung in der NLP. Sie reduzieren Wörter auf ihre Basisformen (Stammwörter), was die Effizienz von Such- und Klassifikationsalgorithmen verbessert. Lemmatisierung hat hierbei den Vorteil gegenüber Stemming, ein Wörterbuch zu verwenden, das die Wortformen auf ihre Stammebene normalisiert.
import spacynlp = spacy.load("de_core_news_sm") ## en_core_web_smdoc = nlp("Michael Jordan erwägt den Kauf eines Autos.")
for token in doc: print(f"{token.text:{20}}", f"{token.lemma_:{20}}")
Text Lemma------------------------------------------Michael MichaelJordan Jordanerwägt erwägenden derKauf Kaufeines einAutos Auto. --
Feature Engineering
Machine Learning Algorithmen können mit Text nicht viel anfangen. Diese bevorzugen numerische Eingaben. Besteht nun die Notwendigkeit, Text zu verarbeiten, ist dessen Umwandlung in eine numerische Darstellungsform unumgänglich. Dieser Vorgang ist Teil des sogenannten Feature Engineerings
. Unter Feature Engineering bei Texten versteht man den Prozess der Auswahl, Erstellung und Transformation von Merkmalen (Features).
Methoden zur Umwandlung von Text in numerische Darstellungen sind beispielsweise One-Hot Encoding
, N-Gramme
und TF-IDF
(Term Frequency-Inverse Document Frequency). N-Gramme werden oft in leichtgewichtigen Shallow-Learning-Modellen wie Random Forest und logistischer Regression verwendet. TF-IDF hingegen finden eher Anwendung in Deep Learning Modellen.
One-Hot Encoding
One-Hot Encoding ist eine Methode, bei der jedes Wort in einem Text in eine binäre Vektorform umgewandelt wird. Jedes Wort wird durch eine Spalte repräsentiert, und wenn das Wort im Text vorkommt, wird die entsprechende Spalte auf 1 gesetzt, sonst auf 0.
import spacyfrom sklearn.feature_extraction.text import CountVectorizernlp = spacy.load('en_core_web_sm') ## de_core_news_sm
text="Jim loves NLP. He will learn NLP in two monts. NLP is Jim's future."
def get_spacy_tokens(text): doc = nlp(text) return [token.text for token in doc]text_tokens = get_spacy_tokens(text)vectorizer = CountVectorizer(tokenizer=get_spacy_tokens, lowercase=False, token_pattern=None)
vectorizer.fit(text_tokens)print("Vocabulary:\n", vectorizer.vocabulary_)
vector = vectorizer.transform(text_tokens)print("Encoded Document is:\n", vector.toarray())
Vocabulary: {'Jim': 3, 'loves': 9, 'NLP': 4, '.': 1, 'He': 2, 'will': 12, 'learn': 8, 'in': 6, 'two': 11, 'monts': 10, 'is': 7, "'s": 0, 'future': 5}Encoded Document is: [[0 0 0 1 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 1 0 0 0] [0 0 0 0 1 0 0 0 0 0 0 0 0] [0 1 0 0 0 0 0 0 0 0 0 0 0] [0 0 1 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 1] [0 0 0 0 0 0 0 0 1 0 0 0 0] [0 0 0 0 1 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 1 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 1 0] [0 0 0 0 0 0 0 0 0 0 1 0 0] [0 1 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 1 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 1 0 0 0 0 0] [0 0 0 1 0 0 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 1 0 0 0 0 0 0 0] [0 1 0 0 0 0 0 0 0 0 0 0 0]]
mit Pandas
Mittels der verwirrend benannten Methode get_dummies()
kann man One-Hot Encoding auch mit Pandas durchführen.
produkt_id,kategorie1,Elektronik2,Kleidung3,Bücher4,Elektronik5,Elektronik6,Bücher7,Kleidung8,Bücher9,Elektronik10,Kleidung11,Bücher12,Elektronik13,Bücher14,Elektronik15,Kleidung16,Kleidung
import pandas as pddf = pd.read_csv('products.csv')df = pd.get_dummies(df, columns=["kategorie"], dtype=int)df.columns = map(str.lower, df.columns)print(df)
produkt_id kategorie_bücher kategorie_elektronik kategorie_kleidung0 1 0 1 01 2 0 0 12 3 1 0 03 4 0 1 04 5 0 1 05 6 1 0 06 7 0 0 17 8 1 0 08 9 0 1 09 10 0 0 110 11 1 0 011 12 0 1 012 13 1 0 013 14 0 1 014 15 0 0 115 16 0 0 1
Bag-of-words (BOW)
Die Bag of Words
(BoW) ist eine häufig verwendete Methode in der Textverarbeitung und maschinellen Sprachverarbeitung. Ihr Ansatz ist darauf ausgerichtet, einen Text auf eine Menge von Wörtern zu reduzieren und die Häufigkeit jedes Worts im Text zu zählen, ohne dabei die Reihenfolge der Wörter zu berücksichtigen.
CountVectorizer
Mithilfe des CountVectorizer
kann man ein Vokabular erstellen und die Wörter in einem Text in numerische Vektoren umwandeln.
from sklearn.feature_extraction.text import CountVectorizer
corpus = ["In a charming village, Max, Lisa, and Tim enjoyed life's joys with their pets: Rocky, the lively dog; Whiskers, Lisa's elegant cat; and Charlie, Tim's colorful parrot. Daily, they gathered at the village square, exploring the nearby forest, discovering vibrant birds, wildflowers, and a babbling stream.", "Grateful for adventures, Max, Lisa, and Tim, with Rocky, Whiskers, and Charlie, remained inseparable. Even on rainy days, the trio met indoors. Max brought tea, Lisa had cookies, and Tim shared apples. These gatherings were filled with laughter and camaraderie.", "In a quaint village, Max, Lisa, and Tim enjoyed life's joys with their pets: Rocky, the lively dog; Whiskers, Lisa's elegant cat; and Charlie, Tim's colorful parrot."]
Standardmäßig kann der CountVectorizer
so verwendet werden:
vectorizer = CountVectorizer()vectorizer.fit(corpus)print(vectorizer.get_feature_names_out())## ['adventures' 'and' 'apples' 'at' 'babbling' 'birds' 'brought' 'camaraderie' 'cat' 'charlie' 'charming' 'colorful' 'cookies' 'daily' 'days' 'discovering' 'dog' 'elegant' 'enjoyed' 'even' 'exploring' 'filled' 'for' 'forest' 'gathered' 'gatherings' 'grateful' 'had' 'in' 'indoors' 'inseparable' 'joys' 'laughter' 'life' 'lisa' 'lively' 'max' 'met' 'nearby' 'on' 'parrot' 'pets' 'quaint' 'rainy' 'remained' 'rocky' 'shared' 'square' 'stream' 'tea' 'the' 'their' 'these' 'they' 'tim' 'trio' 'vibrant' 'village' 'were' 'whiskers' 'wildflowers' 'with']
Dabei werden einbuchstabige Wörter wie a
, I
oder Zahlen ignoriert, was mittels token_pattern
geändert werden kann.
vectorizer = CountVectorizer(token_pattern=u'(?u)\\b\\w+\\b')vectorizer.fit(corpus)print(vectorizer.get_feature_names_out())## ['a' 'adventures' 'and' 'apples' 'at' 'babbling' 'birds' 'brought' 'camaraderie' 'cat' 'charlie' 'charming' 'colorful' 'cookies' 'daily' 'days' 'discovering' 'dog' 'elegant' 'enjoyed' 'even' 'exploring' 'filled' 'for' 'forest' 'gathered' 'gatherings' 'grateful' 'had' 'in' 'indoors' 'inseparable' 'joys' 'laughter' 'life' 'lisa' 'lively' 'max' 'met' 'nearby' 'on' 'parrot' 'pets' 'quaint' 'rainy' 'remained' 'rocky' 's' 'shared' 'square' 'stream' 'tea' 'the' 'their' 'these' 'they' 'tim' 'trio' 'vibrant' 'village' 'were' 'whiskers' 'wildflowers' 'with']
Wenn gewisse Wörter gefiltert werden sollen, kann man dies mit stop_words
tun.
vectorizer = CountVectorizer(token_pattern=u'(?u)\\b\\w+\\b', stop_words=['a','and','at','for','had','in','on','the','s','were','with'])vectorizer.fit(corpus)print(vectorizer.get_feature_names_out())## ['adventures' 'apples' 'babbling' 'birds' 'brought' 'camaraderie' 'cat' 'charlie' 'charming' 'colorful' 'cookies' 'daily' 'days' 'discovering' 'dog' 'elegant' 'enjoyed' 'even' 'exploring' 'filled' 'forest' 'gathered' 'gatherings' 'grateful' 'indoors' 'inseparable' 'joys' 'laughter' 'life' 'lisa' 'lively' 'max' 'met' 'nearby' 'parrot' 'pets' 'quaint' 'rainy' 'remained' 'rocky' 'shared' 'square' 'stream' 'tea' 'their' 'these' 'they' 'tim' 'trio' 'vibrant' 'village' 'whiskers' 'wildflowers']
Jedes Vokabel enthält hier nur ein Wort, was bedeutet, dass beispielsweise max lisa tim
nicht gefunden werden kann. Will man dieses Verhalten beeinflussen, kann man mittels ngram_range
die minimale und maximale Wortanzahl festlegen.
vectorizer = CountVectorizer(token_pattern=u'(?u)\\b\\w+\\b', stop_words=['a','and','at','for','had','in','on','the','s','were','with'], ngram_range=(1,3))vectorizer.fit(corpus)print(vectorizer.get_feature_names_out())## ['adventures' 'adventures max' 'adventures max lisa' 'apples' 'apples these' 'apples these gatherings' 'babbling' 'babbling stream' 'birds' 'birds wildflowers' 'birds wildflowers babbling' 'brought' 'brought tea' 'brought tea lisa' 'camaraderie' 'cat' 'cat charlie' 'cat charlie tim' 'charlie' 'charlie remained' 'charlie remained inseparable' 'charlie tim' 'charlie tim colorful' 'charming' 'charming village' 'charming village max' 'colorful' 'colorful parrot' 'colorful parrot daily' 'cookies' 'cookies tim' 'cookies tim shared' 'daily' 'daily they' 'daily they gathered' 'days' 'days trio' 'days trio met' 'discovering' 'discovering vibrant' 'discovering vibrant birds' 'dog' 'dog whiskers' 'dog whiskers lisa' 'elegant' 'elegant cat' 'elegant cat charlie' 'enjoyed' 'enjoyed life' 'enjoyed life joys' 'even' 'even rainy' 'even rainy days' 'exploring' 'exploring nearby' 'exploring nearby forest' 'filled' 'filled laughter' 'filled laughter camaraderie' 'forest' 'forest discovering' 'forest discovering vibrant' 'gathered' 'gathered village' 'gathered village square' 'gatherings' 'gatherings filled' 'gatherings filled laughter' 'grateful' 'grateful adventures' 'grateful adventures max' 'indoors' 'indoors max' 'indoors max brought' 'inseparable' 'inseparable even' 'inseparable even rainy' 'joys' 'joys their' 'joys their pets' 'laughter' 'laughter camaraderie' 'life' 'life joys' 'life joys their' 'lisa' 'lisa cookies' 'lisa cookies tim' 'lisa elegant' 'lisa elegant cat' 'lisa tim' 'lisa tim enjoyed' 'lisa tim rocky' 'lively' 'lively dog' 'lively dog whiskers' 'max' 'max brought' 'max brought tea' 'max lisa' 'max lisa tim' 'met' 'met indoors' 'met indoors max' 'nearby' 'nearby forest' 'nearby forest discovering' 'parrot' 'parrot daily' 'parrot daily they' 'pets' 'pets rocky' 'pets rocky lively' 'quaint' 'quaint village' 'quaint village max' 'rainy' 'rainy days' 'rainy days trio' 'remained' 'remained inseparable' 'remained inseparable even' 'rocky' 'rocky lively' 'rocky lively dog' 'rocky whiskers' 'rocky whiskers charlie' 'shared' 'shared apples' 'shared apples these' 'square' 'square exploring' 'square exploring nearby' 'stream' 'tea' 'tea lisa' 'tea lisa cookies' 'their' 'their pets' 'their pets rocky' 'these' 'these gatherings' 'these gatherings filled' 'they' 'they gathered' 'they gathered village' 'tim' 'tim colorful' 'tim colorful parrot' 'tim enjoyed' 'tim enjoyed life' 'tim rocky' 'tim rocky whiskers' 'tim shared' 'tim shared apples' 'trio' 'trio met' 'trio met indoors' 'vibrant' 'vibrant birds' 'vibrant birds wildflowers' 'village' 'village max' 'village max lisa' 'village square' 'village square exploring' 'whiskers' 'whiskers charlie' 'whiskers charlie remained' 'whiskers lisa' 'whiskers lisa elegant' 'wildflowers' 'wildflowers babbling' 'wildflowers babbling stream']
Will man das Vokabular auf bestimmte Vokabeln begrenzen, kann man dies mit vocabulary
tun.
vectorizer = CountVectorizer(token_pattern=u'(?u)\\b\\w+\\b', stop_words=['a','and','at','for','had','in','on','the','s','were','with'], ngram_range=(1,4), vocabulary=['max lisa tim'])vectorizer.fit(corpus)print(vectorizer.get_feature_names_out())## ['max lisa tim']
Sobald man mit den Features zufrieden ist, kann man sich das Vokabular anzeigen lassen. Dieses ist ein Dictionary, welches jedes Wort einer Zahl zuweist, damit beim Machine Learning Prozess besser damit gearbeitet werden kann. Computer verstehen Nummern besser als Wörter.
print(vectorizer.vocabulary_)## {'charming': 8, 'village': 50, 'max': 31, 'lisa': 29, 'tim': 47, 'enjoyed': 16, 'life': 28, 'joys': 26, 'their': 44, 'pets': 35, 'rocky': 39, 'lively': 30, 'dog': 14, 'whiskers': 51, 'elegant': 15, 'cat': 6, 'charlie': 7, 'colorful': 9, 'parrot': 34, 'daily': 11, 'they': 46, 'gathered': 21, 'square': 41, 'exploring': 18, 'nearby': 33, 'forest': 20, 'discovering': 13, 'vibrant': 49, 'birds': 3, 'wildflowers': 52, 'babbling': 2, 'stream': 42, 'grateful': 23, 'adventures': 0, 'remained': 38, 'inseparable': 25, 'even': 17, 'rainy': 37, 'days': 12, 'trio': 48, 'met': 32, 'indoors': 24, 'brought': 4, 'tea': 43, 'cookies': 10, 'shared': 40, 'apples': 1, 'these': 45, 'gatherings': 22, 'filled': 19, 'laughter': 27, 'camaraderie': 5, 'quaint': 36}
Nun kann man die Features mittels .transform()
in einem Nummern-Matrix umwandeln. Diese sagt aus, welche Vokabeln in den drei Sätzen von corpus
vorkommen. Beispielsweise kommt im ersten Satz das Wort charming
vor, weswegen bei Index 8 die Zahl 1 steht (grün markiert). Kommt ein Wort öfter vor, steht die entsprechende Anzahl an der Stelle. Hierbei ist das Wort lisa
(Index 29) rot markiert, da Lisa im dritten String zweimal vorkommt.
vector = vectorizer.transform(corpus)print(vector.shape) ## (3, 53)print(vector.toarray())## [## [0 0 1 1 0 0 1 1 1 1 0 1 0 1 1 1 1 0 1 0 1 1 0 0 0 0 1 0 1 2 1 1 0 1 1 1 0 0 0 1 0 1 1 0 1 0 1 2 0 1 2 1 1]## [1 1 0 0 1 1 0 1 0 0 1 0 1 0 0 0 0 1 0 1 0 0 1 1 1 1 0 1 0 2 0 2 1 0 0 0 0 1 1 1 1 0 0 1 0 1 0 2 1 0 0 1 0]## [0 0 0 0 0 0 1 1 0 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 1 0 1 2 1 1 0 0 1 1 1 0 0 1 0 0 0 0 1 0 0 2 0 0 1 1 0]## ]
Aha
Falls Sie sich fragen, woher die Zahl 53
bei der Shape kommt: Es gibt 53 unterschiedliche Wörter in den Sätzen von corpus
. Zumindest hat der CountVectorizer die Sätze so tokenisiert. Der Vectorizer verfügt somit über ein Vokabular von 53 Wörtern.
Hinweis
Man kann mithilfe der Methode fit_transform()
die einzelnen Schritte einfach zusammenfassen und gleichzeitig ein Vokabular erlernen und den Text in eine Bag-of-Words
-Darstellung bringen.
vectorizer.fit_transform(["Ich bin cool!"])vectorizer.get_feature_names_out()## array(['bin', 'cool', 'ich'], dtype=object)
Mit dem CountVectorizer
kann man auch die Features in einem Pandas DataFrame anzeigen lassen.
import pandas as pdpd.DataFrame(vector.toarray(), columns=vectorizer.get_feature_names_out())
LabelEncoder
Ein LabelEncoder
nummeriert die verschiedenen Wörter in einem Vokabular. Diese Wörter werden dann in einem Array zusammengefasst.
from sklearn.preprocessing import LabelEncoderle = LabelEncoder()labels = le.fit_transform(['Muffin', 'Donat', 'Donat', 'Donat', 'Muffin', 'Muffin', 'Donat', 'Muffin', 'Donat', 'Muffin'])print(labels) ## [1 0 0 0 1 1 0 1 0 1]