Разница между массивом nx1 и массивом n-элементов в Julia
в Julia если я определяю массив с 1 столбцом и n строками, он, похоже, создает экземпляр "массива n-элементов", я не понимаю, чем это отличается от массива nx1:
julia> a = [1 2 3]
1x3 Array{Int64,2}:
1 2 3
julia> b = [1;2;3]
3-element Array{Int64,1}:
1
2
3
смущенно, если я возьму транспонирование дважды массива n-элементов, возвращаемый результат будет массивом nx1:
julia> transpose(transpose(b))
3x1 Array{Int64,2}:
1
2
3
это приводит к неожиданному (для меня) поведению, например:
julia> size(b) == size(transpose(transpose(b)))
false
мои вопросы:
- в чем разница между массивом nx1 и массивом n-элементов?
- как я могу создать
nx1
массив, не делая что-то вроде примера двойной транспонирования, который я дал.
1 ответов
быстрый ответ:
- An
n
x1 или 1xn
array-это 2-мерная матрица (которая имеет только одну строку или столбец), в то время как ваш N-элементный массив является 1-мерным вектором столбцов. - Я думаю, что самый простой способ создать
n
X1 array literal принимает транспонирование вектора строки:[1 2 3]'
. Идя в другую сторону, вы можете сгладить любой n-мерный массив до 1-d вектора, используяvec
.
гораздо поучительнее, однако, подумать о том, почему это имеет значение. Система типов Julia разработана полностью на основе типы, а не ценности. Размерность массива включается в сведения о его типе, а количество строк и столбцов-нет. Таким образом, разница между матрицей nx1 и вектором n-элемента заключается в том, что они имеют разные типы... и механизм вывода типов не может видеть что матрица имеет только один столбец.
чтобы получить лучшую производительность от Julia, вы (и особенно дизайнеры основного языка и библиотеки) хотите написать функции, которые тип стабильный. То есть функции должны иметь возможность выводить, какой тип они вернут, исключительно на основе типов аргументов. Это позволяет компилятору следовать вашим переменным через функции, не теряя след типа... который, в свою очередь, позволяет ему генерировать очень высоко оптимизированный код для этого конкретного типа.
теперь подумайте о транспозиции снова. Если вы хотите стабильную функцию транспонирования типа, она должна возвращать по крайней мере двумерный массив. Он просто не может сделать что-то сложное, если один из размеров равен 1 и все еще поддерживает хорошую производительность.
все это говорит о том, что все еще много дискуссий о векторных транспозициях как в списках рассылки, так и в вопросах GitHub. Вот отличное место для начала:вопрос #2686: ones(3) != ones(3)''
. Или для более глубокого обсуждения смежных вопросов:выпуск #3262: встраивание тензорных объектов в качестве многомерных объектов с конечными одноэлементными размерами. Оба в конце концов были вытеснены и свернуты в вопрос #4774: принимая вектор транспонирует серьезно.
обновление для Julia 0.6: Юля теперь очень серьезно относится к переносу вектора! Вектор transpose теперь возвращает специальный RowVector
тип действует как 1-строчная матрица, но с дополнительным знанием, что существует ровно одна строка. Это также ленивый "вид" в исходный вектор. С примерами в вопросе это означает, что не только size(b) == size(transpose(transpose(b)))
верно, но и b'' === b
.
также немного проще указать операции изменения формы, которые изменяют размерность в Julia 0.6. Хороший ответ на вопрос 2 выше (создание nx1
array) с reshape([1,2,3], :, 1)
. Измерение, заданное параметром :
вычисляется для соответствия длина исходного массива.