it-swarm.com.de

Letzte Spalte nach der .str.split () - Operation für die Spalte in Pandas DataFrame abrufen

Ich habe eine Spalte in einem Pandas-DataFrame, die ich auf ein einzelnes Leerzeichen aufteilen möchte. Die Aufteilung ist mit DataFrame.str.split(' ') einfach genug, aber ich kann aus dem letzten Eintrag keine neue Spalte erstellen. Wenn ich die Spalte .str.split() erhalte, bekomme ich eine Liste von Arrays, und ich weiß nicht, wie ich diese manipulieren kann, um eine neue Spalte für meinen DataFrame zu erhalten.

Hier ist ein Beispiel. Jeder Eintrag in der Spalte enthält "Symboldatenpreis" und ich möchte den Preis abspalten (und in der Hälfte der Fälle das "p" ... oder "c" entfernen).

import pandas as pd
temp = pd.DataFrame({'ticker' : ['spx 5/25/2001 p500', 'spx 5/25/2001 p600', 'spx 5/25/2001 p700']})
temp2 = temp.ticker.str.split(' ')

was ergibt

0    ['spx', '5/25/2001', 'p500']
1    ['spx', '5/25/2001', 'p600']
2    ['spx', '5/25/2001', 'p700']

Aber temp2[0] gibt nur das Array eines Listeneintrags an und temp2[:][-1] schlägt fehl. Wie kann ich den letzten Eintrag in jedem Array in eine neue Spalte konvertieren? Vielen Dank!

36
Richard Herron

Sie können die Methode tolist als Vermittler verwenden:

In [99]: import pandas as pd

In [100]: d1 = pd.DataFrame({'ticker' : ['spx 5/25/2001 p500', 'spx 5/25/2001 p600', 'spx 5/25/2001 p700']})

In [101]: d1.ticker.str.split().tolist()
Out[101]: 
[['spx', '5/25/2001', 'p500'],
 ['spx', '5/25/2001', 'p600'],
 ['spx', '5/25/2001', 'p700']]

Daraus könnten Sie einen neuen DataFrame erstellen:

In [102]: d2 = pd.DataFrame(d1.ticker.str.split().tolist(), 
   .....:                   columns="symbol date price".split())

In [103]: d2
Out[103]: 
  symbol       date price
0    spx  5/25/2001  p500
1    spx  5/25/2001  p600
2    spx  5/25/2001  p700

Für ein gutes Maß könnten Sie den Preis festlegen:

In [104]: d2["price"] = d2["price"].str.replace("p","").astype(float)

In [105]: d2
Out[105]: 
  symbol       date  price
0    spx  5/25/2001    500
1    spx  5/25/2001    600
2    spx  5/25/2001    700

PS: aber wenn Sie wirklich nur die letzte Spalte wollen, würde apply ausreichen:

In [113]: temp2.apply(lambda x: x[2])
Out[113]: 
0    p500
1    p600
2    p700
Name: ticker
31
DSM

Mach das:

In [43]: temp2.str[-1]
Out[43]: 
0    p500
1    p600
2    p700
Name: ticker
79
Wes McKinney

https://pandas.pydata.org/pandas-docs/stable/text.html

s2 = pd.Series(['a_b_c', 'c_d_e', np.nan, 'f_g_h'])
s2.str.split('_').str.get(1)

oder 

s2.str.split('_').str[1]
12
James Holland

Verwenden von Pandas 0.20.3:

In [10]: import pandas as pd
    ...: temp = pd.DataFrame({'ticker' : ['spx 5/25/2001 p500', 'spx 5/25/2001 p600', 'spx 5/25/2001 p700']})
    ...:

In [11]: temp2 = temp.ticker.str.split(' ', expand=True)  # the expand=True return a DataFrame

In [12]: temp2
Out[12]:
     0          1     2
0  spx  5/25/2001  p500
1  spx  5/25/2001  p600
2  spx  5/25/2001  p700

In [13]: temp3 = temp.join(temp2[2])

In [14]: temp3
Out[14]:
               ticker     2
0  spx 5/25/2001 p500  p500
1  spx 5/25/2001 p600  p600
2  spx 5/25/2001 p700  p700
1
AllanLRH

Series.str.rpartition

Ist ziemlich effizient.

temp.ticker.str.rpartition(expand=False).str[-1]

0    p500
1    p600
2    p700
Name: ticker, dtype: object

Wenn Sie expand=True Übergeben (dies ist die Standardeinstellung), ist das Ergebnis ein DataFrame, wobei jede Spalte zu einer eigenen Aufteilung gehört:

temp.ticker.str.rpartition()
# temp.ticker.str.rpartition(expand=True)

               0  1     2
0  spx 5/25/2001     p500
1  spx 5/25/2001     p600
2  spx 5/25/2001     p700

Von hier aus ist es einfach, die letzte Spalte zu erhalten.

temp.ticker.str.rpartition().iloc[:,-1]

0    p500
1    p600
2    p700
Name: 2, dtype: object

Series.str.rsplit(n=1)

Ein weiterer Vorschlag ist str.rsplit. Da wir uns vom Ende getrennt haben, können wir split bitten, nur einmal zu trennen (da wir vor der endgültigen Trennung nichts brauchen).

temp.ticker.str.rsplit(n=1).str[-1]

0    p500
1    p600
2    p700
Name: ticker, dtype: object

Oder,

temp.ticker.str.rsplit(n=1, expand=True).iloc[:,-1]

0    p500
1    p600
2    p700
Name: 1, dtype: object

Dies ist effizienter als str.split.


Listenverständnis

Für die Leistung können Sie hier Listenverständnisse verwenden:

[s.rpartition(' ')[-1] for s in temp.ticker]
# ['p500', 'p600', 'p700']

pd.Series([s.rpartition(' ')[-1] for s in temp.ticker])

0    p500
1    p600
2    p700
dtype: object

Sie können auch str.rsplit In einer Liste comp verwenden.

pd.Series([s.rsplit(None, 1)[-1] for s in temp.ticker])

0    p500
1    p600
2    p700
dtype: object

Ich empfehle Listenverständnisse, weil sie einen geringeren Overhead haben als pandas= Zeichenfolgenfunktionen (die auch die Daten durchlaufen - Zeichenfolgenoperationen können nicht einfach wirklich "vektorisiert" werden) Für Schleifen mit pandas - Wann sollte es mich interessieren? .


Performance

df_ = temp.copy()
df = pd.concat([df_] * 10000, ignore_index=True)

%timeit df.ticker.str.split().str[-1]
%timeit df.ticker.str.rpartition().iloc[:,-1]
%timeit df.ticker.str.rsplit(n=1).str[-1]
%timeit pd.Series([s.rpartition(' ')[-1] for s in df.ticker])
%timeit pd.Series([s.rsplit(None, 1)[-1] for s in df.ticker])

72.4 ms ± 1.87 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
54.9 ms ± 1.16 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
65.2 ms ± 1.24 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
20.4 ms ± 334 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
26.5 ms ± 1.53 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Listenerfassungsmethoden sind schneller, aber der größte Teil der Verlangsamung ist auf den Mehraufwand bei der Konvertierung in Serien zurückzuführen. Die Kompositionsoperation für unformatierte Listen ist viel schneller:

%timeit [s.rpartition(' ')[-1] for s in df.ticker]
18 ms ± 289 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
0
coldspeed