Haben Sie sich jemals gefragt, woher Ihr Lieblings-Streaming-Dienst genau weiß, was er als Nächstes empfehlen soll, oder wie On-line-Händler Ihre Einkaufsbedürfnisse vorherzusagen scheinen? Das Herzstück dieser intelligenten Systeme ist ein einfacher, aber leistungsstarker Algorithmus: Okay-Nächste Nachbarn (KNN).
In diesem Beitrag entmystifizieren wir den KNN-Algorithmus, indem wir uns seine Mechanik genauer ansehen und ihn anwenden, um die Torleistungen der NBA-Spieler aus der Saison 2013–2014 vorherzusagen. Unterwegs erfahren wir, wie wir die euklidische Distanz nutzen können, um herauszufinden, welche Spieler LeBron James „am nächsten“ sind. Wenn Sie mit mir programmieren möchten, können Sie sich den NBA-Datensatz, den wir verwenden werden, im CSV-Format herunterladen Hier.
Ein Blick auf unsere Daten
Bevor wir uns mit dem Algorithmus befassen, schauen wir uns an, wie unsere Daten aussehen. Jede Zeile in unserem Datensatz enthält Informationen zur Leistung eines Spielers in der NBA-Saison 2013–2014.
Hier sind einige ausgewählte Spalten aus unseren Daten:
participant
— Title des Spielerspos
— die Place des Spielersg
– Anzahl der Spiele, an denen der Spieler teilgenommen hatgs
– Anzahl der Spiele, die der Spieler gestartet hatpts
– Gesamtpunktzahl, die der Spieler erzielt hat
Der Datensatz enthält viele weitere Spalten, die hauptsächlich Informationen über die durchschnittliche Spielleistung der Spieler im Verlauf der Saison enthalten. Sehen diese Seite für eine Erklärung des Rests.
Als nächstes können wir unseren Datensatz einlesen und herausfinden, welche Spalten vorhanden sind:
import pandas
with open("nba_2013.csv", 'r') as csvfile:
nba = pandas.read_csv(csvfile)
print(nba.columns.values) # The names of all of the columns within the information.
('participant' 'pos' 'age' 'bref_team_id' 'g' 'gs' 'mp' 'fg' 'fga' 'fg.' 'x3p' 'x3pa' 'x3p.' 'x2p' 'x2pa' 'x2p.' 'efg.' 'ft' 'fta' 'ft.' 'orb' 'drb' 'trb' 'ast' 'stl' 'blk' 'tov' 'pf' 'pts' 'season' 'season_end')
KNN-Übersicht
Der k-Nearest-Neighbors-Algorithmus basiert auf der einfachen Idee, unbekannte Werte vorherzusagen, indem die ähnlichsten Werte im Datensatz identifiziert werden.
Nehmen wir zum Beispiel an, wir haben drei verschiedene Arten von Autos. Wir kennen den Namen des Autos, seine PS-Zahl, ob es Rennstreifen trägt oder nicht und ob es schnell ist oder nicht:
automobile,horsepower,racing_stripes,is_fast
Honda Accord,180,False,False
Yugo,500,True,True
Delorean DMC-12,200,True,True
Nehmen wir an, wir haben jetzt ein anderes Auto, wissen aber nicht, wie schnell es ist:
automobile,horsepower,racing_stripes,is_fast
Chevrolet Camaro,400,True,Unknown
Wir wollen herausfinden, ob das Auto schnell ist oder nicht. Um vorherzusagen, ob dies der Fall ist (unter Verwendung der k-nächsten Nachbarn), finden wir zunächst das ähnlichste bekannte Auto. In diesem Fall würden wir die vergleichen horsepower
Und racing_stripes
Werte, um das ähnlichste Auto zu finden, nämlich das Yugo
. Da der Yugo schnell ist, würden wir davon ausgehen, dass auch der Camaro schnell ist. Dies ist ein Beispiel für 1-nächste Nachbarn – wir haben uns nur das ähnlichste Auto angesehen; Im Wesentlichen haben wir ak von 1 verwendet.
Wenn wir eine 2-Nächste-Nachbarn-Methode durchführen würden, hätten wir am Ende 2 True
Werte (für die Delorean
und die Yugo
), was sich im Durchschnitt als ergeben würde True
. Der Delorean und der Yugo sind die beiden ähnlichsten Autos, was uns die Observe 2 gibt.
Wenn wir 3-nächste Nachbarn machen würden, würden wir am Ende 2 haben True
Werte und a False
Wert, der sich im Durchschnitt ergeben würde True
.
Die Anzahl der Nachbarn, die wir für k-nächste Nachbarn (ok) verwenden, kann ein beliebiger Wert sein, der kleiner ist als die Anzahl der Zeilen in unserem Datensatz. In der Praxis führt die Betrachtung nur einiger weniger Nachbarn zu einer besseren Leistung des Algorithmus, denn je weniger ähnlich die Nachbarn unseren Daten sind, desto schlechter wird die Vorhersage sein.
Euklidischer Abstand
Bevor wir mithilfe von KNN Vorhersagen treffen können, müssen wir einen Weg finden, herauszufinden, welche Datenzeilen der Zeile, auf der wir eine Vorhersage treffen möchten, „am nächsten“ sind.
Eine einfache Möglichkeit hierfür ist die Verwendung der euklidischen Distanz. Die Formel lautet (sqrt{(q_1-p_1)^2 + (q_2-p_2)^2 + cdots + (q_n-p_n)^2})
Nehmen wir an, wir haben diese beiden Zeilen (True/False wurde in 1/0 konvertiert) und wir möchten den Abstand zwischen ihnen ermitteln:
automobile,horsepower,is_fast
Honda Accord,180,0
Chevrolet Camaro,400,1
Wir würden zunächst nur die numerischen Spalten auswählen. Dann wird der Abstand zu (sqrt{(180-400)^2 + (0-1)^2}), was ungefähr gleich ist 220
.
Wir können das Prinzip der euklidischen Distanz nutzen, um die NBA-Spieler zu finden, denen sie am ähnlichsten sind Lebron James.
# Choose Lebron James from our dataset
selected_player = nba(nba("participant") == "LeBron James").iloc(0)
# Select solely the numeric columns (we'll use these to compute Euclidean distance)
distance_columns = ('age', 'g', 'gs', 'mp', 'fg', 'fga', 'fg.', 'x3p', 'x3pa', 'x3p.', 'x2p', 'x2pa', 'x2p.', 'efg.', 'ft', 'fta', 'ft.', 'orb', 'drb', 'trb', 'ast', 'stl', 'blk', 'tov', 'pf', 'pts')
def euclidean_distance(row):
"""
A easy Euclidean distance operate
"""
inner_value = 0
for ok in distance_columns:
inner_value += (row(ok) - selected_player(ok)) ** 2
return math.sqrt(inner_value)
# Discover the space from every participant within the dataset to lebron.
lebron_distance = nba.apply(euclidean_distance, axis=1)
Spalten normalisieren
Das ist Ihnen vielleicht schon aufgefallen horsepower
Bei den Autos hatte das Beispiel einen viel größeren Einfluss auf die Enddistanz als racing_stripes
tat. Das liegt daran horsepower
Die Werte sind in absoluten Zahlen viel größer und stellen daher die Auswirkungen von in den Schatten racing_stripes
Werte in den euklidischen Distanzberechnungen.
Dies kann schlecht sein, da eine Variable mit größeren Werten nicht unbedingt besser vorhersagen kann, welche Zeilen ähnlich sind.
Eine einfache Möglichkeit, damit umzugehen, besteht darin, alle Spalten so zu normalisieren, dass sie einen Mittelwert von 0 und eine Standardabweichung von 1 haben. Dadurch wird sichergestellt, dass keine einzelne Spalte einen dominanten Einfluss auf die Berechnungen der euklidischen Distanz hat.
Um den Mittelwert auf 0 zu setzen, müssen wir den Mittelwert einer Spalte ermitteln und dann den Mittelwert von jedem Wert in der Spalte subtrahieren. Um die Standardabweichung auf 1 zu setzen, dividieren wir jeden Wert in der Spalte durch die Standardabweichung. Die Formel lautet (x=frac{x-mu}{sigma}).
# Choose solely the numeric columns from the NBA dataset
nba_numeric = nba(distance_columns)
# Normalize all the numeric columns
nba_normalized = (nba_numeric - nba_numeric.imply()) / nba_numeric.std()
Den nächsten Nachbarn finden
Wir wissen jetzt genug, um den nächsten Nachbarn einer bestimmten Zeile im NBA-Datensatz zu finden. Wir können das nutzen distance.euclidean
Funktion von scipy.spatial
eine viel schnellere Methode zur Berechnung der euklidischen Distanz.
from scipy.spatial import distance
# Fill in NA values in nba_normalized
nba_normalized.fillna(0, inplace=True)
# Discover the normalized vector for lebron james.
lebron_normalized = nba_normalized(nba("participant") == "LeBron James")
# Discover the space between lebron james and everybody else.
euclidean_distances = nba_normalized.apply(lambda row: distance.euclidean(row, lebron_normalized), axis=1)
# Create a brand new dataframe with distances.
distance_frame = pandas.DataFrame(information={"dist": euclidean_distances, "idx": euclidean_distances.index})
distance_frame.kind("dist", inplace=True)
# Discover probably the most related participant to lebron (the bottom distance to lebron is lebron, the second smallest is probably the most related non-lebron participant)
second_smallest = distance_frame.iloc(1)("idx")
most_similar_to_lebron = nba.loc(int(second_smallest))("participant")
Generieren von Trainings- und Testsätzen
Da wir nun wissen, wie wir die nächsten Nachbarn finden, können wir anhand eines Testsatzes Vorhersagen treffen. Wir werden versuchen vorherzusagen, wie viele Punkte ein Spieler mit dem erzielt hat 5
nächste Nachbarn. Wir finden Nachbarn, indem wir alle numerischen Spalten im Datensatz verwenden, um Ähnlichkeitswerte zu generieren.
Zuerst müssen wir Check- und Trainingssätze generieren. Dazu verwenden wir Zufallsstichproben. Wir werden den Index des zufällig mischen nba
Datenrahmen und wählen Sie dann Zeilen mit den zufällig gemischten Werten aus.
Wenn wir dies nicht täten, würden wir letztendlich mit demselben Datensatz vorhersagen und trainieren, was zu einer Überanpassung führen würde. Wir könnten auch eine Kreuzvalidierung durchführen, was etwas besser, aber etwas komplexer wäre.
import random
from numpy.random import permutation
# Randomly shuffle the index of nba.
random_indices = permutation(nba.index)
# Set a cutoff for what number of objects we would like within the take a look at set (on this case 1/3 of the objects)
test_cutoff = math.ground(len(nba)/3)
# Generate the take a look at set by taking the primary 1/3 of the randomly shuffled indices.
take a look at = nba.loc(random_indices(1:test_cutoff))
# Generate the practice set with the remainder of the information.
practice = nba.loc(random_indices(test_cutoff:))
Benutzen sklearn
für Okay-Nächste Nachbarn
Anstatt alles selbst machen zu müssen, können wir die k-nearest neighbors-Implementierung in scikit-learn verwenden. Hier ist die Dokumentation. Es stehen ein Regressor und ein Klassifikator zur Verfügung, aber wir werden den Regressor verwenden, da wir kontinuierliche Werte zur Vorhersage haben.
Sklearn führt die Normalisierung und Entfernungsfindung automatisch durch und lässt uns angeben, wie viele Nachbarn wir betrachten möchten.
# The columns that we'll be making predictions with.
x_columns = ('age', 'g', 'gs', 'mp', 'fg', 'fga', 'fg.', 'x3p', 'x3pa', 'x3p.', 'x2p', 'x2pa', 'x2p.', 'efg.', 'ft', 'fta', 'ft.', 'orb', 'drb', 'trb', 'ast', 'stl', 'blk', 'tov', 'pf')
# The column that we need to predict.
y_column = ("pts")
from sklearn.neighbors import KNeighborsRegressor
# Create the knn mannequin.
# Have a look at the 5 closest neighbors.
knn = KNeighborsRegressor(n_neighbors=5)
# Match the mannequin on the coaching information.
knn.match(practice(x_columns), practice(y_column))
# Make level predictions on the take a look at set utilizing the match mannequin.
predictions = knn.predict(take a look at(x_columns))
Rechenfehler
Da wir nun unsere Punktvorhersagen kennen, können wir den mit unseren Vorhersagen verbundenen Fehler berechnen. Wir können rechnen mittlerer quadratischer Fehler. Die Formel lautet (frac{1}{n}sum_{i=1}^{n}(hat{y_{i}} – y_{i})^{2}).
# Get the precise values for the take a look at set.
precise = take a look at(y_column)
# Compute the imply squared error of our predictions.
mse = (((predictions - precise) ** 2).sum()) / len(predictions)
Nächste Schritte
Weitere Informationen zu k-nächsten Nachbarn finden Sie in unserem sechsteiligen interaktiven Dokument Grundlagenkurs zum maschinellen Lernendas die Grundlagen des maschinellen Lernens mithilfe des k-Nächste-Nachbarn-Algorithmus vermittelt.