Как случайным образом и не многократно выбирать элементы из массива? - PullRequest
3 голосов
/ 19 января 2020

Как следует из названия, я хочу выбрать 2 или 3 элемента из массива без замены.

Я знаю, что могу выполнить эту работу с помощью функции Base.rand и оператора if, но я ' Я все еще ищу более элегантный способ сделать это.

= = = Редактировать: 2020/01/21 = = =

@ Gwang-Jin Kim, @ phipsgabler

Спасибо за ваше предложение, и я делаю небольшой тест в соответствии с вашими ответами.

Что касается скорости, возможно, Base.rand все же лучше, хотя его временные затраты колеблются от 1.3e-7 до 1.4e-7 , Но для элегантного способа могут быть sample и shuffle.

Правильно ли сделан мой вывод?

using Base
using Random
using StatsBase

function _sampling1(M::Int64, N::Int64)
    for i in 1:M
        for j in 1:N
            r1, r2, r3 = Base.rand(1:N, 3)
            while (r1 == r2) | (r2 == r3) | (r1 == r3)
                r2, r3 = Base.rand(1:N, 2)
            end
        end
    end
end

function _sampling2(M::Int64, N::Int64)
    for i in 1:M
        for j in 1:N
            r1, r2, r3 = Random.shuffle(1:N)[1:3]
        end
    end
end

function _sampling3(M::Int64, N::Int64)
    for i in 1:M
        for j in 1:N
            r1, r2, r3 = StatsBase.sample(1:N, 3, replace=false)
        end
    end
end

M = 500
N = 100

time_cost1 = @elapsed _sampling1(M, N)
time_cost2 = @elapsed _sampling2(M, N)
time_cost3 = @elapsed _sampling3(M, N)

println("   rand: $(time_cost1 / (M * N))")
println("shuffle: $(time_cost2 / (M * N))")
println(" sample: $(time_cost3 / (M * N))")

#>>>    rand: 1.3713026e-7
#>>> shuffle: 1.57786382e-6
#>>>  sample: 5.6382496e-7

Ответы [ 2 ]

4 голосов
/ 19 января 2020
# thanks for @Bogumił Kamiński for hint that the `sample`
# function actually is from `StatsBase` package

# install `StatsBase` package or `Distributions` package
using Pkg
Pkg.add("StatsBase") # or: Pkg.add("Distributions")

# load it
using StatsBase # or: using Distributions


# the actual code for sampling 3 or 2 elements without replacement
sample(your_array, 3, replace = false) # 3 elements
sample(your_array, 2, replace = false) # 2 elements
2 голосов
/ 19 января 2020

Вместо специальной функции shuffle из библиотеки вы можете использовать перемешивание. Например, перемешайте массив индексов и выберите первые 5 из них:

using Random

random_indices = shuffle(eachindex(your_array))
your_array[random_indices[1:5]]

Перемешивание Фишера-Йейтса имеет линейную сложность; в некоторых случаях это имеет преимущества перед многократным вызовом sample (с точки зрения практичности или ресурсов).

Вместо индексов вы также можете напрямую перетасовывать массив (что, вероятно, наиболее удобно для кэша). Наиболее эффективный способ использования памяти - использовать один раз shuffle! на месте (например, для перекрестной проверки или пакетирования больших наборов данных).

...