Acerca de… reemplazar valores en un vector en R

Hola.

Para sustituir elementos de un vector por otra cosa usamos

> replace()
> datos<-c("a1","a2","b1","b2","c1","c2","c3","a3","b3")
> datos
[1] "a1" "a2" "b1" "b2" "c1" "c2" "c3" "a3" "b3"
> replace(datos,datos=="c1"|datos=="c2"|datos=="c3","c")
[1] "a1" "a2" "b1" "b2" "c"  "c"  "c" "a3" "b3"

ojo, hay que asignar el resultado a algo, si no el resultado se queda en el limbo:

> datos.n<-replace(datos,datos=="c1"|datos=="c2"|datos=="c3","c")

Esto quiere decir: En el vector datos pon “c” en los lugares de datos que haya c1, c2 o c3.
Pero si datos fuera un factor…

> datos.f<-as.factor(datos)
> datos.f
[1] a1 a2 b1 b2 c1 c2 c3 a3 b3
Levels: a1 a2 a3 b1 b2 b3 c1 c2 c3

… y intentamos reemplazar por algo que no es uno de los niveles del factor nos hace perla.

> datos.n<-replace(datos.f,datos.f=="c1"|datos.f=="c2"|datos.f=="c3","c")
Mensajes de aviso perdidos
In `[<-.factor`(`*tmp*`, list, value = "c") :
invalid factor level, NAs generated

Lo que hay que hacer (lo que hago yo, mejor dicho) es convertir el factor en carácter o número o lo que sea  hacer el replace().

> datos.f<-as.character(datos.f)
> datos.n<-replace(datos.f,datos.f=="c1"|datos.f=="c2"|datos.f=="c3","c")
> datos.n
[1] "a1" "a2" "b1" "b2" "c"  "c"  "c"  "a3" "b3"

No olvidemos hacer el resultado factor de nuevo.

> datos.n<-as.factor(datos.n)

Recordad que los datos pueden ser vectores, filas o columnas de una matriz, filas o columnas de un dataframe, etc.

Pero qué pasa si queremos reemplazar por los valores de otro vector.

Supongamos que queremos reemplazar números por las letras del abecedario que hay en las posiciones que indican esos números (a-1, b-2, c-3, etc.)

Nuestros datos serian un vector de números

> datos<-c(1,2,5,7,3)
> datos
[1] 1 2 5 7 3

Y queremos que en cada numero R nos escriba la letra que está en esa posición en el abecedario.

Escribimos el abecedario

