在pandas中,如何从单词列表或单词集中选择数据帧中的短语?

2024-09-28 20:52:28 发布

您现在位置:Python中文网/ 问答频道 /正文

在Python3和pandas中,我有一个数据帧:

df_projetos_api_final.info()                                                      
<class 'pandas.core.frame.DataFrame'>                                                      
Int64Index: 93631 entries, 1 to 93667                                                      
Data columns (total 21 columns):                                                           
AnoMateria                       93631 non-null object                                     
CodigoMateria                    93631 non-null object                                     
DescricaoIdentificacaoMateria    93631 non-null object                                     
DescricaoSubtipoMateria          93631 non-null object                                     
IndicadorTramitando              93631 non-null object                                     
NomeCasaIdentificacaoMateria     93631 non-null object                                     
NumeroMateria                    93631 non-null object                                     
ApelidoMateria                   891 non-null object                                       
DataApresentacao                 93631 non-null object                                     
DataLeitura                      54213 non-null object                                     
EmentaMateria                    93631 non-null object                                     
ExplicacaoEmentaMateria          9461 non-null object                                      
IndicadorComplementar            93631 non-null object                                     
DescricaoNatureza                54352 non-null object                                     
NomeAutor                        93100 non-null object                                     
IndicadorOutrosAutores           93214 non-null object                                     
CodigoParlamentar                49786 non-null object                                     
NomeParlamentar                  49786 non-null object                                     
NomeCompletoParlamentar          49786 non-null object                                     
UfParlamentar                    45613 non-null object                                     
DescricaoSituacao                78783 non-null object                                     
dtypes: object(21)                                                                         
memory usage: 8.2+ MB 

“校订材料”一栏每行都有一系列句子。我计划从包含此列中任何或多个单词(或单词组)的行创建一个新的数据帧:

^{pr2}$

所以我这样做了:

seleciona2 = df_projetos_api_final [df_projetos_api_final['EmentaMateria'].\
                               str.contains(str_choice, na=False)]

