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