martes, 27 de noviembre de 2012

R: Curvas de Respuesta Principal (PRC) 3. Significatividad de los ejes

Se nos quedó en el tintero en nuestros análisis PRC un tema algo ecabroso y complicado que es el análisis de la significatividad de los ejes. El test de Monte Carlo para el primer eje no tiene problema en vegan con la función anova.cca:

## Significación primer eje

anova(mod, strata = week, perm.max = 499, first = T)
## Permutation test for rda under reduced model
## Permutations stratified within 'week'
## 
## Model: prc(response = pyrifos, treatment = dose, time = week)
##          Df   Var    F N.Perm Pr(>F)   
## RDA1      1  25.3 15.1    199  0.005 **
## Residual 77 129.0                      
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

En la última versión de vegan (2.0-5) se introdujo la modificación adecuada en esta función para que se pudiera utilizar el parámetro by con la opción “axis” con un objeto proveniente de de la función prc. Supuestamente con este parámetro la función realiza los test de Monte Carlo para todos los ejes extrayendo los scores de cada eje y utilizándolos como covariables para el siguiente en cada paso, tal como debe hacerse para garantizar la independencia de cada uno de ellos:

anova(mod, strata = week, perm.max = 499, by = "axis")
## Model: rda(formula = pyrifos ~ dose * week + Condition(week))
##          Df   Var     F N.Perm Pr(>F)   
## RDA1      1  25.3 15.10    199  0.005 **
## RDA2      1   8.3  4.95    199  0.005 **
## RDA3      1   6.0  3.61    199  0.005 **
## RDA4      1   4.8  2.85    199  0.005 **
## RDA5      1   4.1  2.48    199  0.005 **
## RDA6      1   3.9  2.30    199  0.005 **
## RDA7      1   3.6  2.14    199  0.010 **
## RDA8      1   3.3  1.99    199  0.005 **
## RDA9      1   3.1  1.84    299  0.017 * 
## RDA10     1   2.6  1.52    499  0.048 * 
## RDA11     1   2.5  1.47    499  0.066 . 
## RDA12     1   2.2  1.32    199  0.115   
## RDA13     1   2.1  1.27     99  0.130   
## RDA14     1   1.9  1.16     99  0.340   
## RDA15     1   1.8  1.07     99  0.430   
## RDA16     1   1.6  0.97     99  0.570   
## RDA17     1   1.6  0.94     99  0.590   
## RDA18     1   1.4  0.86     99  0.730   
## RDA19     1   1.4  0.83     99  0.700   
## RDA20     1   1.3  0.77     99  0.810   
## RDA21     1   1.2  0.72     99  0.870   
## RDA22     1   1.1  0.68     99  0.940   
## RDA23     1   1.0  0.60     99  0.980   
## RDA24     1   0.9  0.55     99  1.000   
## RDA25     1   0.9  0.51     99  1.000   
## RDA26     1   0.8  0.47     99  0.980   
## RDA27     1   0.7  0.45     99  1.000   
## RDA28     1   0.7  0.43     99  1.000   
## RDA29     1   0.7  0.41     99  1.000   
## RDA30     1   0.6  0.36     99  1.000   
## RDA31     1   0.6  0.35     99  1.000   
## RDA32     1   0.5  0.32     99  1.000   
## RDA33     1   0.5  0.31     99  1.000   
## RDA34     1   0.4  0.26     99  1.000   
## RDA35     1   0.4  0.25     99  1.000   
## RDA36     1   0.4  0.24     99  1.000   
## RDA37     1   0.4  0.22     99  1.000   
## RDA38     1   0.3  0.20     99  1.000   
## RDA39     1   0.3  0.20     99  1.000   
## RDA40     1   0.3  0.18     99  1.000   
## RDA41     1   0.3  0.17     99  1.000   
## RDA42     1   0.3  0.16     99  1.000   
## RDA43     1   0.2  0.12     99  1.000   
## RDA44     1   0.2  0.11     99  1.000   
## Residual 77 129.0                       
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Sin embargo, ya adelanto que los resultados de estos análisis no son correctos. Esto lo he comprobado con resultados obtenidos con CANOCO de otra serie de datos propios. El caso es que la función en vegan parece no tomar las puntuaciones adecuadas de cada eje. He dejado esta cuestión en la página de del foro de vegan por si se tratara de un bug.

