1.- Análisis y limpieza de un conjunto de datos¶
Objetivo: Familiarizarse con el análisis y limpieza de datos a través de un conjunto de datos simulados.
Se requiere llevar a cabo los siguientes pasos:
- Cargar los datos en un DataFrame de Pandas y visualizar las primeras filas.
- Identificar y manejar valores faltantes.
- Detectar y corregir valores fuera de rango.
- Apoyarte en la visualización de datos para encontrar valores atípicos.
- Crear una nueva columna dependencia_movil, calculada mediante la fórmula: horas_movil_dia × (11 – satisfacción).
- Generar un AED básico comentando los estadísticos más importantes.
- Exportar el DataFrame procesado a un archivo CSV, el cual será descargado.
import numpy as np
import pandas as pd
df = pd.read_csv('content/encuesta.csv')
df.head(10)
| edad | genero | horas_movil_dia | satisfaccion | red_social_principal | |
|---|---|---|---|---|---|
| 0 | 24 | Femenino | 3.5 | 8 | |
| 1 | 30 | Masculino | 2.0 | 7 | |
| 2 | 18 | Femenino | 5.5 | 9 | TikTok |
| 3 | 45 | Masculino | 1.5 | 6 | |
| 4 | 29 | Otro | 4.0 | 5 | |
| 5 | 55 | Femenino | 2.0 | 8 | |
| 6 | 22 | Masculino | 6.0 | 7 | |
| 7 | 33 | Femenino | 3.0 | 6 | |
| 8 | 41 | Masculino | 1.0 | 9 | |
| 9 | 19 | Otro | 7.0 | 8 |
- Identificar y manejar valores faltantes
df.isnull().sum()
edad 1 genero 1 horas_movil_dia 2 satisfaccion 3 red_social_principal 1 dtype: int64
Identificamos valores faltantes pero si son numéricos los trataremos más tarde
Edad, horas_movil_dia y satisfacción son numéricas
Genero y red_social_principal son categoricas y no faltan demasiados valores
Vamos a intentar procesar estas últimas
df['genero'].value_counts(dropna=False)
genero Femenino 45 Masculino 38 Otro 16 NaN 1 Name: count, dtype: int64
Podríamos decidir usar la moda en este campo, pero al existir ya la categoria "Otro" también podemos elegirla. Podría pasar que alguien acostumbrado a no poner masculino o femenino lo dejase vacío. Usaremos este razonamiento
df['genero'] = df['genero'].fillna('Otro')
df['genero'].value_counts(dropna=False)
genero Femenino 45 Masculino 38 Otro 17 Name: count, dtype: int64
df['red_social_principal'].value_counts(dropna=False)
red_social_principal Instagram 27 TikTok 21 Facebook 19 Twitter 16 LinkedIn 16 NaN 1 Name: count, dtype: int64
En este caso no podemos hacer una imputación lógica, pero al tener un ganador claro se justifica el uso de la moda.
(Al ser solo un registro, tampoco vamos a cambiar demasiado el caracter de la serie)
moda_red_social = df['red_social_principal'].mode()[0]
df['red_social_principal'] = df['red_social_principal'].fillna(moda_red_social)
print(df[['genero', 'red_social_principal']].isnull().sum())
genero 0 red_social_principal 0 dtype: int64
Como comprobación adicional ¿Puede que haya '0' en lugar de nulos? Lo comprobamos
(df == 0).sum()
edad 0 genero 0 horas_movil_dia 0 satisfaccion 0 red_social_principal 0 dtype: int64
- Detectar y corregir valores fuera de rango
Antes de calcular medias o modas para rellenar huecos vacíos, debemos asegurarnos de que nuestros datos son únicos o nuestro rango estará viciado.
df.duplicated().sum()
np.int64(8)
Tenemos 8 duplicados, pero como no tenemos un identificador único, puede que sean casualidades
# Como no sabemos si podemos borrar o no, pintamos todas las filas y buscamos patrones
df[df.duplicated(keep=False)]
| edad | genero | horas_movil_dia | satisfaccion | red_social_principal | |
|---|---|---|---|---|---|
| 0 | 24 | Femenino | 3.5 | 8 | |
| 1 | 30 | Masculino | 2.0 | 7 | |
| 2 | 18 | Femenino | 5.5 | 9 | TikTok |
| 3 | 45 | Masculino | 1.5 | 6 | |
| 4 | 29 | Otro | 4.0 | 5 | |
| 5 | 55 | Femenino | 2.0 | 8 | |
| 7 | 33 | Femenino | 3.0 | 6 | |
| 8 | 41 | Masculino | 1.0 | 9 | |
| 20 | 24 | Femenino | 3.5 | 8 | |
| 21 | 30 | Masculino | 2.0 | 7 | |
| 22 | 18 | Femenino | 5.5 | 9 | TikTok |
| 23 | 45 | Masculino | 1.5 | 6 | |
| 24 | 29 | Otro | 4.0 | 5 | |
| 25 | 55 | Femenino | 2.0 | 8 | |
| 27 | 33 | Femenino | 3.0 | 6 | |
| 28 | 41 | Masculino | 1.0 | 9 |
# Podemos ver que la repetición va en bloque ( los 8 primeros son los mismos que los 8 últimos) borramos los últimos
df = df.drop_duplicates(keep='first')
df.duplicated().sum()
np.int64(0)
Con las variables categóricas ya vimos que no hay valores fuera de rango (errores tipográficos, fallos en el orden de columnas, etc.). Pero mejor volver a comprobarlo listando valores
print(df['genero'].value_counts())
print(df['red_social_principal'].value_counts())
genero Femenino 41 Masculino 35 Otro 16 Name: count, dtype: int64 red_social_principal Instagram 25 TikTok 20 Facebook 18 Twitter 15 LinkedIn 14 Name: count, dtype: int64
Con las numéricas tenemos que comprobarlo todavía y el primer paso es ver si efectivamente todos los valores son numéricos.
Este es buen momento para identificar también los campos vacíos, pero aún no los modificamos
columnas_numericas = ['edad', 'satisfaccion', 'horas_movil_dia']
# Usamos un df auxiliar porque el coerce nos va a borrar los valores no numéricos (pone NaN)
df_numerico = df[columnas_numericas].apply(pd.to_numeric, errors='coerce')
# Ahora comparamos los NaN del df auxiliar para ver que había en el df original, así podemos modificar lo que nos interese
df[df_numerico.isna().any(axis=1)]
| edad | genero | horas_movil_dia | satisfaccion | red_social_principal | |
|---|---|---|---|---|---|
| 31 | 28 | Masculino | NaN | 8 | |
| 33 | NaN | Masculino | 4.0 | 5 | TikTok |
| 35 | 32 | Otro | 3.0 | NaN | |
| 62 | Veinte | Femenino | 5.0 | 8 | TikTok |
| 63 | 40 | Masculino | 2.5 | Baja | |
| 85 | 33 | Otro | 3.5 | NaN | |
| 91 | 61 | Femenino | NaN | 8 | |
| 94 | 30 | Masculino | 4.0 | NaN |
Todos los valores incorrectos eran ya NaN excepto el 'veinte' de edad y el 'Baja' de satisfacción,
Para 'veinte', le asignamos su valor numérico (20)
Para 'Baja', decidimos asignarle un valor suficientemente bajo (3)
df.loc[df['edad'] == 'Veinte', 'edad'] = 20
df.loc[df['satisfaccion'] == 'Baja', 'satisfaccion'] = 3
# Nos aseguramos de que nuestras columnas corregidas sean reconocidas como numéricas
df[columnas_numericas] = df[columnas_numericas].apply(pd.to_numeric)
df[columnas_numericas].dtypes
# Seguimos sin tocar valores faltantes de momento, pero ya los tenemos localizados
edad float64 satisfaccion float64 horas_movil_dia float64 dtype: object
Hemos identificado los valores faltantes y hemos modificado los "incorrectos".
¿Por qué aún no terminamos el apartado?
Porque si "rellenásemos" nulos con un valor calculado podría pasar que introdujeramos la distorsión de los valores atípicos que aún no hemos tratado
- Apoyarte en la visualización de datos para encontrar valores atípicos.
import matplotlib.pyplot as plt
import seaborn as sns
fig, ax = plt.subplots(1,3)
sns.boxplot(data=df[columnas_numericas[0]], ax=ax[0])
sns.boxplot(data=df[columnas_numericas[1]], ax=ax[1])
sns.boxplot(data=df[columnas_numericas[2]], ax=ax[2])
plt.tight_layout()
Viendo el gráfico es muy claro que hay:
- 3 outliers altos en edad
- 2 altos en satisfaccion
- 2 altos en horas
Podríamos recalcular cuartiles y con ellos los outliers, pero es mucho más sencillo apoyarnos en los valores del gráfico y revisar exactamente esos valores.
Sin embargo también debemos revisar valores por debajo del minimo y máximo aceptable (negativos, valores irreales...)
# Menores de 13 no deben usar RRSS
valores_extremos1 = df.loc[(df['edad'] < 13) | (df['edad'] > 120), 'edad']
# Un día tiene 24 horas (podríamos discutir si alguien puede estar 24 horas con el móvil...)
valores_extremos2 = df.loc[(df['horas_movil_dia'] < 0) | (df['horas_movil_dia'] > 24), 'horas_movil_dia']
# La satisfacción se medía en una escala de 0 a 10
valores_extremos3 = df.loc[(df['satisfaccion'] < 0) | (df['satisfaccion'] > 10), 'satisfaccion']
pd.concat([valores_extremos1, valores_extremos2, valores_extremos3], axis=1)
| edad | horas_movil_dia | satisfaccion | |
|---|---|---|---|
| 54 | 200.0 | NaN | NaN |
| 58 | -5.0 | NaN | NaN |
| 59 | 5.0 | NaN | NaN |
| 43 | NaN | 25.0 | NaN |
| 55 | NaN | 30.0 | NaN |
| 44 | NaN | NaN | 12.0 |
| 57 | NaN | NaN | 15.0 |
Vemos que hay una edad negativa, un niño de 5 años, una persona de 200, además 2 valores erroneos en horas y otros 2 en satisfacción.
Tanto horas como satisfacción coinciden con el gráfico, pero edad tenemos que tratarla añadiendo los outliers inferiores.
grafico = df['edad'].nlargest(3)
inferiores = df['edad'].nsmallest(2)
pd.concat([grafico, inferiores])
54 200.0 42 120.0 49 99.0 58 -5.0 59 5.0 Name: edad, dtype: float64
Las edades de 200, 120, -5 y el niño de 5 años son claramente un error pero podemos dudar con el 99
df.loc[[49]]
| edad | genero | horas_movil_dia | satisfaccion | red_social_principal | |
|---|---|---|---|---|---|
| 49 | 99.0 | Otro | 1.0 | 5.0 |
La fila completa tiene datos "genericos" con valores que perfectamente pueden ser de prueba: edad al máximo, genero indeterminado, unidad de horas, satisfacción media...
No tiene sentido conservarla con ese riesgo
# Eliminamos la fila 49
df = df.drop([49])
Vamos a inspeccionar también las filas de -5, 5, 200 y 120 años por si hay algo que podamos inferir, como un error tipográfico. Si no lo hay las borraremos
# Inspeccionamos las filas completas de los outliers extremos
df.loc[[54, 42, 58, 59]]
| edad | genero | horas_movil_dia | satisfaccion | red_social_principal | |
|---|---|---|---|---|---|
| 54 | 200.0 | Femenino | 1.5 | 8.0 | |
| 42 | 120.0 | Femenino | 2.0 | 8.0 | |
| 58 | -5.0 | Femenino | 3.0 | 8.0 | |
| 59 | 5.0 | Masculino | 2.0 | 9.0 |
Como no podemos adivinar la edad real sin inventárnosla borramos las filas que distorsionan el conjunto
df = df.drop([54, 42, 58, 59])
# 2. SATISFACCIÓN:
pd.concat([df['satisfaccion'].nlargest(2)])
57 15.0 44 12.0 Name: satisfaccion, dtype: float64
En una escala del 1 al 10 está claro que 15 y 12 son incorrectos, podemos eliminar o poner el máximo. Al evaluar el concepto "satisfacción" podemos pensar que en estos valores la intención del usuario era dar la nota máxima, por ello podemos elegir sustituir
df['satisfaccion'] = df['satisfaccion'].clip(upper=10)
# 3. HORAS MÓVIL
df['horas_movil_dia'].nlargest(2)
55 30.0 43 25.0 Name: horas_movil_dia, dtype: float64
El día tiene 24 horas así que 30 y 25 son errores. Con "satisfacción" considerábamos la intención del usuario por ello elegimos sustituir, pero aquí no es clara la intención así que podemos eliminar el registro completo o el dato en concreto.
Para ello podemos borrar la fila o poner el valor como nulo.
Elegimos poner nulo, para posteriormente tratarlo con el valor correspondiente (ahora viene bien no haber tocado nulos en numéricos)
print(df[df['horas_movil_dia'].isna()])
df.loc[df['horas_movil_dia'] > 24, 'horas_movil_dia'] = np.nan
print(df[df['horas_movil_dia'].isna()])
edad genero horas_movil_dia satisfaccion red_social_principal
31 28.0 Masculino NaN 8.0 Twitter
91 61.0 Femenino NaN 8.0 Facebook
edad genero horas_movil_dia satisfaccion red_social_principal
31 28.0 Masculino NaN 8.0 Twitter
43 19.0 Otro NaN 7.0 TikTok
55 25.0 Otro NaN 6.0 TikTok
91 61.0 Femenino NaN 8.0 Facebook
fig, ax = plt.subplots(1,3)
sns.boxplot(data=df[columnas_numericas[0]], ax=ax[0])
sns.boxplot(data=df[columnas_numericas[1]], ax=ax[1])
sns.boxplot(data=df[columnas_numericas[2]], ax=ax[2])
plt.tight_layout()
No tenemos outliers (aunque podriamos tenerlos si estuviesen justificados), así que en este momento tratamos los nulos numéricos
df[df.isna().any(axis=1)]
| edad | genero | horas_movil_dia | satisfaccion | red_social_principal | |
|---|---|---|---|---|---|
| 31 | 28.0 | Masculino | NaN | 8.0 | |
| 33 | NaN | Masculino | 4.0 | 5.0 | TikTok |
| 35 | 32.0 | Otro | 3.0 | NaN | |
| 43 | 19.0 | Otro | NaN | 7.0 | TikTok |
| 55 | 25.0 | Otro | NaN | 6.0 | TikTok |
| 85 | 33.0 | Otro | 3.5 | NaN | |
| 91 | 61.0 | Femenino | NaN | 8.0 | |
| 94 | 30.0 | Masculino | 4.0 | NaN |
Tenemos nulos en todas las columnas numéricas ¿con que los rellenamos?
Tras eliminar los outliers la media y la mediana son estadísticamente similares en este dataset. Sin embargo tenemos valores enteros (o redondeados).
La media aritmética casi siempre genera decimales, lo cual resulta artificial.
La mediana nos facilitaría mantener valores enteros más realistas.
Aún así también podemos redondear para no tener ninguna posibilidad de decimales.
Finalmente usaremos la media redondeada, aunque la mediana también sería válida.
for col in columnas_numericas:
media = df[col].mean().round()
df[col] = df[col].fillna(media)
print(f"Columna {col} rellenada con: {media}")
Columna edad rellenada con: 35.0 Columna satisfaccion rellenada con: 7.0 Columna horas_movil_dia rellenada con: 4.0
- Crear una nueva columna dependencia_movil, calculada mediante la fórmula: horas_movil_dia × (11 – satisfacción)
df['dependencia_movil'] = df['horas_movil_dia'] * (11 - df['satisfaccion'])
df
| edad | genero | horas_movil_dia | satisfaccion | red_social_principal | dependencia_movil | |
|---|---|---|---|---|---|---|
| 0 | 24.0 | Femenino | 3.5 | 8.0 | 10.5 | |
| 1 | 30.0 | Masculino | 2.0 | 7.0 | 8.0 | |
| 2 | 18.0 | Femenino | 5.5 | 9.0 | TikTok | 11.0 |
| 3 | 45.0 | Masculino | 1.5 | 6.0 | 7.5 | |
| 4 | 29.0 | Otro | 4.0 | 5.0 | 24.0 | |
| ... | ... | ... | ... | ... | ... | ... |
| 95 | 20.0 | Femenino | 6.0 | 8.0 | TikTok | 18.0 |
| 96 | 55.0 | Otro | 1.5 | 9.0 | 3.0 | |
| 97 | 34.0 | Masculino | 3.0 | 6.0 | 15.0 | |
| 98 | 48.0 | Femenino | 2.0 | 7.0 | 8.0 | |
| 99 | 25.0 | Masculino | 5.0 | 5.0 | TikTok | 30.0 |
87 rows × 6 columns
Mediante la fórmula horas_movil_dia×(11–satisfaccion), logramos invertir la escala de satisfacción: de este modo, una puntuación baja de felicidad actúa como un multiplicador de impacto, mientras que una satisfacción alta reduce el peso de las horas de uso.
Esta métrica permite diferenciar entre un uso intensivo pero funcional y un uso potencialmente problemático.
Al amplificar los casos donde confluyen muchas horas de pantalla y baja satisfacción, el dataset gana una dimensión analítica que permitiría segmentar a los usuarios por el impacto que dicho comportamiento tiene en su calidad de vida.
- Generar un AED básico comentando los estadísticos más importantes
display(df.describe(include='all').round(2))
| edad | genero | horas_movil_dia | satisfaccion | red_social_principal | dependencia_movil | |
|---|---|---|---|---|---|---|
| count | 87.00 | 87 | 87.00 | 87.00 | 87 | 87.00 |
| unique | NaN | 3 | NaN | NaN | 5 | NaN |
| top | NaN | Femenino | NaN | NaN | NaN | |
| freq | NaN | 38 | NaN | NaN | 24 | NaN |
| mean | 35.17 | NaN | 3.55 | 7.08 | NaN | 14.08 |
| std | 12.57 | NaN | 1.52 | 1.39 | NaN | 7.75 |
| min | 18.00 | NaN | 1.00 | 3.00 | NaN | 2.00 |
| 25% | 25.00 | NaN | 2.35 | 6.00 | NaN | 8.00 |
| 50% | 33.00 | NaN | 3.50 | 7.00 | NaN | 12.80 |
| 75% | 44.50 | NaN | 4.50 | 8.00 | NaN | 20.00 |
| max | 65.00 | NaN | 7.00 | 10.00 | NaN | 36.00 |
Count es igual en todas las columnas confirmando que ya no hay nulos.
No tenemos edades, horas ni niveles de satisfacción fuera de rango.
El análisis más básico nos dice que los datos son plausibles.
Para empezar a sacar conclusiones vamos a ver la relación entre variables, sobre todo con la variable calculada de dependencia móvil.
df.corr(numeric_only=True).round(2)
| edad | horas_movil_dia | satisfaccion | dependencia_movil | |
|---|---|---|---|---|
| edad | 1.00 | -0.84 | 0.16 | -0.68 |
| horas_movil_dia | -0.84 | 1.00 | -0.07 | 0.74 |
| satisfaccion | 0.16 | -0.07 | 1.00 | -0.69 |
| dependencia_movil | -0.68 | 0.74 | -0.69 | 1.00 |
Vemos que hay una clara correlación negativa entre la edad y las horas de uso del móvil (los mayores lo usan menos)
Para la satisfacción no hay correlaciones claras con ninguna variable.
La dependencia móvil la calculamos desde horas y satisfación por lo que no tiene sentido analizar su correlación (sabemos que viene de la fórmula: dependencia_movil = horas_movil_dia × (11 – satisfacción)). Y muestra una ligera correlación con la edad (debido a la diferencia de horas entre distintas edades).
Sin embargo puede ser interesante relacionarla con las variables categóricas.
df.groupby('genero')['dependencia_movil'].agg(['mean', 'count'])
| mean | count | |
|---|---|---|
| genero | ||
| Femenino | 10.613158 | 38 |
| Masculino | 15.500000 | 34 |
| Otro | 19.633333 | 15 |
Respecto al genero vemos grandes diferencias. "Masculino" presenta un índice un 50% superior a "Femenino" y "Otro" es casi el doble, aunque la muestra de "Otro" es más pequeña no es algo excesivo, lo que nos sugiere que este perfil es el más vulnerable a la dependencia tecnológica en nuestro estudio.
tabla = df.groupby('red_social_principal')['dependencia_movil'].agg(['mean', 'count'])
tabla.sort_values(by='mean', ascending=False).round(2)
| mean | count | |
|---|---|---|
| red_social_principal | ||
| TikTok | 21.40 | 20 |
| 15.53 | 15 | |
| 14.31 | 24 | |
| 9.21 | 12 | |
| 6.87 | 16 |
Respecto a la red social vemos aún más diferencias: TikTok va en cabeza triplicando a Facebook, en la que se nota un uso mucho más esporádico. Podemos pensar que esto tiene más que ver con la edad que con la red social, pero debemos comprobarlo
# Debemos categorizar las edades para poder relacionar con variable categórica
df['rango_edad'] = pd.cut(df['edad'], bins=[0, 30, 45, 100], labels =['Joven', 'Adulto', 'Mayor'])
print(df['rango_edad'].value_counts())
df
rango_edad Joven 39 Adulto 28 Mayor 20 Name: count, dtype: int64
| edad | genero | horas_movil_dia | satisfaccion | red_social_principal | dependencia_movil | rango_edad | |
|---|---|---|---|---|---|---|---|
| 0 | 24.0 | Femenino | 3.5 | 8.0 | 10.5 | Joven | |
| 1 | 30.0 | Masculino | 2.0 | 7.0 | 8.0 | Joven | |
| 2 | 18.0 | Femenino | 5.5 | 9.0 | TikTok | 11.0 | Joven |
| 3 | 45.0 | Masculino | 1.5 | 6.0 | 7.5 | Adulto | |
| 4 | 29.0 | Otro | 4.0 | 5.0 | 24.0 | Joven | |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 95 | 20.0 | Femenino | 6.0 | 8.0 | TikTok | 18.0 | Joven |
| 96 | 55.0 | Otro | 1.5 | 9.0 | 3.0 | Mayor | |
| 97 | 34.0 | Masculino | 3.0 | 6.0 | 15.0 | Adulto | |
| 98 | 48.0 | Femenino | 2.0 | 7.0 | 8.0 | Mayor | |
| 99 | 25.0 | Masculino | 5.0 | 5.0 | TikTok | 30.0 | Joven |
87 rows × 7 columns
media_por_rango = df.groupby('rango_edad')['dependencia_movil'].mean()
moda_red_social = df.groupby('rango_edad')['red_social_principal'].apply(lambda x: x.mode()[0])
pd.concat([media_por_rango, moda_red_social], axis=1)
| dependencia_movil | red_social_principal | |
|---|---|---|
| rango_edad | ||
| Joven | 19.284615 | TikTok |
| Adulto | 12.378571 | |
| Mayor | 6.305000 |
Al cruzar los datos por edad, nuestra sospecha se confirma:
El grupo Joven tiene una dependencia altísima y su red favorita es TikTok.
El grupo Mayor tiene una dependencia muy baja y su red favorita es Facebook.
El ranking de redes sociales es casi un espejo del ranking de edad. No es necesariamente que TikTok tenga más dependencia, sino que su público (los jóvenes) tienen hábitos de conexión mayores.
Correlación es distinto a causalidad.
Si queréis ver más sobre este concepto pasaros por mi blog:
Para verlo "en números" debemos usar la librería pingouin.
Deberemos instalar la librería:
A) usando consola
pip install pingouinB) o una celda en Colab
!pip install pingouin
import pingouin as pg
# 1. Convertimos la red social a números (necesario para la función)
df['red_social_num'] = df['red_social_principal'].astype('category').cat.codes
# 2. Lanzamos la correlación parcial eliminando el factor red_social
resultado_edad = pg.partial_corr(data=df,
x='dependencia_movil',
y='edad',
covar='red_social_num')
display(resultado_edad)
| n | r | CI95% | p-val | |
|---|---|---|---|---|
| pearson | 87 | -0.582935 | [-0.71, -0.42] | 3.886556e-09 |
Expliquemos ese dato:
Pregunta: Si todo el mundo usara la misma red social, ¿la edad seguiría influyendo en la dependencia?
Resultado (-0.58): Al estar más cerca de -1 que de 0, nos dice que sí, y mucho. A medida que la edad aumenta, la dependencia del móvil disminuye. La edad tiene un peso propio muy fuerte que no depende de si el usuario está en TikTok o en Facebook.
# 3. Lanzamos la correlación parcial eliminado el factor edad
resultado_red = pg.partial_corr(data=df,
x='dependencia_movil',
y='red_social_num',
covar='edad')
display(resultado_red)
| n | r | CI95% | p-val | |
|---|---|---|---|---|
| pearson | 87 | 0.129271 | [-0.08, 0.33] | 0.235521 |
Pregunta: Si todo el mundo tuviera la misma edad, ¿la elección de la red social seguiría explicando la dependencia?
Resultado (0.129): Es un valor mucho más cercano a 0
Nuestra sospecha se confirma matemáticamente: el ranking de redes sociales es, efectivamente, un espejo del ranking de edad.
Al realizar la correlación parcial, observamos que mientras la edad mantiene una influencia sólida sobre la dependencia (r=−0.58), el peso de la red social se desploma hasta un residual 0.12 cuando aislamos el efecto de la edad.
Esto demuestra que la red social (como TikTok o Facebook) no es la causa principal de la dependencia, sino una variable que simplemente refleja el perfil generacional del usuario. La dependencia es una cuestión generacional más que de plataforma.
- Exportar el DataFrame procesado a un archivo CSV, el cual será descargado.
df.to_csv('tarea.csv', index=False)