Seite 1 von 1

Apply function to every different row of a column

Verfasst: Donnerstag 22. August 2019, 22:28
von BroNKo
Guten Abend, eine Anfängerfrage. Folgender Code

Code: Alles auswählen

df_con.IsX.apply(lambda x: i_delta(x))
Im Moment wird die Funktion auf alle rows des DF angewendet. Was wäre die einfachste Methode um zu gewährleisten das die Funktion nur auf rows angewendet wird die einen verschiedenen Wert haben der im column noch nicht vorkam?

Hätte noch eine andere Frage zur Ausgabe, wenn ich z.B. folgenden Code ausführe

Code: Alles auswählen

df_con.IsX.value_counts()
dann wird mir ja eine Tabelle ausgegeben mit einem column in dem die Werte aus IsX stehen und einem column mit der Anzahl. Wenn ich aber das erste Codebeispiel ausführe wird in der Ausgabe nicht die Ursprüngliche Code ausgegeben sondern nur ein column mit den Rückgabewerten der Funktion. Wie kann ich aber die Ursprünglichen werte in einem column und die Rückgabewerte in einem zweiten ausgeben lassen? Hoffe man versteht was ich meine.

--> Ausgabe im Moment

Column1
Rückgabewert1
Rückgabewert2
Rückgabewert3

--> Gewünschte Ausgabe

Column1 Column2
Wert1 Rückgabewert1
Wert2 Rückgabewert2
Wert3 Rückgabewert3

Danke schonmal für Hilfe! lg

Re: Apply function to every different row of a column

Verfasst: Freitag 23. August 2019, 00:33
von __blackjack__
Man kann mit `duplicated()` auf dem `Series`-Objekt ein `Series`-Objekt bekommen das `False` bei jedem zum ersten mal gesehenen Wert liefert und `True` sonst. Du willst eigentlich das Gegenteil — die Werte die das erste mal gesehen wurden, also mit ``~`` negieren und als Index in das `Series`-Objekt verwenden. Und auf dem Ergebnis kannst Du dann Dein `apply()` aufrufen.

Beispiel mit einem Satz von 100 Zufallswerten zwischen 1 und 10:

Code: Alles auswählen

In [30]: df                                                                     
Out[30]: 
     x
0    6
1    1
2    6
3    9
4    3
5    9
6    4
7    7
8    4
9    3
10   4
11   3
12   8
13   2
14   2
15   3
16  10
17   7
18   6
19   5
20   9
21  10
22   4
23   6
24   2
25   5
26   4
27   8
28   3
29   6
..  ..
70  10
71   6
72   6
73   4
74   5
75   3
76  10
77   8
78   1
79   2
80   1
81   7
82   1
83   1
84   9
85   1
86  10
87   9
88   2
89   8
90   1
91  10
92   7
93   2
94   4
95   4
96   2
97   6
98   1
99   5

[100 rows x 1 columns]

In [31]: df.x.duplicated()                                                      
Out[31]: 
0     False
1     False
2      True
3     False
4     False
5      True
6     False
7     False
8      True
9      True
10     True
11     True
12    False
13    False
14     True
15     True
16    False
17     True
18     True
19    False
20     True
21     True
22     True
23     True
24     True
25     True
26     True
27     True
28     True
29     True
      ...  
70     True
71     True
72     True
73     True
74     True
75     True
76     True
77     True
78     True
79     True
80     True
81     True
82     True
83     True
84     True
85     True
86     True
87     True
88     True
89     True
90     True
91     True
92     True
93     True
94     True
95     True
96     True
97     True
98     True
99     True
Name: x, Length: 100, dtype: bool

In [32]: ~df.x.duplicated()                                                     
Out[32]: 
0      True
1      True
2     False
3      True
4      True
5     False
6      True
7      True
8     False
9     False
10    False
11    False
12     True
13     True
14    False
15    False
16     True
17    False
18    False
19     True
20    False
21    False
22    False
23    False
24    False
25    False
26    False
27    False
28    False
29    False
      ...  
70    False
71    False
72    False
73    False
74    False
75    False
76    False
77    False
78    False
79    False
80    False
81    False
82    False
83    False
84    False
85    False
86    False
87    False
88    False
89    False
90    False
91    False
92    False
93    False
94    False
95    False
96    False
97    False
98    False
99    False
Name: x, Length: 100, dtype: bool

