374 Stimmen

Wie teilt man eine String-Spalte eines Datenrahmens in zwei Spalten?

Ich habe einen Datenrahmen mit einer (String-)Spalte und möchte ihn in zwei (String-)Spalten aufteilen, wobei eine Spaltenüberschrift als ' fips' und das andere 'row'

Mein Datenrahmen df sieht so aus:

          row
0    00000 UNITED STATES
1    01000 ALABAMA
2    01001 Autauga County, AL
3    01003 Baldwin County, AL
4    01005 Barbour County, AL

Ich weiß nicht, wie man df.row.str[:] um mein Ziel der Aufteilung der Zeilenzelle zu erreichen. Ich kann verwenden df['fips'] = hello um eine neue Spalte hinzuzufügen und sie zu füllen mit hello . Irgendwelche Ideen?

         fips       row
0    00000 UNITED STATES
1    01000 ALABAMA 
2    01001 Autauga County, AL
3    01003 Baldwin County, AL
4    01005 Barbour County, AL

792voto

LeoRochael Punkte 12443

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

184voto

root Punkte 73542

Vielleicht gibt es einen besseren Weg, aber das hier ist ein Ansatz:

                            row
    0       00000 UNITED STATES
    1             01000 ALABAMA
    2  01001 Autauga County, AL
    3  01003 Baldwin County, AL
    4  01005 Barbour County, AL

df = pd.DataFrame(df.row.str.split(' ',1).tolist(),
                                 columns = ['fips','row'])

   fips                 row
0  00000       UNITED STATES
1  01000             ALABAMA
2  01001  Autauga County, AL
3  01003  Baldwin County, AL
4  01005  Barbour County, AL

79voto

Andy Hayden Punkte 324102

Sie können Auszug die verschiedenen Teile mit Hilfe eines Regex-Musters recht übersichtlich darzustellen:

In [11]: df.row.str.extract('(?P<fips>\d{5})((?P<state>[A-Z ]*$)|(?P<county>.*?), (?P<state_code>[A-Z]{2}$))')
Out[11]: 
    fips                    1           state           county state_code
0  00000        UNITED STATES   UNITED STATES              NaN        NaN
1  01000              ALABAMA         ALABAMA              NaN        NaN
2  01001   Autauga County, AL             NaN   Autauga County         AL
3  01003   Baldwin County, AL             NaN   Baldwin County         AL
4  01005   Barbour County, AL             NaN   Barbour County         AL

[5 rows x 5 columns]

Zur Erklärung der etwas langen Regex:

(?P<fips>\d{5})
  • Stimmt mit den fünf Ziffern ( \d ) und benennt sie "fips" .

Der nächste Teil:

((?P<state>[A-Z ]*$)|(?P<county>.*?), (?P<state_code>[A-Z]{2}$))

Ist entweder ( | ) eines von zwei Dingen:

(?P<state>[A-Z ]*$)
  • Entspricht einer beliebigen Zahl ( * ) von Großbuchstaben oder Leerzeichen ( [A-Z ] ) und nennt diese "state" vor dem Ende der Zeichenkette ( $ ),

oder

(?P<county>.*?), (?P<state_code>[A-Z]{2}$))
  • mit etwas anderem übereinstimmt ( .* ) dann
  • ein Komma und ein Leerzeichen, dann
  • entspricht der zweistelligen state_code vor dem Ende der Zeichenkette ( $ ).

In diesem Beispiel:
Beachten Sie, dass die ersten beiden Zeilen den "Staat" treffen (wobei NaN in den Spalten "county" und "state_code" übrig bleibt), während die letzten drei den "county" und "state_code" treffen (wobei NaN in der Spalte "state" übrig bleibt).

56voto

Bhagabat Behera Punkte 833
df[['fips', 'row']] = df['row'].str.split(' ', n=1, expand=True)

30voto

jezrael Punkte 716156

Sie können verwenden str.split durch Leerzeichen (Standardtrennzeichen) und Parameter expand=True für DataFrame mit Zuweisung zu neuen Spalten:

df = pd.DataFrame({'row': ['00000 UNITED STATES', '01000 ALABAMA', 
                           '01001 Autauga County, AL', '01003 Baldwin County, AL', 
                           '01005 Barbour County, AL']})
print (df)
                        row
0       00000 UNITED STATES
1             01000 ALABAMA
2  01001 Autauga County, AL
3  01003 Baldwin County, AL
4  01005 Barbour County, AL

df[['a','b']] = df['row'].str.split(n=1, expand=True)
print (df)
                        row      a                   b
0       00000 UNITED STATES  00000       UNITED STATES
1             01000 ALABAMA  01000             ALABAMA
2  01001 Autauga County, AL  01001  Autauga County, AL
3  01003 Baldwin County, AL  01003  Baldwin County, AL
4  01005 Barbour County, AL  01005  Barbour County, AL

Modifikation bei Bedarf entfernen Sie die ursprüngliche Spalte mit DataFrame.pop

df[['a','b']] = df.pop('row').str.split(n=1, expand=True)
print (df)
       a                   b
0  00000       UNITED STATES
1  01000             ALABAMA
2  01001  Autauga County, AL
3  01003  Baldwin County, AL
4  01005  Barbour County, AL

Was ist gleich:

df[['a','b']] = df['row'].str.split(n=1, expand=True)
df = df.drop('row', axis=1)
print (df)

       a                   b
0  00000       UNITED STATES
1  01000             ALABAMA
2  01001  Autauga County, AL
3  01003  Baldwin County, AL
4  01005  Barbour County, AL

Wenn Sie einen Fehler erhalten:

#remove n=1 for split by all whitespaces
df[['a','b']] = df['row'].str.split(expand=True)

WertFehler: Spalten müssen die gleiche Länge wie der Schlüssel haben

Sie können dies überprüfen und erhalten 4 Spalten DataFrame , nicht nur 2:

print (df['row'].str.split(expand=True))
       0        1        2     3
0  00000   UNITED   STATES  None
1  01000  ALABAMA     None  None
2  01001  Autauga  County,    AL
3  01003  Baldwin  County,    AL
4  01005  Barbour  County,    AL

Die Lösung ist dann das Anhängen neuer DataFrame von join :

df = pd.DataFrame({'row': ['00000 UNITED STATES', '01000 ALABAMA', 
                           '01001 Autauga County, AL', '01003 Baldwin County, AL', 
                           '01005 Barbour County, AL'],
                    'a':range(5)})
print (df)
   a                       row
0  0       00000 UNITED STATES
1  1             01000 ALABAMA
2  2  01001 Autauga County, AL
3  3  01003 Baldwin County, AL
4  4  01005 Barbour County, AL

df = df.join(df['row'].str.split(expand=True))
print (df)

   a                       row      0        1        2     3
0  0       00000 UNITED STATES  00000   UNITED   STATES  None
1  1             01000 ALABAMA  01000  ALABAMA     None  None
2  2  01001 Autauga County, AL  01001  Autauga  County,    AL
3  3  01003 Baldwin County, AL  01003  Baldwin  County,    AL
4  4  01005 Barbour County, AL  01005  Barbour  County,    AL

Mit Originalspalte entfernen (wenn es noch weitere Spalten gibt):

df = df.join(df.pop('row').str.split(expand=True))
print (df)
   a      0        1        2     3
0  0  00000   UNITED   STATES  None
1  1  01000  ALABAMA     None  None
2  2  01001  Autauga  County,    AL
3  3  01003  Baldwin  County,    AL
4  4  01005  Barbour  County,    AL

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X