A la espera de conocer qué está pasando realmente con el parámetro by de la función anova.cca, tenemos una solución alternativa para comprobar la significatividad de los ejes de nuestra PRC subsiguientes al primero. Lo primero es saber que una PRC no es más que una RDA de la forma rda (species ~ Treatment * Year + Condition (Year)). Lo segundo que necesitamos saber es dónde están las puntuaciones de los puntos de muestreo que son combinaciones lineales de las variables ambientales y que son las que tenemos que utilizar como covariables en el análisis del siguiente eje (las SamE de CANOCO). El resultado de la PRC es un objeto cca.object y dichas puntuaciones se encuentran en cca.object$CCA$u. Así que solo tenemos que extraerlas y realizar un RDA añadiéndolas como covariable (argumento Condition). Por último, realizaremos el test de Monte Carlo para el primer eje de este análisis que correspondería a nuestro segundo eje de PRC.

## Significación segundo eje

SamE <- mod$CCA$u
SamE <- SamE[, 1]
secondaxis <- rda(pyrifos ~ dose * week + Condition(week) + Condition(SamE))
anova(secondaxis, strata = week, perm.max = 499, first = T)
## Permutation test for rda under reduced model
## Permutations stratified within 'week'
## 
## Model: rda(formula = pyrifos ~ dose * week + Condition(week) + Condition(SamE))
##          Df   Var    F N.Perm Pr(>F)
## RDA1      1   8.3 4.95     99    0.7
## Residual 77 129.0

He comprobado, ya dije, esto con datos propios porque carezco de los resultados del artículo de Ter Braak y van den Brink en el que están basados datos de pyrifos (solo aparecen en él las p y el porcentaje de varianza recogida por los ejes), y tanto los resultados de las F en vegan y CANOCO son similares y los eigenvalues de la prc y de la posterior rda coinciden.

Solo queda saber qué pasa con by=“axis”, porque sería bastante más cómodo hacerlo así.

Por último, como habréis comprobado el formato de las operaciones en R de este post se ve algo más vistoso. Lo he conseguido utilzando el paquete knitr y la interface gráfica RStudio. knitr le permite a uno elaborar mediante markdown informes en HTML a partir de operaciones con R, como véis, resaltando de forma diferente las órdenes en la línea de comandos y los resultados. Permite además incrustar las gráficas en el mismo documento, pero no lo tengo aún muy dominado. Por el momento, parece que el código HTML que genera es aceptado bastante bien por Blogger

jueves, 15 de noviembre de 2012

R: Curvas de Respuesta Principal (PRC) 2. Una gráfica elegante

En el pasado post hablábamos de cómo conseguir que los resultados de la función prc del paquete vegan se parecieran lo más posible a los obtenidos con CANOCO. A pesar de ello la gráfica que se obtiene directamente con la función plot queda bastante fea. Aparte del tema de colores, tamaños de fuentes y ausencia de puntos, el principal problema es la diferencia de rangos de los valores de las puntuaciones de las parcelas (observaciones, puntos de muestreo,etc.) y de las especies. De hecho, Lepš y Šmilauer utilizan un método gráfico en CANOCO que separa los ejes de ambos, de forma que pueden así tener dos escalas distintas, sin importar más que luego coincidan los dos ceros en la gráfica general.

Esta es la misma solución que propongo para obtener una gráfica más elegante y más sencilla de interpretar visualmente. Lo podemos conseguir haciendo la gráfica con plot por un lado sin dibujar las especies con el parámetro species, y haciendo una gráfica independiente para estas con linestack. Ambas gráficas tendremos que fusionarlas luego con alguna aplicación externa. Vamos a ello.

Lo primero es dejar la parte de las parcelas visualmente aceptable. Para ello necesitaremos establecer varias parámetros gráficos previos con par, después dibujarla sin la leyenda con plot y, por último, añadirle la leyenda con legend en la posición más adecuada.

