Распаковка возврата карты в Юлии - PullRequest
5 голосов
/ 05 апреля 2020

У меня есть функция, которая возвращает массив. Я хотел бы отобразить функцию на вектор входных данных, а выходные данные - простую конкатенацию всех массивов. Функция:

function log_it(r, bzero = 0.25, N = 400)
    main = rand(Float16, (N+150));
    main[1] = bzero;
    for i in 2:N+150
        main[i] = *(r, main[i-1], (1-main[i-1]))
    end;
    y = unique(main[(N+1):(N+150)]);
    r_vec = repeat([r], size(y)[1]);
    hcat(r_vec, y)
end;

, и я могу отобразить это нормально:

map(log_it, 2.4:0.001:2.405)

, но результат будет брутто:

 [2.4 0.58349609375]
 [2.401 0.58349609375]
 [2.402 0.583984375; 2.402 0.58349609375]
 [2.403 0.583984375]
 [2.404 0.583984375]
 [2.405 0.58447265625; 2.405 0.583984375]

NB, длина Вложенные массивы не ограничены - я ищу решение, которое не зависит от знания длины вложенных массивов заранее.

То, что я хочу, выглядит примерно так:

 2.4    0.583496
 2.401  0.583496
 2.402  0.583984
 2.402  0.583496
 2.403  0.583984
 2.404  0.583984
 2.405  0.584473
 2.405  0.583984

Который я сделал, используя для l oop:

results = Array{Float64, 2}(undef, 0, 2)
    for i in 2.4:0.001:2.405
        results = cat(results, log_it(i), dims = 1)
    end
    results

Код работает нормально, но для l oop требуется примерно в четыре раза больше времени. Я также чувствую, что map - это верный способ сделать это, и я просто что-то упускаю - либо при выполнении map таким образом, чтобы он возвращал хороший вектор массивов, либо в некоторой мутации массива, которая будет «отменена». Я пробовал просматривать такие функции, как сгладить и собрать, но ничего не могу найти.

Большое спасибо заранее!

1 Ответ

6 голосов
/ 05 апреля 2020

Вы уверены, что тестируете это правильно? Особенно при очень быстрых операциях тестирование производительности может иногда быть сложным В качестве отправной точки я бы порекомендовал вам всегда включать любой код, который вы хотите сравнить, в функцию и использовать пакет BenchmarkTools , чтобы получить надежные тайминги.

Как правило, не должно быть снижения производительности при написании циклов в Julia, поэтому увеличение времени выполнения для oop в 3 раза по сравнению с map звучит подозрительно.

Вот что я получаю:

julia> using BenchmarkTools

julia> @btime map(log_it, 2.4:0.001:2.405)
121.426 μs (73 allocations: 14.50 KiB)

julia> function with_loop()
           results = Array{Float64, 2}(undef, 0, 2)
           for i in 2.4:0.001:2.405
               results = cat(results, log_it(i), dims = 1)
           end
          results
       end

julia> @btime with_loop()
173.492 μs (295 allocations: 23.67 KiB)

Так что l oop примерно на 50% медленнее, но это потому, что вы выделяете больше.

Когда вы ' Использование map обычно дает Джулии более выразительный способ выразить то, что вы делаете, используя широковещание . Это работает для любой пользовательской функции:

julia> @btime log_it.(2.4:0.001:2.405)
121.434 μs (73 allocations: 14.50 KiB)

Эквивалентно вашему выражению map. То, что вы ищете, я думаю, это просто способ сложить все полученные векторы - вы можете использовать vcat и сплаттинг для этого:

julia> @btime  vcat(log_it.(2.4:0.001:2.405)...)
122.837 μs (77 allocations: 14.84 KiB)

и просто подтвердить:

julia> vcat(log_it.(2.4:0.001:2.405)...) == with_loop()
true

Таким образом, использование широковещания и объединения дает тот же результат, что и ваш l oop, при скорости и стоимости памяти вашего map решения.

...