Spacy列表推导式处理Pandas DataFrame提取人名报错排查
问题:用Spacy提取DataFrame人名时的列表推导式错误排查
你有这样一个Pandas DataFrame:
import pandas as pd df = pd.DataFrame({ 'Text': [ "When can I go to Canada?", "Who is king Arthur?", "Can you give me the email of Norton?" ] })
你想要提取每行里的人名,得到这样的结果:
| Index | Text | Name |
|---|---|---|
| 0 | When can I go to Canada? | |
| 1 | Who is king Arthur? | Arthur |
| 2 | Can you give me the email of Norton? | Norton |
你最初用df['Name'] = [nlp(x).ents for x in df['Text']]提取实体,但会把所有类型的实体(比如Canada这种地名)都捞出来,不符合需求。于是你改成了这段代码:
df['Name'] = [token.label_ for token in nlp(x).ents for x in df['Text']]
结果直接触发了NameError: name 'x' is not defined,这到底是哪里出问题了?
错误原因分析
这个列表推导式的循环顺序完全搞反了!
列表推导式的嵌套循环是按从左到右的顺序执行的,你写的[token.label_ for token in nlp(x).ents for x in df['Text']],逻辑上是先尝试遍历nlp(x).ents里的每个token,但这时候x还没被定义——因为遍历df['Text']的循环被放在了最后!
Python会先解析最内层的循环条件,当它试图调用nlp(x)时,x还没有被赋值,自然就抛出NameError了。而且就算顺序改对,你现在取的是token.label_(也就是实体类型,比如PERSON),而不是实体的文本内容,这也达不到你提取人名的目的。
正确的写法
你需要先遍历DataFrame里的每一行文本,再对每个文本的实体筛选出类型为PERSON的,提取它们的文本;如果没有符合条件的实体,就留空。
可以用这样的列表推导式:
import spacy nlp = spacy.load("en_core_web_sm") df['Name'] = [ ', '.join([ent.text for ent in nlp(text).ents if ent.label_ == 'PERSON']) for text in df['Text'] ]
简单解释下:
- 外层循环遍历
df['Text']里的每一段文本text - 内层遍历这段文本的所有实体
ent,只保留类型是PERSON的,提取它们的文本内容 - 用
,把多个人名(如果有的话)拼接起来,没有符合条件的就返回空字符串
运行这段代码后,就能得到你期望的结果啦!
内容的提问来源于stack exchange,提问作者Ctrl
相关产品推荐
相关产品推荐

