Proyecto 7 · Sprint 8 · Python

NovaRetail+:
explorando drivers de comportamiento

Analicé 15.000 registros de clientes para identificar qué comportamientos se asocian con el ingreso anual generado. Compras, visitas, publicidad y premium se contrastan con evidencia visual y numérica, sin confundir correlación con causalidad.

PythonPandasNumPySeabornMatplotlibSciPyJupyter

Resumen del proyecto

Una base completa de 15.000 registros, cuatro métodos de asociación y una pregunta central: qué comportamientos se relacionan con el ingreso generado para NovaRetail+.

Qué hice
  • Cargué y revisé la estructura de una tabla de 15.000 filas y 12 columnas.
  • Corregí el tipo de edad y documenté el significado de cada variable.
  • Exploré distribuciones, outliers, indicadores binarios, dispositivos y regiones.
  • Construí matrices Pearson y Spearman y un PairGrid con color por región.
  • Visualicé los pares visitas–ingreso anual y compras–ingreso anual.
  • Calculé punto-biserial y V de Cramér para tipos de variables distintos.
  • Traducí los resultados en hallazgos no causales, limitaciones y próximos pasos.
Aporte como Data Analyst

Mi aporte fue organizar la exploración del comportamiento del cliente en una secuencia reproducible: entender la calidad del dataset, elegir un coeficiente según el tipo de variable y contrastar las cifras con gráficos.

Diferencié el ingreso estimado del cliente del ingreso que genera para la empresa. También separé el tamaño de una asociación de su posible relevancia comercial.

El proyecto combina análisis exploratorio, funciones reutilizables y comunicación ejecutiva. No propone aumentar presupuesto o prometer revenue sin evidencia adicional.
65,45 %
registros con dispositivo móvil
9.818 de 15.000 registros
13,93 %
indicador miembro_premium = 1
Proporción descrita por la media binaria
15,07 %
indicador abandono = 1
No es una tasa mensual de churn
≥ 25 %
registros con ingreso anual cero
Límite inferior: mínimo = Q1 = 0
Diccionario de las 12 variables
CampoTipo / funciónSignificado
id_clienteIdentificadorCódigo del cliente; no se usa para correlacionar.
edadNumérica · enteroEdad en años; se convirtió de float64 a int64.
nivel_ingresoNuméricaIngreso anual estimado del cliente, distinto del revenue que genera.
visitas_mesNumérica · conteoVisitas durante el mes a la app o al sitio web.
compras_mesNumérica · conteoCompras realizadas durante el mes.
gasto_publicidad_dirigidaNuméricaGasto en anuncios asignado al usuario.
satisfaccionNumérica · escalaCalificación del cliente de 1 a 5.
miembro_premiumBinaria1 = premium; 0 = no premium.
abandonoBinaria1 = abandonó la plataforma; 0 = no.
tipo_dispositivoCategóricaMóvil, escritorio o tablet.
regionCategóricaNorte, oeste, sur o este.
ingreso_anualNumérica · objetivoIngreso anual generado por el cliente para NovaRetail+.
Ver resumen estadístico completo de las variables numéricas
VariableMediaMedianaMínimoMáximoQ1 / Q3
Edad38,2638,0018,0075,0030,00 / 46,00
Ingreso estimado del cliente30.019,7030.023,748.000,0074.790,8423.127,10 / 36.768,44
Visitas del mes10,0310,001,0025,008,00 / 12,00
Compras del mes1,211,000,008,000,00 / 2,00
Gasto publicitario dirigido20,1519,730,0075,5112,31 / 27,29
Satisfacción3,603,601,005,003,10 / 4,10
Ingreso anual para la empresa36,5930,700,00244,690,00 / 58,22

Valores de describe() y medianas guardados en la celda 19. Las unidades monetarias de ingreso_anual no se especifican de forma explícita en el diccionario; se conservan sus valores sin atribuirles una moneda. No se calcula una tasa de conversión con la razón entre medias de compras y visitas.

Proceso analítico, sección a sección

Las seis secciones del notebook se mantienen en el orden original. Cada bloque explica lo realizado, las cifras relevantes y el código disponible para revisarlo.

01

Sección 1. Cargar y explorar el dataset

15.000 registros · 12 columnas · 0 nulos

Importé Pandas, NumPy, Seaborn y Matplotlib. Cargué novaretail_comportamiento_clientes_2024.csv con pd.read_csv() y revisé la estructura mediante info() y las primeras cinco filas con head(5).

Las doce columnas muestran 15.000 valores no nulos. El índice va de 0 a 14.999: el total es 15.000 filas, no 14.999. El análisis utiliza todo el conjunto disponible.

Pregunta de negocio: ¿qué factores del comportamiento del cliente están más fuertemente asociados con el ingreso anual que genera para la empresa?
Ver código y salidas guardadas de esta sección

Celda 7 · código original

# Importar librerías
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

Sin salida textual adicional guardada. Las figuras y matrices se incluyen en la galería.

Celda 9 · código original

# Cargar el dataset y explorar datos
# df = pd.read_csv("https://drive.google.com/uc?export=download&id=1-eHDkD0ZapRUKZ2zoWojNzT-Ufy_nqX9") (CODIGO AUXILIAR WEB DIRECTO)
df = pd.read_csv("/datasets/novaretail_comportamiento_clientes_2024.csv")
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 15000 entries, 0 to 14999
Data columns (total 12 columns):
 #   Column                     Non-Null Count  Dtype  
