En primer lugar, cargamos/instalmos las librerías que vamos a usar y leemos la base de datos en la variable “df”, nos quedamos solo con los datos completos, tiramos los niveles que no se usan, renombramos el identimicador de la encuesta de V3 a ID y exploramos las primeras líneas:
if (!require("pacman")) install.packages("pacman")
pacman::p_load("MASS","tidyverse","haven","stringr", "FactoMineR","factoextra","corrplot","gplots","ggrepel")
df <- read_sav("WV6_Data_Spain_2011_Spss_v20180912.sav") %>%
# select (V3,V39, V46, V218_ESMA, V217_ESMA, V219_ESMA, V220_ESMA, V221_ESMA, V222_ESMA, V223_ESMA) %>%
# rename(ID=V3) %>%
as_factor() %>%
filter(complete.cases(.)) %>%
droplevels()
df %>% head()
Es posible que nos interese simplificar ideologia en pocas categorias:
df2 = df %>% mutate(Ideol=as.numeric(Ideol)) %>%
mutate(Ideol=ifelse(Ideol<=5, 1,
ifelse(Ideol<=10, 2,
3))) %>%
mutate(CatLab=ifelse(CatLab %in% c("CASA","AUTON","DESEMP","OTROS","TParc","ESTUD"),"PrecLab",as.character(CatLab)))%>%
mutate(PriorNac=ifelse(PriorNac %in% c("PriorINDEF", "PriorNO"),"PriorNO",as.character(PriorNac))) %>%
mutate(ConfExtr=ifelse(ConfExtr %in% c("ALGO", "COMPLETAMENTE"),"ConfSI", "ConfNo"#as.character(ConfExtr)
)) %>%
mutate(ClaseSoc=ifelse(ClaseSoc %in% c("ALTA", "MEDIA ALTA","MEDIA BAJA"),"ClMedia","ClBaja")) %>%
select(-OrgNac,-TV)
En formato “tidy”:
df3 <- df2 %>% gather("Variable", "Valor",-ID)
attributes are not identical across measure variables;
they will be dropped
df3 %>% arrange(ID) %>% head()
vamos a explorar visualmente qué pintan tienen las respuestas. Empezamos por un tabla simple de recuentos:
tabla=xtabs (~ Variable+Valor,data=df3)
tabla %>% knitr::kable()
1 | 2 | ClBaja | ClMedia | ConfNo | ConfSI | EmailNO | EmailSI | InmNO | InmSI | InternetNO | InternetSI | JUB | MovilNO | MovilSI | PeriodicoNO | PeriodicoSI | PrecLab | PriorNO | PriorSI | RadioNO | RadioSI | RevistaNO | RevistaSI | TCompl | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
CatLab | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 171 | 0 | 0 | 0 | 0 | 408 | 0 | 0 | 0 | 0 | 0 | 0 | 271 |
ClaseSoc | 0 | 0 | 236 | 614 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
ConfExtr | 0 | 0 | 0 | 0 | 431 | 419 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 612 | 238 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
Ideol | 605 | 245 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Internet | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 523 | 327 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Movil | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 503 | 347 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Periodico | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 302 | 548 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
PriorNac | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 388 | 462 | 0 | 0 | 0 | 0 | 0 |
Radio | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 431 | 419 | 0 | 0 | 0 |
Revista | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 580 | 270 | 0 |
VecInm | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 68 | 782 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
El modelo que se ha hecho en SPSS tenía esta pinta si lo he visto bien:
fit <- MCA(df2 %>% select(-ID)%>%mutate_all(as.factor), ncp = 2, graph = TRUE)
Los autovalores son:
get_eigenvalue(fit)
eigenvalue variance.percent cumulative.variance.percent
Dim.1 0.24064005 22.212928 22.21293
Dim.2 0.12253258 11.310700 33.52363
Dim.3 0.10388916 9.589769 43.11340
Dim.4 0.08408853 7.762018 50.87541
Dim.5 0.08022838 7.405696 58.28111
Dim.6 0.07596893 7.012516 65.29363
Dim.7 0.06973865 6.437414 71.73104
Dim.8 0.06799284 6.276262 78.00730
Dim.9 0.06653336 6.141541 84.14884
Dim.10 0.05746678 5.304626 89.45347
Dim.11 0.05341440 4.930560 94.38403
Dim.12 0.04110216 3.794046 98.17808
Dim.13 0.01973751 1.821924 100.00000
fviz_screeplot(fit, addlabels = TRUE)
Realmente si nos quedamos solo con 2 dimensiones no vamos a ver mucho, pues queda mucha información fuera de ellas, pero vamos a echar un vistazo e todos modos:
fviz_mca_var(fit, choice = "mca.cor", col.var="black",
repel = TRUE,
ggtheme = theme_minimal())
fviz_mca_var(fit,
repel = TRUE, col.var="black",
ggtheme = theme_minimal())
Ya vimos que 2 dimensiones se quedaban cortas para representar las variables. Vamos a poner de color rojo las que estén mejor representadas en un plano, y de otros colores conforme vayamos perdiendo esta propiedad
fviz_mca_var(fit, col.var = "cos2",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE, # Avoid text overlapping
ggtheme = theme_minimal())
Una forma de ver quien está mejor o peor representado también sería asociando, en lugar de color rojo, un grado de transparencia al símbolo que lo representa:
fviz_mca_var(fit, alpha.var="cos2", col.var="black",
repel = TRUE,
ggtheme = theme_minimal())
Ordenemos de mejor a peor lo bien que se representan cada valor de las variables en un plano:
fviz_cos2(fit, choice = "var", axes = 1:2)
Aparentemente, en la clasificación sobre la cuestión de los inmigrantes y TV, la cuestión de dónde se sitúa las respuestas de la gente no se puede asociar muy bien con las dimensiones del plano donde lo hemos representado.
Hasta aquí era MDS estándar. Vamos a explorar un poco más por nuesra cuenta. Empezamos por el grado de independencia que hay entre cualquier par de variables que haya, para poder establecer un grado de disimilaridad.
Variables=df3$Variable %>% unique() %>% setdiff("ID")
tablaParejas=expand.grid(V1=Variables, V2=Variables)
tablaParejas %>% head(20) %>% knitr::kable()
V1 | V2 |
---|---|
VecInm | VecInm |
PriorNac | VecInm |
Ideol | VecInm |
ConfExtr | VecInm |
Revista | VecInm |
Periodico | VecInm |
Radio | VecInm |
Movil | VecInm |
VecInm | |
Internet | VecInm |
CatLab | VecInm |
ClaseSoc | VecInm |
VecInm | PriorNac |
PriorNac | PriorNac |
Ideol | PriorNac |
ConfExtr | PriorNac |
Revista | PriorNac |
Periodico | PriorNac |
Radio | PriorNac |
Movil | PriorNac |
Vamos a añadir una medida de distancia para cada combinación. En principio tomo esta que hace que dos variables sean menos distantes cuanto menos independiente sean.
#Esto es solo un truco para hacer pruebas chi2 entre la misma variable, cosa que no tiene interés.
df2b=df2
names(df2b)=str_c(names(df2),"b")
df2TRUCO=cbind(df2,df2b)
Voy a ver qué pinta tienen los “p” de independencia entre parejas de variables:
tablaParejas$p=map2_dbl(tablaParejas[,1],tablaParejas[,2], ~ (xtabs(formula(str_c("~",.x,"+",.y,"b")),data=df2TRUCO) %>% chisq.test() %>% .[["p.value"]] ))
matrizP <- matrix(round(tablaParejas$p,5), nrow = length(Variables), dimnames=list(Variables,Variables))
matrizP
VecInm PriorNac Ideol ConfExtr Revista Periodico Radio Movil Email Internet CatLab ClaseSoc
VecInm 0.00000 0.00003 0.00003 0.00000 0.76515 0.92843 0.99596 0.56101 0.31886 0.04653 0.00210 0.64742
PriorNac 0.00003 0.00000 0.00329 0.00084 0.04202 0.62939 0.07880 0.12690 0.29276 0.14748 0.03456 0.29768
Ideol 0.00003 0.00329 0.00000 0.00127 0.21180 0.38012 0.24169 0.59159 0.18273 0.72653 0.65984 0.03420
ConfExtr 0.00000 0.00084 0.00127 0.00000 0.00032 0.70598 0.01373 0.53456 0.00547 0.00419 0.00027 0.00991
Revista 0.76515 0.04202 0.21180 0.00032 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00007 0.00001
Periodico 0.92843 0.62939 0.38012 0.70598 0.00000 0.00000 0.00000 0.04440 0.00000 0.00000 0.00000 0.00771
Radio 0.99596 0.07880 0.24169 0.01373 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00091 0.00629
Movil 0.56101 0.12690 0.59159 0.53456 0.00000 0.04440 0.00000 0.00000 0.00000 0.00000 0.00003 0.00000
Email 0.31886 0.29276 0.18273 0.00547 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000
Internet 0.04653 0.14748 0.72653 0.00419 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000
CatLab 0.00210 0.03456 0.65984 0.00027 0.00007 0.00000 0.00091 0.00003 0.00000 0.00000 0.00000 0.00038
ClaseSoc 0.64742 0.29768 0.03420 0.00991 0.00001 0.00771 0.00629 0.00000 0.00000 0.00000 0.00038 0.00000
Con dibujitos lo veo mejor:
corrplot(matrizP, is.corr = FALSE)
Vamos a hacer algo similar, creando una distancias entre variables según una medida del grado de independencia
tablaParejas$distancia=map2_dbl(tablaParejas[,1],tablaParejas[,2], ~ (xtabs(formula(str_c("~",.x,"+",.y,"b")),data=df2TRUCO) %>% chisq.test() %>% (function(chi2) (1/(1+abs(chi2[["statistic"]]))/chi2[["parameter"]]))(.)
))
Con ella contruyo la matriz de distancias, asegurándome de que la diagonal la pongo en cero
matrizDistancias <- matrix(round(tablaParejas$distancia,4), nrow = length(Variables), dimnames=list(Variables,Variables))
for (i in 1:nrow(matrizDistancias))matrizDistancias[i,i]=0L
matrizDistancias
VecInm PriorNac Ideol ConfExtr Revista Periodico Radio Movil Email Internet CatLab ClaseSoc
VecInm 0.0000 0.0537 0.0547 0.0414 0.9181 0.9920 1.0000 0.7474 0.5016 0.2015 0.0375 0.8270
PriorNac 0.0537 0.0000 0.1037 0.0823 0.1948 0.8111 0.2445 0.3003 0.4746 0.3228 0.0647 0.4797
Ideol 0.0547 0.1037 0.0000 0.0879 0.3908 0.5649 0.4218 0.7765 0.3603 0.8910 0.2730 0.1823
ConfExtr 0.0414 0.0823 0.0879 0.0000 0.0718 0.8754 0.1414 0.7216 0.1147 0.1087 0.0287 0.1307
Revista 0.9181 0.1948 0.3908 0.0718 0.0000 0.0122 0.0113 0.0117 0.0113 0.0214 0.0248 0.0501
Periodico 0.9920 0.8111 0.5649 0.8754 0.0122 0.0000 0.0162 0.1984 0.0327 0.0226 0.0079 0.1235
Radio 1.0000 0.2445 0.4218 0.1414 0.0113 0.0162 0.0000 0.0319 0.0225 0.0300 0.0333 0.1181
Movil 0.7474 0.3003 0.7765 0.7216 0.0117 0.1984 0.0319 0.0000 0.0042 0.0077 0.0228 0.0311
Email 0.5016 0.4746 0.3603 0.1147 0.0113 0.0327 0.0225 0.0042 0.0000 0.0022 0.0071 0.0250
Internet 0.2015 0.3228 0.8910 0.1087 0.0214 0.0226 0.0300 0.0077 0.0022 0.0000 0.0054 0.0185
CatLab 0.0375 0.0647 0.2730 0.0287 0.0248 0.0079 0.0333 0.0228 0.0071 0.0054 0.0000 0.0299
ClaseSoc 0.8270 0.4797 0.1823 0.1307 0.0501 0.1235 0.1181 0.0311 0.0250 0.0185 0.0299 0.0000
tablaParejas$distancia=map2_dbl(tablaParejas[,1],tablaParejas[,2], ~ (xtabs(formula(str_c("~",.x,"+",.y,"b")),data=df2TRUCO) %>% chisq.test() %>% (function(chi2)chi2[["statistic"]]/chi2[["parameter"]])(.) %>% (function(x)1/(1+sqrt(abs(x))) )(.)))
tablaParejas %>% head(20)
Con ella contruyo la matriz de distancias, asegurándome de que la diagonal la pongo en cero
matrizDistancias <- matrix(round(tablaParejas$distancia,4), nrow = length(Variables), dimnames=list(Variables,Variables))
for (i in 1:nrow(matrizDistancias))matrizDistancias[i,i]=0L
matrizDistancias
VecInm PriorNac Ideol ConfExtr Revista Periodico Radio Movil Email Internet CatLab ClaseSoc
VecInm 0.0000 0.1924 0.1938 0.1721 0.7700 0.9176 0.9950 0.6324 0.5008 0.3344 0.2871 0.6862
PriorNac 0.1924 0.0000 0.2538 0.2305 0.3297 0.6745 0.3626 0.3958 0.4873 0.4084 0.3528 0.4899
Ideol 0.1938 0.2538 0.0000 0.2369 0.4447 0.5326 0.4607 0.6508 0.4287 0.7409 0.6080 0.3208
ConfExtr 0.1721 0.2305 0.2369 0.0000 0.2176 0.7261 0.2887 0.6169 0.2647 0.2588 0.2587 0.2794
Revista 0.7700 0.3297 0.4447 0.2176 0.0000 0.1001 0.0967 0.0982 0.0967 0.1289 0.2442 0.1868
Periodico 0.9176 0.6745 0.5326 0.7261 0.1001 0.0000 0.1137 0.3322 0.1554 0.1319 0.1519 0.2729
Radio 0.9950 0.3626 0.4607 0.2887 0.0967 0.1137 0.0000 0.1537 0.1316 0.1496 0.2743 0.2679
Movil 0.6324 0.3958 0.6508 0.6169 0.0982 0.3322 0.1537 0.0000 0.0608 0.0811 0.2361 0.1519
Email 0.5008 0.4873 0.4287 0.2647 0.0967 0.1554 0.1316 0.0608 0.0000 0.0448 0.1454 0.1381
Internet 0.3344 0.4084 0.7409 0.2588 0.1289 0.1319 0.1496 0.0811 0.0448 0.0000 0.1288 0.1207
CatLab 0.2871 0.3528 0.6080 0.2587 0.2442 0.1519 0.2743 0.2361 0.1454 0.1288 0.0000 0.2629
ClaseSoc 0.6862 0.4899 0.3208 0.2794 0.1868 0.2729 0.2679 0.1519 0.1381 0.1207 0.2629 0.0000
Vamos a visualizar esas distancias
corrplot(matrizDistancias, is.corr = FALSE)
Vamos a intentar representar esas distancias como si de distancias entre ciudades se tratase usando escalamiento dimensional:
Podemos hacerlo
fit <- cmdscale(matrizDistancias,eig=TRUE,k=2)
fit
$points
[,1] [,2]
VecInm -0.5852622238 0.179064849
PriorNac -0.2302196247 -0.075967082
Ideol -0.2477231106 -0.354561210
ConfExtr -0.2355390852 -0.100291092
Revista 0.1762511274 -0.073625632
Periodico 0.3771678016 0.005211178
Radio 0.3204803496 -0.170238285
Movil 0.1717794473 0.157853408
Email 0.0728919652 0.045474403
Internet 0.0679933218 0.265194838
CatLab -0.0005076661 0.183511292
ClaseSoc 0.1126876974 -0.061626666
$eig
[1] 8.405493e-01 3.428243e-01 1.789290e-01 1.253356e-01 5.868912e-02 9.340754e-03 4.297083e-03 -1.110223e-16 -1.340308e-02 -1.107221e-01 -2.090123e-01 -3.821644e-01
$x
NULL
$ac
[1] 0
$GOF
[1] 0.5201032 0.7585898
Coordenadas=fit$points%>% as_tibble() %>% mutate(Variable=dimnames(fit$points)[[1]])
ggplot(Coordenadas,aes(x=V1,y=V2,label=Variable)) + geom_point() +geom_text_repel(alpha=0.5)+
coord_cartesian(xlim=c(-1,1) ,ylim=c(-0.5,0.5))+theme_minimal()
No me hace gracia ver autovalores negativos, así que cambio a otro método:
fit <- isoMDS(matrizDistancias, k=2)
initial value 22.914048
iter 5 value 16.143230
iter 10 value 15.314215
iter 15 value 14.823088
final value 14.236163
converged
fit
$points
[,1] [,2]
VecInm -0.94856770 -0.02424811
PriorNac -0.71870231 -0.39872698
Ideol -0.48407458 -0.68807952
ConfExtr -0.38688095 -0.07385496
Revista 0.37342093 0.11479621
Periodico 0.64960110 -0.18053381
Radio 0.58121305 0.06477342
Movil 0.29099449 0.52300367
Email 0.24991008 0.25405642
Internet 0.21171970 0.25031406
CatLab -0.06217582 0.34546959
ClaseSoc 0.24354201 -0.18696999
$stress
[1] 14.23616
Coordenadas=fit$points%>% as_tibble() %>% mutate(Variable=dimnames(fit$points)[[1]])
ggplot(Coordenadas,aes(x=V1,y=V2,label=Variable)) + geom_point() +geom_text_repel(alpha=0.5)+
coord_cartesian(xlim=c(-1.25,1.25) ,ylim=c(-1,1))+theme_minimal()
Bueno, con eso nos hacemos una idea de qué variables son las más independientes entre sí. Por ejemplo: