使用正则表达式有选择地将数据拉取到 pandas 数据帧中



我正在使用正则表达式和熊猫来读取文件中的文本行,并有选择地将数据拉入数据帧。

假设我有以下文本行

Name : "Bob" Occupation : "Builder" Age : "42" Name : "Jim" Occupation : "" Age : "25"

我想将所有这些信息拉入数据帧,使其如下所示:

Name    Occupation    Age
Bob      Builder       42

我想忽略阅读有关第二个人的任何信息,因为他们的职业是空白的。

法典:

with open(txt, 'r') as txt
for line in txt:
line = line.strip
a = re.findall(r'Name : "(S+)"', line)
if a:
b = re.findall(r'Occupation : "(S+)"', line)
if b:
c = re.findall(r'Age : "(S+)"', line)
if c:
df = df.append({'Name' : a, 'Occupation' : b, 'Age' : c}, ignore_index = True)

这将返回以下(不正确的)数据帧

Name        Occupation      Age
["Bob", "Jim"]  ["Builder"]  ["42","25"]

我想修改此代码,使其永远不会包含"Jim"所处的情况,即如果此人没有"职业",则不要将他们的信息读取到数据帧中。您还可以看到此代码不正确,因为它现在说"Jim"的职业为"Builder"。

如果给我以下几行文字:

Name : "Bob" Occupation : "Builder" Age : "42" Name : "Jim" Occupation : "" Age : "25" Name : "Steve" Occupation : "Clerk" Age : "110"

生成的 df 将是:

Name              Occupation             Age
["Bob", "Steve"]  ["Builder", "Clerk"]  ["42","110"]

这很方便,因为我不会再遇到任何索引问题,所以我可以将这个 df 扩展到我的最终目标(知道如何做):

Name  Occupation  Age
Bob   Builder     42
Steve Clerk       110

根据您的评论,NameOccupationAge的 3 个键始终处于相同的顺序,因此我们可以使用单个正则表达式模式来检索字段值,同时确保匹配的值为非空。下面是一个使用 Series.str.extractall() 的示例:

# example texts copied from your post
str="""
Name : "Bob" Occupation : "Builder" Age : "42" Name : "Jim" Occupation : "" Age : "25" Name : "Steve" Occupation : "Clerk" Age : "110"
Name : "Bob" Occupation : "Builder" Age : "42" Name : "Jim" Occupation : "" Age : "25"
"""
# read all lines into one field dataframe with column name as 'text'
df = pd.read_csv(pd.io.common.StringIO(str), squeeze=True, header=None).to_frame('text')
# 3 fields which have the same regex sub-pattern
fields = ['Name', 'Occupation', 'Age']
# regex pattern used to retrieve values of the above fields. There are 3 sub-patterns
# corresponding to the above 3 fields and joined by at least one white spaces(s+)
ptn = r's+'.join([ r'{0}s*:s*"(?P<{0}>[^"]+)"'.format(f) for f in fields ])
print(ptn)
#Names*:s*"(?P<Name>[^"]+)"s+Occupations*:s*"(?P<Occupation>[^"]+)"s+Ages*:s*"(?P<Age>[^"]+)"

哪里:

  • 子模式Names*:s*"(?P<Name>[^"]+)"基本上与Name : "([^"]+)"相同,但冒号:周围有0更多空白区域和命名捕获组。
  • "([^"]+)"+加号字符是为了确保用双引号括起来的值不为空,因此将跳过 Jim 的个人资料,因为他的职业是空的。
  • 使用命名捕获组,以便我们可以在运行 Series.str.extractall() 后拥有正确的列名,否则生成的列名将默认为012

然后你可以从 Series.str.extractall() 检查结果:

df['text'].str.extractall(ptn)
Name Occupation  Age
match
0 0        Bob    Builder   42
1      Steve      Clerk  110
1 0        Bob    Builder   42

删除 1 级索引,您将获得一个包含原始索引的数据帧。如果任务中使用了其他列,则可以将其联接回原始数据帧。

df['text'].str.extractall(ptn).reset_index(level=1, drop=True)
###
Name Occupation  Age
0    Bob    Builder   42
0  Steve      Clerk  110
1    Bob    Builder   42

使用正则表达式 -->re.finditer与正则表达式分组。

前任:

import re
import pandas as pd
s = 'Name : "Bob" Occupation : "Builder" Age : "42" Name : "Jim" Occupation : "" Age : "25"'
name = re.findall(r'Name : "(.*)" ', s)
occupation = re.findall(r'Occupation : "(.*)" ', s)
age = re.findall(r'Age : "(.*)" ', s)
regexPattern = re.compile(r'Name : "(?P<name>.*?)"s+Occupation : "(?P<occupation>.*?)"s+Age : "(?P<age>.*?)"')
df = pd.DataFrame([i.groupdict() for i in regexPattern.finditer(s) if len(filter(None, i.groupdict().values())) == 3])
print(df)

输出:

age name occupation
0  42  Bob    Builder

你说这些字符串有一个固定的格式,Name先出现,Occupation跟随,然后Age。您可以使用

df = pd.DataFrame()
pat = r'Names*:s*"([^"]+)"s*Occupations*:s*"([^"]+)"s*Ages*:s*"(d+)"'
s='Name : "Bob" Occupation : "Builder" Age : "42" Name : "Jim" Occupation : "" Age : "25" Name : "Steve" Occupation : "Clerk" Age : "110"'
for name, occupation, age in re.findall(pat, s):
df = df.append({'Name' : name, 'Occupation' : occupation, 'Age' : age}, ignore_index = True)

输出:

>>> df
Age   Name Occupation
0   42    Bob    Builder
1  110  Steve      Clerk

正则表达式是

Names*:s*"([^"]+)"s*Occupations*:s*"([^"]+)"s*Ages*:s*"(d+)"

请参阅正则表达式演示。由于捕获组中的量词设置为+(一次或多次出现),因此这些值永远不会为空。为避免前两个中的空值,您可以更改模式Names*:s*"([^"]*[^s"][^"]*)"s*Occupations*:s*"([^"]*[^s"][^"]*)"s*Ages*:s*"(d+)",请参阅此演示。

  • Name-Name
  • s*:s*-:用 0+ 空格括起来
  • "- 双引号
  • ([^"]+)- 第 1 组:除"以外的一个或多个字符
  • "- 双引号
  • s*- 0+ 空格
  • Occupations*:s*"
  • ([^"]+)- 第 2 组:除"以外的一个或多个字符
  • "s*Ages*:s*"-"、0+ 空格、
  • Age:用 0+ 空格括起来,然后"
  • (d+)- 第 3 组:一个或多个数字
  • "- 双引号

相关内容

最新更新