---  ------                     --------------  -----  
 0   id_cliente                 15000 non-null  object 
 1   edad                       15000 non-null  float64
 2   nivel_ingreso              15000 non-null  float64
 3   visitas_mes                15000 non-null  int64  
 4   compras_mes                15000 non-null  int64  
 5   gasto_publicidad_dirigida  15000 non-null  float64
 6   satisfaccion               15000 non-null  float64
 7   miembro_premium            15000 non-null  int64  
 8   abandono                   15000 non-null  int64  
 9   tipo_dispositivo           15000 non-null  object 
 10  region                     15000 non-null  object 
 11  ingreso_anual              15000 non-null  float64
dtypes: float64(5), int64(4), object(3)
memory usage: 1.4+ MB

Celda 11 · código original

# mostrar las primeras 5 filas
df.head(5)
id_cliente edad nivel_ingreso visitas_mes compras_mes gasto_publicidad_dirigida satisfaccion miembro_premium abandono tipo_dispositivo region ingreso_anual
0 CL-100000 44.0 28565.77 9 1 31.36 3.9 0 0 móvil norte 23.22
1 CL-100001 36.0 29673.44 11 3 24.66 3.7 0 0 tablet sur 93.47
2 CL-100002 46.0 30642.95 9 0 0.00 2.9 0 0 móvil este 0.00
3 CL-100003 56.0 39468.61 8 0 6.81 3.1 0 0 móvil este 0.00
4 CL-100004 35.0 22527.83 9 2 26.49 2.3 0 0 móvil sur 33.76
02

Sección 2. Preparar datos y documentar supuestos

7 numéricas · 2 binarias · 2 categóricas · 1 identificador

Convertí edad de float64 a int64 y verifiqué el cambio. Separé las variables por tipo: siete numéricas, dos binarias y dos categóricas. Dejé id_cliente como identificador, fuera de los cálculos de asociación.

Calculé describe(), medianas y frecuencias. Definí funciones para generar histogramas y boxplots por variable, y countplots de dispositivos y regiones. No imputé nulos ni eliminé filas: las salidas no muestran valores faltantes.

Validé edades de 18 a 75 años, satisfacción entre 1 y 5, y variables binarias codificadas como 0/1. Se conservan valores cero plausibles en compras, publicidad e ingreso anual.

TipoMétodo utilizadoLectura
Numérica–numéricaPearson / SpearmanRelación lineal / monótona
Binaria–numéricaPunto-biserialAsociación del indicador con una variable numérica
Categórica–categóricaV de CramérIntensidad de asociación, sin signo
Supuesto central: el análisis es correlacional, no causal. La documentación y la página distinguen observaciones de hipótesis comerciales.
Ver código y salidas guardadas de esta sección

Celda 16 · código original

# Corregir el tipo de dato
df['edad'] = df['edad'].astype('int64')

Sin salida textual adicional guardada. Las figuras y matrices se incluyen en la galería.

Celda 17 · código original

# verificar cambios
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 15000 entries, 0 to 14999
Data columns (total 12 columns):
 #   Column                     Non-Null Count  Dtype  
---  ------                     --------------  -----  
 0   id_cliente                 15000 non-null  object 
 1   edad                       15000 non-null  int64  
 2   nivel_ingreso              15000 non-null  float64
 3   visitas_mes                15000 non-null  int64  
 4   compras_mes                15000 non-null  int64  
 5   gasto_publicidad_dirigida  15000 non-null  float64
 6   satisfaccion               15000 non-null  float64
 7   miembro_premium            15000 non-null  int64  
 8   abandono                   15000 non-null  int64  
 9   tipo_dispositivo           15000 non-null  object 
 10  region                     15000 non-null  object 
 11  ingreso_anual              15000 non-null  float64
dtypes: float64(4), int64(5), object(3)
memory usage: 1.4+ MB

Celda 19 · código original

# Estadísticas descriptivas de variables numéricas
variables_numericas = ['edad', 'nivel_ingreso', 'visitas_mes', 'compras_mes', 'gasto_publicidad_dirigida', 'satisfaccion', 'ingreso_anual']
variables_binarias = ['miembro_premium', 'abandono']
variables_categoricas = ['tipo_dispositivo', 'region']

print(df[variables_numericas].describe())
print()
print('Medianas de cada columna')
print(df[variables_numericas].median())

def distribuciones(df, columnas):
    for col in columnas:
        fig, axes = plt.subplots(1, 2, figsize=(12, 4))
        sns.histplot(data=df, x=col, bins=20, hue='tipo_dispositivo', kde=True, ax=axes[0])
        axes[0].axvline(x=df[col].mean(), color='red', linestyle='--', label='Media')
        axes[0].set_title(f"Distribución de los valores en {col}")
        axes[0].set_xlabel(f"Rango de {col}")
        axes[0].set_ylabel("Repeticiones")
        sns.boxplot(df[col], ax=axes[1])
        axes[1].set_title(f"Distribución de outliers en {col}")
        axes[1].set_xlabel(f"Rango de {col}")
        axes[1].set_ylabel("Repeticiones")
    return plt.show()

distribuciones(df, variables_numericas)
               edad  nivel_ingreso   visitas_mes   compras_mes  \
count  15000.000000   15000.000000  15000.000000  15000.000000   
mean      38.262400   30019.704782     10.029000      1.206467   
std       11.492378    9833.166305      3.158189      1.105284   
min       18.000000    8000.000000      1.000000      0.000000   
25%       30.000000   23127.097500      8.000000      0.000000   
50%       38.000000   30023.745000     10.000000      1.000000   
75%       46.000000   36768.440000     12.000000      2.000000   
max       75.000000   74790.840000     25.000000      8.000000   

       gasto_publicidad_dirigida  satisfaccion  ingreso_anual  
