Wersja TL; DR:
W prostym przypadku:
- Mam kolumnę tekstową z separatorem i chcę dwie kolumny
Najprostszym rozwiązaniem jest:
df['A'], df['B'] = df['AB'].str.split(' ', 1).str
Możesz też utworzyć automatycznie DataFrame z jedną kolumną dla każdego wpisu podziału automatycznie za pomocą:
df['AB'].str.split(' ', 1, expand=True)
Musisz użyć, expand=True
jeśli ciągi mają nierównomierną liczbę podziałów i chcesz None
zastąpić brakujące wartości.
Zauważ, że w obu przypadkach .tolist()
metoda nie jest konieczna. Ani też niezip()
.
Szczegółowo:
Rozwiązanie Andy'ego Haydena jest najdoskonalsze w zademonstrowaniu siły str.extract()
metody.
Ale w przypadku zwykłego podziału na znany separator (np. Dzielenie za pomocą myślników lub dzielenie za pomocą białych znaków) .str.split()
metoda wystarczy 1 . Działa na kolumnie (Seria) ciągów i zwraca kolumnę (Seria) list:
>>> 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: Jeśli nie masz pewności, co robią pierwsze dwa parametry .str.split()
, polecam dokumentację dla zwykłej wersji metody w języku Python .
Ale jak to zrobić:
- kolumna zawierająca listy dwuelementowe
do:
- dwie kolumny, każda zawierająca odpowiedni element list?
Cóż, musimy przyjrzeć się bliżej .str
atrybutowi kolumny.
Jest to magiczny obiekt, który służy do zbierania metod, które traktują każdy element w kolumnie jako ciąg znaków, a następnie stosuje odpowiednią metodę w każdym elemencie tak wydajnie, jak to możliwe:
>>> 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
Ale ma również interfejs „indeksowania” do pobierania każdego elementu ciągu według jego indeksu:
>>> df['AB'].str[0]
0 A
1 A
Name: AB, dtype: object
>>> df['AB'].str[1]
0 1
1 2
Name: AB, dtype: object
Oczywiście ten interfejs indeksowania .str
nie obchodzi, czy każdy indeksowany element jest w rzeczywistości łańcuchem, o ile można go indeksować, więc:
>>> 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
Następnie jest to prosta kwestia skorzystania z rozpakowywania iterowych krotek w Pythonie
>>> 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
Oczywiście uzyskanie DataFrame z podziału kolumny ciągów jest tak przydatne, że .str.split()
metoda może to zrobić za pomocą expand=True
parametru:
>>> df['AB'].str.split('-', 1, expand=True)
0 1
0 A1 B1
1 A2 B2
Kolejnym sposobem na osiągnięcie tego, co chcieliśmy, jest:
>>> 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
expand=True
Wersja, chociaż dłużej, ma wyraźną przewagę nad metodą krotki rozpakowaniu. Rozpakowywanie krotek nie radzi sobie dobrze z podziałami o różnych długościach:
>>> 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
>>>
Ale expand=True
radzi sobie z tym ładnie, umieszczając None
w kolumnach, dla których nie ma wystarczającej liczby „podziałów”:
>>> 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
read_table()
lubread_fwf()