Unterscheide geeignete und ähnliche Spiele

PythonBeginner
Jetzt üben

Einführung

Eine kleine Spielebibliothek sucht Alternativen für heute Abend. Ein Spiel kann deinem Lieblingsspiel ähneln und trotzdem ausgeliehen sein oder nicht zur Gruppengröße passen. Du trennst deshalb zwei Fragen: Welche Spiele sind nutzbar, und wie lassen sich ihre numerischen Eigenschaften vergleichen?

Du erstellst ein erneut ausführbares Auswahlprogramm und eine echte JSON-Ergebnisdatei. Voraussetzungen sind Python-Funktionen und Dictionaries, einfache NumPy-Arrays und das Lesen von Tabellen. Kenntnisse der Klassifikation mit nächsten Nachbarn helfen, doch hier werden keine Zielklassen vorhergesagt. Python und NumPy stehen bereit; scikit-learn wird nicht benötigt. Die 45 Minuten sind eine Schätzung des Autors einschließlich Lesen und üblicher Fehlerkorrekturen.

Bestimme die heute nutzbaren Spiele

In diesem Schritt untersuchst du den tatsächlichen Bibliothekskatalog und implementierst anschließend die Eignungsregeln für heute in einem Bereich einer vorbereiteten Funktion.

Öffne den Tab Terminal. Alle Befehle laufen dort, auch der Leser gespeicherter Dateien. Öffnen oder erneutes Verbinden von Terminal installiert deinen Arbeitsbereich nicht neu und setzt ihn nicht zurück. cd ändert das aktuelle Verzeichnis dieses Terminals; ein anderes Terminal hat sein eigenes Verzeichnis.

cd /home/labex/project/board-games

Beginne mit der tatsächlichen Eingabe. CSV hat eine Kopfzeile, gefolgt von kommagetrennten Zeilen. cat zeigt die Datei an, ohne sie zu ändern. Dies ist der vollständige, ungefilterte Katalog, keine Liste bereits für heute geeigneter Spiele.

cat catalog.csv

Jede Zeile steht für eine eigene Spielausgabe. Ihre eindeutige, nicht leere game_id ist der Schlüssel zum Suchen und Zuordnen dieser Ausgabe. title ist Anzeigetext: Mehrere Harbor-Ausgaben haben unterschiedliche IDs und müssen getrennt bleiben. minutes ist eine positive Spieldauerschätzung; complexity eine synthetische Bewertung von 1 bis 5, wobei höhere Werte komplizierter bedeuten. Die ganzzahligen Grenzen min_players und max_players schließen beide Endpunkte ein. Die synthetische Eingabe ist vollständig und enthält eine Zeile pro ID; fehlerhafte Daten zu bereinigen gehört nicht zu dieser Übung.

cat availability.csv

Die getrennte Ausleihtabelle hat eine Zeile für jede Katalog-ID, in anderer Reihenfolge. Ihr CSV-Text true/false wird im vorbereiteten Leser zu Pythons booleschen Werten True/False. Über einen Schlüssel verknüpfen bedeutet, dieselbe game_id zu finden, nicht Zeile 1 an Zeile 1 anzuhängen. Eindeutige Schlüssel und ein Ausleihstatus je ID verhindern mehrdeutige oder fehlende Zuordnungen. Du wirst dieses Nachschlagen implementieren.

JSON speichert benannte Werte, Listen und Objekte. Lies die Anfrage für heute:

cat night.json

reference_id ist das Beispiel, dem Alternativen ähneln sollen, players die Gruppengröße und k die gewünschte Zahl naher Alternativen für das nächste Lab. Die Referenz ist ein Suchbeispiel und darf selbst nicht verfügbar oder ungeeignet sein; nur zurückgegebene Alternativen müssen heute passen. Schließe nur ihre genaue ID aus, nicht alle Spiele mit gleichem Titel oder identischen Merkmalen. Die Übersicht der Roheingaben hat diese Regeln noch nicht angewandt und kein Eignungsergebnis erzeugt.

Betrachte drei verfügbare Spiele für vier Personen: Harbor dauert 60 Minuten bei Komplexität 3, Quay 61 bei 5 und Bridge 90 bei 3. Unterschiede in Originaleinheiten sind Kandidat minus Referenz: Quay dauert eine Minute länger und ist zwei Punkte komplexer; Bridge dauert dreißig Minuten länger bei gleicher Komplexität. Pythons -c führt die zitierte Berechnung als ein Argument aus. Das Semikolon trennt zwei Python-Anweisungen.

