4 Matrices

El álgebra lineal ocupa un lugar fundamental en el conjunto de herramientas que manejamos los economistas. En Julia, las matrices no son otra cosa que Arreglos (Arrays) homogéneos (que contienen sólo números) en dos dimensiones. Específicamente:

  • Una matriz es un arreglo bidireccional que contiene números reales o complejos. Una matriz de dimensión \(n m\) tiene \(n\) filas y \(m\) columnas.
  • Escalares representados por arreglos en una dimensión.
  • Vectores fila y vectores columna están representados por arreglos en dos dimensiones con \(1 m\) y \(n 1\), respectivamente.

Existen dos formas de definir matrices: usando el teclado y/o leyendo archivos externos (de texto, Excel, etc).

  • Usando el teclado: Toda matriz se inicia y termina con [ ], las columnas están separadas por espacios y filas por punto y coma.
  • Leyendo archivos externos: Se usan los comandos dlmread. Más adelante veremos detalles.
# Cargamos el paquete de herramientas de álgebra lineal de Julia (viene en la instalación base)
using LinearAlgebra
A = [1.0 2.0 3.0; 4.0 5.0 6.0; 7.0 8.0 9.0]
3×3 Array{Float64,2}:
 1.0  2.0  3.0
 4.0  5.0  6.0
 7.0  8.0  9.0
B = [1.0 2.0 3.0; 4.0 5.0 6.0]
2×3 Array{Float64,2}:
 1.0  2.0  3.0
 4.0  5.0  6.0
C = [1.0; 2.0; 3.0]  # Note que este es un arreglo en una dimensión 
3-element Array{Float64,1}:
 1.0
 2.0
 3.0
C = [1.0 2.0 3.0]' # Vector columna 3 x 1
3×1 Adjoint{Float64,Array{Float64,2}}:
 1.0
 2.0
 3.0
D = [1.0 4.0 3.0] # Vector fila 1 x 3
1×3 Array{Float64,2}:
 1.0  4.0  3.0

Para determinar el tamaño de una matriz utilizamos la función size():

filas, cols = size(A)
(3, 3)

4.1 Secuencias

Es posible crear arreglos unidimensionales a partir de secuencias con valores equidistantes unos de otros.

  • Forma 1: inicio:incremento:fin (incremento por defecto = 1). La secuencia termina en el número más cercano al número final definido. En Julia las secuencias son iterables son un tipo de objeto denominado iterable. Para convertir este objeto en un Arreglo se usa el comando collect.
  • Forma 2: range(inicio; tamaño, fin, incremento=1) crea también in iterable con una secuencia de números. Si tamaño e incremento son provistos el último número es calculado automáticamente. Si fin e incrementos son provistos, el tamaño es calculado automáticamente. Finalmente, si tamaño y fin son provistos el incremento será calculado automáticamente. De nuevo, collect se usa par transformar este objeto iterable en un Arreglo.

Adicionalmente, existe la posibilidad de crear secuencias con número espaciados logarítmicamente.

  • Forma 3: exp10.(range(inicio; tamaño, fin, incremento=1)) crea un vector de numero elementos en el intervalo \([10^{inicio},10^{fin}]\) espaciados logarítmicamente. Todas las opciones de range() aplican en este caso.
H0 = 1:10
1:10
H0 = collect(1:10)
10-element Array{Int64,1}:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
H1 = collect(1:0.6:3)
4-element Array{Float64,1}:
 1.0
 1.6
 2.2
 2.8
o = collect(10:-2:2)
5-element Array{Int64,1}:
 10
  8
  6
  4
  2
H2 = range(1,stop=4,step = 0.1)
1.0:0.1:4.0
H2 = collect(range(1,stop=8,length = 10))
10-element Array{Float64,1}:
 1.0               
 1.7777777777777777
 2.5555555555555554
 3.3333333333333335
 4.111111111111111 
 4.888888888888889 
 5.666666666666667 
 6.444444444444445 
 7.222222222222222 
 8.0               
H3 = collect(exp10.(range(1,stop=3,length=3)))
3-element Array{Float64,1}:
   10.0
  100.0
 1000.0

4.2 Matrices Especiales

Julia tiene funciones especialmente diseñadas para construir cierto tipo de matrices:

  • Matrices de ceros: zeros(nfilas,ncolumnas)
  • Matrices de unos: ones(nfilas,ncolumnas)
  • Matriz identidad: eye(dimesion)
  • Matrices con números aleatorios: rand(nfilas,ncolumnas) (uniforme [0,1]) y randn(nfilas,ncolumnas) (Normal estándar).
