【问题标题】:How to apply regex function to dataframe column to return value如何将正则表达式函数应用于数据框列以返回值
【发布时间】:2019-11-21 23:24:05
【问题描述】:

我正在尝试将正则表达式函数应用于数据框的列以确定性别代词。这是我的数据框的样子:

    name                                            Descrip
0  Sarah           she doesn't like this because her mum...
1  David                 he does like it because his dad...
2    Sam  they generally don't like it because their par...

这些是我为制作该数据框而运行的代码:

list_label = ["Sarah", "David", "Sam"]
list_descriptions = ["she doesn't like this because her mum...", "he does like it because his dad...", "they generally don't like it because their parent..."]

data3 = {'name':list_label, 'Descrip':list_descriptions}
test_df = pd.DataFrame(data3)

我正在尝试通过在“描述”列上应用正则表达式函数来确定此人的性别。具体来说,这些是我想要实现的模式:

"male":"(he |his |him )",
"female":"(she |her |hers )",
"plural, or singular non-binary":"(they |them |their )"

我写的完整代码如下:

此函数尝试匹配每个模式并返回在行值描述中最常提及的性别代词的名称。每个性别代词在模式字符串中都有几个关键词(例如,他、她、他们)。这个想法是确定 max_gender 或与在描述列中的值中最常提到的模式组相关联的性别。因此,max_gender 可以采用以下三个值之一:male |女|复数,或单数非二进制。如果在 Descrip 行值中没有识别出任何模式,则将返回“未知”。

import re
def get_pronouns(text):
    patterns = {
        "male":"(he |his |him )",
        "female":"(she |her |hers )",
        "plural, or singular non-binary":"(they |them |their )"
    }
    max_gender = "unknown"
    max_gender_count = 0
    for gender in patterns:
        pattern = re.compile(gender)
        mentions = re.findall(pattern, text)
        count_mentions = len(mentions)
        if count_mentions > max_gender_count:
            max_gender_count = count_mentions
            max_gender = gender
    return max_gender

test_df["pronoun"] = test_df.loc[:, "Descrip"].apply(get_pronouns)
print(test_df)

但是,当我运行代码时,它显然无法确定性别代词。这显示在以下输出中:

    name                                            Descrip  pronoun
0  Sarah           she doesn't like this because her mum...  unknown
1  David                 he does like it because his dad...  unknown
2    Sam  they generally don't like it because their par...  unknown

有人知道我的代码有什么问题吗?

【问题讨论】:

  • 您能解释一下您在get_pronouns() 中使用的算法吗?我会试着弄清楚,还有一些其他的事情我会改变。我也很困惑为什么描述被切断了。
  • 我添加了一些 cmets -- 谢谢!这是一个示例案例,因此描述被切断的原因。我对完全不同的方法持非常开放的态度。
  • 听起来不错,我快完成了。如果您正在寻找不同的方法,那么您可以多谈谈您的实际情况,而不仅仅是示例,这可能会有所帮助。
  • 我正在做一个网络抓取练习。具体来说,我正在提取一长串维基百科传记文章的整个文本源。所以我有一个包含两列的数据框。第一栏是文章的名称。第二栏是那篇文章的全部源内容。我需要创建第三列,用于确定文章所针对的人是男性、女性还是复数形式。这就是为什么我需要这个正则表达式代码,将其应用于第二列(内容)以创建第三列(性别代词)。
  • 我开始质疑 DataFrame 是否是正确的数据结构。当然,如果您打算操纵结果,您可以让文章文本列保存包含所有文本的字典的键。

标签: python regex


【解决方案1】:

如果您想找出代码不工作的原因,请向您的函数添加一条打印语句,如下所示:

    for gender in patterns:
        print(gender)
        pattern = re.compile(gender)

您的正则表达式还需要一些调整。例如,在 Pink Floyd 的歌曲 Breathe 的第一行 Breathe, Breath in the air,您的正则表达式会找到两个男性代词。

可能还有其他问题,我不确定。


这是一个与您的解决方案非常相似的解决方案。正则表达式是固定的,字典被元组列表替换,等等。


解决方案代码

import pandas as pd
import numpy as np
import re
import operator as op

names_list = ['Sarah', 'David', 'Sam']
descs_list = ["she doesn't like this because her mum...", 'he does like it because his dad...',
              "they generally don't like it because their parent..."]

df_1 = pd.DataFrame(data=zip(names_list, descs_list), columns=['Name', 'Desc'])