count               15000.000000  15000.000000   15000.000000  
mean                   20.149301      3.603693      36.594180  
std                    10.880724      0.685300      34.484888  
min                     0.000000      1.000000       0.000000  
25%                    12.310000      3.100000       0.000000  
50%                    19.730000      3.600000      30.705000  
75%                    27.292500      4.100000      58.220000  
max                    75.510000      5.000000     244.690000  

Medianas de cada columna
edad                            38.000
nivel_ingreso                30023.745
visitas_mes                     10.000
compras_mes                      1.000
gasto_publicidad_dirigida       19.730
satisfaccion                     3.600
ingreso_anual                   30.705
dtype: float64

Celda 22 · código original

# Verificar que cada columna tenga únicamente dos valores posibles
print(df[variables_binarias].describe())
print()
print(df[variables_binarias].value_counts(normalize=True))
print()
print(df[variables_binarias].nunique())

       miembro_premium      abandono
count     15000.000000  15000.000000
mean          0.139267      0.150733
std           0.346236      0.357801
min           0.000000      0.000000
25%           0.000000      0.000000
50%           0.000000      0.000000
75%           0.000000      0.000000
max           1.000000      1.000000

miembro_premium  abandono
0                0           0.716067
                 1           0.144667
1                0           0.133200
                 1           0.006067
dtype: float64

miembro_premium    2
abandono           2
dtype: int64

Celda 25 · código original

# Verificar el número de valores únicos por variable categórica
print(df[variables_categoricas].describe())
print()
print(df[variables_categoricas].nunique())
       tipo_dispositivo region
count             15000  15000
unique                3      4
top               móvil  norte
freq               9818   4395

tipo_dispositivo    3
region              4
dtype: int64

Celda 26 · código original

# Explorar variables categóricas y cómo se distribuyen
print(df[variables_categoricas].value_counts())              # frecuencia absoluta
print('____________________________')
print(df[variables_categoricas].value_counts(normalize=True)) # frecuencia relativa (porcentaje)

def graficar_cat(df, columnas):
    for col in columnas:
        otra_col = [c for c in columnas if c != col][0]
        plt.figure()
        sns.countplot(data=df, x=col, hue=otra_col)
    return plt.show()

graficar_cat(df, variables_categoricas)
tipo_dispositivo  region
móvil             norte     2843
                  oeste     2489
                  sur       2483
                  este      2003
escritorio        norte     1125
                  oeste      935
                  sur        894
                  este       766
tablet            norte      427
                  oeste      386
                  sur        349
                  este       300
dtype: int64
____________________________
tipo_dispositivo  region
móvil             norte     0.189533
                  oeste     0.165933
                  sur       0.165533
                  este      0.133533
escritorio        norte     0.075000
                  oeste     0.062333
                  sur       0.059600
                  este      0.051067
tablet            norte     0.028467
                  oeste     0.025733
                  sur       0.023267
                  este      0.020000
dtype: float64
03

Sección 3. Visualizar las relaciones

2 matrices coloreadas · PairGrid de 7 × 7 · 2 pares clave

Construí matrices con corr(method="pearson") y corr(method="spearman"), presentadas con Styler.background_gradient(cmap="coolwarm"). Estas son tablas HTML coloreadas originales, no imágenes estáticas.

Generé un PairGrid de siete variables, puntos diferenciados por región y líneas de regresión global fuera de la diagonal. Después destaqué dos scatterplots: visitas del mes frente al ingreso anual y compras del mes frente al ingreso anual.

El primer par presenta una relación positiva limitada y mayor dispersión; el segundo muestra una asociación muy fuerte. Las líneas son descriptivas: no representan un modelo predictivo validado ni un efecto causal.

La relación publicidad–visitas aparece en ambas matrices y en el PairGrid. No existe un scatterplot independiente guardado para ese par en la versión adjunta.

Ver código y salidas guardadas de esta sección

Celda 32 · código original

# Visualizar la matriz de correlación para identificar relaciones

def corr_numerica(df, columnas, metodo="pearson"):
    matriz = df[columnas].corr(method=metodo)
    return matriz.style.background_gradient(cmap="coolwarm")


# CODIGO MANUAL
#corr = df[variables_numericas].corr(method='pearson')
# corr.style.background_gradient(cmap="coolwarm") CODIGO AUXILIAR SIN IMAGEN

#plt.figure(figsize=(10,6))
#sns.heatmap(corr, annot=True, cmap="coolwarm", center=0)
#plt.title("Correlation Heatmap — NovaRetail+")
#plt.show()

#Codigo con Imagen

#def corr_numerica_imagen(df, columnas, metodo="pearson"):
#    matriz = df[columnas].corr(method=metodo)
#    plt.figure(figsize=(10,6))
#    sns.heatmap(matriz, annot=True, cmap="coolwarm", center=0)
#    plt.title(f"Correlation Heatmap Variables Numericas")
#    return plt.show()

#corr_numerica_imagen(df, variables_numericas, metodo="pearson")

Sin salida textual adicional guardada. Las figuras y matrices se incluyen en la galería.

Celda 33 · código original

corr_numerica(df, variables_numericas, metodo="pearson")
<pandas.io.formats.style.Styler at 0x7ff69ccafe20>

Celda 34 · código original

corr_numerica(df, variables_numericas, metodo="spearman")
<pandas.io.formats.style.Styler at 0x7ff6b29b5940>

Celda 38 · código original

#sns.pairplot(df, vars=variables_numericas, hue='region', kind='scatter') CODIGO DEL BOOTCAMP

# Paso 1: Crear el PairGrid (CODIGO DADO POR IA)
pg = sns.PairGrid(df, vars=variables_numericas, hue='region')

# Paso 2: Dibujar los puntos con color por región
pg.map_offdiag(sns.scatterplot)