新生成的数据帧收集了包含一个或多个这些单词的多个句子。但是,许多行没有这些单词,如
“ENCAMINHA AO SENADO FEDERAL,UM ADENDO AS SUGESTOES DE EMENDAS A
提议联邦地区的奥卡门塔利亚,引用一个替代方案
基金会计划(PROGRAMA DE TRABALHO DO FUNDEPE-FUNDO DE DESENVOLVIMENTO DO)
VISANDO A ACRESCENTAR MAIS CZ联邦地区,邮编:3.453.977.000,00
(TRES BILHOES,QUATROCENTOS E Cinkenta E TRES MILHOES,NOVECENTOS E
执行项目
教育和文化系统设备。”

请问,这是因为相似的词也在句子中被搜索吗?或者是因为许多句子中有太多的空格或一些单词之间的换行符?在

编辑:7/12/2019

非常感谢各位朋友的关注。在你写了这篇文章之后,我又重新检查了数据库和建议的代码。我得到了原始数据库,有巴西葡萄牙语的口音。我想这是最初的问题-我不知道原来的基地已经改变

我发现我正在处理的数据库已经通过unidecode从葡萄牙语中删除口音。所以我用str_选项,用口音和原始数据库重复了测试,然后它成功了-我还没有检查所有的行,但到目前为止我所看到的都是正确的

因此,新的str_选项(我使用的名称是search_list),我使用的是:

df_projetos_api_final['EmentaMateria'] = df_projetos_api_final['EmentaMateria'].str.upper()
search_list = ["MULHER", "MULHERES", "TRABALHO DOMÉSTICO", "VIOLÊNCIA CONTRA A MULHER", "VIOLÊNCIA DOMÉSTICA", "VIOLÊNCIA DE GÊNERO", "MARIA DA PENHA", "ABORTO", "ABORTAMENTO", "INTERRUPÇÃO DE GRAVIDEZ", "INTERRUPÇÃO DE GESTAÇÃO", "DIREITO REPRODUTIVO", "DIREITOS REPRODUTIVOS", "DIREITO À VIDA", "CONCEPÇÃO", "CONTRACEPÇÃO", "CONTRACEPTIVO", "MISOPROSTOL", "MIFEPRISTONE", "CYTOTEC", "ÚTERO", "GESTAÇÃO", "GRAVIDEZ", "PARTO", "VIOLÊNCIA OBSTÉTRICA", "FETO", "BEBÊ", "CRIANÇA", "VIOLÊNCIA SEXUAL", "FEMINICÍDIO", "MORTE DE MULHER", "MORTE DE MULHERES", "HOMICÍDIO DE MULHER", "HOMICÍDIO DE MULHERES", "ASSÉDIO SEXUAL", "ASSÉDIO", "ESTUPRO", "VIOLÊNCIA SEXUAL", "ABUSO SEXUAL", "ESTUPRO DE VULNERÁVEL", "LICENÇA MATERNIDADE", "FEMININO", "MULHER NEGRA", "MULHERES NEGRAS", "MULHERES QUILOMBOLAS", "MULHERES INDÍGENAS", "NEGRAS", "NEGRA", "RACISMO", "RAÇA", "RACIAL", "ABUSO SEXUAL", "MATERNIDADE", "MÃE", "AMAMENTAÇÃO", "SEXUALIDADE", "SEXO", "GÊNERO", "FEMINISMO", "MACHISMO", "GUARDA DE FILHOS", "GUARDA DOS FILHOS", "IGUALDADE DE GÊNERO", "IDENTIDADE DE GÊNERO", "IDEOLOGIA DE GÊNERO", "EDUCAÇÃO SEXUAL", "ESCOLA SEM PARTIDO", "TRANSEXUAL", "TRANSEXUALIDADE", "MULHER TRANS", "MULHERES TRANS", "MUDANÇA DE SEXO", "READEQUAÇÃO SEXUAL", "EXPLORAÇÃO SEXUAL", "PROSTITUIÇÃO", "ORIENTAÇÃO SEXUAL", "HOMOSSEXUAL", "HOMOSSEXUALIDADE", "HOMOSSEXUALISMO",  "LÉSBICA",  "LÉSBICAS",  "DIREITO DOS HOMENS", "EDUCAÇÃO RELIGIOSA",  "DEUS", "RELIGIÃO", "EDUCACÃO DOMICILIAR", "HOMESCHOOLING", "CRECHE",  "EDUCAÇÃO INFANTIL",  "CASAMENTO INFANTIL"]
mask = df_projetos_api_final['EmentaMateria'].str.contains('|'.join(search_list))
seleciona = df_projetos_api_final[mask]
seleciona.info()

Tags: apidfobjectdenullfinalnonstr
3条回答

诊断

首先,让我们来看看为什么你的代码不能工作。@jorijnsmit提供了它(并共享了一个useful answer),不管字符在哪里,正则表达式都会匹配字符。让我们用一个更简单的例子来说明,我将贯穿始终:

我们想要匹配单词'app''he',因此我们构造了一个与您的非常相似的regex。在

strings_to_match = ['app', 'he']

match_pattern = '|'.join(strings_to_match) # "app|he"

我们用交替运算符连接要匹配的字符串,这样就可以开始了,对吧?感谢regex101的魔力,以下是将我们的模式应用于几个字符串(匹配项在方括号中)的结果:

  • [he]llo
  • brot[he]r
  • [app]lication
  • [he]
  • [app]le
  • ^{cd8}
  • [app]
  • [he]ll

我们的模式在任何地方匹配字符串'app''he',而我们只需要单词本身!在


正则表达式解决方案

我们能做些什么来解决这个问题?我们的第一个想法可能是将我们的模式改为' app | he ',这确实解决了'application'这样的字符串的问题。不幸的是,这不是万无一失的。该模式无法识别'I downloaded an app.'中的单词'app',这对我们来说是完全有效的。幸运的是,regex正好有我们需要的解决方案:Word boundaries,由标记'\b'表示,其原理相当不言自明。在

以下是新模式'\bapp\b|\bhe\b'的一些结果:

  • '[he]'
  • 'apple'
  • 'happier'
  • ' [app] '
  • 'hell'
  • 'I downloaded an [app]!'

正是我们所期待的!虽然它确实工作正常,但这种模式不必要地难以阅读。通过将所有子字符串放入non-capturing group:'\b(?:app|he)\b',我们只能使用一组单词边界标记。一个捕获组,嗯,分组并捕获正则表达式的一个子集。在本例中,组将返回与整个匹配项相同的结果。非捕获组消除了这种冗余,同时仍然允许我们在逻辑上分离表达式的一部分。在

下面是一个完整的程序,演示如何构建模式并将其用于熊猫系列:

^{pr2}$

print(match_res)的输出:

0    False
1    False
2    False
3     True
4    False
5    False
6     True
7    False
8     True
9     True
dtype: bool

关于其他解决方案的几点注记

1.

请注意,这些方法只能匹配单词,不能匹配任意子字符串。因此,它们实际上并不是这个特定问题的有效解决方案,只是为了完整起见才在这里讨论。

这与@FBruzzesi的解决方案相同,我们将其称为版本1。供参考:

# Convert string into list of strings
str_list = str_choice.split(|)

# Control if any word is in the sentence after splitting the sentence by space
df['has_match'] = df.apply(lambda r: [x for x in str_list if x in r['EmentaMateria'].split(' ')], axis=1)

#This will create a list of words you find, then you can filter only those which has a match
df = df[df.apply(lambda r: len(r['has_match'])>0, axis=1)]

当他们的解决方案收集所有匹配项时,我们只关心是否有匹配项。让我们看看他们的解决方案的重构版本,版本2:

import pandas as pd

test_strs = ['hello', 'brother', 'application', 'he', 'apple', 'happier', 'app', 'hell', ' app ',
             'I downloaded an app.']

test_series = pd.Series(data=test_strs)

strings_to_match = ['app', 'he']

series_split = test_series.str.split()

match_res = series_split.map(lambda curr_words: any((curr_sub in curr_words for curr_sub in strings_to_match)))

与版本1不同,版本2将split()操作的数量保持在最低限度,这是一个真正值得关注的问题(我估计整个列大约有8000000个split()操作)。由于迭代次数取决于要匹配的子字符串的数量,因此它应该更高效,而子字符串的数目通常应低于要检查的字符串中的单词数。在

2.

我看到了一些关于regex参数的提及,我觉得这些参数不清楚或有误导性。是的,传递regex=False将匹配一个文本字符串,不,仅仅更改参数不会使当前代码正常工作(为什么会这样呢?)。在


我希望这就是你在要求一个规范的答案时所想的那种事情。如果有任何不清楚的地方或您有任何进一步的问题,请告诉我:)

