Dataframe 矢量化;在;朱莉娅的作用?
我经常想在数据帧的长数组或列上循环,并且对于每个项,查看它是否是另一个数组的成员。而不是做Dataframe 矢量化;在;朱莉娅的作用?,dataframe,vectorization,julia,Dataframe,Vectorization,Julia,我经常想在数据帧的长数组或列上循环,并且对于每个项,查看它是否是另一个数组的成员。而不是做 giant_list = ["a", "c", "j"] good_letters = ["a", "b"] isin = falses(size(giant_list,1)) for i=1:size(giant_list,1) isin[i] = giant_list[i] in good_letters end 在julia中有没有矢量化(双重矢量化?)的方法?与基本运算符类似,我想做如下
giant_list = ["a", "c", "j"]
good_letters = ["a", "b"]
isin = falses(size(giant_list,1))
for i=1:size(giant_list,1)
isin[i] = giant_list[i] in good_letters
end
在julia中有没有矢量化(双重矢量化?)的方法?与基本运算符类似,我想做如下操作
isin = giant_list .in good_letters
我意识到这可能不可能,但我只是想确保我没有遗漏什么。我知道我可能可以使用DataStructures中的DefaultDict来做类似的事情,但我不知道base中的任何东西 该函数执行与您所需类似的操作:
indexin(a,b)
对于a
中作为b
成员的每个值,返回包含b
中最高索引的向量。如果a
不是b
的成员,则输出向量包含0
由于您希望在巨型字母列表中的每个元素都有一个布尔值(而不是好字母
中的索引),您只需执行以下操作:
julia> indexin(giant_list, good_letters) .> 0
3-element BitArray{1}:
true
false
false
这是非常简单的,并且指出了如果您不关心b
中的索引,您可以如何对此进行优化:
function vectorin(a, b)
bset = Set(b)
[i in bset for i in a]
end
只有一组有限的名称可以用作中缀运算符,因此不可能将其用作中缀运算符。在Julia v0.6中,使用
通过使用一个元素元组来记录好字母的数量。或者,您可以使用标量类型,如staticArray.jl中引入的类型
Julia v0.5支持相同的语法,但需要一个专门的函数来进行scalarification(或前面提到的Scalar
类型):
之后
julia> in.(giant_list, scalar(good_letters))
3-element Array{Bool,1}:
true
false
false
findin()
不提供布尔掩码,但您可以轻松使用它为包含在另一个数组中的值的数组/数据帧子集:
julia> giant_list[findin(giant_list, good_letters)]
1-element Array{String,1}:
"a"
有几种现代(即Julia v1.0)解决方案可以解决此问题:
首先,对标量策略进行更新。可以使用Ref
对象实现标量广播,而不是使用1元素元组或数组:
julia> in.(giant_list, Ref(good_letters))
3-element BitArray{1}:
true
false
false
通过播放中缀∈代码>(\in
选项卡)运算符:
julia> giant_list .∈ Ref(good_letters)
3-element BitArray{1}:
true
false
false
此外,使用一个参数调用
中的,将创建一个Base.Fix2
,稍后可通过广播调用应用该函数。不过,与简单地定义函数相比,这似乎具有有限的好处
julia> is_good1 = in(good_letters);
is_good2(x) = x in good_letters;
julia> is_good1.(giant_list)
3-element BitArray{1}:
true
false
false
julia> is_good2.(giant_list)
3-element BitArray{1}:
true
false
false
总之,使用。∈带有Ref
的code>可能会产生最短、最干净的代码。性能评估
其他答案忽略了一个重要方面——性能。所以,让我简单回顾一下。为了实现这一点,我创建了两个Integer
向量,每个向量包含100000个元素
using StatsBase
a = sample(1:1_000_000, 100_000)
b = sample(1:1_000_000, 100_000)
为了知道什么是好的性能,我在R
中做了同样的事情,导致性能中值为4.4 ms
:
# R code
a <- sample.int(1000000, 100000)
b <- sample.int(1000000, 100000)
microbenchmark::microbenchmark(a %in% b)
Unit: milliseconds
expr min lq mean median uq max neval
a %in% b 4.09538 4.191653 5.517475 4.376034 5.765283 65.50126 100
比R
慢,但相差不大。然而,语法确实需要一些改进
不共振解
速度慢了800倍(几乎比R
慢了1000倍)——这真的没什么好写的。在我看来,这三种解决方案的语法也不是很好,但至少在我看来,第一种解决方案比“性能解决方案”要好
这不是一个解决方案
这个
indexin(a,b)
5.287 ms (38 allocations: 6.53 MiB)
是有效的,但对我来说这不是一个解决方案。当元素不在另一个向量中时,它不包含任何元素。在我看来,主要的应用是对一个向量进行子集,而这不适用于这个解决方案
a[indexin(b,a)]
ERROR: ArgumentError: unable to check bounds for indices of type Nothing
这在DataArray上运行得很好,尽管它在NAs上运行得不好(幸运的是,这对我来说并不重要)。我想我在这里遗漏了一些东西:上面的命令和0.5.0中抛出错误的几个变体。@ARM:啊,对不起,原来我一直在0.6.0上测试,在0.6.0上,确切的命令可以工作。在0.5.0上,您需要一个零维数组(或标量类型)。@ARM我已经用一个同样适用于0.5的答案更新了我的解决方案。注意:这适用于数组,但不适用于0.6上的DataArray。Matt B.的答案仍然适用于这两种情况。请注意,findin
在0.7中被弃用,并从1.0中删除findall(在(…),…)
替换它。
findall(in(b),a)
5.039 ms (27 allocations: 3.63 MiB)
a .∈ Ref(b)
in.(a,Ref(b))
findall(x -> x in b, a)
3.879468 seconds (6 allocations: 16.672 KiB)
3.866001 seconds (6 allocations: 16.672 KiB)
3.936978 seconds (178.88 k allocations: 5.788 MiB)
indexin(a,b)
5.287 ms (38 allocations: 6.53 MiB)
a[indexin(b,a)]
ERROR: ArgumentError: unable to check bounds for indices of type Nothing