Was maschinelles Lernen ist
Kurz gesagt: Maschinelles Lernen ist ein Weg, auf dem das Programm die Regel selbst aus Beispielen (Merkmale und ein Label) holt, statt dass ein Programmierer sie von Hand mit ifs schreibt.
Problem
Wie viele Tage braucht die Bestellung
Die Produktseite muss „kommt in 2 Tagen an“ sagen. Ein Kollege schreibt die Regel nach Kilometern: Bis 100 km sind es 1 Tag, bis 250 km 2 Tage, darüber 3. Dann lässt er sie über 12 frühere Bestellungen laufen, deren Reisezeit wir kennen:
// die Regel des Kollegen: nach Kilometernstatic int Rule(double km){ if (km < 100) return 1; if (km < 250) return 2; return 3;}var right = 0;for (var i = 0; i < orders.Length; i++){ var guess = Rule(orders[i][0]); if (guess == days[i]) right++; else Console.WriteLine($"Bestellung {i + 1}: die Regel sagt {guess}, tatsächlich {days[i]}");}Console.WriteLine($"die Regel trifft {right} von {orders.Length}");Bestellung 2: die Regel sagt 1, tatsächlich 2Bestellung 5: die Regel sagt 2, tatsächlich 3Bestellung 6: die Regel sagt 2, tatsächlich 3Bestellung 9: die Regel sagt 3, tatsächlich 4Bestellung 10: die Regel sagt 3, tatsächlich 4Bestellung 12: die Regel sagt 3, tatsächlich 5die Regel trifft 6 von 12Sechs von zwölf. Der Kollege fügt zwei Regeln hinzu: Ein schweres Paket (über 10 kg) braucht einen Tag länger, ebenso ein ausgelasteter Kurier (über 35 Pakete an dem Tag). Dieselbe Schleife, mit der neuen Regel:
// zwei weitere Regeln: ein schweres Paket und ein ausgelasteter Kurierstatic int Rule(double km, double kg, double parcels){ var days = km < 100 ? 1 : km < 250 ? 2 : 3; if (kg > 10) days++; if (parcels > 35) days++; return days;}Bestellung 2: die Regeln sagen 1, tatsächlich 2Bestellung 12: die Regeln sagen 4, tatsächlich 5die Regeln treffen 10 von 12Zehn von zwölf, aber mit drei neuen Zahlen nach Augenmaß: 10 kg, 35 Pakete und „einen Tag länger“. Warum nicht 8 kg? Warum +1 und nicht +0,5? Und nächsten Monat wechselt der Shop den Kurier, und alle Zahlen stimmen wieder nicht. Bei 50.000 Bestellungen und zehn Dingen, die zählen, kann sie niemand von Hand abstimmen.
Die Idee
Die Regel aus den Beispielen
Dreh es um. Statt die Regel zu schreiben und an den früheren Bestellungen zu prüfen, gib dem Programm die früheren Bestellungen und lass es die Regel selbst finden. Das heißt maschinelles Lernen: ein Programm, das die Regel aus Beispielen ableitet, statt dass jemand sie schreibt.
Jedes Beispiel hat zwei Teile:
- Merkmale: was du über die Bestellung weißt, bevor sie losgeht. Hier sind es drei: der Abstand, das Gewicht und wie viele Pakete der Kurier an dem Tag hat;
- Label: die Antwort, die du erraten willst. Hier ist es die Anzahl der Tage, die die Bestellung gebraucht hat.
// frühere Bestellungen: km, kg, Pakete des Kuriers an dem Tagdouble[][] orders =[ [15, 1.2, 18], [40, 0.8, 35], [60, 3.5, 20], [120, 2.0, 22], [150, 12.0, 25], [180, 1.5, 40], [220, 0.5, 15], [250, 8.0, 30], [300, 2.5, 45], [320, 18.0, 20], [380, 1.0, 28], [400, 6.0, 42],];// wie viele Tage jede gebraucht hatint[] days = [1, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 5];Was du aus den Beispielen bekommst und was für eine neue Bestellung eine Antwort gibt, heißt Modell. Es gibt viele Arten von Modellen. Wir beginnen mit dem einfachsten, bei dem du jede Zahl sehen kannst.
Die Idee
Die nächsten Nachbarn
Wie würdest du raten? Du würdest nach früheren Bestellungen suchen, die der neuen ähneln: ein ähnlicher Abstand, ein ähnliches Gewicht, eine ähnliche Auslastung. Wenn sie 3 Tage gebraucht haben, braucht die neue wahrscheinlich genauso lange.
Das ist ein Modell: k nächste Nachbarn (k-NN). Es behält alle früheren Bestellungen. Für eine neue findet es die k nächsten und gibt den Durchschnitt ihrer Tage zurück. Hier ist k = 3.
„Nah“ heißt ein kleiner Abstand zwischen zwei Bestellungen. Die Differenz jedes Merkmals wird quadriert, die Quadrate werden addiert, und du ziehst die Quadratwurzel aus der Summe, wie beim Abstand zwischen zwei Punkten auf einer Karte.
Es gibt eine Falle. Kilometer liegen in den Hundertern, Kilogramm im einstelligen Bereich. Addierst du die Differenzen, wie sie sind, wiegen 10 kg so viel wie 10 km, also nichts, und die Kilometer entscheiden allein. Deshalb wird jede Differenz durch den Bereich ihres Merkmals geteilt (der größte minus der kleinste Wert in den Daten). Dann liegt jedes Merkmal auf einer Skala: 1 heißt „von einem Ende zum anderen“.
// wie weit die Werte jedes Merkmals auseinanderliegen: max − minstatic double[] Ranges(double[][] rows) => Enumerable.Range(0, rows[0].Length) .Select(j => rows.Max(r => r[j]) - rows.Min(r => r[j])) .ToArray();double Distance(double[] a, double[] b){ double sum = 0; for (var j = 0; j < a.Length; j++) { var d = (a[j] - b[j]) / range[j]; sum += d * d; } return Math.Sqrt(sum);}Sieh es dir an
Die drei nächsten zur neuen Bestellung
int[] Nearest(double[] order){ var dist = new double[orders.Length]; for (var i = 0; i < orders.Length; i++) { dist[i] = Distance(order, orders[i]); } return Enumerable.Range(0, orders.Length) .OrderBy(i => dist[i]) .ToArray();}
double Predict(double[] order, int k){ var near = Nearest(order); double sum = 0; for (var n = 0; n < k; n++) { sum += days[near[n]]; } return sum / k;}Schritt für Schritt, in Worten
- Eine neue Bestellung: 140 km, 10 kg, 30 Pakete des Kuriers. Unten stehen die 12 früheren Bestellungen und wie viele Tage jede gebraucht hat.
- Der Abstand zu jeder früheren Bestellung. Jede Differenz wird durch den Bereich ihres Merkmals geteilt: km übertönen kg nicht.
- Dann sortiert es die Bestellungen nach Abstand: Die ähnlichsten stehen zuerst.
- Es nimmt die ersten k = 3: Bestellung 5, Bestellung 8, Bestellung 4. Die übrigen zählen nicht.
- Die Vorhersage ist der Durchschnitt ihrer Tage: (3 + 3 + 2) / 3 = 2,7 Tage.
- Niemand hat eine Regel geschrieben. Die Antwort kommt von den früheren Bestellungen, die der neuen am meisten ähneln.
Das Modell misst den Abstand zu jeder früheren Bestellung, sortiert sie und nimmt die ersten k:
int[] Nearest(double[] order){ var dist = new double[orders.Length]; for (var i = 0; i < orders.Length; i++) { dist[i] = Distance(order, orders[i]); } return Enumerable.Range(0, orders.Length) .OrderBy(i => dist[i]) .ToArray();}
double Predict(double[] order, int k){ var near = Nearest(order); double sum = 0; for (var n = 0; n < k; n++) { sum += days[near[n]]; } return sum / k;}Die neue Bestellung hat 140 km, 10 kg und 30 Pakete beim Kurier:
double[] order = [140, 10.0, 30];Console.WriteLine($"die 3 nächsten zu {order[0]:F0} km, {order[1]:F1} kg, {order[2]:F0} Pakete:");foreach (var i in Nearest(order).Take(3)){ var o = orders[i]; Console.WriteLine($" Bestellung {i + 1}: {o[0]:F0} km, {o[1]:F1} kg, {o[2]:F0} Pakete → {days[i]} Tage (Abstand {Distance(order, o):F2})");}Console.WriteLine($"Vorhersage: {Predict(order, 3):F1} Tage");die 3 nächsten zu 140 km, 10.0 kg, 30 Pakete: Bestellung 5: 150 km, 12.0 kg, 25 Pakete → 3 Tage (Abstand 0.20) Bestellung 8: 250 km, 8.0 kg, 30 Pakete → 3 Tage (Abstand 0.31) Bestellung 4: 120 km, 2.0 kg, 22 Pakete → 2 Tage (Abstand 0.53)Vorhersage: 2.7 TageAm nächsten liegt das schwere Paket aus 150 km. Bestellung 8 ist 100 km weiter weg, aber sie ist schwer und an einem ebenso vollen Tag, deshalb kommt sie an zweiter Stelle. Die leichte Bestellung aus 120 km ist die dritte. Der Durchschnitt von 3, 3 und 2 Tagen ist 2,7.
Probier es aus
Sag die Ausgabe vorher
Für eine Bestellung mit 230 km, 3 kg und 24 Paketen sind die drei nächsten Bestellung 4 (2 Tage), Bestellung 7 (2 Tage) und Bestellung 8 (3 Tage), in dieser Reihenfolge. Was druckt das Programm?
double[] order = [230, 3.0, 24];Console.WriteLine($"{Predict(order, 1):F1} {Predict(order, 3):F1}");Bei k = 1 sind die Tage des nächsten die Vorhersage: Bestellung 4, 2 Tage. Bei k = 3 ist es der Durchschnitt von 2, 2 und 3: 7 / 3 = 2,33, mit einer Nachkommastelle ausgegeben als 2.3.
Die Idee
Eine Vorhersage für neue Bestellungen
Das Modell ist fertig, sobald es die Daten hat. Neue Bestellungen:
double[][] fresh = [[140, 10.0, 30], [90, 1.0, 20], [350, 4.0, 40]];foreach (var order in fresh){ Console.WriteLine($"{order[0]:F0} km, {order[1]:F1} kg, {order[2]:F0} Pakete: {Predict(order, 3):F1} Tage");}140 km, 10.0 kg, 30 Pakete: 2.7 Tage90 km, 1.0 kg, 20 Pakete: 1.3 Tage350 km, 4.0 kg, 40 Pakete: 4.0 TageWie gut es rät, sagen diese drei Zahlen nicht. Die ehrliche Prüfung läuft an Bestellungen, die das Modell nicht gesehen hat, und sie steht in der Lektion über die Auswertung.
Wie wählst du k? Bei k = 1 sind die Tage einer einzigen Bestellung die Vorhersage, und die kann eine Ausnahme sein: ein Feiertag, ein verlorenes Paket. Ist k gleich allen Bestellungen, ist die Vorhersage der Durchschnitt von allem, und das Modell unterscheidet nicht mehr zwischen 15 km und 400 km. Meist probierst du ein paar Werte aus und nimmst den, der bei ungesehenen Bestellungen am seltensten daneben liegt.
Probier es aus
Ergänze
Die Vorhersage ist der Durchschnitt der Tage der k nächsten. Wodurch wird die Summe geteilt?
double sum = 0;
for (var n = 0; n < k; n++)
{
sum += days[near[n]];
}
return sum / ;Die Summe läuft über k Bestellungen, deshalb wird sie durch k geteilt. Teilst du sie durch die Anzahl aller Bestellungen, wird die Vorhersage viel kleiner als die echte.
Probier es aus
Finde den Fehler
Ein Kollege schreibt den Abstand um. Das Programm läuft, aber die Nachbarn der Bestellung mit 140 km und 10 kg sind jetzt die Bestellungen 5, 4, 6: Die schwere Bestellung 8 vom selben vollen Tag ist herausgefallen, und ein leichtes Paket hat ihren Platz genommen. Für die Bestellung mit 90 km wird die Vorhersage 1.7 Tage statt 1.3. In welcher Zeile steckt der Fehler?
Wähle die Zeile mit dem Fehler.
Die Differenz wird nicht durch den Bereich geteilt. Kilometer liegen in den Hundertern, Kilogramm und Pakete im ein- und zweistelligen Bereich, deshalb geht es im Abstand fast nur um Kilometer. Das Gewicht des Pakets und der ausgelastete Kurier wiegen nichts. Mit / RANGE[j] (in C# / range[j]) liegt jedes Merkmal auf derselben Skala.
Die Idee
Wann maschinelles Lernen das falsche Werkzeug ist
Ein Modell ist eine Regel, die niemand geschrieben hat. Das ist seine Stärke und sein Preis.
- Die Regel ist bekannt und stabil. Die Liefergebühr beträgt 4,90 € bis 2 kg, 6,90 € über 2 kg, ab 50 € ist sie frei. Das ist ein
if, kein Modell. Ein Modell würde sie nur ungefähr lernen und läge manchmal um ein paar Cent daneben. - Du brauchst eine exakte Antwort oder eine Erklärung. Steuer, ein Rabatt aus einem Vertrag, das Rückgaberecht. „Meistens ist es so“ reicht dort nicht, und „das Modell hat entschieden“ ist für den Kunden keine Erklärung.
- Es gibt keine Daten. Ein neuer Shop ohne frühere Bestellungen hat nichts, woraus er lernen kann. Dann ist eine Regel nach Augenmaß ein ehrlicher Anfang, und die Daten kommen später.
- Die Welt hat sich verändert. Das Modell kennt nur die Vergangenheit. Ein neuer Kurier, Feiertage, ein Streik: Vorhersagen aus den alten Bestellungen lügen, bis das Modell neu trainiert wird.
- Ein Fehler ist teuer. Ein Modell, das in 1 von 20 Fällen danebenliegt, taugt für „kommt in 2 Tagen an“ und taugt nicht für „die Zahlung durchlassen“. Dort steht eine Regel oder ein Mensch daneben.
Maschinelles Lernen ist für die Fälle, in denen die Regel zu viele Teile hat, als dass ein Mensch sie schreiben könnte, und es viele Beispiele gibt.
Genauer, für Neugierige
Was eine Vorhersage kostet. k-NN lernt nichts im Voraus: Für jede neue Bestellung vergleicht es mit allen früheren und sortiert sie. Bei n Bestellungen sind das mindestens n Abstände pro Vorhersage. Bei 12 Bestellungen ist das nichts, bei 10 Millionen ist es langsam. Deshalb benutzen echte Bibliotheken Strukturen wie einen k-d-Baum, und bei vielen Merkmalen suchen sie näherungsweise. Was „wächst mit n“ heißt, steht in der Lektion über Big-O.
Dieselbe Suche, aber für Text. Die Suche nach Bedeutung in Datenbanken ist k nächste Nachbarn über Vektoren: die Lektion über Vektoren im SQL-Kurs.
Das Teilen durch den Bereich heißt Min-Max-Normalisierung. Ein anderer Weg ist, den Mittelwert abzuziehen und durch die Standardabweichung zu teilen. Warum die Skala der Merkmale auch für andere Modelle wichtig ist, siehst du in der Lektion über den Gradientenabstieg.
Die echten Werkzeuge. Hier sind es Schleifen und Arrays, damit du jede Zahl siehst. In der Praxis wird maschinelles Lernen meist in Python gemacht: NumPy für Arrays, scikit-learn für die klassischen Modelle (dort ist k-NN KNeighborsRegressor), PyTorch für neuronale Netze. C# hat ML.NET, Java hat DJL und Tribuo, JavaScript hat TensorFlow.js und ONNX Runtime. Die Ideen sind dieselben.
Modelle trainieren und in Produktion betreiben (Trainingsserver, Deployment, beobachten, ob ein Modell veraltet) ist Infrastruktur und wird im DevOps-Kurs ZeroToOps gelehrt.
Übung
Wie viele Minuten das Verpacken dauert
Löse die Aufgabe in deinem Editor.
Das Lager will wissen, wie viele Minuten das Verpacken einer Bestellung dauert, damit es das Personal planen kann. Die Merkmale sind die Anzahl der Artikel und das Gesamtgewicht, das Label sind die Minuten. Hier sind zehn frühere Bestellungen:
// frühere Bestellungen: Anzahl der Artikel, kgdouble[][] orders =[ [1, 0.5], [2, 1.0], [3, 4.0], [5, 2.0], [6, 8.0], [8, 3.0], [10, 12.0], [12, 5.0], [15, 9.0], [20, 6.0],];// Minuten zum Verpackenint[] minutes = [4, 6, 9, 10, 15, 14, 22, 18, 25, 28];Schreib k nächste Nachbarn mit k = 3 und Teilung durch den Bereich und sag zwei neue Bestellungen vorher: 4 Artikel und 1,5 kg sowie 11 Artikel und 10 kg.
4 Artikel, 1.5 kg: 6.7 Min.11 Artikel, 10.0 kg: 20.7 Min.Weitere Aufgaben
- Ohne den Bereich. Entferne die Teilung durch den Bereich und sieh nach, welche Nachbarn herauskommen. Welches Merkmal entscheidet jetzt?
- Gewichte. Gib den Nachbarn ein Gewicht: Der nähere zählt mehr (zum Beispiel 1 / Abstand). Ändert sich die Vorhersage?
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: Parameter und return · static: was alle Objekte teilen · Lambdas und Delegates · Stabiles Sortieren und die eingebaute Sortierung
- Geht weiter in: Lineare Regression · Gradientenabstieg · Klassifikation: Betrug oder nicht · Auswertung: Die Genauigkeit lügt
- Aufgaben zum Thema: Wie ein Modell lernt