pd Dataframe als Queue: Wie bekommt man das am effizientesten hin? Alternativen?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
CptK
User
Beiträge: 7
Registriert: Sonntag 16. Januar 2022, 12:04
Wohnort: Darmstadt

Hallo, ich habe eine Klasse, die ein Pandas-Dataframe verwaltet. Index ist die Spalte 'time' vom Typ datetime. Das Dataframe hat eine maximale Größe, die über __init__ gesetzt wird.

Code: Alles auswählen

class TimeDataManager():
    def __init__(self, max_size):
        self.max_size = max_size
        self.data = pd.DataFrame(columns=["time", "...", "...", "...",])
        self.data.set_index("time", inplace=True)
In einer Methode "push" wird eine Zeile übergeben und vorne (also Index = 0) an das Dataframe angehängt, diese Methode folgt dabei diesem Schema:
- Ist die Zeit der neuen Zeile gleich der Zeit der aktuellen Zeile mit Index 0: entferne die Zeile mit Index 0 (diese wird durch die neue ersetzt)
- Entferne am Ende des Dataframes so viele Zeilen, dass nur noch max_size - 1 übrig sind
- füge die neue Zeile vorne an

Code: Alles auswählen

def push(self, row: pd.DataFrame):
        assert len(row) == 1
        self.data.reset_index(inplace=True)

        if(len(self.data) > 0 and row.iloc[0]['time'] == self.data.at[0, 'time']):
            self.data = self.data.tail(self.max_size - 1)

        self.data = self.data.head(self.max_size - 1)
        self.data = pd.concat([row, self.data], ignore_index=True)
        self.data.set_index("time", inplace=True)
Da meine Index-Spalte vom Typ datetime ist, ich aber mit den Indizes arbeiten will muss ich jedesmal erst reset_index aufrufen und nach der Bearbeitung set_index, da ich iloc/loc so nicht verwenden kann (korrekt?). Ich wäre allerdings auch nicht abgeneigt zu sagen, dass ich auf time als Index verzichte und index als int definiere. Allerdings bekomme ich das nicht hin, da durch das ständige Zeilen hinzufügen (diese neuen Zeilen haben jeweils einen int als Index und zwar immer 0) die Numerierung nicht richtig passt, bzw. immer irgendwelche Spalten "index" bzw. "level_0" eingefügt werden, bis das Programm mit einem Fehler abbricht. Insgesamt habe ich jedenfalls das Gefühl, dass meine jetzige Implementierung zwar tut was sie soll., dabei aber nicht sonderlich effizient ist. Gleiches gilt für folgende zwei Methoden:

Code: Alles auswählen

def to_dict(self, index) -> dict:
    """Returns the values of the row with the specified index as dict. \n
        Input:
            index -- The row-index of data that will be returned. It must be >= 0 and < len(data)."""
    assert index >= 0 and index < len(self.data)
    res = self.data[index:index+1].reset_index()
    return res.to_dict('records')[0]

def at(self, index, field):
    """Returns the value in column field of the row with the specified index. \n
        Input:
            index -- The row-index of data that will be returned. It must be >= 0 and < len(data).\n
            field -- The column name from which the value should be returned. """
    return self.to_dict(index)[field]
Insgesamt würde das vermutlich alles durch einen int-index und die Möglichkeit Zeilen per iloc zu bekommen verbessert werden. Allerdings bekomme ich das - wie schon erwähnt - nicht hin.
Eine zweite Frage die sich mir stellt ist, ob der Ansatz mittels pd.DataFrame überhaupt der Richtige ist, oder ob ich das nicht lieber komplett anders umsetzten sollte.

Vielen Dank
Sirius3
User
Beiträge: 18279
Registriert: Sonntag 21. Oktober 2012, 17:20

Ein Dataframe ist keine Queue, das als solche zu verwenden, ist sehr ineffizient.
Warum nimmst Du ein Dataframe und nicht eine deque, die dafür geeignet ist.
Antworten