library (vegan)
##Extraemos los parámetros gráficos por defecto para no perderlos
opar <- par (no.readonly=T)
##Establecemos los parámetros gráficos para que nos haga todo en negro,
##aumente un poco el tamaño de las fuentes y las líneas,suprima los
##márgenes exteriores,nos ponga márgenes adecuados para los títulos
##de los ejes y los números de las escalas, nos deje los números de
##las escalas a 0.5 y en el sentido de lectura y establecemos el
##tamaño de las marcas de escala
png ('PRC.sites2.png')
par (bty='l', col='black', cex=2, cex.axis=1, cex.lab=1.3, lwd=1.8,
     xaxs='i',yaxs='i', mar=c(3,3,1,4), mgp=c(2,0.5,0), omi=c(0,0,0,0), 
     adj=0.5, las=1, tcl= -0.3)
##Dibujamos el gráfico sin especies y sin leyenda, con líneas y puntos y
##con límites de escala adecuados
plot (mod, scaling=1, species=F, col='black',type='b',ylab=c('PRC'),
      pch=c(15,16,17,18,19), ylim=c(-1,1.8),xlim=c(-5,25),legpos=NA)
##Dibujamos la leyenda sin el nivel de control, cuidando que los
##caracteres de los puntos coincidan con los graficados
legend (0.05,0.2,legend=levels(dose)[-1],pch=c(15,16,17,18,19),
        ncol=2,cex=1.5)
dev.off()


Ahora toca dibujar el eje de las especies. Si recordáis, en el post anterior extrajimos del análisis las puntuaciones de las especies a un vector con el escalado adecuado. Por si acaso, aquí está otra vez, solo que sin multiplicar por la constante correspondiente a CANOCO:

##Extraemos las puntuaciones de las especies para el primer eje
##RDA (choices=1), multiplicadas por la constante (const) que
##utiliza CANOCO
scores.sps <- scores (mod, choices=1, scaling=1,
                      dis='sp')

Vamos a hacer la gráfica con un poco menos de especies para que no salga tan abigarrada, así que estableceremos con colSums un límite inferior de 250, en vez de 100 como en el ejemplo de la función prc. Vamos a dibujar el eje de las especies con la función linestack, a la cual hay que especificarle que nos tiene que dibujar el eje con el parámetro axis. Con los parámetros air y hoff vamos a hacer que los nombres de las especies se separen un poco entre ellos y del eje. Por último, con el parámetro at colocaremos el eje en el centro de la gráfica. Podéis poner en el vector names los nombres completos de las especies, pero eso ya os lo dejo a vosotros.

##Dibujo del eje de especies
png ('PRCsps.png', 240, 480, res=100)
linestack (scores.sps[logabu>250], labels=names[logabu>250], axis=T,
           air=1.3, hoff=6, at=-1, font=3)
dev.off()

Y ya solo tenemos que unir los dos gráficos en uno con algún programa externo. La función linestack tiene un parámetro, add, con el que añadir el eje al gráfico actual, pero si hacemos esto, por la diferencia de escalas, no nos quedará bien colocado respecto al 0 de la figura de las observaciones. Por eso es mejor hacer los dos gráficos independientemente y luego juntarlos con un programa externo. Yo lo he hecho con Libre Office Draw.

Y, en principio, ya está. Sugerencias y comentarios serán bienvenidos.

martes, 13 de noviembre de 2012

R: Curvas de Respuesta Principal (PRC) 1. El lío del escalado

Este post va a ser un poco más técnico y menos divulgativo, aviso. Son un poco mis apuntes de R, paquete estadístico libre con muchas ventajas pero difícil de utilizar para los que venimos de programas con interfaces gráficas. Estos posts de R espero que además sirvan de ayuda para aquellos que andan dándose de cabezazos con él.

Estoy trabajando con unos datos de campo para hacer unas curvas de respuesta principal (PRC). Existe un paquete para R desarrollado principalmente por Jari Oksanen llamado vegan. Tenía las PRC hechas antes con el programa se suele usar para estos casos: CANOCO. Sin embargo, los resultados con vegan diferían bastante de los que había obtenido con CANOCO.

