【问题标题】:How to change array elements that are greater than 5 to 5, in one line?如何在一行中将大于 5 的数组元素更改为 5?
【发布时间】:2021-01-25 04:22:16
【问题描述】:

我想获取一个数组x 并将所有大于 5 的数字更改为 5。在一行中执行此操作的标准方法是什么?

下面是几行代码。逻辑索引上的 question 是相关的,但似乎与选择而不是分配有关。 谢谢

x = [1 2 6 7]
for i in 1:length(x)
    if x[i] >= 5 
        x[i] = 5
    end
end

期望的输出: x = [1 2 5 5]

【问题讨论】:

  • 请注意,在 Julia 中,即使有答案,您也不需要它们来提高性能。循环很快。
  • 答案太短了,但这有效:clamp!(x, -Inf, 5)

标签: indexing julia


【解决方案1】:

广播运算符. 适用于任何函数,包括关系运算符,也适用于赋值。因此,一个直观的单行是:

x[x .> 5] .= 5

这部分x .> 5x 上广播> 5,产生一个指示大于5 的元素的布尔向量。这部分.= 5x[x .> 5] 指示的所有元素上广播5 的分配。

但是,受以下 Benoit 非常酷的答案中 显着 加速的启发(请检查一下),我决定还添加一个带有速度测试的优化变体。上述方法虽然看起来非常直观,但并不是最优的,因为它为索引分配了一个临时的布尔数组。避免临时分配的(更多)最佳方法是:

function f_cond!(x::Vector{Int}, f::Function, val::Int)
    @inbounds for n in eachindex(x)
        f(x[n]) && (x[n] = val)
    end
    return x
end

因此,使用此函数,我们将编写f_cond!(x, a->a>5, 5),它将5 分配给条件(匿名)函数a->a>5 计算结果为true 的任何元素。显然,这个解决方案不是一个简洁的单行,但请查看以下速度测试:

julia> using BenchmarkTools

julia> x1 = rand(1:10, 100);

julia> x2 = copy(x1);

julia> @btime $x1[$x1 .> 5] .= 5;
  327.862 ns (8 allocations: 336 bytes)

julia> @btime f_cond!($x2, a->a>5, 5);
  15.067 ns (0 allocations: 0 bytes)

这速度快得离谱。此外,您可以将Int 替换为T<:Any。考虑到加速,人们可能想知道Base 中是否有一个已经这样做的函数。单行是:

map!(a->a>5 ? 5 : a, x, x)

虽然这比第一种方法显着加快了速度,但远低于第二种方法。

顺便说一句,我觉得这肯定是另一个 StackOverflow 问题的重复,但 5 分钟的搜索没有发现任何问题。

【讨论】:

    【解决方案2】:

    你也可以广播min

    x .= min.(x, 5)
    

    请注意,这比使用 x[x .> 5] .= 5 (稍微)更有效,因为它不分配布尔值的临时数组 x .> 5,并且它可以自动矢量化,只需通过内存一次(根据 Oscar 的评论下方):

    julia> using BenchmarkTools
    
    julia> x = [1 2 6 7] ; @btime $x .= min.($x, 5) ; # fast, no allocations
      19.144 ns (0 allocations: 0 bytes)
    
    julia> x = [1 2 6 7] ; @btime $x[$x .> 5] .= 5 ; # slower, allocates
      148.678 ns (5 allocations: 304 bytes)
    

    【讨论】:

    • 这个答案几乎可以肯定是更快的答案
    • 速度较快的另一个原因是该方案可以自动向量化,并且只通过内存一次。
    • 不错的提示!将其添加到答案中:)
    • 哦,这非常整洁!赞成。但你不是说min,而不是max吗?顺便说一句,鉴于此答案中显示的性能显着提高,我决定编辑我的以包括一般情况
    • 你也可以写clamp!(x, -Inf, 5)。我不认为它更快,但它可能更容易阅读——更明显的是一个上限。显然,我不是唯一一个必须阅读 minmax 两遍才能检查事情应该如何解决的人。
    猜你喜欢
    • 2020-03-03
    • 2020-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-13
    • 1970-01-01
    • 2020-07-13
    相关资源
    最近更新 更多