训练LDA主题模型时json.dump报int64类型无法JSON序列化错误如何解决?
错误成因
- 直接原因:Python标准库的
json模块仅支持序列化Python原生数据类型,无法识别Numpy定义的数值类型(如np.int64、np.float64等)。LdaModel.show_topics()返回的结果中包含主题编号、词权重等数值,当主题数为5、10时这些值恰好是Python原生的int/float类型,可以正常序列化;当主题数为15时,部分返回值为Numpy的int64类型,触发序列化报错。 - 隐藏bug:你的
build_models方法参数中定义了start作为主题数起始值,但是在循环内部你又用start = time.time()给这个变量赋了时间戳值,虽然单次run内的主题数循环不受影响(range在循环启动时就已经完成计算),但第二轮及之后的run在生成主题数范围时,start已经变成了远大于71的时间戳,后续轮次的训练会直接跳过。
解决方法
1. 修复变量名冲突
先把统计时间的变量改名,避免覆盖参数:
# 把原来的start = time.time() 改成 start_time = time.time() # 对应的打印语句里的计算改成 print('Calculating topics for ', str(num_topics), 'number of topics, took: ', str(int(end - start_time)), ' seconds.')
2. 解决Numpy类型序列化问题
有三种常用方案可选:
- 方案A:序列化前统一转换Numpy类型
先定义一个递归转换函数,把所有Numpy类型转成Python原生类型后再序列化:
import numpy as np def convert_np_to_python(obj): if isinstance(obj, np.integer): return int(obj) elif isinstance(obj, np.floating): return float(obj) elif isinstance(obj, np.ndarray): return obj.tolist() elif isinstance(obj, dict): return {k: convert_np_to_python(v) for k, v in obj.items()} elif isinstance(obj, (list, tuple)): return [convert_np_to_python(i) for i in obj] return obj
保存前对结果做转换:
topic_dict[num_topics] = convert_np_to_python(model.show_topics()) coherence_dict[num_topics] = convert_np_to_python(coherence_dict[num_topics])
- 方案B:给json.dump增加default参数处理Numpy类型
不需要额外转换函数,直接在序列化时指定类型处理逻辑:
json.dump(topic_dict, dump, default=lambda x: int(x) if isinstance(x, np.integer) else float(x) if isinstance(x, np.floating) else x)
- 方案C:改用pickle做序列化
如果不需要生成人类可读的json文件,直接用Python原生的pickle库序列化,无需处理类型兼容问题:
import pickle # 保存 with open(PATH+"LDA_topics.pkl", "wb") as f: pickle.dump(topic_dict, f) # 读取 with open(PATH+"LDA_topics.pkl", "rb") as f: topic_dict = pickle.load(f)
内容的提问来源于stack exchange,提问作者Emil
相关产品推荐
相关产品推荐

