Okey versuche es morgen mal mit pandas. Natürlich brauche ich nicht nur eine einzige Zeile, sondern wie ich schon sagte jede Sekunde eine Zeile meist eine andere aus der selben Datei. Dabei kann es vorkommen, dass ich eine andere Datei brauche, welche ich dann bei Bedarf einlese um mit dieser zu arbeiten. Alle 30 Dateien bei Start einlesen halte ich etwas für unsinnig, da ich ja meist nur 3-4 brauche. Dies meine Überlegung wegen Speicherresourcen oder wäre das Nullproblemo? Habe mich mit Speichergrösse, -platz nie befasst. (eine Datei hat 118MB) Die werden in den Arbeitspeicher gelanden - oder? Und jenachdem wieviel Arbeitsspeicher ich halt habe, klappt es oder nicht?
Bestimmte Zeile (Zeilennummer) in Textdatei lesen
drei bis vier Dateien im Speicher zu halten, ist heutzutage kein Problem mehr. Wenn die x und y-Werte so regelmäßig sind, dann braucht man die gar nicht. Damit brauchen alle 30 Dateien nicht mal ein Gigabyte.
Zudem speichert man die Daten binär, dann ist es völlig egal ob die Dateien als Memory-mapped Files in den Speicher passen, oder nicht.
Zudem speichert man die Daten binär, dann ist es völlig egal ob die Dateien als Memory-mapped Files in den Speicher passen, oder nicht.
Die Dateien in der Grösse selbst zu optimieren habe ich auch schon gedacht.
Ich bekomme diese von extern und habe keinen Einfluss darauf wie sie erstellt werden. Darum wollte ich sie im ersten Schritt mal unverändert lassen.
Ich bekomme diese von extern und habe keinen Einfluss darauf wie sie erstellt werden. Darum wollte ich sie im ersten Schritt mal unverändert lassen.
Hallo zusammen,
ich finde das Thema gerade spannend und habe mal vier Wege getestet, wie man eine bestimme Zeile in der Koordinaten-Datei auslesen kann und habe auch dazu die Zeiten gestoppt.
Das Ergebnis ist:
- Mit pandas dauert es am längsten.
- Die Suchdauer hängt wesentlich ab von
-- der Position, an der sich die gesuchte Zeilennummer befindet
-- ob pandas oder itertools verwendet werden
Bsp.:
Pandas vs. itertools
Datei: 8.000.000 Zeilen, letzte Zeile suchen: 12 sec vs. 1,08 sec
Datei: 8.000.000 Zeilen, 4.000.000. Zeile suchen: 12 sec vs. 0,55 sec
Vor dem Programmlauf habe ich jeweils den Kernel neu gestartet.
Natürlich kommt es immer darauf an, was man später mit den Daten machen will. Aber ein DataFrame mit pandas zu erzeugen, wenn man „nur“ eine Zeile braucht, scheint mir mit Kanonen auf Sparten zu schießen, oder?
Die in den Programmen angegebenen Zeiten (im Kommentar) beziehen sich auf die Suche der letzten Zeile in einer 4.000.000 Zeilen großen Datei.
ich finde das Thema gerade spannend und habe mal vier Wege getestet, wie man eine bestimme Zeile in der Koordinaten-Datei auslesen kann und habe auch dazu die Zeiten gestoppt.
Das Ergebnis ist:
- Mit pandas dauert es am längsten.
- Die Suchdauer hängt wesentlich ab von
-- der Position, an der sich die gesuchte Zeilennummer befindet
-- ob pandas oder itertools verwendet werden
Bsp.:
Pandas vs. itertools
Datei: 8.000.000 Zeilen, letzte Zeile suchen: 12 sec vs. 1,08 sec
Datei: 8.000.000 Zeilen, 4.000.000. Zeile suchen: 12 sec vs. 0,55 sec
Vor dem Programmlauf habe ich jeweils den Kernel neu gestartet.
Natürlich kommt es immer darauf an, was man später mit den Daten machen will. Aber ein DataFrame mit pandas zu erzeugen, wenn man „nur“ eine Zeile braucht, scheint mir mit Kanonen auf Sparten zu schießen, oder?
Die in den Programmen angegebenen Zeiten (im Kommentar) beziehen sich auf die Suche der letzten Zeile in einer 4.000.000 Zeilen großen Datei.
Code: Alles auswählen
with open ("Koordinaten.txt","w") as outputfile:
for i in range (0,4000000):
print("2624000.25 1133999.75 1121.99",file=outputfile)
Code: Alles auswählen
from time import time
import pandas as pd
# pandas Version 0.23.4
t1 = time()
df = pd.read_csv('Koordinaten.txt',delimiter=" ",header=None)
print (df.iloc[[399999],:])
print (time()-t1)
# t=6.094815254211426
Code: Alles auswählen
from itertools import islice
from time import time
t1 = time()
with open ("Koordinaten.txt","r") as file:
print (list(islice(file,3999998,3999999,)))
#print (str(l))
file.close()
print (time()-t1)
#t=0.556002140045166
Code: Alles auswählen
from time import time
t1 = time()
with open ("Koordinaten.txt","r") as file:
n=0
for line in file:
n +=1
if n == 3999999:
print(line,end="")
file.close()
print (time()-t1)
#t=0.8531761169433594
Code: Alles auswählen
from time import time
t1 = time()
with open("Koordinaten.txt","r") as file:
for n, value in enumerate(file):
if n == 3999999:
print (value, end="")
file.close()
print (time()-t1)
#t=0.8580334186553955
@heyJo: Du vergleichst Äpfel mit Birnen. Das macht höchstens bei Obstsalat Sinn. Pandas tut viel mehr als nur Zeilenendenzeichen zu zählen und zu verwerfen, was vorher in der Datei steht. Pandas vorher zu sagen, was in den Spalten steht sollte schon gehörig Schub bringen, denn du lässt es ja hier seine Magie anwenden.
So schwierig ist die Beschreibung doch nun nicht: Du bekommst also jede Sekunde Koordinaten. Der erste Schritt ist es, aus den Koordinaten die Kachel zu berechnen, dann die Kachel zu laden und darin den Index zu berechnen, wo Du den z-Wert findest.
Um effektiv auf die Arrays zugreifen zu können, müssen sie im Arbeitsspeicher liegen. Da sich die Topologiedaten nicht sehr häufig ändern, macht es schon Sinn, die in ein passendes Format zu konvertieren, um effektiv damit arbeiten zu können.
Dann kann man sie ohne weiteres komplett in den Speicher mappen:
Und beliebig darauf zugreifen:
Um effektiv auf die Arrays zugreifen zu können, müssen sie im Arbeitsspeicher liegen. Da sich die Topologiedaten nicht sehr häufig ändern, macht es schon Sinn, die in ein passendes Format zu konvertieren, um effektiv damit arbeiten zu können.
Code: Alles auswählen
import numpy
TILE_FILENAME_CSV = "topologie_{:03d}.csv"
TILE_FILENAME_BIN = "topologie_{:03d}.bin"
def convert_tile(tile_number):
with open(TILE_FILENAME_CSV.format(tile_number)) as lines:
data = numpy.array([l.split() for l in lines], dtype=float)
data.tofile(TILE_FILENAME_BIN.format(tile_number)
Code: Alles auswählen
tiles = [
numpy.memmap(TILE_FILENAME_BIN.format(tile_number), dtype=float).reshape(-1, 3)
for tile_number in range(30)
]
Code: Alles auswählen
print(tiles[17, 3242])
@sparrow
Mir ist schon klar, dass pandas ein mächtiges Werkzeug ist. Wenn es allerdings "nur" darum geht eine einzelne Zeil/ Information zu extrahieren, finde ich es zu schwerfällig.
Mir ist schon klar, dass pandas ein mächtiges Werkzeug ist. Wenn es allerdings "nur" darum geht eine einzelne Zeil/ Information zu extrahieren, finde ich es zu schwerfällig.
Mit meinem Wissen habe ich nur den Code hier hin bekommen; der ist aber noch langsamer ...
Code: Alles auswählen
from time import time
import pandas as pd
import numpy as np
# pandas Version 0.23.4
t1 = time()
df = pd.read_csv('Koordinaten.txt',delimiter=" ",header=None,names=("x","y","z"),converters={'x':np.float32,'y':np.float32,'z':np.float32})
print (df.iloc[[399999],:])
print (time()-t1)
# ohne np t=6.094815254211426
# mit np t=8.270103693008423
- MaximalMax
- User
- Beiträge: 18
- Registriert: Sonntag 3. Mai 2020, 00:51
Die Lösung kann man ohne jegliche Imports lösen. Hier ist mein Code, der funktioniert.
Du öffnest erstmal die Datei mittels des With-Statements, dann wird abgefragt, welche Zeile du willst.
Dann wird das -1 gerechnet, da eine Liste immer bei 0 und nicht bei 1 anfängt.
Dann wird die For-Schleife genutzt um alle Werte, aller Zeilen zu speicher und die werden alle in die Liste eingetragen.
Dann gibt man in einem try die einzelne Zeile aus und wenn man eine zu große Zeilen-Nummer auswählt, dann wird im except einfach ein "Error" ausgegeben
Mit freundlichen, Max
PS: Viel Spaß beim weiteren Programmieren!
Du öffnest erstmal die Datei mittels des With-Statements, dann wird abgefragt, welche Zeile du willst.
Dann wird das -1 gerechnet, da eine Liste immer bei 0 und nicht bei 1 anfängt.
Dann wird die For-Schleife genutzt um alle Werte, aller Zeilen zu speicher und die werden alle in die Liste eingetragen.
Dann gibt man in einem try die einzelne Zeile aus und wenn man eine zu große Zeilen-Nummer auswählt, dann wird im except einfach ein "Error" ausgegeben
Code: Alles auswählen
with open('test.txt') as file:
zeile = int(input("Zeile: "))
zeile = zeile - 1
liste = []
for line in file:
liste += [line.strip()]
try:
print(liste[zeile])
except:
print("Diese Datei hat nicht so viele Zeilen")
![Very Happy :D](./images/smilies/icon_biggrin.gif)
PS: Viel Spaß beim weiteren Programmieren!
Genau - da haben wir uns voll richtig verstandenSirius3 hat geschrieben: ↑Donnerstag 1. Oktober 2020, 09:17 So schwierig ist die Beschreibung doch nun nicht: Du bekommst also jede Sekunde Koordinaten. Der erste Schritt ist es, aus den Koordinaten die Kachel zu berechnen, dann die Kachel zu laden und darin den Index zu berechnen, wo Du den z-Wert findest.
![Smile :-)](./images/smilies/icon_smile.gif)
Wenn ich das richtig verstehe, ist das aus der Dateinummer 17, die Zeilennummer 3242 - oder???Und beliebig darauf zugreifen:Code: Alles auswählen
print(tiles[17, 3242])
Aber müsste wohl so sein?
Code: Alles auswählen
print(tiles[17][3242])
@MaximalMax: Nackte Excepts sind keine gute Idee, weil sie _alle_ Ausnahmen schlucken, ohne eine Hinweis darauf zu geben, was schief gelaufen ist. Vertippst du dich innerhalb des try-Blocks, wirst du den Fehler ewig suchen, weil du nicht darauf hingewiesen wirst. Dein Programm geht dann immer davon aus, dass es nicht genug Zeilen waren. Deshalb gilt: Nur die Exceptions fangen, die man auch erwartet.
@MaximalMax: es ist sehr umständlich, um ein Element an eine Liste anzufügen, dafür extra eine neue Liste mit einem Element zu erzeugen. Statt dessen benutzt man append.
Du erwartest, wenn die Zeile nicht existiert einen IndexError.
Du erwartest, wenn die Zeile nicht existiert einen IndexError.
- MaximalMax
- User
- Beiträge: 18
- Registriert: Sonntag 3. Mai 2020, 00:51
Hoffe das hilftMaximalMax hat geschrieben: ↑Donnerstag 1. Oktober 2020, 12:44 Die Lösung kann man ohne jegliche Imports lösen. Hier ist mein Code, der funktioniert.
Du öffnest erstmal die Datei mittels des With-Statements, dann wird abgefragt, welche Zeile du willst.
Dann wird das -1 gerechnet, da eine Liste immer bei 0 und nicht bei 1 anfängt.
Dann wird die For-Schleife genutzt um alle Werte, aller Zeilen zu speicher und die werden alle in die Liste eingetragen.
Dann gibt man in einem try die einzelne Zeile aus und wenn man eine zu große Zeilen-Nummer auswählt, dann wird im except einfach ein "Error" ausgegeben
Mit freundlichen, MaxCode: Alles auswählen
with open('test.txt') as file: zeile = int(input("Zeile: ")) zeile = zeile - 1 liste = [] for line in file: liste += [line.strip()] try: print(liste[zeile]) except: print("Diese Datei hat nicht so viele Zeilen")
![]()
PS: Viel Spaß beim weiteren Programmieren!
![Very Happy :D](./images/smilies/icon_biggrin.gif)
Hallo zusammen
Ich habe das Ganze nun umgesetzt - noch nicht ganz fertig (GPS funktioniert, Topodaten lesen funktioniert - nun nur noch beides verheiraten und testen.
Vielen Dank für eure Inputs und Ideen!
Ich habe mich schlussendlich für die Variante von Sirius3 entschieden viewtopic.php?f=1&t=49740&start=15#p373772
Alle 30 Binärdateien laden und eine der letzen Wert (Zeilen) suchen in weniger als 20ms, danach kanns nur noch schneller werden weil ja die Daten im Speicher sind.
Vielleicht hat noch jemand Lust mir die folgende Zeile zu erklären. Verstehe ich nicht. Dok nachgelesen --> trotzdem nicht verstanden. Ev. kanns jemand kurz und einfach erklären.
Was macht "reshape(-1, 3)" genau und warum -1, 3
Danke nochmals!
Ich habe das Ganze nun umgesetzt - noch nicht ganz fertig (GPS funktioniert, Topodaten lesen funktioniert - nun nur noch beides verheiraten und testen.
Vielen Dank für eure Inputs und Ideen!
Ich habe mich schlussendlich für die Variante von Sirius3 entschieden viewtopic.php?f=1&t=49740&start=15#p373772
Alle 30 Binärdateien laden und eine der letzen Wert (Zeilen) suchen in weniger als 20ms, danach kanns nur noch schneller werden weil ja die Daten im Speicher sind.
Vielleicht hat noch jemand Lust mir die folgende Zeile zu erklären. Verstehe ich nicht. Dok nachgelesen --> trotzdem nicht verstanden. Ev. kanns jemand kurz und einfach erklären.
Was macht "reshape(-1, 3)" genau und warum -1, 3
Code: Alles auswählen
numpy.memmap(TILE_FILENAME_BIN.format(tile_number), dtype=float).reshape(-1, 3)
Zuerst hast du nur einen großen Speicherbereich, mit vielen Zahlen. Du willst aber immer drei Zahlen als eine Zeile in der Matrix haben. Daher wird die Form (shape) der Matrix mit beliebig viele Zeilen (-1) und drei Spalten angegeben.
Hallo
Meine Anwendung läuft. Aber.... Probleme mit Speicher:
Auf eine Latte-Panda mit WIN10 läuft die Anwendung mit 30 Tiles (diese haben ca. 2.7 GB) --> soweit so gut.
Nun möchte ich die selbe Anwendung auch auf dem Raspberry mit "Raspberry Pi OS" laufen lassen.
Ich habe einen 8GB RPi4. Bei 30 Tiles kommt unten stehende Fehlermeldung. Bei 15 klappt es noch.
Wenn ich im Taskmanager schaue, nachdem die 15 Tiles geladen sind, sind "nur" etwa 225MB belegt und etwa 7875 frei, also genügend Arbeitsspeicher frei ?!?!?!?!
Werden die Tiles nicht in diesen Arbeitsspeicher geladen?
Jemand eine Idee woran das liegt?
Meine Anwendung läuft. Aber.... Probleme mit Speicher:
Auf eine Latte-Panda mit WIN10 läuft die Anwendung mit 30 Tiles (diese haben ca. 2.7 GB) --> soweit so gut.
Nun möchte ich die selbe Anwendung auch auf dem Raspberry mit "Raspberry Pi OS" laufen lassen.
Ich habe einen 8GB RPi4. Bei 30 Tiles kommt unten stehende Fehlermeldung. Bei 15 klappt es noch.
Wenn ich im Taskmanager schaue, nachdem die 15 Tiles geladen sind, sind "nur" etwa 225MB belegt und etwa 7875 frei, also genügend Arbeitsspeicher frei ?!?!?!?!
Werden die Tiles nicht in diesen Arbeitsspeicher geladen?
Jemand eine Idee woran das liegt?
Code: Alles auswählen
self.tiles = [numpy.memmap(TILE_FILEPATH_BIN + self.bin_filenames[file_nr], dtype=float, mode='r').reshape(-1, 3) for file_nr in range(len(self.bin_filenames))]
File "/usr/lib/python3/dist-packages/numpy/core/memmap.py", line 264, in __new__
mm = mmap.mmap(fid.fileno(), bytes, access=acc, offset=start)
OSError: [Errno 12] Nicht genügend Hauptspeicher verfügbar