TL; версия DR:
Для простого случая:
- У меня есть текстовый столбец с разделителем, и я хочу два столбца
Самое простое решение:
df['A'], df['B'] = df['AB'].str.split(' ', 1).str
Или вы можете автоматически создать DataFrame с одним столбцом для каждой записи разделения:
df['AB'].str.split(' ', 1, expand=True)
Вы должны использовать, expand=Trueесли ваши строки имеют неоднородное количество разбиений, и вы хотите Noneзаменить отсутствующие значения.
Обратите внимание, что в любом случае .tolist()метод не является обязательным. Ни то, ни другое zip().
В деталях:
Решение Энди Хейдена является превосходным в демонстрации силы str.extract()метода.
Но для простого разбиения по известному разделителю (например, деление по тире или расщепление по пробелам) этого .str.split()метода достаточно 1 . Он работает со столбцом (Series) строк и возвращает столбец (Series) списков:
>>> 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: Если вы не уверены, что делают первые два параметра .str.split(), я рекомендую документы для простой Python-версии метода .
Но как вы идете от:
- столбец, содержащий двухэлементные списки
чтобы:
- два столбца, каждый из которых содержит соответствующий элемент списков?
Что ж, нам нужно поближе взглянуть на .strатрибут столбца.
Это магический объект, который используется для сбора методов, которые рассматривают каждый элемент в столбце как строку, а затем применяют соответствующий метод в каждом элементе настолько эффективно, насколько это возможно:
>>> 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
Но он также имеет интерфейс «индексации» для получения каждого элемента строки по его индексу:
>>> df['AB'].str[0]
0 A
1 A
Name: AB, dtype: object
>>> df['AB'].str[1]
0 1
1 2
Name: AB, dtype: object
Конечно, этот интерфейс индексации на .strсамом деле не заботится о том, является ли каждый элемент, который он индексирует, действительно строкой, если он может быть проиндексирован, поэтому:
>>> 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
Тогда вам просто нужно воспользоваться кортежем Python для распаковки итераций, чтобы сделать
>>> 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
Конечно, получение DataFrame из разбиения столбца строк настолько полезно, что .str.split()метод может сделать это для вас с expand=Trueпараметром:
>>> df['AB'].str.split('-', 1, expand=True)
0 1
0 A1 B1
1 A2 B2
Итак, еще один способ выполнить то, что мы хотели, это сделать:
>>> 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Версия, хотя и дольше, имеет явное преимущество по сравнению с методом кортежа распаковки. Распаковка кортежей не справляется с разбиениями разной длины:
>>> 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
>>>
Но expand=Trueхорошо справляется с этим, помещая Noneв столбцы, для которых недостаточно «разбиений»:
>>> 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()илиread_fwf()