Создание вектора строки из среза матрицы - PullRequest
2 голосов
/ 28 апреля 2020

Мне было интересно, есть ли у кого-нибудь понятный способ вернуть вектор строки из фрагмента матрицы?

matrix[k,:]

на самом деле возвращает вектор размером (n,), поэтому Юлия автоматически рассматривает его как столбец вектор, а не вектор строки. До сих пор я использовал синтаксис

matrix[k,:]'

для представления вектора строки размером (1,n), но почему-то это кажется неуклюжим и совсем не интуитивным, поскольку это вектор строки, а не столбец вектор. Большинство математиков, с которыми я говорил, неверно полагают, что это не вектор строки.

Есть ли у Джулиани c способ получить срез вектора строки, который более понятен?

1 Ответ

4 голосов
/ 28 апреля 2020
julia> m=rand(1:10,3,4)
3×4 Array{Int64,2}:
 4  5  3  9
 6  8  1  5
 4  5  3  4

julia> m[[1],:]
1×4 Array{Int64,2}:
 4  5  3  9

Обратите внимание, что почти всегда лучше использовать view с, чтобы избежать копирования данных:

julia> @view m[[1],:]
1×4 view(::Array{Int64,2}, [1], :) with eltype Int64:
 4  5  3  9

Объяснение:

Можно выбрать Array элементов либо используя скаляры, либо используя итерации. Использование скаляра приводит к удалению данного измерения. С другой стороны, использование коллекции не отбрасывает измерение. Для лучшего объяснения рассмотрим еще один пример:

julia> m[1:1,1:1]
1×1 Array{Int64,2}:
 4

Вы можете видеть, что был выбран только один элемент, но размеры не были отброшены. Следовательно, в итоге вы получите Matrix (то есть 2-мерный Array), имеющий только одну строку и один столбец.

РЕДАКТИРОВАТЬ (комментарий Colin T Bowers - спасибо!)

Решение о том, использовать или нет представления, не является пустяком - в основном это то, выигрывает ли ваш код от буферизации. Однако на удивление часто view с лучше.

julia> const vals = rand(200,200);

julia> using BenchmarkTools

julia> @btime sum(view(vals,1,:))
  169.392 ns (1 allocation: 48 bytes)
95.08924081258299

julia> @btime sum(vals[1,:])
  184.384 ns (1 allocation: 1.77 KiB)
95.08924081258299

Давайте определим нашу собственную функцию суммирования.

julia> function mysum(a::AbstractVector{A}) where A <: Number
    v = zero(A)
    @inbounds @simd for i in 1:length(a)
        v += a[i]
    end
    v
end;

julia> @btime mysum(view(vals,1,:))
  141.931 ns (0 allocations: 0 bytes)
95.08924081258299

julia> @btime mysum(vals[1,:])
  174.934 ns (1 allocation: 1.77 KiB)
95.08924081258297

Хорошо видно, что при суммировании строки один раз view s все же лучше. Последнее, но не менее важное суммирование по столбцам, конечно, в несколько раз быстрее, и копирование данных обходится до чертиков:

julia> @btime sum(view(vals,:,1))
  25.828 ns (1 allocation: 48 bytes)
96.04440265541243

julia> @btime mysum(view(vals,:,1))
  13.927 ns (0 allocations: 0 bytes)
96.04440265541243

julia> @btime sum(vals[:,1])
  167.745 ns (1 allocation: 1.77 KiB)
96.04440265541243
...