递归遍历嵌套字典列表的情感计算函数返回None且输出不稳定排查
问题分析与修复方案
嘿,咱们来拆解下你的walk函数为啥返回None还输出不稳定,然后一步步把它修好:
原代码的核心问题
- 递归调用白忙活了:碰到嵌套列表时,你调用了
walk(ele)但完全没管它返回的结果,深层的字典根本没被处理就丢了,等于递归白做了。 - 情感计算粒度错了:你用
str(ele.values())把整个字典的所有值拼成一串去算情感,这样得到的是整个字典内容的综合得分,没法对应到每个键值对,和你预期的“每个字段单独有得分”完全不符。 - 变量越改越乱:
new_sentiment每次循环字典都会被重新赋值,最后只留得下最后一个字典的结果;而且sentimentos在函数开头就初始化,递归的时候会被重置,深层数据的情感得分直接丢没了。 - 返回结构不对:你预期输出是列表包字典,但原函数返回的是单个字典,要是输入是多层嵌套,最后很可能因为没处理到顶层逻辑返回空字典,甚至在某些分支下返回
None。
修复后的完整代码
def walk(lst): result = [] # 专门用来收集所有处理好的字典 for ele in lst: if isinstance(ele, list): # 递归处理嵌套列表,把结果合并到当前列表里 result.extend(walk(ele)) elif isinstance(ele, dict): processed_dict = {} for key, value in ele.items(): # 对每个字段的值单独计算情感得分 score_list = calcula_sentimento(str(value)) # 取得分平均值(如果没得分就设为0,避免报错) avg_score = sum(score_list)/len(score_list) if score_list else 0.0 processed_dict[key] = [value, avg_score] result.append(processed_dict) return result # 你的calcula_sentimento函数保持不变 def calcula_sentimento(doc): sentences = nltk.sent_tokenize(doc) stokens = [nltk.word_tokenize(sent) for sent in sentences] taggedlist=[] for stoken in stokens: taggedlist.append(nltk.pos_tag(stoken)) wnl = nltk.WordNetLemmatizer() score_list=[] for idx,taggedsent in enumerate(taggedlist): score_list.append([]) for idx2,t in enumerate(taggedsent): newtag='' lemmatized=wnl.lemmatize(t[0]) if t[1].startswith('NN'): newtag='n' elif t[1].startswith('JJ'): newtag='a' elif t[1].startswith('V'): newtag='v' elif t[1].startswith('R'): newtag='r' else: newtag='' if(newtag!=''): synsets = list(swn.senti_synsets(lemmatized, newtag)) score=0 if(len(synsets)>0): for syn in synsets: score+=syn.pos_score()-syn.neg_score() score_list[idx].append(score/len(synsets)) sentence_sentiment=[] for score_sent in score_list: try: sentence_sentiment.append(sum([word_score for word_score in score_sent])/len(score_sent)) except ZeroDivisionError as err: pass return sentence_sentiment
关键修复点说明
- 递归结果不丢了:遇到嵌套列表时,用
result.extend(walk(ele))把递归返回的处理好的字典列表合并到当前结果里,深层的嵌套结构再也不会被忽略。 - 每个字段单独算分:对字典里的每个值单独调用
calcula_sentimento,计算这个值的情感得分,然后取平均值(因为你的calcula_sentimento返回的是句子级别的得分列表,单个值可能对应一个句子,取平均更合理)。 - 结果收集更靠谱:用
result列表统一收集所有处理后的字典,最后返回这个列表,完全符合你预期的输出结构。 - 变量不再乱覆盖:每个字典处理时单独创建
processed_dict,不会被后续的字典覆盖,确保每个字典都被正确处理并加入结果。
测试一下
用你给的输入样例跑一遍:
input_data = [[{'A0': 'Up to 140 asylum seekers', 'V': 'overpowered', 'A1': 'security guards', 'AM-LOC': 'at the tunnel s entrance', 'AM-TMP': 'as trains passed by dangerously close'}, {'A0': 'Up to 140 asylum seekers', 'V': 'swarmed on', 'A1': 'to the tracks', 'AM-TMP': 'as trains passed by dangerously close'}, {'A1': 'trains', 'V': 'passed', 'A2': 'by dangerously close'}]] output = walk(input_data) print(output)
会得到和你预期一致的结构,比如:
[ {'A0': ['Up to 140 asylum seekers', 0.0], 'V': ['overpowered', -0.125], 'A1': ['security guards', 0.0], 'AM-LOC': ['at the tunnel s entrance', 0.0], 'AM-TMP': ['as trains passed by dangerously close', -0.0625]}, {'A0': ['Up to 140 asylum seekers', 0.0], 'V': ['swarmed on', 0.0], 'A1': ['to the tracks', 0.0], 'AM-TMP': ['as trains passed by dangerously close', -0.0625]}, {'A1': ['trains', 0.0], 'V': ['passed', 0.0], 'A2': ['by dangerously close', -0.125]} ]
(具体得分取决于SentiWordNet的计算结果)
内容的提问来源于stack exchange,提问作者hjmnzs
相关产品推荐
相关产品推荐

