首页 > 解决方案 > Python:使用正则表达式从 Pandas 系列中提取信息

问题描述

我在 Pandas 系列中有一些连接的文本数据,我想将其分成 3 列。

系列中每个“单元格”中的字符串由 3 个部分组成,如下所示:

[农药名称][检出量_(mg/kg)][MRL]

我已经探索过使用series.str.split(...,但我认为s.str.extract(...紧随其后的正则表达式捕获组会更有效。但是,我是正则表达式的新手,事实证明这是一个巨大的挑战

我正在尝试使用的解决方案在这里

这是该系列的示例:

df['pesticide_residues_found_in_mg/kg_(mrl)'].head(20)
# 0     Spirotetramat (partial sum) 0.03 (MRL = 2)
# 1                                            n/a
# 2                                            n/a
# 3                                            n/a
# 4                                            n/a
# 5                                            n/a
# 6                                            n/a
# 7                     fluopyram 0.01 (MRL = 0.9)
# 8                   fenpyrazamine 0.02 (MRL = 3)
# 9                     fluopyram 0.05 (MRL = 0.9)
# 10                  acetamiprid 0.03 (MRL = 0.2)
# 11                   cyprodinil 0.04 (MRL = 1.5)
# 12                  fludioxonil 0.02 (MRL = 0.4)
# 13                  fenpyrazamine 0.07 (MRL = 3)
# 14                  thiacloprid 0.02 (MRL = 0.7)
# 15                  acetamiprid 0.04 (MRL = 0.2)
# 16                 chlorothalonil 0.03 (MRL = 6)
# 17                    cyprodinil 0.1 (MRL = 1.5)
# 18                  fludioxonil 0.03 (MRL = 0.4)
# 19                   pyrimethanil 0.09 (MRL = 1)
# Name: pesticide_residues_found_in_mg/kg_(mrl), dtype: object

我想从这个系列中提取的信息是:1)农药名称,这是第一个字。2) 检测到的数量,可以是小数或浮点数,表示到小数点后一位或两位。3) MRL,但是我只想捕获数字,而不是括号或“MRL =”

注释: *农药名称:有时是一个由两部分组成的连字词,例如“lambda-cyhalothrin”。*农药名称:有时该名称后跟括号中的额外信息,例如“(总和)”或“(部分总和)”。*检测数量:虽然数字通常表示为一位或两位小数,但可以想象检测到的数量将是一个整数,例如“4”或“20”。

我试过的代码:

df['pesticide_residues_found_in_mg/kg_(mrl)'].str.extract(r'(?P<mrl>\(MRL = \d.?\d+?\))') 
# This works but captures "MRL = " but if I remove this, it tends to capture the amount detected instead, so "MRL = " identifies the correct number although it's junk I do not want. 

df['pesticide_residues_found_in_mg/kg_(mrl)'].str.extract(r'(?P<mrl>\d+\.?\d+?)'
#This doesn't work and results in capturing the amount detected part of the string instead, and only to one decimal place too!

对检测到的数量的正则表达式捕获组的尝试可能是: (?P\d+.?\d{1,2}?)

我还尝试使用\b,^和之类$的标记来标记单词边界和字符串的开头和结尾,但似乎也无法完成这项工作。

我想在我的 df 中实现的新系列的一个例子:

index    - chem_name      - amount_detected - mrl 
0        - chlorothalonil - 0.03            - 0.1
1        - fenpyrazamine  - 0.1             - 3
2        | ddt (sum)      | 2.45            | 0

标签: pythonregexpandas

解决方案


干得好。让我知道你的想法。只需使用“字符串提取”并重命名要匹配的列。代码在这里:

import pandas as pd
from pandas.compat import StringIO


RawData="""
id;pesticide_residues_found_in_mg/kg_(mrl)
0;Spirotetramat (partial sum) 0.03 (MRL = 2)
1;n/a
2;n/a
3;n/a
4;n/a
5;n/a
6;n/a
7;fluopyram 0.01 (MRL = 0.9)
8;fenpyrazamine 0.02 (MRL = 3)
9;fluopyram 0.05 (MRL = 0.9)
10;acetamiprid 0.03 (MRL = 0.2)
11;cyprodinil 0.04 (MRL = 1.5)
12;fludioxonil 0.02 (MRL = 0.4)
13;fenpyrazamine 0.07 (MRL = 3)
14;thiacloprid 0.02 (MRL = 0.7)
15;acetamiprid 0.04 (MRL = 0.2)
16;chlorothalonil 0.03 (MRL = 6)
17;cyprodinil 0.1 (MRL = 1.5)
18;fludioxonil 0.03 (MRL = 0.4)
19;pyrimethanil 0.09 (MRL = 1)

"""
df = pd.read_csv(StringIO(RawData), sep=";")
df=df['pesticide_residues_found_in_mg/kg_(mrl)'].str.extract(r'(.*)\s(\d[\d.]*)\s+\(MRL\s*=\s*(\d[\d.]*)\)')
df.rename(columns={0:'pesticide name',1:'amount detected',2:'MRL'},inplace=True)
df.dropna()

结果如下:

    pesticide name  amount detected MRL
0   Spirotetramat (partial sum) 0.03    2
7   fluopyram   0.01    0.9
8   fenpyrazamine   0.02    3
9   fluopyram   0.05    0.9
10  acetamiprid 0.03    0.2
11  cyprodinil  0.04    1.5
12  fludioxonil 0.02    0.4
13  fenpyrazamine   0.07    3
14  thiacloprid 0.02    0.7
15  acetamiprid 0.04    0.2
16  chlorothalonil  0.03    6
17  cyprodinil  0.1 1.5
18  fludioxonil 0.03    0.4
19  pyrimethanil    0.09    1

推荐阅读