python3 -c "print('Quay minutes:', 61 - 60); print('Bridge minutes:', 90 - 60)"

Erwarte 1 und 30. Rohe euklidische Distanz quadriert und addiert Merkmalsunterschiede und zieht dann die Quadratwurzel. Dreißig Minuten können zwei Komplexitätspunkte überwiegen, wenn diese Einheiten direkt vermischt werden. Als Nächstes definierst du eine gemeinsame Skala; bestimme zuerst, wer überhaupt teilnehmen darf.

Du darfst suitability.py, ranking.py, deine Ergebnisdateien und deine eigenen Skriptsicherungen bearbeiten. Erhalte jede bereitgestellte CSV/JSON-Eingabe, planner.py, coursekit.py, show_results.py und beide Wiederherstellungskopien starter-*.py. planner.py wählt eine öffentliche Funktion und überlässt Dateilesen, Typumwandlung und JSON-Schreiben coursekit.py; keines trifft die fachliche Entscheidung. Lasse ranking.py in diesem Lab unfertig.

Lies das vorbereitete Modul:

cat suitability.py

choose_games(catalog, availability, request) erhält die geladenen Listen von Dictionaries und das Anfrage-Dictionary. Seine zwei beschrifteten Bereiche beginnen mit eligible = [] und scale = {}. Dies sind unfertige Platzhalter, keine Behauptung, dass kein Spiel geeignet ist. Die abschließende Rückgabe verpackt IDs und Skala für den Starter. Du ersetzt nun den Eignungsbereich und behältst den Skalenplatzhalter für Schritt 2. Setup und Eingabeübersicht erzeugen kein bewertetes Ergebnis.

Sichere dieses Modul. cp SOURCE DESTINATION kopiert nur die benannte Datei; .bak ist eine Sicherungsendung. Überschreibe diese Sicherung nach einem Fehler nicht.

cp suitability.py suitability.py.bak

nano bearbeitet eine vorhandene Datei innerhalb von Terminal. Das befehlslokale LC_ALL=C.UTF-8 wählt UTF-8 nur für diesen Editor, ohne globale Shell-Einstellungen zu ändern. In nanos Kürzelleiste bedeutet ^, Strg gedrückt zu halten. Pfeiltasten bewegen den Cursor; Tippen fügt Text ein. Strg+W, ein Suchausdruck und Enter finden Text. Pos1 führt zum Zeilenanfang; Strg+K schneidet diese ganze Zeile aus. Python verwendet Einrückung: Die folgenden Zeilen beginnen innerhalb der Funktion mit vier Leerzeichen, weitere Einrückung folgt innerhalb von Schleife und Bedingung.

LC_ALL=C.UTF-8 nano suitability.py

Übe zuerst das Verwerfen einer unerwünschten Bearbeitung. Finde ## Candidate identities mit Strg+W und Enter, drücke Ende und ergänze temporary in diesem Kommentar. Drücke Strg+X, dann N bei der Speicherfrage. Du verlässt den Editor ohne Dateiänderung. Öffne sie erneut:

LC_ALL=C.UTF-8 nano suitability.py

Finde eligible = [], drücke Pos1 und dann einmal Strg+K, um nur diese Platzhalterzeile zu entfernen. Erhalte Funktionskopf, Skalenbereich und abschließende Rückgabe. Füge dort die folgenden eingerückten Zeilen ein. Die Dictionary-Comprehension erstellt ein Nachschlagewerk von ID zu Verfügbarkeit. Die Schleife verwendet and für drei unabhängige Anforderungen; verkettete <=-Vergleiche schließen beide Personengrenzen ein. append fügt die passende ID hinzu, nicht den Anzeigetitel.

    status = {row['game_id']: row['available'] for row in availability}
    eligible = []
    for game in catalog:
        different_id = game['game_id'] != request['reference_id']
        fits_group = game['min_players'] <= request['players'] <= game['max_players']
        if different_id and fits_group and status[game['game_id']]:
            eligible.append(game['game_id'])

Speichere mit Strg+O, drücke Enter zum Bestätigen des unveränderten Dateinamens und dann Strg+X zum Beenden. Speichern führt die Funktion nicht aus. Ihre vorhandene Rückgabe verwendet sorted(eligible) für eine alphabetische Identitätsliste unabhängig von der Eingabezeilenfolge und lässt scale als leeres Objekt stehen.

