Mi blog personal sobre investigación y divulgación
Tag Archives: código
Identificar con MATLAB valores repetidos en un vector



En el contexto de muchos estudios que podamos estar haciendo con una serie de datos, un problema típico que no encontramos es el de necesitar identificar valores duplicados en un vector. Por ejemplo, puedes necesitar simplemente identificar un registro que por alguna razón se haya escrito dos veces en la base de datos.

Si trabajas con MATLAB seguramente sabrás que hay un comando para identificar valores únicos dentro de un vector (el comando unique), pero hasta donde yo sé no hay uno para identificar valores que están repetidos. Claro, la lógica nos dice que si podemos cuáles son únicos ya tenemos el problema resuelto, porque todos los demás aparecerán en el vector al menos dos veces. El problema es, por un lado, saber cuáles son esos valores y, por otro lado, logran conocer el índice que nos indica la posición de esos valores en el vector. Con esta información podríamos, por ejemplo, construir un nuevo vector que nos sirva de flag para solo marcar los valores repetidos.

Yo me encontré con este problema y lo primero que hice fue lo obvio…programar un loop donde se calculara la diferencia de un valor con el anterior, y si la diferencia era nula entonces ya tenía localizado un valor que se repetía. El problema es que en mi caso esa era una información muy limitada, porque los valores repetidos no tenían por qué aparecer uno después del otro en la base de datos.

Hay varias maneras (similares) de resolver esto, pero yo voy a mostrar aquí la que me resultó más sencilla. Supongamos que nuestro vector, que contiene algunos valores repetidos, es el que llamamos «vector».

Lo primero que hago es identificar los valores únicos (los que nunca se repiten) y sus posiciones en el vector:

[valores_unicos, ind_unicos] = unique(vector);

Luego identifico los índices que me marcan las posiciones de los valores que sí están repetidos. Para ello hago uso del comando setdiff:

ind_repetidos = setdiff(1:length(vector), ind_unicos);

Ahora extraemos los valores de esos registros repetidos:

valores_repetidos = vector(ind_repetidos, 1);

Pero claro, si quiero construir otro vector que me sirva de flag para indicar los datos repetidos, que aparecen dos o más veces, tengo que identificar dónde están esos valores todas las veces que se repitan. Esto puede parecer lioso, pero imagina que tenemos un vector que es [2 2 2 3 4 5]. Con lo anterior lo que hacemos es identificar que el valor repetido es 2 y que ese 2 aparece por primera vez en la posición 1 del vector. Yo lo que estoy buscando es tener un vector que sea [1 1 1 0 0 0], es decir, que me marque con un 1 todos los sitios donde aparezca un valor que aparezca al menos dos veces.

Para ello el siguiente paso es este, donde uso el comando ismember. Lo que hago es pedirle a MATLAB que busque en mi vector cuáles son los índices (posiciones en el vector) donde se encuentra cualquiera de los valores repetidos.

ind_flag=ismember(vector, valores_repetidos);

ind_flag es ya el vector que estamos buscando, el que nos indica con un 1 un valor que está repetido, y con un cero los valores únicos. Para conocer el número de datos repetidos simplemente buscamos en ind_flag todos los valores diferentes de cero (o mayores que cero, o iguales a 1, como prefieras).

numero_repetidos=length(find(ind_flag >0));

Si quieres grabar el vector ind_flag en un fichero de texto, por ejemplo para importarlo en MATLAB en otra sesión de trabajo, o para importarlo en una hoja de cálculo Excel o similar, podrías usar este código:

fid=fopen(‘flag.txt’,’wt’);
formato=’%d\n’;
for i=1:size(ind_flag,1);
fprintf(fid,formato,ind_flag(i,:));
end
fclose(fid)

Y con esto ya tienes el método, que puedes reducir a los cuatro primeros pasos, para identificar todos los valores que aparecen iguales más de una vez en un vector, e incluso crear un nuevo vector para identificar dónde están esos valores.

Libro recomendado (enlace afiliado):


Guardar una matriz formateada en un archivo de texto en MATLAB

Este post debería en realidad llamarse algo así como «Cómo guardar una matriz con formato en un archivo de texto con MATLAB, y no morir en el intento».

