matlab - ¿Cómo pueden conservarse todas las dimensiones que quedan después de la especificada, sin enumerarlas explícitamente?
numpy (2)
Enfoque 1: usar una lista separada por comas con '':''
No conozco una manera de especificar
:
tantas veces como sea necesario
conservando la forma. Pero puedes especificar
:
un número arbitrario de veces
donde ese número de veces se define en tiempo de ejecución . Con este método puede conservar la forma, siempre que el número de índices coincida con el número de dimensiones.
Esto se hace usando una lista separada por comas generada a partir de una matriz de celdas y aprovechando el hecho de que la cadena '':''
se puede usar como un índice en lugar de :
function y = fun(x)
colons = repmat({'':''}, 1, ndims(x)-1); % row cell array containing the string '':''
% repeated the required number of times
y = x(1,colons{:}).*x(2,colons{:}) + x(3,colons{:});
Este enfoque se puede generalizar fácilmente para indexar a lo largo de cualquier dimensión , no solo la primera:
function y = fun(x, dim)
% Input argument dim is the dimension along which to index
colons_pre = repmat({'':''}, 1, dim-1);
colons_post = repmat({'':''}, 1, ndims(x)-dim);
y = x(colons_pre{:}, 1, colons_post{:}) ...
.*x(colons_pre{:}, 2, colons_post{:}) ...
+ x(colons_pre{:}, 3, colons_post{:});
Enfoque 2: dividir la matriz
Puede dividir la matriz a lo largo de la primera dimensión usando num2cell
, y luego aplicar la operación a las subarrays resultantes. Por supuesto esto usa más memoria; y como lo señaló @Adriaan es más lento.
function y = fun(x)
xs = num2cell(x, [2:ndims(x)]); % x split along the first dimension
y = xs{1}.*xs{2} + xs{3};
O, para indexar a lo largo de cualquier dimensión :
function y = fun(x, dim)
xs = num2cell(x, [1:dim-1 dim+1:ndims(x)]); % x split along dimension dim
y = xs{1}.*xs{2} + xs{3};
O, de manera equivalente, "cuál es el equivalente de los índices de puntos suspensivos de NumPy en Matlab"
Digamos que tengo una matriz de alta dimensión:
x = zeros(3, 4, 5, 6);
Quiero escribir una función que tome una matriz de tamaño (3, ...)
y realice algunos cálculos. En NumPy, podría escribir esto:
def fun(x):
return x[0]*x[1] + x[2]
Sin embargo, el equivalente en MATLAB no funciona, porque la indexación con un entero alisa la matriz a 1d
function y = fun_bad(x)
y = x(1)*x(2) + x(3)
Puedo hacer este trabajo para arreglos de hasta 3 dimensiones con
function y = fun_ok3d(x)
y = x(1,:,:)*x(2,:,:) + x(3,:,:)
Si quiero que esto funcione para arrays de hasta 10 dimensiones, puedo escribir
function y = fun_ok10d(x)
y = x(1,:,:,:,:,:,:,:,:,:)*x(2,:,:,:,:,:,:,:,:,:) + x(3,:,:,:,:,:,:,:,:,:)
¿Cómo puedo evitar escribir números estúpidos de dos puntos aquí y hacer que esto funcione para cualquier dimensión? ¿Hay alguna sintaxis x(1,...)
que implique esto?
NumPy puede usar el literal ...
( Ellipsis
) en una expresión de indexación para significar " :
tantas veces como sea necesario" , lo que resolvería este problema.
MATLAB aplana todas las dimensiones finales cuando se usa un solo punto, de modo que puede usar eso para obtener de su matriz N- D a una matriz 2D, que puede volver a reshape
en las dimensiones N originales después del cálculo.
A lo largo de la primera dimensión
Si desea utilizar la primera dimensión, puede utilizar un código relativamente simple y corto:
function y = MyMultiDimensional(x)
x_size = size(x); % Get input size
yflat = x(1,:) .* x(2,:) + x(3,:); % Calculate "flattened" 2D function
y = reshape(yflat, [1 x_size(2:end)]); % Reshape output back to original size
end
A lo largo de una dimensión arbitraria, ahora con permute ND.
Cuando quiere que su función actúe a lo largo de la n -ésima dimensión de un total de N , puede permute
esa cota al frente primero:
function y = MyMultiDimensional(x,n)
x_size = size(x); % Get input size
Order = 1:numel(x_size);
Order(n)=[]; % Remove n-th dimension
Order2 = [n, Order]; % Prepend n-th dimension
xPermuted = permute(x,Order2); % permute the n-th dimension to the front
yTmp = xPermuted (1,:) .* xPermuted (2,:) + xPermuted (3,:); % Calculate "flattened" 2D function
y = reshape(yTmp, x_size(Order)); % Reshape output back to original size
end
Programé los resultados de los dos métodos de Luis y mis métodos:
function timeMultiDim()
x = rand(1e1,1e1,1e1,1e1,1e1,1e1,1e1,1e1);
function y = Luis1(x)
colons = repmat({'':''}, 1, ndims(x)-1); % row cell array containing the string '':''
% repeated the required number of times
y = x(1,colons{:}).*x(2,colons{:}) + x(3,colons{:});
end
function y = Luis2(x)
xs = num2cell(x, [2:ndims(x)]); % x split along the first dimension
y = xs{1}.*xs{2} + xs{3};
end
function y = Adriaan(x)
x_size = size(x); % Get input size
yflat = x(1,:) .* x(2,:) + x(3,:); % Calculate "flattened" 2D function
y = reshape(yflat, [1 x_size(2:end)]); % Reshape output back to original size
end
n=1;
function y = Adriaan2(x,n)
x_size = size(x); % Get input size
Order = 1:numel(x_size);
Order(n)=[]; % Remove n-th dimension
Order2 = [n, Order]; % Prepend n-th dimension
xPermuted = permute(x,Order2); % permute the n-th dimension to the front
yTmp = xPermuted (1,:) .* xPermuted (2,:) + xPermuted (3,:); % Calculate "flattened" 2D function
y = reshape(yTmp, x_size(Order)); % Reshape output back to original size
end
t1 = timeit(@() Luis1(x));
t2 = timeit(@() Luis2(x));
t3 = timeit(@() Adriaan(x));
t4 = timeit(@() Adriaan2(x,n));
format long g;
fprintf(''Luis 1: %f seconds/n'', t1);
fprintf(''Luis 2: %f seconds/n'', t2);
fprintf(''Adriaan 1: %f seconds/n'', t3);
fprintf(''Adriaan 2: %f seconds/n'', t4);
end
Luis 1: 0.698139 seconds
Luis 2: 4.082378 seconds
Adriaan 1: 0.696034 seconds
Adriaan 2: 0.691597 seconds
Por lo tanto, ir a una celda es malo, lleva más de 5 veces más tiempo, reshape
y '':''
están apenas separados, por lo que eso se reduce a la preferencia.