Version TL; DR:
Pour le cas simple de:
- J'ai une colonne de texte avec un délimiteur et je veux deux colonnes
La solution la plus simple est:
df['A'], df['B'] = df['AB'].str.split(' ', 1).str
Ou vous pouvez créer créer un DataFrame avec une colonne pour chaque entrée de la division automatiquement avec:
df['AB'].str.split(' ', 1, expand=True)
Vous devez utiliser expand=True
si vos chaînes ont un nombre non uniforme de fractionnements et que vous souhaitez None
remplacer les valeurs manquantes.
Remarquez comment, dans les deux cas, la .tolist()
méthode n'est pas nécessaire. Ni l'un ni l'autre zip()
.
En détail:
La solution d'Andy Hayden est la plus excellente pour démontrer la puissance de la str.extract()
méthode.
Mais pour un simple fractionnement sur un séparateur connu (comme le fractionnement par des tirets ou le fractionnement par des espaces), la .str.split()
méthode est suffisante 1 . Il fonctionne sur une colonne (série) de chaînes et renvoie une colonne (série) de listes:
>>> 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: Si vous n'êtes pas sûr de ce que font les deux premiers paramètres .str.split()
, je recommande les documents pour la version Python standard de la méthode .
Mais comment allez-vous:
- une colonne contenant des listes à deux éléments
à:
- deux colonnes, chacune contenant l'élément respectif des listes?
Eh bien, nous devons examiner de plus près l' .str
attribut d'une colonne.
C'est un objet magique qui est utilisé pour collecter des méthodes qui traitent chaque élément d'une colonne comme une chaîne, puis appliquent la méthode respective dans chaque élément aussi efficacement que possible:
>>> 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
Mais il a aussi une interface "d'indexation" pour récupérer chaque élément d'une chaîne par son index:
>>> df['AB'].str[0]
0 A
1 A
Name: AB, dtype: object
>>> df['AB'].str[1]
0 1
1 2
Name: AB, dtype: object
Bien sûr, cette interface d'indexation de .str
ne se soucie pas vraiment si chaque élément qu'il indexe est en fait une chaîne, tant qu'il peut être indexé, donc:
>>> 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
Ensuite, c'est une simple question de tirer parti du déballage du tuple Python des itérables pour faire
>>> 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
Bien sûr, extraire un DataFrame du fractionnement d'une colonne de chaînes est si utile que la .str.split()
méthode peut le faire pour vous avec le expand=True
paramètre:
>>> df['AB'].str.split('-', 1, expand=True)
0 1
0 A1 B1
1 A2 B2
Donc, une autre façon d'accomplir ce que nous voulions est de faire:
>>> 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
La expand=True
version, bien que plus longue, présente un net avantage sur la méthode de décompression de tuple. Le déballage de tuple ne gère pas bien les divisions de différentes longueurs:
>>> 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
>>>
Mais le expand=True
gère bien en plaçant None
dans les colonnes pour lesquelles il n'y a pas assez de "divisions":
>>> 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()
orread_fwf()