Con frecuencia deberemos “cargar” datos almacenados en archivos externos para utilizarlos en cálculos o programas realizados en Matlab/Octave. En la sección “Descargas” de la web de la asignatura se encuentran accesibles una colección de archivos en formato .csv
con datos de diversas variables medidas durante una campaña oceanográfica. El formato .csv
(“comma separated values”) es un formato de texto estándar para el intercambio de datos. Cada fila de un archivo .csv
corresponde a los valores de distintas variables; dichos valores se encuentran separados por comas; el símbolo del separador decimal es el punto; y las variables tipo texto se recogen entre comillas (dobles o simples).
Prácticamente todos los programas para el tratamiento de hojas de cálculo (Excel, libreOffice Calc, …) son capaces de leer un archivo .csv
y mostrarlo como hoja de cálculo. A su vez, si hemos rellenado una hoja de cálculo con datos utilizando uno de estos programas es siempre posible exportar los datos a formato .csv
.
Los datos que vamos a utilizar como ejemplo han sido medidos con boyas ARGO. En concreto, los archivos temperatura.csv y salinidad.csv contienen valores de temperatura y salinidad obtenidos a 100 profundidades distintas, medidos en los 109 puntos de muestreo que se muestran en la figura al margen. Cada uno de estos archivos contiene 100 filas y 109 columnas. Cada columna corresponde a una posición longitud-latitud y cada fila corresponde a una profundidad. El archivo depth.csv contiene también 100 filas y 109 columnas que indican la profundidad a que se ha medido cada uno de los valores de temperatura y salinidad de los otros dos archivos. Los archivos latitud.csv y longitud.csv contienen, cada uno, 109 filas y una columna. La combinación de cada valor de longitud y latitud (de 1 a 109) especifica la localización de cada punto de muestreo. A su vez, el archivo time.csv tiene también 109 filas (un valor por fila) que especifican el momento en que la boya comenzó a tomar datos en cada punto.
Si abrimos, por ejemplo, el archivo temperatura.csv con LibreOffice (o Excel) veremos los datos de temperatura dispuestos como una hoja de cálculo:
Si abrimos el mismo archivo con el bloc de notas veremos que sus valores están simplemente separados por comas (el símbolo decimal es el punto):
Nótese que en algunos lugares aparece escrito NaN
. Esta expresión es un acrónimo de “Not a Number” indicando que en ese punto no se pudo medir la temperatura, y por tanto falta el valor numérico correspondiente. En tales casos es equivalente escribir NaN
en el archivo, o dejar la casilla en blanco. Escribir otra cosa daría lugar a errores de lectura del archivo.
csvread
Para leer estos archivos en Matlab en primer lugar hemos de colocarnos en la carpeta que los contiene. Supongamos que los archivos anteriores están en una carpeta llamada datos
, que a su vez está dentro de la carpeta c:\users\Mis documentos
. Nos colocamos en primer lugar en esta carpeta mediante:
Hemos puesto el nombre de la carpeta entre comillas porque la ruta contiene espacios en blanco; si no fuese así, podríamos introducir directamente la ruta sin comillas
>> cd "c:\users\Mis documentos"
(o bien nos situamos en ella utilizando el navegador que aparece a la izquierda en la pestaña “HOME” de la aplicación de matlab)
Ahora, para leer los datos contenidos en los archivos utilizamos la función csvread()
, asignando el contenido de cada archivo a una variable:
NOTA: Por ahora no hemos leido el archivo “datos/time.csv”. La razón es que ese archivo contiene la fecha y hora a la que se tomó cada una de las medidas que figuran en los demás archivos. Si abrimos este archivo con libreOffice o Excel podemos comprobar que el formato de fecha y hora es de la forma 2013-02-18 12:28:44. En esta codificación de fechas se usan los símbolos “-” y “:”, que son símbolos no numéricos, que no pueden ser leidos por la función csvread
>> T=csvread("datos/temperatura.csv");
S=csvread("datos/salinidad.csv");
lon=csvread("datos/longitud.csv");
lat=csvread("datos/latitud.csv");
z=csvread("datos/depth.csv");
De esta forma hemos creado las matrices T, S, lon, lat, y Z, que contienen los datos que se han leido desde los archivos csv originales. Podemos ver, por ejemplo, la dimensión (el tamaño) de la matriz T donde se han cargado los datos de temperatura:
>> size(T)
ans =
100 109
Como señalábamos más arriba, cada una de las 109 columnas de T corresponde a una localización de la boya en un día concreto, y cada fila corresponde a una profundidad. Así, por ejemplo, la columna 15 de la matriz T correspondería a las temperaturas medidas por la boya en la longitud:
>> lon(15)
ans = -38.484
y en la latitud:
>> lat(15)
ans = 25.154
Podemos combinar en una única matriz los datos de profundidad (z
) con los de temperatura (T
) en esa posición:
>> zt=[z(:,15),T(:,15)]
zt =
2.9000 23.2790
3.9000 23.2770
5.9000 23.2750
7.9000 23.2770
9.9000 23.2780
11.9000 23.2780
13.9000 23.2780
15.9000 23.2760
17.9000 23.2710
19.9000 23.2560
21.9000 23.2230
23.9000 23.2060
25.9000 23.2070
28.0000 23.2070
29.9000 23.2060
31.9000 23.2050
33.9000 23.2030
35.9000 23.2010
37.9000 23.1990
39.9000 23.1960
41.9000 23.1910
43.9000 23.1890
45.9000 23.1890
47.9000 23.1800
49.9000 23.1750
51.9000 23.1720
53.9000 23.1700
55.9000 23.1610
57.9000 23.1540
59.9000 23.1420
61.9000 23.1290
63.9000 23.1080
65.9000 23.0910
67.9000 23.0880
69.9000 23.0800
71.9000 23.0550
73.9000 23.0460
75.9000 23.0430
77.9000 23.0410
79.9000 23.0250
81.9000 23.0000
83.9000 22.9760
85.9000 22.9530
87.9000 22.9260
89.9000 22.9220
91.9000 22.9210
93.9000 22.9110
95.9000 22.9080
97.9000 22.9070
99.9000 22.9040
101.9000 22.8890
103.9000 22.8670
105.9000 22.7850
107.9000 22.7120
109.9000 22.6510
111.9000 22.5950
113.9000 22.5590
115.9000 22.5540
117.9000 22.5530
119.9000 22.5510
121.9000 22.5430
123.9000 22.5420
125.9000 22.5290
127.9000 22.4780
129.9000 22.3700
131.9000 22.3190
133.9000 22.2660
135.9000 22.1650
137.9000 22.0760
139.9000 22.0260
141.9000 21.9720
143.9000 21.8850
146.0000 21.8320
148.0000 21.7270
149.9000 21.4130
151.9000 21.1790
153.9000 20.9950
155.9000 20.9170
157.9000 20.7930
159.9000 20.7730
161.9000 20.7440
163.9000 20.6220
165.9000 20.4420
167.9000 20.2770
169.9000 20.4070
172.0000 20.2500
NaN NaN
NaN NaN
NaN NaN
NaN NaN
NaN NaN
NaN NaN
NaN NaN
NaN NaN
NaN NaN
NaN NaN
NaN NaN
NaN NaN
NaN NaN
NaN NaN
z
es la profundidad en metros y T
es la temperatura (en ºC) medida a esa profundidad; como podemos apreciar, a partir de 172 metros no hay datos disponibles. En matlab es sencillo hacer una representación gráfica de estos datos. El código siguiente representa la temperatura en el eje X y la profundidad en el eje Y (nótese que cambiamos el signo del vector z
, de forma que la profundidad se mida “hacia abajo”):
>> plot(T(:,15),-z(:,15))
xlabel("Temperatura")
ylabel("Profundidad")
En esta gráfica podemos apreciar claramente que a medida que aumenta la profundidad disminuye la temperatura.
Matlab ofrece también la posibilidad de dibujar mapas. Para ello es preciso descargar el Mapping Toolbox (paquete de aplicaciones para representación geográfica) y al menos un mapa base. La descarga de ambos componentes puede hacerse directamente desde la aplicación matlab (al menos a partir de la versión R2017b): dentro de la pestaña “HOME” pinchamos en Add-Ons -> Get Add-Ons y en el buscador de la ventana que aparece escribimos “basemap”. Para que funcione tenemos que estar conectados a internet, en cuyo caso el servidor de Mathworks nos presentará diversas aplicaciones y complementos, entre los que se encuentran el Mapping Toolbox y los mapas base que necesitamos. Basta pinchar en el nombre de la aplicación o mapa que queramos descargar para que matlab nos ofrezca la opción de descargar e instalar. Matlab tiene cinco mapas base (landcover, colorterrain, grayterrain, grayland y bluegreen). Podemos descargarlos los cinco (tarda bastante) o uno solo de ellos. El mapa que veremos a continuación usa como mapa base el landcover. Una vez descargados e instalados el Mapping Toolbox y el mapa base, la siguiente sintaxis dibuja los 109 puntos de muestreo (lat,lon) en los que la boya ha medido la temperatura y la salinidad a distintas profundidades:
>> geoscatter(lat, lon, 3, 'red')
geobasemap('landcover')
En la función geoscatter
hemos especificado los vectores lat
y lon
con las latitudes y longitudes respectivas de los puntos de muestreo. El valor 3 es simplemente el tamaño de cada punto, y 'red'
es el color que usamos para la representación. Por defecto matlab centra el mapa en la región en la que se observan los puntos.
Si queremos ampliar el mapa anterior para situar la región de muestreo y poder hacernos una mejor idea de donde se encuentra, podemos cambiar los límites de latitud y longitud con los que se ha trazado el mapa, de forma que se incluyan las islas Canarias y parte de la costa africana. Para ello basta ejecutar la linea siguiente a continuación de las anteriores.
>> geolimits([25,28],[-40,-10])
Observamos, pues, que los puntos de muestreo se encuentran al este y ligeramente al sur de las islas Canarias.
Como señalábamos más arriba, en los archivos de datos de temperatura y salinidad faltan valores que han sido sustituidos por el código de valor perdido NaN
. Estos valores pueden no haberse medido por fallos del sensor, por fallos de la batería de la boya o por cualquier otra causa. La presencia de valores perdidos en un conjunto de datos generalmente es causa de problemas. Si quisiéramos, por ejemplo, calcular la temperatura media en la columna de agua correspondiente al punto de muestreo número 15, podríamos utilizar la función mean
:
>> mean(T(:,15))
ans = NaN
pero, cotras omo vemos, la función nos devuelve NaN
(Not a Number). Ello se debe a que la presencia de valores perdidos en el conjunto de datos impide calcular la media directamente (como hay valores que no se conocen, matlab no puede calcular la media usando dichos valores). Esto ocurre con muchas funciones. Por ejemplo, si quisiéramos calcular la media sumando los valores y dividiendo por el número total de valores válidos (no perdidos) y aplicamos para ello la función sum
, obtenemos el mismo resultado que antes:
>> sum(T(:,15))
ans = NaN
Para poder calcular la media (o la suma) en presencia de valores perdidos, hay que utilizar funciones que ignoren dichos valores y calculen la media (o la suma) con los valores no perdidos. Las funciones nanmean
y nansum
hacen exactamente eso:
>> nanmean(T(:,15))
ans =
22.5908
>> nansum(T(:,15))
ans =
1.9428e+03
Si quisiéramos saber cuántos valores perdidos hay en el vector T(:,15)
podemos utilizar la función isnan()
. Esta función vale 1 para los valores perdidos y 0 en otro caso. Si, por ejemplo consideramos el vector:
>> v=[1 2 3 NaN 4 5 NaN];
al aplicar la función isnan()
obtenemos:
>> isnan(v)
ans =
0 0 0 1 0 0 1
es decir, un 1 donde había NaN
s y un 0 donde no había NaNs
. Por tanto, si queremos contar el número de valores perdidos en un vector, bastará con hacer:
>> sum(isnan(v))
ans = 2
y, análogamente, si queremos contar el número de valores no perdidos:
>> sum(~isnan(v))
ans = 5
Asimismo, si queremos seleccionar sólo aquellos valores de v
que no están perdidos, podemos ejecutar:
>> v(~isnan(v))
ans =
1 2 3 4 5
(podemos leer esta última expresión como que le estamos pidiendo a matlab: “muéstrame los valores de v
tales que no están perdidos”)
En el caso de nuestro vector de temperaturas T(:,15)
, el número de valores perdidos que contiene es:
>> sum(isnan(T(:,15)))
ans = 14
y el número de valores no perdidos:
>> sum(~isnan(T(:,15)))
ans = 86
Combinando todo lo anterior, si quisiéramos calcular la media de T(:,15)
sin utilizar las funciones nanmean()
ni nansum()
podemos utilizar la siguiente sintaxis:
>> Temp= T(:,15); % Valores de temperatura en el punto 15
noPerdidos=~isnan(Temp); % Vector que identifica los valores no perdidos
n=sum(noPerdidos); % Total de valores no perdidos
media=sum(Temp(noPerdidos))/n
media = 22.591
readtable
Para leer el archivo time.csv hemos de proceder de manera diferente. Si lo abrimos con LibreOffice o Excel vemos que su contenido son fechas y horas:
En particular, podemos observar que aparecen los símbolos “-” y “:” como separadores para marcar las fechas y las horas. La función csvread
es capaz de leer ficheros que contengan solamente números; si el archivo contiene algún otro símbolo como en este caso, matlab nos devuelve un error:
>> file=fopen("datos/time.csv")
time=csvread(file);
Error using dlmread (line 147)
Mismatch between file and format character vector.
Trouble reading 'Numeric' field from file (row number 1, field number 1) ==>
"2013-02-18 12:28:44"\n
Error in csvread (line 48)
m=dlmread(filename, ',', r, c);
Para leer archivos que contengan caracteres no numéricos podemos utilizar la función readtable
:
La función readtable se utiliza para leer archivos de texto que contienen caracteres no numéricos (fechas, palabras, etc)
>> fh=readtable("datos/time.csv");
Cuando se usa esta función, el objeto que se crea (fh
en nuestro caso) es un objeto de clase table
, que tiene algunas particularidades específicas de esta clase (en esencia una tabla en matlab es un contenedor con variables de distinta naturaleza ordenadas a modo de hoja de cálculo). Para convertir una tabla en una matriz estándar usamos la función table2array
:
>> FechaHora=table2array(fh);
Como ventaja adicional, la función table2array
identifica que la variable FechaHora que hemos creado es de clase datetime
, que es la clase específica que le permite a matlab manejar adecuadamente variables de fecha y hora. Si le pedimos a matlab que nos muestre los diez primeros valores de esta variable obtenemos la salida siguiente:
>> FechaHora(1:10)
ans =
10×1 datetime array
2013-02-18 12:28:44
2013-02-18 14:34:01
2013-02-18 16:59:21
2013-02-18 19:25:21
2013-02-18 21:54:55
2013-02-19 00:18:42
2013-02-19 02:23:02
2013-02-19 04:27:01
2013-02-19 06:36:58
2013-02-19 08:43:33
y en particular podemos comprobar que la fecha y hora a que se tomaron los datos en el punto 15 de muestreo fue:
>> FechaHora(15)
ans =
10×1 datetime array
2013-02-19 19:34:56
xlsread
El formato estándar de los archivos .csv
requiere que los valores estén separados por comas (,) y que el símbolo decimal sea el punto (.). Sin embargo es frecuente que en muchas regiones del planeta (en particular en España) se utilicen archivos .csv
en los que el separador decimal es la coma y el separador entre valores es el punto y coma (;). Numerosos programas para el tratamiento de datos (en particular los desarrollados como software libre) son capaces de leer los archivos csv en cualesquiera de sus configuraciones regionales. No ocurre así con Matlab, que no incluye ninguna opción para leer archivos .csv
que se aparten de la configuración estándar.
Dado que en España es muy habitual que incluso programas como excel generen los .csv
con la configuración regional española, para importar estos archivos en Matlab hay que hacer “encaje de bolillos” (pueden leerse varias soluciones aquí: https://stackoverflow.com/questions/29896457/read-csv-with-semicolon-separated-data-with-comma-as-decimal-mark-in-matlab): Por eso puede ser más sencillo importar directamente el archivo en formato excel. Para ello se utiliza el comando xlsread()
. Debe tenerse en cuenta, no obstante, que esta función solo lee los campos numéricos.