ningiser
Goto Top

3000 zufällige Zeilen aus TXT mit 22 Mio Zeilen auslesen

Hallo,

ich bin ein Quereinsteiger und arbeite egentlich mit Geo-informationssystemen. Daher habe ich leider keine Erfahrung mit Skripten (außer einfachem Batch-Kopieren von Dateien). Nun habe ich folgendes Problem, bei dem ich hoffe dass mir ein Batch-Skript helfen kann...

Es geht um Folgendes:

Ich habe eine Textdatei in der 22 Mio Koordinatenpunkte gespeichert sind, d.h. in jeder Zeile der TXT sind durch Tabs getrennte x,y und z Werte eines Koordinatensystems gespeichert. Sie ist ca. 700MB schwer. Dabei ist jede Zeile der Textdatei exakt gleichviele Zeichen lang und auch die Anzahl der Zeilen kenne ich. Nun will ich aus diesen vielen Punkten 3000 zufällig herausnehmen, d.h. aus der Textdatei 3000 Zeilen nach dem Zufallsprinzip "ausschneiden" und in eine neue Textdatei schreiben, sodass ich am Ende zwei Dateien erhalte:
a) eine Datei mit den 3000 Zufallspunkten (d.h. Zeilen) und
b) eine Datei mit den verbleibenden 21997000 Mio Zeilen.

Diese Aktion muss ich nur für diese eine Datei durchführen.

Meine Fragen sind nun:
1. Ist das Vorhaben mit einem Batch-Skript grundsätzlich (auf einem normalen Büro-PC) möglich, so dass es sich für mich lohnt mich damit näher zu beschäftigen?
2. Falls das der Fall ist, hat jemand Tipps für die Erstellung eines solchen Skripts?

Es wäre super wenn ihr einem Laien wie mir da weiterhelfen könntet...

Dank und Gruß,
ningiser

Content-Key: 111702

Url: https://administrator.de/contentid/111702

Printed on: April 19, 2024 at 09:04 o'clock

Member: problemsolver
problemsolver Mar 18, 2009 at 08:09:49 (UTC)
Goto Top
Hallo,

ich habe mir gerade den Kopf darüber zerbrochen und überlegt, ob es mit Batch bzw. normalen VB Script möglich ist.
Nach einigem Lesen bin ich aber sicher, dass Du um die VBMath.Randomize() Funktion von .Net (als Beispiel) nicht drumherum kommen wirst, da Du nur hier große Zufallszahlen in dem Bereich > INT erstellen kannst.

Ich habe zwar versucht, die einzelnen Stellen der "22.000.000" seperat per Zufall zu bestimmen, aber die Verteilung ist einfach nicht zufällig... egal wie oft man Randomize mit Rnd zusammen benutzt.

Nichts desto trotz wird es Dich vielleicht freuen jetzt einen Weg zu wissen, wie man es nicht macht face-wink

Du müsstest Du "mal eben" schnell eine Konsolenanwendung in .NET erstellen, die Dir aus den 22000000 insgesamt 3000 Zufallszahlen pickt. Diese Schreibst Du entweder in ein Array (um zu kontrollieren, ob sie wirklich eindeutig sind).
Danach liest Du genau diese Zeilen aus der 22000000 Datei aus und löscht die besagten Zeilen , nachdem Du alle 3000 Zeilen extrahiert hast.

Wünsch noch viel Erfolg

Gruß

Markus
Member: Biber
Biber Mar 18, 2009 at 11:46:19 (UTC)
Goto Top
Moin ningiser,

willkommen im Forum.

Wenn das eine einmalige Aktion und Dein Rechner auch die ganze Mittagspause (oder die halbe Nacht) damit verbringen kann, dann geht es auch mit normalem Batchkrams oder ein bis zwei Zeilen am Cmd-Prompt.