pronoun_re_list = [('male', re.compile(r"\b(?:he|his|him)\b", re.IGNORECASE)),
                   ('female', re.compile(r"\b(?:she|her|hers)\b", re.IGNORECASE)),
                   ('plural/nb', re.compile(r"\b(?:they|them|their)\b", re.IGNORECASE))]


def detect_pronouns(str_in: str) -> str:
    match_results = ((curr_pron, len(curr_patt.findall(str_in))) for curr_pron, curr_patt in pronoun_re_list)
    max_pron, max_counts = max(match_results, key=op.itemgetter(1))
    if max_counts == 0:
        return np.NaN
    else:
        return max_pron


df_1['Pronouns'] = df_1['Desc'].map(detect_pronouns)

说明

代码

match_results 是一个生成器表达式curr_pron 代表“当前代词”,curr_patt 代表“当前模式”。如果我将它重写为创建列表的 for 循环,它可能会让事情变得更清楚:

    match_results = []
    for curr_pron, curr_patt in pronoun_re_list:
        match_counts = len(curr_patt.findall(str_in))
        match_results.append((curr_pron, match_counts))

for curr_pron, curr_patt in ... 正在利用一些不同名称的东西,通常是多重赋值或元组解包。您可以在 here 上找到一篇不错的文章。在这种情况下,它只是一种不同的写法:

    for curr_tuple in pronoun_re_list:
        curr_pron = curr_tuple[0]
        curr_patt = curr_tuple[1]

正则表达式

大家最喜欢的科目的时间到了;正则表达式!我使用了一个很棒的网站,叫做RegEx101,你可以在那里乱搞模式,它让事情变得更容易理解。我已经建立了一个页面,其中包含一些测试数据和我将在下面介绍的正则表达式:https://regex101.com/r/Y1onRC/2

现在,让我们看看我使用的正则表达式:\b(?:he|his|him)\b

he|his|him 部分与您的完全一样,它匹配单词“he”、“his”或“him”。在您的正则表达式中,被括号包围,我的还包括 ?: 在左括号之后。 (pattern stuff)capturing group,顾名思义,意味着它捕获任何匹配的内容。由于这里我们实际上并不关心匹配的内容,只关心是否匹配,我们添加?: 创建一个非捕获组,它不会捕获(或保存)内容.

我说正则表达式的he|his|him 部分与您的相同,但这并不完全正确。您在每个代词后都包含一个空格,大概是为了避免它与单词中间的字母 he 匹配。不幸的是,正如我上面提到的,它在句子 Breathe, Breath in the air 中找到了两个匹配项。我们的救星是\b,匹配word boundaries。这意味着我们在 Words words words he. 中捕获了 he,而 (he |his |him ) 没有。

最后,我们用re.IGNORECASE 标志编译模式,我认为不需要太多解释,但如果我错了请告诉我。

下面是我用简单的英语描述这两种模式的方式:

  • (he |his |him ) 匹配字母 he 后跟空格、his 后跟空格或 him 后跟空格,并返回完整匹配加上一组。
  • 带有re.IGNORECASE 标志的\b(?:he|his|him)\b 匹配单词hehishim,无论大小写如何,并返回完整匹配。

希望这足够清楚,让我知道!


结果输出

    Name    Desc                                                  Pronouns
--  ------  ----------------------------------------------------  ----------
 0  Sarah   she doesn't like this because her mum...              female
 1  David   he does like it because his dad...                    male
 2  Sam     they generally don't like it because their parent...  plural/nb

如果您有任何问题,请告诉我:)

【讨论】:

  • @BenjaminPng 一切都清楚了吗?你发现你的代码为什么不工作了吗?
  • 实际上你能详细说明一下你的detect_pronouns函数吗?我对正则表达式的了解并没有超出 pandas,我发现它相当混乱。例如,curr_pron 和 curr_patt 是什么意思?如果您能指出我正确的方向来了解更多有关这些概念的信息,那就太好了。我无法在谷歌上找到任何信息。谢谢!
  • @BenjaminPng 我做了一个编辑,让我知道你的想法:)
  • 谢谢亚历山大!超级有帮助。非常感谢您抽出宝贵的时间。
  • 不!你已经完美地解释了一切。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-07
  • 2019-06-15
  • 2018-09-24
  • 1970-01-01
  • 1970-01-01
  • 2016-11-18
  • 2020-07-03
相关资源
最近更新 更多