Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R 如何将一个大的、复杂的、嵌套很深的JSON文件展平为多个CSV文件—一个链接标识符_R_Json_Csv_Jq_Jsonlite - Fatal编程技术网

R 如何将一个大的、复杂的、嵌套很深的JSON文件展平为多个CSV文件—一个链接标识符

R 如何将一个大的、复杂的、嵌套很深的JSON文件展平为多个CSV文件—一个链接标识符,r,json,csv,jq,jsonlite,R,Json,Csv,Jq,Jsonlite,我有一个复杂的JSON文件(~8GB),其中包含企业公开可用的数据。我们决定将这些文件拆分为多个CSV文件(或.xlsx中的选项卡),以便客户端可以轻松地使用这些数据。这些文件将通过NZBN列/键链接 我使用R和jsonlite在中读取一个小样本(在扩展到完整文件之前)。我猜我需要某种方法来指定每个文件中的键/列(即,第一个文件将有标题:australianBusinessNumber、australianCompanyNumber、australianServiceAddress,第二个文件将

我有一个复杂的JSON文件(~8GB),其中包含企业公开可用的数据。我们决定将这些文件拆分为多个CSV文件(或.xlsx中的选项卡),以便客户端可以轻松地使用这些数据。这些文件将通过NZBN列/键链接

我使用R和jsonlite在中读取一个小样本(在扩展到完整文件之前)。我猜我需要某种方法来指定每个文件中的键/列(即,第一个文件将有标题:australianBusinessNumber、australianCompanyNumber、australianServiceAddress,第二个文件将有标题:annualReturnFilingMonth、AnnualReturnLastField、countryOfOrigin…)

下面是两个企业/实体的示例(我也收集了一些数据,因此忽略了实际值):

我读过几乎每一篇关于s/o的类似问题的帖子,似乎都没有给我带来任何运气。我尝试过purrr、*apply命令、自定义展平函数和jqr(jq的r版本——看起来很有希望,但我似乎无法运行)

这里尝试创建单独的文件,但我不确定如何包含链接标识符(NZBN)+我一直在运行进一步的嵌套列表(我不确定有多少层嵌套)

批量
我不确定有多少层次的筑巢

这将非常有效地解决这一问题:

jq '
  def max(s): reduce s as $s (null; 
    if . == null then $s elif $s > . then $s else . end);
   max(paths|length)' input.json
(对于测试文件,答案是14。)

要获得数据的总体视图(模式),您可以 运行:

其中schema.jq在此处可用。这将产生一个结构模式

例如,我想创建以下元素的csv: 除了标题之外,还有一个jq解决方案:

.companies.entity[]
| [.entityName, .nzbn]
  + (.emailAddress[] | [.uniqueIdentifier, .emailAddress, .emailPurpose, .emailPurposeDescription, .startDate])
| @csv
持股 持股数据是复杂的,因此在下面我使用了本页其他地方定义的
to_table
函数

示例数据不包括“公司名称”字段,因此在下面,我添加了一个基于0的“公司索引”字段:

jqr 上述解决方案使用独立的jq可执行文件,但一切顺利,使用相同的过滤器应该很简单,尽管要使用jq的
include
,可能最简单的方法是显式指定路径,例如:

include "schema" {search: "~/.jq"};

如果输入JSON足够规则,则 可能会发现以下展平函数很有用,特别是因为它可以根据输入的叶元素的“路径”以字符串数组的形式发出头,可以任意嵌套:

# to_table produces a flat array.
# If hdr == true, then ONLY emit a header line (in prettified form, i.e. as an array of strings);
# if hdr is an array, it should be the prettified form and is used to check consistency.
def to_table(hdr):
  def prettify: map( (map(tostring)|join(":") ));
  def composite: type == "object" or type == "array";

  def check:
     select(hdr|type == "array") 
     | if prettify == hdr then empty
       else error("expected head is \(hdr) but imputed header is \(.)")
       end ;

  . as $in
  | [paths(composite|not)]           # the paths in array-of-array form
  | if hdr==true then prettify
    else check, map(. as $p | $in | getpath($p))
    end;


例如,要为.emailAddress生成所需的表(无标题),可以编写:

.companies.entity[]
| [.entityName, .nzbn] as $ix
| $ix + (.emailAddress[] | to_table(false))
| @tsv
(添加标题并检查一致性, 现在只剩下练习了,但将在下面讨论。)

生成多个文件 更有趣的是,您可以选择所需的级别,并自动生成多个表。有效地将输出划分为单独文件的一种方法是使用awk。例如,您可以通过管道将使用此jq过滤器获得的输出:

["entityName", "nzbn"] as $common
| .companies.entity[]
| [.entityName, .nzbn] as $ix
| (to_entries[] | select(.value | type == "array") | .key) as $key
| ($ix + [$key] | join("-")) as $filename
| (.[$key][0]|to_table(true)) as $header

# First emit the line giving all the headers:
| $filename, ($common + $header | @tsv),
# Then emit the rows of the table:
  (.[$key][]
   | ($filename,  ($ix + to_table(false) | @tsv)))


这将在每个文件中生成标题;如果您想要一致性检查,请将
更改为\u table(false)
更改为
更改为\u table($header)

很遗憾,我没有jq-我想我需要管理员权限,这是一台工作PC。jqr(jq的R实现)没有提供使用上述代码所获得的信息。语言大致相同吗?感谢您的深入回答,包括下面的to_table函数。我还不能让它工作,但你们的jq解决方案上面的电子邮件地址已经和其他收集工作。cheersHi,我在持股部分遇到了一些问题(比emailAddress示例更复杂):.companys.entity[]|[.entityName,.nzbn]+(.company.holdings[]|.numberOfShares)不会从文件中产生任何结果我在其他响应中添加了“持股”部分,正如你的jq所建议的那样,你没有试图使用
来创建一个表
。非常感谢-哇,这很强大。还有最后一个复杂的问题,我似乎无法弄清楚,在每个持股中,可能有多个股东(最多50个)。您的to_table函数似乎只是在同一行上扩展了这些内容(正如预期的那样)-但是,这会为拥有大量股东/股份的公司带来真正广泛的csv。您是否可以在下面的行中重复多个股东/持股(相同的实体名称和nzbn)。这里有一个更新的测试文件:“生成多个文件”一节说明了如何避免拉伸问题,但是您必须决定在什么时候开始创建新文件。也就是说,“生成多个文件”部分是说明性的——您必须理解它才能根据您的需要进行调整。假设JSON具有足够的规则性,那么
to_table
的要点是处理可能需要的任何拉伸,以避免丢失数据。
.companies.entity[]
| [.entityName, .nzbn] as $ix
| $ix + (.emailAddress[] | to_table(false))
| @tsv
["entityName", "nzbn"] as $common
| .companies.entity[]
| [.entityName, .nzbn] as $ix
| (to_entries[] | select(.value | type == "array") | .key) as $key
| ($ix + [$key] | join("-")) as $filename
| (.[$key][0]|to_table(true)) as $header

# First emit the line giving all the headers:
| $filename, ($common + $header | @tsv),
# Then emit the rows of the table:
  (.[$key][]
   | ($filename,  ($ix + to_table(false) | @tsv)))

awk -F\\t 'fn {print >> fn; fn=0;next} {fn=$1".tsv"}'