Für ein Textklassifizierungsprojekt (Alter) mache ich eine Teilmenge meiner Daten. Ich habe 3 Listen mit Dateinamen erstellt, sortiert nach Alter. Ich möchte diese Listen mischen und dann 5000 Dateinamen aus jeder gemischten Liste an eine neue Liste anhängen. Das Ergebnis sollte eine Datenteilmenge mit 15000 Dateien sein (5000 10s, 5000 20s, 5000 30s). Darunter kannst du sehen, was ich bisher geschrieben habe. Aber ich weiß, dass random.shuffle
keine und ein Objekt vom Typ none zurückgibt ist nicht iterierbar. Wie kann ich dieses Problem lösen?
Sie haben Recht, dass random.shuffle
None zurückgibt. Das liegt daran, dass es sein Listenargument an Ort und Stelle mischt, und es ist eine Python-Konvention, die ein veränderbares Argument verwendet und es mutiert, return None
. Sie missverstehen jedoch die random
arg zu random.shuffle
: Es muss ein Zufallszahlengenerator sein, keine Funktion wie Ihre seed
, die immer die gleiche Zahl zurückgibt.
Übrigens können Sie den Standard-Zufallszahlengenerator, der vom Zufallsmodul bereitgestellt wird, mit seiner Funktion seed
säen. random.seed
akzeptiert ein beliebiges Objekt als Argument, obwohl es üblich ist, ihm eine Zahl oder einen String zu übergeben. Sie können auch None
übergeben (was äquivalent dazu ist, dass es überhaupt keinen arg übergeben wird), und es wird den Randomisierer mit der zufälligen Systemquelle versehen (wenn es keine zufällige Systemquelle gibt, dann wird die Systemzeit verwendet) als der Samen). Wenn Sie seed
nicht explizit nach dem Import des Zufallsmoduls aufrufen, entspricht das dem Aufruf von seed()
Der Vorteil der Bereitstellung eines Seeds besteht darin, dass jedes Mal, wenn Sie das Programm mit dem gleichen Seed ausführen, die Zufallszahlen, die von den verschiedenen zufälligen Modulfunktionen erzeugt werden, genau gleich sind. Das ist sehr nützlich beim Entwickeln und Debuggen Ihres Codes: Es kann schwierig sein, Fehler aufzuspüren, wenn sich die Ausgabe ständig ändert. :)
Es gibt zwei Möglichkeiten, das zu tun, was Sie wollen. Sie können die Listen mischen und dann die ersten 5000 Dateinamen von ihnen trennen. Oder Sie können die Funktion random.sample
verwenden, um 5000 Stichproben zu nehmen. Auf diese Weise müssen Sie nicht die gesamte Liste mischen.
Verwenden von sample
Ich habe keine Geschwindigkeitstests für diesen Code durchgeführt, aber ich vermute, dass sample
schneller ist, da nur Elemente zufällig ausgewählt werden müssen und nicht alle Listenelemente verschoben werden müssen. shuffle
ist ziemlich effizient, so dass Sie wahrscheinlich keinen großen Unterschied in der Laufzeit feststellen würden, es sei denn, Ihre Teaser-, Tweens- und Thirds-Dateilisten haben jeweils mehr als 5000 Dateinamen.
Beide dieser Schleifen machen data
zu einer verschachtelten Liste mit 3 Unterlisten, mit 5000 Dateinamen in jeder Unterliste. Wenn Sie möchten, dass es eine flache Liste von 15000 Dateinamen ist, müssen Sie nur die Methode list.extend
anstelle von list.append
verwenden. ZB
Oder wir können es mit einem Listenverständnis mit einer doppelten for
Schleife tun:
Wenn Sie den Inhalt von data
filtern müssen, um Ihre endgültige Dateiliste zu erstellen, besteht die einfachste Möglichkeit darin, dem Listenverständnis eine if
-Bedingung hinzuzufügen.
Nehmen wir an, wir haben eine Funktion, die testen kann, ob ein Dateiname einer ist, den wir behalten wollen:
%Vor%Dann können wir
machen %Vor% und data
enthalten nur die Dateinamen, die den keep_file
Test bestehen.
Eine andere Möglichkeit besteht darin, die Dateinamen unter Verwendung eines Generatorausdrucks anstelle eines Listenverständnisses zu erstellen und dann an die integrierte Funktion filter
zu übergeben:
data_gen
ist selbst ein Iterator. Sie können daraus eine Liste erstellen:
Oder wenn Sie nicht wirklich alle Namen als Sammlung benötigen und sie nur einzeln verarbeiten können, können Sie sie in eine for
-Schleife schreiben, wie folgt:
Dies benötigt weniger RAM, aber der Nachteil ist, dass es die Dateinamen "verbraucht". Sobald die for
Schleife beendet ist, ist data_gen
leer.
Nehmen wir an, Sie haben eine Funktion geschrieben, die aus jeder Datei die gewünschten Daten extrahiert:
%Vor% Sie könnten eine Liste dieser (filename, age, text)
Tupel wie folgt erstellen:
Beachten Sie die Scheibe in meinem ersten Ausschnitt: flist[:5000]
. Das nimmt die ersten 5000 Artikel in flist
, die Artikel mit den Indizes 0 bis einschließlich 4999. Ihre Version hatte teens[:5001]
, was ein Fehler nach dem anderen ist. Slices funktionieren genauso wie Bereiche. Somit liefert range(5000)
die 5000 Zahlen von 0 bis 4999. Das funktioniert so, weil Python (wie die meisten modernen Programmiersprachen) Zero-basierte Indexierung verwendet.
Das erste Problem ist, dass Sie die Liste bestehend aus den drei Elementen [Teens, Tweens, Thirthies] mischen (selbst jedes Element ist eine Liste), anstatt jede Unterliste zu mischen
Zweitens können Sie random.sample
anstelle von random.shuffle
oder als @ JonClements, die in den Kommentaren vorgeschlagen werden, können Sie das Listenverständnis
verwenden %Vor% shuffle
gibt None
zurück, was nicht iterierbar ist
sollten Sie
tun %Vor%