Die Option --mode suitable des Starters wählt choose_games; das erforderliche --output suitable.json benennt sein gespeichertes Ergebnis. Standardwerte sind catalog.csv, availability.csv und night.json in diesem Verzeichnis. --catalog, --availability und --request können andere Pfade wählen. Diese Eingaben bleiben schreibgeschützt.

python3 planner.py --mode suitable --output suitable.json

Der bereitgestellte Leser öffnet nur dieses gespeicherte JSON. Er erzeugt weder eine fehlende Datei noch berechnet er etwas aus dem Katalog.

python3 show_results.py suitable.json

Erwarte Scale: {} und die IDs left, near, raw, right, same, zero. Sowohl same als auch zero sind andere Harbor-Ausgaben; zero hat sogar identische numerische Merkmale zur Referenz. blocked ist nicht verfügbar, small kann keine vier Personen aufnehmen und ref ist die genaue Referenz. Vergleiche diese Identitäten mit den zwei Eingabetabellen. Die Eignung ist nun vollständig, die Skalierung absichtlich noch nicht implementiert.

Der nächste Fehler durch ein falsches Verzeichnis ist beabsichtigt. Gehe ein Verzeichnis nach oben:

cd /home/labex/project
python3 planner.py --mode suitable --output suitable.json

Python meldet can't open file und No such file or directory: Der Starter ist hier nicht zu finden. Dein vorhandenes Programm und Ergebnis wurden nicht zurückgesetzt. pwd zeigt das Verzeichnis dieses Terminals; kehre in den Arbeitsbereich zurück und wiederhole den tatsächlichen Befehl.

pwd
cd /home/labex/project/board-games
python3 planner.py --mode suitable --output suitable.json
python3 show_results.py suitable.json

Lies bei einem Bearbeitungsfehler Pythons Dateinamen und Zeilennummer, öffne das Modul erneut in nano und korrigiere nur den betroffenen Bereich. SyntaxError deutet oft auf einen fehlenden Doppelpunkt oder ein Anführungszeichen hin; IndentationError bedeutet, dass die führenden Leerzeichen Aufmerksamkeit benötigen. Speichere, beende und führe erneut aus. Strg+X, N verwirft ungespeicherte Änderungen. Falls nötig stellt cp suitability.py.bak suitability.py nur diese unfertige Basis wieder her; danach musst du den Eignungsbereich erneut ergänzen. Weder eine Sicherung noch das geschützte starter-suitability.py ist deine fertige Lösung. Führe zur Wiederherstellung weder das Setup erneut aus noch ändere Eingaben.

Verwende eine Skala für den gesamten Katalog

In diesem Schritt implementierst du den Skalenbereich und erhältst dabei deine fertige Eignungslogik.

Bleibe im Terminal-Tab. Gib das Verzeichnis ausdrücklich an, damit die Befehle auch in einem neuen Terminal funktionieren.

cd /home/labex/project/board-games

Ein Merkmal ist eine numerische Eigenschaft für den Vergleich. Die Reihenfolge ist immer minutes, dann complexity; Personengrenzen und Verfügbarkeit bestimmen die Eignung, nicht die Distanz. Ermittle je Merkmal Minimum und Maximum im gesamten Katalog, einschließlich Referenz sowie nicht verfügbarer und ungeeigneter Spiele. Die Spannweite ist Maximum minus Minimum. MinMax bildet x auf (x - minimum) / range ab: Unterschiede werden damit zu Anteilen ihrer jeweiligen Katalogspannweite.

Der vollständige Katalog hat Minima [10, 1] und Spannweiten [100, 4]. Quay ergibt [1/100, 2/4], Bridge [30/100, 0/4]. Quays skalierte Distanz liegt ungefähr bei 0.5001, Bridges bei 0.3. Die Metrik ändert die Rangfolge, sagt aber nichts über persönliche Vorlieben. Gleiche Gewichte nach der Skalierung sind eine offen gelegte Übungsentscheidung.

Dieser Katalog dient zur Definition der Metrik, nicht als überwachter Trainingssatz. Ohne zukünftige Zielvariable gibt es keine Trainings-/Testaufteilung. Nur die Verfügbarkeit zu ändern darf weder die Skala noch Distanzen weiterhin geeigneter Spiele ändern. Nach dem Filtern neu angepasste Parameter würden bei jedem Ausleihvorgang den Maßstab verschieben.

