前言
在机器学习领域中,.json
和.jsonl
格式的文件是非常常见的。大量数据集都以这两种格式处理。然而,在导出这种类型文件的时候,会遇到很多问题。这篇文章就来谈一谈这两种文件格式以及如何解决相关问题。
1. 文件格式
.json
格式
JSON的全称是JavaScript Object Notation,是一种以键值对存储信息的文件格式。其基本数据类型有:
- 数字。
- 字符串。
- 布尔值。
- 数组,由中括号括起。
- 对象:由大括号括起。
- 空值:null
我们随便打开一个.json
文件,观察一下其结构:
1 | [ |
熟悉Python语言的朋友们都知道,这个格式就是:由一个或多个字典组织起来的列表。
值得一提的是,在.json
文件中,字符串只能由双括号括起,不能由单括号括起来。此外,键也只能是字符串。
.jsonl
格式
.jsonl
格式的文件可以看作.json
文件的一个扩展,其例子如下:
1 | {"name": "John", "age": 30} |
这个格式就是:多个字典,按照一行一个的排列方式排列起来的格式。同样,字符串只能由双括号括起,不能由单括号括起来。
2. 导出字典为.json
格式
假设我们有这样一个字典列表:
1 | a = [{"name": "w", 1:2}, {"name": "t", 3:4}] |
想要将其导出为.json
格式,应该怎么做呢?
1.字典转为字符串,直接导出
乍一看,a
符合.json
文件的格式,那么,我们会很自然的想到,直接将a
转成字符串,输出到文件中不就可以了:
1 | output_file = open("output.json", "a") |
然而,当我们尝试打开output.json
时,会发现其并非一个合法的.json
文件,此时该文件内容如下:
1 | [{'name': 'w', 1: 2}, {'name': 't', 3: 4}] |
该文件具有几个问题:
- 键不全是字符串。
- 文件中的字符串没有用双引号括起来。
那么该怎么办呢?
2. 修改字典转化成的字符串
可能,我们可以先将字典转化为字符串,然后将全部的单引号改为双引号,然后检查键的值。
这个方法很麻烦,此外,当键值对中出现转义的双引号时,处理会更加复杂:
1 | a = [{"name": "w", 1:2}, {"name": "This is \"Q\"", 3:4}] |
3. 利用json
库导出
代码如下:
1 | import json |
这种方法简洁有效。
3. 导出字典为.jsonl
格式
既然我们已经会导出为.json
格式了,那么导出为.jsonl
格式,无非只需要增加一个遍历输出的操作。因为.jsonl
是多个字典,按照一行一个的排列方式排列起来的格式:
1 | import json |
这样就可以了。
4. 中文问题
应用如上代码导出中文内容时,文件会变成:
1 | {"src": "\u8fd9\u4e2a\u673a\u957f\u4eca\u5929\u7684\u98de\u884c\u4efb\u52a1\u662f\u5f00\u4e00\u67b6\u5927\u7684\u98de\u673a\u3002\n", "tgt": "The captain's mission today is to fly a large aircraft.\n", "hyp": "This sentence is already in English."} |
这个时候,我们只需要向json.dump()
中,增加一个ensure_ascii=False
参数,结果就会变成:
1 | {"src": "这个机长今天的飞行任务是开一架大的飞机。\n", "tgt": "The captain's mission today is to fly a large aircraft.\n", "hyp": "This sentence is already in English."} |
5. 导入文件
我们要利用的妙妙工具是:eval()
函数。这个函数可以将一个字符串当作代码处理。比如:
1 | eval("print(\"s\")") # Output: "s" |
第一个例子会在命令行中打印一个s,第二个例子则会返回一个列表,其元素只有一个1。
.json
格式
调用json
库中的load
即可:
1 | input_file = open("input.json", "r") |
.jsonl
格式
由于.jsonl
是一行一个字典,那么我们只需要:
1 | actual_blocks = [] |
先获得所有行,然后通过eval()
函数,将所有字符串转换成dict
即可。
迭代器
当我们有迭代.jsonl
文件中全部dict的需要时,可以应用如下的迭代器:
1 | def SR_jsonl_iterator(file_name): |