ME1 = zeros(3,2)
3×2 Array{Float64,2}:
 0.0  0.0
 0.0  0.0
 0.0  0.0
ME2 = ones(4,1)
4×1 Array{Float64,2}:
 1.0
 1.0
 1.0
 1.0
ME3 = Matrix{Float64}(I, 2, 2)
2×2 Array{Float64,2}:
 1.0  0.0
 0.0  1.0

Julia también tiene funcionalidad para crear matrices a partir de números aleatorios, esto usando las funciones rand(nfilas,ncolumnas) y randn(nfilas,ncolumnas) (el primero de una uniforme \([0,1]\) y el segundo de una Normal Estándar):

ME4 = rand(2,2)
2×2 Array{Float64,2}:
 0.20804    0.604411
 0.0871356  0.985899
ME5 = randn(3,1)
3×1 Array{Float64,2}:
 1.0342585936317028 
 0.28496500889049486
 0.7736579119015603 

Notas: - Para generar número aleatorios de una distribución Normal con media \(\) y desviación estándar \(\) usamos mu+sig*randn(nfilas,ncols). - Para generar número aleatorios de una distribución Uniforme definida en el intervalo \([a,b]\) usamos a+(b-a)*rand(nfilas,ncols).

Números aleatorios de una \(N(2,0.5^2)\) se obtienen:

xn = 2.0*ones(3,3) + 0.5*randn(3,3)
3×3 Array{Float64,2}:
 1.55053  1.98854  1.30453
 1.69637  1.93245  3.06781
 1.86568  1.49236  2.81504

Números aleatorios de una \(U(2,4)\) se obtienen:

xu = 2.0*ones(2,2) + (4-2)*rand(2,2)
2×2 Array{Float64,2}:
 2.00448  2.74206
 2.09066  2.50046

4.3 Operaciones con Matrices

El álgebra lineal define operaciones matriciales que Julia es capaz de realizar. Julia determina su uso is los arreglos califican como matrices (dos dimensiones). Todas las operaciones matriciales deben cumplir con los requerimiento de conformabilidad apropiados a la operación, caso contrario Julia indicara que existe un error. Note: Las operaciones con arreglos en una dimensión se realizan elemento por elemento.

  • Suma +
  • Sustracción -
A = [1 2 3; 4 5 6; 7 8 9];
B = [1 1 1; 2 2 2; 3 3 3];   

Nota: terminar una línea con ; suprime la impresión del resultado en pantalla.

S = A + B
3×3 Array{Int64,2}:
  2   3   4
  6   7   8
 10  11  12
R = A - B
3×3 Array{Int64,2}:
 0  1  2
 2  3  4
 4  5  6
  • Multiplicación *
  • Potencia ^
MM = A*B
3×3 Array{Int64,2}:
 14  14  14
 32  32  32
 50  50  50
P = A^2 # Idem P = A*A
3×3 Array{Int64,2}:
  30   36   42
  66   81   96
 102  126  150
  • Traspuesta ' o transpose()
  • Inversa inv(matriz)
  • División Izquierda ’' (\(A^{-1}B\))
  • División Derecha ‘/’ (\(B A^{-1}\))
C = rand(3,3)
3×3 Array{Float64,2}:
 0.0248423  0.280085  0.225705
 0.264967   0.293499  0.971384
 0.958973   0.414976  0.625647
Ctrans = transpose(C)
3×3 Transpose{Float64,Array{Float64,2}}:
 0.0248423  0.264967  0.958973
 0.280085   0.293499  0.414976
 0.225705   0.971384  0.625647
IV = inv(C)
3×3 Array{Float64,2}:
 -1.28864  -0.478949   1.2085  
  4.4961   -1.17959    0.209453
 -1.00697   1.51651   -0.392932
DI = C \ A    # Idem DI = inv(C)*A`
3×3 Array{Float64,2}:
 5.25507  4.69598  4.1369 
 1.24391  4.76988  8.29584
 2.30855  2.42516  2.54177
DI = inv(C)*A
3×3 Array{Float64,2}:
 5.25507  4.69598  4.1369 
 1.24391  4.76988  8.29584
 2.30855  2.42516  2.54177
  • Operaciones elemento por elemento usan un punto precediendo al operador: .*, .^, ./.
