2017-10-03 3 views
0

J'ai un jeu de données dans lequel j'essaie d'extraire le nom de ville simple de la version la plus désordonnée montrée ici. La plupart d'entre eux sont suivis de parenthèses "(. *", Mais certains ne suivent pas ce modèle et se terminent par ":" (voir ligne 200) Enfin, il y en a qui n'ont pas de parenthèses mais des parties séparées par une virgule ", . "(voir la ligne 240, 246)Impossible d'extraire une chaîne à l'aide de plusieurs caractères spéciaux ou d'un modèle en même temps en python

           'Region' 
196 Boston (Boston University, Boston College, Bos... 
197   Bridgewater (Bridgewater State College)[2] 
198 Cambridge (Harvard University, Massachusetts I... 
199      Chestnut Hill (Boston College) 
200    The Colleges of Worcester Consortium: 
201        Dudley (Nichols College) 
240      Faribault, South Central College 
241 Mankato (Minnesota State University, Mankato),... 
242 Marshall (Southwest Minnesota State University... 
243 Moorhead (Minnesota State University, Moorhead... 
244   Morris (University of Minnesota Morris)[2] 
245 Northfield (Carleton College, St. Olaf College... 
246     North Mankato, South Central College 
247 St. Cloud (St. Cloud State University, The Col... 
248   St. Joseph (College of Saint Benedict)[2] 
249    St. Peter (Gustavus Adolphus College)[2] 

ce que je voudrais idéalement voir est:

        'RegionName' 
    196         Boston 
    197       Bridgewater 
    198        Cambridge 
    199       Chestnut Hill 
    200 The Colleges of Worcester Consortium 
    201         Dudley 
    240        Faribault 
    241        Mankato 
    242        Marshall 
    243        Moorhead 
    244         Morris 
    245        Northfield 
    246       North Mankato 
    247        St. Cloud 
    248        St. Joseph 
    249        St. Peter 

Mon code est actuellement:

df['RegionName'] = df['Region'].str.extract('(.*)[:(,]', expand=False) 

Mais cela me donne l'étrange résultat de ne pas obtenir le gréement parenthèses ht:

196 Boston (Boston University, Boston College, Bos... 
197           Bridgewater 
198 Cambridge (Harvard University, Massachusetts I... 
199          Chestnut Hill 
200     The Colleges of Worcester Consortium 
201            Dudley 
240           Faribault 
241  Mankato (Minnesota State University, Mankato) 
242           Marshall 
243 Moorhead (Minnesota State University, Moorhead 
244           Morris 
245      Northfield (Carleton College 
246          North Mankato 
247    St. Cloud (St. Cloud State University 
248          St. Joseph 
249          St. Peter 

J'ai aussi essayé:

df['RegionName'] = df['Region'].str.extract('(.*)[ (.*|:|,]', expand=False) 

Je ne sais pas exactement comment extraire la chaîne en utilisant les trois modèles en même temps. Serait également ouvert à une solution à deux lignes. Merci (mes excuses si cela est formaté mal!)

Répondre

1

Vous pouvez juste extraire tout 0 ou plusieurs caractères autres que :, , ou ( au début d'une chaîne avec

df['RegionName'] = df['Region'].str.extract(r'^([^:(,]*)\b', expand=False) 

Si vous travaillez avec Python 2.x, utilisez (?u) au début de le motif de sorte que la limite de mot \b puisse également correspondre aux bons endroits dans une chaîne Unicode.

Détails

  • ^ - début d'une chaîne
  • ([^:(,]*) - Groupe 1: zéro ou plus (*) occurrences consécutives de toute carbonisation autre que (les [^...] forme un niés classe de caractères) :, ( et ,.
  • \b - une limite de mot.

Voir la regex demo et Python 3 démo ci-dessous:

>>> from pandas import DataFrame 
>>> import pandas as pd 
>>> item_list = ['Boston (Boston University, Boston College, Bos...','Bridgewater (Bridgewater State College)[2]','Cambridge (Harvard University, Massachusetts I...','Chestnut Hill (Boston College)','The Colleges of Worcester Consortium:','Dudley (Nichols College)','Faribault, South Central College','Mankato (Minnesota State University, Mankato),...','Marshall (Southwest Minnesota State University...','Moorhead (Minnesota State University, Moorhead...','Morris (University of Minnesota Morris)[2]','Northfield (Carleton College, St. Olaf College...','North Mankato, South Central College','St. Cloud (St. Cloud State University, The Col...','St. Joseph (College of Saint Benedict)[2]','St. Peter (Gustavus Adolphus College)[2]'] 
>>> df = pd.DataFrame(item_list, columns=['Region']) 
>>> df['RegionName'] = df['Region'].str.extract(r'^([^:(,]*)\b', expand=False) 
>>> df['RegionName'] 

           RegionName 
0         Boston 
1       Bridgewater 
2        Cambridge 
3       Chestnut Hill 
4 The Colleges of Worcester Consortium 
5         Dudley 
6        Faribault 
7        Mankato 
8        Marshall 
9        Moorhead 
10        Morris 
11       Northfield 
12       North Mankato 
13        St. Cloud 
14       St. Joseph 
15        St. Peter 
>>> 
+0

Merci pour cette réponse. Quelque chose que je n'ai pas montré dans l'ensemble de données est qu'il y a des états énumérés tels que "Michigan \ [edit \]", que je veux supprimer. Auparavant, le 'str.extract' a fait ceux-ci en NaN et donc je les déposerais. Mais votre méthode les laisse dans l'ensemble de données (ils deviennent "Michigan [edit"). Comment vous adapteriez-vous à cela? Partie 2: J'ai essayé: 'df ['RegionName'] = df ['RegionName']. tout en NaN. Pourquoi cela serait-il? Au lieu de cela, je l'ai remplacé par une cellule vide, puis remplacé vide à NaN. Cela semble inefficace. Thx – Vicki

+0

Essayez ['r '^ ([^: (,] *?) \ S * [: (,]''] (https://regex101.com/r/asdHNp/1) et utilisez votre précédent 'dropna 'approche. –

0

Utilisez cette expression régulière:

([\w\s.]+)(?<!\s) 

Vous pouvez supprimer le look-derrière (?<!\s) négatif à la fin si vous ne se soucient pas de fuite des espaces blancs.

1

Puisque vous avez seulement trois délimiteurs possibles, vous pouvez tirer parti de split() chaîné, car split retournera la chaîne non modifiée si le délimiteur n'est pas trouvé.

>>> s = """196 Boston (Boston University, Boston College, Bos... 
... 197   Bridgewater (Bridgewater State College)[2] 
... 198 Cambridge (Harvard University, Massachusetts I... 
... 199      Chestnut Hill (Boston College) 
... 200    The Colleges of Worcester Consortium: 
... 201        Dudley (Nichols College) 
... 240      Faribault, South Central College 
... 241 Mankato (Minnesota State University, Mankato),... 
... 242 Marshall (Southwest Minnesota State University... 
... 243 Moorhead (Minnesota State University, Moorhead... 
... 244   Morris (University of Minnesota Morris)[2] 
... 245 Northfield (Carleton College, St. Olaf College... 
... 246     North Mankato, South Central College 
... 247 St. Cloud (St. Cloud State University, The Col... 
... 248   St. Joseph (College of Saint Benedict)[2] 
... 249    St. Peter (Gustavus Adolphus College)[2]""" 
>>> for i in s.split('\n'): 
... number, text = i.split('(')[0].split(',')[0].split(':')[0].split(' ',1) 
... print('{} {}'.format(number, text.strip())) 
... 
196 Boston 
197 Bridgewater 
198 Cambridge 
199 Chestnut Hill 
200 The Colleges of Worcester Consortium 
201 Dudley 
240 Faribault 
241 Mankato 
242 Marshall 
243 Moorhead 
244 Morris 
245 Northfield 
246 North Mankato 
247 St. Cloud 
248 St. Joseph 
249 St. Peter 

Vous pouvez utiliser df.apply faire la même transformation pour vos cordes.

+0

Je ne pense pas que le numéro de ligne et le rembourrage est une partie des données - il est juste la façon dont les données sont formatées lors de l'impression à la console . – Mark