In [33]: df.x[~df.x.duplicated()]                                               
Out[33]: 
0      6
1      1
3      9
4      3
6      4
7      7
12     8
13     2
16    10
19     5
Name: x, dtype: int64

In [34]: df.x[~df.x.duplicated()].apply(lambda x: -x)                           
Out[34]: 
0     -6
1     -1
3     -9
4     -3
6     -4
7     -7
12    -8
13    -2
16   -10
19    -5
Name: x, dtype: int64
Bei Deinem Code ist übrigens das ``lambda`` überflüssig wenn das nur dazu dient das Argument 1:1 an die tatsächliche Funktion durchzureichen.

Die zweite Frage verstehe ich nicht, denn Du bekommst doch ein `Series`-Objekt und das hat einen Index, und der Index sind genau die Werte die Du gerne hättest:

Code: Alles auswählen

In [35]: df.x.value_counts()                                                    
Out[35]: 
8     14
1     12
4     11
10    10
7     10
3     10
2     10
9      9
6      8
5      6
Name: x, dtype: int64

Re: Apply function to every different row of a column

Verfasst: Freitag 23. August 2019, 11:46
von BroNKo
Danke für die ausführliche Anwort. Zu meiner zweiten Frage.

Code: Alles auswählen

df_temp = pd.DataFrame()
df_temp = (df_con.IsX[~df_con.IsX.duplicated()])
df_temp['VoX'] = df_temp.apply(lambda x: (function(x)))
df_temp
Verstehe nicht warum das nicht funktioniert. Es wird immer eine neue Zeile eingefügt?? Eigentlich müsste hier doch eine column eingefügt werden. Die Länge stimmt ja auch???

[Out]

0 wert1
1 wert2
2 wert3
3 wert4
4 und dann wird bei mir am Schluss in einer Zeile der komplette inhalt der neuen Column ['VoX'] geschrieben

Hoffe man versteht mein Problem. Wenn ich Beispielcode aus dem Internet verwende funktioniert es??

Re: Apply function to every different row of a column

Verfasst: Freitag 23. August 2019, 12:09
von __blackjack__
@BroNKo: Also die erste Zeile ist überflüssig weil der leere `DataFrame` ja nie für irgendetwas verwendet wird. Insgesamt sind in dem Code auch zwei Klammerpaare zu viel die keinen Effekt haben und auch die Lesbarkeit nicht erhöhen weil beide nichts gruppieren.

Ich weiss nicht was Du mit „die Länge stimmt ja auch“ meinst — das Ergebnis vom `apply()` beziehungsweise ja schon das `Series`-Objekt auf das `apply()` aufgerufen wird ist kürzer als der `DataFrame`. Das entscheidende ist hier nicht die Länge, sondern das die Indexwerte von `Series` und `DataFrame` passen, damit die Zuweisung an eine neue Spalte im `DataFrame` funktioniert. Mit den Beispieldaten aus meinem letzten Beitrag:

Code: Alles auswählen

In [54]: df.x[~df.x.duplicated()]                                               
Out[54]: 
0      6
1      1
3      9
4      3
6      4
7      7
12     8
13     2
16    10
19     5
Name: x, dtype: int64

In [55]: df['vx'] = df.x[~df.x.duplicated()].apply(lambda x: -x * 1000)         

In [56]: df                                                                     
Out[56]: 
     x       vx
0    6  -6000.0
1    1  -1000.0
2    6      NaN
3    9  -9000.0
4    3  -3000.0
5    9      NaN
6    4  -4000.0
7    7  -7000.0
8    4      NaN
9    3      NaN
10   4      NaN
11   3      NaN
12   8  -8000.0
13   2  -2000.0
14   2      NaN
15   3      NaN
16  10 -10000.0
17   7      NaN
18   6      NaN
19   5  -5000.0
20   9      NaN
21  10      NaN
22   4      NaN
23   6      NaN
24   2      NaN
25   5      NaN
26   4      NaN
27   8      NaN
28   3      NaN
29   6      NaN
..  ..      ...
70  10      NaN
71   6      NaN
72   6      NaN
73   4      NaN
74   5      NaN
75   3      NaN
76  10      NaN
77   8      NaN
78   1      NaN
79   2      NaN
80   1      NaN
81   7      NaN
82   1      NaN
83   1      NaN
84   9      NaN
85   1      NaN
86  10      NaN
87   9      NaN
88   2      NaN
89   8      NaN
90   1      NaN
91  10      NaN
92   7      NaN
93   2      NaN
94   4      NaN
95   4      NaN
96   2      NaN
97   6      NaN
98   1      NaN
99   5      NaN

