Falls Sie es noch nicht wussten: Python verfügt über einige unglaublich leistungsstarke Instruments, mit denen Sie Leistung erbringen können Verarbeitung natürlicher Sprache (NLP) auf Textdaten. In diesem Tutorial erfahren Sie, wie Sie mit Python in NLP einsteigen.
Blick auf die Daten
Wir werden mit einem Datensatz arbeiten, der aus Unterlektionen zu besteht Hacker-Information von 2006 bis 2015. Die Daten stammen aus Hier. Arnaud Drizard nutzte die Hacker Information API, um es zu kratzen. Wir haben probiert 10000
Zeilen aus den Daten zufällig ausgewählt und alle überflüssigen Spalten entfernt. Unsere Daten bestehen nur aus vier Spalten:
-
sublesson_time
: als die Geschichte eingereicht wurde. -
url
: die Foundation-URL der Unterlektion. -
upvotes
: Anzahl der Upvotes, die die Unterlektion erhalten hat. -
headline
: die Überschrift der Unterlektion.
Wir werden die Schlagzeilen verwenden, um die Anzahl der Upvotes vorherzusagen. Die Daten werden im gespeichert sublessons
Variable.
Verarbeitung natürlicher Sprache mit Python – Erste Schritte
Wir möchten schließlich einen Algorithmus für maschinelles Lernen trainieren, um eine Überschrift aufzunehmen und uns mitzuteilen, wie viele Upvotes sie erhalten würde. Allerdings verstehen Algorithmen des maschinellen Lernens nur Zahlen, keine Wörter. Wie übersetzen wir unsere Schlagzeilen in etwas, das ein Algorithmus verstehen kann?
Der erste Schritt besteht darin, eine sogenannte Bag-of-Phrases-Matrix zu erstellen. Eine Tüte Wortmatrix gibt uns eine numerische Darstellung, welche Wörter in welchen Schlagzeilen vorkommen. Um eine Bag-of-Wort-Matrix zu erstellen, suchen wir zunächst die eindeutigen Wörter in der gesamten Schlagzeilengruppe. Dann erstellen wir eine Matrix, in der jede Zeile eine Überschrift und jede Spalte eines der eindeutigen Wörter ist. Dann tragen wir in jede Zelle ein, wie oft dieses Wort in dieser Überschrift vorkommt. Dies führt zu einer Matrix, in der viele Zellen den Wert Null haben, es sei denn, das Vokabular wird größtenteils von den Überschriften übernommen.
from collections import Counter
headlines = (
"PretzelBros, airbnb for individuals who like pretzels, raises $2 million",
"High 10 the reason why Go is best than no matter language you utilize.",
"Why working at apple stole my soul (I nonetheless adore it although)",
"80 issues I feel you must do instantly when you use python.",
"Present HN: carjack.me: Uber meets GTA"
)
# Discover all of the distinctive phrases within the headlines.
unique_words = checklist(set(" ".be part of(headlines).break up(" ")))
def make_matrix(headlines, vocab):
matrix = ()
for headline in headlines:
# Depend every phrase within the headline, and make a dictionary.
counter = Counter(headline)
# Flip the dictionary right into a matrix row utilizing the vocab.
row = (counter.get(w, 0) for w in vocab)
matrix.append(row)
df = pandas.DataFrame(matrix)
df.columns = unique_words
return df
print(make_matrix(headlines, unique_words))
. why HN: for folks instantly like I Go 80 meets ... my who
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
2 0 0 0 0 0 0 1 0 0 0 ... 0 0
3 0 0 0 0 0 0 1 0 0 0 ... 0 0
4 0 0 0 0 0 0 0 0 0 0 ... 0 0
PretzelBros, no matter language do $2 nonetheless than soul
0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0 0
(5 rows x 51 columns)
Satzzeichen entfernen
Die Matrix, die wir gerade erstellt haben, ist sehr dünn besetzt – das bedeutet, dass viele Werte Null sind. Dies ist bis zu einem gewissen Grad unvermeidlich, da die Schlagzeilen nicht viel gemeinsames Vokabular enthalten. Wir können jedoch einige Schritte unternehmen, um das Drawback zu beheben. Im Augenblick Why
Und why
Und use
Und use.
werden als unterschiedliche Entitäten behandelt, aber wir wissen, dass sie sich auf dasselbe Wort beziehen. Wir können dem Parser dabei helfen, zu erkennen, dass diese tatsächlich gleich sind, indem wir jedes Wort kleinschreiben und alle Satzzeichen entfernen.
import re
# Lowercase, then substitute any non-letter, area, or digit character within the headlines.
new_headlines = (re.sub(r'(^wsd)','',h.decrease()) for h in headlines)
# Exchange sequences of whitespace with an area character.
new_headlines = (re.sub("s+", " ", h) for h in new_headlines)
unique_words = checklist(set(" ".be part of(new_headlines).break up(" ")))
# We have lowered the variety of columns within the matrix a bit.
print(make_matrix(new_headlines, unique_words))
. 2 why high hn for folks instantly like python 80 ... ought to
0 1 0 0 0 0 0 0 0 0 0 ... 0
1 0 0 0 0 0 0 0 0 0 0 ... 0
2 0 0 0 0 0 0 0 0 0 0 ... 0
3 0 0 0 0 0 0 0 0 0 0 ... 0
4 0 0 0 0 0 0 0 0 0 0 ... 0
my who go no matter language do nonetheless than soul
0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0 0 0
(5 rows x 47 columns)
Stoppwörter entfernen
Bestimmte Wörter helfen Ihnen nicht dabei, zwischen guten und schlechten Schlagzeilen zu unterscheiden. Wörter wie the
, a
Und additionally
kommen in allen Zusammenhängen so häufig vor, dass sie uns nicht wirklich viel darüber verraten, ob etwas intestine ist oder nicht. Im Allgemeinen ist die Wahrscheinlichkeit, dass sie sowohl in guten als auch in schlechten Schlagzeilen auftauchen, gleich groß. Indem wir diese entfernen, können wir die Größe der Matrix reduzieren und das Coaching eines Algorithmus beschleunigen.
# Learn in and break up the stopwords file.
with open("stop_words.txt", 'r') as f:
stopwords = f.learn().break up("n")
# Do the identical punctuation alternative that we did for the headlines, # so we're evaluating the fitting issues.
stopwords = (re.sub(r'(^wsd)','',s.decrease()) for s in stopwords)
unique_words = checklist(set(" ".be part of(new_headlines).break up(" ")))
# Take away stopwords from the vocabulary.unique_words = (w for w in unique_words if w not in stopwords)
# We're all the way down to 34 columns, which is means higher!
print(make_matrix(new_headlines, unique_words))
. 2 high hn folks instantly like python 80 meets pretzels ...
0 1 0 0 0 0 0 0 0 0 0 ...
1 0 0 0 0 0 0 0 0 0 0 ...
2 0 0 0 0 0 0 0 0 0 0 ...
3 0 0 0 0 0 0 0 0 0 0 ...
4 0 0 0 0 0 0 0 0 0 0 ...
gta 10 uber raises pretzelbros go no matter language nonetheless soul
0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0 0 0 0
(5 rows x 34 columns)
Generieren einer Matrix für alle Schlagzeilen
Nachdem wir nun die Grundlagen kennen, können wir eine Wortmatrix für die gesamten Schlagzeilen erstellen. Wir möchten nicht jedes Mal alles manuell codieren müssen, deshalb verwenden wir eine Klasse von scikit-lernen um es automatisch zu tun. Mit der Vektorisierer Von Scikit-Study bis zum Erstellen Ihrer Wortsammlung mit Matrizen wird der Prozess viel einfacher und schneller.
from sklearn.feature_extraction.textual content import CountVectorizer
# Assemble a bag of phrases matrix.
# It will lowercase the whole lot, and ignore all punctuation by default.
# It should additionally take away cease phrases.
vectorizer = CountVectorizer(lowercase=True, stop_words="english")
matrix = vectorizer.fit_transform(headlines)
# We created our bag of phrases matrix with far fewer instructions.
print(matrix.todense())
# Let's apply the identical methodology to all of the headlines in all 100000 sublessons.
# We'll additionally add the url of the sublesson to the top of the headline so we will take it under consideration.
sublessons('full_test') = sublessons("headline") + " " + sublessons("url")
full_matrix = vectorizer.fit_transform(sublessons("headline"))
print(full_matrix.form)
((0 0 1 0 0 0 0 0 0 0 1 0 0 1 1 1 1 0 1 0 0 0 0 0 0 0 0)
(1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0)
(0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1)
(0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 1 0)
(0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0))
(9356, 13631)
Reduzierung der Dimensionalität
Wir haben eine Matrix erstellt, aber jetzt ist sie da 13631
eindeutige Wörter oder Spalten. Es wird sehr lange dauern, damit Vorhersagen zu treffen. Wir wollen es beschleunigen, additionally müssen wir die Spaltenanzahl irgendwie reduzieren. Eine Möglichkeit, dies zu erreichen, besteht darin, eine Teilmenge der Spalten auszuwählen, die am informativsten sind – additionally die Spalten, die am besten zwischen guten und schlechten Schlagzeilen unterscheiden.
Eine gute Möglichkeit, die informativsten Spalten herauszufinden, ist die Verwendung von a Chi-Quadrat prüfen. Ein Chi-Quadrat-Check findet die Wörter, die am meisten zwischen stark positiv bewerteten Posts und Posts, die nicht positiv bewertet wurden, unterscheiden. Dabei kann es sich um Wörter handeln, die in Beiträgen mit hohem Upvote häufig vorkommen, in Posts ohne Upvotes jedoch überhaupt nicht, oder um Wörter, die in Posts mit hohem Upvote häufig, aber nicht in Posts mit Upvote vorkommen. Ein Chi-Quadrat-Check funktioniert nur bei Binärwerten, daher machen wir unsere Upvotes-Spalte binär, indem wir alles mit mehr Upvotes als dem Durchschnitt auf setzen 1
und alles mit weniger Upvotes als der Durchschnitt 0
. Ein Nachteil dabei ist, dass wir Wissen aus dem Datensatz nutzen, um Options auszuwählen, und somit eine gewisse Überanpassung einführen. Wir könnten die Überanpassung in der „realen Welt“ umgehen, indem wir eine Teilmenge der Daten für die Merkmalsauswahl und eine andere Teilmenge für das Coaching des Algorithmus verwenden. Wir machen es vorerst etwas einfacher und überspringen diesen Schritt.
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
# Convert the upvotes variable to binary so it really works with a chi-squared take a look at.
col = sublessons("upvotes").copy(deep=True)
col_mean = col.imply()
col(col < col_mean) = 0
col((col > 0) & (col > col_mean)) = 1
# Discover the 1000 most informative columns
selector = SelectKBest(chi2, ok=1000)
selector.match(full_matrix, col)
top_words = selector.get_support().nonzero()
# Choose solely essentially the most informative columns within the knowledge.
chi_matrix = full_matrix(:,top_words(0))
Wenn wir die „Meta“-Merkmale der Schlagzeilen ignorieren, entgehen uns viele gute Informationen. Zu diesen Merkmalen gehören Dinge wie Länge, Anzahl der Satzzeichen, durchschnittliche Wortlänge und andere satzspezifische Merkmale. Durch das Hinzufügen dieser Elemente kann die Vorhersagegenauigkeit erheblich erhöht werden. Um sie hinzuzufügen, durchlaufen wir unsere Überschriften und wenden auf jede einzelne eine Funktion an. Einige Funktionen zählen die Länge der Überschrift in Zeichen, andere erledigen komplexere Aufgaben, wie z. B. das Zählen der Anzahl der Ziffern.
# Our checklist of capabilities to use.
transform_functions = (
lambda x: len(x),
lambda x: x.depend(" "),
lambda x: x.depend("."),
lambda x: x.depend("!"),
lambda x: x.depend("?"),
lambda x: len(x) / (x.depend(" ") + 1),
lambda x: x.depend(" ") / (x.depend(".") + 1),
lambda x: len(re.findall("d", x)),
lambda x: len(re.findall("(A-Z)", x)),
)
# Apply every operate and put the outcomes into a listing.
columns = ()
for func in transform_functions:
columns.append(sublessons("headline").apply(func))
# Convert the meta options to a numpy array.
meta = numpy.asarray(columns).T
Weitere Funktionen hinzufügen
Es gibt mehr Funktionen, mit denen wir arbeiten können als nur Textfunktionen. Wir haben eine Kolumne namens sublesson_time
das uns sagt, wann eine Geschichte eingereicht wurde, und könnte weitere Informationen hinzufügen. Wenn Sie die Verarbeitung natürlicher Sprache mit Python durchführen, können Sie häufig externe Funktionen hinzufügen, die Ihre Vorhersagen erheblich verbessern. Einige Algorithmen für maschinelles Lernen können herausfinden, wie diese Funktionen mit Ihren Textfunktionen interagieren (z. B. „Ein Beitrag um Mitternacht mit dem Wort „Tacos“ in der Überschrift führt zu einem Beitrag mit hoher Punktzahl“).
columns = ()
# Convert the sublesson dates column to datetime.
sublesson_dates = pandas.to_datetime(sublessons("sublesson_time"))
# Remodel capabilities for the datetime column.
transform_functions = (
lambda x: x.12 months,
lambda x: x.month,
lambda x: x.day,
lambda x: x.hour,
lambda x: x.minute
)
# Apply all capabilities to the datetime column.
for func in transform_functions:
columns.append(sublesson_dates.apply(func))
# Convert the meta options to a numpy array.
non_nlp = numpy.asarray(columns).T
# Concatenate the options collectively.
options = numpy.hstack((non_nlp, meta, chi_matrix.todense()))
Vorhersagen treffen
Da wir nun Wörter in Zahlen übersetzen können, können wir mithilfe eines Algorithmus Vorhersagen treffen. Wir werden nach dem Zufallsprinzip auswählen 7500
Schlagzeilen als Trainingssatz verwenden und dann die Leistung des Algorithmus anhand des Testsatzes bewerten 2500
Schlagzeilen. Die Vorhersage der Ergebnisse auf demselben Satz, auf dem wir trainieren, wird zu Folgendem führen: Überanpassungwenn Ihr Algorithmus übermäßig für den Trainingssatz optimiert ist – wir denken, dass die Fehlerrate intestine ist, aber bei neuen Daten könnte sie tatsächlich viel höher sein. Für den Algorithmus verwenden wir Gratregression. Im Vergleich zur gewöhnlichen linearen Regression führt die Ridge-Regression zu einer Strafe für die Koeffizienten, die verhindert, dass sie zu groß werden. Dies kann dazu beitragen, dass es mit einer großen Anzahl von Prädiktoren (Spalten) funktioniert, die wie bei uns miteinander korreliert sind.
from sklearn.linear_model
import Ridge
import numpy
import random
train_rows = 7500
# Set a seed to get the identical "random" shuffle each time.
random.seed(1)
# Shuffle the indices for the matrix.
indices = checklist(vary(options.form(0)))
random.shuffle(indices)
# Create practice and take a look at units.
practice = options(indices(:train_rows), :)
take a look at = options(indices(train_rows:), :)
train_upvotes = sublessons("upvotes").iloc(indices(:train_rows))
test_upvotes = sublessons("upvotes").iloc(indices(train_rows:))
practice = numpy.nan_to_num(practice)
# Run the regression and generate predictions for the take a look at set.
reg = Ridge(alpha=.1)
reg.match(practice, train_upvotes)
predictions = reg.predict(take a look at)
Bewertung des Fehlers
Wir haben jetzt Vorhersagen, aber wie bestimmen wir, wie intestine sie sind? Eine Möglichkeit besteht darin, die Fehlerrate zwischen den Vorhersagen für den Testsatz und den tatsächlichen Upvote-Zählungen für den Testsatz zu berechnen. Wir möchten auch, dass ein Basel den Fehler vergleicht, um zu sehen, ob die Ergebnisse intestine sind. Wir können dies erreichen, indem wir eine einfache Methode verwenden, um Basisschätzungen für den Testsatz vorzunehmen, und die Fehlerrate unserer Vorhersagen mit der Fehlerrate der Basisschätzungen vergleichen.
Eine sehr einfache Grundlinie besteht darin, die durchschnittliche Anzahl der Upvotes professional Unterlektion im Trainingssatz zu nehmen und diese als Vorhersage für jede Unterlektion zu verwenden. Wir werden verwenden mittlerer absoluter Fehler als Fehlermetrik. Es ist ganz einfach: Subtrahieren Sie einfach den tatsächlichen Wert von der Vorhersage, nehmen Sie den absoluten Wert der Differenz und ermitteln Sie dann den Mittelwert aller Differenzen.
# We will use imply absolute error as an error metric.
# Our error is about 13.6 upvotes, which signifies that, on common,
# our prediction is 13.6 upvotes away from the precise variety of upvotes.
print(sum(abs(predictions - test_upvotes)) / len(predictions))
# As a baseline, we'll use the common variety of upvotes# throughout all sublessons.
# The error right here is 17.2―our estimate is best, however not massively so.
# There both is not a ton of predictive worth encoded within the
# knowledge now we have, or we aren't extracting it nicely.
average_upvotes = sum(test_upvotes)/len(test_upvotes)
print(sum(abs(average_upvotes - test_upvotes)) / len(predictions))
13.6606593988
17.2759421912
Nächste Schritte
Diese Methode funktionierte bei diesem Datensatz einigermaßen, aber nicht besonders intestine. Wir haben festgestellt, dass die Überschriften und anderen Spalten einen gewissen Vorhersagewert haben. Wir könnten diesen Ansatz verbessern, indem wir einen anderen Vorhersagealgorithmus verwenden, beispielsweise einen Zufallswald oder ein neuronales Netzwerk. Wir könnten auch Ngramme wie Bigramme und Trigramme verwenden, wenn wir unsere Wortbeutelmatrix erstellen.
Versuche ein Tf-idf Eine Transformation auf der Matrix könnte ebenfalls hilfreich sein – scikit-learn verfügt über eine Klasse, die dies automatisch erledigt. Wir könnten auch andere Daten berücksichtigen, etwa den Benutzer, der den Artikel eingereicht hat, und Funktionen generieren, die Dinge wie das Karma des Benutzers und die jüngsten Aktivitäten des Benutzers angeben. Andere Statistiken zur übermittelten URL, wie die durchschnittliche Anzahl der von dieser URL erhaltenen Upvotes-Unterlektionen, wären möglicherweise ebenfalls nützlich.
Achten Sie dabei darauf, nur Informationen zu berücksichtigen, die vor der Unterlektion, für die Sie eine Vorhersage treffen, vorhanden waren. Die Ausführung aller dieser Ergänzungen wird viel länger dauern als bisher, aber sie werden die Fehlerquote reduzieren. Hoffentlich haben Sie etwas Zeit, sie auszuprobieren! Wenn Sie mehr über NLP mit Python erfahren möchten, können Sie sich unsere interaktiven Übungen ansehen Verarbeitung natürlicher Sprache für Deep Studying Kurs. Es endet mit einem Projekt zum Thema Klassifizierung katastrophenbezogener Tweets als echt oder gefälscht Dies stellt eine hervorragende Ergänzung Ihres Projektportfolios dar.