如何避免在 Julia 中使用匿名函数对多个字段进行条件过滤并使用可调用函数来获得一些性能?.
using DataFrames
df=DataFrame( a=rand(["cat","dog","tiger","parrot","elephant","mouse"],100000),
r=rand(vcat(1:6),100000)
)
##this is OK:
subset(df, :r => r->r.>4) #using anonymous function
##this is faster
subset(df, :r => ByRow(>(4)) #somehow is vectorized, this is the gain I guess!
##with multiples field: (animal could be dog or r higher than 4)
subset(df,[:a,:r]=>ByRow((a,r) -> .|((a=="dog") ,(r>4))))
#fast, but could be faster without anonymous part "(a,r) ->"?
##so wondering:
subset(df,[:a,:r]=> ##callable function for the condition above
谢谢!
subset
将多个标准作为附加参数,所以我认为您所追求的是:
subset(df, :a => ByRow(==("dog")), :r => ByRow(>(4)))
我看到大约 10% 的加速,所以它不是一个性能方面的游戏规则改变者:
julia> @btime subset($df, :a => ByRow(==("dog")), :r => ByRow(>(4)));
677.500 μs (296 allocations: 358.28 KiB)
julia> @btime subset($df, [:a, :r] => ((a, r) -> r .> 4 .&& a .== "dog"));
607.200 μs (215 allocations: 174.95 KiB)
也许考虑使用标准索引的简单视图?
julia> @btime @view $df[$df.r .> 4 .&& $df.a .== "dog", :];
476.300 μs (14 allocations: 60.67 KiB)
或者
filter
无论如何都是有效的:
julia> @btime filter([:r, :a] => (r, a) -> r > 4 && a == "dog", $df)
502.000 μs (27 allocations: 149.00 KiB)
一般来说,对
DataFrame
对象进行行操作的一个很好的参考是 Bogumil Kaminski 的优秀(并且始终是最新的!)教程 Jupyter notebooks 的“行”部分:
https://github.com/bkamins/Julia-DataFrames-Tutorial/blob/master/06_rows.ipynb
在匿名函数和具有倍数字段的已定义函数之间,增益很小或没有增益。但重要的是用 ByRow 包装它,因为使用匿名函数的广播会有一些损失。
using BenchmarkTools
#Scenario 1
@btime subset($df,[:a,:r]=>ByRow((a,r) -> .|((a=="dog") ,(r>4))))
#scenario 2: with callable function
function myfilter(a::String,r::Int64)
a=="dog" || r>4
end
@btime subset($df,[:a,:r]=>ByRow(myfilter))