Каково математическое объяснение добавления 2d Array и 1d Array? - PullRequest
6 голосов
/ 23 января 2020

Я не могу воспроизвести это numpy арифметика c. Я использую Джулию, но хочу узнать математическое объяснение этого кода. Кажется, это нарушает то, что я знаю о линейной алгебре.

X = np.arange(-5, 5, 0.2).reshape(-1, 1)

X.shape  ## (50, 1)

test = np.sum(X**2, 1).reshape(-1, 1) + np.sum(X**2, 1)

test.shape  ## (50, 50)

В Джулии я бы написал

X = reshape(collect(range(-5, stop=5, length=N)), :, 1);

size(X)  ## (50, 1)

test = sum(X.^2, dims=2) + vec(sum(X.^2, dims=2));

size(test) ## (50, 1)

Я пытаюсь представить, как матрица 50x50 будет результатом добавления двух векторов? Я знаю, что numpy использует много вещания под капотом, но мне не ясно, что это делает.

Что такое математическая запись или эквивалент Джулии для того, что numpy здесь делает?

1 Ответ

10 голосов
/ 23 января 2020

Вы делаете много вещей, которые действительно затеняют вашу точку зрения, которая, я полагаю, касается того, как добавлять массивы различных форм.

Python:

In [21]: x = np.random.rand(5, 1)                                               

In [22]: x.shape                                                                
Out[22]: (5, 1)

In [23]: y = np.random.rand(1, 4)                                               

In [24]: y.shape                                                                
Out[24]: (1, 4)

In [25]: (x + y).shape                                                          
Out[25]: (5, 4)

Юлия :

julia> x = rand(5);

julia> y = rand(1, 4);

julia> x + y
ERROR: DimensionMismatch("dimensions must match")

julia> x .+ y
5×4 Array{Float64,2}:
 1.95779  1.31897   1.23345   1.32423 
 1.78126  1.14244   1.05692   1.14771 
 1.08306  0.444243  0.35872   0.449509
 1.69756  1.05874   0.97322   1.06401 
 1.18661  0.547789  0.462265  0.553054

julia> size(x .+ y)
(5, 4)

Как вы можете сказать, Python передает массивы по умолчанию, в то время как Джулия требует, чтобы вы специально запросили ее, используя оператор точки, ..

It именно потому, что не имеет смысла добавлять два массива разных форм, которые Юлия не передает по умолчанию. Точно так же с умножением * и .* отличаются:

julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
 1  2
 3  4

julia> B = [4 5; 6 7]
2×2 Array{Int64,2}:
 4  5
 6  7

julia> A * B
2×2 Array{Int64,2}:
 16  19
 36  43

julia> A .* B
2×2 Array{Int64,2}:
  4  10
 18  28

Обычным * является умножение матрицы, в то время как последнее является умножением на массив элементов.

Другой пример:

julia> A = [1 2 3; 4 5 6]
2×3 Array{Int64,2}:
 1  2  3
 4  5  6

julia> b = [7, 8]
2-element Array{Int64,1}:
 7
 8

julia> A * b
ERROR: DimensionMismatch("matrix A has dimensions (2,3), vector B has length 2")

julia> A .* b
2×3 Array{Int64,2}:
  7  14  21
 32  40  48
...