【问题标题】:RegEx to split address into three distinct Series [Part 1]RegEx 将地址拆分为三个不同的系列 [第 1 部分]
【发布时间】:2019-12-09 02:18:32
【问题描述】:

我正在使用包含客户信息的数据集来试验/学习 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

我对@9​​87654322@ 系列特别感兴趣。具体来说,我的目标是将 streetnumberbox 的信息“拆分”为三个不同的 Series。

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

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

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

由于我不是 Python 专家(也不是正则表达式),我想我可以从识别 address 系列中的模式开始。其实每个地址都有如下模式:

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

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

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

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

【问题讨论】:

    标签: python regex pandas dataframe


    【解决方案1】:

    另一种正则表达式方法:

    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
    

    【讨论】:

      【解决方案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
      

      【讨论】:

      • [\d\w] = \w,并且b.必须是b\.,因为.是原始数据中的一个点。
      • @QuangHoang 谢谢,非常感谢。您的解决方案几乎就是我想要的。有没有一种简单的方法来修改您的代码,以便在缺少框信息时,该模式仍然捕获街道和数字部分?我在原始帖子中添加了一个明确的示例。
      • 与另一个答案类似,您可以将模式更改为pattern = "^(?P&lt;street&gt;.+)\s+(?P&lt;number&gt;[\w-]+)?[\s+b\.]?(?P&lt;box&gt;.*)$"
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-11
      • 1970-01-01
      相关资源
      最近更新 更多