【问题标题】:Create a `Bool` array by randomly selecting values from two other `Bool` arrays通过从另外两个“Bool”数组中随机选择值来创建一个“Bool”数组
【发布时间】:2015-04-06 00:02:55
【问题描述】:

这里有两个真/假数组

a = [true, true, false, true, false]
b = [true, false, false, false, true]

我愿意创建一个新数组c,其中c 的每个元素来自ab 的概率相同

这是我找到的两个解决方案:

c=trues(5)
for i = 1:5
  c[i] = rand() > 0.5 ? a[i] : b[i]
end

c=trues(5)
ab = hcat(a,b)
which = sample([1,2], 5)
for i = 1:5
  c[i] = ab[i,which[i]]
end

有更好(更快)的解决方案吗?

【问题讨论】:

标签: arrays boolean julia


【解决方案1】:

我想说的是:

r = randbit(5)
c = [ r[i] ? a[i] : b[i] for i = 1:5 ]

第一行有效地生成了一个随机布尔数组r(实际上是一个位数组,但这是一个实现细节)。第二行根据r 中的值从ab 中选择元素,使用array comprehension,相当于您的for 循环,但更易读。

【讨论】:

    【解决方案2】:

    这与 jch 的答案略有不同,但使用位操作而不是根据“掩码”r 选择 ab 的元素可能会更快:

    julia> r = bitrand(5)
    5-element BitArray{1}:
      true
      true
     false
     false
     false
    
    julia> r&a | ~r&b
    5-element BitArray{1}:
      true
      true
      false
      false
      true
    

    请注意,我已更正此问题的位操作答案

    在我对这个问题的原始回答中,我说过根据掩码r 选择ab 的方式是a&r|b。然而被这个公式缺乏对称性所困扰,我更仔细地研究了这个问题,生成了一个完整的真值表并将公式更正为r&a | ~r&b

    julia> r = [trues(4), falses(4)]
    julia> a = [trues(2), falses(2)]
    julia> a = [a, a]
    julia> b = [true, false]
    julia> b = [b, b, b, b]
    julia> c = r&a | ~r&b
    julia> nocigar = a&r|b
    julia> q = [r[i] ? a[i] : b[i] for i in 1:length(a)]
    
    julia> all([c[i] == q[i] for i in 1:length(a)])
    true
    
    julia> all([nocigar[i] == q[i] for i in 1:length(a)])
    false
    

    当掩码为trueafalseortrue b 错误地导致@ 时,原始公式对于真值表中的 8 个条目之一出错987654337@。解决方法是用a 和掩码,用b 补码掩码,或者得到结果。这是真值表:

    julia> hcat(a, b, r, c, nocigar)
    8x5 Array{Bool,2}:
      true   true   true   true   true
      true  false   true   true   true
     false   true   true  false   true
     false  false   true  false  false
      true   true  false   true   true
      true  false  false  false  false
     false   true  false   true   true
     false  false  false  false  false
    

    现在进行一些分析

    我的直觉是,这个问题的位操作解决方案比使用 ? 运算符的理解要快得多。对这些操作进行计时表明,对于大型数组,位操作速度要快几个数量级,并且内存密集度要少得多。这是abr 的长度为 10^6 时得到的结果:

    julia> a = bitrand(10^6)
    ...
    
    julia> @time c = r&a | ~r&b
    elapsed time: 0.000607186 seconds (500496 bytes allocated)
    
    julia> @time c = [r[i] ? a[i] : b[i] for i in 1:length(a)]
    elapsed time: 0.446756657 seconds (167967416 bytes allocated, 16.91% gc time)
    

    多次运行这些分配会产生一致的结果。对于较短的数组,长度为 100,执行时间几乎没有差异,但理解使用更多内存:

    julia> a = bitrand(100)
    ...
    
    julia> @time c = r&a | ~r&b
    elapsed time: 1.3979e-5 seconds (464 bytes allocated)
    
    julia> @time c = [r[i] ? a[i] : b[i] for i in 1:length(a)]
    elapsed time: 5.326e-5 seconds (10520 bytes allocated)
    

    因此,如果您使用的是小型数组,任何一种技术都可以,但位操作对于非常大的数组更有效。

    【讨论】:

    • 我们真正需要的是“逐点条件”,所以我们可以说r .? a : b
    • @jch 肯定“逐点条件”会很棒。这个问题是针对布尔值的,所以我想我会指出这种“老派”技术,它可能又好又快。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-01
    • 2012-02-21
    • 2017-02-07
    • 1970-01-01
    • 2014-05-15
    • 2021-12-14
    • 2021-05-13
    相关资源
    最近更新 更多