Why do I get TypeError: unhashable type when using NLTK lemmatizer on sentence?
Why do I get TypeError: unhashable type when using NLTK lemmatizer on sentence?
我目前正在对一个句子进行词形还原,同时也在应用 pos_tags。这是我目前所拥有的
import nltk
from nltk.tokenize import word_tokenize
from nltk.corpus import wordnet
from nltk.stem import WordNetLemmatizer
from nltk import pos_tag
lem = WordNetLemmatizer()
def findTag(sentence):
sentence = word_tokenize(sentence)
sentence = [i.strip(" ") for i in sentence]
pos_label = nltk.pos_tag(sentence)[0][1][0].lower()
if pos_label == "j":
pos_label == "a"
if pos_label in ["a", "n", "v"]:
print(lem.lemmatize(word, pos = pos_label))
elif pos_label in ['r']:
print(wordnet.synset(sentence+".r.1").lemmas()[0].pertainyms()[0].name())
else:
print(lem.lemmatize(sentence))
findTag("I love running angrily")
但是,当我用这个输入一个句子时,我得到了错误
Traceback (most recent call last):
File "spoilerDetect.py", line 25, in <module>
findTag("I love running angrily")
File "spoilerDetect.py", line 22, in findTag
print(lem.lemmatize(sentence))
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/nltk/stem/wordnet.py", line 41, in lemmatize
lemmas = wordnet._morphy(word, pos)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/nltk/corpus/reader/wordnet.py", line 1905, in _morphy
if form in exceptions:
TypeError: unhashable type: 'list'
我知道列表是不可散列的,但不确定如何解决这个问题。我是将列表更改为元组还是有什么我不理解的地方?
让我们浏览一下代码,看看如何获得所需的输出。
首先是导入,你有
import nltk
from nltk import pos_tag
然后你在使用
pos_label = nltk.pos_tag(...)
由于您已经在使用 from nltk import pos_tag
,因此 pos_tag
已经在全局命名空间中,只需执行以下操作:
pos_label = pos_tag(...)
按照惯例,应该稍微清理一下导入,使其看起来像这样:
from nltk import word_tokenize, pos_tag
from nltk.corpus import wordnet as wn
from nltk.stem import WordNetLemmatizer
wnl = WordNetLemmatizer()
接下来实际保留标记化单词列表,然后分别保留 pos 标签列表和引理列表听起来合乎逻辑,但由于函数最终只有 return 函数,您应该能够链接启动 pos_tag(word_tokenize(...))
函数并遍历它,以便您可以检索 POS 标签和标记,即
sentence = "I love running angrily"
for word, pos in pos_tag(word_tokenize(sentence)):
print(word, '|', pos)
[出]:
I | PRP
love | VBP
running | VBG
angrily | RB
现在,我们知道 pos_tag
的输出与 WordNetLemmatizer
期望的 POS 之间存在不匹配。从 https://github.com/alvations/pywsd/blob/master/pywsd/utils.py#L124 开始,有一个函数调用 penn2morphy
看起来像这样:
def penn2morphy(penntag, returnNone=False, default_to_noun=False) -> str:
"""
Converts tags from Penn format (input: single string) to Morphy.
"""
morphy_tag = {'NN':'n', 'JJ':'a', 'VB':'v', 'RB':'r'}
try:
return morphy_tag[penntag[:2]]
except:
if returnNone:
return None
elif default_to_noun:
return 'n'
else:
return ''
一个例子:
>>> penn2morphy('JJ')
'a'
>>> penn2morphy('PRP')
''
如果我们使用这些转换后的标签作为 WordNetLemmatizer
的输入并重新使用您的 if-else 条件:
sentence = "I love running angrily"
for token, pos in pos_tag(word_tokenize(sentence)):
morphy_pos = penn2morphy(pos)
if morphy_pos in ["a", "n", "v"]:
print(wnl.lemmatize(token, pos=morphy_pos))
elif morphy_pos in ['r']:
print(wn.synset(token+".r.1").lemmas()[0].pertainyms()[0].name())
else:
print(wnl.lemmatize(token))
[出]:
I
love
run
angry
嘿,你在那里做什么?您的代码有效,但我的代码无效!
好的,现在我们知道如何获得所需的输出了。让我们回顾一下。
- 首先,我们清理导入
- 然后,我们清理预处理(不保留中间变量)
- 然后,我们"functionalized"从Penn -> Morphy
转换POS标签
- 最后,我们应用了相同的 if/else 条件和 运行 词形还原器。
但是我的代码怎么不起作用?!
好的,让我们检查一下您的代码,看看为什么会出现错误。
首先让我们检查您在 findTag
函数中获得的每个输出,打印输出类型和输出
sentence = "I love running angrily"
sentence = word_tokenize(sentence)
print(type(sentence))
print(sentence)
[出]:
<class 'list'>
['I', 'love', 'running', 'angrily']
在 sentence = word_tokenize(sentence)
处,您已经将原始变量覆盖到函数中,通常这是稍后出现错误的标志 =)
现在让我们看下一行:
sentence = "I love running angrily"
sentence = word_tokenize(sentence)
sentence = [i.strip(" ") for i in sentence]
print(type(sentence))
print(sentence)
[出]:
<class 'list'>
['I', 'love', 'running', 'angrily']
现在我们看到sentence = [i.strip(" ") for i in sentence]
实际上是没有意义的例句。
问:但是 word_tokenize
输出的所有标记都没有 i.strip(' ')
试图做的 trailing/heading 空格是真的吗?
A:对,好像是这样。然后 NLTK 首先对字符串进行正则表达式操作,然后调用 str.split()
function which would have removed heading/trailing spaces between tokens, see https://github.com/nltk/nltk/blob/develop/nltk/tokenize/destructive.py#L141
让我们继续:
sentence = "I love running angrily"
sentence = word_tokenize(sentence)
sentence = [i.strip(" ") for i in sentence]
pos_label = nltk.pos_tag(sentence)[0][1][0].lower()
print(type(pos_label))
print(pos_label)
[出]:
<class 'str'>
p
问:等一下,pos_label
只有一个字符串在哪里?
问:什么是 POS 标签 p
?
A:让我们仔细看看 nltk.pos_tag(sentence)[0][1][0].lower()
中发生了什么
通常,当您必须执行这样的 [0][1][0]
嵌套索引检索时,它很容易出错。我们需要问什么是 [0][1][0]
?
我们知道sentence = word_tokenize(sentence)
之后的那句话现在变成了一个字符串列表。 pos_tag(sentence)
将 return 一个字符串元组列表,其中元组中的第一项是标记,第二项是 POS 标记,即
sentence = "I love running angrily"
sentence = word_tokenize(sentence)
sentence = [i.strip(" ") for i in sentence]
thing = pos_tag(sentence)
print(type(thing))
print(thing)
[出]:
<class 'list'>
[('I', 'PRP'), ('love', 'VBP'), ('running', 'VBG'), ('angrily', 'RB')]
现在,如果我们知道 thing = pos_tag(word_tokenize("I love running angrily"))
,输出上面的内容,让我们用它来查看 [0][1][0]
正在访问什么。
>>> thing = [('I', 'PRP'), ('love', 'VBP'), ('running', 'VBG'), ('angrily', 'RB')]
>>> thing[0][1]
('I', 'PRP')
所以thing[0]
输出第一个token的(token, pos)
的元组。
>>> thing = [('I', 'PRP'), ('love', 'VBP'), ('running', 'VBG'), ('angrily', 'RB')]
>>> thing[0][1]
'PRP'
并且thing[0][1]
输出第一个token的POS。
>>> thing = [('I', 'PRP'), ('love', 'VBP'), ('running', 'VBG'), ('angrily', 'RB')]
>>> thing[0][1][0]
'P'
接下来,[0][1][0]
查找第一个标记的 POS 的第一个字符。
所以问题是期望的行为?如果是,为什么只看第一个词的词性?
不管我在看什么。您的解释仍然没有告诉我 TypeError: unhashable type: 'list'
发生的原因。不要再分散我的注意力,告诉我如何解决 TypeError
!!
好的,我们继续前进,现在我们知道 thing = pos_tag(word_tokenize("I love running angrily"))
和 thing[0][1][0].lower() = 'p'
鉴于您的 if-else 条件,
if pos_label in ["a", "n", "v"]:
print(lem.lemmatize(word, pos = pos_label))
elif pos_label in ['r']:
print(wordnet.synset(sentence+".r.1").lemmas()[0].pertainyms()[0].name())
else:
print(lem.lemmatize(sentence))
我们发现 'p'
值会转到其他地方,即 print(lem.lemmatize(sentence))
但等一下,请记住 sentence
在您修改后变成了什么:
>>> sentence = word_tokenize("I love running angrily")
>>> sentence = [i.strip(" ") for i in sentence]
>>> sentence
['I', 'love', 'running', 'angrily']
那么如果我们忽略所有其余代码并专注于此会发生什么:
from nltk.stem import WordNetLemmatizer
lem = WordNetLemmatizer()
sentence = ['I', 'love', 'running', 'angrily']
lem.lemmatize(sentence)
[出]:
-------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-34-497ae98ecaa3> in <module>
4 sentence = ['I', 'love', 'running', 'angrily']
5
----> 6 lem.lemmatize(sentence)
~/Library/Python/3.6/lib/python/site-packages/nltk/stem/wordnet.py in lemmatize(self, word, pos)
39
40 def lemmatize(self, word, pos=NOUN):
---> 41 lemmas = wordnet._morphy(word, pos)
42 return min(lemmas, key=len) if lemmas else word
43
~/Library/Python/3.6/lib/python/site-packages/nltk/corpus/reader/wordnet.py in _morphy(self, form, pos, check_exceptions)
1903 # 0. Check the exception lists
1904 if check_exceptions:
-> 1905 if form in exceptions:
1906 return filter_forms([form] + exceptions[form])
1907
TypeError: unhashable type: 'list'
啊哈!!这就是错误发生的地方!!!
这是因为 WordNetLemmatizer
需要单个字符串输入,而您输入的是字符串列表。用法示例:
from nltk.stem import WordNetLemmatizer
wnl = WordNetLemmatizer()
token = 'words'
wnl.lemmatize(token, pos='n')
问:为什么不说正题?!
A: 那么你会错过如何调试你的代码并使其变得更好=)
我目前正在对一个句子进行词形还原,同时也在应用 pos_tags。这是我目前所拥有的
import nltk
from nltk.tokenize import word_tokenize
from nltk.corpus import wordnet
from nltk.stem import WordNetLemmatizer
from nltk import pos_tag
lem = WordNetLemmatizer()
def findTag(sentence):
sentence = word_tokenize(sentence)
sentence = [i.strip(" ") for i in sentence]
pos_label = nltk.pos_tag(sentence)[0][1][0].lower()
if pos_label == "j":
pos_label == "a"
if pos_label in ["a", "n", "v"]:
print(lem.lemmatize(word, pos = pos_label))
elif pos_label in ['r']:
print(wordnet.synset(sentence+".r.1").lemmas()[0].pertainyms()[0].name())
else:
print(lem.lemmatize(sentence))
findTag("I love running angrily")
但是,当我用这个输入一个句子时,我得到了错误
Traceback (most recent call last):
File "spoilerDetect.py", line 25, in <module>
findTag("I love running angrily")
File "spoilerDetect.py", line 22, in findTag
print(lem.lemmatize(sentence))
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/nltk/stem/wordnet.py", line 41, in lemmatize
lemmas = wordnet._morphy(word, pos)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/nltk/corpus/reader/wordnet.py", line 1905, in _morphy
if form in exceptions:
TypeError: unhashable type: 'list'
我知道列表是不可散列的,但不确定如何解决这个问题。我是将列表更改为元组还是有什么我不理解的地方?
让我们浏览一下代码,看看如何获得所需的输出。
首先是导入,你有
import nltk
from nltk import pos_tag
然后你在使用
pos_label = nltk.pos_tag(...)
由于您已经在使用 from nltk import pos_tag
,因此 pos_tag
已经在全局命名空间中,只需执行以下操作:
pos_label = pos_tag(...)
按照惯例,应该稍微清理一下导入,使其看起来像这样:
from nltk import word_tokenize, pos_tag
from nltk.corpus import wordnet as wn
from nltk.stem import WordNetLemmatizer
wnl = WordNetLemmatizer()
接下来实际保留标记化单词列表,然后分别保留 pos 标签列表和引理列表听起来合乎逻辑,但由于函数最终只有 return 函数,您应该能够链接启动 pos_tag(word_tokenize(...))
函数并遍历它,以便您可以检索 POS 标签和标记,即
sentence = "I love running angrily"
for word, pos in pos_tag(word_tokenize(sentence)):
print(word, '|', pos)
[出]:
I | PRP
love | VBP
running | VBG
angrily | RB
现在,我们知道 pos_tag
的输出与 WordNetLemmatizer
期望的 POS 之间存在不匹配。从 https://github.com/alvations/pywsd/blob/master/pywsd/utils.py#L124 开始,有一个函数调用 penn2morphy
看起来像这样:
def penn2morphy(penntag, returnNone=False, default_to_noun=False) -> str:
"""
Converts tags from Penn format (input: single string) to Morphy.
"""
morphy_tag = {'NN':'n', 'JJ':'a', 'VB':'v', 'RB':'r'}
try:
return morphy_tag[penntag[:2]]
except:
if returnNone:
return None
elif default_to_noun:
return 'n'
else:
return ''
一个例子:
>>> penn2morphy('JJ')
'a'
>>> penn2morphy('PRP')
''
如果我们使用这些转换后的标签作为 WordNetLemmatizer
的输入并重新使用您的 if-else 条件:
sentence = "I love running angrily"
for token, pos in pos_tag(word_tokenize(sentence)):
morphy_pos = penn2morphy(pos)
if morphy_pos in ["a", "n", "v"]:
print(wnl.lemmatize(token, pos=morphy_pos))
elif morphy_pos in ['r']:
print(wn.synset(token+".r.1").lemmas()[0].pertainyms()[0].name())
else:
print(wnl.lemmatize(token))
[出]:
I
love
run
angry
嘿,你在那里做什么?您的代码有效,但我的代码无效!
好的,现在我们知道如何获得所需的输出了。让我们回顾一下。
- 首先,我们清理导入
- 然后,我们清理预处理(不保留中间变量)
- 然后,我们"functionalized"从Penn -> Morphy 转换POS标签
- 最后,我们应用了相同的 if/else 条件和 运行 词形还原器。
但是我的代码怎么不起作用?!
好的,让我们检查一下您的代码,看看为什么会出现错误。
首先让我们检查您在 findTag
函数中获得的每个输出,打印输出类型和输出
sentence = "I love running angrily"
sentence = word_tokenize(sentence)
print(type(sentence))
print(sentence)
[出]:
<class 'list'>
['I', 'love', 'running', 'angrily']
在 sentence = word_tokenize(sentence)
处,您已经将原始变量覆盖到函数中,通常这是稍后出现错误的标志 =)
现在让我们看下一行:
sentence = "I love running angrily"
sentence = word_tokenize(sentence)
sentence = [i.strip(" ") for i in sentence]
print(type(sentence))
print(sentence)
[出]:
<class 'list'>
['I', 'love', 'running', 'angrily']
现在我们看到sentence = [i.strip(" ") for i in sentence]
实际上是没有意义的例句。
问:但是 word_tokenize
输出的所有标记都没有 i.strip(' ')
试图做的 trailing/heading 空格是真的吗?
A:对,好像是这样。然后 NLTK 首先对字符串进行正则表达式操作,然后调用 str.split()
function which would have removed heading/trailing spaces between tokens, see https://github.com/nltk/nltk/blob/develop/nltk/tokenize/destructive.py#L141
让我们继续:
sentence = "I love running angrily"
sentence = word_tokenize(sentence)
sentence = [i.strip(" ") for i in sentence]
pos_label = nltk.pos_tag(sentence)[0][1][0].lower()
print(type(pos_label))
print(pos_label)
[出]:
<class 'str'>
p
问:等一下,pos_label
只有一个字符串在哪里?
问:什么是 POS 标签 p
?
A:让我们仔细看看 nltk.pos_tag(sentence)[0][1][0].lower()
通常,当您必须执行这样的 [0][1][0]
嵌套索引检索时,它很容易出错。我们需要问什么是 [0][1][0]
?
我们知道sentence = word_tokenize(sentence)
之后的那句话现在变成了一个字符串列表。 pos_tag(sentence)
将 return 一个字符串元组列表,其中元组中的第一项是标记,第二项是 POS 标记,即
sentence = "I love running angrily"
sentence = word_tokenize(sentence)
sentence = [i.strip(" ") for i in sentence]
thing = pos_tag(sentence)
print(type(thing))
print(thing)
[出]:
<class 'list'>
[('I', 'PRP'), ('love', 'VBP'), ('running', 'VBG'), ('angrily', 'RB')]
现在,如果我们知道 thing = pos_tag(word_tokenize("I love running angrily"))
,输出上面的内容,让我们用它来查看 [0][1][0]
正在访问什么。
>>> thing = [('I', 'PRP'), ('love', 'VBP'), ('running', 'VBG'), ('angrily', 'RB')]
>>> thing[0][1]
('I', 'PRP')
所以thing[0]
输出第一个token的(token, pos)
的元组。
>>> thing = [('I', 'PRP'), ('love', 'VBP'), ('running', 'VBG'), ('angrily', 'RB')]
>>> thing[0][1]
'PRP'
并且thing[0][1]
输出第一个token的POS。
>>> thing = [('I', 'PRP'), ('love', 'VBP'), ('running', 'VBG'), ('angrily', 'RB')]
>>> thing[0][1][0]
'P'
接下来,[0][1][0]
查找第一个标记的 POS 的第一个字符。
所以问题是期望的行为?如果是,为什么只看第一个词的词性?
不管我在看什么。您的解释仍然没有告诉我 TypeError: unhashable type: 'list'
发生的原因。不要再分散我的注意力,告诉我如何解决 TypeError
!!
好的,我们继续前进,现在我们知道 thing = pos_tag(word_tokenize("I love running angrily"))
和 thing[0][1][0].lower() = 'p'
鉴于您的 if-else 条件,
if pos_label in ["a", "n", "v"]:
print(lem.lemmatize(word, pos = pos_label))
elif pos_label in ['r']:
print(wordnet.synset(sentence+".r.1").lemmas()[0].pertainyms()[0].name())
else:
print(lem.lemmatize(sentence))
我们发现 'p'
值会转到其他地方,即 print(lem.lemmatize(sentence))
但等一下,请记住 sentence
在您修改后变成了什么:
>>> sentence = word_tokenize("I love running angrily")
>>> sentence = [i.strip(" ") for i in sentence]
>>> sentence
['I', 'love', 'running', 'angrily']
那么如果我们忽略所有其余代码并专注于此会发生什么:
from nltk.stem import WordNetLemmatizer
lem = WordNetLemmatizer()
sentence = ['I', 'love', 'running', 'angrily']
lem.lemmatize(sentence)
[出]:
-------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-34-497ae98ecaa3> in <module>
4 sentence = ['I', 'love', 'running', 'angrily']
5
----> 6 lem.lemmatize(sentence)
~/Library/Python/3.6/lib/python/site-packages/nltk/stem/wordnet.py in lemmatize(self, word, pos)
39
40 def lemmatize(self, word, pos=NOUN):
---> 41 lemmas = wordnet._morphy(word, pos)
42 return min(lemmas, key=len) if lemmas else word
43
~/Library/Python/3.6/lib/python/site-packages/nltk/corpus/reader/wordnet.py in _morphy(self, form, pos, check_exceptions)
1903 # 0. Check the exception lists
1904 if check_exceptions:
-> 1905 if form in exceptions:
1906 return filter_forms([form] + exceptions[form])
1907
TypeError: unhashable type: 'list'
啊哈!!这就是错误发生的地方!!!
这是因为 WordNetLemmatizer
需要单个字符串输入,而您输入的是字符串列表。用法示例:
from nltk.stem import WordNetLemmatizer
wnl = WordNetLemmatizer()
token = 'words'
wnl.lemmatize(token, pos='n')
问:为什么不说正题?!
A: 那么你会错过如何调试你的代码并使其变得更好=)