Für den ersten Teil der Aufgabe (3000 Zufallszahlen aus roundabout 22 Mio rausfieseln könnte ich Dir eine Skizze anbieten
>(for /L %i in ( 1,1,30) do @set /a x="!random!*!random!">nul & @set /a "y=!x! % 21997000">nul & @echo !y!)|sort  
10137224
10153303
10878128
12684210
14344419
15210636
16417280
16557600
17083854
17257936
1857192
2074661
21110862
21343388
21828460
21924535
2686070
282968
2911667
2959750
548502
5697962
6137867
6515124
6667600
7245863
8041045
8313475
8644748
9300321
... hier mal beispielhaft für die ersten dreißig statt dreitausend Zeilen.
[Edit] Erst zu spät gesehen... der "sort" sortiert hier natürlich "literal" und nicht aufsteigend nach Zahlenwerten.
also bitte den "Sort" einfach wegdenken. Ist nicht wesentlich. [/Edit]


Diese Zeilen(nummern) wiederum könnten
  • in eine Textdatei "3000ZeilenNr.txt" umgeleitet/durchgereicht werden
  • wenn es der FindStr-Befehl rafft, dass es auch GROSSE Zeilennummern in Textdateien geben kann (ich weiß nicht, wo da intern die MaxZeilen-Zahl festgelegt ist), dann sollte die Zeilenzahl auch mit FindStr /N herauskommen und somit die betrefende Zeile gefunden werden können.
  • aber das könnte genauso lange dauern, wie auch eine FOR /F - Anweisung in der Monsterdatei benötigt, um Zeile für Zeile zu dieser Zeilennummer zu gelangen.

Egal... ist alles Schritt 2.
Zu prüfen wäre jetzt von Dir, ob Dir die Streuung der 3000 "Zufalls"-zahlen mit der oben stehenden Mimik ausreicht oder ob eine "bessere" Random()-Funktion eines anderen Tools (VBS / java / #Net / whatever) benötigt wird.

Grüße
Biber
Member: ningiser
ningiser Mar 19, 2009 at 14:52:31 (UTC)
Goto Top
Hallo Markus, Hallo Biber,

vielen Dank für eure Infos! Ich werde das gleich mal testen. Hoffe das gelingt mir und meiner (leider nicht all zu leistungsfähigen) Maschine. Schaun´mer mal...

LG,
ningiser
Member: ningiser
ningiser Mar 19, 2009 at 23:33:25 (UTC)
Goto Top
So, da bin ich wieder...

Leider bin ich als praktisch absoluter Neueinsteiger mit meinen mangelnden Skripting-Kenntnissen bereits an Schritt gescheitert.
Vielleicht mögt ihr für einen Laien noch einmal weiter vorne anfangen?

@Biber: Wie bekomme ich deine Idee denn zum laufen? Ich habe nichts dagegen, wenn mein Compouter auch mal was länger rechnet....
Wäre das Problem mit einer anderen Skriptsprache denn einfacher zu lösen?
Für mich sind nämlch leider auch der FindStr-Befehl oder die FOR /F - Anweisung Böhmische Dörfer...

Oder wäre für diese meine Aufgabe ein längeres Skript notwendig?

LG,
ningiser
Member: Biber
Biber Mar 20, 2009 at 09:19:38 (UTC)
Goto Top
Moin ningiser,

@Biber: Wie bekomme ich deine Idee denn zum laufen?
Ich habe nichts dagegen, wenn mein Compouter auch mal was länger rechnet....
Lass uns mal nichts überstürzen... wir sind ja noch in der Klärungsphase.
Wäre das Problem mit einer anderen Skriptsprache denn einfacher zu lösen?
Ich denke, wie meistens hängt es eher von der Lösungsstrategie, dem Algorithmus ab.
Und bevor ich WTHF mit 22 Mio. Zeilen mache, nehme ich mir in der Regel ein paar Minuten Zeit für die Überlegung, wie ich es mache.

Deshalb (etwas kürzer und deshalb hoffentlich verständlicher) die Klärungsfragen:

  • wie "gleichverteilt" sollen denn die "Zufallszahlen" sein?
  • Liegen die 22-Mio-Koordinaten denn irgendwie logisch sortiert vor oder bekommst Du auch eine gut durchmischte Koordinatenkonstellation, wenn Du z.B. 3.000 Zeilen en bloc nehmen würdest, meinetwegen die Zeilen 118.000 bis 120999?
  • Wenn es irgendwie vermeidbar ist würde ich unbedingt das physische Erzeugen einer Quasi-Kopie der 22-Mio-Monsterdatei vermeiden. Das kann nicht schnell und kann nicht ressourcenschonend sein. 3000 Zeilen aus dem Gesamtbestand kopieren: Ja. Eine 22-Mio-minus-3000-Zeile-Kopie erzeugen - wenn es vermeidbar ist: Nein. Also: Ist die Kopie der Datei für irgendetwas anderes nötig?

Grüße
Biber
Member: ningiser
ningiser Mar 20, 2009 at 12:52:58 (UTC)
Goto Top
Hallo Biber,

ja, da hast du wohl recht. Um das Ganze nun etwas zu praezisieren:

1. Eine moeglichst gleiche Verteilung ist nicht so wichtig, die 3000 Punkte sollen nur moegichst zufaellig verteilt sein.

2. Die Koordinaten liegen leider "teilsortiert" vor. D.h. sie sind in Bloecken sortiert, die Bloecke untereinander aber leider nicht.
Insgesamt liegen die 22-Mio-Koordinaten raeumlich beieinander, also in einem Wertebereich auf der X-Achse von 5865000.000 bis 5870000.000. Und auf der Y-Achse in einem aehlichen Bereich. Leider scheitern alle Texteditotren die ich probiert habe daran, die Datei zu oeffen oder zu bearbeiten...

Von daher kommt ein entnehmen ganzer Bloecke leider nicht in Frage...

Ich hoffe, das klaert ein paar strategische Fragen...
Member: Biber
Biber Mar 20, 2009 at 13:22:10 (UTC)
Goto Top
Na gut, ningiser,

ich denke, jetzt bekommen wir langsam ein Gefühl dafür, wie wir dieses gewünschte Ergebnis erzielen können.
Wenn wir zu früh (nur) darüber diskutieren, mit welchem Werkzeug und welchen Detailbefehlen-> das versperrt manchmal den Blick aufs Eigentliche.

Wenn Du mich also danach fragen würdest (sagen wir mal abends in der Kneipe in noch entspannterer Atmosphäre als hier), wie ich diese Kuh vom Eis bekommen wollte, würde ich auch vor dem ersten Becks schon antworten:

  • ich würde ein Cmd-Fenster im Verzeichnis der 22-Mio-Zeilen-Monsterdatei öffnen.
  • dort einen einzigen Befehl losjagen:
 findstr "1.2.3.4." 22MioMonster.txt >MiniMonster.txt  
  • d.h. alle Datensätze, die den Text ["1"-beliebigesZeichen-"2-beliebigesZeichen-"3"-...."] enthalten, werden aus der großen in eine kleine Datei geschrieben.
  • dort sind dann, wenn ich in Statistik für Quereinsteiger damals richtig aufgepasst habe, roundabout 12000 Sätze gelandet in ebensovielen Zeilen.
  • diese Zeilen Zählen wir einmal durch mit "Findstr /n $ minimonster.txt"
  • wenns mehr als 3000 Zeilen sind--> nehmen wir die ersten (oder letzten) 3000 davon (mit "more +x")
  • wenn es weniger sind, hängen wir noch ein Sätze dran mit [findstr "9.8.7.6." 22MioMonster.txt >>MiniMonster.txt]

Fertig is'.
Ohne da 3000x eine Randomize-Arie aufzurufen und ohne 22 Mio.Zeilen von A nach B zu kopieren.

Unelegant, aber vor dem Abendessen fertig.
Und wir Bremer essen zeitig.

Grüße
Biber
Member: ningiser
ningiser Mar 20, 2009 at 14:10:29 (UTC)
Goto Top
Hallo Biber,

ersteinmal Danke fuer deine weiteren Infos. Mit dem Biergleichnis wird es fuer mich jedenfalls verstaendlicher...
Aber einiges ist mir noch nicht ganz klar geworden:
Mit findstr wird doch nach bestimmten Textwerten gesucht oder habe ich das falsch verstanden?
Damit wuerde ich doch nur bestimmte Koordinaten zurueckgeliefert bekommen, die dann alles andere als zufaellig verteilt sind, oder nicht? Oder verstehe ich da etwas falsch?
Hab das gefuehl ich stehe da etwas wie der Ochs vorm Berge.
Member: Biber
Biber Mar 20, 2009 at 15:13:14 (UTC)
Goto Top
Moin ningiser,

wenn (falls!) ich Deine Aussage
also in einem Wertebereich auf der X-Achse von 5865000.000 bis 5870000.000.
...nicht zu blauäugig aufgenommen habe, dann stehet do irgenwo in jeder Zeile minimal ein X-Wert zwischen
5865000.000 
....
5870000.000

Habe ich so interpretiert, dass auch Werte dabei sind wie..
5865000.000 
...
5865102.304  -->passt 
5865112.354 --> passt
5865122.304  --> dto

5877132.374 dto
....
5865192.394 dto

5886192.394 dto

Muss ja nicht sein, dass wir ein 8-Stelliges Zufallsmuster der Form "1x2x3x4x" rausfiltern.
--> ein 2 Zeichen kürzerer Matchwert würde auch besser gehen bzw streuen.
Wir können ebenso statt nach "1234" oder "4711" nach Zufallszahlen suchen
--> aber nicht mehr über die aufwändige Krücke "Zufallszahl soll gleich sein der Zeillennummer".
Denn wenn ich die zufällig ermittelte Zeilennummer 17Mio300001 aus der Datei lesen muss, dann muss ich erst 17Mio300000 (über)lesen, bevor ich irgendetwas sinnvolles -nämlich das Kopieren dieser Zeile- beginnen kann.
Das wollte ich vermeiden.

Natürlich ist es NICHT gleichverteilt -- okay.
Aber ich decke den gesamten Bereich von 5Mio865Tausend bis 5Mio870Tausend ab. und dass die 3te Nachkommastelle halt bei meiner Mimik immer eine "4" ist.... okay.
Irgendwas geht immer im Rauschen unter.

Für das Ziel "3000 Koordinaten aus dem Wertebereich von-bis aus insgesamt 22 Mio vorhandenen zufällig ermittelt" sollte es reichen.

Grüße
Biber
Member: ningiser
ningiser Mar 20, 2009 at 16:13:24 (UTC)
Goto Top
Moin Biber,

jaaaaaa, jetzt kommen wir der Sache schon deutlich naeher!!! Das Ergebnis sieht jedenfals schon mal recht vielversprechend aus und das Auslesen geht auch echt flott.
Die Idee mit den Nachommastellen zu operieren gefaellt mir auf jeden Fall sehr gut! Genialer Einfall !!!

Das Filtern muesste allerdings noch etwas justiert werden, da ich bei meinem Test mit dem folgenden Befehl:
findstr "58...9.330" mehr als 20.000 Zeilen zurueckgeliefert bekomme.

Punkte werden im Findstring als "Joker" verwendet, richtig? Wie kann ich dann nach Punkten, die die Nachkommastellen in der Textdatei definieren suchen lassen, oder geht das nicht?

In diesem Zusammenhang stellt sich mir auch die Frage wie ich in findstr mit <tabs> umgehen kann. Denn x und y Koordinaten sind durch tabs getrennt. Und ich koennte mir vorstellen die suchergebnisse ueber die verwendung der Nachkommastellen der x und y Koordinaten weiter einzugrenzen, also z.B. so

findstr "58****.330<tab>684****.330"  

Super waere es, wenn ich die von mir vorgegebenen Nachkommastellen durch einzelne Zufallsziffern ersetzen koennte...

Ach ja, und die herausgelesenen Zeilen sollten am Ende in der 22Mio Monsterdatei hinterher eigentlich nicht mehr enthalten sein. Aber das ist ein weiterer Schritt denke ich...

Bis hier her bin ich aber auch schon einen grossen Schritt weiter, tausend dank schon jetzt!

LG nach Bremen,
ningiser
Member: Biber
Biber Mar 20, 2009 at 17:38:16 (UTC)
Goto Top
Moin ningiser,

na siehst Du... und wir haben noch keine einzige Rnd() oder Zufallszahl()-Methode gebraucht und kein Byte Batch oder VBScript oder #.net-Geraffel.

Punkte werden im Findstring als "Joker" verwendet, richtig?
Yepp.
Wie kann ich dann nach Punkten, die die Nachkommastellen in der Textdatei definieren suchen lassen, oder geht das nicht?
Oder-Fragen beantworte ich immer mit "Selbstverständlich." oder "Auf keinen Fall."
Aber weniger haarspalterisch: nach "Punkt"en im Text kannst Du auch suchen, wenn Du sie maskierst mit einem vorangestellten "\"

--> findstr "12.34" --> sucht nach "12"-ein beliebiges Zeichen-"34"
--> findstr "12\.34" --> sucht nach "12.34"
--> findstr "1.\..4" --> sucht nach "1"-ein beliebiges Zeichen-Punkt-ein beliebiges Zeichen-"4"
Super waere es, wenn ich die von mir vorgegebenen Nachkommastellen durch einzelne Zufallsziffern ersetzen koennte...
Mach doch. Am Cmd-Prompt hast Du dafür %random%--> siehe Hilfe "Set /?" oder "cmd /?"
Oder Forumssuche im Bereich Batch & Shell nach "random" oder "Zufallszahl"
Ach ja, und die herausgelesenen Zeilen sollten am Ende in der 22Mio Monsterdatei hinterher eigentlich nicht mehr enthalten sein.
Weil....?????
Muss doch nicht. Wir können die auch logisch ausschliessen statt physisch.
Alle Zeilen, die "logisch" nicht mehr dazugehören, haben wir doch in der kleineren "minimonster.txt".
Was brauchen wir mehr.

[Aber: wenn es partout sein müsste: Einfach den vorher verwendeten FindStr-Befehl, der in die "minimonster.txt" umgelenkt wurde, nochmals verwenden mit Parameter /v [Alle Zeilen, die NICHT enthalten..] und umlenken in "MonsterMinus3000.txt"
Ist aber IMHO Dönekens.
]

Was ich nicht aus dem Kopf beantworten kann ist die Frage nach den TABs... keine Ahnung.
Könnte sich auch maskieren lassen... hab ich noch nie versucht.

Vielleicht liest einer mit, der es mal gebraucht hat und weiss, wie es geht.

Grüße
Biber
Member: ningiser
ningiser Mar 20, 2009 at 18:34:12 (UTC)
Goto Top
Ja, super! Tausen Dank!

Nicht mehr weit und wir können einen Haken dran machen!!!

Das mit dem Tabs kann man vielleicht umgehen, indem man erst nach bestimmten Nachkommastellen in den X-Werten sucht, die in die minimonsterdatei schreibt und dann die minimonsterdatei noch einmal nach Nachkommasellen der Y-Koordinate zu durchsuchen...

So, jetzt schaue ich mal nach den Zufallszahlen und dann sehn wir weiter...
Member: Biber
Biber Mar 20, 2009 at 19:23:20 (UTC)
Goto Top
Moin ningiser,

noch ein winziger Nachtrag zu der "Suche nach Tabs"
Geht nicht wirklich/wirklich nicht, aber lässt sich umgehen..

findstr "58....\.330.684....\.330" m:\eine\Monsterdatei.csv  
... --> soll heißen: nach dem "330" darf genau EIN Zeichen folgen (unser <tab> ) dann werden gefunden:
>findstr "58....\.330.684....\.330" m:\eine\Monsterdatei.csv  
581234.330      6840000.330
582345.330      6849999.330

Sollte reichen, weil ja alle anderen Postionen durch die beiden Dezimal-Punkte "\." eindeutig verankert sind.

Grüße & schönes Wochenende
Biber