El paquete vegan contiene una colección de datos denominada pyrifos para hacer prácticas con él. Curiosamente los datos de pyrifos son de un estudio de van den Brink y ter Braak1 en el que se analizan precisamente con PRC. Además, ter Braak ha participado en el desarrollo de la función prc del paquete vegan junto con Oksanen. Lo más gracioso es que haciendo el análisis con el código propuesto por el archivo de ayuda de la función prc se obtienen también resultados distintos a los que se exponen en el artículo.

Lo primero que hay que recordar para entender esta disparidad de resultados es que la PRC es un análisis multivariante en el que las escalas pueden ser muy arbitrarias porque lo que interesa son las distancias relativas entre los elementos en estudio (normalmente parcelas y especies). Jari Oksanen ha generado varios documentos respecto a su paquete vegan para aclarar ciertas dudas. Uno de ellos es Design decisions and implementation details in vegan. En él explica cuáles son las constantes que ha utilizado para hacer los escalados de especies y parcelas en los análisis de redundancias (RDA, las PRC son un caso especial de estas) comparándolos con las usadas en CANOCO. Además, hay que observar que el escalado se puede hacer centrado en especies o en parcelas y que la función prc nos da la opción de especificarlo con el parámetro scaling.

Veamos qué es lo que ocurre siguiendo el código propuesto por el archivo de ayuda de la función prc:

##Cargamos el paquete
library (vegan)
##Cargamos en el espacio de trabajo los datos
data(pyrifos)
##Generamos un factor con las semanas de aplicación del tratamiento
week <- gl(11, 12, labels=c(-4, -1, 0.1, 1, 2, 4, 8, 12, 15, 19, 24))
##Generamos otro factor con los tratamientos
dose <- factor(rep(c(0.1, 0, 0, 0.9, 0, 44, 6, 0.1, 44, 0.9, 0, 6), 11))
##Hacemos el análisis prc
mod <- prc(pyrifos, dose, week)
##Metemos en un vector la suma de los datos para cada especie
logabu <- colSums(pyrifos)
##Hacemos la gráfica solo con las especies cuya suma de datos sea superior
##a 100
png ('prc.man.png')
plot(mod, select = logabu > 100)
dev.off()





Vemos que no solo no encontramos las parcelas en la parte negativa del eje, sino que además el rango de la escala sobrepasa las 2 unidades cuando en la figura 3 del trabajo de van den Brink y ter Braak no sobrepasa el valor 1.80. También en el eje de especies vemos cómo la más alejada, caenhora (Caenis horaria), se encuentra por debajo del valor -3, cuando en la figura del artículo se encuentra por debajo del 5. Esto aparte de lo feo de la figura y la saturación del eje de especies. Y esta gráfica obtenida con R es la que se repite en multitud de sitios. Hay que poner un poco más de cuidado.

Lo primero que hemos de saber es que el escalado puede estar centrado en las especies o en las parcelas, unidades de muestreo o como lo queramos llamar. Esto lo especificábamos en CANOCO y también lo podemos especificar en R con el parámetro scaling. Los valores para este parámetro están perfectamente explicados en el archivo de ayuda de la función plot.cca. En el caso de la PRC y siguiendo el método descrito en Šmilauer y Lepš2, centramos por parcelas, así que scaling=1.

png ('prc.scale1.png')
plot(mod, select = logabu > 100, scaling=1)
dev.off()



Aún así, vemos que los resultados siguen si parecerse mucho a los del artículo, sobre todo en las especies si prestamos atención a la más alejada. Y es que, como explica Oksanen en Design decisions and implementation details in vegan, las puntuaciones de especies y parcelas se multiplican por una constante distinta en CANOCO y en vegan. Para obtener al menos los mismos valores absolutos en CANOCO y en vegan, tenemos que dar un rodeo algo más largo, porque plot.cca no permite especificar dicha constante, pero scores, sí. Vamos a hacerlo con las especies para comprobarlo. En CANOCO esta constante es la raiz cuadrada del número de especies.