> abecedario<-c(letters)
> abecedario
[1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m"
[14] "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"

Asignamos nombres al vector del abecedario, pero ojo que sean character.

> names(abecedario)<-as.character(c(1:length(abecedario)))
> abecedario
1   2   3   4   5   6   7   8   9  10  11  12  13  14
"a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n"
15  16  17  18  19  20  21  22  23  24  25  26
"o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"

Hacemos un bucle.

> salida<-0
> for(x in 1:5) { salida[x]<-abecedario[names(abecedario)==datos[x]] }
> salida
[1] "a" "b" "e" "g" "c"

para cada valor de x (1-5) va a la posición x (1-5) del vector salida y le asigna el valor del vector abecedario cuyo nombre es igual al  valor del vector datos en la posición x.

Bueno, esto funciona, pero tengo un escozor en el cogote que me dice que podría ser mucho más sencillo.

Espero que os sea útil. Ya sabéis, las ideas, quejas y comentarios son bienvenidos.

jaume

Acerca de… Actualizar el R de RKward en Windows.

Hola,

He instalado RKward en Windows. De momento va bastante bien.

Podéis descargar un ejecutable aquí. Buscad en downoload y en windows instaler.

El problema que he encontrado es que no se como actualizar el R que viene con el RKward.

Lo que he hecho es instalar la última versión de R (para windows) en la carpeta que crea el RKward. Dentro de esa carpeta hay una subcarpeta llamada R y otra llamada KDE. Renombramos la carpeta del R como Rold y la carpeta de la nueva versión como R, así el Rkward irá a buscar a la carpeta de la nueva versión. Pero en esta nueva versión no están los paquetes que usa Rkward ni los que hemos instalado anteriormente. Lo que hay que hacer es copiar las subcarpetas de la carpeta lib de Rold a la carpeta lib de R llevándonos con nosotros todos los paquetes instalados anteriormente.

Bueno, parece que funciona.

Ya sabéis, sugerencias, ideas, quejas aquí abajo.

Acerca de… rkward.

Hola,

editado 27/10/2011: Mirad esta entrada.

Estoy empezando a utilizar una nueva interfaz gráfica para R en linux. Se llama RKward y va bastante mejor que JGR.

A pesar de ser para KDE va muy bien el Ubuntu, se instala directamente con el Añadir y Quitar de Ubuntu y no necesita un montón de librerias de KDE para funcionar. Además en su web en forma de wiki esta todo bastante bien explicado.

Puedes ver gráficamente lo que tienes en el Workspace,  tiene la opción de autocompletar con el tabulador, puedes buscar en la ayuda de forma gráfica, etc.

Una vista del RKward funcionando en Ubuntu.

Ya iré colgando cositas.

Saludos.

Acerca de… glm con datos trucados.

Siempre que he intentado entender la salida de un lm o un glm en el R me he encontrado con el mismo problema, como no conozco bien los datos, o son muy complicados, me queda la duda de si estaré interpretando bien lo que me dice el R.

Lo que hice el otro día, después de discutir con un compañero de trabajo que interpretaba las salidas de una forma diferente que yo, fue crear unos datos con los que sabía lo que iba a salir. Así por fin entendí del todo la salida del glm y me di cuenta de que interpretaba mal las salidas.

A continuación os pego lo que hice, primero como crear unos datos trucados, después una exploración con algunos gráficos y por fin los análisis.

Espero que os sea útil.

Creemos los datos trucados.

Creamos los datos de base aleatorios

origen<-rnorm(900,mean=0,sd=10)

es un vector de 900 elementos distribuidos como una normal de media 0 y desviación típica 10

Creamos los factores:

un vector de 900 elementos con 300 para cada nivel del factor

factorA<-c(rep(“controlA”,300)
,rep(“a1”,300)
,rep(“a2”,300)
)

y un vector de 900 elementos que divide cada nivel del factor anterior en 3 grupos de 100

factorB<-c(rep(
c(rep(“controlB”,100)
,rep(“b1”,100)
,rep(“b2”,100)
)
,3
)
)

Ahora los hacemos factores y arreglamos los niveles de base.

factorA<-as.factor(factorA)
factorA<-relevel(factorA,”controlA”)
#El control es el nivel base… así después en el análisis queda todo mejor
factorB<-as.factor(factorB)
factorB<-relevel(factorB,”controlB”)        #id

Hasta aquí tenemos la estructura típica de unos datos para analizar. Ahora hay que hacer el efecto de los factores sobre los datos.
Creamos los efectos
Modificación producida por cada nivel del factor… enseguida tendrá sentido.

controlA<-0
a1<-20
a2<-30
controlB<-0
b1<-6
b2<-12

Vector de los efectos, este vector modificará los datos origen.

efectosA<-c(rep(controlA,300),rep(a1,300),rep(a2,300))
efectosB<-c(rep(c(rep(controlB,100),rep(b1,100),rep(b2,100)),3))

Si os fijáis los valores están en la misma posición en que están los niveles de los factores.

Ahora creamos los datos definitivos, creamos los datos modificando el vector aleatorio con los efectos de los factores

datos<-origen + efectosA + efectosB

Si os fijáis lo que estamos haciendo aquí es coger una distribución normal y modificarla en función de unos factores que es lo que en realidad suponemos que está pasando cuando vamos a analizar unos datos haciendo un ANOVA.

si hubiera interacción, cuando se juntan el a1 y b2 el efecto se multiplicaría.

datos.int<-replace(datos,factorA==”a1″&factorB==”b2″,datos[factorA==”a1″&factorB==”b2″]*2)

Replace mola, lo que pone aarriba le dice al R: “en el vector datos, cuando el vector factorA es igual a a1 o el vector factorB es igual a b2, pon lo que haya pero multiplicado por 2”.

Y ya tenemos los datos trucados.
Con estos datos se puede jugar modificando los valores de ControlA, ControlB, a1, a2, b1 y b2.

Exploremos los datos trucados.

DATOS SIN INTERACCIÓN:

plot(datos~factorA)

plot(datos~factorB)

La diferencia entre los niveles de los factores es, aproximadamente, la que hemos dado al crear los datos.

Veamos las medias:

tapply(datos,list(factorA,factorB),mean)
controlB            b1                 b2
controlA   -0.9258813      6.894822     11.98925
a1           20.3019293      27.829253   31.74711
a2           29.1412938      36.630104   41.87341

Y un gráfico de interacción:

interaction.plot(factorA,factorB,datos,fun=mean)

Como veis es bastante soso, al pasar de un nivel a otro de A se incrementa su valor y lo mismo ocurre con B. Pero si probamos con los datos con interacción sale distinto.

DATOS CON INTERACCIÓN

plot(datos.int~factorA)
plot(datos.int~factorB)
interaction.plot(factorA,factorB,datos.int,fun=mean)

Fijaos en las dos primeras gráficas; Ha aumentado la variabilidad en los grupos en los que hemos hecho la interacción. Y en el gráfico de interacción ya está muy claro como la línea correspondiente a b2 se comporta de forma rara.

Análisis

Probemos con los datos sin interacción, por suerte los datos son normales, je je.
Primero hacemos (los puristas dirán ajustamos) el modelo.
modelo.glm<-glm(datos~factorA+factorB+factorA:factorB)
summary(modelo.glm)

Call:
glm(formula = datos ~ factorA + factorB + factorA:factorB)

Deviance Residuals:
Min        1Q    Median        3Q       Max
-33.4490   -6.7897   -0.3912    6.3939   34.0443

Coefficients:
Estimate       Std. Error     t value     Pr(>|t|)
(Intercept)               -0.3451     1.0159         -0.340     0.734
factorAa1                 19.9125     1.4367        13.860     < 2e-16 ***
factorAa2                 28.9171    1.4367         20.128     < 2e-16 ***
factorBb1                  8.0833     1.4367          5.626     2.46e-08 ***
factorBb2                 12.7213     1.4367         8.855      < 2e-16 ***
factorAa1:factorBb1   -1.2277     2.0317        -0.604      0.546
factorAa2:factorBb1   -0.8083     2.0317        -0.398      0.691
factorAa1:factorBb2    0.1649     2.0317         0.081      0.935
factorAa2:factorBb2    1.1961     2.0317         0.589      0.556

Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for gaussian family taken to be 103.1990)