# Paso 3: Recorrer cada subgráfico y agregar regresión global
for i, var_y in enumerate(variables_numericas):
    for j, var_x in enumerate(variables_numericas):
        if i != j:  # solo fuera de la diagonal
            sns.regplot(data=df, x=var_x, y=var_y,
                        scatter=False, ax=pg.axes[i][j],
                        color='black', line_kws={'linewidth': 1.5})

pg.add_legend()
plt.show()

Sin salida textual adicional guardada. Las figuras y matrices se incluyen en la galería.

Celda 40 · código original

# Visualizar pares de variables con relaciones moderadas o fuertes

# Crear scatterplot
sns.scatterplot(data=df,x="visitas_mes", y="ingreso_anual", hue='region')

# Crear línea de tendencia
sns.regplot(data=df, x='visitas_mes', y='ingreso_anual',
    scatter=False, color='black')
<AxesSubplot:xlabel='visitas_mes', ylabel='ingreso_anual'>

Celda 41 · código original

# Crear scatterplot
sns.scatterplot(data=df,x="compras_mes", y="ingreso_anual", hue='region')

# Crear línea de tendencia
sns.regplot(data=df, x='compras_mes', y='ingreso_anual',
    scatter=False, color='black')
<AxesSubplot:xlabel='compras_mes', ylabel='ingreso_anual'>
04

Sección 4. Calcular coeficientes y evidencia numérica

Pearson · Spearman · punto-biserial · V de Cramér

Respaldé los patrones visuales con coeficientes adecuados para cada tipo de variable. Reporté Pearson y Spearman para los dos pares principales, y revisé los restantes pares en las matrices.

Par de variablesPearsonSpearmanLectura descriptiva
Compras → ingreso anual0,9670,967Muy fuerte, positiva
Visitas → ingreso anual0,3370,321Positiva, limitada
Publicidad → visitas0,5790,559Moderada, positiva
Publicidad → ingreso anual0,1970,185Débil, positiva
Ingreso estimado → ingreso anual0,0170,025Cercana a cero
Satisfacción → ingreso anual0,0560,061Muy pequeña

Con scipy.stats.pointbiserialr evalué las variables binarias frente a variables numéricas. Premium–ingreso anual dio 0,0931; abandono–ingreso anual, −0,0028. Con pd.crosstab() y chi2_contingency() calculé V de Cramér para dispositivo–región: 0,012378.

El código generaliza el punto-biserial a las columnas numéricas, pero la salida guardada solo contiene seis por indicador: no aparece nivel_ingreso. No inventé ese resultado faltante.

Ver código y salidas guardadas de esta sección

Celda 46 · código original

# Calcular correlación entre variables relevantes

corr_pearson  = df['visitas_mes'].corr(df['ingreso_anual'], method='pearson')
corr_spearman = df['visitas_mes'].corr(df['ingreso_anual'], method='spearman')

print(f"Correlacion entre: visitas_mes y ingreso_anual")
print(f"Pearson: {corr_pearson:.3f}") #La correlación Pearson evalúa relación lineal
print(f"Spearman: {corr_spearman:.3f}") #La correlación Spearman evalúa consistencia (monotonía)
Correlacion entre: visitas_mes y ingreso_anual
Pearson: 0.337
Spearman: 0.321

Celda 47 · código original

# Calcular correlación entre variables relevantes
corr_pearson  = df['compras_mes'].corr(df['ingreso_anual'], method='pearson')
corr_spearman = df['compras_mes'].corr(df['ingreso_anual'], method='spearman')

print(f"Correlacion entre: compras_mes y ingreso_anual")
print(f"Pearson: {corr_pearson:.3f}")
print(f"Spearman: {corr_spearman:.3f}")
Correlacion entre: compras_mes y ingreso_anual
Pearson: 0.967
Spearman: 0.967

Celda 50 · código original

# Calcular correlacion Punto-biserial: estado suscripcion ingresos mensuales
# Punto-biserial compara dos grupos (premium / no premium)
# contra una variable numérica.

#El coeficiente indica si existe diferencia entre ambos grupos,
#no causalidad

from scipy.stats import pointbiserialr

# Codificar suscripción (CODIGO EN CASO DE QUE APLIQUE. EN ESTE CASO EL DATASET YA ESTABA CONFIGURADO)
#df["estado_suscripcion_bin"] = df["estado_suscripcion"].replace({
#    "Yes": 1,
#    "No": 0
#})
def corr_point_biserial(df, col_binarias, col_numericas):

        for col_b in col_binarias:
            print(f"\nCorrelacion de la variable binaria {col_b}")
            for col_n in col_numericas:
                coef, p_value = pointbiserialr(df[col_b],df[col_n])
                print(f"\ncon la variable {col_n}")
                print(f"Point-Biserial: {coef:.4f}")
                print(f"p-value: {p_value:.4f}")
            print('_________________________________________________________________________')


corr_point_biserial(df, variables_binarias, variables_numericas)
Correlacion de la variable binaria miembro_premium

con la variable edad
Point-Biserial: 0.0046
p-value: 0.5728

con la variable visitas_mes
Point-Biserial: -0.0127
p-value: 0.1211

con la variable compras_mes
Point-Biserial: 0.0034
p-value: 0.6744

con la variable gasto_publicidad_dirigida
Point-Biserial: 0.0027
p-value: 0.7390

con la variable satisfaccion
Point-Biserial: 0.0257
p-value: 0.0016

con la variable ingreso_anual
Point-Biserial: 0.0931
p-value: 0.0000
_________________________________________________________________________

Correlacion de la variable binaria abandono

con la variable edad
Point-Biserial: -0.0115
p-value: 0.1590

con la variable visitas_mes
Point-Biserial: -0.0089
p-value: 0.2734

con la variable compras_mes
Point-Biserial: 0.0083
p-value: 0.3099

con la variable gasto_publicidad_dirigida
Point-Biserial: -0.0046
p-value: 0.5744

con la variable satisfaccion
Point-Biserial: -0.0238
p-value: 0.0035

con la variable ingreso_anual
Point-Biserial: -0.0028
p-value: 0.7295
_________________________________________________________________________

Celda 53 · código original


# Función mejorada y generalizable para calcular V de Cramér
from scipy.stats import chi2_contingency
def cramer_v(df, col_cat):
    for i, col_1 in enumerate(col_cat):
        for col_2 in col_cat[i+1:]:
            print(f"\nCorrelacion de la variable categorica {col_1}")
            # tabla de contingencia
            tabla = pd.crosstab(df[col_1], df[col_2])

            # calcular chi-cuadrado
            chi2, p_value, dof, expected = chi2_contingency(tabla)

            # calcular coeficiente V de Cramér
            n = tabla.values.sum()
            v = np.sqrt(chi2 / (n * (min(tabla.shape) -1)))
            print(f"\ncon la variable {col_2}:")
            print(v)
            print('_________________________________')

Sin salida textual adicional guardada. Las figuras y matrices se incluyen en la galería.

Celda 54 · código original

# Aplicar V de Cramér en variables relevantes
cramer_v(df, variables_categoricas)
Correlacion de la variable categorica tipo_dispositivo

con la variable region:
0.012378338407739397
_________________________________
05

Sección 5. Interpretar resultados para el negocio

3 hallazgos originales · evidencia, límites e implicaciones

Documenté tres hallazgos siguiendo la estructura del notebook: evidencia visual, evidencia numérica, interpretación no causal, qué no puede afirmarse e implicación de negocio.

  • Las visitas del mes se asocian con el ingreso anual, pero de forma limitada: Pearson 0,337 y Spearman 0,321.
  • El gasto publicitario se asocia moderadamente con las visitas: Pearson 0,579 y Spearman 0,559.
  • La condición premium tiene una asociación positiva pequeña con el ingreso anual: punto-biserial 0,0931.

La página también destaca el par compras–ingreso anual, porque es el vínculo más fuerte de las matrices y de los gráficos clave: Pearson 0,967 y Spearman 0,967. Ese destacado sintetiza resultados existentes; no añade un análisis nuevo.

Más visitas, más publicidad o una suscripción premium no garantizan por sí solas mayor revenue. Las implicaciones se plantean como hipótesis para explorar o experimentar.
06

Sección 6. Reconocer limitaciones y próximos pasos

Segmentación · embudo · experimentos · documentación

Reconocí variables no controladas —campañas, antigüedad y promociones— y la posibilidad de efectos distintos por segmento. Propuse profundizar por dispositivo, región, premium, abandono y nivel de ingreso estimado.

Planteé comparar asociaciones globales con asociaciones por grupo para detectar cambios compatibles con una paradoja de Simpson. No afirmé que esa paradoja esté demostrada.

Como siguiente fase, propuse analizar el embudo visitas → compras → ingreso y diseñar pruebas A/B sobre publicidad dirigida. El notebook no ejecuta esos experimentos ni calcula su impacto causal.

El proyecto se documentó en la versión revisada del notebook y en GitHub. Esta web organiza el material para portafolio, conserva las figuras y permite descargar el archivo adjunto.

Ver código y salidas guardadas de esta sección

Celda 63 · código original

"Link del repositorio: https://github.com/andaba2101/NovaRetail_Correlational_analysis.git"
'Link del repositorio: https://github.com/andaba2101/NovaRetail_Correlational_analysis.git'

Hallazgos y evidencia de negocio

Los tres hallazgos escritos en el notebook se conservan, junto con el destacado de compras–ingreso anual obtenido de sus matrices y scatterplots. Cada recomendación queda separada del resultado observado.

Compras: la asociación más fuerte

Destacado adicional · resultados existentes en celdas 33, 34, 41 y 47

Evidencia

Pearson = 0,967149; Spearman = 0,967482. Matrices y scatterplot de compras_mes frente a ingreso_anual.

Interpretación

Ambos coeficientes muestran una asociación positiva muy fuerte: quienes registran más compras tienden a generar más ingreso en este dataset.

No podemos afirmar

Que haya un efecto causal estimado, una mejora de revenue del 96,7 % o un modelo predictivo ya validado.

Implicación de negocio

Investigar frecuencia de compra, valor por pedido y consistencia temporal del ingreso anual antes de usar compras_mes para predecir resultados.

Visitas: relación positiva, pero limitada

Hallazgo 1 original · celda 57

Evidencia

Pearson = 0,337147; Spearman = 0,320954. Scatterplot por región y matrices.

Interpretación

Las visitas se mueven positivamente con el ingreso anual, aunque con bastante dispersión. Es un vínculo menor que el observado con compras.

No podemos afirmar

Que aumentar las visitas por sí solo garantice más ingresos o que exista una tasa de conversión del 10 % calculada en el proyecto.

Implicación de negocio

Explorar el embudo visitas → compras → ingreso y posibles fricciones. Las hipótesis de precio, oferta o segmento requieren datos y pruebas adicionales.

Publicidad: más asociación con visitas que con ingreso

Hallazgo 2 original · celda 58; complemento de las matrices

Evidencia

Publicidad–visitas: Pearson = 0,578947; Spearman = 0,559267. Publicidad–ingreso anual: Pearson = 0,197483; Spearman = 0,184999.

Interpretación

La asociación con visitas es moderada; con ingreso anual es menor. El patrón descriptivo no cuantifica retorno ni eficiencia de campañas.

No podemos afirmar

Que aumentar gasto cause más visitas, que exista saturación a un gasto concreto o que la publicidad sea rentable o no rentable.

Implicación de negocio

Diseñar pruebas A/B sobre publicidad y analizar ingresos, costos y atribución con ventanas temporales comparables antes de reasignar presupuesto.

Premium: asociación pequeña con el ingreso

Hallazgo 3 original · celda 59; salida numérica en celda 50

Evidencia

Punto-biserial = 0,0931 para miembro_premium–ingreso_anual. El p-value se imprime como 0,0000 por redondeo.

Interpretación

La asociación es positiva y pequeña. La condición premium no basta para describir diferencias importantes de ingreso entre clientes.

No podemos afirmar

Que no exista ninguna relación, que premium explique por sí solo el revenue o que el coeficiente demuestre un efecto causal de la suscripción.

Implicación de negocio

Combinar premium con métricas de comportamiento y comparar segmentos; no utilizar la membresía como criterio único de valor.

Dispositivos en la base
Móvil9.818 · 65,45 %
Escritorio3.720 · 24,80 %
Tablet1.462 · 9,75 %

Base: 15.000 registros. Totales agregados de las frecuencias dispositivo–región guardadas.

Regiones en la base
Norte4.395 · 29,30 %
Oeste3.810 · 25,40 %
Sur3.726 · 24,84 %
Este3.069 · 20,46 %

Base: 15.000 registros. Son etiquetas regionales del dataset; no se identifican países.

Ver todas las asociaciones punto-biseriales guardadas
Variable binariaVariable numéricaCoeficientep guardado
miembro_premiumedad0,00460,5728
miembro_premiumvisitas_mes-0,01270,1211
miembro_premiumcompras_mes0,00340,6744
miembro_premiumgasto_publicidad_dirigida0,00270,7390
miembro_premiumsatisfaccion0,02570,0016
miembro_premiumingreso_anual0,09310,0000 *
abandonoedad-0,01150,1590
abandonovisitas_mes-0,00890,2734
abandonocompras_mes0,00830,3099
abandonogasto_publicidad_dirigida-0,00460,5744
abandonosatisfaccion-0,02380,0035
abandonoingreso_anual-0,00280,7295

* p se imprime con cuatro decimales en el notebook; 0,0000 representa redondeo. Se reproducen las doce asociaciones disponibles sin completar nivel_ingreso.

Dispositivo y región: asociación prácticamente nula
V de Cramér0,012378

La asociación global entre dispositivo y región es muy pequeña. El predominio móvil existe en los conteos, pero esa distribución no demuestra diferencias de ingreso, conversión o rentabilidad por dispositivo.

Método del notebook: tabla de contingencia, chi-cuadrado y V = √(χ² / [n × (min(filas, columnas) − 1)]).

Rigor metodológico, limitaciones y alcance
  • Correlación no implica causalidad: el dataset no controla campañas, promociones, antigüedad ni otros posibles factores de confusión.
  • visitas_mes y compras_mes son variables mensuales; ingreso_anual es anual según el diccionario. Falta documentar las ventanas exactas y cómo se construyó el ingreso para interpretar esa relación temporal.
  • La ausencia de nulos y rangos plausibles no garantiza ausencia de duplicados, errores de medición o sesgos. No aparece una auditoría explícita de duplicados en el código adjunto.
  • El Q1 de ingreso_anual es cero: permite destacar al menos un 25 % de registros con ingreso cero, pero no un porcentaje exacto de clientes sin ingreso.
  • La razón entre medias de compras y visitas no equivale a conversión de visitantes únicos. El notebook no calcula una tasa de conversión de clientes.
  • El valor 0,0000 de p es una salida redondeada, no un p-value exactamente cero. Una asociación pequeña debe distinguirse de su significación estadística.
  • Una correlación alta entre compras y la variable objetivo ingreso no demuestra multicolinealidad entre predictores. Antes de modelar conviene revisar variables explicativas, redundancia y posible relación mecánica en la definición de ingreso.
  • El análisis no calcula ROAS, ROI, efectos marginales ni retornos causales de publicidad. Tampoco demuestra que las personas mayores compren menos o que la marca no sea de lujo.
  • La proporción del indicador abandono es descriptiva de la muestra; no define por sí sola una tasa de abandono mensual ni un horizonte de retención.
  • El código numérico incluye nivel_ingreso, pero la salida guardada de punto-biserial no muestra esa variable. La web conserva las doce asociaciones disponibles, sin reconstruir las faltantes.
  • No se reejecutó el análisis sobre el CSV fuente. La presentación utiliza el notebook adjunto, sus salidas guardadas y cálculos de porcentajes sobre frecuencias ya disponibles.
Seguimiento de la revisión del proyecto

La versión adjunta incluye comentarios de la Iteración 1 del revisor Israel: validación positiva de carga/exploración y observaciones sobre la tipificación y los pares clave. El código actual incorpora edad como entero y los scatterplots de visitas–ingreso y compras–ingreso. No se presenta esta versión como “aprobada” ni se atribuye una calificación que no está documentada.

Comentario original del revisor · celda 12
Comentario del revisor. (Iteración 1)
Excelente trabajo. La carga y exploración inicial cumplen con lo solicitado. Se importan las librerías, se carga el dataset, se revisan los tipos y valores nulos y se muestran las primeras filas antes de continuar con el análisis.
Comentario original del revisor · celda 29
Comentario del revisor. (Iteración 1)
Buen trabajo. La conversión de `edad`, la clasificación de variables y la exploración de variables numéricas, binarias y categóricas están correctamente realizadas. Ajusta únicamente el supuesto que afirma que los datos ya estaban correctamente tipificados, porque `edad` requirió una conversión.
GRACIAS POR EL APORTE, YA SE CORRIÓ. TMBIÉN SE AGREGÓ EL NIVEL DE INGRESO DEL CLIENTE QUE SE HABIA OMITIDO
Comentario original del revisor · celda 43
Comentario del revisor. (Iteración 1)
Revisa esta sección. Los pares principales solicitados son `compras_mes` vs `ingreso_anual` y `visitas_mes` vs `ingreso_anual`. Actualmente se grafica `visitas_mes` vs `gasto_publicidad_dirigida` en lugar del segundo par principal. Incluye el scatterplot de visitas e ingreso anual y deja publicidad dirigida solo como análisis complementario.

GRACIAS POR EL APORTE PERO CONSIDERO QUE DEBIÓ HABERSE PUESTO DE MANERA MÁS EXPLICITA EL DESVÍO DEL OBJETIVO PRINCIPAL. SESIÓN 1:1 FUE NECESARIA PARA RESOLVER ESTA INQUIETUD, POR MUY REDUNDANTE QUE PUEDA PARECER

Próximos pasos planteados

Propuestas del notebook, todavía no ejecutadas como análisis o experimentos adicionales.

Segmentar las relaciones

Repetir los cálculos por dispositivo, región, premium, abandono y rangos de ingreso estimado. Comparar la dirección y magnitud dentro de cada grupo.

Revisar el embudo

Definir visitas, compradores únicos y compras en una misma ventana. Identificar fricciones y estudiar a los clientes con ingreso cero.

Validar mediante experimentos

Diseñar pruebas A/B sobre publicidad dirigida para evaluar efectos sobre compras e ingreso, en lugar de atribuir causalidad a correlaciones.

Conclusión exploratoria: compras_mes muestra la asociación más fuerte con ingreso_anual. Visitas y publicidad aportan señales complementarias; las decisiones de inversión y retención requieren evidencia adicional.

Todas las visualizaciones del proyecto

12 figuras originales y 2 matrices coloreadas: siete figuras de distribución, con histograma y boxplot; dos countplots; un PairGrid; dos scatterplots clave; y las matrices Pearson y Spearman.

Las imágenes y las matrices conservan los colores y las salidas del notebook. Pulsa las figuras para ampliarlas; en el PairGrid puedes activar zoom al 200 % y desplazarte. El fondo blanco preserva la legibilidad en ambos modos.

14 de 14 visualizaciones
Figura 01 / 12 · celda 19

Edad: distribución y outliers

38 años de mediana · rango de 18 a 75

Histograma con 20 intervalos, comparación por dispositivo y línea de la media; junto a él, boxplot de edad. La media es 38,26 y los cuartiles son 30 y 46.

La forma de la distribución no demuestra que las personas mayores compren menos.

Figura 02 / 12 · celda 19

Ingreso estimado del cliente

30.023,75 de mediana · máximo 74.790,84

Distribución y boxplot de nivel_ingreso. La media es 30.019,70 y el rango va de 8.000 a 74.790,84. Esta variable describe el ingreso estimado del cliente.

No confundir nivel_ingreso con ingreso_anual: el segundo mide el ingreso generado para NovaRetail+.

Figura 03 / 12 · celda 19

Visitas durante el mes

10 visitas de mediana · máximo 25

El histograma y el boxplot muestran visitas_mes: media 10,03, mínimo 1, Q1 = 8 y Q3 = 12. Hay clientes más activos que el centro de la distribución.

Son visitas por cliente, no el número de clientes únicos que convierten.

Figura 04 / 12 · celda 19

Compras durante el mes

1 compra de mediana · máximo 8

La media es 1,21; Q1 = 0 y Q3 = 2. Los ceros representan clientes con visitas, pero sin compras registradas en el mes.

Dividir la media de compras entre la media de visitas no calcula una tasa de conversión de clientes.

Figura 05 / 12 · celda 19

Gasto publicitario dirigido

19,73 de mediana · máximo 75,51

La media es 20,15, con Q1 = 12,31 y Q3 = 27,2925. La figura permite revisar asignaciones elevadas de gasto publicitario a usuarios.

Esta distribución no demuestra saturación publicitaria, rentabilidad ni causalidad.

Figura 06 / 12 · celda 19

Satisfacción del cliente

3,6 de mediana · escala de 1 a 5

Histograma y boxplot de satisfaccion. La media es 3,60; Q1 = 3,1 y Q3 = 4,1. Las calificaciones bajas son un grupo para investigar.

No se calculó un índice NPS ni se demostró que satisfacción determine las compras.

Figura 07 / 12 · celda 19

Ingreso anual para NovaRetail+

Q1 = 0 · máximo 244,69

Distribución y boxplot de ingreso_anual. La media es 36,59 y la mediana 30,705. Con mínimo y Q1 iguales a cero, al menos el 25 % de los registros no genera ingreso en este campo.

Es un límite inferior basado en cuartiles; el notebook no reporta el porcentaje exacto de clientes con ingreso cero.

Figura 08 / 12 · celda 26

Dispositivo utilizado, por región

9.818 registros móviles · 65,45 %

Countplot original de tipo_dispositivo, con color por region. El total agregado es móvil: 9.818; escritorio: 3.720; tablet: 1.462.

Que móvil sea mayoritario no prueba que tenga mayor conversión o rentabilidad.

Figura 09 / 12 · celda 26

Región del cliente, por dispositivo

Norte: 4.395 registros · 29,30 %

Countplot original de region, con color por tipo_dispositivo. Norte reúne 4.395 registros; oeste 3.810; sur 3.726 y este 3.069.

Las categorías son regiones del dataset, no países o ciudades identificados.

Matriz 1 / 2 · celda 33

Matriz Pearson · siete variables numéricas

Pearson recoge asociaciones lineales; compras–ingreso anual = 0,967149 y publicidad–visitas = 0,578947.
edad nivel_ingreso visitas_mes compras_mes gasto_publicidad_dirigida satisfaccion ingreso_anual
edad 1.000000 -0.009003 0.004998 0.014971 0.000062 -0.006963 0.017496
nivel_ingreso -0.009003 1.000000 0.001060 0.007309 0.016834 0.002301 0.017446
visitas_mes 0.004998 0.001060 1.000000 0.353844 0.578947 -0.003179 0.337147
compras_mes 0.014971 0.007309 0.353844 1.000000 0.207528 -0.003542 0.967149
gasto_publicidad_dirigida 0.000062 0.016834 0.578947 0.207528 1.000000 -0.013175 0.197483
satisfaccion -0.006963 0.002301 -0.003179 -0.003542 -0.013175 1.000000 0.056171
ingreso_anual 0.017496 0.017446 0.337147 0.967149 0.197483 0.056171 1.000000

Matriz HTML original con los 49 coeficientes y colores guardados. En móvil, desplaza la tabla horizontalmente para recorrer las siete columnas.

Colores conservados de Styler.background_gradient(cmap="coolwarm"): el gradiente original se aplica por columna, no con una escala global común. Para comparar pares, utiliza los valores numéricos.

Matriz 2 / 2 · celda 34

Matriz Spearman · siete variables numéricas

Spearman recoge asociaciones por rangos; compras–ingreso anual = 0,967482 y publicidad–visitas = 0,559267.
edad nivel_ingreso visitas_mes compras_mes gasto_publicidad_dirigida satisfaccion ingreso_anual
edad 1.000000 -0.007775 0.005205 0.015630 0.002869 -0.007590 0.016097
nivel_ingreso -0.007775 1.000000 0.001420 0.009004 0.015393 0.005243 0.025017
visitas_mes 0.005205 0.001420 1.000000 0.332943 0.559267 -0.001305 0.320954
compras_mes 0.015630 0.009004 0.332943 1.000000 0.192511 -0.002006 0.967482
gasto_publicidad_dirigida 0.002869 0.015393 0.559267 0.192511 1.000000 -0.012612 0.184999
satisfaccion -0.007590 0.005243 -0.001305 -0.002006 -0.012612 1.000000 0.060834
ingreso_anual 0.016097 0.025017 0.320954 0.967482 0.184999 0.060834 1.000000

Matriz HTML original con los 49 coeficientes y colores guardados. En móvil, desplaza la tabla horizontalmente para recorrer las siete columnas.

Colores conservados de Styler.background_gradient(cmap="coolwarm"): el gradiente original se aplica por columna, no con una escala global común. Para comparar pares, utiliza los valores numéricos.

Figura 10 / 12 · celda 38

PairGrid: mapa general de relaciones

7 variables · cuadrícula de 49 posiciones

Vista conjunta de las siete variables numéricas. Los puntos se diferencian por región y las líneas negras resumen la tendencia global fuera de la diagonal.

La diagonal no tiene distribuciones dibujadas. Amplía y activa el zoom para leer los pares; el tamaño de puntos refleja superposición, no conteos exactos.

Figura 11 / 12 · celda 40

Visitas del mes frente a ingreso anual

Pearson 0,337 · Spearman 0,321

Scatterplot original por región y línea de regresión global. La relación es positiva, pero tiene dispersión considerable: más visitas no se traducen de forma automática en más ingreso.

No se validó un modelo predictivo ni se controlaron campañas, antigüedad u otras variables.

Figura 12 / 12 · celda 41

Compras del mes frente a ingreso anual

Pearson 0,967 · Spearman 0,967

La asociación positiva es muy fuerte en ambos métodos. El ingreso anual aumenta en conjunto con la cantidad de compras, en el patrón observado del dataset.

Un coeficiente de 0,967 no significa 96,7 % de aumento de ingresos ni prueba una relación causal.

Notebook y repositorio del proyecto

El análisis original se conserva en el notebook revisado del Sprint 8. Esta presentación reúne sus resultados y facilita la revisión del código, las cifras y las visualizaciones.

Proyecto 7 · Explorando drivers de comportamiento en NovaRetail+

S8_Student_Version_Project_NovaRetail_V2_Reviewed.ipynb
Portafolio de Andrés Barrios · TripleTen Data Analytics

Ver repositorio
Abrir el archivo en GitHub

El botón abre exactamente la versión revisada que compartiste, dentro de NovaRetail_Correlational_analysis. El notebook incluye código, gráficos, matrices y comentarios de revisión.

Abrir notebook revisado
Descargar el notebook correcto

Incluí una copia íntegra del notebook adjunto dentro de esta página. La descarga incluida funciona desde el navegador sin depender de Google Drive.

El enlace de Drive proporcionado tiene el mismo identificador que el usado en Telecom. No pude verificar su contenido; se conserva tal como lo solicitaste. Para obtener NovaRetail con certeza, utiliza “Descargar NovaRetail incluido” o el archivo de GitHub.
Ver notebook en GitHubDescargar desde Drive
Fuentes: notebook adjunto del Sprint 8, sus 64 celdas y salidas guardadas; repositorio NovaRetail_Correlational_analysis; plantilla HTML anterior del portafolio. Las frecuencias por dispositivo y región se agregan a partir de conteos guardados; no se reejecuta el CSV ni se realizan nuevos modelos. Fecha de preparación: 5 de octubre de 2026.

Figura del proyecto

Figura ampliada

↑