在 pandas 中,如何从单词列表或单词集中 select 数据框中的短语?
In pandas, how to select phrases in a dataframe from word list or word set?
在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
第 "EmentaMateria" 列的每一行都有一系列句子。我计划从包含此列中这些单词(或一组单词)中的任何一个或几个的行创建一个新的数据框:
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"
所以我这样做了:
seleciona2 = df_projetos_api_final [df_projetos_api_final['EmentaMateria'].\
str.contains(str_choice, na=False)]
新生成的数据框收集了多个包含一个或多个这些词的句子。然而,很多行没有这些词,如
"向联邦参议院发送修正案的附录
联邦区关于
修正案的预算提案
FUNDEPE 工作计划 - 发展基金
联邦区,旨在增加更多 CZ 3,453,977,000.00
(三十亿,四亿五千三百万,九百零
7.7 万次)工程执行项目和
教育和文化系统的设备。
请问,这是不是因为相似词也在句子中搜索?还是因为很多句子有太多的白色space或者某些单词之间有换行符?
编辑 2019 年 12 月 7 日
非常感谢各位朋友的关注。在你写完之后我回去查看数据库并再次查看建议的代码。我得到了原始数据库,带有巴西葡萄牙语口音。我认为这是原来的问题-我不知道原来的基地已经改变了
我发现我正在处理的数据库已经通过 unidecode 删除了葡萄牙语的重音。所以我用带有重音符号的 str_choice 和原始数据库重复了测试,然后它起作用了——我还没有检查所有的行,但到目前为止我所看到的都是正确的
所以新的str_choice(我用的名字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()
.contains()
mention you could use the stricter .match()
的文档,因为它基于 re.match
而不是 re.search
。
有关两者之间的解释,请参见此线程的示例: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)]
Returns:
18 ALTERACAO
Name: 0, dtype: object
这个returns因为它包含了子串'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)]
可能的解决方案:
"Create a new dataframe from rows that contain any or several of these
words (or group of words) in this column:"
第 1 步:将列拆分为新的 DataFrame
# Assume that each 'sentence' is comma-separated.
df_split = df_projetos_api_final.EmentaMateria.split(",", expand=True)
第 2 步:搜索子字符串
# Set regex=False if you want the entire word to match vs a sub-string.
rows_that_match = df_split[df_split.str.contains(str_choice, case=False)]
诊断
首先,让我们看一下为什么您的代码不起作用。 @jorijnsmit 放弃了它(并分享了一个 useful answer),你的正则表达式匹配字符,不管它们在哪里。让我们用一个更简单的例子来说明,我将在整个过程中使用它:
我们想要匹配单词 'app'
和 'he'
,因此我们构建了一个与您的非常相似的正则表达式。
strings_to_match = ['app', 'he']
match_pattern = '|'.join(strings_to_match) # "app|he"
我们使用交替运算符连接我们想要匹配的字符串,我们很高兴,对吧?感谢 regex101 的魔法,这里是将我们的模式应用于几个字符串的结果(匹配在方括号中):
[he]llo
brot[he]r
[app]lication
[he]
[app]le
h[app]ier
[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'
来仅使用一组单词边界标记。一个捕获组,嗯,分组并捕获正则表达式的一个子集。在这种情况下,该组将 return 与整场比赛相同。非捕获组消除了冗余,同时仍然允许我们在逻辑上分离表达式的一部分。
这是一个完整的程序,演示了如何构建模式并将其用于 Pandas 系列:
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']
match_pattern = fr"\b(?:{'|'.join(strings_to_match)})\b" # "\b(?:app|he)\b"
match_res = test_series.str.contains(match_pattern, case=False)
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()
操作的数量保持在最低限度,这是真正令人担忧的(我估计整个专栏大约有 8,000,000 split()
操作)。它也应该更有效,因为迭代次数取决于要匹配的子字符串的数量,这通常应该低于要检查的字符串中的单词数量。
2.
我看到一些提到 regex
参数的地方,我觉得这些地方不清楚或具有误导性。是的,传递 regex=False
将匹配文字字符串,不,仅更改参数不会使您当前的代码工作(为什么会这样?)。
我希望这是您在要求规范答案时想到的那种事情。如果有任何不清楚的地方或您有任何其他问题,请告诉我:)
在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
第 "EmentaMateria" 列的每一行都有一系列句子。我计划从包含此列中这些单词(或一组单词)中的任何一个或几个的行创建一个新的数据框:
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"
所以我这样做了:
seleciona2 = df_projetos_api_final [df_projetos_api_final['EmentaMateria'].\
str.contains(str_choice, na=False)]
新生成的数据框收集了多个包含一个或多个这些词的句子。然而,很多行没有这些词,如
"向联邦参议院发送修正案的附录
联邦区关于
修正案的预算提案
FUNDEPE 工作计划 - 发展基金
联邦区,旨在增加更多 CZ 3,453,977,000.00
(三十亿,四亿五千三百万,九百零
7.7 万次)工程执行项目和
教育和文化系统的设备。
请问,这是不是因为相似词也在句子中搜索?还是因为很多句子有太多的白色space或者某些单词之间有换行符?
编辑 2019 年 12 月 7 日
非常感谢各位朋友的关注。在你写完之后我回去查看数据库并再次查看建议的代码。我得到了原始数据库,带有巴西葡萄牙语口音。我认为这是原来的问题-我不知道原来的基地已经改变了
我发现我正在处理的数据库已经通过 unidecode 删除了葡萄牙语的重音。所以我用带有重音符号的 str_choice 和原始数据库重复了测试,然后它起作用了——我还没有检查所有的行,但到目前为止我所看到的都是正确的
所以新的str_choice(我用的名字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()
.contains()
mention you could use the stricter .match()
的文档,因为它基于 re.match
而不是 re.search
。
有关两者之间的解释,请参见此线程的示例: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)]
Returns:
18 ALTERACAO
Name: 0, dtype: object
这个returns因为它包含了子串'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)]
可能的解决方案:
"Create a new dataframe from rows that contain any or several of these words (or group of words) in this column:"
第 1 步:将列拆分为新的 DataFrame
# Assume that each 'sentence' is comma-separated.
df_split = df_projetos_api_final.EmentaMateria.split(",", expand=True)
第 2 步:搜索子字符串
# Set regex=False if you want the entire word to match vs a sub-string.
rows_that_match = df_split[df_split.str.contains(str_choice, case=False)]
诊断
首先,让我们看一下为什么您的代码不起作用。 @jorijnsmit 放弃了它(并分享了一个 useful answer),你的正则表达式匹配字符,不管它们在哪里。让我们用一个更简单的例子来说明,我将在整个过程中使用它:
我们想要匹配单词 'app'
和 'he'
,因此我们构建了一个与您的非常相似的正则表达式。
strings_to_match = ['app', 'he']
match_pattern = '|'.join(strings_to_match) # "app|he"
我们使用交替运算符连接我们想要匹配的字符串,我们很高兴,对吧?感谢 regex101 的魔法,这里是将我们的模式应用于几个字符串的结果(匹配在方括号中):
[he]llo
brot[he]r
[app]lication
[he]
[app]le
h[app]ier
[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'
来仅使用一组单词边界标记。一个捕获组,嗯,分组并捕获正则表达式的一个子集。在这种情况下,该组将 return 与整场比赛相同。非捕获组消除了冗余,同时仍然允许我们在逻辑上分离表达式的一部分。
这是一个完整的程序,演示了如何构建模式并将其用于 Pandas 系列:
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']
match_pattern = fr"\b(?:{'|'.join(strings_to_match)})\b" # "\b(?:app|he)\b"
match_res = test_series.str.contains(match_pattern, case=False)
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()
操作的数量保持在最低限度,这是真正令人担忧的(我估计整个专栏大约有 8,000,000 split()
操作)。它也应该更有效,因为迭代次数取决于要匹配的子字符串的数量,这通常应该低于要检查的字符串中的单词数量。
2.
我看到一些提到 regex
参数的地方,我觉得这些地方不清楚或具有误导性。是的,传递 regex=False
将匹配文字字符串,不,仅更改参数不会使您当前的代码工作(为什么会这样?)。
我希望这是您在要求规范答案时想到的那种事情。如果有任何不清楚的地方或您有任何其他问题,请告诉我:)