Versão TL; DR:
Para o caso simples de:
- Eu tenho uma coluna de texto com um delimitador e quero duas colunas
A solução mais simples é:
df['A'], df['B'] = df['AB'].str.split(' ', 1).str
Ou você pode criar um DataFrame com uma coluna para cada entrada da divisão automaticamente com:
df['AB'].str.split(' ', 1, expand=True)
Você deve usar expand=True
se suas seqüências de caracteres tiverem um número não uniforme de divisões e desejar None
substituir os valores ausentes.
Observe como, em ambos os casos, o .tolist()
método não é necessário. Nem é zip()
.
Em detalhe:
A solução de Andy Hayden é mais excelente para demonstrar o poder do str.extract()
método.
Mas, para uma simples divisão sobre um separador conhecido (como, por hífens ou em branco), o .str.split()
método é suficiente 1 . Opera em uma coluna (Série) de cadeias e retorna uma coluna (Série) de listas:
>>> 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: Se você não tiver certeza do que os dois primeiros parâmetros .str.split()
fazem, recomendo os documentos para a versão simples do método Python .
Mas como você vai:
- uma coluna contendo listas de dois elementos
para:
- duas colunas, cada uma contendo o respectivo elemento das listas?
Bem, precisamos dar uma olhada mais de perto no .str
atributo de uma coluna.
É um objeto mágico que é usado para coletar métodos que tratam cada elemento em uma coluna como uma sequência e, em seguida, aplica o método respectivo em cada elemento da maneira mais eficiente possível:
>>> 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
Mas também possui uma interface de "indexação" para obter cada elemento de uma string pelo seu índice:
>>> df['AB'].str[0]
0 A
1 A
Name: AB, dtype: object
>>> df['AB'].str[1]
0 1
1 2
Name: AB, dtype: object
Obviamente, essa interface de indexação .str
não se importa realmente se cada elemento que está sendo indexado é realmente uma string, desde que possa ser indexado, portanto:
>>> 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
Então, é uma simples questão de tirar vantagem da descompactação tupla do Python dos iteráveis
>>> 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
Obviamente, tirar um DataFrame da divisão de uma coluna de strings é tão útil que o .str.split()
método pode fazer isso por você com o expand=True
parâmetro:
>>> df['AB'].str.split('-', 1, expand=True)
0 1
0 A1 B1
1 A2 B2
Portanto, outra maneira de realizar o que queríamos é fazer:
>>> 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
A expand=True
versão, embora mais longa, possui uma vantagem distinta sobre o método de descompactação da tupla. A descompactação da tupla não lida bem com divisões de diferentes comprimentos:
>>> 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
>>>
Mas expand=True
lida bem com isso, colocando None
nas colunas para as quais não há "divisões" suficientes:
>>> 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()
ouread_fwf()