wake-up-neo.net

Wie teilt man eine Spalte in zwei Spalten auf?

Ich habe einen Datenrahmen mit einer Spalte, und ich möchte ihn in zwei Spalten aufteilen, wobei ein Spaltenkopf als 'fips' und der andere 'row'

Mein Datenrahmen df sieht folgendermaßen 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 ich mit df.row.str[:] mein Ziel erreichen soll, die Zeilenzelle zu teilen. Ich kann df['fips'] = hello verwenden, um eine neue Spalte hinzuzufügen und sie mit hello aufzufüllen. 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
120
a k

Es könnte einen besseren Weg geben, aber hier ist ein Ansatz:

In [34]: import pandas as pd

In [35]: df
Out[35]: 
                        row
0       00000 UNITED STATES
1             01000 ALABAMA
2  01001 Autauga County, AL
3  01003 Baldwin County, AL
4  01005 Barbour County, AL

In [36]: df = pd.DataFrame(df.row.str.split(' ',1).tolist(),
                                   columns = ['flips','row'])

In [37]: df
Out[37]: 
   flips                 row
0  00000       UNITED STATES
1  01000             ALABAMA
2  01001  Autauga County, AL
3  01003  Baldwin County, AL
4  01005  Barbour County, AL
92
root

TL; DR-Version:

Für den einfachen Fall von:

  • Ich habe eine Textspalte mit einem Trennzeichen und ich möchte zwei Spalten

Die einfachste Lösung ist:

df['A'], df['B'] = df['AB'].str.split(' ', 1).str

Oder erstellen Sie einen DataFrame mit einer Spalte für jeden Eintrag der Aufteilung automatisch mit:

df['AB'].str.split(' ', 1, expand=True)

Beachten Sie, dass in beiden Fällen die .tolist()-Methode nicht erforderlich ist. Weder ist Zip().

Im Detail:

Andy Haydens Lösung zeigt am besten die Leistungsfähigkeit der str.extract() - Methode.

Für eine einfache Aufteilung in ein bekanntes Trennzeichen (z. B. durch Bindestriche oder durch Leerzeichen) ist die Methode .str.split() ausreichend1. Es arbeitet mit einer Spalte (Series) von Strings und gibt eine Spalte (Series) 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 .str.split() tun, Ich empfehle die Dokumente für die plain Python-Version der Methode .

Aber wie geht es weiter von:

  • eine Spalte, die Listen mit zwei Elementen enthält

zu:

  • zwei Spalten, die jeweils das jeweilige Element der Listen enthalten?

Nun, wir müssen uns das .str-Attribut einer Spalte genauer ansehen.

Es ist ein magisches Objekt, das zum Sammeln von Methoden verwendet wird, die jedes Element in einer Spalte als String behandeln und dann die jeweilige Methode in jedem Element so effizient wie möglich anwenden:

>>> 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

Es hat aber auch eine "Indizierungs" -Schnittstelle, um jedes Element eines Strings über seinen Index abzurufen:

>>> 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 interessiert es diese Indizierungsschnittstelle von .str nicht wirklich, wenn jedes indizierte Element tatsächlich eine Zeichenfolge ist, sofern 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 Sache, das Python-Tuple-Auspacken von Iterables zu nutzen

>>> 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 Stringspalte herauszuholen, sodass die .str.split()-Methode dies mit dem expand=True-Parameter für Sie erledigen kann:

>>> 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, ist:

>>> 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
262
LeoRochael

Sie können extrahieren die verschiedenen Teile mit einem Regex-Muster ganz ordentlich herausnehmen:

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]

Um den etwas langen Regex zu erklären:

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

Der nächste Teil:

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

Führt entweder (|) eine von zwei Sachen aus:

(?P<state>[A-Z ]*$)
  • Entspricht einer beliebigen Anzahl (*) von Großbuchstaben oder Leerzeichen ([A-Z ]) und nennt diesen "state" vor dem Ende der Zeichenfolge ($).

