【问题标题】:Pandas: explode a column into multiple rowsPandas:将一列分解为多行
【发布时间】:2021-07-23 20:57:26
【问题描述】:

在 Pandas 中基于正则表达式拆分字段和创建数据框时需要一些帮助。

A B C
1129 19-APR-2021 Zip Code Details: City: Huntsville_Alabama , Zip: 35808 , 801thru816 City: Anchorage_Alaska , Zip: 99506 , 501thru524
1139 20-APR-2021 Zip Code Details: City: Miami_Florida , Zip: 33128 , 124thru190 City: Atlanta_Georgia , Zip: 30301 , 301thru381

在其中一个 C 列中,需要提取多个 City & Zip Code 详细信息并在 以下格式:

No Date City Zip
1129 19-APR-2021 Huntsville_Alabama 35808
1129 19-APR-2021 Anchorage_Alaska 99506
1139 20-APR-2021 Miami_Florida 33128
1139 20-APR-2021 Atlanta_Georgia 30301

我的 re.findall 表达式如下,工作正常:

city_regex_extract = r" [a-z|A-Z|0-9|_]*\_[a-z|A-Z|0-9|_]*"    (https://regex101.com/r/VM8oFF/1)
zip_regex_extract = r"[0-9]{5}"                            (https://regex101.com/r/oBYJZX/1)

以下是目前的代码,但无法添加 Zip 字段。

import pandas as pd
import json, re, sys, time


df = pd.DataFrame({
   'No': ['1129', '1139'],
   'Date': ['19-APR-2021','20-APR-2021'],
   'C': ['Zip Code Details: City: Huntsville_Alabama , Zip: 35808 , 801thru816  City: Anchorage_Alaska , Zip: 99506 , 501thru524','Zip Code Details: City: Miami_Florida , Zip: 33128 , 124thru190  City: Atlanta_Georgia , Zip: 30301 , 301thru381'] 
})


city_regex_extract = r" [a-z|A-Z|0-9|_]*\_[a-z|A-Z|0-9|_]*"
zip_regex_extract = r"[0-9]{17}"


df['City'] =  [re.findall(city_regex_extract, str(x)) for x in df['C']]
df['Zip'] =  [re.findall(zip_regex_extract, str(x)) for x in df['C']]

df = (df
.set_index(['No','Date'])['City']
.apply(pd.Series)
.stack()
.reset_index()
.drop('level_2', axis=1)
.rename(columns={0:'City'}))

print(df)

感谢任何帮助。

【问题讨论】:

    标签: python regex pandas dataframe


    【解决方案1】:

    Series.str.extractall

    s = df['C'].str.extractall(r'City:\s*(?P<City>[^,]+?)\s*,\s*Zip:\s*(?P<Zip>\d+)')
    df[['No', 'Date']].join(s.droplevel(1))
    

         No         Date                City    Zip
    0  1129  19-APR-2021  Huntsville_Alabama  35808
    0  1129  19-APR-2021    Anchorage_Alaska  99506
    1  1139  20-APR-2021       Miami_Florida  33128
    1  1139  20-APR-2021     Atlanta_Georgia  30301
    

    正则表达式详细信息:

    • City: :匹配字符 City: 字面意思
    • \s* :匹配零个或多个空白字符
    • (?P&lt;City&gt;[^,]+?):第一个命名的捕获组
      • [^,]+?:匹配任何字符,除了 , 一次或多次,但尽可能少
    • \s*,\s* :匹配零个或多个空格,后跟逗号,后跟零个或多个空格
    • Zip: :匹配字符 Zip: 字面意思
    • \s* :匹配零个或多个空白字符
    • (?P&lt;Zip&gt;\d+): 第二个命名捕获组
      • \d+:匹配一个数字一次或多次

    在线查看regex demo

    【讨论】:

    • 谢谢舒巴姆。但是我无法获得上述输出。不知道我是否遗漏了什么,下面是输出:否日期 C 0 1129 19-APR-2021 邮政编码详细信息:城市:Huntsville_Alabama,Z... 1 1139 20-APR-2021 邮政编码详细信息:城市:Miami_Florida,邮政编码: 3...
    • 使用上述方法 2 或 4 后你得到了多少行?
    • 我只能查看 2 条记录,而无需提取任何城市或邮编。
    • df[['No', 'Date']].join(s.droplevel(1)) 不是inplace 操作,您必须将其分配回某个变量。例如out = df[['No', 'Date']].join(s.droplevel(1)) 现在检查out 的值
    【解决方案2】:

    在我看来,你实际上甚至不需要正则表达式库,pandas 包含正则表达式,因此你可以拆分:

    df['C'] = df['C'].str.split(' City: ').str[1:]
    df = df.explode('C')
    df[['City','Zip']] = df['C'].str.split(' , Zip: | , ', expand=True).iloc[:,:2]
    
    print(df)
    
         No         Date                City    Zip
    0  1129  19-APR-2021  Huntsville_Alabama  35808
    0  1129  19-APR-2021    Anchorage_Alaska  99506
    1  1139  20-APR-2021       Miami_Florida  33128
    1  1139  20-APR-2021     Atlanta_Georgia  30301
    

    expand=True 参数允许一次检索多个列。 .iloc[] 用于选择拆分发生后要使用的值。

    【讨论】:

    • 谢谢 Andreas,但是我无法获得 4 条记录。仅检索到 Anchorage_Alaska 和 Atlanta_Georgia。
    • @pats4u 哦,你是对的,修复它。很抱歉造成混乱。
    【解决方案3】:

    CityZip 上尝试.explode(),然后是reset_index(),最后在索引上加入两个爆炸结果

    df.explode('City').reset_index()[['No', 'Date', 'City']]\
        .join(df.explode('Zip').reset_index()[['Zip']])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-30
      • 1970-01-01
      相关资源
      最近更新 更多