[100 rows x 2 columns]
Wie man sieht eine Menge NaN-Werte wo das `apply()`-Ergebnis keinen Wert hat.

Re: Apply function to every different row of a column

Verfasst: Freitag 23. August 2019, 12:43
von __blackjack__
@BroNKo: Ah, Moment, ich habe mich vom Namen `df_temp` täuschen lassen: Das ist ja gar kein `DataFrame` sondern ein `Series`-Objekt — was soll denn das bedeuten was Du da machst? Was es tatsächlich bedeutet ist: füge an Index "VoX" eine neues Datum zu dem `Series`-Objekt hinzu, also wenn man das `Series`-Objekt als Spalte sieht, fügt das eine weitere Zeile hinzu. Und der Datentyp der Spalte ist dann natürlich `object` weil man als Wert zu einer vorher numerischen Spalte ein `Series`-Objekt hinzufügt, und das hat natürlich keinen kleineren gemeinsamen Nenner als `object`.

Code: Alles auswählen

In [58]: s = df.x[~df.x.duplicated()]                                           

In [59]: s['vx'] = s.apply(lambda x: -x * 1000)                                 

In [60]: s                                                                      
Out[60]: 
0                                                     6
1                                                     1
3                                                     9
4                                                     3
6                                                     4
7                                                     7
12                                                    8
13                                                    2
16                                                   10
19                                                    5
vx    0     -6000
1     -1000
3     -9000
4     -300...
Name: x, dtype: object
Beispiel dafür das gute und *passende* Namen wichtig sind. Nenne nix `df_irgendwas` was nicht tatsächlich ein `DataFrame` ist. Sonst ist Verwirrung beim Leser – und hier ja auch beim Autor selbst – vorprogrammiert.

Re: Apply function to every different row of a column

Verfasst: Samstag 24. August 2019, 11:43
von BroNKo
@__blackjack__ Danke für deine Mühe. Ja hab das so genannt weil es eigentlich ein Dataframe sein sollte. Aller Anfang ist schwer. Hab jetzt die Lösung für mein Problem nach 3 Stunden trail and error. Manchmal geht es einem so als Anfänger das man am Anfang der Lösung am nächsten ist und nur ein Syntaxfehler dazuführt das man sich im Ausprobieren immer weiter von der richtigen Lösung entfernt. Die überflüssigen Klammern kommen meist daher das ich versuche nur den für mein Problem relevanten Code hier einzustellen.

Code: Alles auswählen

def df_get_isX_vol(df):
    df_temp = pd.DataFrame(df.IsX[~df.IsX.duplicated()])
    df_temp['Vol'] = df_temp.IsX.apply(lambda x: IsX_delta_vol(x))
    return df_temp
So einfach wäre es gewesen :D Hoffe das ist jetzt so halbwegs sauber programmiert. Danke dir nochmal blackjack!

Re: Apply function to every different row of a column

Verfasst: Samstag 24. August 2019, 12:47
von __blackjack__
@BroNKo: Der ``lambda``-Ausdruck ist hier eine unnötige Indirektion. Einfach ``….apply(IsX_delta_vol)`` reicht. `df_temp` würde ich `result` oder so nennen, denn wenn etwas als Ergebnis zurückgegeben wird, dann ist es ja nicht wirklich „temporär“ – oder zumindest weiss man das an dieser Stelle nicht. Beziehungsweise könnte man an *alle* lokalen Namen ein „_temporary“ anhängen, was aber nicht wirklich einen Gewinn für den Leser bringt. Oh, und abgekürzt ist es ein bisschen problematisch, weil man sich in bestimmten Fällen fragen muss was es eigentlich bedeutet – „temporary“ oder „temperature“.