【问题标题】:Use of Regex based partial matches to select a subdataframe of a Pandas dataframe使用基于正则表达式的部分匹配来选择 Pandas 数据帧的子数据帧
【发布时间】:2018-04-18 07:05:45
【问题描述】:

我有一个 Pandas 数据框,它有两列,一列(“流程参数”列)包含字符串,另一列(“值”列)具有相应的浮点值。我需要过滤掉与列“流程参数”中的一组键部分匹配的子数据框,并提取与这些键匹配的数据框的两列

df = pd.DataFrame({'Process Parameter' : ['Temperature', 'System Clk', 'Core Clk', 'Bilinear Coeff', 'Prec Coeff', 'Yield'], 'Value' : [1.2,2.0,3.0, 5.1, 6.2, 7.4]})

keys =['Clk', 'Coeff']

我应该得到一个输出

df_filtered 为

Process Parameter    Value
System Clk            3.0
Core Clk              2.0
Bilinear Coeff        5.1
Prec Coeff            6.2

我尝试了几种混乱的方法,例如将数据框转换为列表,然后使用 re.search(), map, str.contains() 等。任何有非常有效的解决方案的人请告诉我

感谢和问候, 桑托什

【问题讨论】:

  • 所有keys 都只是一个词,或者可能是多个词,如keys =['Clk aa', 'Coeff b']

标签: python regex pandas dataframe slice


【解决方案1】:

选项 1
你可以使用numpy.core.defchararray.find

from numpy.core.defchararray import find

p = df['Process Parameter'].values.astype(str)
df[(find(p[:, None], keys) >= 0).any(1)]

  Process Parameter  Value
1        System Clk    2.0
2          Core Clk    3.0
3    Bilinear Coeff    5.1
4        Prec Coeff    6.2

解释
numpy.core.defchararray 标识它在字符串中找到另一个字符串的位置。如果没有找到,它会返回-1。所以我只需要检查>= 0。我还利用numpy 广播,然后检查是否在所有keys 中找到任何匹配项。


选项 2
我喜欢设定逻辑。

df[df['Process Parameter'].str.split().apply(set) & set(keys)]

  Process Parameter  Value
1        System Clk    2.0
2          Core Clk    3.0
3    Bilinear Coeff    5.1
4        Prec Coeff    6.2

【讨论】:

  • 一直在等你回答!
  • 我完全被淹没了。我会在这里和那里用很少的时间淹没一段时间(-:
  • 为了进一步复杂化,在键列表中,我可以添加另一个约束,即字符串应该以这些键结尾。例如,我想匹配部分字符串“Clock”但不想匹配“Clocks”......如果输入字符串是“System Clock”、“Core Clock”、“Clockspeed”,则输出正则表达式匹配只能是“系统时钟”和“核心时钟”——
【解决方案2】:

选项 1
str.findall

df = df[df['Process Parameter'].str.findall('|'.join(keys)).astype(bool)]
df

  Process Parameter  Value
1        System Clk    2.0
2          Core Clk    3.0
3    Bilinear Coeff    5.1
4        Prec Coeff    6.2

选项 2
只是为了好玩,str.split + df.isin:

m = df['Process Parameter'].str.split(expand=True).isin(keys).any(1)
m

0    False
1     True
2     True
3     True
4     True
5    False
dtype: bool


df[m]

  Process Parameter  Value
1        System Clk    2.0
2          Core Clk    3.0
3    Bilinear Coeff    5.1
4        Prec Coeff    6.2

此方法不使用基于正则表达式的检查,但是,它仅适用于单个完整单词匹配(不适用于多单词或子字符串匹配)。

【讨论】:

  • @jezrael 因为正如你所说的那样,它不适用于多个单词。
  • 我不是 100% 确定,但我认为基于非正则表达式的比较比正则表达式更快,但我不能保证,因为我没有计时。
  • 是的,有可能。但我认为这里是检查更多单词键的更好更通用的解决方案 - 如果 OP 不能保证总是一个单词关键字。
  • 我重新排序了选项,希望现在可以了。
  • 嗯,第二个解决方案最慢,正则表达式获胜 ;)
