用熊猫计算另一列中的正则表达式匹配项

Posted

技术标签:

【中文标题】用熊猫计算另一列中的正则表达式匹配项【英文标题】:Count regex matches in one column by values in another column with pandas 【发布时间】:2020-09-01 04:03:56 【问题描述】:

我正在使用 pandas,并且有一个数据框,其中包含一系列句子和说它们的人,如下所示:

 sentence                 person
 'hello world'              Matt
 'cake, delicious cake!'    Matt
 'lovely day'               Maria
 'i like cake'             Matt
 'a new day'                Maria
 'a new world'              Maria

我想通过person 计算sentence(例如cakeworldday)中正则表达式字符串的非重叠匹配。注意sentence 的每一行可能包含多个匹配项(例如cake):

person        'day'        'cake'       'world'
Matt            0            3             1
Maria           2            0             1

到目前为止,我正在这样做:

rows_cake = df[df['sentences'].str.contains(r"cake")
counts_cake = rows_cake.value_counts()

但是,这个str.contains 给了我包含cake 的行,但不是cake 的单个实例。

我知道我可以在rows_cake 上使用str.counts(r"cake")。但是,在实践中,我的数据框非常大(> 1000 万行),并且我使用的正则表达式非常复杂,因此如果可能,我正在寻找更有效的解决方案。

【问题讨论】:

【参考方案1】:

也许您应该首先尝试获取句子本身,然后使用re 来执行优化的正则表达式:

for row in df.itertuples(index=False):
   do_some_regex_stuff(row[0], row[1])#in this case row[0] is a sentence. row[1] is person

据我所知,itertuples 非常安静(注释 1 here)。所以你唯一的优化问题是正则表达式本身。

【讨论】:

【参考方案2】:

我想出了一个相当简单的解决方案。但不能声称它是最快或最有效的。

import pandas as pd
import numpy as np

# to be used with read_clipboard()
'''
sentence    person
'hello world'   Matt
'cake, delicious cake!' Matt
'lovely day'    Maria
'i like cake'   Matt
'a new day' Maria
'a new world'   Maria
'''

df = pd.read_clipboard()
# print(df)

输出:

                  sentence person
0            'hello world'   Matt
1  'cake, delicious cake!'   Matt
2             'lovely day'  Maria
3            'i like cake'   Matt
4              'a new day'  Maria
5            'a new world'  Maria

.

# if the list of keywords is fix and relatively small
keywords = ['day', 'cake', 'world']

# for each keyword and each string, counting the occourance
for key in keywords:
    df[key] = [(len(val.split(key)) - 1) for val in df['sentence']]

# print(df)

输出:

                 sentence person  day  cake  world
0            'hello world'   Matt    0     0      1
1  'cake, delicious cake!'   Matt    0     2      0
2             'lovely day'  Maria    1     0      0
3            'i like cake'   Matt    0     1      0
4              'a new day'  Maria    1     0      0
5            'a new world'  Maria    0     0      1

.

# create a simple pivot with what data you needed
df_pivot = pd.pivot_table(df, 
values=['day', 'cake', 'world'], 
columns=['person'], 
aggfunc=np.sum).T

# print(df_pivot)

最终输出:

        cake  day  world
person
Maria      0    2      1
Matt       3    0      1

如果这似乎是一种好方法,特别是考虑到数据量,欢迎提出建议。渴望学习。

【讨论】:

【参考方案3】:

由于这主要涉及字符串,我建议将计算从 Pandas 中取出 - 在大多数情况下,在字符串操作方面,Python 比 Pandas 更快:

#read in data
df = pd.read_clipboard(sep='\s2,', engine='python')

#create a dictionary of persons and sentences : 
from collections import defaultdict, ChainMap
d = defaultdict(list)
for k,v in zip(df.person, df.sentence):
    d[k].append(v)


d = k:",".join(v) for k,v in d.items()

#search words
strings = ("cake", "world", "day")

#get count of words and create a dict
m = defaultdict(list)
for k,v in d.items():
    for st in strings:
        m[k].append(st:v.count(st))

res = k:dict(ChainMap(*v)) for k,v in m.items()


print(res)
'Matt': 'day': 0, 'world': 1, 'cake': 3,
 'Maria': 'day': 2, 'world': 1, 'cake': 0

output = pd.DataFrame(res).T

       day  world   cake
Matt    0     1     3
Maria   2     1     0

测试速度,看看哪个更好。这对我和其他人也很有用。

【讨论】:

谢谢!这就说得通了。在这种情况下,strings 还可以包含一堆正则表达式吗?我使用的一些正则表达式非常复杂。 是的,你可以,只要确保你会调整你的正则表达式以适应。

以上是关于用熊猫计算另一列中的正则表达式匹配项的主要内容,如果未能解决你的问题,请参考以下文章

如何在红移中进行动态正则表达式匹配?

从 pandas 数据框列中查找所有正则表达式匹配项

熊猫使用正则表达式选择列并按值除

熊猫正则表达式提取物为 re.search 提供不同的输出?

SQL Server:选择列中多次出现正则表达式匹配的行

替换字符串中的重叠匹配项(正则表达式或字符串操作)