RegEx将地址分为三个不同的系列[第1部分]

时间:2019-07-31 14:12:39

标签: python regex pandas dataframe

我正在使用包含客户信息的数据集进行实验/学习Python。

DataFrame结构如下(这些都是记录):

import pandas as pd
import numpy as np

df = pd.DataFrame({'cus_name' : ['James', 'Mary', 'David', 'Linda', 'George', 'Jennifer', 'John', 'Maria', 'Charles', 'Helen'],
                   'address' : ['Main St 59', 'Yellow Av 11 b.F1', 'Terrazzo Way 100-102', np.nan, 'Hamilton St 159 b.A/B', np.nan, 'Henry St 7 D', 'Mc-Kenzie Av 40P b.1', 'Neptune Av 14 15 b.G', np.nan ], 
                   'postal_code' : [1410, 1210, 1020, np.nan, 1310, np.nan, 1080, 1190, 1040, np.nan], 
                  })

print(df)

   cus_name                address  postal_code
0     James             Main St 59       1410.0
1      Mary      Yellow Av 11 b.F1       1210.0
2     David   Terrazzo Way 100-102       1020.0
3     Linda                    NaN          NaN
4    George  Hamilton St 159 b.A/B       1310.0
5  Jennifer                    NaN          NaN
6      John           Henry St 7 D       1080.0
7     Maria   Mc-Kenzie Av 40P b.1       1190.0
8   Charles   Neptune Av 14 15 b.G       1040.0
9     Helen                    NaN          NaN

我对address系列特别感兴趣。具体来说,我的目标是将街道数字盒子的信息“拆分”为三个不同的系列。

例如,转换后,第一个和第七个记录/行应如下所示:

| cus_name | street       | number | box | postal_code |
|----------|--------------|--------|-----|-------------|
| James    | Main St      | 59     | NaN | 1410        |
| Maria    | Mc-Kenzie Av | 40P    | 1   | 1190.0      |

起初,我不知道如何解决这个问题。在这里进行了一些研究之后,我发现了一些有趣的,使用正则表达式的相关文章。

由于我不是Python专家(也不是正则表达式),所以我认为我可以从确定address系列中的模式开始。实际上,每个地址都有以下模式:

  • 位于字符串开头的街道部分。它由一个或多个用空格字符或破折号分隔的单词组成(例如Mc-Kenzie Av);

  • 位于字符串中间的 number 部分。它由一个或多个用空格字符或破折号分隔的字母数字词组成(例如100-1027 D);

  • 位于字符串末尾的部分。它始终紧跟b.个字符,由一个包含字母数字字符和可能包含某些特殊字符(例如A/BF1)的单词组成。

我正在寻求帮助,以使用正则表达式(如果正则表达式是解决方案)实现期望的目标。

2 个答案:

答案 0 :(得分:2)

您可以尝试以下模式:

pattern = "^(?P<street>.+)\s+(?P<number>[\d\w]+)\s+b\.(?P<box>.*)$"
df['address'].str.extract(pattern)

输出

          street number  box
0            NaN    NaN  NaN
1      Yellow Av     11   F1
2            NaN    NaN  NaN
3            NaN    NaN  NaN
4    Hamilton St    159  A/B
5            NaN    NaN  NaN
6            NaN    NaN  NaN
7   Mc-Kenzie Av    40P    1
8  Neptune Av 14     15    G
9            NaN    NaN  NaN

有关说明,请粘贴模式here

如果您要求街道严格没有数字,例如上面的第8行,请使用以下模式:

pattern = "^(?P<street>[\D]+)\s+(?P<number>[\w\s]+)\s+b\.(?P<box>.*)$"

给出:

         street number  box
0           NaN    NaN  NaN
1     Yellow Av     11   F1
2           NaN    NaN  NaN
3           NaN    NaN  NaN
4   Hamilton St    159  A/B
5           NaN    NaN  NaN
6           NaN    NaN  NaN
7  Mc-Kenzie Av    40P    1
8    Neptune Av  14 15    G
9           NaN    NaN  NaN

答案 1 :(得分:2)

另一种正则表达式方法:

In [913]: df[['street', 'number', 'box']] = df.address.str.extract(r'(\D+)\s+(\d+[\s-]?(?!b)\w*)(?:\s+b\.)?(\S+)?', expand=True)

In [914]: df
Out[914]: 
   cus_name                address  postal_code        street   number  box
0     James             Main St 59       1410.0       Main St       59  NaN
1      Mary      Yellow Av 11 b.F1       1210.0     Yellow Av       11   F1
2     David   Terrazzo Way 100-102       1020.0  Terrazzo Way  100-102  NaN
3     Linda                    NaN          NaN           NaN      NaN  NaN
4    George  Hamilton St 159 b.A/B       1310.0   Hamilton St      159  A/B
5  Jennifer                    NaN          NaN           NaN      NaN  NaN
6      John           Henry St 7 D       1080.0      Henry St      7 D  NaN
7     Maria   Mc-Kenzie Av 40P b.1       1190.0  Mc-Kenzie Av      40P    1
8   Charles   Neptune Av 14 15 b.G       1040.0    Neptune Av    14 15    G
9     Helen                    NaN          NaN           NaN      NaN  NaN