簡體   English   中英

使用正則表達式有選擇地將數據拉入pandas數據框

[英]Using regex to selectively pull data into pandas dataframe

我正在使用正則表達式和熊貓來讀取文件中的文本行,並有選擇地將數據拉入數據框。

說我有以下文字

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總是相同的順序,因此我們可以使用單個正則表達式模式檢索字段值,同時確保匹配的值是非EMPTY。 以下是使用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)
#Name\s*:\s*"(?P<Name>[^"]+)"\s+Occupation\s*:\s*"(?P<Occupation>[^"]+)"\s+Age\s*:\s*"(?P<Age>[^"]+)"

哪里:

  • 子模式Name\\s*:\\s*"(?P<Name>[^"]+)"Name : "([^"]+)"基本相同,但可選地0更大冒號周圍的空白:和一個命名的捕獲組。
  • "([^"]+)"的加號+是為了確保用雙引號引起來的值不是EMPTY,因此將跳過Jim的個人資料,因為他的職業是EMPTY。
  • 使用命名的捕獲組,使我們可以在運行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 > re.finditer和regex分組。

例如:

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'Name\s*:\s*"([^"]+)"\s*Occupation\s*:\s*"([^"]+)"\s*Age\s*:\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

正則表達式是

Name\s*:\s*"([^"]+)"\s*Occupation\s*:\s*"([^"]+)"\s*Age\s*:\s*"(\d+)"

參見regex演示 由於捕獲組中的量詞設置為+ (一次或多次出現),因此這些值永遠不會為空。 為了避免前兩個值都是空,您可以將模式更改為Name\\s*:\\s*"([^"]*[^\\s"][^"]*)"\\s*Occupation\\s*:\\s*"([^"]*[^\\s"][^"]*)"\\s*Age\\s*:\\s*"(\\d+)" ,請參見此演示

細節

  • Name - Name
  • \\s*:\\s* - :包含0+空格
  • " -雙引號
  • ([^"]+) -組1:一個或多個除"
  • " -雙引號
  • \\s* -0+空格
  • Occupation\\s*:\\s*"
  • ([^"]+) -第2組: "以外的一個或多個字符
  • "\\s*Age\\s*:\\s*" - "空格, Age:附帶0+空格,然后"
  • (\\d+) -第3組:一個或多個數字
  • " -雙引號

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM