Estudio en R sobre los estudiantes de la UNED 2022-2023
Author
J. Raúl Marin Pizarro
Published
May 2, 2024
1 Introducción
Hemos elegido para este caso práctico una base de datos directamente del portál estadístico de la UNED, Portal Estadístico UNED y que se aporta en la documentación. Al descargarlo y abrirlo con EXCEL se ha guardado como archivo .xlslx. y asi se proporciona, sin ningun cambio ni modificación.
La idea principal es analizar si existe una relación (o no) entre las variables edad, sexo y nota media en la base de datos prpporcionada , para lo que aplicaremos los conocimientos y técnicas de analisis adquiridas en este curso y otros , entre otras, apoyando el informe con gráficos siguiendo lo aprendido en dicho curso, además de la base matemática.
Los conocimientos de estadística descriptiva son los de primer curso de ADE de la asignatura de Estadística, seguidos por el manual de la asignatura (Angel Muñoz Alamillos), y en su continuacion en segundo curso de ADE sobre las distribuciones e inferencia estadística del manual de la asignatura (Jose M. Casas Sánchez, 2018).
La parte de analisis está apoyada en textos que uso habitualmente de referencia como (Javier Marín Morales, 2023) y (Eva Laude, 2022). Muchas de las ideas y códigos son consultadas habitualmente en páginas de internet, como R coder R Coder o github y muchas que me sería difícil citarlas.
La parte en la que hemos trabajado con Machine Learning, con algoritmos de clasificación y segmentacion han sido conocimientos adquiridos en cuarto curso, con la Asignatura de Machine Learning, y el manual recomendado por el equipo docente (Lantz, 2023), uno de los libros con los mas he aprendido y disfrutado (y sigo haciéndolo).
Imprescindible en la parte gráfica han sido los manuales e información aportada en esta asignatura por el equipo docente, muy elaborados y que nos han facilitado mucho la tarea.
2 Primeros pasos
Lo primero que hacemos es ejecutar las instrucciones para cargar las librerias necesarias para ejecutar nuestro código R, que son estas que vemos a continuación (si no las tenemos instaladas hay que instalarlas primero):
Code
######## un estudio sobre los estudiantes de la UNED ##### #librarias a usar library (readxl) library (tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.3 ✔ readr 2.1.4
✔ forcats 1.0.0 ✔ stringr 1.5.0
✔ ggplot2 3.4.3 ✔ tibble 3.2.1
✔ lubridate 1.9.2 ✔ tidyr 1.3.0
✔ purrr 1.0.2
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Warning: package 'kableExtra' was built under R version 4.3.3
Attaching package: 'kableExtra'
The following object is masked from 'package:dplyr':
group_rows
Code
library (car)
Loading required package: carData
Attaching package: 'car'
The following object is masked from 'package:dplyr':
recode
The following object is masked from 'package:purrr':
some
Code
library (psych)
Attaching package: 'psych'
The following object is masked from 'package:car':
logit
The following objects are masked from 'package:ggplot2':
%+%, alpha
Code
library (mice)
Warning: package 'mice' was built under R version 4.3.3
Attaching package: 'mice'
The following object is masked from 'package:stats':
filter
The following objects are masked from 'package:base':
cbind, rbind
Code
library (plotly)
Warning: package 'plotly' was built under R version 4.3.3
Attaching package: 'plotly'
The following object is masked from 'package:ggplot2':
last_plot
The following object is masked from 'package:stats':
filter
The following object is masked from 'package:graphics':
layout
Code
library (Boruta)
Warning: package 'Boruta' was built under R version 4.3.3
Code
library (cluster) library (factoextra)
Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
Code
library (dummy)
dummy 0.1.3
dummyNews()
Esas son las librerias que vamos a utilizar en nuestro script. Dicho esto, cargamos el archivo .xlsx y lo importamos como un dataframe:
Code
# cargando fichero descargado de la UNED sgttitulsccaa_xls <-read_excel("sgttitulsccaa.xls.xlsx", skip =2)
Y podemos ver que en la ventana de entorno (arriba a derecha) ya tenemos el dataframe cargado, incluso podemos desplegarlo en el icono (lo que equivale a ejecutar un str o glimpse) y nos da informacion sobre el nombre de la variable, el tipo, la extensión y los campos. Si pulsamos directamente en el archivo nos abre el dataframe en la ventana del scrip, lo cual es equivalente a la instrucción view, y siempre viene bien tener los datos ahi.
Para algunas operaciones aleatorias que vamos a utilizar con algunos algoritmos, es conveniente fijar una “semilla” : esto significa que R ejecutará el código de forma aleatoria (pero cada vez que lo ejecutemos la salida de los datos será siempre la misma)
Code
#semilla fija para obtener iguales resultados set.seed =0709
3 Análisis exploratorio
Usamos ahora la función head combinada con la libreria kable Zhu (2024) visualizar los seis primeros registros de nuestro dataframe:
Code
#mirando los 6 primeros registros del DF (kableExtra)kable(head (sgttitulsccaa_xls)) %>%kable_styling(bootstrap_options ="striped", full_width = F)
CURSO ACADÉMICO
CAMPUS
CENTRO
RAMA DE CONOCIMIENTO
NIVEL ESTUDIOS
TITULACIÓN
MATRICUADOS
MATRI. EQUIV. TIEMPO COMPLETO
Nº ESTUDIANTES NUEVOS
CRED. MATRI. ESTUD. NUEVOS
CRED. MATRICULADOS
CRED. MATRI 1ª VEZ
CRED. MATRI 2ª VEZ
CRED. MATRI 3ª VEZ
CRE. EVALUADOS
CRED. SUPERADOS
CRED. RECONOCIDOS
MEDIA CRED. REC X ESTUD.
NOTA MEDIA
% SUSPENSOS
% APROBADOS
% NOTABLES
% SOBRESALIENTES
% MATRICULAS
TASA EVALUACIÓN
TASA DE ÉXITOS
TASA RENDIMIENTO
TASA RECONOCIMIENTO
TASA ÉXITO. EXÁM. REALIZ.
Nº ESTUD. EGRESADOS
NOTA MEDIA EGRESADOS
DURACIÓN MEDIA
% APROBADOS EGRS.
% NOTABLES EGRS.
% SOBRESALIENTES EGRS.
% MATRÍCULAS DE H. EGRS.
% EGRESADOS VS. ESTUD. NUEVOS
TASA ABANDONO
TASA EGRESO
NUM. EXÁM. REALIZ.
NUM. EXÁM. APTOS
% ESTUD. 0 EXÁM.
% ESTUD. 1 EXÁM.
% ESTUD. 2 EXÁM.
% ESTUD. 3 EXÁM.
% ESTUD. 4 EXÁM.
% ESTUD. 5 EXÁM.
EXÁM. POR ESTUD. MATRIC.
EDAD MEDIA GLOBAL
EDAD MEDIA HOMBRES
EDAD MEDIA MUJERES
EDAD MEDIA NO NACIONALES
% HOMBRES
% MUJERES
% UNIÓN EUROPEA
% NO NACIONALES
EVALUACIÓN X CAMPUS Y RAMA
ÉXITO X CAMPUS Y RAMA
RENDIMIENTO X CAMPUS Y RAMA
ABANDONO X CAMPUS Y RAMA
EGRESO X CAMPUS Y RAMA
EFICIENCIA X CAMPUS Y RAMA
ÉXITO EXÁM. X CAMPUS Y RAMA
2022 - 2023
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS EXPERIMENTALES
GRADO
6101 - GRADO EN CIENCIAS AMBIENTALES
23
12
4
82
532
465
36
31
382
372
0
0.00
7.79
2.04
27.04
39.29
22.45
1.02
71.80
97.38
69.92
NA
80.72
2
7.30
11.3
33.73
53.01
10.84
2.41
50.00
NA
NA
83
67
21.74
13.04
13.04
13.04
8.70
30.43
3.61
32.8
35.0
30.5
NA
50.00
50.00
0.00
0.00
37.57
79.36
29.81
NA
NA
81.16
53.25
2022 - 2023
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS EXPERIMENTALES
GRADO
6102 - GRADO EN MATEMÁTICAS
22
13
7
222
556
365
149
42
191
141
125
5.68
5.32
27.60
29.69
16.15
8.85
0.00
34.35
73.82
25.36
18.36
42.37
NA
NA
NA
NA
NA
NA
NA
NA
NA
NA
59
25
60.87
4.35
4.35
4.35
0.00
26.09
2.68
28.9
29.0
28.0
28.0
85.71
14.29
14.29
14.29
37.57
79.36
29.81
NA
NA
81.16
53.25
2022 - 2023
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS EXPERIMENTALES
GRADO
6103 - GRADO EN QUÍMICA
13
7
4
66
275
154
92
29
95
89
39
3.00
5.98
6.25
25.00
6.25
4.17
4.17
34.55
93.68
32.36
12.42
64.00
NA
NA
NA
NA
NA
NA
NA
NA
NA
NA
25
16
53.85
7.69
7.69
7.69
0.00
23.08
1.92
35.5
NA
35.5
NA
0.00
100.00
0.00
0.00
37.57
79.36
29.81
NA
NA
81.16
53.25
2022 - 2023
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS EXPERIMENTALES
GRADO
6104 - GRADO EN FÍSICA
13
9
4
102
392
263
124
5
192
150
0
0.00
6.99
22.73
29.80
15.15
9.60
0.00
48.98
78.13
38.27
NA
46.30
NA
NA
NA
NA
NA
NA
NA
NA
NA
NA
54
25
38.46
23.08
0.00
0.00
7.69
30.77
4.15
33.0
33.0
33.0
36.0
50.00
50.00
0.00
25.00
37.57
79.36
29.81
NA
NA
81.16
53.25
2022 - 2023
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS DE LA SALUD
GRADO
6201 - GRADO EN PSICOLOGÍA
367
253
109
3786
11385
7902
2343
1140
6162
4482
753
2.05
6.76
30.58
43.53
20.94
4.22
0.56
54.12
72.74
39.37
6.20
43.00
26
6.92
9.3
53.36
34.56
10.61
1.47
23.85
NA
NA
1642
706
19.57
8.15
14.67
6.52
10.33
40.76
4.47
32.1
33.8
31.5
31.3
25.69
74.31
1.83
3.67
51.93
76.61
39.78
NA
NA
85.33
47.04
2022 - 2023
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS SOCIALES Y JURÍDICAS
GRADO
6301 - GRADO EN EDUCACIÓN SOCIAL
49
36
9
390
1602
1356
174
72
1062
900
288
5.88
7.28
15.44
33.74
41.80
8.27
0.75
66.29
84.75
56.18
15.24
61.47
8
7.00
7.3
35.32
49.44
13.75
1.49
88.89
NA
NA
231
142
16.33
14.29
4.08
16.33
2.04
46.94
4.71
33.4
49.0
31.5
40.0
11.11
88.89
0.00
11.11
55.09
82.08
45.22
NA
NA
87.28
58.18
Y lo que vemos las primeras filas del dataframe y como está estructurado: tenemos una tabla con 4080 filas (observaciones) y 63 columnas (variables). Para este trabajo nos centramos en las edades, el sexo y las notas, por lo que en principio habrá que elegir.
Tambien vemos que en algunas casillas aparece NA, que es la forma que R tiene de decir que ese dato no está relleno (no vale Cero, lo que dice es que no hay un valor asignado, y suele ser fuente de problemas.
Ahora queremos ver un resumen más estadístico del dataframe, porque asi no podemos hacer mucho. El uso de skim (Waring et al., 2022) nos facilita enormemente la tarea, ya que tendriamos que hacer un table de cada variable tipo caracter y un summary de cada variable humerica, a parte de contar los NA´s y hacer los correspondientes histogramas; pero todo ese resumen lo conseguimos con una sola instrucción, y nos ahora mucho tiempo:
Code
#mirando el DF con skim kable(skim (sgttitulsccaa_xls)) %>%kable_styling(bootstrap_options ="basic", full_width = F)
skim_type
skim_variable
n_missing
complete_rate
character.min
character.max
character.empty
character.n_unique
character.whitespace
logical.mean
logical.count
numeric.mean
numeric.sd
numeric.p0
numeric.p25
numeric.p50
numeric.p75
numeric.p100
numeric.hist
character
CURSO ACADÉMICO
0
1.0000000
11
11
0
1
0
NA
NA
NA
NA
NA
NA
NA
NA
NA
NA
character
CAMPUS
0
1.0000000
3
18
0
7
0
NA
NA
NA
NA
NA
NA
NA
NA
NA
NA
character
CENTRO
32
0.9921569
4
44
0
64
0
NA
NA
NA
NA
NA
NA
NA
NA
NA
NA
character
RAMA DE CONOCIMIENTO
32
0.9921569
11
29
0
5
0
NA
NA
NA
NA
NA
NA
NA
NA
NA
NA
character
NIVEL ESTUDIOS
0
1.0000000
5
20
0
2
0
NA
NA
NA
NA
NA
NA
NA
NA
NA
NA
character
TITULACIÓN
0
1.0000000
22
182
0
106
0
NA
NA
NA
NA
NA
NA
NA
NA
NA
NA
logical
TASA ABANDONO
4080
0.0000000
NA
NA
NA
NA
NA
NaN
:
NA
NA
NA
NA
NA
NA
NA
NA
logical
TASA EGRESO
4080
0.0000000
NA
NA
NA
NA
NA
NaN
:
NA
NA
NA
NA
NA
NA
NA
NA
logical
ABANDONO X CAMPUS Y RAMA
4080
0.0000000
NA
NA
NA
NA
NA
NaN
:
NA
NA
NA
NA
NA
NA
NA
NA
logical
EGRESO X CAMPUS Y RAMA
4080
0.0000000
NA
NA
NA
NA
NA
NaN
:
NA
NA
NA
NA
NA
NA
NA
NA
numeric
MATRICUADOS
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
31.480392
125.1277753
1.00
2.0000
4.000
20.0000
4911.00
▇▁▁▁▁
numeric
MATRI. EQUIV. TIEMPO COMPLETO
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
21.312745
85.6978005
0.00
1.0000
3.000
13.0000
3427.00
▇▁▁▁▁
numeric
Nº ESTUDIANTES NUEVOS
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
9.852206
36.6645304
0.00
1.0000
2.000
7.0000
1375.00
▇▁▁▁▁
numeric
CRED. MATRI. ESTUD. NUEVOS
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
339.607108
1324.3067748
0.00
18.0000
61.000
211.2500
49809.00
▇▁▁▁▁
numeric
CRED. MATRICULADOS
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
937.204167
3856.4435810
0.00
45.0000
122.500
576.0000
154188.00
▇▁▁▁▁
numeric
CRED. MATRI 1ª VEZ
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
700.434926
2781.1384284
0.00
36.0000
105.000
444.5000
110274.00
▇▁▁▁▁
numeric
CRED. MATRI 2ª VEZ
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
168.648284
805.5063142
0.00
0.0000
12.000
88.0000
31851.00
▇▁▁▁▁
numeric
CRED. MATRI 3ª VEZ
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
68.120956
310.7518722
0.00
0.0000
0.000
36.0000
12063.00
▇▁▁▁▁
numeric
CRE. EVALUADOS
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
500.038725
2080.4932885
0.00
22.0000
70.000
305.2500
83832.00
▇▁▁▁▁
numeric
CRED. SUPERADOS
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
418.684804
1679.0900971
0.00
20.0000
64.000
262.0000
67134.00
▇▁▁▁▁
numeric
CRED. RECONOCIDOS
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
83.301471
353.1257407
0.00
0.0000
0.000
27.0000
10830.00
▇▁▁▁▁
numeric
MEDIA CRED. REC X ESTUD.
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
1.469333
4.2293835
0.00
0.0000
0.000
1.5000
99.00
▇▁▁▁▁
numeric
NOTA MEDIA
380
0.9068627
NA
NA
NA
NA
NA
NA
NA
7.419416
1.1633247
0.51
6.8100
7.420
8.2000
10.00
▁▁▁▇▃
numeric
% SUSPENSOS
348
0.9147059
NA
NA
NA
NA
NA
NA
NA
7.870841
10.4711183
0.00
0.0000
2.925
13.7325
100.00
▇▁▁▁▁
numeric
% APROBADOS
348
0.9147059
NA
NA
NA
NA
NA
NA
NA
22.471543
17.6244548
0.00
6.7825
22.425
35.6175
100.00
▇▆▂▁▁
numeric
% NOTABLES
348
0.9147059
NA
NA
NA
NA
NA
NA
NA
30.287291
20.4640954
0.00
16.6700
28.715
41.0300
100.00
▆▇▃▁▁
numeric
% SOBRESALIENTES
348
0.9147059
NA
NA
NA
NA
NA
NA
NA
16.892580
20.0064155
0.00
3.0300
10.165
23.5300
100.00
▇▂▁▁▁
numeric
% MATRICULAS
348
0.9147059
NA
NA
NA
NA
NA
NA
NA
2.784341
7.3124423
0.00
0.0000
0.000
2.9725
100.00
▇▁▁▁▁
numeric
TASA EVALUACIÓN
3
0.9992647
NA
NA
NA
NA
NA
NA
NA
56.377937
30.1272153
0.00
36.8400
55.740
80.0000
100.00
▃▅▇▆▇
numeric
TASA DE ÉXITOS
348
0.9147059
NA
NA
NA
NA
NA
NA
NA
89.822583
15.3416634
0.00
83.6100
96.660
100.0000
100.00
▁▁▁▂▇
numeric
TASA RENDIMIENTO
3
0.9992647
NA
NA
NA
NA
NA
NA
NA
52.149146
31.0316111
0.00
30.0000
50.000
77.2100
100.00
▅▆▇▅▇
numeric
TASA RECONOCIMIENTO
2657
0.3487745
NA
NA
NA
NA
NA
NA
NA
11.444582
10.8688486
0.20
4.5500
8.280
14.2900
85.17
▇▂▁▁▁
numeric
TASA ÉXITO. EXÁM. REALIZ.
497
0.8781863
NA
NA
NA
NA
NA
NA
NA
73.411250
25.2128800
0.00
56.1850
76.680
100.0000
100.00
▁▁▃▅▇
numeric
Nº ESTUD. EGRESADOS
2052
0.4970588
NA
NA
NA
NA
NA
NA
NA
3.979783
9.9834142
1.00
1.0000
2.000
4.0000
275.00
▇▁▁▁▁
numeric
NOTA MEDIA EGRESADOS
2052
0.4970588
NA
NA
NA
NA
NA
NA
NA
7.690192
0.7998908
5.40
7.1000
7.620
8.3000
9.90
▁▆▇▆▁
numeric
DURACIÓN MEDIA
2052
0.4970588
NA
NA
NA
NA
NA
NA
NA
5.205177
3.3086688
1.00
2.0000
4.100
8.0000
14.00
▇▃▃▂▁
numeric
% APROBADOS EGRS.
2285
0.4399510
NA
NA
NA
NA
NA
NA
NA
33.863838
18.3559693
2.27
18.1800
33.330
46.1500
100.00
▇▇▆▂▁
numeric
% NOTABLES EGRS.
2072
0.4921569
NA
NA
NA
NA
NA
NA
NA
42.645747
14.1499264
2.38
34.2025
41.670
50.0000
100.00
▁▇▇▂▁
numeric
% SOBRESALIENTES EGRS.
2141
0.4752451
NA
NA
NA
NA
NA
NA
NA
25.086060
17.4160926
1.25
11.9450
20.000
33.3300
100.00
▇▅▂▁▁
numeric
% MATRÍCULAS DE H. EGRS.
2945
0.2781863
NA
NA
NA
NA
NA
NA
NA
6.818291
7.8639694
0.27
2.3800
4.220
8.6550
66.67
▇▁▁▁▁
numeric
% EGRESADOS VS. ESTUD. NUEVOS
2419
0.4071078
NA
NA
NA
NA
NA
NA
NA
57.104232
56.4867768
1.19
20.0000
40.000
91.4300
600.00
▇▁▁▁▁
numeric
NUM. EXÁM. REALIZ.
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
119.154167
531.0689577
0.00
4.0000
13.000
65.2500
21235.00
▇▁▁▁▁
numeric
NUM. EXÁM. APTOS
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
70.656127
285.4985852
0.00
3.0000
10.000
43.0000
11066.00
▇▁▁▁▁
numeric
% ESTUD. 0 EXÁM.
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
25.644461
27.9268912
0.00
0.0000
20.450
37.6450
100.00
▇▅▂▁▁
numeric
% ESTUD. 1 EXÁM.
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
14.613934
23.1596449
0.00
0.0000
7.515
18.1800
100.00
▇▁▁▁▁
numeric
% ESTUD. 2 EXÁM.
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
12.239002
20.5701523
0.00
0.0000
5.000
15.6375
100.00
▇▁▁▁▁
numeric
% ESTUD. 3 EXÁM.
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
9.252135
18.2192359
0.00
0.0000
0.000
10.7100
100.00
▇▁▁▁▁
numeric
% ESTUD. 4 EXÁM.
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
7.681069
16.5837381
0.00
0.0000
0.000
9.0900
100.00
▇▁▁▁▁
numeric
% ESTUD. 5 EXÁM.
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
30.569073
30.4412185
0.00
0.0000
25.000
50.0000
100.00
▇▅▃▁▂
numeric
EXÁM. POR ESTUD. MATRIC.
0
1.0000000
NA
NA
NA
NA
NA
NA
NA
3.176659
2.3885626
0.00
1.5000
2.950
4.4400
15.00
▇▆▁▁▁
numeric
EDAD MEDIA GLOBAL
872
0.7862745
NA
NA
NA
NA
NA
NA
NA
35.464059
8.4483379
18.00
29.6000
34.200
40.4000
76.00
▃▇▃▁▁
numeric
EDAD MEDIA HOMBRES
1607
0.6061275
NA
NA
NA
NA
NA
NA
NA
36.995188
9.4564094
18.00
30.0000
35.800
43.0000
73.00
▃▇▅▁▁
numeric
EDAD MEDIA MUJERES
1651
0.5953431
NA
NA
NA
NA
NA
NA
NA
34.060478
8.3096852
18.00
28.0000
33.000
39.0000
76.00
▅▇▂▁▁
numeric
EDAD MEDIA NO NACIONALES
3363
0.1757353
NA
NA
NA
NA
NA
NA
NA
31.315202
8.5694407
18.00
25.0000
30.000
36.5000
65.00
▇▇▃▁▁
numeric
% HOMBRES
870
0.7867647
NA
NA
NA
NA
NA
NA
NA
49.660573
37.6634619
0.00
12.5000
50.000
88.8900
100.00
▇▃▅▃▇
numeric
% MUJERES
870
0.7867647
NA
NA
NA
NA
NA
NA
NA
50.339430
37.6634632
0.00
11.1100
50.000
87.5000
100.00
▇▃▅▃▇
numeric
% UNIÓN EUROPEA
870
0.7867647
NA
NA
NA
NA
NA
NA
NA
1.695321
8.5888698
0.00
0.0000
0.000
0.0000
100.00
▇▁▁▁▁
numeric
% NO NACIONALES
870
0.7867647
NA
NA
NA
NA
NA
NA
NA
4.926726
15.6113003
0.00
0.0000
0.000
0.0000
100.00
▇▁▁▁▁
numeric
EVALUACIÓN X CAMPUS Y RAMA
32
0.9921569
NA
NA
NA
NA
NA
NA
NA
58.974787
15.4160346
0.00
50.4800
55.090
76.9900
81.33
▁▁▃▇▆
numeric
ÉXITO X CAMPUS Y RAMA
33
0.9919118
NA
NA
NA
NA
NA
NA
NA
90.397153
8.7691287
23.61
82.6200
95.530
97.3100
100.00
▁▁▁▅▇
numeric
RENDIMIENTO X CAMPUS Y RAMA
32
0.9921569
NA
NA
NA
NA
NA
NA
NA
54.332357
17.6506872
0.00
44.1900
48.430
74.4500
79.76
▁▃▇▃▇
numeric
EFICIENCIA X CAMPUS Y RAMA
38
0.9906863
NA
NA
NA
NA
NA
NA
NA
87.340678
4.1957075
67.05
85.3300
87.280
90.3500
96.31
▁▁▃▇▃
numeric
ÉXITO EXÁM. X CAMPUS Y RAMA
33
0.9919118
NA
NA
NA
NA
NA
NA
NA
74.008925
16.6167944
9.38
58.7100
77.540
88.4100
93.90
▁▁▅▂▇
Y ahora tenemos un resumen más util para nuestro análisis exploratorio: ya sabemos que R ha importado el dataframe y ha asignado tres tipos de variables: character, logical y numerical. Vemos el número de casos incompletos de cada variable, el nombre de la variable, y en el caso de las variables numéricas la media, mediana, cuartiles y un pequeño histograma. Aun asi, la cantidad de información que tenemos es abrumadora para nuestro estudio.
3.1 Creando un subconjunto de datos
Vamos a crear un nuevo dataframe a partir del original, que nunca es conveniente tocar, porque son los datos originales. El primer filtro es seleccionar los alumnos que son de Grado (el dataframe contiene los alumnos de Grado y Master):
Code
#seleccionando registros con FILTER alumnos_grado <- sgttitulsccaa_xls %>%filter (`NIVEL ESTUDIOS`=="GRADO")
Y volvemos a ver en nuestra ventana de entorno un dataframe al que hemos llamado alumnos_grado.
Ahora, elegimos las variables que creemos que son convenientes para nuestro estudio. Es un paso importante, ya que si elegimos mal o de menos, tendremos que repetir todo el proceso desde aquí:
Code
#eligiendo las variables a estudio con SELECT alumnos_grado <- alumnos_grado %>%select (CAMPUS, CENTRO,`RAMA DE CONOCIMIENTO`, `NIVEL ESTUDIOS`, TITULACIÓN, MATRICUADOS,`Nº ESTUDIANTES NUEVOS`, `NOTA MEDIA`, `% SUSPENSOS`,`% APROBADOS`, `% NOTABLES`, `% SOBRESALIENTES`, `% MATRICULAS`, `EDAD MEDIA GLOBAL`, `EDAD MEDIA HOMBRES`, `EDAD MEDIA MUJERES`, `% HOMBRES`, `% MUJERES`)
En ambos casos hemos usado el lenguaje que aporta el paquete de librerías tidyverse(Wickham et al., 2019) con dplyr(Wickham et al., 2023) y el uso de %>% nos facilita mucho la tarea. También podríamos haber seleccionado las variables por número de columna.
Vemos que nuestro dataframe ha cambiado. Ahora tiene 18 variables y 1761 observaciones. Lo siguiente es cambiar el nombre de las variables. Los espacios en blanco, determinados símbolos y algunas otras cosas suelen dar problemas en alguas librerías (incluso con los registros). Asi que vamos a cambiar el nombre de las variables para evitar futuros fallos y tambien corregir errores tipográficos:
Code
# Renombrar las variables en el dataframe colnames(alumnos_grado) <-c("CAMPUS", "CENTRO", "RAMA_DE_CONOCIMIENTO", "NIVEL_ESTUDIOS", "TITULACION", "MATRICULADOS","N_ESTUDIANTES_NUEVOS","NOTA_MEDIA","P_SUSPENSOS", "P_APROBADOS", "P_NOTABLES","P_SOBRESALIENTES", "P_MATRICULAS", "EDAD_MEDIA_GLOBAL", "EDAD_MEDIA_HOMBRES","EDAD_MEDIA_MUJERES","P_HOMBRES", "P_MUJERES")
Y ya podemos comenzar a explorar más detenidamente nuestros datos:
¿Cual es el número de alumnos que estamos manejando?
Code
#alumnos que tenemos en en estudio sum (alumnos_grado$MATRICULADOS)
[1] 119023
Este es el número de alumnos. En el resumen estadístico anterior, que hicimos con skim, vimos que teníamos valores NA´s en muchas variables. Veamos como ha quedado ahora
Code
#visualizamos el resumen del dataframe con los cambios realizados kable(skim (alumnos_grado)) %>%kable_styling(bootstrap_options ="striped", full_width = F)
skim_type
skim_variable
n_missing
complete_rate
character.min
character.max
character.empty
character.n_unique
character.whitespace
numeric.mean
numeric.sd
numeric.p0
numeric.p25
numeric.p50
numeric.p75
numeric.p100
numeric.hist
character
CAMPUS
0
1.0000000
3
18
0
7
0
NA
NA
NA
NA
NA
NA
NA
NA
character
CENTRO
32
0.9818285
4
44
0
64
0
NA
NA
NA
NA
NA
NA
NA
NA
character
RAMA_DE_CONOCIMIENTO
32
0.9818285
11
29
0
5
0
NA
NA
NA
NA
NA
NA
NA
NA
character
NIVEL_ESTUDIOS
0
1.0000000
5
5
0
1
0
NA
NA
NA
NA
NA
NA
NA
NA
character
TITULACION
0
1.0000000
22
65
0
30
0
NA
NA
NA
NA
NA
NA
NA
NA
numeric
MATRICULADOS
0
1.0000000
NA
NA
NA
NA
NA
67.588302
183.951168
1.00
9.0000
24.00
62.0000
4911.00
▇▁▁▁▁
numeric
N_ESTUDIANTES_NUEVOS
0
1.0000000
NA
NA
NA
NA
NA
20.232822
53.622547
0.00
3.0000
7.00
18.0000
1375.00
▇▁▁▁▁
numeric
NOTA_MEDIA
90
0.9488927
NA
NA
NA
NA
NA
6.700497
1.023670
0.51
6.4400
6.91
7.2500
9.60
▁▁▁▇▁
numeric
P_SUSPENSOS
69
0.9608177
NA
NA
NA
NA
NA
14.881602
10.571518
0.00
7.1700
13.70
20.9075
100.00
▇▃▁▁▁
numeric
P_APROBADOS
69
0.9608177
NA
NA
NA
NA
NA
31.115810
12.956177
0.00
23.0800
33.06
40.8950
100.00
▃▇▅▁▁
numeric
P_NOTABLES
69
0.9608177
NA
NA
NA
NA
NA
24.093676
12.537587
0.00
15.6625
25.00
33.1525
100.00
▅▇▁▁▁
numeric
P_SOBRESALIENTES
69
0.9608177
NA
NA
NA
NA
NA
7.604255
6.272296
0.00
2.8775
6.67
11.0125
42.90
▇▅▁▁▁
numeric
P_MATRICULAS
69
0.9608177
NA
NA
NA
NA
NA
2.495774
3.299250
0.00
0.0000
1.53
3.6400
37.75
▇▁▁▁▁
numeric
EDAD_MEDIA_GLOBAL
93
0.9471891
NA
NA
NA
NA
NA
35.512470
7.120977
18.00
30.9750
34.50
39.7000
71.00
▂▇▃▁▁
numeric
EDAD_MEDIA_HOMBRES
256
0.8546281
NA
NA
NA
NA
NA
36.840399
8.719029
18.00
31.0000
36.00
42.2000
73.00
▂▇▅▁▁
numeric
EDAD_MEDIA_MUJERES
358
0.7967064
NA
NA
NA
NA
NA
34.330934
7.548873
18.00
29.4000
33.50
38.5000
68.00
▃▇▃▁▁
numeric
P_HOMBRES
91
0.9483248
NA
NA
NA
NA
NA
51.223910
32.037936
0.00
25.0000
50.00
76.5675
100.00
▇▇▇▆▇
numeric
P_MUJERES
91
0.9483248
NA
NA
NA
NA
NA
48.776096
32.037939
0.00
23.4325
50.00
75.0000
100.00
▇▆▆▇▆
3.2 El problema de los NA´s
Dos de las variables tipo character y nueve de las variables tipo numeric presentan valores NA.
Vamos a centrarnos en esto, debemos de hacer algo con esos valores NA:
Code
#buscando algunos NA en la variables alumnos_grado %>%skim() %>%filter(n_missing >0)
Data summary
Name
Piped data
Number of rows
1761
Number of columns
18
_______________________
Column type frequency:
character
2
numeric
11
________________________
Group variables
None
Variable type: character
skim_variable
n_missing
complete_rate
min
max
empty
n_unique
whitespace
CENTRO
32
0.98
4
44
0
64
0
RAMA_DE_CONOCIMIENTO
32
0.98
11
29
0
5
0
Variable type: numeric
skim_variable
n_missing
complete_rate
mean
sd
p0
p25
p50
p75
p100
hist
NOTA_MEDIA
90
0.95
6.70
1.02
0.51
6.44
6.91
7.25
9.60
▁▁▁▇▁
P_SUSPENSOS
69
0.96
14.88
10.57
0.00
7.17
13.70
20.91
100.00
▇▃▁▁▁
P_APROBADOS
69
0.96
31.12
12.96
0.00
23.08
33.06
40.89
100.00
▃▇▅▁▁
P_NOTABLES
69
0.96
24.09
12.54
0.00
15.66
25.00
33.15
100.00
▅▇▁▁▁
P_SOBRESALIENTES
69
0.96
7.60
6.27
0.00
2.88
6.67
11.01
42.90
▇▅▁▁▁
P_MATRICULAS
69
0.96
2.50
3.30
0.00
0.00
1.53
3.64
37.75
▇▁▁▁▁
EDAD_MEDIA_GLOBAL
93
0.95
35.51
7.12
18.00
30.98
34.50
39.70
71.00
▂▇▃▁▁
EDAD_MEDIA_HOMBRES
256
0.85
36.84
8.72
18.00
31.00
36.00
42.20
73.00
▂▇▅▁▁
EDAD_MEDIA_MUJERES
358
0.80
34.33
7.55
18.00
29.40
33.50
38.50
68.00
▃▇▃▁▁
P_HOMBRES
91
0.95
51.22
32.04
0.00
25.00
50.00
76.57
100.00
▇▇▇▆▇
P_MUJERES
91
0.95
48.78
32.04
0.00
23.43
50.00
75.00
100.00
▇▆▆▇▆
Nos centramos primero en las variables tipo caracter que tienen los NA´s:
Code
#buscando NA en las variables tipo caracter which (is.na(alumnos_grado$CENTRO))
Todas son consecutivas, y todas coinciden con la variable CAMPUS cuando toma el vamos de CC. PENITENCIARIOS. No tiene asignado ningún valor tanto en la variable CENTRO como en la variable RAMA_DE_CONOCIMIENTO. Vamos a rellenar entonces la variable CENTRO en función de la variable CAMPUS. Cuando CAMPUS toma el valor CC. PENITENCIARIOS crearemos el valor CC. PENITENCIARIOS tambien en la variable CENTRO
Code
#rellenamos el valor de la variable CENTRO en funcion del CAMPUSalumnos_grado <- alumnos_grado %>%mutate (CENTRO =ifelse(is.na(CENTRO) & CAMPUS =="CC. PENITENCIARIOS","CC. PENITENCIARIOS", CENTRO ) )
La variable RAMA_DE_CONOCIMIENTO la trabajaremos más tarde.
Proseguimos con las variables numéricas. Las últimas variables son la proporción de hombres y la proporción de mujeres, expresada en tanto por ciento. Pero una es combinación lineal de otra, por lo que queremos una sola variable que exprese ese porcentaje.
Por otra parte tambien nos faltan valores en la EDAD_MEDIA_HOMBRES, una de nuestras principales variables de estudio; se nos ocurre que si la variable está vacía, pero la proporción de hombres es el 100% , entonces la media de edad será la misma (si existe) que la EDAD_MEDIA_GLOBAL, y lo mismo para la variable EDAD_MEDIA_MUJERES:
Code
#resolviendo NA´s de la edad en base a las otras variables alumnos_grado <- alumnos_grado %>%mutate(EDAD_MEDIA_HOMBRES =ifelse(is.na(EDAD_MEDIA_HOMBRES) & P_MUJERES ==100.00,mean (EDAD_MEDIA_HOMBRES, na.rm =TRUE), EDAD_MEDIA_HOMBRES)) alumnos_grado <- alumnos_grado %>%mutate( EDAD_MEDIA_MUJERES =ifelse(is.na(EDAD_MEDIA_MUJERES) & P_HOMBRES ==100.00,mean (EDAD_MEDIA_MUJERES, na.rm =TRUE), EDAD_MEDIA_MUJERES))
Vamos a buscar ahora los alumnos que no tienen NOTA_MEDIA:
Code
#revisamos ahora los alumnos que no tienen nota mediawhich (is.na(alumnos_grado$NOTA_MEDIA))
hist (alumnos_grado$NOTA_MEDIA,breaks =40, col ="salmon",main ="Histograma de la variable Nota Media",xlab ="Nota media", ylab ="Frecuencia")
Code
summary (alumnos_grado$NOTA_MEDIA, na.rm =TRUE)
Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
0.51 6.44 6.91 6.70 7.25 9.60 90
Code
sd (alumnos_grado$NOTA_MEDIA, na.rm =TRUE)
[1] 1.02367
Estos no son registros consecutivos, y ocurre además que si lo imputamos mediante un algoritmo no va a cambiar su distribución, por lo que nos da igual. Si le imputamos a los NA el valor de la media vamos a romper la distribución diciendo que (X alumos que no tenian nota ahora tienen de nota la nedia).
¿De cuantos alumnos hablamos? Porque hemos partido de un total de 119023 alumnos:
Code
casos_incompletos <- alumnos_grado %>%filter (is.na(alumnos_grado$NOTA_MEDIA)) #visualizamos el del dataframe con los cambios realizadoskable(head (casos_incompletos)) %>%kable_styling(bootstrap_options ="striped", full_width = F)
CAMPUS
CENTRO
RAMA_DE_CONOCIMIENTO
NIVEL_ESTUDIOS
TITULACION
MATRICULADOS
N_ESTUDIANTES_NUEVOS
NOTA_MEDIA
P_SUSPENSOS
P_APROBADOS
P_NOTABLES
P_SOBRESALIENTES
P_MATRICULAS
EDAD_MEDIA_GLOBAL
EDAD_MEDIA_HOMBRES
EDAD_MEDIA_MUJERES
P_HOMBRES
P_MUJERES
CAMPUS ESTE-CENTRO
CIUDAD REAL "Lorenzo Luzuriaga"
INGENIERÍAS
GRADO
6805 - GRADO EN INGENIERÍA DE LA ENERGÍA
1
1
NA
NA
NA
NA
NA
NA
35.0
35
34.33093
100
0
CAMPUS ESTE-CENTRO
CUENCA
CIENCIAS EXPERIMENTALES
GRADO
6103 - GRADO EN QUÍMICA
2
1
NA
NA
NA
NA
NA
NA
53.0
53
34.33093
100
0
CAMPUS ESTE-CENTRO
CUENCA
CIENCIAS EXPERIMENTALES
GRADO
6104 - GRADO EN FÍSICA
2
0
NA
NA
NA
NA
NA
NA
NA
NA
NA
NA
NA
CAMPUS ESTE-CENTRO
DENIA
INGENIERÍAS
GRADO
6803 - GRADO EN INGENIERÍA MECÁNICA
3
3
NA
NA
NA
NA
NA
NA
41.0
41
34.33093
100
0
CAMPUS ESTE-CENTRO
DENIA
INGENIERÍAS
GRADO
6805 - GRADO EN INGENIERÍA DE LA ENERGÍA
2
2
NA
30
0
0
0
0
40.0
40
34.33093
100
0
CAMPUS ESTE-CENTRO
GUADALAJARA
INGENIERÍAS
GRADO
6805 - GRADO EN INGENIERÍA DE LA ENERGÍA
2
2
NA
NA
NA
NA
NA
NA
35.5
47
24.00000
50
50
Code
sum (casos_incompletos$MATRICULADOS)
[1] 234
Podemos permitirnos perder 90 registros (o 234 alumnos). Pero ademas en esta tabla de casos incompletos tambien hemso observado que la mayoría de los centros tienen muy pocos alumnos. Elegimos entonces los alumnos que tengan nota media y ademas establezcamos otro flitro de al menos 5 alumnos tambien y veamos si el resultado es aceptable:
Code
#eliminando centros cuyos alumnos no tienen nota alumnos_grado <- alumnos_grado %>%filter (NOTA_MEDIA >=0) #eliminando centros con menos de 5 alumnos alumnos_grado <- alumnos_grado %>%filter (MATRICULADOS >5) sum (alumnos_grado$MATRICULADOS)
[1] 118125
De momento hemos perdido un 0.8% de datos. Veamos todavía como estamos de datos faltantes:
Code
#buscando algunos NA en la variables alumnos_grado %>%skim() %>%filter(n_missing >0)
Data summary
Name
Piped data
Number of rows
1470
Number of columns
18
_______________________
Column type frequency:
character
1
numeric
5
________________________
Group variables
None
Variable type: character
skim_variable
n_missing
complete_rate
min
max
empty
n_unique
whitespace
RAMA_DE_CONOCIMIENTO
17
0.99
11
29
0
5
0
Variable type: numeric
skim_variable
n_missing
complete_rate
mean
sd
p0
p25
p50
p75
p100
hist
EDAD_MEDIA_GLOBAL
14
0.99
35.65
6.62
18
31.20
34.70
39.60
71
▂▇▃▁▁
EDAD_MEDIA_HOMBRES
13
0.99
36.95
8.10
18
31.80
36.84
41.60
73
▂▇▃▁▁
EDAD_MEDIA_MUJERES
14
0.99
34.45
7.03
18
30.37
34.33
38.00
68
▂▇▃▁▁
P_HOMBRES
13
0.99
48.91
29.57
0
25.00
50.00
71.43
100
▇▇▇▆▆
P_MUJERES
13
0.99
51.09
29.57
0
28.57
50.00
75.00
100
▆▇▇▇▆
Y vamos a volver a recortar los 14 registros que no tienen nota media (y que si lo revisamos ademas son los mismos a los que le falta el resto de registros):
Code
alumnos_grado <- alumnos_grado %>%filter (EDAD_MEDIA_GLOBAL >=0) #buscando algunos NA en la variables alumnos_grado %>%skim() %>%filter(n_missing >0)
Data summary
Name
Piped data
Number of rows
1456
Number of columns
18
_______________________
Column type frequency:
character
1
________________________
Group variables
None
Variable type: character
skim_variable
n_missing
complete_rate
min
max
empty
n_unique
whitespace
RAMA_DE_CONOCIMIENTO
17
0.99
11
29
0
5
0
Code
sum (alumnos_grado$MATRICULADOS)
[1] 118002
Y tenemos algo mas del 99% de los alumnos (118002). Solo nos quedan los casos incompletos de la variable tipo character. En este caso, podríamos hacer una comparativa que vaya rellenando la RAMA_DE_CONOCIMIENTO en función de la variable TITULACION. Pero en este caso vamos a ejecutar un algoritmo de imputación de datos (que hace lo mismo básicamente) para hacerlo de forma predictiva:
Code
# recodificamos las variables tipo caracter a factor alumnos_grado <-strings2factors(alumnos_grado) #car
The following character variables were converted to factors
CAMPUS CENTRO RAMA_DE_CONOCIMIENTO NIVEL_ESTUDIOS TITULACION
Code
#rellenando valores NA´s usando el algoritmo MICE #ejecutando mice, creando modelo predictivo vartemporales <-mice (alumnos_grado, m =1, method ="pmm", seed =10) #creando los modelos predictivos
Lo primero que hemos hecho es recodificar todas las variables a tipo factor. Esto lo hemos hecho con la instruccion strings2factor de la librería car (Fox & Weisberg, 2019) ; igualmente pudieramos haber recodificados las variables una a una.
Despues hemos ejecutado MICE(Buuren & Groothuis-Oudshoorn, 2011) una sola vez (m =1) en todo el dataframe. MICE crea un archivo especial con sus calculos al que hemos llamado vartemporales. Una vez hecho estro, hemos llamado prediccion1 a un nuevo dataframe completando los casos a partir de vartemporales.
Hemos mirado los registros vacios (which is.na) y hemos mirado las frecuencias de la variable RAMA_DE_CONOCIMIENTO en alumnos_grado y en predicción (el primero no está completo y el segundo si) ; por lo que hemos sustituido la variable completa en nuestro dataframe.
Si todo nos ha salido bien, tenemos un dataframe completo para poder pasar proseguir con nuestro análisis:
Code
#visualizamos el resumen del dataframe con los cambios realizados kable(skim (alumnos_grado)) %>%kable_styling(bootstrap_options ="striped", full_width = F)
skim_type
skim_variable
n_missing
complete_rate
factor.ordered
factor.n_unique
factor.top_counts
numeric.mean
numeric.sd
numeric.p0
numeric.p25
numeric.p50
numeric.p75
numeric.p100
numeric.hist
factor
CAMPUS
0
1
FALSE
7
CAM: 377, SUR: 363, CAM: 343, CAM: 285
NA
NA
NA
NA
NA
NA
NA
NA
factor
CENTRO
0
1
FALSE
65
ALZ: 30, BAR: 30, CAR: 30, LES: 30
NA
NA
NA
NA
NA
NA
NA
NA
factor
RAMA_DE_CONOCIMIENTO
0
1
FALSE
5
CIE: 677, HUM: 334, ING: 202, CIE: 179
NA
NA
NA
NA
NA
NA
NA
NA
factor
NIVEL_ESTUDIOS
0
1
FALSE
1
GRA: 1456
NA
NA
NA
NA
NA
NA
NA
NA
factor
TITULACION
0
1
FALSE
30
660: 66, 650: 65, 620: 64, 630: 61
NA
NA
NA
NA
NA
NA
NA
NA
numeric
MATRICULADOS
0
1
NA
NA
NA
81.045330
199.7098841
6.00
15.0000
33.00000
75.0000
4911.00
▇▁▁▁▁
numeric
N_ESTUDIANTES_NUEVOS
0
1
NA
NA
NA
24.206044
58.1943667
1.00
4.0000
9.00000
22.0000
1375.00
▇▁▁▁▁
numeric
NOTA_MEDIA
0
1
NA
NA
NA
6.706854
0.9568415
0.51
6.5100
6.91000
7.2200
8.71
▁▁▁▇▅
numeric
P_SUSPENSOS
0
1
NA
NA
NA
15.438826
9.7453683
0.00
8.1775
14.11500
21.0950
65.31
▇▇▂▁▁
numeric
P_APROBADOS
0
1
NA
NA
NA
32.825666
11.1783840
0.00
25.9300
34.40000
41.4575
66.92
▁▃▇▅▁
numeric
P_NOTABLES
0
1
NA
NA
NA
25.650474
11.0483391
0.00
18.3200
26.09000
33.8125
58.75
▂▆▇▅▁
numeric
P_SOBRESALIENTES
0
1
NA
NA
NA
8.146861
5.9876663
0.00
3.9000
7.14500
11.3400
42.90
▇▅▁▁▁
numeric
P_MATRICULAS
0
1
NA
NA
NA
2.673482
3.1085352
0.00
0.3675
1.79000
3.9125
37.75
▇▁▁▁▁
numeric
EDAD_MEDIA_GLOBAL
0
1
NA
NA
NA
35.645192
6.6198632
18.00
31.2000
34.70000
39.6000
71.00
▂▇▃▁▁
numeric
EDAD_MEDIA_HOMBRES
0
1
NA
NA
NA
36.947270
8.1007977
18.00
31.8000
36.84040
41.6000
73.00
▂▇▃▁▁
numeric
EDAD_MEDIA_MUJERES
0
1
NA
NA
NA
34.454592
7.0281869
18.00
30.3750
34.33093
38.0000
68.00
▂▇▃▁▁
numeric
P_HOMBRES
0
1
NA
NA
NA
48.945653
29.5547372
0.00
25.0000
50.00000
71.4300
100.00
▇▇▇▆▆
numeric
P_MUJERES
0
1
NA
NA
NA
51.054354
29.5547406
0.00
28.5700
50.00000
75.0000
100.00
▆▇▇▇▆
Y no tenemos ya ningún NA, nuestras variables son tipo factor o numéricas, y podemos proseguir. Limpiamos el entorno de variables y dataframes que no necesitamos:
Code
#limpiando el entorno rm (casos_incompletos, prediccion1, vartemporales)
3.3 Recodificando variables
Ahora es buena idea que algunas de las variables numéricas las pasemos a factor, para trabajar despues con ellas a nuestra conveniencia, como variable discreta o como factor, según necesitemos un tipo de datos u otros:
Code
#recoficando los centros por numero de alumnos matriculados en tramos de 200 alumnos_grado$MATRICULADOS_F <-cut (alumnos_grado$MATRICULADOS, breaks =c(-Inf, 200, 400, 600, 800, 1000, +Inf), right =FALSE, labels =c("De 1 a 199", "De 200 a 399","de 400 a 599", "De 600 a 799","De 800 a 999","Mas de 1000"))
Creamos una variable nueva llamada MATRICULADOS_F. Es de tipo factor, y comprende los centros por tramos de alumnos de sde 0 y 200 en 200, y a partir de 1000 el resto (que son pocos). La distribución de frecuencias que presenta queda asi:
Code
CrossTable((alumnos_grado$MATRICULADOS_F), format ="SPSS")
Cell Contents
|-------------------------|
| Count |
| Row Percent |
|-------------------------|
Total Observations in Table: 1456
| De 1 a 199 | De 200 a 399 | de 400 a 599 | De 600 a 799 | De 800 a 999 |
|--------------|--------------|--------------|--------------|--------------|
| 1348 | 63 | 19 | 10 | 5 |
| 92.582% | 4.327% | 1.305% | 0.687% | 0.343% |
|--------------|--------------|--------------|--------------|--------------|
| Mas de 1000 |
|--------------|
| 11 |
| 0.755% |
|--------------|
Vemos que un 92% de los centros tienen entre 5 y 200 alumnos (porque habiamos filtrado antes los centros con menos de 5).
Recodificamos ahora las variables EDAD_MEDIA_HOMBRES y EDAD_MEDIA_MUJERES, creando 4 tramos, desde la edad minima hasta 35, que serán los jóvenes, desde 35 a 50, que serán los adultos (o adultas), de 50 a 65 los llamaremos maduros (o maduras) , y desde 65 en adelante serán seniors
Code
#recodificando la edad de los alulmnos a factor alumnos_grado$EDAD_MEDIA_HOMBRES_F <-cut (alumnos_grado$EDAD_MEDIA_HOMBRES, breaks =c(-Inf, 35, 50, 65, +Inf), right =FALSE,labels =c("jovenes", "adultos", "maduros", "seniors")) #recodificando la edad de los alulmnos a factoralumnos_grado$EDAD_MEDIA_MUJERES_F <-cut (alumnos_grado$EDAD_MEDIA_MUJERES, breaks =c(-Inf, 35, 50, 65, +Inf), right =FALSE, labels =c("jovenes", "adultas", "maduras", "seniors"))
Asi vemos un histograma doble, con la distribución de frecuencias de la edad media tanto de los hombres y de las mujeres, donde las lineas verticales representan los cortes que hemos realizado. Asi la variable ahora tiene cuatro tramos:
Code
#histograma edad y cortes hist (alumnos_grado$EDAD_MEDIA_HOMBRES, main ="Tramos de edad", breaks =30, col=rgb(0, 0, 1, alpha=0.2), xlab ="Edad Media", ylab ="Frecuencia") abline (v =35, col ="red", lwd =2) abline (v =50, col ="blue", lwd =2)abline (v =65, col ="green", lwd =2) hist (alumnos_grado$EDAD_MEDIA_MUJERES,add =TRUE, breaks =30, col=rgb(0, 1, 0, alpha=0.4))
Donde ya pondemos comenzar a apreciar que la distribución de edad de los hombres es mayor a simple vista que en las mujeres. Lo analizaremos más adelante.
Igualmente se recodifica la variable de NOTA_MEDIA, en tramos de suspenso, aprobado, notable y sobresaliente. No hay ningún tramo de la variable con sobresaliente, porque obviamente el propio dataframe ya es un resumen estadístico de medias de los estudiantes.
Code
#recodificamos la nota media tambien a factor alumnos_grado$NOTA_MEDIA_F <-cut (alumnos_grado$NOTA_MEDIA, breaks =c(-Inf,5, 7, 9, +Inf),right =FALSE, labels =c("Suspenso", "Aprobado", "Notable", "Sobresliente"))
Y nos queda de esta forma:
Code
#histograma de la nota media hist (alumnos_grado$NOTA_MEDIA, main ="Tramos de edad", breaks =30,col="lightblue", xlab ="Nota Media", ylab ="frecuencia") abline (v =5, col ="red", lwd =2)abline (v =7, col ="blue", lwd =2) abline (v =9, col ="green", lwd =2)
Por último teníamos una combinación lineal de dos variables, la proporción de hombres y la de mujeres (cualquiera de ellas será 100% menos la otra variable) . vamos a recodificar una sola columna, en tramos de 20%. Asi, si la proporción de hombres es del 20% podemos decir que la proporción de mujeres es del 80% y no necesitamos las dos variables para esto. Asi que los factores serán mas del 80% mujeres, mas del 60% mujeres, igualdad de sexo (entre 40 y 60%, mas del 60% de hobres y más del 80% de hombres.
Code
#eliminamos la combinacion lineal de porporciion de hombres y mujeres #recodificando una de ellas creando una nueva variable factor. alumnos_grado$PROP_H_M <-cut (alumnos_grado$P_HOMBRES, breaks =c(-Inf, 20, 40, 60, 80, +Inf), right =FALSE, labels =c( "> 80% mujeres", "> 60% mujeres", "igualdad de sexos", "> 60% hombres", "> 80% hombres"))
Vemos como queda la distribucion de frecuencias de los factores y eliminamos las dos columnas P_HOMBRES y P_MUJERES:
Code
#distribucion de frecuencias CrossTable (alumnos_grado$PROP_H_M, format ="SPSS")
#y ahora eliminanos las dos columas P_HOBRES y P_MUJERES alumnos_grado$P_HOMBRES <-NULLalumnos_grado$P_MUJERES <-NULL
Observamos como se reparte las preferencias por sexos a favor del sexo femenino, con más del 40% de mayoría de alumnos, frente al 21% de titulaciones que tiene una igualdad de sexos, y el resto serían las titulaciónes con mayoría de hombres.
Y ya nos queda para finalizar este capítulo ver como ha quedado nuestro dataframe:
Code
#visualizamos el resumen del dataframe con los cambios realizados kable(head (alumnos_grado)) %>%kable_styling(bootstrap_options ="striped", full_width = F)
CAMPUS
CENTRO
RAMA_DE_CONOCIMIENTO
NIVEL_ESTUDIOS
TITULACION
MATRICULADOS
N_ESTUDIANTES_NUEVOS
NOTA_MEDIA
P_SUSPENSOS
P_APROBADOS
P_NOTABLES
P_SOBRESALIENTES
P_MATRICULAS
EDAD_MEDIA_GLOBAL
EDAD_MEDIA_HOMBRES
EDAD_MEDIA_MUJERES
MATRICULADOS_F
EDAD_MEDIA_HOMBRES_F
EDAD_MEDIA_MUJERES_F
NOTA_MEDIA_F
PROP_H_M
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS EXPERIMENTALES
GRADO
6101 - GRADO EN CIENCIAS AMBIENTALES
23
4
7.79
2.04
27.04
39.29
22.45
1.02
32.8
35.0000
30.5
De 1 a 199
adultos
jovenes
Notable
igualdad de sexos
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS EXPERIMENTALES
GRADO
6102 - GRADO EN MATEMÁTICAS
22
7
5.32
27.60
29.69
16.15
8.85
0.00
28.9
29.0000
28.0
De 1 a 199
jovenes
jovenes
Aprobado
> 80% hombres
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS EXPERIMENTALES
GRADO
6103 - GRADO EN QUÍMICA
13
4
5.98
6.25
25.00
6.25
4.17
4.17
35.5
36.8404
35.5
De 1 a 199
adultos
adultas
Aprobado
> 80% mujeres
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS EXPERIMENTALES
GRADO
6104 - GRADO EN FÍSICA
13
4
6.99
22.73
29.80
15.15
9.60
0.00
33.0
33.0000
33.0
De 1 a 199
jovenes
jovenes
Aprobado
igualdad de sexos
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS DE LA SALUD
GRADO
6201 - GRADO EN PSICOLOGÍA
367
109
6.76
30.58
43.53
20.94
4.22
0.56
32.1
33.8000
31.5
De 200 a 399
jovenes
jovenes
Aprobado
> 60% mujeres
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS SOCIALES Y JURÍDICAS
GRADO
6301 - GRADO EN EDUCACIÓN SOCIAL
49
9
7.28
15.44
33.74
41.80
8.27
0.75
33.4
49.0000
31.5
De 1 a 199
adultos
jovenes
Notable
> 80% mujeres
Donde vemos, a la derecha del desplegable, las variables que hemos añadido del tipo factor que segmentan la poblacion objeto del estudio.
4 Analizando las variables
Completado ya el analisis exploratorio de los datos y habiendo suprimido los NA y modificado o creado el resto de variables, podemos comenzar nuestro análisis. Para esta parte del analisis, le diremos a R que memorize todas nuestras variables con el comando attach, y crearemos tambien la base gráfica, a fin de simplificar el código (pero ninguno de estos pasos es obligatorio)
Code
#memorizando variables attach (alumnos_grado) #comparando variables de estudio: edad, nota media y sexo #base grafica base <-ggplot (data = alumnos_grado)
4.1 Nota media y Edad
Podríamos preguntarnos si existe una correlación entre la nota media y la edad.
Ver algo de forma gráfica nos puede aportar siempre algunos indicios de como es una variable, de como se comporta y poder iniciar un estudio. Veamos entonces un gráfico donde se relaciona la edad media global con la nota media, en este caso como factor. la librería ggplot2 aporta siempre elegantes y comprensibles gráficos Wickham (2016). No la hemos visto cargada en el inicio porque se incluye por defecto con el paquete de librerías tydiverse
Code
#Boxplot de la edad media global y la nota media como factorbase +geom_boxplot (aes(x = EDAD_MEDIA_GLOBAL, fill =factor(NOTA_MEDIA_F)), alpha =0.80) +ggtitle ("BoxPlot de la edad media global y nota media")
A simple vista, parece que a medida que aumenta la edad, aumenta la nota (esto podría ser una correlación); no solo es que aumente la media, es que incluso el rango intercuartílico se desplaza entero. Pero claro, aqui se encuentra la media de la edad de toda la población, asi que primero queremos saber si la edad de hombres y mujeres (su media) es igual, para lo que vamos a hacer un test de contraste de medias. Ya habiamos visto en un histograma anterior que no parecia. La hipótesis nula sería las medias de edad de hombres y mujeres son iguales.
Code
#contrastes entre variable ¿Son iguales las medias de edad?t.test (EDAD_MEDIA_HOMBRES, EDAD_MEDIA_MUJERES, alternative =c("two.sided"), conf.level =0.95)
Welch Two Sample t-test
data: EDAD_MEDIA_HOMBRES and EDAD_MEDIA_MUJERES
t = 8.8688, df = 2853.2, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
1.941572 3.043784
sample estimates:
mean of x mean of y
36.94727 34.45459
El test no puede verificar que la hipotesis nula sea cierta, por lo que la hipótesis alternativa (no son iguales) seria más correcta. De hecho, la media de los hombres, según el test, es entre 1,94 y 3,04 años mayor que las de las mujeres, con una confianza del 95%. La media de edad de los hombres es de 36,95 años y la media de edad de las mujeres des de 34,45 años. Por lo tanto vamos a comparar por separado la edad de ambos grupos y la nota media, por si hubiese diferencias.
Invertimos ahora el Boxplot para mostrar la nota media como variable discreta y la edad de los hombres como factor:
Code
#Boxplot de la nota media frente al factor edad hombresbase +geom_boxplot (aes(x = NOTA_MEDIA, fill =factor(EDAD_MEDIA_HOMBRES_F)), alpha =0.50) +ggtitle ("BoxPlot de la nota media con el factor Hombres")
Y en en caso de las mujeres:
Code
#Boxplot de la nota media frente al factor mujer base +geom_boxplot (aes(x = NOTA_MEDIA, fill =factor(EDAD_MEDIA_MUJERES_F)),alpha =0.50) +ggtitle ("BoxPlot de la nota media frente al factor mujer")
De hecho incluso parece que la nota media de las mujeres es ligeramente superior. Vamos a ver la parte estadística para poder verificar esto: elaboremos dos resumenes estadísticos basicos, cruzando los datos por el factor edad en la nota media tanto en hombres como mujeres:
Code
#elaborando un cuadro resumen aggregate (NOTA_MEDIA~EDAD_MEDIA_MUJERES_F, FUN = summary)
Pero observamos que se comportan de una forma muy similar, les separan décimas, pero es ligéramente superior por unas décimas en las mujeres A veces unas décimas o centesimas son importantes, porque por ejemplo en el grupo de maduros y maduras, de 50 a 65 años, ellas tendrian una media de NOTABLE con 7.02, mientras que ellos tendrían un APROBADO con 6.94.
Igual podemos cruzar las frecuencias relativas de las variables como factor, con los grupos que hemos creado, tanto en los hombres. Crosstable pertenece a la libreria gmodels(Warnes et al., 2022), y aporta mejor información y opciones que table
Code
#edad media hombres (factor) segun la nota media de los alumnos (factor)CrossTable (EDAD_MEDIA_HOMBRES_F, NOTA_MEDIA_F, digits =2,format ="SPSS")
Y la tendencia sigue siendo la misma, que veiamos con los datos anteriores. Aqui observamos las frecuencias relativas (por filas y por columnas) y la frecuencia total.
Visto esto, si parece que podemos considerar la edad media global fiable ya que los grupos de los que proviene se comportan de una manera muy similar, aunque no son iguales. Pero si sumamos dos variables con una distribución normal, el resultado será otra variable con una distribución normal. Esto se puede visualizar buscando la correlación entre estas variables. Nos gusta usar la librería pysch (2023) para esto, porque resume muchos datos a la vez:
Code
#correlacion pairs.panels(alumnos_grado[c(8,14:16)],main ="Correlación entre nota y medias de edad")
El valor de la correlación entre la edad media global y la edad media de los hombres es de 0.75, y la edad media global y la edad media de las mujeres es de 0.69; por lo que se confirma lo que comentabamos anteriormente.
Igualmente ocurre si estudiamos la correlación entre la edad media global y la nota media de los alumnos, añadiendo todas las columnas que comprenden el porcentaje que comprenden los aprobados, suspensos, notables, matriculas…. y aunque estén expresados en porcentaje lo podemos comparar a efectos de correlación para ver que la nota media es una suma de todas las otras:
Code
#mas correlacionpairs.panels(alumnos_grado[c(8:14)], main ="Correlación entre la edad media y todas las notas")
Lo que nos lleva al siguiente capítulo.
4.2 Correlación
Los datos que hemos visto apuntan a una relación entre la edad y la nota media, en el sentido de que “a mas edad, mejor nota”. Pues vamos a buscar entonces la explicación científica (si existe) a esto, o realmente esto algo casual y no causa-efecto.
Estudiemos las variables. Queremos saber si su distribución adopta alguna forma Por el tipo de datos, vemos la forma habitual de campana de una distribución normal N(0,1), por lo que vamos a relizar los test correspondientes a ambas variables:
Code
#comprobando normalidad de las variables #test de normalidadshapiro.test(EDAD_MEDIA_GLOBAL)
Shapiro-Wilk normality test
data: EDAD_MEDIA_GLOBAL
W = 0.96788, p-value < 2.2e-16
Code
shapiro.test(NOTA_MEDIA)
Shapiro-Wilk normality test
data: NOTA_MEDIA
W = 0.80185, p-value < 2.2e-16
Donde una W muy cercana a 1 y un p-valor muy inferior a 0.05 nos confirman que las variables son de tipo normal. Una comprobación gráfica la podemos ver con un histograma y un qqPlot , tambien de la librería car, de ambas variables, donde los puntos representan la variable real y la linea el ajuste ideal teorico (la N(0,1). Mientras más se acerquen, mas predecible será su comportamiento:
Code
#mirando histogramas de las variables par (mfrow =c(2, 2)) hist (EDAD_MEDIA_GLOBAL, main ="Distribución de la edad",col ="lightblue", breaks =40) qqPlot(EDAD_MEDIA_GLOBAL,col ="lightblue",distribution ="norm", envelope =0.95)
[1] 661 1185
Code
hist (NOTA_MEDIA, main ="Distribución de nota media",col ="salmon", breaks =40) qqPlot(NOTA_MEDIA, col ="salmon", distribution ="norm", envelope =0.95)
[1] 453 106
Code
par (mfrow =c(1, 1))
Ya que las distribuciones normales presentan ciertas características especiales frente a otro tipo de distribuciones, podemos buscar una correlacción entre ellas. Habiamos visto en los paneles de correlación que el la edad presentaba una correlación entre debil y moderara desde -0,07 y 0,29. La correlación entre las variables globales es de 0.15, pero lo volvemos a comprobar ejecutando primero un test estadístico que nos confirme la correlación entre ambas:
Pearson's product-moment correlation
data: EDAD_MEDIA_GLOBAL and NOTA_MEDIA
t = 5.916, df = 1454, p-value = 4.106e-09
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.1027502 0.2030869
sample estimates:
cor
0.1533137
Nos aporta un coeficiente de 0.15 (muy debil). Pero sabemos que estamos ante un dataframe muy sesgado, ya que algunos registros aportan los datos mas de 1000 alumnos matriculados, mientras que muchos otros presentan un número muy bajo, asi que seguimos investigando esta correlación.
Aprobados y notables son los que más frecuencia tienen, según parece en los paneles de correlación, y tienen más correlación, aportarían más peso. La “nube” de puntos de la edad y la nota media de forma global tendrá esta forma:
Code
#visualizando una posible correlacion de forma graficaggplot(alumnos_grado, aes(x = NOTA_MEDIA, y = EDAD_MEDIA_GLOBAL)) +geom_point() +geom_smooth(method ="lm", se =FALSE, color ="red")
`geom_smooth()` using formula = 'y ~ x'
Y como comentabamos antes, las distancias a la linea roja se irían anulando por distancias en los puntos tanto por arriba como por abajo, por las propiedades de la distribución. De todas formas Vamos a filtrar estos datos, y vamos a coger, por ejemplo solo los registros que tengan un numero maor de 100 alumnos matriculados. Además ahora vamos a usar plotly, (Sievert, 2020) que aporta gráficos interactivos, pero convirtiento un ggplot directamente:
Code
#filtrando el dataframe por el numero de alumnos matriculados añadimos plotlyggplotly (ggplot(alumnos_grado %>%filter (MATRICULADOS >100),aes(x = NOTA_MEDIA, y = EDAD_MEDIA_GLOBAL)) +geom_point() +geom_smooth(method ="lm", se =TRUE, color ="red")+ggtitle("Correlacion Edad y Nota media"))
`geom_smooth()` using formula = 'y ~ x'
Misma distribución, mas centrada. Probemos a hacer una regresión lineal para este caso concreto, que parece que se ajustará mejor:
Code
#haciendo una prueba, creando una regresion lineal simple DF_regresion <- alumnos_grado %>%filter (MATRICULADOS >100)relacion_nota_edad <-lm (DF_regresion$NOTA_MEDIA~DF_regresion$EDAD_MEDIA_GLOBAL)
La formula del tipo Y = A +bX que nos diría la nota medía (Y) en función de la edad (X) sería :
Nota Media = 5,9490 + 0.02 * Edad
Es decir que una persona con 50 años (yo) tendrá de nota media 5,9490 + 0.02*50 = 6.949. Es decir que o estudio más o ¡me espero cuatro años más para tener un notable!
Miramos un poco más la regresión nos interesa que los R y , R^2 y los residuos sean lo más próximo a cero para validar la fórmula:
Code
#mirando un poco mas a fondo summary (relacion_nota_edad)
Call:
lm(formula = DF_regresion$NOTA_MEDIA ~ DF_regresion$EDAD_MEDIA_GLOBAL)
Residuals:
Min 1Q Median 3Q Max
-0.99170 -0.19008 -0.03394 0.21432 0.94142
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 5.948967 0.162670 36.571 < 2e-16 ***
DF_regresion$EDAD_MEDIA_GLOBAL 0.029600 0.004671 6.337 1.04e-09 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.2971 on 258 degrees of freedom
Multiple R-squared: 0.1347, Adjusted R-squared: 0.1313
F-statistic: 40.15 on 1 and 258 DF, p-value: 1.04e-09
Que es un valor algo alto pero aceptable para poder verificar todo lo visto anteriormente. Nos queda estudiar por último la homocedasticidad, los residuos y el apalancamiento de la regresión. Dado que las distribuciones tenian un p-valor bajo y una W muy alta para una distribución normal, los resultados deben de ser aceptables:
Code
#totalmente experto par (mfcol =c(2,2)) #2 filas, dos columnas plot (relacion_nota_edad) #dibujar la regresión, 4 gráficos
Code
par (mfcol =c(1,1)) #lo dejo como estaba
Y visto esto validariamos esta correlación entre la edad media y la nota media de los alumnos de grado de la UNED del curso 2022-2023 que estabamos intuyendo desde el inicio del analisis. Quitamos de la memoria las variables con detach, y pasamos a otro capítulo.
Code
detach (alumnos_grado)
4.3 Segmentación
Cuando veo un dataframe lo primero que pienso siempre en es si es posible segmentar o clasificar los grupos, en buscar un patrón o algo que los agrupe. Asi que vamos a ello.
Lo primero, volver a crear un grupo de variables que sea de interes para este objetivo. Nos hemos decidido por estas, pero se podría pobrar con otras combinaciones y obtener sorprendentes resultados.
Creamos un nuevo dataframe con 9 variables a nuestra elección:
Code
#intentamos clasificar la poblacion#creando nuevo subrupo subgrupo1 <- alumnos_grado %>%select (CAMPUS, CENTRO, RAMA_DE_CONOCIMIENTO, TITULACION, MATRICULADOS_F, NOTA_MEDIA_F, EDAD_MEDIA_HOMBRES_F, EDAD_MEDIA_MUJERES_F,PROP_H_M)
4.3.1 Importancia de las Variables. Boruta
Pero antes de clasificar queremos ver la importancia de las variables elegidas. Vamos a usar un algoritmo llamado Boruta(Kursa & Rudnicki, 2010) basado en Random Forest, para ver la importancia de cada variable, teniendo en cuenta que hemos elegido como variable objetivo la rama del conocimiento:
Code
#vamos a valorar la importancia de cada variable con el algoritmo Boruta#basado en random forest valoracion <-Boruta (RAMA_DE_CONOCIMIENTO~., data = subgrupo1)valoracion$finalDecision
Y nos dice que para esta variable, rechaza CAMPUS y CENTRO, y nos confirma el resto de variables.
Graficamente, asigna una puntuación a cada variable:
Code
#cambiando tamaño de letras y direcion de las etiquetas para el plot par(cex.axis =0.5, las =2) plot (valoracion, main ="Puntuación de las variables")
Code
#restaurando par (cex.axis =1, las =1) #eliminamos variables subgrupo1$CAMPUS <-NULLsubgrupo1$CENTRO <-NULLsubgrupo1$MATRICULADOS_F <-NULLsubgrupo1$TITULACION <-NULL
Vemos que la RAMA_DE_CONOCIMIENTO y TITULACION son las más importantes. Hemos eliminado CAMPUS y CENTRO del dataframe. Pero además vamos a eliminar MATRICULADOS_F, ya que su puntuación es baja y su distribución es tan asimétrica que nos podría distorsionar los resultados. Asi mismo, valmos a eliminar tambien la variable TITULACION aun siendo la más importante, ya que esta variable está contenida en la RAMA_DE_CONOCIMIENTO como subconjunto de ellas.
4.3.2 Segmentando con kmeans
Vamos a probar a usar el algoritmo kmeans para segmentar el datafreme en función de la variable elegida, la rama del conocimiento, que es una variable tipo factor con 5 niveles que tenemos del dataframe original.
Para este algoritmo (Maechler et al., 2022) hay que trabajar un poco antes de empezar; hay algunas formas sencillas de manejar muchos algoritmos y muy automatizadas, como puede ser el paquete caret, aunque no lo hayamos usado aqui.
Lo primero es convertir todas las variables tipo factor a dummys (Ballings & Van den Poel, 2015). Si la variable coincide con el factor la funcion le asigna el valor 1, y si no contiene ese factor le asigna 0. Esto es porque kmeans no trabaja con variables de tipo factor, como Boruta (o muchos otros), ya que estamos midiendo distancias. Lo que kmeans hace es ver a cuanta distancia estan las variables unas de otras, por eso necesita convertir los factores a 0 y 1. Una vez que mide las distancias (hay varios métodos) busca los centroides, los puntos que son los centros de diferentes variables. Y eso serían los segmentos. Suena todo complicado pero se calcula automáticamente si el dataframe esta bién configurado. Si hubiese variables numéricas habria que normalizarlas mediante una función max-min o normalize, habría que igualarlas para que su “peso” o su ponderación fuera el mismo. como nuestras variables son todas tipo factor, no tenemos que realizar ese paso.
Vamos a realizar una prueba por el método de la suma de cuadrados, a ver cuantos centros encuentra:
Code
######################### Clasificando con k-means <##############################estudio_grupos <-dummy (subgrupo1, int =TRUE)#buscando la k por el metodo de la suma de cuadrados fviz_nbclust(estudio_grupos, kmeans, method ="wss")
Hay que buscar un “codo” en la gráfica, que indica el número óptimo de “k” . k=3 y k 7 parecen candidatos óptimos. Lo más difícil del algoritmo kmeans, al igual que knn, es buscar la k optima.
Miramos ahora otro método, la media de distancia a los centros. Ademas hemos puesto un Boostrap para que lo repita 10 veces , y la k como máximo sea 10:
Code
#buscando k optima en funcion de la distancia media a diferentes centros distancias <-clusGap(estudio_grupos, FUN = kmeans, K.max =10, B =10)
Warning: did not converge in 10 iterations
Code
#dibuja el k optimo segun el metodo elegido anteriormente fviz_gap_stat (distancias)
Code
# dice que el mejor k esta entre 6 y 7
Igualmente coincide se aproxima al optimo de la k por el método anterior. Pues ejecutemos el algoritmo para k=6 y veamos el resultado gráfico (requiere el uso especifico de una de las librerias que hemos cargado al principio (Kassambara & Mundt, 2020) ):
Code
#algoritmo modelo_kmeans <-kmeans (estudio_grupos, 6) #quita columnas constantes o cero para solucionar errores el el plot siguienteestudio_grupos <- estudio_grupos[, apply(estudio_grupos,2, var,na.rm =TRUE) !=0]#mirando los gruposfviz_cluster(modelo_kmeans, data = estudio_grupos, geom =c("point"), main ="Segmentos de Poblacion")
Cada observación se ha clasificado en clusters (grupos) del uno al seis y esta sería la representación gráfica de los cluster creados para la variable RAMA_DE_CONOCIMIENTO en función de las demás. El tamaño de cada grupo es:
Code
#tamaño de los grupos modelo_kmeans$size
[1] 193 394 219 187 150 313
Y lo que hacemos es crear una nueva variable con el numero de cluster, y añadirla como una columna nueva (una variable nueva) al dataframe subgrupo1, con el numero de cluster al que pertenece cada observación, y en cada observación nos aparece la pertenencia al grupo:
Code
#añadiendo la pertenencia al grupo al dataframe grupo <- modelo_kmeans$cluster subgrupo1 <-cbind (grupo, subgrupo1) #mirando el DF kable (head (subgrupo1)) %>%kable_styling(bootstrap_options ="striped", full_width = F)
grupo
RAMA_DE_CONOCIMIENTO
NOTA_MEDIA_F
EDAD_MEDIA_HOMBRES_F
EDAD_MEDIA_MUJERES_F
PROP_H_M
1
CIENCIAS EXPERIMENTALES
Notable
adultos
jovenes
igualdad de sexos
6
CIENCIAS EXPERIMENTALES
Aprobado
jovenes
jovenes
> 80% hombres
2
CIENCIAS EXPERIMENTALES
Aprobado
adultos
adultas
> 80% mujeres
6
CIENCIAS EXPERIMENTALES
Aprobado
jovenes
jovenes
igualdad de sexos
6
CIENCIAS DE LA SALUD
Aprobado
jovenes
jovenes
> 60% mujeres
4
CIENCIAS SOCIALES Y JURÍDICAS
Notable
adultos
jovenes
> 80% mujeres
Veamos los grupos. Creamos un resumen estadistico del grupo 1 para su analisis:
Code
#resumen estadistico basico del grupo 1 subgrupo1 %>%filter(grupo ==1) %>%summary()
Para este cluster, son 193 observaciones. En cuanto a la variable RAMA_DE_CONOCIMIENTO, el algoritmo ha agrupado las titulaciones de Humanidades. Ademas predominan los centros con una media de sus alumnos de Notable, y tambien la edad media de lso hombres es “adultos” (de 35 a 50 años) mientras que la edad predominante en las mujeres es de “jóvenes” (hasta 35 años). No hay un predominio de sexo claro en este grupo.
Pasemos a ver el grupo 2, con 394 observaciones:
Code
#resumen estadistico basico del grupo 2 subgrupo1 %>%filter(grupo ==2) %>%summary()
Este grupo parece heterogeneo, aunque hay mayoría de Ciencias sociales y Jurídicas y humanidades. Por la parte de sexos no hay un predominio claro tampoco, ni en la nota media golbal. La única distinción es que está formado por personas de la clase “adultas” (entre 35 y 50 años) tanto en hombres como mujeres.
Grupo 3, con 219 registros:
Code
#resumen estadistico basico del grupo 3 subgrupo1 %>%filter(grupo ==3) %>%summary()
Está mas definido. vuelven a ser mayoria las Ciencias Sociales y Jurídicas. La nota media en 210 casos de lso 219 es de Aprobado, y la edad media, al igual que venimos viendo en todo el analisis, vuelve a ser mayor en los hombres que en las mujeres (adultos vs jóvenes). La proporción de sexos se mantiene similar a lso subgrupos anteriores, no hay diferencias.
Respecto al grupo 4 son 187 filas del dataframe:
Code
#resumen estadistico basico del grupo 4 subgrupo1 %>%filter(grupo ==4) %>%summary()
grupo RAMA_DE_CONOCIMIENTO NOTA_MEDIA_F
Min. :4 CIENCIAS DE LA SALUD : 1 Suspenso : 1
1st Qu.:4 CIENCIAS EXPERIMENTALES : 0 Aprobado : 0
Median :4 CIENCIAS SOCIALES Y JURÍDICAS:186 Notable :186
Mean :4 HUMANIDADES : 0 Sobresliente: 0
3rd Qu.:4 INGENIERÍAS : 0
Max. :4
EDAD_MEDIA_HOMBRES_F EDAD_MEDIA_MUJERES_F PROP_H_M
jovenes:95 jovenes:163 > 80% mujeres :83
adultos:85 adultas: 20 > 60% mujeres :45
maduros: 5 maduras: 4 igualdad de sexos:31
seniors: 2 seniors: 0 > 60% hombres :18
> 80% hombres :10
Es un segmento muy definido. Son el 100% de los registros pertenecientes a la rama de Ciencias Sociales y Juridicas y en cuyos centros han sacado de media un Notable. Predomina ademas mayoría de mujeres en este segmento, y también de entre ellas las más jóvenes.
Mirando el grupo 5 que comprende a 150 registros:
Code
#resumen estadistico basico del grupo 5 subgrupo1 %>%filter(grupo ==5) %>%summary()
Este último comparte caracteristicas similares al grupo 2: proporción de hombres y mujeres con cierta simetria, mayoría de alumnos jóvenes en ambos sexos, mayoría de aprobados y algo mayor el registro de Ciencias Sociales y Jurídicas, pero es una constante en todo el dataframe.
Podemos valildar la segmentación realizada con kmeans, para un valor de k=6, ya que aunque tengamos 2 grupos heterogéneos, hay cuatro grupos de alumnos muy definidos. Nos llevamos la variable grupo que habíamos creado con kmeans y la incorporamos a nuestro dataframe inicial, el de alumnos_grado, para completar este capítulo
Code
#unir la columna alumnos_grado <-cbind (grupo, alumnos_grado) #ver el DF kable(head (alumnos_grado)) %>%kable_styling(bootstrap_options ="striped", full_width = F)
grupo
CAMPUS
CENTRO
RAMA_DE_CONOCIMIENTO
NIVEL_ESTUDIOS
TITULACION
MATRICULADOS
N_ESTUDIANTES_NUEVOS
NOTA_MEDIA
P_SUSPENSOS
P_APROBADOS
P_NOTABLES
P_SOBRESALIENTES
P_MATRICULAS
EDAD_MEDIA_GLOBAL
EDAD_MEDIA_HOMBRES
EDAD_MEDIA_MUJERES
MATRICULADOS_F
EDAD_MEDIA_HOMBRES_F
EDAD_MEDIA_MUJERES_F
NOTA_MEDIA_F
PROP_H_M
1
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS EXPERIMENTALES
GRADO
6101 - GRADO EN CIENCIAS AMBIENTALES
23
4
7.79
2.04
27.04
39.29
22.45
1.02
32.8
35.0000
30.5
De 1 a 199
adultos
jovenes
Notable
igualdad de sexos
6
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS EXPERIMENTALES
GRADO
6102 - GRADO EN MATEMÁTICAS
22
7
5.32
27.60
29.69
16.15
8.85
0.00
28.9
29.0000
28.0
De 1 a 199
jovenes
jovenes
Aprobado
> 80% hombres
2
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS EXPERIMENTALES
GRADO
6103 - GRADO EN QUÍMICA
13
4
5.98
6.25
25.00
6.25
4.17
4.17
35.5
36.8404
35.5
De 1 a 199
adultos
adultas
Aprobado
> 80% mujeres
6
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS EXPERIMENTALES
GRADO
6104 - GRADO EN FÍSICA
13
4
6.99
22.73
29.80
15.15
9.60
0.00
33.0
33.0000
33.0
De 1 a 199
jovenes
jovenes
Aprobado
igualdad de sexos
6
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS DE LA SALUD
GRADO
6201 - GRADO EN PSICOLOGÍA
367
109
6.76
30.58
43.53
20.94
4.22
0.56
32.1
33.8000
31.5
De 200 a 399
jovenes
jovenes
Aprobado
> 60% mujeres
4
CAMPUS ESTE-CENTRO
ALBACETE
CIENCIAS SOCIALES Y JURÍDICAS
GRADO
6301 - GRADO EN EDUCACIÓN SOCIAL
49
9
7.28
15.44
33.74
41.80
8.27
0.75
33.4
49.0000
31.5
De 1 a 199
adultos
jovenes
Notable
> 80% mujeres
5 Mas datos y más números
Llegamos al final de nuestro pequeño anñalisis, sin dejar de seguir preguntandonos cosas y pensando en formas de cruar los datos y obtener información. Es siempre el mismo problema cuando estoy con R. Dificil establecer el punto y final, porque siempre hay una idea más, una prueba más. hacer lo mismo de una forma diferente…
Ya que hemos segmentado los grupos, nos gustaría saber cuantos alumnos matriculados (del 99% del total de alumnos de Grado con los que estamos trabajando) hay matriculados en cada segmento:
Code
#nomero de alumnos por grupokable (alumnos_grado %>%group_by(grupo) %>%summarise(Total_Matriculados =sum(MATRICULADOS)) %>%arrange(grupo)) %>%kable_styling(bootstrap_options ="striped", full_width = F)
grupo
Total_Matriculados
1
10138
2
32365
3
22140
4
12499
5
4451
6
36409
El grupo 5 era el grupo de hombres que estudian Ingenierias y ciencias experimentales. Los alumnos de ciencias sociales y jurídicas son los más numerosos de cualquier forma que miremos el dataframe- ¿Por qué? Veamos el número de alumnos matriculados por titulación ( de forma global):
Code
#ordenados el numero de alumnos por titulacion kable (alumnos_grado %>%group_by(TITULACION) %>%summarise(Total_Matriculados =sum(MATRICULADOS)) %>%arrange(desc(Total_Matriculados))) %>%kable_styling(bootstrap_options ="striped", full_width = F)
TITULACION
Total_Matriculados
6201 - GRADO EN PSICOLOGÍA
28548
6602 - GRADO EN DERECHO
14542
6701 - GRADO EN GEOGRAFÍA E HISTORIA
6454
6502 - GRADO EN ADMINISTRACIÓN Y DIRECCIÓN DE EMPRESAS
6334
6702 - GRADO EN HISTORIA DEL ARTE
6127
6604 - GRADO EN CRIMINOLOGÍA
5827
6603 - GRADO EN TRABAJO SOCIAL
4644
6301 - GRADO EN EDUCACIÓN SOCIAL
4305
6303 - GRADO EN EDUCACIÓN INFANTIL
3926
7001 - GRADO EN FILOSOFÍA
3866
6402 - GRADO EN ESTUDIOS INGLESES: LENGUA, LITERATURA Y CULTURA
3380
7101 - GRADO EN INGENIERÍA INFORMÁTICA
2812
6102 - GRADO EN MATEMÁTICAS
2731
6401 - GRADO EN LENGUA Y LITERATURA ESPAÑOLAS
2631
6302 - GRADO EN PEDAGOGÍA
2454
6501 - GRADO EN ECONOMÍA
2343
6601 - GRADO EN CC. JURÍDICAS DE LAS ADMINISTRACIONES PÚBLICAS
2132
7002 - GRADO EN ANTROPOLOGÍA SOCIAL Y CULTURAL
2063
6101 - GRADO EN CIENCIAS AMBIENTALES
2055
6901 - GRADO EN CIENCIA POLÍTICA Y DE LA ADMINISTRACIÓN
1899
6104 - GRADO EN FÍSICA
1764
6503 - GRADO EN TURISMO
1600
6103 - GRADO EN QUÍMICA
1369
6902 - GRADO EN SOCIOLOGÍA
1210
6803 - GRADO EN INGENIERÍA MECÁNICA
844
7102 - GRADO EN INGENIERÍA EN TECNOLOGÍAS DE LA INFORMACIÓN
705
6802 - GRADO EN INGENIERÍA EN ELECTRÓNICA INDUSTRIAL Y AUTOMÁTICA
622
6801 - GRADO EN INGENIERÍA ELÉCTRICA
417
6804 - GRADO EN INGENIERÍA EN TECNOLOGÍAS INDUSTRIALES
289
6805 - GRADO EN INGENIERÍA DE LA ENERGÍA
109
EL mayor número de alumnos pertenece a Psicología, que pertenece a la rama de conocimiento de Ciencias de la Salud, y que nos da un conteo de 28548 alumnos . Si el total de nuestra población es de 118002, solo esta titulación representa el 24% de los alumnos de Grado de la Uned. En segundo lugar están los alumnos de derecho, pero a gran distancia, con 14542 alumnos, que es el 12%.El resto de asignaturas aparecen de forma decreciente. Las últimas, con menos alumnos, las ingenierias (exceto Ingeniería Informática).
Y de los 6 grupos, que notas sacan cada grupo de media agrupando la rama de conocimiento ?
Code
#rama de conocimiento y grupo por nota media kable (alumnos_grado %>%group_by(RAMA_DE_CONOCIMIENTO, grupo) %>%summarise(Nota_Media =mean(NOTA_MEDIA)) %>%arrange(grupo)) %>%kable_styling(bootstrap_options ="striped", full_width = F)
`summarise()` has grouped output by 'RAMA_DE_CONOCIMIENTO'. You can override
using the `.groups` argument.
RAMA_DE_CONOCIMIENTO
grupo
Nota_Media
CIENCIAS DE LA SALUD
1
7.020000
CIENCIAS EXPERIMENTALES
1
7.240417
HUMANIDADES
1
7.505489
INGENIERÍAS
1
7.372000
CIENCIAS DE LA SALUD
2
6.580000
CIENCIAS EXPERIMENTALES
2
6.760500
CIENCIAS SOCIALES Y JURÍDICAS
2
6.665503
HUMANIDADES
2
7.349701
INGENIERÍAS
2
6.930000
CIENCIAS DE LA SALUD
3
6.688947
CIENCIAS EXPERIMENTALES
3
6.013438
CIENCIAS SOCIALES Y JURÍDICAS
3
6.468309
HUMANIDADES
3
6.575000
INGENIERÍAS
3
5.933333
CIENCIAS DE LA SALUD
4
7.020000
CIENCIAS SOCIALES Y JURÍDICAS
4
7.178979
CIENCIAS EXPERIMENTALES
5
4.242000
CIENCIAS SOCIALES Y JURÍDICAS
5
4.105000
INGENIERÍAS
5
5.560699
CIENCIAS DE LA SALUD
6
6.743590
CIENCIAS EXPERIMENTALES
6
6.270135
CIENCIAS SOCIALES Y JURÍDICAS
6
6.437012
HUMANIDADES
6
6.765000
INGENIERÍAS
6
6.290000
Y por ultimo nos volvemos a preguntar, si en la variable que habiamos creado como proporcion entre hombres y mujeres, podemos volver a comprobar si cuando aumenta el número de mujeres que estudian aumenta la nota media:
Code
#y la proporcion de hombres y nmujeres y la nota media kable (alumnos_grado %>%group_by(PROP_H_M) %>%summarise(Nota_Media =mean(NOTA_MEDIA)) %>%arrange(PROP_H_M)) %>%kable_styling(bootstrap_options ="striped", full_width = F)
PROP_H_M
Nota_Media
> 80% mujeres
6.935654
> 60% mujeres
6.910866
igualdad de sexos
6.804837
> 60% hombres
6.611424
> 80% hombres
6.218727
6 Conclusiones
Y dando fin a este análisis, en el que hemos sacado algunas conclusiones que exponemos a continuación:
1.- Hemos aportado datos de una posible correlación entre las variables edad y nota media de los alumnos. cuando aumenta la edad media global, aumenta la nota. Esto ocurre tambien cuando se separa la edad por sexos.
Code
#Boxplot de la edad media global y la nota media como factorbase <-ggplot(data = alumnos_grado) ggplotly ( base +geom_density (aes(x = EDAD_MEDIA_GLOBAL,fill = (NOTA_MEDIA_F)), alpha =0.70) +ggtitle ("Edad media y nota media") )
Vistos estos datos hemos buscado la correlación entre las variables, obteniendo una fórmula que predice la nota media en función de la edad del alumno.
2.- Hemos comprobado que la nota media de la poblacion mujeres es ligéramente máyor que la nota media de la población hombres.
Code
#proporcion de hombres y nmujeres y la nota mediakable (alumnos_grado %>%group_by(PROP_H_M) %>%summarise(Nota_Media =mean(NOTA_MEDIA)) %>%arrange(PROP_H_M)) %>%kable_styling(bootstrap_options ="striped", full_width = F)
PROP_H_M
Nota_Media
> 80% mujeres
6.935654
> 60% mujeres
6.910866
igualdad de sexos
6.804837
> 60% hombres
6.611424
> 80% hombres
6.218727
3.- También la media de edad de los hombres es ligéramente mayor entre 2 y 3 años por encima, según hemos comprobado mediante análisis estadísticos.
Pearson's product-moment correlation
data: alumnos_grado$EDAD_MEDIA_GLOBAL and alumnos_grado$NOTA_MEDIA
t = 5.916, df = 1454, p-value = 4.106e-09
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.1027502 0.2030869
sample estimates:
cor
0.1533137
4.- Hemos podido segmentar la población y obtener, de los 6 k posibles que ofrecia el algoritmo de clasificación, al meno 4 subgrupos con características bien diferenciadas, los grupos 1, 3, 4 y 5. Los grupos 2 y 6 han resultado ser el resto de observaciones más heterogeneas.
Fin.
References
Angel Muñoz Alamillos, I. T. M. Introducción a la estadística para admistración y dirección de empresas. Sanz y Torres.
Buuren, S. van, & Groothuis-Oudshoorn, K. (2011). Mice: Multivariate imputation by chained equations in r. 45, 1–67. https://doi.org/10.18637/jss.v045.i03
Eva Laude, H. L. (2022). Data scientist y lenguaje r. Ediciones ENI.
Sievert, C. (2020). Interactive web-based data visualization with r, plotly, and shiny. https://plotly-r.com
Waring, E., Quinn, M., McNamara, A., Arino de la Rubia, E., Zhu, H., & Ellis, S. (2022). Skimr: Compact and flexible summaries of data. https://CRAN.R-project.org/package=skimr
Warnes, G. R., Bolker, B., Lumley, T., SAIC-Frederick, R. C. Johnson. C. from R. C. J. are C., Program, Inc. F. by the I. R., NIH, of the, Institute, N. C., & NO1-CO-12400., C. for C. R. under N. C. (2022). Gmodels: Various r programming tools for model fitting. https://CRAN.R-project.org/package=gmodels
Wickham, H., Averick, M., Bryan, J., Chang, W., McGowan, L. D., François, R., Grolemund, G., Hayes, A., Henry, L., Hester, J., Kuhn, M., Pedersen, T. L., Miller, E., Bache, S. M., Müller, K., Ooms, J., Robinson, D., Seidel, D. P., Spinu, V., … Yutani, H. (2019). Welcome to the tidyverse. 4, 1686. https://doi.org/10.21105/joss.01686