Aplicaciones de Data Mining en Ciencia y Tecnología Trabajo Práctico 1. Aplicaciones en astronomía: Las Hyades Un cluster abierto de estrellas es un grupo de estrellas que se originaron a partir de la misma nube molecular y que actualmente conservan interacciones gravitatorias entre ellas, pero débiles. Los clusters abiertos pueden llegar a tener varios miles de estrellas, en general son jóvenes, menos de algunos cientos de millones de años, y en ellos todavía ocurren procesos de formación de estrellas. Debido a estas características, las estrellas de un cluster tienden a tener características químicas y edades similares. Las Hyades es un cluster abierto, el más cercano al Sistema Solar, se ubica a unos 151 años-luz, y probablemente por su cercanía es uno de los clusters abiertos mejor estudiados. Tiene unas 300 a 400 miembros, con un núcleo de 17,6 años luz de diámetro con estrellas cercanas entre sí, rodeada por otro grupo de estrellas más separadas entre sí que se extienden en una región de 130 años luz. Por fuera de este límite exterior se contaron cerca de un tercio de las estrellas de la Hyades, en un halo extendido, donde la atracción gravitatoria del cluster se debilita, lo que facilita el escape de sus miembros. VOStat, VOTable, VO El práctico que vamos a realizar está originalmente inspirado en un tutorial para demostrar las posibilidades de análisis de VOStat (http://vostat.caltech.edu/demos/hyades/). VOStat es un servicio e interfaz web para hacer análisis exploratorios y estadísticos de datos astronómicos. Diferentes instituciones crearon puntos de acceso a VOStat. El usuario carga sus datos como un archivo de valores separados por coma, o mejor, en formato VOTable, que es una implementación XML estándar para astronomía. Hay diferentes bases de datos y servicios astronómicos que tienen como opción de descarga el formato VOTable (.vot) , uno de los más interesantes es el proyecto VO (http://www.us-vo.org/) que es un portal desde donde se puede acceder con interfaces uniformes a un gran número de catálogos astronómicos y realizar consultas para recuperar, por ejemplo, mediciones hechas a distintos tiempos de un mismo punto del cielo en un rango de frecuencias del espectro electromagnético. (nota: cuando descarguen archivos .vot en máquinas corriendo Windows, puede suceder que el servidor responda con un error, muchas veces esto se corrige modificando los caracteres de fin de línea para que sea compatible con unix. Los sistemas linux/unix incluyen un programa para hacer esto por línea de comando, dos2unix. También hay versiones para Windows de este programa y opciones que lo hacen on-line y gratis, como http://www.dos2unix.org/) Objetivos de la parte 1 del trabajo práctico Vamos a hacer dos tareas relacionadas con las Hyades. La primera es agregar algunas estrellas a una lista restringida de estrellas de las Hyades y analizar los resultados. En Wikipedia hay una lista de miembros de las Hyades (http://en.wikipedia.org/wiki/List_of_stars_of_Hyades). Un objetivo complementario de esta práctica de laboratorio es repasar R y aprender algunos trucos nuevos. Procedimiento La lista de Wikipedia es incompleta, pero son miembros confirmados del cluster. Por otra parte tenemos una tabla obtenida por la misión Hipparcos y descargada desde el agregador de catálogos VizieR. Esta tabla contiene estrellas que se ubican en la misma región donde están las Hyades. hyadw.csv: el archivo de miembros confirmados de las Hyades preparado a partir de la tabla de Wikipedia. Hyades_vezier.csv: el archivo con estrellas relevadas por la misión Hipparcos en la región que ocupan las Hyades. Tarea opcional: los que quieran recuperar los mismos datos de VizieR, tiene que ir a la dirección del catálogo Hipparcos (http://vizier.u-strasbg.fr/cgibin/VizieR?-source=I/239/hip_main) y después, Fijar estos criterios de búsqueda en “Constraint” : RA (ICRS) 2 .. 6 10 DE (ICRS) 0 .. 31 Plx 18..34 (nota: estos valores son diferentes de los que figuran en el tutorial (The Hyades & surrounding stars, http://vostat.caltech.edu/demos/hyades/) Marcar para recuperar los campos: "recno", "HIP", "RAhms", "DEdms", "Vmag", "RA", "DE", "Plx", "pmRA", "pmDE", ,"B.V", "SpType". Finalmente en “output layout” seleccionar algún formato como “tab-separatedvalues”, “; separated values”, etc. 1. Cargar los dos archivos, hyadw.csv y hyadz.csv, en R. Antes conviene copiar los dos archivos en un subdirectorio apropiado y utilizar el comando setwd() para fijar el directorio de trabajo de R. > hyadw <- read.csv(file="hyadw.csv", header=T, colClasses="character", quote="\"") > head(hyadw) NAME Right.ascension Declination Spectral.type 1 HD 29789 04 h 41m 34.8451s -00° 44' 38.275 F2 2 HD 31622 04 h 57m 23.4780s +00° 59' 31.227 G5 3 HD 23261 03 h 43m 54.3405s +03° 26' 46.875 G5 4 BD+04° 568 03 h 40m 07.1925s +04° 37' 49.227 G0 5 HD 27935 04 h 24m 43.2257s +04° 41' 59.805 G5 6 HD 28069 04 h 25m 57.3388s +05° 09' 00.521 F5 Cuando R lee este archivo intenta convertir todas las variables a factores, para evitar esto usamos colClasses="character". La primera columna, NAME, es el nombre asignado a la estrella. Right.ascencion y Declination son coordenadas espaciales, en español se llaman ascensión recta y declinación; la primera es equivalente a las longitudes en las coordenadas terrestres, y la segunda a las latitudes terrestres. Para la ascensión recta, los 360° de la circunferencia de la esfera celesta se dividen en 24 horas. El rango de valores posibles para la declinación es el mismo que para las latitudes terrestres, de 90° a +90°. Spectral.type es el tipo espectral de la estrella y es un indicador de su temperatura y composición química. Hay que hacer algunas correcciones en este dataframe. 1.1 En la estrella “LP 16-620”, > hyadw[102,] NAME Right.ascension Declination Spectral.type 102 LP 16-620 04 h 33m 37.9643s +16° 45 44'.979 G5 La declinación está mal formateada. El valor correcto es +16° 45' 44.979 > hyadw$Declination[102] <- "+16° 45' 44.979" 1.2. La estrella “BD+29°” tiene un error en la ascención recta > hyadw[188,] NAME Right.ascension Declination Spectral.type 188 BD+29° 5 03 h 02m 57 46.6735s +29° 39' 41.260 G5 > hyadw[188,]$Right.ascension <- "03 h 02m 46.6735s" 1.3. Eliminar el registro de la estrella “BD+16° 630” > hyadw[99,] NAME Right.ascension Declination Spectral.type 99 BD+16° 630 04 h 36m 00s +16° 32.5' > hyadw <- hyadw[-99,] 2. Leemos el archivo con los datos descargados de VizieR > hyadz <- read.csv(file="Hyades_vezier.csv", header=T, quote="\"") > head(hyadz) 1 2 3 4 5 6 recno 9347 9457 9467 9481 9482 9486 HIP 9353 9463 9473 9487 9488 9492 02 02 02 02 02 02 00 01 01 02 02 02 RAhms 09.02 47.83 52.40 02.80 03.37 07.17 +03 +13 +07 +02 +03 +22 DEdms Vmag RA DE 05 51.5 5.89 30.04 3.10 01 28.2 10.16 30.45 13.02 51 52.2 7.06 30.47 7.86 45 49.5 3.82 30.51 2.76 56 27.9 10.48 30.51 3.94 06 15.2 7.21 30.53 22.10 Plx pmRA pmDE B.V SpType 32.18 231.21 -255.20 0.61 G2IV 24.83 -128.28 -146.27 1.19 K7V: 21.43 121.23 -49.33 0.51 F2 23.45 33.29 -0.42 0.02 A2 25.12 -338.69 -325.39 1.25 K7V: 18.56 8.18 -51.16 0.50 F8V recno y HIP son identificadores, Rahms, DEdms, RA y DE son la ascensión recta y la declinación, en el primer par como una secuencia de caracteres y en el segundo se indican los grados y las horas y los minutos y segundos como partes decimales. Plx es parallax en inglés y paralaje en español, es una medida de la distancia de las estrellas al sistema solar. Cuanto mayor es el paralaje, menor es la distancia. pmRA y pmDE indica los valores de movimientos propios ( “proper motion”en inglés), que representan el movimiento de la estrella con respecto al Sol. Vmag es la magnitud de la estrella medida y B.V es el índice de color B-V, ambas mediciones en el sistema fotométrico UBV de Johnson. Hacemos algunas modificaciones en los nombres y tipo de los datos para que sean parecidos a los de hyadw: > hyadz$SpType <- as.character(hyadz$SpType) > names(hyadw) <- c("name", "Right.ascension", "Declination", "SpType") 3. Necesitamos comparar los objetos de los dos dataframes, hyadw y hyadz. Tenemos dos problemas, el primero es que las posiciones en ascensión recta y declinación no son exactamente las mismas para los dos conjuntos de datos. Esto puede deberse a errores de medición en una y otra fuente de datos. Podemos comparar por cercanía en el espacio las estrellas de uno y otro grupo. Para esto es conveniente tener las coordenadas almacenadas en una variable numérica, como ocurre en hyadz$RA y hyadz$DE. El segundo problema es que hyadw no tiene las coordenadas expresadas de esta forma. Comencemos por agregar dos variables con los valores numéricos de ascensión recta y declinación al hyadw. Primero creamos una variable temporaria a, en la que eliminamos los símbolos de grados, minuto y segundos de la declinación. > a <- gsub('[°\']' , '', hyadw$Declination) La función de R gsub() utiliza expresiones regulares para las búsquedas. '[°\']' representa el patrón de búsqueda formado por el símbolo grado o el apóstrofe de minutos y segundos. A continuación creamos una función para convertir los grados, minutos y segundos a grados y fracción decimal de segundos: dec_car2num <- function(dec_car) { numvec <- as.array(3) dec_num <- as.array(length(dec_car)) for(i in 1:length(dec_car)) { numvec <- as.numeric(unlist(strsplit(dec_car[i], " " ))) dec_num[i] <- numvec[1] + numvec [2]/60 + numvec [3]/60^2 if(substr(dec_car[i],1,1)== "-" & numvec[1]==0) dec_num[i] <- dec_num[i]*-1 } return(dec_num) } Ahora hacemos lo mismo para la ascensión recta. b <- hyadw$Right.ascension b <- gsub("[hms]", "", b) b <- gsub("\\s{2}", " ", b) # eliminamos los símbolos h, m y s # reemplazamos dobles espacios en blanco por uno ra_car2num <- function(ra_car) { numvec <- as.array(3) ra_num <- as.array(length(ra_car)) for(i in 1:length(ra_car)) { numvec <- as.numeric(unlist(strsplit(ra_car[i], " " ))) ra_num[i] <- numvec[1]*15 + numvec [2]*15/60 + numvec [3]*15/60^2 } return(ra_num) } Para completar este paso: a <- dec_car2num(a) b <- ra_car2num(b) hyadw <- data.frame(hyadw, "RA"=b, "DE"=a) 4. Ya tenemos las coordenadas de las estrellas, ahora tenemos que determinar las correspondencias entre los objetos de los dos dataframes. Para lograr esto vamos a calcular la distancia euclídea entre las estrellas de hyadw y cada una de las de hyadz y almacenaremos las distancias mínimas. Luego analizaremos las distancias mínimas para determinar un umbral que nos indique cuando la diferencia entre distancias en uno y otro dataframe se debe sólo a un error de medición entre entradas para la misma estrella en los dos dataframes. distv <- array(dim=dim(hyadz)[1]) mins <- array(dim=c(dim(hyadw)[1],3)) names <- array(dim=dim(hyadw)[1]) # el vector de las distancias # una matriz con IDs y distancias # el nombre de la estrella for (i in 1:dim(hyadw)[1]) { for (j in 1:dim(hyadz)[1]) { distv[j] <- dist(rbind(hyadw[i, c(5,6)], hyadz[j, c(6,7)])) # cálculo de la distancia a partir de RA y DE } mins[i,1] <- i mins[i,2] <- min(distv)[1] # el [1] después min(distv) hay que agregarlo porque puede haber más # de una distancia mínima mins[i,3] <- hyadz[which(min(distv)==distv)[1],2] # el paso anterior es para determinar el identificador HIP # que dio el valor mínimo names[i] <- hyadw[i,1] } TODO: Tarda mucho con solo hacer la combinacion de los dos dataset que son bastante chicos. mins <- data.frame(mins, names) names(mins)[1:3] <- c("hyadw_n", "dist", "hyadz_HIP") head(mins) hyadw_n dist hyadz_HIP names 1 1 3.747856527 21092 HD 29789 2 2 0.585776289 23105 HD 31622 3 3 2.534025329 17888 HD 23261 4 4 3.202967448 17936 BD+04° 568 5 5 0.546426914 20693 HD 27935 6 6 0.001097913 20693 HD 28069 Veamos la distribución acumulada de los errores: > plot(ecdf(mins$dist), pch="") Y haciendo zoom sobre la parte más cercana a cero… > plot(ecdf(mins$dist), pch="", xlim=c(0,0.01)) > mins[order(mins$dist),] Vemos que cerca de 0,007 hay un cambio en el patrón de las distancias, por lo que ponemos nuestro punto de corte ahí. > mins2 <- mins[mins$dist<0.007,] Observar esto: 182 183 182 0.0021650892 183 0.0038245097 24019 24019 V* V1156 Tau CCDM J05098+28°02BC Puede ser que haya dos estrellas muy cercanas en la tabla compilada de miembros de las Hyades, pero en el relevamiento Hipparcos se detectó sólo una ¿Con cuál nos quedamos? > hyadz[hyadz$HIP==24019,] recno HIP RAhms DEdms Vmag RA DE Plx pmRA pmDE B.V SpType 387 24002 24019 05 09 45.06 +28 01 50.2 5.93 77.44 28.03 18.28 55.86 -60.57 0.31 A5m > hyadw[hyadw$name=="V* V1156 Tau",] name right.ascencion declination SpType RA DE 183 V* V1156 Tau 05h 09m 45.0923s +28° 01' 49.660 A5m 77.43788 28.03046 > hyadw[hyadw$name=="CCDM J05098+28°02BC",] name right.ascencion declination SpType RA DE 184 CCDM J05098+28°02BC 05h 09m 45.5061s +28° 02' 01.696 G7 77.43961 28.03380 La estrella con el identificador HIP 24019 parece estar un poco más cerca de "V* V1156 Tau" y además tiene una magnitud similar. Entonces nos quedamos con ésta: > mins2 <- mins2[mins2$names!="CCDM J05098+28°02BC",] ¿Habrá otro caso similar? La duplicación anterior era fácil de ver porque apareció justo al final de la tabla. Para ver si hay otros duplicados podemos hacer: > table(mins2$hyadz_HIP)[table(mins2$hyadz_HIP) > 1] 19261 2 Sucede lo mismo con la estrella HIP 19261, buscamos cuáles son las correspondientes estrellas en hyadw. > mins2[mins2$hyadz_HIP==19261,] hyadw_n dist hyadz_HIP names 57 57 0.004662828 19261 BD+14° 657B 58 58 0.005663395 19261 NSV 1466 > hyadz[hyadz$HIP==19261,] recno HIP RAhms DEdms Vmag RA DE Plx pmRA pmDE B.V SpType 177 19244 19261 04 07 41.91 +15 09 46.2 6.02 61.92 15.16 21.27 127.06 -22.75 0.4 F3V > hyadw[hyadw$name=="BD+14° 657B",] name right.ascencion declination SpType RA DE 57 BD+14° 657B 04 h 07m 41.809s +15° 09' 43.26 G7 61.9242 15.16202 > hyadw[hyadw$name=="NSV 1466",] name right.ascencion declination SpType RA DE 58 NSV 1466 04 h 07m 41.9831s +15° 09' 46.037 F3V 61.92493 15.16279 En este caso, NSV 1466 está un poco más lejos de HIP 19261, pero comparte su mismo tipo espectral, por lo que preferimos quedarnos con esta: > mins2 <- mins2[mins2$names!="BD+14° 657B",] Utilizando mins2 podemos determinar un grupo de estrellas que fueron confirmadas como miembros de las Hyades, les podemos asignar el nombre y las otras variables extraídas de Vezier: Creamos un nuevo dataframe para recopilar la información que obtuvimos al emparejar hyadw y hyadz. hyades <-data.frame(hyadz, "name"="", "SpType_wk"="", stringsAsFactors =FALSE) for (i in 1:dim(hyades)[1]) { if (hyades$HIP[i] %in% mins2$hyadz_HIP) { ind <- which(mins2$hyadz_HIP == hyades$HIP[i]) hyades$name[i] <- mins2$names[ind] hyades$SpType_wk[i] <- hyadw[hyadw$name==mins2$names[ind],4] } } El loop anterior recorre el dataframe hyades, a cada paso verifica si la estrella está incluida en mins2, el dataframe que lista todos los objetos de hyadz y hyadw que se determinó que eran son los mismos por el criterio de distancia. Si la condición anterior es verdadera, en el hyades$name se carga el nombre de la estrella y en hyades$SpType_wk el valor de magnitud registrado en la lista de Wikipedia. Terminamos la primera etapa! Ya tenemos un dataframe con todas las estrellas de la región de las Hyades y el nombre para aquellos miembros confirmados del cluster. ¿Estás perdido? Si tuviste algún problema con alguno de los pasos anteriores y no querés atrasarte, está disponible un archivo hyades.csv para continuar con el trabajo, que incluye además algunas de las variables que vamos a agregar en el paso posterior. Algo de análisis Creamos una variable lógica indicando cuáles son los miembros confirmados y luego hacemos algunos boxplots. > hyades$name != "" -> truehyades > > > > > > > boxplot(hyades$B.V ~ truehyades) boxplot(hyades$Vmag ~ truehyades) boxplot(hyades$Plx ~ truehyades) boxplot(hyades$pmRA ~ truehyades) boxplot(hyades$pmDE ~ truehyades) boxplot(hyades$RA ~ truehyades) boxplot(hyades$DE ~ truehyades) ¿Qué se puede decir de las características de las estrellas confirmadas con respecto al conjunto de estrellas? ¿Será posible agregar estrellas de la región analizada a la lista de estrellas que pertenecen al cluster? Para responder esto y, eventualmente, enriquecer nuestra lista de miembros de las Hyades, vamos a hacer un análisis de agrupamientos con los datos de posición, movimiento propio, distancia al sistema solar y características espectrales. Si muchos miembros de las Hyades se concentraran en uno o dos grupos, podríamos considerar que las otras estrellas de esos grupos también deberían pertenecer a las Hyades. > kfactors <- c(5:11) > kdata <- hyades[complete.cases(hyades[,kfactors]), c(2,13,kfactors)] > head(kdata) HIP name Vmag RA DE Plx pmRA pmDE B.V 1 9353 5.89 30.04 3.10 32.18 231.21 -255.20 0.61 2 9463 10.16 30.45 13.02 24.83 -128.28 -146.27 1.19 3 9473 7.06 30.47 7.86 21.43 121.23 -49.33 0.51 4 9487 5 9488 6 9492 3.82 30.51 2.76 23.45 33.29 -0.42 0.02 10.48 30.51 3.94 25.12 -338.69 -325.39 1.25 7.21 30.53 22.10 18.56 8.18 -51.16 0.50 kanalysis <- kmeans(kdata[,-c(1,2)], 6) d<-dist(kdata[,-c(1,2)]) library(fpc) kanalysis2 <- pam(kdata[,-c(1,2)], 6) cluster.stats(d, kanalysis$cluster) ¿Qué se puede decir del gráfico de las salidas de k-medias? > plot(kdata[,-c(1,2)], col=kanalysis$cluster) Agregamos los datos de los clusters a kdata. > kdata <- data.frame(kdata, "cluster"=kanalysis$cluster) ¿Las estrellas de las Hyades tienden a agruparse en algún cluster? > kdata[order(kdata$cluster),] En este análsis en particular, la mayoría de las Hyades están en el cluster 3. Seleccionemos esas estrellas: kdata[kdata$name=="" & kdata$cluster==3,] dim(kdata[kdata$name=="" & kdata$cluster==3,]) [1] 118 nuevas <- kdata$HIP[kdata$name=="" & kdata$cluster==3] Y lo registramos también en el dataframe hyades. > hyades <- data.frame(hyades, "agregadas"=FALSE) for (i in 1:length(nuevas)) { hyades[hyades$HIP==nuevas[i],15] <- TRUE } ¿Qué se puede decir sobre las características de las Hyades con respecto al conjunto de estrellas de la región a partir de los gráficos de más abajo (u otros similares)? > > > > x <- hyades$Vmag[hyades$name!="" | hyades$agregadas] y <- hyades$B.V[hyades$name!="" | hyades$agregadas] plot(hyades$Vmag,hyades$B.V, col="blue", pch=19) points(x,y, col="red", pch=19) > > > > x <- hyades$RA[hyades$name!="" | hyades$agregadas] y <- hyades$DE[hyades$name!="" | hyades$agregadas] plot(hyades$RA,hyades$DE, col="blue", pch=19) points(x,y, col="red", pch=19) x <- hyades$pmRA[hyades$name!="" | hyades$agregadas] y <- hyades$pmDE[hyades$name!="" | hyades$agregadas] plot(hyades$pmRA,hyades$pmDE, col="blue", pch=19) points(x,y, col="red", pch=19) Consideraciones finales Existen listas más exhaustivas de miembros de las Hyades que la publicada en Wikipedia. Hubiera sido mejor trabajar con una de esas listas, pero de esta forma nos resultó más fácil identificar nuevos miembros. Podríamos haber buscado otros catálogos o cruzar la información de Hipparcos con otras fuentes para confirmar los nombres de las estrellas, en lugar de calcular las distancias entre las posiciones de dos relevamientos distintos, pero el objetivo de esta parte del práctico era practicar algunos conceptos de R, y por otra parte, el acondicionamiento de datos con cierto grado de incertidumbre es una tarea habitual en data mining. Nuestro paso de “enriquecimiento” de estrellas tiende a agregar estrellas que se parecen al núcleo de miembros de las Hyades más similares entre sí. Puede haber otras, que con nuestro método se escaparían. Para los agrupamientos por k-medias podríamos haber agregado las magnitudes en otras bandas del espectro electromagnético o utilizar esas mediciones para validar nuestros agrupamientos.