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