Dataframe zeilenweise bearbeiten

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
Stephan12
User
Beiträge: 24
Registriert: Mittwoch 29. Januar 2014, 14:52

Hallo,

ich suche nach irgend einem Befehl, mit dem man
Dataframes zeilenweise bearbeiten kann,
sowas wie
from i=1 to len(dataframe) do
dataframe.firstcolumn=irgendwas
dataframe.secondcolumn=irgendwas
end

Scheinbar gibts diese Kontrollstruktur in Python aber gar nicht.
Mit for each Zeile in dataframe
passieren seltsame Sachen, der ganze Dataframe wird dann mehrmals durchgekämmt.

Wie muss kann so eine zeilenweise Bearbeitung machen?
BlackJack

@Stephan12: Was willst Du denn eigentlich machen? Eine ``for``-Schleife in Python über ein `numpy`-Array ist eigentlich immer nur die letzte Lösung wenn man es nicht mit Methoden und Funktion hinbekommt die `numpy` und `panda` bieten. Und eine ``for``-Schleife die über den Umweg eines Index auf fortlaufende Elemente einer Sequenz zugreifen ist in Python ein „anti pattern”.

``for each Zeile in dataframe`` ist keine gültige Python-Syntax weil es kein ``each``-Schlüsselwort gibt. Jede ``for``-Schleife in Python ist das was in anderen Sprachen ``for each``-Schleife heisst. Beim `dataframe` sind die Elemente über die man so iterieren kann aber nicht die Zeilen sondern die Namen der Spalten.
Stephan12
User
Beiträge: 24
Registriert: Mittwoch 29. Januar 2014, 14:52

Ich habe einen Dataframe, in dem in einer Spalte Datumsangaben stehen.
Diese will ich auf das Vorhandensein des dritten Samstags im Monat prüfen
und wenn das der Fall ist, diese Zeilen des gesamten Dataframes behalten, den Rest
verwerfen. Ich habe eine Funktion geschrieben, die für einen gegebenen Monat
und Jahr den 3. Samstag errechnet und mit dem Datumswert des
gerade abzuarbeitenden Elements in der Dataframespalte vergleicht.
Dann sollte jeweils true oder false rauskommen und aus diesen Werten entweder
eine neue Dataframespalte erzeugt oder gleich die betreffende Zeile
im Dataframe herausgefiltert werden. Ich hab das bisher mit den implementierten vektoriellen Pandasfunktionen
nicht hinbekommen und wollte es deshalb inkrementell lösen, also Zeile für Zeile in der Datumsspalte prüfen und Aktionen
in der betreffenden Dataframezeile durchführen.
BlackJack

@Stephan12: Wenn Du eine Funktion hast die pro Datumswert Wahr/Falsch liefert, dann kannst Du die auf die Datumswerte mit der `map()`-Funktion anwenden und das resultierende Array als Index in den gesamten Datenframe verwenden. Mal an einem einfachen Beispiel mit einem Datenframe mit Zufallszahlen in den Spalten 'x' und 'y' und einer Spalte 'datum' in der ein ganzes Jahr an Daten stehen. Dass die Werte in dieser Spalte alle einmalig, regelmässig aufsteigend, und sortiert sind ist für den Vorgang nicht wichtig. War halt einfach die so zu generieren. :-) pd == pandas:

Code: Alles auswählen

In [154]: d
Out[154]: 
<class 'pandas.core.frame.DataFrame'>
Int64Index: 365 entries, 0 to 364
Data columns (total 3 columns):
x        365  non-null values
y        365  non-null values
datum    365  non-null values
dtypes: datetime64[ns](1), float64(2)

In [155]: d.datum.map(pd.datetools.WeekOfMonth(week=3, weekday=5).onOffset)
Out[155]: 
0     False
1     False
2     False
3     False
4     False
5     False
6     False
7     False
8     False
9     False
10    False
11    False
12    False
13    False
14    False
...
350    False
351    False
352    False
353    False
354    False
355    False
356    False
357    False
358    False
359    False
360     True
361    False
362    False
363    False
364    False
Name: datum, Length: 365, dtype: bool

In [156]: d[d.datum.map(pd.datetools.WeekOfMonth(week=3, weekday=5).onOffset)]
Out[156]: 
             x          y               datum
24   62.134000  65.927203 2014-01-25 00:00:00
52   80.218566  98.210317 2014-02-22 00:00:00
80   38.208752  96.189346 2014-03-22 00:00:00
115  82.704522  50.556027 2014-04-26 00:00:00
143  82.406230  40.177194 2014-05-24 00:00:00
178  38.855840  44.012386 2014-06-28 00:00:00
206  13.145839  60.348764 2014-07-26 00:00:00
234  50.999593  52.372542 2014-08-23 00:00:00
269  93.140144  48.018650 2014-09-27 00:00:00
297  45.916681  18.412948 2014-10-25 00:00:00
325  69.603523  26.544856 2014-11-22 00:00:00
360  69.541351  14.857823 2014-12-27 00:00:00
Stephan12
User
Beiträge: 24
Registriert: Mittwoch 29. Januar 2014, 14:52

