熊猫使用正则表达式分隔符读取csv

时间:2020-04-10 14:41:56

标签: python regex pandas

我一直试图读取这样的自定义csv文件:

6 Rotterdam NLD Zuid-Holland 593321 
19 Zaanstad NLD Noord-Holland 135621 
214 Porto Alegre BRA Rio Grande do Sul 1314032 
397 Lauro de Freitas BRA Bahia 109236 
547 Dobric BGR Varna 100399 
552 Bujumbura BDI Bujumbura 300000 
554 Santiago de Chile CHL Santiago 4703954 
626 al-Minya EGY al-Minya 201360 
646 Santa Ana SLV Santa Ana 139389 
762 Bahir Dar ETH Amhara 96140 
123 Chicago 10000 
222 New York 200000  

我在https://regex101.com/中尝试了正则表达式 以下代码有效:

这有效

# https://regex101.com/
s = "6 Rotterdam NLD Zuid-Holland 593321 "
pat = r'(\d+)\s+([\D]+)\s(\d+)\s+'

m = re.match(pat,s)
m.groups() # ('6', 'Rotterdam NLD Zuid-Holland', '593321')

我得到了正确的答案,但是当我将代码应用于熊猫read_csv时,它以某种方式无法正常工作。

我的尝试

import numpy as np
import pandas as pd
from io import StringIO

s = """6 Rotterdam NLD Zuid-Holland 593321 
19 Zaanstad NLD Noord-Holland 135621 
214 Porto Alegre BRA Rio Grande do Sul 1314032 
397 Lauro de Freitas BRA Bahia 109236 
547 Dobric BGR Varna 100399 
552 Bujumbura BDI Bujumbura 300000 
554 Santiago de Chile CHL Santiago 4703954 
626 al-Minya EGY al-Minya 201360 
646 Santa Ana SLV Santa Ana 139389 
762 Bahir Dar ETH Amhara 96140 
123 Chicago 10000 
222 New York 200000  """;

sep = r'(\d+)\s+|([\D]+)\s+|(\d+)\s+'
df = pd.read_csv(StringIO(s), sep=sep,engine='python')
df

我得到很多Nans,如何只得到3列?

Column names are: ID CITY POPULATION

类似问题

2 个答案:

答案 0 :(得分:2)

您使用模式匹配(提取)文本,但在pandas方法中,您正在与模式分离。

如果每行开头只能有1位,2位或3位数字,请使用

sep = r'(?:(?<=^\d)|(?<=^\d{2})|(?<=^\d{3}))\s+|\s+(?=\S+\s*$)'

请参见regex demo。您可以通过在第一个非捕获组中添加更多的回溯来扩展它。

详细信息

  • (?:(?<=^\d)|(?<=^\d{2})|(?<=^\d{3}))\s+-1个以上的空格(\s+)前面有1位数字(\d,2位数字(\d{2})或3位数字({{ 1}})放在字符串(\d{3})的开头
  • ^-或
  • |-1+个空格,后跟1+个非空格字符,然后在字符串末尾加上任何结尾的0+空格。

答案 1 :(得分:1)

仅提供不使用正则表达式的替代解决方案:

您还可以使用纯Python解析文本文件。在某些情况下,这可能比复杂的正则表达式更容易维护。

对于这种特定格式,我们知道每行的第一个和最后一个数字具有特殊含义。因此,我本可以使用splitrsplit来选择它们。

import pandas as pd
from io import StringIO

s = """6 Rotterdam NLD Zuid-Holland 593321 
19 Zaanstad NLD Noord-Holland 135621 
214 Porto Alegre BRA Rio Grande do Sul 1314032 
397 Lauro de Freitas BRA Bahia 109236 
547 Dobric BGR Varna 100399 
552 Bujumbura BDI Bujumbura 300000 
554 Santiago de Chile CHL Santiago 4703954 
626 al-Minya EGY al-Minya 201360 
646 Santa Ana SLV Santa Ana 139389 
762 Bahir Dar ETH Amhara 96140 
123 Chicago 10000 
222 New York 200000  """

data = []
for line in StringIO(s):
    line = line.strip()
    if not line:
        continue
    id_value, line = line.split(" ", 1)
    city, population = line.rsplit(" ", 1)

    data.append((id_value, city, population))

df = pd.DataFrame(data, columns=["id", "city", "population"])
df["id"] = pd.to_numeric(df["id"])
df["population"] = pd.to_numeric(df["population"])
print(df)

我没有进行任何速度测量。但是,取决于文件大小,速度可能根本不是问题。但是,即使是这样:我将使用此脚本先(仅一次)预处理数据,以便能够使用常规的旧pd.read_csv而无需其他参数。