##Extraemos las puntuaciones de las especies para el primer eje
##RDA (choices=1), multiplicadas por la constante (const) que
##utiliza CANOCO
scores.sps <- scores (mod, choices=1, scaling=1, const=sqrt(132), dis='sp')
##Extraemos solo los valores para las especies con más presencia,
##así como sus nombres
scores.sps.sel <- scores.sps [logabu>100]
names <- colnames (pyrifos)
names.sel <- names [logabu>100]
##Dibujamos el eje de las especies de la PRC
png ('spsCANOCO.png')
linestack (scores.sps.sel, axis=T, labels=names.sel)
dev.off()




Ahora, nuestra especie de referencia por ejemplo, caenhora, cae en la zona del eje que en valor absoluto más se asemeja a los resultados del artículo. Si además contáramos con las puntuaciones exactas de las especies en CANOCO, veríamos que coinciden con las obtenidas por scores con la constante establecida. Y lo mismo para las puntuaciones de cada combinación de semana y dosis, solo que aquí la constante es la raiz cuadrada del número de observaciones.

Quedaría por saber por qué narices en vegan obtenemos resultados con el signo cambiado, algo que no he podido entender y que espero que algún lector más avispado o entendido que yo u Oksanen mismo lo puedan explicar. Sin embargo, da un poco igual porque, como decíamos al principio, lo importante es la posición relativa de los objetos de estudio en el espacio, sea en la parte positiva o negativa del eje. Queda para un próximo post la solución que he encontrado para hacer el gráfico de las curvas un poco más elegante.

1Van den Brink, P. J. and Braak, C. J. F. T. (1999), Principal response curves: Analysis of time-dependent multivariate responses of biological community to stress. Environmental Toxicology and Chemistry, 18: 138–148.

2Jan Lepš, Petr Šmilauer. Multivariate Analysis of Ecological Data using CANOCO. Cambridge University Press 2003.

jueves, 8 de noviembre de 2012

Las semillas que no flotan pero sí navegan

La dispersión de las semillas de una planta es fundamental para que persista en el el lugar en el que vive o incluso en el tiempo y no se extinga. Los viajes de las semillas que produce una planta pueden llevarla a nuevos sitios que colonizar en los que, por ejemplo, haya menos competidores, o más agua, o más nutrientes,... Las semillas viajan para conquistar nuevos territorios por tierra, aire, a lomos de bestias de carga y... por agua.

Un reciente artículo publicado aún on-line en Journal of Vegetation Science explica cómo es el modo de viajar y asentarse de las semillas en un río japonés: Yoshikawa, M., Hoshino, Y., Iwata, N. (2012), Role of seed settleability and settling velocity in water for plant colonization of river gravel bars. Journal of Vegetation Science. doi: 10.1111/jvs.12001. Yoshikawa y colaboradores nos explican cómo en las bandas de grava de las orillas del río Tama se depositan capas de arena por la actividad humana después de cada subida, y con ellas aparecen especies de plantas que antes no estaban allí. Se preguntaron si las semillas de estas especies tienen una especial capacidad de flotación que las ayuden en su dispersión por las aguas del río. Sin embargo, lo que encontraron es que la mayoría no flotan tanto como lo esperado, sino que más bien, tienen una velocidad de decantación -es decir, la velocidad con la que llegan al fondo- similar a la de las partículas de arena. Es decir, que no flotan, sino que se van hundiendo lo suficientemente despacio como para que les dé tiempo a llegar a estas zonas que se ven inundadas con las crecidas del río.

Sabemos que la actividad humana aguas arriba de un río provoca efectos aguas abajo o en su desembocadura, donde se depositan más los materiales que lleva en suspensión al ralentizarse la velocidad del agua. En estas zonas de grava se instalan, como comentan los autores, especies de plantas xerofíticas, acostumbradas al ir y venir de las crecidas, las cuales están siendo desplazadas por estas especies cuyas semillas son capaces de navegar hundiéndose poco a poco con la arena que, presuntamente, ha aumentado por la actividad humana. Entender estos mecanismos por los que unas especies son capaces de colonizar y desplazar a otras es fundamental para hacer previsiones de los efectos de nuestra actividad alrededor de los ríos.