TL;DR-Version:
Für den einfachen Fall von:
- Ich habe eine Textspalte mit einem Begrenzungszeichen und möchte zwei Spalten
Das ist die einfachste Lösung:
df[['A', 'B']] = df['AB'].str.split(' ', 1, expand=True)
Sie müssen Folgendes verwenden expand=True
wenn Ihre Strings eine ungleichmäßige Anzahl von Splits haben und Sie wollen None
um die fehlenden Werte zu ersetzen.
Beachten Sie, dass in beiden Fällen die .tolist()
Methode ist nicht erforderlich. Ebenso wenig ist zip()
.
Im Detail:
Die Lösung von Andy Hayden ist ein hervorragender Beweis für die Macht der str.extract()
Methode.
Aber für eine einfache Aufteilung über ein bekanntes Trennzeichen (z.B. Aufteilung durch Bindestriche oder Aufteilung durch Leerzeichen), wird die .str.split()
Methode ist ausreichend 1 . Sie verarbeitet eine Spalte (Reihe) von Zeichenketten und gibt eine Spalte (Reihe) von Listen zurück:
>>> import pandas as pd
>>> df = pd.DataFrame({'AB': ['A1-B1', 'A2-B2']})
>>> df
AB
0 A1-B1
1 A2-B2
>>> df['AB_split'] = df['AB'].str.split('-')
>>> df
AB AB_split
0 A1-B1 [A1, B1]
1 A2-B2 [A2, B2]
1: Wenn Sie sich nicht sicher sind, was die ersten beiden Parameter von <code>.str.split()</code> tun, Ich empfehle die Dokumentationen für das <a href="https://docs.python.org/3.6/library/stdtypes.html#str.split" rel="noreferrer">einfache Python-Version der Methode </a>.
Aber wie kommt man von:
- eine Spalte mit Zwei-Elemente-Listen
zu:
- zwei Spalten, die jeweils das entsprechende Element der Listen enthalten?
Nun, wir müssen einen genaueren Blick auf die .str
Attribut einer Spalte.
Es ist ein magisches Objekt, das verwendet wird, um Methoden zu sammeln, die jedes Element in einer Spalte als Zeichenkette behandeln, und dann die jeweilige Methode in jedem Element so effizient wie möglich anzuwenden:
>>> upper_lower_df = pd.DataFrame({"U": ["A", "B", "C"]})
>>> upper_lower_df
U
0 A
1 B
2 C
>>> upper_lower_df["L"] = upper_lower_df["U"].str.lower()
>>> upper_lower_df
U L
0 A a
1 B b
2 C c
Aber es hat auch eine "Indizierungs"-Schnittstelle, um jedes Element einer Zeichenkette über seinen Index zu erhalten:
>>> df['AB'].str[0]
0 A
1 A
Name: AB, dtype: object
>>> df['AB'].str[1]
0 1
1 2
Name: AB, dtype: object
Natürlich ist diese Indizierungsschnittstelle von .str
kümmert sich nicht wirklich darum, ob jedes Element, das es indiziert, tatsächlich eine Zeichenkette ist, solange es indiziert werden kann, also:
>>> df['AB'].str.split('-', 1).str[0]
0 A1
1 A2
Name: AB, dtype: object
>>> df['AB'].str.split('-', 1).str[1]
0 B1
1 B2
Name: AB, dtype: object
Dann ist es eine einfache Angelegenheit, die Vorteile des Python-Tupel-Entpackens von Iterables zu nutzen, um Folgendes zu tun
>>> df['A'], df['B'] = df['AB'].str.split('-', 1).str
>>> df
AB AB_split A B
0 A1-B1 [A1, B1] A1 B1
1 A2-B2 [A2, B2] A2 B2
Natürlich ist es so nützlich, einen DataFrame aus der Aufteilung einer Spalte von Strings zu erhalten, dass die .str.split()
Methode kann dies für Sie mit der expand=True
Parameter:
>>> df['AB'].str.split('-', 1, expand=True)
0 1
0 A1 B1
1 A2 B2
Eine andere Möglichkeit, das zu erreichen, was wir wollten, wäre also, dies zu tun:
>>> df = df[['AB']]
>>> df
AB
0 A1-B1
1 A2-B2
>>> df.join(df['AB'].str.split('-', 1, expand=True).rename(columns={0:'A', 1:'B'}))
AB A B
0 A1-B1 A1 B1
1 A2-B2 A2 B2
En expand=True
Version ist zwar länger, hat aber einen deutlichen Vorteil gegenüber der Tupel-Entpackungsmethode. Das Tupel-Entpacken kommt mit unterschiedlich langen Splits nicht gut zurecht:
>>> df = pd.DataFrame({'AB': ['A1-B1', 'A2-B2', 'A3-B3-C3']})
>>> df
AB
0 A1-B1
1 A2-B2
2 A3-B3-C3
>>> df['A'], df['B'], df['C'] = df['AB'].str.split('-')
Traceback (most recent call last):
[...]
ValueError: Length of values does not match length of index
>>>
Aber expand=True
handhabt es gut, indem es die None
in den Spalten, für die es nicht genügend "Splits" gibt:
>>> df.join(
... df['AB'].str.split('-', expand=True).rename(
... columns={0:'A', 1:'B', 2:'C'}
... )
... )
AB A B C
0 A1-B1 A1 B1 None
1 A2-B2 A2 B2 None
2 A3-B3-C3 A3 B3 C3