【问题标题】:Processing JSON from a .txt file and converting to a DataFrame in Julia从 .txt 文件处理 JSON 并在 Julia 中转换为 DataFrame
【发布时间】:2021-05-14 14:18:05
【问题描述】:

来自Julia Discourse 的交叉发帖,以防这里的任何人有任何线索。

我只是想了解一下为什么下面的代码返回的数据框只包含我的 json 文件的第一行。如果您想尝试使用我正在使用的文件,您可以从Microsoft Open Academic Graph site 下载aminer_papers_0.zip,我正在使用该组文件中的第一个文件。

using JSON3, DataFrames, CSV
file_name = "path/aminer_papers_0.txt"
json_string = read(file_name, String)
js = JSON3.read(json_string)
df = DataFrame([js])

生成的 DataFrame 只有一行,但列标题是正确的,第一行也是如此。对我来说,谜团在于为什么其余部分没有得到处理。我想我可以排除 read() 只是读取第一个 JSON 对象,因为我可以索引到结果对象并看到许多 JSON 对象:

enter image description here

我的第一个猜测可能是换行符 \n 导致了转义问题,并尝试使用 chomp 来摆脱它们,但无法正常工作。

无论如何 - 任何帮助将不胜感激!

【问题讨论】:

  • 你能分享你正在处理的文件吗?在我的机器上下载整个 zip 文件需要 9 小时。
  • 是的 - 我将很快创建一个共享链接。不过,单个文件也很大,所以需要几分钟才能放到一个我可以分享的地方。
  • 好的 - 我想你应该可以在这里得到它:dropbox.com/s/mfv8e7uc2267786/aminer_papers_0.txt?dl=0
  • OK - 我看到文件有 9GB。不幸的是,我没有足够的 RAM 来处理它。也许@quinnj 可以看看你的问题。我会ping他。您是否尝试过使用github.com/JuliaData/JSONTables.jl
  • 好的——没问题。而且我还没有给 JSONTables 一个适当的尝试。

标签: json julia dataframes.jl


【解决方案1】:

我认为问题在于文件是JSON Lines 格式,除非另有说明,否则 JSON3 库只返回它在字符串开头找到的第一个有效 JSON 值。

tl;博士

使用关键字参数jsonlines=true 调用JSON3.read

为什么?

默认情况下,JSON3 将传递给其read 函数的字符串解释为由RFC 8259 section 1.3.2 定义的单个“JSON 文本”:

JSON 文本是一个序列化值....

(我强调不定单数冠词“a”的使用。)section 1.3.3中定义了一个“JSON值”:

JSON 值必须是对象、数组、数字或字符串,或以下三个文字名称之一:false、null、true。

其中包含多个 JSON 值的字符串在技术上是多个“JSON 文本”。由解析器决定你给它的字符串参数的哪一部分是 JSON 文本,并且 JSON3 的作者选择了从字符串开头到第一个有效 JSON 值结尾的默认行为。

为了让 JSON3 将字符串读取为多个 JSON 值,您必须为其提供关键字选项 jsonlines=true,其记录为:

jsonlines:一个 Bool,表示 json_str 包含换行符分隔的 JSON 字符串,这些字符串将被读入 JSON 值的 JSON3.Array。请参阅jsonlines 以供参考。 [默认假]

示例

以这个简单的字符串为例:

two_values = "3.14\n2.72"

每一行都是数字的有效 JSON 序列化。但是,当传递给JSON3.read 时,只解析第一个:

using JSON3
@assert JSON3.read(two_values) == 3.14

使用jsonlines=true,两个值都被解析并作为JSON3.Array结构返回:

@assert JSON3.read(two_values, jsonlines=true) == [3.14, 2.72]

其他包

JSON.jl 库,在给定名称的情况下,人们可能会默认使用它,它根本不实现 JSON Lines 字符串的解析,而是由调用者根据需要正确拆分字符串:

using JSON
JSON.parse(two_values)
# ERROR: Expected end of input
# Line: 1
# Around: ...3.14 2.72...
#                 ^

实现读取多个值的简单方法是使用eachline

@assert [JSON.parse(line) for line in eachline(IOBuffer(two_values))] == [3.14, 2.72]

【讨论】:

  • 我认为你必须小心使用eachline,因为它会拆分包含换行符本身的JSON字符串,例如{"a": "new\nline"}。为避免这种情况,您必须编写自己的 JSON 解析器......更容易使用 JSON3。
  • 伟大的收获!除了技术上带有非转义控制字符的字符串值(如 \n)之外,section 7 of RFC 8259 是无效的 JSON,因此当由符合标准的 JSON 解析器解析时,该示例应该会失败。我查了一下,JSON3不会接受这样的字符串作为值。
  • 澄清一下,如果代码序列 U+000A(换行符)出现在字符串值中,那么这是一个无效的 JSON 字符串。但是,换行符可以出现在有效 JSON 中的字符串值之外(它们被视为空格并被忽略),并且上面的 eachline 方法在读取类似格式的文本时失败。正如 BallpointBen 所说,最好只使用像 JSON3 这样正确处理 JSON Lines 格式的解析器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-09
  • 2020-11-09
  • 1970-01-01
  • 1970-01-01
  • 2013-05-26
  • 2017-06-18
  • 2019-07-11
相关资源
最近更新 更多