Es muy posible que si usas MATLAB y tienes un set de datos guardados en una matriz, quieras guardar esa matriz en un fichero de texto. Esto puede servirte para cargarlos en MATLAB posteriormente, o usarlos con otro programa como puede ser Excel. Hay muchas maneras de hacer esto, pero cuando queremos guardar cada columna con un determinado formato la cosa se complica un poco. Se complica porque hay que empezar a lidiar, por un lado, con la definición del formato y, por otro lado, con las formas aveces poco lógicas de trabajar en MATLAB. Que sí, que es un software fantástico, pero aveces tiene detalles y caprichos que dan ganas de tirar la toalla con él.

Una de las formas de guardar nuestra matriz de datos en MATLAB es usar el comando fprintf. Con pfrintf puedes especificar el formato con el que quieres escribir cada columna de la matriz (puede que una columna sea un número con 4 decimales, otra sea un número entero, otra sea una cadena de texto…). Las normas para aplicar el formato deseado son las que encontrarás aquí. El caso es que, una vez escrito el formato, podrías encontrarte con una desagradable sorpresa como me ha pasado a mí, y es que siguiendo el típico ejemplo que Mathworks escribe en web o en la ayuda de MATLAB, solo consigues escribir valores de la primera columna pero ordenados en filas hasta que se acaban y comienzan a escribirse valores de la segunda columna y así sucesivamente. Voy a poner un ejemplo para que se entienda mejor lo que quiero decir:

Supongamos que tenemos un set de datos que consta de 4 columnas con 4 filas. La primera columna es temperatura dada con un decimal, la segunda es año, la tercera es mes y la cuarta es día (en estas tres últimas columnas todos los valores son enteros). Entonces, nuestra definición de formato sería algo así: formato=’%5.2f %d %d %d\n’    Tenemos 4 filas, lo que quiere decir que lo que queremos guardar es un registro de cuatro medidas de temperatura con su correspondiente fecha. Podría ser algo así:

temperatura=[10.25; 40.36; 28.50; 3.32]

agno=[2003; 2003; 2003; 2003]

mes=[12; 12; 12; 12]

dia=[25; 25; 25; 25]

datos=[temperatura, agno, mes, dia]

Muy bien, pues es muy posible que para grabar este set en un fichero y con el formato que queremos probemos con esto:

formato=’%5.2f %d %d %d\n’

fid=fopen(‘ficherodatos.txt’,’w’);

fprintf(fid,formato,datos);

fclose(fid);

————–

La \n es para empezar a escribir en una nueva línea tras escribir los primeros valores de cada columna. %d es para escribir números enteros, y el %5.2f lo hemos puesto para escribir la temperatura con dos decimalos. El 5 en %5.2 significa que pueden haber 5 caracteres de texto en total, contando la parte entera, el punto y los dos decimales.

La desagradable sorpresa es que fichero de texto que se ha grabado tiene esta pinta:

Fichero de texto MATLAB

Como ves, ha escrito cuatro columnas pero con los valores de la temperatura primero, luego los años, luego mes y finalmente día, eso sí, con el formato que le pedimos. Pero no es el orden en el que queremos los datos!

La solución es escribir un pequeño código con un sencillo loop, como este:

fid=fopen(‘ficherodatos.txt’,‘wt’);

formato=’%5.2f %d %d %d\n’ ;

for i=1:size(datos,1);

    fprintf(fid,formato,datos(i,:));

end

fclose(fid)

Ahora sí, si abrimos el fichero de texto resultante nos encontramos con esto:

Archivo de texto MATLAB

Esto sí es justo lo que queríamos. En el código de arriba verás que en la instrucción fid he puesto ‘wt’ en vez del ‘w’ que teníamos al principio. Esto es para indicarle que queremos escribir en un fichero que es un fichero de texto y que debe adaptarse a las directrices seguidas por los ficheros de texto en el sistema operativo donde estés ejecutando este código. Esto puede interesarte o no. Lo que he hecho es comprobar cuáles son las dimensiones de la matriz datos y hacer un loop desde 1 hasta el número de datos en cada columna (esto es, el número de filas). Dentro del loop he ordenado a MATLAB que escriba las filas de la matriz datos, una a una, en el archivo ficherodatos.txt con el formato deseado.

Ahí queda este tip por si lo necesitas en algún momento. A mí además me sirve escribirlo aquí para no perder estos apuntes entre cientos de papeles. 🙂