Wow, das funktioniert bei mir so, das hab ich allein mit einem ganzen Tag Probiererei nicht hinbekommen.
Allerdings hab ich Schwierigkeiten, die Syntax zu verstehen.

Wie kann man z.B. die Funktion pd.datetools.WeekOfMonth(week=3, weekday=5).onOffset auf ein einzelnes
Pandas Datetime-Objekt anwenden? Ich hab das nicht hinbekommen. Ich hatte nicht mal eine Doku gefunden,
daß man .onOffset true ausgeben kann, wenn das WeekofMonth-Kriterium erfüllt ist.

Vorher hatte ich folgendes probiert:
filterframe=frame[frame.eins.isin(verfallstage)]
verfallstage war hierbei ein pandas.date_range

der filterframe war dann leer, obwohl etwas hätte drin stehen müssen. Evtl. wegen unterschiedlicher Datumsformate o.ä.

Zum Thema map(): Wie kann man hier eine Funktion implementieren, deren Inputs abhängig sind von den (unterschiedlichen)
Zahlen der Dataframezeilen?
z.B. Dataframe mit

'Spalte'
1 01.01.2010
2 02.01.2010

und der Funktion testfunktion(Spalte.month, Spalte.day)
BlackJack

@Stephan12: Bei der Pandas-Dokumentation muss man wohl zwingend interaktiv die Objekte selbst inspizieren. Eine Erweiterte Python-Shell wie IPython oder bpython ist dabei recht nützlich. Auf `onOffset()` bin ich gekommen in dem ich mir live angeschaut hatte was diese Objekte so alles bieten. Sonst hätte ich mir nämlich mit den ”dokumentierten”¹ `rollback()` und `rollforward()` so etwas gebastelt.

Die `onOffset()`-Methode kann man auf ein einzelnes Objekt anwenden in dem man sie einfach aufruft und dabei das Objekt als Argument übergibt. Wenn man das mehrfach vorhat, beziehungsweise das in einem Programm verwendet welches man auch nach einem Jahr noch einfach verstehen möchte, sollte man die Methode vielleicht vorher an einen sprechenden Bezeichner binden, damit der Leser einfacher erfassen kann was da passiert:

Code: Alles auswählen

In [159]: t1, t2
Out[159]: 
(Timestamp('2014-01-01 00:00:00', tz=None),
 Timestamp('2014-12-27 00:00:00', tz=None))

In [160]: pd.datetools.WeekOfMonth(week=3, weekday=5).onOffset(t1)
Out[160]: False

In [161]: pd.datetools.WeekOfMonth(week=3, weekday=5).onOffset(t2)
Out[161]: True

In [162]: is_third_saturday_of_month = pd.datetools.WeekOfMonth(week=3, weekday=5).onOffset

In [163]: is_third_saturday_of_month(t1)
Out[163]: False

In [164]: is_third_saturday_of_month(t2)
Out[164]: True
Zur letzten Frage: Das geht gar nicht. Ich sehe aber auch nicht warum man das brauchen sollte, denn man kann den Wert aus der Spalte ja *in* der Funktion nach Monat und Tag fragen.

______
¹ Die Methoden werden im Fliesstext erwähnt sind aber nicht im Index zu finden.
Stephan12
User
Beiträge: 24
Registriert: Mittwoch 29. Januar 2014, 14:52

BlackJack hat geschrieben:@Stephan12:

Zur letzten Frage: Das geht gar nicht. Ich sehe aber auch nicht warum man das brauchen sollte, denn man kann den Wert aus der Spalte ja *in* der Funktion nach Monat und Tag fragen.
Ich hätte das gebraucht z.B. für den Fall, daß es nicht sowas wie WEEKOFMONTH.onoffset() gibt.
Meine Funktion hätte dann als als Input Monat und Tag aus allen Datumswerten in der Datumsspalte
rausziehen und dann einen boolschen Wert berechnen müssen. Das hätte ich dann wohl irgendwie versucht,
mit map zu implementieren, um nicht über die ganze Spalte iterieren zu müssen.
Ich wüsste zwar, wie ich einen einzelnen Wert aus der Datumsspalte auswerte (mit Datumsspalte[Index])
aber wie das mit map() für alle Einträge funktioniert, wüsste ich nicht.

Mal noch ne ganz andere Pandas-Frage:
Ich will aus nem Dataframe nen Pivot-Table machen und auch die Daten im Index bei rows[] und colums[] im Pivot mit verwenden.
Wie geht das? Konnte ich auch nirgendwo finden.
Antworten