Null deviance: 249869  on 899  degrees of freedom
Residual deviance:  91950  on 891  degrees of freedom
AIC: 6738

Number of Fisher Scoring iterations: 2

Después, hacemos el ANOVA.
anova(modelo.glm, test=”F”)

Analysis of Deviance Table

Model: gaussian, link: identity

Response: datos

Terms added sequentially (first to last)

Df    Deviance   Resid.Df   Resid. Dev        F Pr(>F)
NULL                                     899        249869
factorA             2   131624      897        118245           637.7182 <2e-16 ***
factorB             2     26171      895        92075            126.7971 <2e-16 ***
factorA:factorB  4        124      891        91950             0.3012 0.8772

Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Como se ve en el modelo ninguna de las interacciones entre los niveles de ambos factores es significativa, después el ANOVA nos lo enseña de otra forma.

Probemos con los datos con interacción.

Primero el modelo:
modelo.glm.int<-glm(datos.int~factorA+factorB+factorA:factorB)
summary(modelo.glm.int)

Call:
glm(formula = datos.int ~ factorA + factorB + factorA:factorB)

Deviance Residuals:
Min        1Q    Median        3Q       Max
-46.2969   -6.9360   -0.3912    6.7193   44.3720

Coefficients:
Estimate      Std. Error    t value   Pr(>|t|)
(Intercept)               -0.3451       1.1532         -0.299   0.765
factorAa1                 19.9125       1.6309        12.210   < 2e-16 ***
factorAa2                 28.9171       1.6309        17.731   < 2e-16 ***
factorBb1                  8.0833       1.6309        4.956     8.60e-07 ***
factorBb2                 12.7213       1.6309       7.800     1.72e-14 ***
factorAa1:factorBb1   -1.2277       2.3064       -0.532    0.595
factorAa2:factorBb1   -0.8083       2.3064       -0.350    0.726
factorAa1:factorBb2  32.6186       2.3064      14.143    < 2e-16 ***
factorAa2:factorBb2    1.1961       2.3064        0.519    0.604

Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for gaussian family taken to be 132.9891)

Null deviance: 432750  on 899  degrees of freedom
Residual deviance: 118493  on 891  degrees of freedom
AIC: 6966.3

Number of Fisher Scoring iterations: 2

Después el ANOVA:

anova(modelo.glm.int, test=”F”)

Analysis of Deviance Table

Model: gaussian, link: identity

Response: datos.int

Terms added sequentially (first to last)

Df    Deviance   Resid. Df    Resid. Dev       F           Pr(>F)
NULL                                    899          432750
factorA              2      176817     897         255933            664.779   < 2.2e-16 ***
factorB              2      90566       895         165367            340.502   < 2.2e-16 ***
factorA:factorB   4      46874       891         118493            88.116     < 2.2e-16 ***

Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Como se puede ver, ahora el resumen del modelo – summary() –  nos da como significativa la interacción entre a1 y b2, justo los datos que son diferentes entre datos y datos.int. Además en el ANOVA también sale significativa la interacción.

También está aquí.

Ahora habría que ver qué pasa si modificamos para 2 niveles de dos factores, pero eso para otro día.

Saludos.

Acerca de… letras y ubunutu

Hola,

Dos cositas interesantes.

Llamar a las letras griegas por su nombre.

La verdad es que es una cosa que nunca he sabido y cada profesor decía una cosa diferente. Aquí podéis encontrar una entrada en un blog sobre el tema. Es un señor que se ve que ha vivido en Atenas y se ha molestado en escribirnos los nombres adecuados de las letras griegas.

Así que vayamos ovidándonos de llamar a esto μ “mu” por que se dice mi. Y nada de Chi cuadrado, sino Ji cuadrado.

Después de instalar Ubuntu.

Echadle un ojo a esta entrada. Este señor se ha apuntado todo lo que hay que hacer después de instalar Ubuntu. Muy útil.

Solo le falta una cosa, instalar y actualizar el R, jeje, eso se puede ver aquí.

Saludos.

P.D.: Ya está corregido el enlace a la web de lo que hay que hacer después de instalar Ubuntu. Gracias Eloi.