oder

(?P<county>.*?), (?P<state_code>[A-Z]{2}$))
  • passt dann auf etwas anderes (.*)
  • ein Komma und ein Leerzeichen dann 
  • entspricht der zweistelligen state_code vor dem Ende der Zeichenfolge ($).

Im Beispiel:
Beachten Sie, dass die ersten beiden Zeilen den Zustand "state" treffen (NaN in den County- und State_code-Spalten belassen), während die letzten drei Zeilen den County-State_code treffen (wobei NaN in der Statusspalte bleibt).

45
Andy Hayden
df[['fips', 'row']] = df['row'].str.split(' ', n=1, expand=True)
24
Bhagabat Behera

Wenn Sie keinen neuen Datenrahmen erstellen möchten oder wenn Ihr Datenrahmen mehr Spalten als nur die Spalten enthält, die Sie teilen möchten, können Sie Folgendes tun:

df["flips"], df["row_name"] = Zip(*df["row"].str.split().tolist())
del df["row"]  
21
keberwein

Sie können str.split nach Whitespace (Standardtrennzeichen) und den Parameter expand=True für DataFrame verwenden, um neue Spalten zuzuweisen:

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

Änderung, falls erforderlich, Entfernen der Originalspalte 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 das Gleiche wie:

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 Fehler ausgegeben werden:

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

ValueError: Spalten müssen die gleiche Länge wie key haben

Sie können 4 Spalte DataFrame überprüfen und zurückgeben, 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

Dann fügt die Lösung neue DataFrame durch join hinzu:

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 Original-Spalte entfernen (falls noch weitere Spalten vorhanden sind):

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   
16
jezrael

Wenn Sie eine Zeichenfolge basierend auf einem Trennzeichen in mehr als zwei Spalten aufteilen möchten, können Sie den Parameter 'Maximum Splits' weglassen.
Sie können verwenden: 

df['column_name'].str.split('/', expand=True)

Dadurch werden automatisch so viele Spalten erstellt, wie die maximale Anzahl von Feldern in Ihren ursprünglichen Zeichenfolgen ist. 

8
lacrima

Series.str.partition
Überrascht habe ich diesen noch nicht gesehen. partition führt eine Aufteilung des Trennzeichens durch und ist im Allgemeinen ziemlich performant.

df['row'].str.partition(' ')[[0, 2]]

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

Wenn Sie die Zeilen umbenennen müssen, 

df['row'].str.partition(' ')[[0, 2]].rename({0: 'fips', 2: 'row'}, axis=1)

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

Wenn Sie dies wieder mit dem Original verbinden möchten, verwenden Sie join oder concat:

df.join(df['row'].str.partition(' ')[[0, 2]])

pd.concat([df, df['row'].str.partition(' ')[[0, 2]]], axis=1)

                        row      0                   2
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
1
coldspeed

Ich bevorzuge es, die entsprechende Pandaserie (d. H. Die von mir benötigten Spalten) zu exportieren. Mit der Funktion apply teilen Sie den Spalteninhalt in mehrere Serien auf und teilen dann die generierten Spalten join mit dem vorhandenen DataFrame auf. Natürlich sollte die Quellspalte entfernt werden.

z.B. 

 col1 = df["<col_name>"].apply(<function>)
 col2 = ...
 df = df.join(col1.to_frame(name="<name1>"))
 df = df.join(col2.toframe(name="<name2>"))
 df = df.drop(["<col_name>"], axis=1)

Um zwei Wörter zu teilen, sollte die Funktion Strings so aussehen:

lambda x: x.split(" ")[0] # for the first element
lambda x: x.split(" ")[-1] # for the last element
0
mcchran

Ich habe gesehen, dass niemand die Slice-Methode angewendet hat, also habe ich hier meine 2 Cent eingesetzt.

df["<col_name>"].str.slice(stop=5)
df["<col_name>"].str.slice(start=6)

Diese Methode erstellt zwei neue Spalten.

0
Vingt Cent