gpt4 book ai didi

json - 在 Julia 中是否值得对 `JSON.parsefile` 返回的字典进行类型缩小

转载 作者:行者123 更新时间:2023-12-05 00:44:45 25 4
gpt4 key购买 nike

我正在编写 Julia 代码,其输入是 json 文件,在(数学金融领域)执行分析并将结果写入 json。代码是从 R 移植过来的,希望能提高性能。

我使用 JSON.parsefile 解析输入文件.这将返回一个 Dict,其中我观察到所有向量的类型都是 Array{Any,1} .碰巧的是,我知道输入文件永远不会包含混合类型的向量,例如某些 String s 和一些 Number s。
所以我写了下面的代码,它似乎运行良好并且“安全”,如果调用 convert失败然后向量继续具有类型 Array{Any,1} .

function typenarrow!(d::Dict)
for k in keys(d)
if d[k] isa Array{Any,1}
d[k] = typenarrow(d[k])
elseif d[k] isa Dict
typenarrow!(d[k])
end
end
end

function typenarrow(v::Array{Any,1})
for T in [String,Int64,Float64,Bool,Vector{Float64}]
try
return(convert(Vector{T},v))
catch; end
end
return(v)
end

我的问题是:这值得吗?我可以期待处理 Dict 内容的代码吗?如果我进行这种类型的缩小,执行速度会更快吗?我认为答案是肯定的,因为 Julia performance tips建议“注释取自无类型位置的值”,这种方法可确保没有“无类型位置”。

最佳答案

这个问题的答案有两个层次:

级别 1

是的,这将有助于代码的性能。例如,请参阅以下基准:

julia> using BenchmarkTools

julia> x = Any[1 for i in 1:10^6];

julia> y = [1 for i in 1:10^6];

julia> @btime sum($x)
26.507 ms (477759 allocations: 7.29 MiB)
1000000

julia> @btime sum($y)
226.184 μs (0 allocations: 0 bytes)
1000000

您可以写下您的 typenarrow函数使用更简单的方法,如下所示:
typenarrow(x) = [v for v in x]

因为使用理解将产生一个具体类型的向量(假设你的源向量是同质的)

2级

这不是完全最优的。仍然存在的问题是您有一个 Dict那是一个带有抽象类型参数的容器(见 https://docs.julialang.org/en/latest/manual/performance-tips/#Avoid-containers-with-abstract-type-parameters-1)。因此,为了使计算更快,您必须使用屏障函数(请参阅 https://docs.julialang.org/en/latest/manual/performance-tips/#kernel-functions-1 )或对您引入的变量使用类型注释(请参阅 https://docs.julialang.org/en/v1/manual/types/index.html#Type-Declarations-1 )。

在理想世界中你的 Dict将具有同类类型的键和值,并且所有这些都将是最快的,但是如果我正确理解您的代码,那么您的情况下的值不是同类的。

编辑

为了解决2级问题,您可以转换 Dict进入 NamedTuple像这样(这是一个最小的例子,假设 Dict s 只嵌套在 Dict s 中,但如果你想要更多的灵活性,它应该很容易扩展)。

首先,执行转换的函数如下所示:
function typenarrow!(d::Dict)
for k in keys(d)
if d[k] isa Array{Any,1}
d[k] = [v for v in d[k]]
elseif d[k] isa Dict
d[k] = typenarrow!(d[k])
end
end
NamedTuple{Tuple(Symbol.(keys(d)))}(values(d))
end

现在是它使用的 MWE:
julia> using JSON

julia> x = """
{
"name": "John",
"age": 27,
"values": {
"v1": [1,2,3],
"v2": [1.5,2.5,3.5]
},
"v3": [1,2,3]
}
""";

julia> j1 = JSON.parse(x)
Dict{String,Any} with 4 entries:
"name" => "John"
"values" => Dict{String,Any}("v2"=>Any[1.5, 2.5, 3.5],"v1"=>Any[1, 2, 3])
"age" => 27
"v3" => Any[1, 2, 3]

julia> j2 = typenarrow!(j1)
(name = "John", values = (v2 = [1.5, 2.5, 3.5], v1 = [1, 2, 3]), age = 27, v3 = [1, 2, 3])

julia> dump(j2)
NamedTuple{(:name, :values, :age, :v3),Tuple{String,NamedTuple{(:v2, :v1),Tuple{Array{Float64,1},Array{Int64,1}}},Int64,Array{Int64,1}}}
name: String "John"
values: NamedTuple{(:v2, :v1),Tuple{Array{Float64,1},Array{Int64,1}}}
v2: Array{Float64}((3,)) [1.5, 2.5, 3.5]
v1: Array{Int64}((3,)) [1, 2, 3]
age: Int64 27
v3: Array{Int64}((3,)) [1, 2, 3]

这种方法的美妙之处在于 Julia 会知道 j2 中的所有类型。 ,所以如果你通过 j2将任何函数作为参数,该函数内的所有计算都会很快。

这种方法的缺点是函数采用 j2必须预编译,如果 j2 可能会有问题结构是巨大的(因为结果 NamedTuple 的结构很复杂)并且您的函数所做的工作量相对较小。但是对于小的 JSON-s(在结构意义上很小,因为其中包含的向量可能很大 - 它们的大小不会增加复杂性)这种方法已被证明在我开发的几个应用程序中是有效的。

关于json - 在 Julia 中是否值得对 `JSON.parsefile` 返回的字典进行类型缩小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54709020/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com