Autor: Luis Fernando Apáez Álvarez
-Curso PyM-
Proyecto 2: Introducción al análisis de datos
Fecha: 03 de Septiembre del 2022
Librerías que ocuparemos en este proyecto:
Dentro de este proyecto iremos trabajando paso a paso enfocándonos en el análisis de datos.
La información con la que trabajaremos corresponde a los datos generados en la primer semana del curso propedéutico 2023-1 impartido por la Facultad de Ciencias de la UNAM. Dentro de dicho curso se dieron diferentes talleres de diferentes temas.
Ahora bien, para la información recopilada consideraremos dos archivos csv:
Encuestas: Recopila información sobre los diferentes talleres brindados, donde las preguntas evalúan qué tan claro fue la exposición de los temas, el lenguaje que se ocupó, etcétera. De manera global las encuestas evalúan los talleres. Además, el curso estuvo conformado por talleres, donde se veían los temas de una manera intuitiva y sencilla, y por secuencias didácticas (SD), donde se veían los temas del taller pero de una manera más especifica y técnica. En las encuestas se evalúan tanto los talleres como las SD's.
Asistencias: Recopila la asistencia de los participantes del curso propedéutico en la primer semana del curso (es decir, recopila las asistencias de 5 días).
Con base en lo anterior, es natural enfocar nuestro análisis de datos en ver las evaluaciones que se les dieron a cada uno de los talleres, o ver de manera global la evalución conjunta de todos los talleres para determinar una evalución general al curso propedéutico. Podremos ver también cuáles fueron los aspectos (o preguntas de la encuesta) que obtuvieron mejor o peor respuesta; por ejemplo, si logramos identificar las preguntas de la encuesta que obtuvieron peor respuesta, se puede enfocar más en dicho tema o abordarlo de una manera distinta en los siguientes cursos propedéuticos. En teoría, cada participante debía responder sólo una vez la encuesta en dicha primer semana.
Asimismo, podemos ver el comportamiento de los participantes entorno a sus asistencias. Por ejemplo, puede ser que el día viernes asistieron menos participantes a los talleres respecto a los demás días, o tal vez, el día en que asistieron más participantes fue, justamente, el primer día del curso (lunes). Lo anterior podremos responderlo de una manera certera.
Así, lo dicho antes representa el punto de partida y el camino que debemos seguir respecto a nuestro análisis de datos.
Comenzamos por cargar los datos de las encuestas
# Librerias que ocuparemos
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# Cargaremos el archivo Encuestas.csv de la web y lo convertiremos
# en un dataframe denominado encuestas
encuestas = pd.read_csv('https://cursopypagina.github.io/CursoPy/Encuestas.csv')
# Vemos los primeros registros
encuestas.head(2)
Unnamed: 0 | Marca temporal | Dirección de correo electrónico | Escribe el nombre del taller | El lenguaje de los taller fue adecuado | Se distinguió los objetivos del taller | Fueron claras las instrucciones de los talleres | ¿Qué tan ameno te pareció el taller? | Los talleres te motivaron a seguir indagando en el tema | Si tienes comentarios y/o sugerencias acerca de los talleres son bienvenidos. | El lenguaje de las secuencias didácticas te pareció apropiado | Se distinguió los objetivos de las secuencias didácticas | Fueron claros los conceptos que se formalizaron en las secuencias didácticas | ¿Qué tan complicado te pareció la formalización de los conceptos en las secuencias didácticas? | ¿Qué tan apropiado fue introducir los conceptos formales a partir de los talleres? | Si tienes comentarios y/o sugerencias son bienvenidos | El lenguaje de los talleres fue adecuado | Se distinguieron los objetivos del taller | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 21/07/2022 9:16:50 | NaN | Serpientes estocásticas y escaleras aleatorias | 1.0 | 1.0 | 1 | 1 | 2 | Sería bueno si pudieran sugerir bibliografía ú... | Mucho | Mucho | Mucho | Poco | Poco | . | NaN | NaN |
1 | 1 | 21/07/2022 9:18:07 | NaN | Serpientes estocásticas y escaleras aleatorias | 1.0 | 1.0 | 2 | 1 | 1 | En general el taller fue ameno, la actividad d... | Mucho | Mucho | Mucho | Mucho | Mucho | No tengo mucho que agregar, me pareció bastant... | NaN | NaN |
Para trabajar con mayor facilidad cambiaremos el nombre de las columnas
# Vemos la forma del dataframe
print(encuestas.shape)
print("-" * 100)
# Almacenaremos el numero total de columnas
# en la siguiente variable
ncols = encuestas.shape[1]
# Nombres originales de las columnas
ncolumnas = encuestas.columns
print(ncolumnas)
print("-" * 100)
# Los nuevos nombres seran numeros para trabajar de una
# manera mas facil
encuestas.columns = [str(i) for i in range(ncols)]
print("Nuevos nombres de las columnas: ")
print(encuestas.columns)
print("-" * 100)
# Creamos una lista de tuplas de la asociacion que acabamos de realizar
# esto es, en las primeras entradas de la tuplas estaran los numeros
# de las columnas como los asignamos antes, y en las segundas entradas
# los nombres originales de las columnas
name_columns = []
for i in range(ncols):
tupla = (str(i), ncolumnas[i])
name_columns.append(tupla)
display(name_columns)
(145, 18) ---------------------------------------------------------------------------------------------------- Index(['Unnamed: 0', 'Marca temporal', 'Dirección de correo electrónico', 'Escribe el nombre del taller ', 'El lenguaje de los taller fue adecuado ', 'Se distinguió los objetivos del taller', 'Fueron claras las instrucciones de los talleres', '¿Qué tan ameno te pareció el taller?', 'Los talleres te motivaron a seguir indagando en el tema', 'Si tienes comentarios y/o sugerencias acerca de los talleres son bienvenidos.', 'El lenguaje de las secuencias didácticas te pareció apropiado', 'Se distinguió los objetivos de las secuencias didácticas', 'Fueron claros los conceptos que se formalizaron en las secuencias didácticas', '¿Qué tan complicado te pareció la formalización de los conceptos en las secuencias didácticas?', '¿Qué tan apropiado fue introducir los conceptos formales a partir de los talleres?', 'Si tienes comentarios y/o sugerencias son bienvenidos', 'El lenguaje de los talleres fue adecuado ', 'Se distinguieron los objetivos del taller'], dtype='object') ---------------------------------------------------------------------------------------------------- Nuevos nombres de las columnas: Index(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17'], dtype='object') ----------------------------------------------------------------------------------------------------
[('0', 'Unnamed: 0'), ('1', 'Marca temporal'), ('2', 'Dirección de correo electrónico'), ('3', 'Escribe el nombre del taller '), ('4', 'El lenguaje de los taller fue adecuado '), ('5', 'Se distinguió los objetivos del taller'), ('6', 'Fueron claras las instrucciones de los talleres'), ('7', '¿Qué tan ameno te pareció el taller?'), ('8', 'Los talleres te motivaron a seguir indagando en el tema'), ('9', 'Si tienes comentarios y/o sugerencias acerca de los talleres son bienvenidos.'), ('10', 'El lenguaje de las secuencias didácticas te pareció apropiado'), ('11', 'Se distinguió los objetivos de las secuencias didácticas'), ('12', 'Fueron claros los conceptos que se formalizaron en las secuencias didácticas'), ('13', '¿Qué tan complicado te pareció la formalización de los conceptos en las secuencias didácticas?'), ('14', '¿Qué tan apropiado fue introducir los conceptos formales a partir de los talleres?'), ('15', 'Si tienes comentarios y/o sugerencias son bienvenidos'), ('16', 'El lenguaje de los talleres fue adecuado '), ('17', 'Se distinguieron los objetivos del taller')]
Podemos notar que la columna 0 ('Unnamed: 0'
) y la columna 1 no nos aportan información relevante para el análisis que buscamos hacer. Luego, la columna 2 tiene en todas sus entradas el valor NaN
. Para comprobar lo anterior ocuparemos el método unique()
el cual nos arroja todos los valores diferentes que están almacenados en una columna
encuestas['2'].unique()
array([nan])
entonces sólo hay un valor distinto almacenado en dicha columna, esto es, todos los valores en la columna 2
tienen el valor NaN
.
Otro ejemplo utilizando unique()
es al hallar todos los nombres de los distintos talleres del curso:
encuestas['3'].unique()
array(['Serpientes estocásticas y escaleras aleatorias', 'Serpientes estocásticas y escaleras aleatorias.', 'Lógica y sudokus', 'Lógica, sudokus y...¿demostraciones?', 'Cartas en Set', 'Sudoku', 'Bingo del multiverso ', ' Bingo del Multiverso. ', 'Bingo del Multiverso', 'Bingo del Multiverso ', 'Bingo del multiverso', 'bingo del multiiverso', 'Curso Propedeutico', 'Juntos con Conujntos', 'Juntos con conjuntos', 'juntos con conjuntos ', 'Juntos con Conjuntos', 'Junto con Conjuntos', 'Juntos con conjuntos ', 'Conjuntos ?', 'Probabilidad ', 'Carrera de probabilidades con Mario Kart', 'carrera de probabilidades con Mario Kart ', 'Carrera de probabilidad con Mario Kart', 'Carrera de Probabilidades', 'Carrera de Probabilidad', 'Mario Kart y probabilidades ', 'Carrera de Probabilidades con Mario Kart.', 'carrera de probabilidades con Mario kart ', 'Los caminos del infinito (no son como yo pensaba).', 'Los caminos del infinito (no son como yo pensaba)', 'Los caminos del infinito (no son lo que yo pensaba).', 'Los caminos del infinito (no son lo que yo pensaba)', 'Los caminos del infinito (no son como yo pensaba). ', 'Los caminos del infinito', 'Los caminos del infinito no son lo que yo pensaba', 'Probabilidad, con Mario kart ', 'Aliens mentirosos', 'Cursos Propedéuticos Facultad de Ciencias ', 'Secuencias didacticas', 'Curso Propedéutico Facultad de Ciencias', 'Aliens Mentirosos', 'Aliens mentirosos.', 'Aliens mentirosos ', 'Un algoritmo para calcular el día del fin del mundo ', 'un algoritmo para calcular el fin del mundo', 'El algoritmo para calcular el fin del mundo. ', 'Un algoritmo para calcular el fin del mundo', 'Un algoritmo para calcular el día del fin del mundo', 'Ecuación para calcular el fin del mundo', 'Un algoritmo para calcular el fin del mundo ', 'Juego del grafimar', 'el juego del grafimar', 'Juego del Grafimar (Teoría de Grafos)', 'El juego del Grafimar', 'Juego del grafimar ', 'El juego del grafimar ', 'El juego del grafimar', 'Juego del Grafimar', 'Juego del Grafimar G10', '¿Leonardo Di Caprio es perfecto?', '¿Leonardo Dicaprio es perfecto?', '¿Leonardo Di caprio es perfecto?', 'Propedéutico Facultad de Ciencias ', 'Leonardo Di Caprio es perfecto?', 'Propedéutico facultad de ciencias ', '¿Leonardo DiCaprio es perfecto?', 'Cursos Propedéuticos Facultad de Ciencias', 'Leonardo di caprio ', 'Scram∅ (Scrampty)', 'Scrampin', 'Conjuntos', 'Leonardo di caprino es perfecto?', 'Scrampty', 'Scram∅', 'scrampty', 'Cursos Propedeuticos Ciencias', 'Curso propedéutico 2022', 'Cursos propedéuticos FCiencias', 'Máquina para transformar café en teoremas', 'Maquina de cafe para hacer teoremas¿', 'Maquina para transformar cafe en teoremas ', 'Maquina para transformar café en teoremas', 'Máquina para transformar café en teoremas. ', 'Máquina para transformar café en teoremas ', 'Máquina para transformas café en teoremas. ', 'No lo recuerdo, ya que el link que me mandaron al principio me mandaba a un equipo que no era el mío entonces creo que me perdí eso ', 'Toros y vacas ', 'Vacas y toros', 'toros y vacas', 'Toros vacas ', 'Toros y Vacas', 'Propedeutico ', 'Máquina para transformas café en teoremas', 'Màquina para transformar café en teoremas', 'maquina para transformar café en teoremas', 'Maquina para transformar café en teoremas.', 'Maquina para transformar cafe en teoremas', 'TOROS Y VACAS', 'maquina para transformar café en teoremas '], dtype=object)
lo cual más o menos resulta como queríamos, solo que los estudiantes ingresaron de diferentes maneras el nombre de un mismo taller. Para obtener tal cual el resultado que queríamos tendríamos que realizar una limpieza de datos sobre dicha columna, lo cual no haremos.
El punto es que la columna 2 solo tiene el valor NaN
repetido, por lo cual también la eliminaremos.
Para eliminar un columna o fila utilizaremos el método drop(<columnas o filas>, axis=)
donde colocaremos en el primer parámetro la columna o fila (o una lista de columnas o filas) que queramos eliminar, y asignaremos el valor de axis=1
cuando queramos eliminar columnas o axis=0
cuando queramos eliminar filas. De tal manera:
# Eliminaremos las columnas 0, 1 y 2
encuestas = encuestas.drop(['0','1','2'], axis=1)
encuestas.head(2)
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Serpientes estocásticas y escaleras aleatorias | 1.0 | 1.0 | 1 | 1 | 2 | Sería bueno si pudieran sugerir bibliografía ú... | Mucho | Mucho | Mucho | Poco | Poco | . | NaN | NaN |
1 | Serpientes estocásticas y escaleras aleatorias | 1.0 | 1.0 | 2 | 1 | 1 | En general el taller fue ameno, la actividad d... | Mucho | Mucho | Mucho | Mucho | Mucho | No tengo mucho que agregar, me pareció bastant... | NaN | NaN |
Cada fila del dataframe corresponde a un participante que contestó la encuesta, de modo que podemos ver cuántos alumnos respondieron la encuesta:
# Numero de participantes que respondieron la encuesta
encuestas.shape[0]
145
Veamos el tipo de dato de cada una de las columnas del dataframe de encuestas
, para lo cual nos auxiliamos del método info()
:
# Veamos ahora una breve informacion de nuestro dataframe
encuestas.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 145 entries, 0 to 144 Data columns (total 15 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 3 145 non-null object 1 4 133 non-null float64 2 5 133 non-null float64 3 6 145 non-null int64 4 7 145 non-null int64 5 8 145 non-null int64 6 9 145 non-null object 7 10 145 non-null object 8 11 145 non-null object 9 12 145 non-null object 10 13 145 non-null object 11 14 145 non-null object 12 15 145 non-null object 13 16 12 non-null float64 14 17 12 non-null float64 dtypes: float64(4), int64(3), object(8) memory usage: 17.1+ KB
Notamos que las columnas 4-8 y 16-17 son numéricas, por lo cual podría ser de nuestro interés ver algunas estadísticas sobre dichas columnas:
encuestas.describe()
4 | 5 | 6 | 7 | 8 | 16 | 17 | |
---|---|---|---|---|---|---|---|
count | 133.000000 | 133.000000 | 145.000000 | 145.000000 | 145.000000 | 12.000000 | 12.000000 |
mean | 1.593985 | 1.676692 | 1.510345 | 1.606897 | 1.668966 | 1.166667 | 1.333333 |
std | 1.161488 | 1.158296 | 1.093651 | 1.144410 | 1.074032 | 0.389249 | 0.651339 |
min | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 |
25% | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 |
50% | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 |
75% | 2.000000 | 2.000000 | 1.000000 | 2.000000 | 2.000000 | 1.000000 | 1.250000 |
max | 5.000000 | 5.000000 | 5.000000 | 5.000000 | 5.000000 | 2.000000 | 3.000000 |
# Veamos los nombres de algunas columnas de interes
name_columns[4:9]
[('4', 'El lenguaje de los taller fue adecuado '), ('5', 'Se distinguió los objetivos del taller'), ('6', 'Fueron claras las instrucciones de los talleres'), ('7', '¿Qué tan ameno te pareció el taller?'), ('8', 'Los talleres te motivaron a seguir indagando en el tema')]
vemos que, para la pregunta: ¿El lenguaje de los taller fue adecuado? En promedio (mean
) se obtuvo una buena calificación (recordemos que 1 es una muy buena calificación y 5 una muy mala); vemos también que el 75% de los datos tienen un valor asociado (en la columna 4
) menor a 2, lo que quiere decir, prácticamente, que el 75% de los alumnos dió una muy buena calificación respecto a dicha pregunta, esto es, podemos concluir que en general el lenguaje de los talleres fue adecuado.
De la misma manera, para el resto de las preguntas a considerar
('5', 'Se distinguió los objetivos del taller')
('6', 'Fueron claras las instrucciones de los talleres')
('7', '¿Qué tan ameno te pareció el taller?')
('8', 'Los talleres te motivaron a seguir indagando en el tema')
obtenemos resultados similares, y por tanto buenas calificaciones, en general, para todos los talleres impartidos.
Para las columnas 16
y 17
tendríamos que realizar un análisis a parte.
Ahora bien, las preguntas de las columnas de la 4 a la 8 serán respondidas por un número entre el 1 y el 5, donde 1 representa la idea "Mucho" y el 5 representa la idea "Poco". Las preguntas de la 10 a la 14 son respondidas únicamente con la etiqueta "Mucho" o "poco".
Lo que haremos ahora a partir de las preguntas será realizar un gráfico para visualizar de mejor manera cómo fueron calificados los distintos talleres y secuencias didácticas (SD), algo como
donde vemos en el eje vertical los distintos valores de 1 a 5 que representan las calificaciones dadas por los estudiantes, y la altura de cada barra representa el total de estudiantes que asigaron dicha calificación. Por ejemplo, del gráfico anterior vemos que más de 80 alumnos (de los 145 totales) dió una muy buena calificación respecto a la pregunta: El lenguaje de los taller fue adecuado
(el lenguaje de los talleres fue adecuado). Y menos de 20 estudiante dieron mala calificación respecto a esa pregunta.
Así, lo que haremos será construir el gráfico anterior
plt.style.use('ggplot')
# Recordemos que la columna 4 tiene asociada
# la pregunta:
# El lenguaje de los taller fue adecuado
# Utilizaremos un histograma para realizar el grafico
# para lo cual escribiremos plt.hist() como sigue:
plt.hist(encuestas['4'], color="#34DE14")
# Etiquetas y titulo
plt.xlabel("1: Mucho, 3: Medio, 5: Muy poco", size=12)
plt.ylabel("# Respuestas")
plt.title(name_columns[4][1], size=17)
# Mostramos el grafico
plt.show()
Obteniéndose así el gráfico que queríamos. Continuando, ahora mostraremos los gráficos pero del resto de las preguntas. Configuraremos la salida de nuestros gráficos para que se muestren juntos, para lo cual utilizaremos plt.subplot(n,k,j)
donde:
Por ejemplo:
De tal manera
plt.style.use('ggplot')
# Configuramos el tamanio total del grafico
# (14 px de largo por 16 px de ancho)
fig = plt.figure(figsize=(14,16))
# Primer grafico:
plt.subplot(2,2,1)
plt.hist(encuestas['4'], color="#34DE14")
plt.xlabel("1: Mucho, 3: Medio, 5: Muy poco", size=12)
plt.ylabel("# Respuestas")
plt.title(name_columns[4][1], size=17)
# Segundo grafico:
plt.subplot(2,2,2)
plt.hist(encuestas['5'], color="#FFE631")
plt.xlabel("1: Mucho, 3: Medio, 5: Muy poco", size=12)
plt.ylabel("# Respuestas")
plt.title(name_columns[5][1], size=17)
# Tercer grafico:
plt.subplot(2,2,3)
plt.hist(encuestas['6'], color="#A931FF")
plt.xlabel("1: Mucho, 3: Medio, 5: Muy poco", size=12)
plt.ylabel("# Respuestas")
plt.title(name_columns[6][1], size=17)
# Cuarto grafico
plt.subplot(2,2,4)
# Aqui juntaremos dos histogramas en un solo subgrafico
# correspondientes a las preguntas
# ¿Qué tan ameno te parecio el taller? (7) y
# Los talleres te motivaron a seguir indagando en el tema (8)
# configuramos un rango
# de graficacion refe-
# rente al eje x
plt.hist(encuestas['7'], color="#0705FB", range=(1,6))
plt.hist(encuestas['8'], color='#05DBFB', range=(0.7,5.7))
plt.xlabel("1: Mucho, 3: Medio, 5: Muy poco", size=12)
plt.ylabel("# Respuestas")
# Configuramos plt.legend() para distinguir entre los dos histogramas
plt.legend(["Ameno", "Motivación"])
plt.title("Qué tan ameno te pareció el taller\nLos talleres te motivaron a seguir indagando", size=17)
# Titulo del grafico completo
plt.suptitle("Resultados generales de las encuestas: Taller", size=20)
plt.show()
Observamos que, en general, todos los talleres del curso obtuvieron una calificación buena. En más detalle:
concluyendo así que el curso propedéutico fue bueno.
Realizamos lo mismo pero ahora para la secuencia didáctica. Notemos primero lo siguiente
# Veamos los nombres de algunas columnas de interes
name_columns[10:]
[('10', 'El lenguaje de las secuencias didácticas te pareció apropiado'), ('11', 'Se distinguió los objetivos de las secuencias didácticas'), ('12', 'Fueron claros los conceptos que se formalizaron en las secuencias didácticas'), ('13', '¿Qué tan complicado te pareció la formalización de los conceptos en las secuencias didácticas?'), ('14', '¿Qué tan apropiado fue introducir los conceptos formales a partir de los talleres?'), ('15', 'Si tienes comentarios y/o sugerencias son bienvenidos'), ('16', 'El lenguaje de los talleres fue adecuado '), ('17', 'Se distinguieron los objetivos del taller')]
las preguntas de la 10 a la 15 corresponden a las secuencias didácticas, y de la 16 a la 17 son errores pues dichas preguntas fueron abordadas en columnas anteriores. De modo que sólo consideraremos las columnas de la 10 a la 15. Además, dichas preguntas se contestaron ahora sólo con dos etiquetas posibles: Mucho o Poco. Por ende, para analizarlas de una manera más sencilla convertiremos la etiqueta Mucho al valor 1 y la etiqueta Poco al valor 0. Notemos el dataframe concentrándonos en las columnas de la 10 a al 14
encuestas[['10','11','12','13','14']]
10 | 11 | 12 | 13 | 14 | |
---|---|---|---|---|---|
0 | Mucho | Mucho | Mucho | Poco | Poco |
1 | Mucho | Mucho | Mucho | Mucho | Mucho |
2 | Mucho | Mucho | Mucho | Mucho | Mucho |
3 | Mucho | Mucho | Mucho | Poco | Mucho |
4 | Mucho | Mucho | Mucho | Poco | Mucho |
... | ... | ... | ... | ... | ... |
140 | Mucho | Mucho | Mucho | Poco | Mucho |
141 | Mucho | Mucho | Mucho | Mucho | Mucho |
142 | Mucho | Mucho | Mucho | Poco | Mucho |
143 | Mucho | Mucho | Mucho | Poco | Mucho |
144 | Mucho | Mucho | Mucho | Poco | Mucho |
145 rows × 5 columns
Para hacer el cambio de Mucho a 1 y de Poco a 0 dentro de nuestro dataframe, utilizaremos el método replace()
auxiliándonos de diccionarios. Primero crearemos un diccionario donde las keys serán los valores que tiene una determinada columna. Por ejemplo, la columna 10
tiene por valores a Mucho
y a Poco
, de modo que dichos valores serán las keys del diccionario que crearemos. Luego, los values asociados a dichas keys serán los valores de reemplazo. Para nuestro ejemplo escribiríamos el siguiente diccionario
valores_reemplazo = {'Mucho': 1, 'Poco': 0}
pues queremos reemplazar la etiqueta Mucho por el número 1, y la etiqueta Poco con el número 0.
Una vez que tenemos el diccionario para efectuar los reemplazos, debemos definir otro diccionario en el cual las keys serán las columnas donde haremos el reemplazo de los valores, y los values asociados serán diccionarios con las asociaciones de reemplazo. En nuestro ejemplo, si queremos cambiar los valores de la columna 10
, entonces el 10
será una key de este último diccionario y su value asociado es el diccionario que definimos antes valores_reemplazo
. De tal manera, para efectuar el cambio que deseamos escribimos
encuestas.replace({'10': valores_reemplazo})
para conseguir el reemplazo que queremos. Dado que el cambio queremos realizarlo en más de una columna, entonces escribiremos:
# Mucho --> 1
# Poco --> 0
valores_reemplazo = {'Mucho': 1, 'Poco': 0}
# Realizamos los reemplazos en las columnas de la 10
# a la 14
encuestas = encuestas.replace({'10': valores_reemplazo,
'11': valores_reemplazo,
'12': valores_reemplazo,
'13': valores_reemplazo,
'14': valores_reemplazo})
# Veamos los cambios
encuestas[['10','11','12','13','14']]
10 | 11 | 12 | 13 | 14 | |
---|---|---|---|---|---|
0 | 1 | 1 | 1 | 0 | 0 |
1 | 1 | 1 | 1 | 1 | 1 |
2 | 1 | 1 | 1 | 1 | 1 |
3 | 1 | 1 | 1 | 0 | 1 |
4 | 1 | 1 | 1 | 0 | 1 |
... | ... | ... | ... | ... | ... |
140 | 1 | 1 | 1 | 0 | 1 |
141 | 1 | 1 | 1 | 1 | 1 |
142 | 1 | 1 | 1 | 0 | 1 |
143 | 1 | 1 | 1 | 0 | 1 |
144 | 1 | 1 | 1 | 0 | 1 |
145 rows × 5 columns
Continuando, escribiremos un código para poder realizar los gráficos de barras correspondientes para ver cómo fueron calificados, ahora, las secuencias didácticas. El código será totalmente análogo al que se empleó para los gráficos de las preguntas de los talleres.
Ahora, el código que escribiremos para crear los gráficos será mediante una función
name_columns[10:15]
[('10', 'El lenguaje de las secuencias didácticas te pareció apropiado'), ('11', 'Se distinguió los objetivos de las secuencias didácticas'), ('12', 'Fueron claros los conceptos que se formalizaron en las secuencias didácticas'), ('13', '¿Qué tan complicado te pareció la formalización de los conceptos en las secuencias didácticas?'), ('14', '¿Qué tan apropiado fue introducir los conceptos formales a partir de los talleres?')]
# Funcion para graficar la informacion
# de las secuencias
def graficar_secuencias(dataframe):
"""La función recibirá como parámetro un
dataframe y realizará los gráficos de barras
para cada una de las preguntas dadas
en la encuesta para las secuencias
didácticas.
Las preguntas de la encuesta para la SD
son de la 10 a la 14."""
# Configuramos el tamanio del grafico
fig = plt.figure(figsize=(12,13))
plt.subplot(2,2,1)
# Pregunta 10 SD
plt.hist(dataframe['10'], color="#02FE0C", bins=3, range=(0,1))
plt.xticks([0.172, 0.837], ['0: Poco', '1: Mucho'], size=12)
plt.ylabel("# Respuestas")
plt.title(" Lenguaje apropiado")
plt.subplot(2,2,2)
# Pregunta 11 SD
plt.hist(dataframe['11'], color="#F747FF", bins=3, range=(0,1))
plt.xticks([0.172, 0.837], ['0: Poco', '1: Mucho'], size=12)
plt.ylabel("# Respuestas")
plt.title("Distinción de objetivos")
plt.subplot(2,2,3)
# Pregunta 12 SD
plt.hist(dataframe['12'], color="#FCB31E", bins=3, range=(0,1))
plt.xticks([0.172, 0.837], ['0: Poco', '1: Mucho'], size=12)
plt.ylabel("# Respuestas")
plt.title(" Conceptos claros en la formalización")
plt.subplot(2,2,4)
# Graficamos juntos las graficas de la pregunta 13 y 14
# Pregunta 13 SD
plt.hist(dataframe['13'], color="#FF0000", bins=3, range=(0,1))
# Pregunta 14 SD
plt.hist(dataframe['14'], color='#05DBFB', bins=3, range=(0,1), alpha=0.8)
plt.xticks([0.172, 0.837], ['0: Poco', '1: Mucho'], size=12)
plt.ylabel("# Respuestas")
plt.legend(["Complicado", "Apropiado"])
plt.title("Qué tan complicado fue la formaliz\nFue apropiado introducir la formaliz a partir taller",
size=14)
plt.suptitle("Resultados generales de las encuestas: SD", size=18)
plt.show()
Ahora bien, utilizaremos la función anterior y le pasaremos el dataframe encuestas
con el que estamos trabajando
graficar_secuencias(encuestas)
De lo anterior podemos decir que:
Ahora leeremos el archivo Asistencia.csv
para analizar la asistencia de los participantes en la primer semana del curso propedéutico y ver algunas tendencias.
# Comenzamos por cargar los datos
asistencias = pd.read_csv('https://cursopypagina.github.io/CursoPy/Asistencias.csv')
asistencias.head(2)
Unnamed: 0 | Primer apellido | Segundo apellido | Nombre (s) | Email alterno | 2022-07-18 00:00:00 | 2022-07-19 00:00:00 | 2022-07-20 00:00:00 | 2022-07-21 00:00:00 | ... | 2022-07-25 00:00:00 | 2022-07-26 00:00:00 | 2022-07-27 00:00:00 | 2022-07-28 00:00:00 | 2022-07-29 00:00:00 | 2022-08-01 00:00:00 | 2022-08-02 00:00:00 | 2022-08-03 00:00:00 | 2022-08-04 00:00:00 | 2022-08-05 00:00:00 | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | NaN | NaN | JACIR JEZHAELL | NaN | NaN | 0 | 0 | 1 | 0.0 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1 | 1 | NaN | NaN | MANUEL ALEJANDRO | NaN | NaN | 0 | 0 | 0 | 0.0 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2 rows × 21 columns
print(asistencias.columns)
print(asistencias.shape)
Index(['Unnamed: 0', 'Primer apellido', 'Segundo apellido', 'Nombre (s)', 'Email', 'Email alterno', '2022-07-18 00:00:00', '2022-07-19 00:00:00', '2022-07-20 00:00:00', '2022-07-21 00:00:00', '2022-07-22 00:00:00', '2022-07-25 00:00:00', '2022-07-26 00:00:00', '2022-07-27 00:00:00', '2022-07-28 00:00:00', '2022-07-29 00:00:00', '2022-08-01 00:00:00', '2022-08-02 00:00:00', '2022-08-03 00:00:00', '2022-08-04 00:00:00', '2022-08-05 00:00:00'], dtype='object') (261, 21)
Las únicas columnas que serán de nuestro interés son de la 2022-07-18 00:00:00'
a la '2022-07-22 00:00:00'
que representan los días de la semana del lunes al viernes de cuando se impartió el curso propedéutico. Además, para los fines del análisis que realizaremos, las demás columnas no nos interesarán.
Nuevamente, por comodidad cambiaremos el nombre de las columnas
# Almacenamos los nombres de las columnas
nombres = asistencias.columns
# Cambiamos el nombre de las columnas
asistencias.columns = [str(i) for i in range(21)]
# Creamos una lista de tuplas de la asociacion anterior
names_columns = []
for i in range(21):
tupla = (str(i), nombres[i])
names_columns.append(tupla)
display(names_columns)
print("-" * 100)
display(asistencias.head(2))
[('0', 'Unnamed: 0'), ('1', 'Primer apellido'), ('2', 'Segundo apellido'), ('3', 'Nombre (s)'), ('4', 'Email'), ('5', 'Email alterno'), ('6', '2022-07-18 00:00:00'), ('7', '2022-07-19 00:00:00'), ('8', '2022-07-20 00:00:00'), ('9', '2022-07-21 00:00:00'), ('10', '2022-07-22 00:00:00'), ('11', '2022-07-25 00:00:00'), ('12', '2022-07-26 00:00:00'), ('13', '2022-07-27 00:00:00'), ('14', '2022-07-28 00:00:00'), ('15', '2022-07-29 00:00:00'), ('16', '2022-08-01 00:00:00'), ('17', '2022-08-02 00:00:00'), ('18', '2022-08-03 00:00:00'), ('19', '2022-08-04 00:00:00'), ('20', '2022-08-05 00:00:00')]
----------------------------------------------------------------------------------------------------
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ... | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | NaN | NaN | JACIR JEZHAELL | NaN | NaN | 0 | 0 | 1 | 0.0 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1 | 1 | NaN | NaN | MANUEL ALEJANDRO | NaN | NaN | 0 | 0 | 0 | 0.0 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2 rows × 21 columns
notamos que las columnas con la cuales trabajaremos serán de la 6 a la 10:
asistencias[['6', '7', '8', '9', '10']]
6 | 7 | 8 | 9 | 10 | |
---|---|---|---|---|---|
0 | 0 | 0 | 1 | 0.0 | 0.0 |
1 | 0 | 0 | 0 | 0.0 | 0.0 |
2 | 1 | 1 | 1 | 1.0 | 1.0 |
3 | 0 | 1 | 1 | 1.0 | 1.0 |
4 | 0 | 1 | 1 | 1.0 | 1.0 |
... | ... | ... | ... | ... | ... |
256 | 1 | 1 | 1 | 0.0 | 1.0 |
257 | 1 | 1 | 1 | 1.0 | 1.0 |
258 | 1 | 1 | 0 | 0.0 | 0.0 |
259 | 1 | 0 | 0 | 0.0 | 0.0 |
260 | 0 | 0 | 0 | 0.0 | 0.0 |
261 rows × 5 columns
asistencias = asistencias[['6', '7', '8', '9', '10']]
print(asistencias.shape)
display(asistencias.head(2))
(261, 5)
6 | 7 | 8 | 9 | 10 | |
---|---|---|---|---|---|
0 | 0 | 0 | 1 | 0.0 | 0.0 |
1 | 0 | 0 | 0 | 0.0 | 0.0 |
Donde 1 representa que el alumno asistió a clase y 0 caso contrario.
Luego, calcularemos el número total de asistencias por cada día (es decir por cada columna), para lo cual, principalmente, utilizaremos el método sum()
.
# Lista auxiliar para almacenar el # de asistencias totales por dia
asistencias_num = []
# Lista con el nombre de los dias
dias = ['Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes']
for i in range(5):
x = 0
# sumamos el total de asistencias por cada columna (de la columna 6 a la 10)
x = asistencias[str(i + 6)].sum()
# dado que la suma anterior nos dara en algunos casos
# un valor flotante o un valor entero, para que la salida
# de la informacion sea homogenea convertimos a x al tipo de
# dato int, y agregamos dicho valor a la lista asistencias_num
asistencias_num.append(int(x))
# Arrojamos un mensaje
msj = f'Asistencias del {dias[i]}: {int(x)}'
print(msj)
Asistencias del Lunes: 339 Asistencias del Martes: 321 Asistencias del Miercoles: 295 Asistencias del Jueves: 254 Asistencias del Viernes: 226
No obstante, el análisis anterior es incorrecto pues, por ejemplo, veamos las siguientes filas, las cuales tienen valores mayores a 1 asignados
asistencias[asistencias['10'] > 1]
6 | 7 | 8 | 9 | 10 | |
---|---|---|---|---|---|
19 | 7 | 8 | 9 | 8.0 | 8.0 |
39 | 14 | 11 | 10 | 11.0 | 11.0 |
59 | 13 | 13 | 12 | 11.0 | 10.0 |
79 | 15 | 13 | 13 | 14.0 | 15.0 |
118 | 14 | 16 | 12 | 14.0 | 11.0 |
138 | 14 | 14 | 12 | 8.0 | 10.0 |
197 | 13 | 13 | 12 | 12.0 | 8.0 |
219 | 15 | 14 | 11 | 12.0 | 10.0 |
240 | 14 | 11 | 9 | 10.0 | 10.0 |
lo cual compromete nuestro análisis dado que esperamos sólo tener valores asignados de 0 y 1. Lo que ocurre es que dichos valores son sumas parciales de asistencias por lo cual, en primera instancia, podríamos pensar en sumar dichos valores para obtener el número total de asistencias por día. El detalle radica en dichas sumas parciales no involucran a todos los datos. Así, de manera más fiable, bastará con no considerar las filas anteriores en nuestra suma. Luego, consideramos entonces
# un dataframe sin las filas anteriores, es decir,
# solo consideraremos a las filas que tengan asociados
# el valor de 0 o 1
asistencias = asistencias[asistencias['10'] <= 1]
# Volvemos a utilizar el siguiente codigo:
# Lista auxiliar para almacenar el # de asistencias totales por dia
asistencias_num = []
# Lista con el nombre de los dias
dias = ['Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes']
for i in range(5):
x = 0
# sumamos el total de asistencias por cada columna (de la columna 6 a la 10)
x = asistencias[str(i + 6)].sum()
# dado que la suma anterior nos dara en algunos casos
# un valor flotante o un valor entero, para que la salida
# de la informacion sea homogenea convertimos a x al tipo de
# dato int, y agregamos dicho valor a la lista asistencias_num
asistencias_num.append(int(x))
# Arrojamos un mensaje
msj = f'Asistencias del {dias[i]}: {int(x)}'
print(msj)
Asistencias del Lunes: 176 Asistencias del Martes: 166 Asistencias del Miercoles: 152 Asistencias del Jueves: 141 Asistencias del Viernes: 133
Vemos un comportamiento decreciente respecto a la asistencia diaria del curso. En porcentajes
asistencias.shape
(249, 5)
# Proporcion de asistencias
porcentajes = []
# Dias
dias = ['Lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes']
for i in range(5):
x = asistencias[str(i + 6)].sum()
# Calculamos los porcentajes
porcentajes.append((x / asistencias.shape[0]) * 100)
# Arrojamos un mensaje y redondeamos los porcentajes a
# dos decimales
msj = f'Asistencias del {dias[i]}: {round( porcentajes[i], 2 )}%'
print(msj)
Asistencias del Lunes: 70.68% Asistencias del Martes: 66.67% Asistencias del Miercoles: 61.04% Asistencias del Jueves: 56.63% Asistencias del Viernes: 53.41%
Donde el númeto total de inscritos en el propedéutico es de 249 y notamos que el primer día del curso asistieron alrededor del 70.68% de estudiantes inscritos; luego, el viernes tan solo asistieron alrededor del 53.41% de los inscritos.
Comenzamos por ver la gráfica de los porcentajes de asistencia en cada día de la semana
# Tamanio del grafico de 12px de largo por 5px de ancho
fig = plt.figure(figsize=(12,5))
# Grafico de dias versus porcentajes de asistencias
# Creara un grafico de lineas:
plt.plot(dias, porcentajes, color="#00E9FE")
# Graficaremos cada uno de los puntos (Lunes, 70.68),
# (Martes, 66.67), etc
for i in range(5):
plt.plot(dias[i], porcentajes[i], marker="o", color="#FE0404")
# Mostraremos etiquetas de texto en nuestro grafico
# que contengan la informacion del numero de
# asistencias totales por cada dia
plt.text(dias[i], porcentajes[i]-0.8, asistencias_num[i])
plt.legend(["Tendencia", "# Asistencias"])
plt.ylabel("Porcentaje")
plt.xlabel("Día")
plt.title("Porcentaje de asistencia de la semana")
plt.show()
Veamos ahora qué tan constantes fueron los alumnos. Para ello, sumaremos los valores de las columnas 6-10 para cada fila, esto es, veremos cuántas asistencias obtuvo cada estudiante y los clasificaremos. Recordemos que cada fila representa a un estudiante, de tal manera, si ahora sumamos por filas obtendremos el número total de asistencias por cada estudiante
# Dado que la suma la hacemos ahora por filas,
# entonces escribimos sum(axis=1)
asis_por_alumno = asistencias.sum(axis=1)
# Convertimos lo anterior a un dataframe
asis_por_alumno = pd.DataFrame(asis_por_alumno)
asis_por_alumno
0 | |
---|---|
0 | 1.0 |
1 | 0.0 |
2 | 5.0 |
3 | 4.0 |
4 | 4.0 |
... | ... |
256 | 4.0 |
257 | 5.0 |
258 | 2.0 |
259 | 1.0 |
260 | 0.0 |
249 rows × 1 columns
Lo anterior no es tan visual. Para entender mejor la información anterior clasificaremos a los alumnos por aquellos que obtuvieron 0 asistencias, 1 asistencia, etcétera.
Lo anterior lo conseguiremos utilizando el método value_counts()
que identifica los distintos valores de una columna de un dataframe, y cuenta el número de apariciones de dichos valores. Por ejemplo, en el dataframe asis_por_alumno
identificamos los distintos valores 0,1,2,3,4 y 5, luego, se contará cuántas veces apareció en dicha columna el valor 0, cuántas veces apareció en dicha columna el valor 1, etcétera. Así:
asis_por_alumno.value_counts()
5.0 103 0.0 55 4.0 41 1.0 23 2.0 15 3.0 12 dtype: int64
que nos dice que en total:
Con base en lo anterior podemos construir la siguiente gráfica
# Obtengamos el total de asistencias por cada
# dia y guardemoslo en una lista auxiliar
num_group = []
for i in range(6):
num_group.append(asis_por_alumno.value_counts()[i])
num_group
[55, 23, 15, 12, 41, 103]
donde
Número de asistencias | Total de alumnos | Índice en la lista num_group |
---|---|---|
0 | 55 | 0 |
1 | 23 | 1 |
2 | 15 | 2 |
3 | 12 | 3 |
4 | 41 | 4 |
5 | 103 | 5 |
Continuando
fig = plt.figure(figsize=(12,5))
# Numeros posibles de asistencias de la semana para cada alumno
lista_asistencias = [0, 1, 2, 3, 4, 5]
# Graficamos
colores = ["#FE0404", "#FE0404","#FE9304", "#FE9304", "#62FF00", "#62FF00"]
# Lista de posibles| numero total de alumnos
# asistencias | con ese numero de
# (0,1,2,3,4,5) | asistencias
plt.bar(lista_asistencias, num_group, color=colores)
# Agregamos un texto informativo con el total de alumnos
# que asistieron 5 dias, 4, etc
for i in range(6):
plt.text(i-0.06, num_group[i]-10, num_group[i], color="black")
plt.xlabel("Número de asistencias totales")
plt.ylabel("Número de alumnos")
plt.title("Alumnos por número de asistencias de la semana")
plt.show()
Notamos que bastantes alumnos no obtuvieron ninguna asistencia en la semana; unos pocos alumnos tuvieron entre 2 y 3 asistencias en la semana y, la mayoría, fue constante con sus asistencias al tener entre 4 y 5 asistencias.
Hemos abordado ya las cuestiones que planteamos al inicio, por lo cual el análisis ha terminado. Con todo lo anterior nos damos una idea intuitiva de cómo realizar un pequeño análisis sobre los datos que sean de interés, además, el primer paso siempre debe ser explorar los datos (también de manera gráfica si es posible) para así ver algunas estadísticas, ver la "naturaleza" de nuestros datos, ver si hay datos faltantes o si debemos realizar algunas modificaciones (limpieza de datos). Una vez hecho lo anterior podremos indagar en las cuestiones que se nos han planteado y, ahora sí, realizar un análisis sobre nuestros datos.