Ein konstantes Merkmal hat Spannweite null. Speichere die tatsächliche Spannweite 0, verwende später aber Divisor 1. Weil die Referenz zum Katalog gehört, sind alle Unterschiede auf diesem Merkmal null und tragen keine Distanz bei. So wird die Division durch null vermieden, ohne Informationen zu erfinden.

Lege eine neue Sicherung deiner funktionierenden Eignungsphase an und lasse die ursprüngliche Basissicherung unverändert:

cp suitability.py suitability-ids.py.bak
LC_ALL=C.UTF-8 nano suitability.py

Finde scale = {} mit Strg+W und Enter, drücke Pos1 und schneide nur diese eine Platzhalterzeile mit Strg+K aus. Lasse das fertige ID-Nachschlagen und die Schleife darüber unverändert. Füge die vier eingerückten Zeilen unten ein. np.array erstellt eine zweispaltige numerische Tabelle in der veröffentlichten Merkmalsreihenfolge; axis=0 findet Minima und Maxima entlang jeder Spalte. tolist() wandelt Arrays in gewöhnliche Listen um, die JSON speichern kann.

    features = np.array([[game['minutes'], game['complexity']] for game in catalog])
    minimum = features.min(axis=0)
    ranges = features.max(axis=0) - minimum
    scale = {'min': minimum.tolist(), 'range': ranges.tolist()}

Die vorhandene Rückgabe enthält nun diese berechnete scale und dieselben sortierten IDs. Speichere mit Strg+O, Enter, dann Strg+X. Du hast einen Bereich ergänzt, statt die vorherige Arbeit zu ersetzen oder ein weiteres Programm anzuhängen.

Speichere Zahlen statt formatierter Zeichenketten. Die Liste enthält jede zulässige ID genau einmal in alphabetischer Reihenfolge. scale.min und scale.range enthalten je zwei Zahlen in der genannten Reihenfolge. Zusätzliche harmlose Erklärfelder sind erlaubt. Absolute und relative Prüftoleranz sind 1e-8: Das erlaubt übliche Gleitkommaabweichungen, keine andere Metrik.

Erzeuge das echte Ergebnis erneut aus den unveränderten Eingaben und überschreibe nur deine Ausgabe.

python3 planner.py --mode suitable --output suitable.json
python3 show_results.py suitable.json

Nun sollten Minima 10 und 1, Spannweiten 100 und 4 sowie dieselben sechs IDs erscheinen. Der Leser kann 10.0 statt 10 zeigen; beides ist die Zahl zehn. Untersuche die gespeicherte Struktur direkt:

cat suitable.json

Beschädigt eine Bearbeitung den Eignungsbereich, stellt cp suitability-ids.py.bak suitability.py nur diesen funktionierenden Stand wieder her. Öffne nano erneut und implementiere den Skalenbereich nochmals. cp starter-suitability.py suitability.py stellt dagegen die unfertige Basis wieder her und verliert beide Bereiche; verwende es nur, wenn du bewusst von vorn beginnen möchtest. Gewöhnliche Korrekturen sollten die betreffenden Zeilen reparieren, speichern, beenden und erneut ausführen. Erhalte beide bereitgestellten Starterdateien und alle Eingaben. Erneutes Verbinden von Terminal führt niemals das Setup aus und stellt keine Sicherung für dich wieder her.

Selbstprüfung: Die Eignung für heute kann sich ändern, ohne diesen Maßstab des Gesamtkatalogs zu ändern. Im nächsten unabhängigen Lab ist die vollständige Eignungsfunktion vorhanden, damit du dich auf Distanzen und Auswahl konzentrieren kannst.

Zusammenfassung

Du hast die Eignung für heute von inhaltlicher Ähnlichkeit getrennt, unabhängige Datensätze über stabile IDs verknüpft, zulässige gleichnamige und numerisch identische Alternativen behalten und eine feste MinMax-Skala aus dem gesamten Katalog abgeleitet. suitable.json ist ein echtes, neu erzeugbares Ergebnis. Im nächsten Lab nutzt du dieses Wissen zum Messen und Erklären von Kandidaten; es startet mit einer eigenen unabhängigen Umgebung.