【解决方案3】:

使用contains|(正则表达式OR)作为布尔掩码,然后按boolean indexing 过滤:

df = df[df['Process Parameter'].str.contains('|'.join(keys))]
print (df)
  Process Parameter  Value
1        System Clk    2.0
2          Core Clk    3.0
3    Bilinear Coeff    5.1
4        Prec Coeff    6.2

详情:

print (df['Process Parameter'].str.contains('|'.join(keys)))
0    False
1     True
2     True
3     True
4     True
5    False
Name: Process Parameter, dtype: bool

extract 的另一种解决方案,对于不匹配的值返回 NaNs,所以 notnull 是必要的:

df = df[df['Process Parameter'].str.extract('('+'|'.join(keys)+')',expand=False).notnull()]
print (df)
  Process Parameter  Value
1      System Clk a    2.0
2        Core Clk a    3.0
3    Bilinear Coeff    5.1
4        Prec Coeff    6.2

时间安排

a = 'Temperature System Clk Core Clk Bilinear Coeff Prec Coeff Yield'.split()

N = 200000
df = pd.DataFrame({'Process Parameter': [np.random.choice(a, size=np.random.randint(1,10)) for x in range(N)]})
df['Process Parameter'] = df['Process Parameter'].str.join(' ')

keys =['Clk', 'Coeff']

In [115]: %timeit df[df['Process Parameter'].str.contains('|'.join(keys))]
10 loops, best of 3: 140 ms per loop

In [116]: %timeit df[df['Process Parameter'].str.extract('('+'|'.join(keys)+')',expand=False).notnull()]
1 loop, best of 3: 247 ms per loop

#cᴏʟᴅsᴘᴇᴇᴅ's solution 1
In [117]: %timeit df[df['Process Parameter'].str.findall('|'.join(keys)).astype(bool)]
10 loops, best of 3: 177 ms per loop

#cᴏʟᴅsᴘᴇᴇᴅ's solution 2
In [118]: %timeit df[df['Process Parameter'].str.split(expand=True).isin(keys).any(1)]
1 loop, best of 3: 527 ms per loop

#piRSquared solution 1
In [136]: %timeit df[(find(df['Process Parameter'].values.astype(str)[:, None], keys) >= 0).any(1)]
1 loop, best of 3: 487 ms per loop

#piRSquared solution 2
In [137]: %timeit df[df['Process Parameter'].str.split().apply(set) & set(keys)]
1 loop, best of 3: 401 ms per loop

编辑您需要word boundary 进行匹配:

df = pd.DataFrame({'Process Parameter' : ['Clockspeed', 'System Clk', 'Core Clk', 
                                        'Bilinear Coeff', 'Prec Coeff', 'Yield'], 
                                        'Value' : [1.2,2.0,3.0, 5.1, 6.2, 7.4]})

keys =['Clk', 'Coeff']
print (df)
  Process Parameter  Value
0        Clockspeed    1.2
1        System Clk    2.0
2          Core Clk    3.0
3    Bilinear Coeff    5.1
4        Prec Coeff    6.2
5             Yield    7.4

pat = '|'.join(r"\b{}\b".format(x) for x in keys)
df = df[df['Process Parameter'].str.contains(pat)]
print (df)
  Process Parameter  Value
1        System Clk    2.0
2          Core Clk    3.0
3    Bilinear Coeff    5.1
4        Prec Coeff    6.2

【讨论】:

  • 这是一个很好的方法!更复杂的是,在键列表中,我可以添加另一个约束,即字符串应该以这些键结尾。例如,我想匹配部分字符串“Clock”但不想匹配“Clocks”......如果输入字符串是“System Clock”、“Core Clock”、“Clockspeed”,则输出正则表达式匹配只能是“系统时钟”和“核心时钟”
猜你喜欢
  • 2022-01-24
  • 2023-03-07
  • 1970-01-01
  • 2021-01-29
  • 2019-05-23
  • 2017-08-19
  • 2019-09-02
  • 2016-01-21
  • 2017-12-27
相关资源
最近更新 更多