A = [1 2 3; 4 5 6; 7 8 9];
B = [1 1 1; 2 2 2; 3 3 3];  
Me = A.*B
3×3 Array{Int64,2}:
  1   2   3
  8  10  12
 21  24  27
Me = A./B
3×3 Array{Float64,2}:
 1.0      2.0      3.0
 2.0      2.5      3.0
 2.33333  2.66667  3.0
Pe = A.^2
3×3 Array{Int64,2}:
  1   4   9
 16  25  36
 49  64  81

4.4 Referenciación y Submatrices

Los elementos se una matriz se pueden referenciar de diversas formas:

  • Usando matriz[i,j] donde i es la fila y j es la columna.
A
3×3 Array{Int64,2}:
 1  2  3
 4  5  6
 7  8  9
a22 = A[2,2]
5
a31 = A[3,1]
7
  • Usando matriz[ii:if,ci:cf] para extraer más de un elemento. ii e if corresponden a la fila inicial y la fila final (lo mismo aplica a ci y cf para las columnas). Este método se usa para extraer submatrices o particionar.
subA1 = A[1:2,1:2]
2×2 Array{Int64,2}:
 1  2
 4  5
subA2 = A[2:3,1:3]
2×3 Array{Int64,2}:
 4  5  6
 7  8  9

Usar únicamente : indica toda la fila o columna según corresponda. El término end indica el último elemento.

subA3 = A[2,:]
3-element Array{Int64,1}:
 4
 5
 6
subA4 = A[:,2:3]
3×2 Array{Int64,2}:
 2  3
 5  6
 8  9
subA5 = A[2:end,3]
2-element Array{Int64,1}:
 6
 9
  • Note que al usar matriz(ii:if,ji:jf) no estamos haciendo otra cosa que definir un vector secuencia (iterable) dentro la matriz. Por tanto es válido usar vectores para referenciar elementos (en secuencia o no).
B=rand(4,6);
Ind = 1:4;
subB1 = B[Ind,5]
4-element Array{Float64,1}:
 0.5560264737076632
 0.5600729968972253
 0.6266873098922461
 0.1025504189478712
subB2 = B[1:4,5]
4-element Array{Float64,1}:
 0.5560264737076632
 0.5600729968972253
 0.6266873098922461
 0.1025504189478712
  • Podemos usar la misma lógica para elegir elementos que no son contiguos:
Indc = [1, 3, 4]
3-element Array{Int64,1}:
 1
 3
 4
Indf = [2, 4]
2-element Array{Int64,1}:
 2
 4
subB3 = B[Indf,Indc]
2×3 Array{Float64,2}:
 0.959789  0.416037  0.689965
 0.930512  0.753947  0.592671

4.5 Concatenar Matrices

Para concatenar matrices usamos los mismos procedimientos que para la definición de matrices usando el teclado, la única diferencia está en que los elementos son matrices.

  • La matriz se define en [].
  • Concatenar horizontalmente (espacio).
  • Concatenar verticalmente ;.

Nota: Ser cuidadoso con la conformabilidad de las matrices.

A = rand(3,2);
B = rand(2,2);

Concatenar verticalmente A y B:

C = [A ; B]
5×2 Array{Float64,2}:
 0.628677  0.210709
 0.834725  0.597568
 0.553228  0.358765
 0.981208  0.359241
 0.767161  0.913423

Concatenar horizontalmente la traspuesta de A con B:

D = [A' B]
2×5 Array{Float64,2}:
 0.628677  0.834725  0.553228  0.981208  0.359241
 0.210709  0.597568  0.358765  0.767161  0.913423

4.6 Arreglos de Mayor Dimensión

Julia es capaz de manipular matrices de mayor dimensión (ejemplo 3D). Todas las reglas de creación, referenciación, partición y concatenación aplican.

Nota: Sólo operaciones elemento por elemento son utilizables con arreglos de mayor dimensión.

A = rand(2,2,2)
2×2×2 Array{Float64,3}:
[:, :, 1] =
 0.901501  0.376398
 0.493339  0.568221

[:, :, 2] =
 0.728904  0.707847
 0.177334  0.236264

La referenciación a los elementos funciona de la misma forma. Por ejemplo, encontramos el elemento de la fila 2, columna 2, grupo (matriz) 1:

A[2,2,1]
0.5682212000427107