浅谈json-2
这是我浅谈json一二事的第一篇,链接如下
https://blog.csdn.net/dongguanting/article/details/115267289
如果对我或者NLP相关的知识感兴趣,欢迎关注我刚搭建的个人blog:
https://dongguanting.github.io/
前言
之前我已经说了一期嵌套非常复杂的json,今天我想聊的是另一种json,估计做NLP的小伙伴也很常见,这种json的特征是数据量非常常庞大,但是每条dict键值相同,数据集详见:
在此对数据稍作赘述:
数据集来自百度知道,百度知道的四个数据特点以及4个应用点,本项目通过采集百度知道,形成了百万级别的问答数据库规模。其中:
1, 问题个数583万个。
2, 问答对983万个。
3, 每个问题的答案个数1.7个。
4, 问题标签个数5824个。
QA对的数量情况(多余1即一问多答):
一、初探数据
json示例如下(示例)
{
"_id" : ObjectId("5d36e599bc54f451543da02b"),
"url" : "http://zhidao.baidu.com/question/2207667243516878988.html",
"answers" : [
"这与当时的历史背景有关。卡萨布兰卡属于法国的殖民地,而当时的法国是与纳粹德国合作的。但在法国人中又分为合作和抵抗两派。警长的立场早先是在双方之间摇摆不定。后来与Rick站在了一起。拿酒瓶又扔掉象征其抛弃过去,走上了义无反顾的抵抗道路。----------------------------------------------------------------------------------------卡萨布兰卡的剧情简介 · · · · · · 二战期间,卡萨布兰卡是欧洲逃往美国的必经之地,那里鱼龙混杂,局势紧张。里克(亨佛莱?鲍嘉 Humphrey Bogart 饰)是一个神秘的商人,他在卡萨布兰卡开了一家人气很旺的夜总会,并拥有两张宝贵的通行证。一天,反纳粹人士维克多和妻子伊尔莎(英格丽?褒曼 Ingrid Bergman 饰)来到夜总会,原来他们正在逃避纳粹的追捕。碰巧的是,里克发现,伊尔莎竟然是他的旧日情人。那段爱曾经刻骨铭心,却因为一个误会而终止。而当误会消解时,伊尔莎和里克的感情还是不可避免的重燃了。里克手上的两张通行证能帮助维克多度过难关,但这样一来,伊尔莎是决定留下,还是离去,他们的爱情在政治和伦理的推波逐流中走向何方。"
],
"question" : "卡萨布兰卡为什么是欧洲逃往美国的必经之地",
"tags" : [
"美国"
]
}
{
"_id" : ObjectId("5d36e599bc54f451543da02c"),
"url" : "http://zhidao.baidu.com/question/1929874578384929307。html",
"answers" : [
"你好是的!现在办理的身份证都是2代身份证!都是有磁性的"
],
"question" : "2017年办的身份证是二代身份证吗",
"tags" : [
"公务办理"
]
}
{
"_id" : ObjectId("5d36e599bc54f451543da02d"),
"url" : "http://zhidao.baidu.com/question/941683273505984492.html",
"answers" : [
"龙凤汤是一道色香味俱全的传统名肴,属于闽系。此菜汤色微红,清澈见底,是一道上等滋补药膳。此菜由泰西宾馆一级厨师孙业富创作,被泰安市地方名吃评审会评为一等奖,受到海内外宾客的好评。龙凤汤主要食材:鲤鱼 ,口 味:鲜香 ,辅 料:香菇主料鲤鱼1条﹐鸡(大雏鸡)1/2只﹐香菇5个﹐大枣﹑栗子各10个﹐切好的葱2大勺﹐蒜1头﹐香油﹐胡椒粉鸡肉佐料切好的葱1大勺﹐捣好的蒜1大勺﹐胡椒面1/4小勺﹐香油1小勺调料鸡蛋﹐辣椒丝做法(1) 鸡要准备大雏鸡﹐去掉头和瓜﹐除去内脏洗净。(2) 要准备活鲤鱼﹐去尾放血后刮鳞﹐并切成块洗净。(3) 把香菇泡在水里除去香菇柱﹐大枣去核﹐栗子去皮。(4) 鸡蛋煎出来﹐切成丝。(5) 往平锅里倒水﹐开锅时放鸡﹑香菇﹑栗子﹑大枣﹑蒜煮熟。营养价值编辑鸡完全煮熟时﹐捞取撕肉与葱﹑蒜﹑香油﹑胡椒粉一起拌。在煮鸡的汤里放鲤鱼块儿﹐重煮一遍。有龙凤汤的真味儿出来时﹐盛在碗里﹐并在上面放拌的鸡肉和辣椒丝。",
"因为香菇具有特殊的香味,会相互影响口味,所以不适合放。"
],
"question" : "为什么炖龙凤汤不能放香菇呢",
"tags" : [
"美食",
"花鸟鱼虫",
"香菇"
]
}
不难看出这json数据每一个dict都有相同的键值,难点在于dict数量繁多,并且dict都一个个分开。因为我们之后要做QA对的匹配(nlp的兄弟肯定懂QA是什么),所以目标就是要找到dict中键值“answer”数量为1个的dict(这样的dict有36w个),并将它保留,取其中的30w个dict输出在一个新json中即可,这样任务明确,开干!
二、代码实现
1.思路
我的思路很简单,其实就是读取这些json,然后通过if语句筛选len(data[“answer”])==1的json
将他们输出在新的json即可,并且每有一个符合条件的dict,计数器就+1,直到300000个结束。
2.几个坑
当我在实际编程的时候,遇到了几个坑:
- 500w条json实在太庞大了,所以在读取的时候一定要逐行读,这样保证每次line_data变量永远只存当前json,而不会将500w条全存进去,否则会出现虚拟内存不够的报错
这块要感谢这位博主的点播:
https://blog.csdn.net/Threeyearsago/article/details/104763329.
line_data = f.readline() #逐行读
data= json.loads(line_data)
- 写操作的时候,只允许字符串类型,且不会自动换行,所以大家可以参考我的模板进行写入
with open(path2, "a",encoding = 'utf-8') as fo:
fo.write(str(data)+"\n") #逐行读如并换行
3.全部代码
代码如下(示例):
import json
path1 =r"D:\json\zhidao_qa.json"#文件的存储位置
count = 0
with open(path1, 'r', encoding='utf-8') as f:#整体思路是逐行读取,一旦遇到空行
try: #用try和except语法,可以排错不报错
while True :#没出来的话一直读
line_data = f.readline() #逐行读
if line_data:
data= json.loads(line_data)#把读取的一行的json数据加载出来
#print(data)
if len(data['answers'])==1 and count<300000: #只找答案这一项为1的,并且只要30w行数据即可
path2 = r"D:\json\res.json"
with open(path2, "a",encoding = 'utf-8') as fo:
fo.write(str(data)+"\n") #逐行读如并换行
count+=1 #统计数加1
else:
break
except Exception as e:
print(e)
f.close()
代码注释很详尽了。
总结
以上就是我想分享的内容,json除了复杂list与dict的嵌套种类,还有dict数量庞大但是键值相似的json,nlp的学生未来必然会接触庞大的文本资源,希望大家可以在磨练中得心应手。
另附个人blog:https://dongguanting.github.io/
salute!