^{}的文档提到可以使用更严格的^{},因为它基于re.match,而不是{}。在

有关两者之间的解释,请参见以下线程:What is the difference between re.search and re.match?。在

编辑: 我试着找出哪种模式是完全匹配的:

str_choice = "MULHER|MULHERES|TRABALHO DOMESTICO|VIOLENCIA CONTRA A MULHER|VIOLENCIA DOMESTICA|VIOLENCIA DE GENERO|MARIA DA PENHA|ABORTO|ABORTAMENTO|INTERRUPCAO DE GRAVIDEZ|INTERRUPCAO DE GESTACAO|DIREITO REPRODUTIVO|DIREITOS REPRODUTIVOS|DIREITO A VIDA|CONCEPCAO|CONTRACEPCAO|CONTRACEPTIVO|MISOPROSTOL|MIFEPRISTONE|CYTOTEC|UTERO|GESTACAO|GRAVIDEZ|PARTO|VIOLENCIA OBSTETRICA|FETO|BEBE|CRIANCA|VIOLENCIA SEXUAL|FEMINICIDIO|MORTE DE MULHER|MORTE DE MULHERES|HOMICIDIO DE MULHER|HOMICIDIO DE MULHERES|ASSEDIO SEXUAL|ASSEDIO|ESTUPRO|VIOLENCIA SEXUAL|ABUSO SEXUAL|ESTUPRO DE VULNERAVEL|LICENCA MATERNIDADE|FEMININO|MULHER NEGRA|MULHERES NEGRAS|MULHERES QUILOMBOLAS|MULHERES INDIGENAS|NEGRAS|NEGRA|RACISMO|RACA|RACIAL|ABUSO SEXUAL|MATERNIDADE|MAE|AMAMENTACAO|SEXUALIDADE|SEXO|GENERO|FEMINISMO|MACHISMO|GUARDA DE FILHOS|GUARDA DOS FILHOS|IGUALDADE DE GENERO|IDENTIDADE DE GENERO|IDEOLOGIA DE GENERO|EDUCACAO SEXUAL|ESCOLA SEM PARTIDO|TRANSEXUAL|TRANSEXUALIDADE|MULHER TRANS|MULHERES TRANS|MUDANCA DE SEXO|READEQUACAO SEXUAL|EXPLORACAO SEXUAL|PROSTITUICAO|ORIENTACAO SEXUAL|HOMOSSEXUAL|HOMOSSEXUALIDADE|HOMOSSEXUALISMO|LESBICA|LESBICAS|DIREITO DOS HOMENS|EDUCACAO RELIGIOSA|DEUS|RELIGIAO|EDUCACAO DOMICILIAR|HOMESCHOOLING|CRECHE|EDUCACAO INFANTIL|CASAMENTO INFANTIL"

df = pd.DataFrame(['ENCAMINHA AO SENADO FEDERAL, UM ADENDO AS SUGESTOES DE EMENDAS A PROPOSTA ORCAMENTARIA DO DISTRITO FEDERAL, REFERENTE A ALTERACAO DO PROGRAMA DE TRABALHO DO FUNDEPE - FUNDO DE DESENVOLVIMENTO DO DISTRITO FEDERAL, VISANDO A ACRESCENTAR MAIS CZ 3.453.977.000,00 (TRES BILHOES, QUATROCENTOS E CINQUENTA E TRES MILHOES, NOVECENTOS E SETENTA E SETE MIL CRUZADOS) AO PROJETO DE EXECUCAO DE OBRAS E EQUIPAMENTOS DO SISTEMA DE EDUCACAO E CULTURA.'.split()])

df.T[0][df.T[0].str.contains(str_choice)]

退货:

^{pr2}$

它返回是因为它包含子字符串'RACA'。如果设置regex=False,则不会发生这种情况;它将查找完整的字符串。在

要获得完全匹配,此解决方案有效:

# Convert string into list of strings
str_list = str_choice.split(|)

# Control if any word is in the sentence after splitting the sentence by space
df['has_match'] = df.apply(lambda r: [x for x in str_list if x in r['EmentaMateria'].split(' ')], axis=1)

#This will create a list of words you find, then you can filter only those which has a match
df = df[df.apply(lambda r: len(r['has_match'])>0, axis=1)]

相关问题 更多 >