<jupyter_start><jupyter_text>ESTADÍSTICA DESCRIPTIVA CON PYTHON  Importando librerías necesarias<jupyter_code># librerías de apoyo
import pandas as pd
import numpy as np
import math
from sklearn.datasets import load_boston
# librerías especializadas
from scipy import stats
import statsmodels.api as sm
#librerías de visualización
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns<jupyter_output><empty_output><jupyter_text>Configuración de visualización de tablas de datos<jupyter_code>pd.set_option('max_columns', 50)
pd.set_option('max_rows', 300)<jupyter_output><empty_output><jupyter_text>Carga de datos<jupyter_code># Qué datos contiene el dataset "load_boston"
load_boston()
boston = load_boston()
print(boston.DESCR)
# Obtención del Dataframe
df_boston = pd.DataFrame(data=np.c_[boston['data'], boston['target']], columns=list(boston['feature_names']) + ['MEDV'])
df_boston.head()
df_boston.shape<jupyter_output><empty_output><jupyter_text>Revisión general del dataset<jupyter_code>df_boston.info()
# Se convierte la variable 'CHAS' en tipo object, para facilitar la separación de los datos numéricos y categóricos.
df_boston['CHAS'] = (df_boston['CHAS'].astype('int')).astype('object')
df_boston['CHAS'].value_counts(), df_boston['CHAS'].dtype<jupyter_output><empty_output><jupyter_text>**A partir de datos numéricos podemos obtener datos categóricos (de escala ordinal), haciendo uso de qcut():**- Especificando el número de cuartiles (q), las etiquetas que se asignaran a cada categoría es opcional, retbins=True para saber el intervalo de cada categoria<jupyter_code>out, bins = pd.qcut(df_boston['RAD'], q=3, labels=None, retbins=True)
bins, out
df_boston['cat_RAD'] = out.astype('object')
df_boston.head()
df_boston.info()<jupyter_output><class 'pandas.core.frame.DataFrame'>
RangeIndex: 506 entries, 0 to 505
Data columns (total 15 columns):
 #   Column   Non-Null Count  Dtype  
---  ------   --------------  -----  
 0   CRIM     506 non-null    float64
 1   ZN       506 non-null    float64
 2   INDUS    506 non-null    float64
 3   CHAS     506 non-null    object 
 4   NOX      506 non-null    float64
 5   RM       506 non-null    float64
 6   AGE      506 non-null    float64
 7   DIS      506 non-null    float64
 8   RAD      506 non-null    float64
 9   TAX      506 non-null    float64
 10  PTRATIO  506 non-null    float64
 11  B        506 non-null    float64
 12  LSTAT    506 non-null    float64
 13  MEDV     506 non-null    float64
 14  cat_RAD  506 non-null    object 
dtypes: float64(13), object(2)
memory usage: 59.4+ KB<jupyter_text>Ahora se cuenta con 2 variables de tipo categóricas para analizar.**Separación de variables categóricas y numéricas:**<jupyter_code>var_categoricas = ['CHAS', 'cat_RAD']
var_numericas = df_boston.columns.drop(var_categoricas)
print(f'Variables categóricas: {var_categoricas}\n\nVariables numéricas: {var_numericas.values}')<jupyter_output>Variables categóricas: ['CHAS', 'cat_RAD']

Variables numéricas: ['CRIM' 'ZN' 'INDUS' 'NOX' 'RM' 'AGE' 'DIS' 'RAD' 'TAX' 'PTRATIO' 'B'
 'LSTAT' 'MEDV']<jupyter_text>Resumen Estadístico de datos Utilizando Pandas **Resumen estadístico para variables categóricas:**- El resultado describe() varía según se aplique a una columna de datos numéricos o categóricos- Para obtener resumen de las variables numéricas se utiliza el parámetro exclude='object'- Describe por defecto calcula el count: número de registro (o muestra: n), media, desviación estándar, min, max, percentiles 25, 50 y 75 (Remember: P25=Mediana)- Si se desea traer percentiles distintos a los que están por defecto se debe especificar como parámetro de describe()<jupyter_code>df_boston.describe(percentiles=[.1, .25, .5, .75, .9], exclude='object')<jupyter_output><empty_output><jupyter_text>**Resumen estadístico para variables categóricas:**- La siguiente, es una tabla de resumen estadistico de las variables categóricas, para ello se especifica exclude='float' como parámetro.- count: es el número de registro (o muestra: n)- top: el valor categoria o valor modal- freq: el número de veces que se repite la moda<jupyter_code>df_boston.describe(exclude='float')<jupyter_output><empty_output><jupyter_text>**Resumen de Estadistica descriptiva de variables seleccionadas, con medidas determinadas, utilizando agg():**- Funciones: count, mean, median, mad, min, max, prod, sum, std, var, sem, skew, kurt- Se pueden agregar las funciones entre comillas, directamente con el nombre o anteponiendo np.- Para el calculo de la moda, no sirve esta manera.<jupyter_code>df_boston[list(df_boston.columns[4:10])].agg({min, max, np.mean, np.median, 'std', 'skew'})<jupyter_output><empty_output><jupyter_text>Resumen utilizando stats de Scipy **Del modo siguiente, se obtiene medidas de estadistica descriptiva, como:**- Nro de observaciones, minimo, máximo, media, varianza, simetria y curtosis- Y permite seleccionar los grados de libertad para el calculo de la varianza, y la corrección o no a partir del sesgo para la simetria y curtosis- Con el prámetro nan_policy permite configurar la manipulación de valores faltantes.<jupyter_code>descrip_stat = stats.describe(df_boston[var_numericas], ddof=1, bias=True)      # salida: n, (min, max), mean, varianza, skewness, kurtosis 
descrip_stat<jupyter_output><empty_output><jupyter_text>Para mostrar los resultados en tabla se llevó a un dataframe:<jupyter_code>data = {'nobs': descrip_stat.nobs, 'min': descrip_stat.minmax[0], 'max': descrip_stat.minmax[1], 'mean': descrip_stat.mean,
       'varianza': descrip_stat.variance, 'desv_estandar': np.sqrt(descrip_stat.variance), 'simetria': descrip_stat.skewness,
       'curtosis': descrip_stat.kurtosis, 'CV': np.sqrt(descrip_stat.variance)/descrip_stat.mean*100}
pd.DataFrame(data=data, index=var_numericas)<jupyter_output><empty_output><jupyter_text>Medidas de Resumen  Medidas de Tendencia Central  **Media (aritmética)**  Media con Pandas<jupyter_code># Media de cada una de las variables del dataset
df_boston.mean(numeric_only=True)
# Media de una característica específica
df_boston['MEDV'].mean()
# Medias por grupos de categorias
df_boston.groupby('CHAS').mean()
df_boston.groupby(var_categoricas).mean()<jupyter_output><empty_output><jupyter_text>Media con Numpy<jupyter_code># Media de cada una de las variables del dataset
medias_np = np.mean(np.array(df_boston.drop(columns=var_categoricas)), axis=0)
medias_np
pd.DataFrame(data=medias_np, index=var_numericas, columns=['media'])
# Media de una característica específica
np.mean(np.array(df_boston['MEDV']))<jupyter_output><empty_output><jupyter_text>Media con stats de Scipy- https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.describe.htmlscipy.stats.describe<jupyter_code># Media de cada una de las variables del dataset (Utilizando el resumen arriba mostrado)
pd.DataFrame(data=descrip_stat.mean, index=var_numericas, columns=['media'])
# Media de una característica específica
var = 'MEDV'
est_descript_medv = stats.describe(df_boston[var])
print(f'La media de {var} es {float(est_descript_medv.mean)}')<jupyter_output>La media de MEDV es 22.532806324110677<jupyter_text>**Mediana**  Mediana con Pandas<jupyter_code># Mediana de cada una de las variables del dataset
df_boston.median()
# Mediana de una característica específica
df_boston['MEDV'].median()<jupyter_output><empty_output><jupyter_text>Mediana con Numpy<jupyter_code># Mediana de cada una de las variables del dataset
medianas_np = np.median(np.array(df_boston[var_numericas]), axis=0)
pd.DataFrame(data=medianas_np, index=var_numericas, columns=['mediana'])
# Mediana de una característica específica
np.median(np.array(df_boston['MEDV']))<jupyter_output><empty_output><jupyter_text>**Moda**  Moda con Pandas<jupyter_code># Moda de cada una de las variables del dataset
df_boston.mode()
# Moda de una característica específica
df_boston['MEDV'].mode()<jupyter_output><empty_output><jupyter_text>Moda con NumpyNo existe manera directa  Moda con stats de Scipy<jupyter_code># Moda de cada una de las variables del dataset
# Con la desventaja que no muestra todas las modas presentes
modas = (stats.mode(df_boston))
modas
# Mostrado en tabla
pd.DataFrame(data=np.c_[modas.mode.ravel(),modas.count.ravel()], index=df_boston.columns, columns=['moda', 'frecuencia'])
# Moda de una característica específica
var = 'MEDV'
moda = stats.mode(df_boston[var])
print(f'La moda de {var} es {float(moda.mode)}, con frecuencia de {float(moda.count)}')<jupyter_output>La moda de MEDV es 50.0, con frecuencia de 16.0<jupyter_text>Medidas de Posición  **Cuartiles y percentiles**  Usando Numpy<jupyter_code># Especificación de los cuartiles en probabilidad
p_cuartiles = np.arange(.25, 1, .25)   # O np.array([0.25, 0.5 , 0.75]) para especificar uno a uno
# Cálculo de los cuartiles
valores_cuartiles = np.quantile(df_boston[var_numericas], p_cuartiles, axis=0)
pd.DataFrame(data=valores_cuartiles, index=(p_cuartiles*100).astype(int), columns=var_numericas)
# Especificación de los percentiles en porcentajes
p_percentiles = np.arange(20, 100, 20)   # O np.array([0.25, 0.5 , 0.75]) para especificar uno a uno
# Cálculo de los percentiles
valores_percentiles = np.percentile(df_boston[var_numericas], p_percentiles, axis=0)
pd.DataFrame(data=valores_percentiles, index=p_percentiles, columns=var_numericas)
# Especificación de los cuartiles en probabilidad
p_cuartiles = np.arange(.25, 1, .25)   # O np.array([.25, .50, .75]) para especificar uno a uno
# Calculo de los cuartiles
valores_cuartiles = np.quantile(df_boston['CRIM'], p_cuartiles)
print(f'Cuartiles del Índice de Criminalidad:\nQ1={valores_cuartiles[0]}\nQ2={valores_cuartiles[1]}\nQ3={valores_cuartiles[2]}')
# Especificación de los cuartiles en porcentajes
p_cuartiles = np.arange(25, 100, 25)   # O np.array([25, 50, 75]) para especificar uno a uno
# Calculo de los cuartiles
valores_cuartiles = np.percentile(df_boston['CRIM'], p_cuartiles)
print(f'Cuartiles del Índice de Criminalidad:\nQ1={valores_cuartiles[0]}\nQ2={valores_cuartiles[1]}\nQ3={valores_cuartiles[2]}')<jupyter_output>Cuartiles del Índice de Criminalidad:
Q1=0.08204499999999999
Q2=0.25651
Q3=3.6770825<jupyter_text>Medidas de Dispersión  **Rango**  Rango con Pandas<jupyter_code># Rango de cada una de las variables del dataset
rangos = df_boston[var_numericas].max() - df_boston[var_numericas].min()
rangos
# Rango de una característica específica
df_boston['MEDV'].max() - df_boston['MEDV'].min()<jupyter_output><empty_output><jupyter_text>Rango con Numpy<jupyter_code># Rango de cada una de las variables del dataset
rangos_np = np.max(np.array(df_boston[var_numericas]), axis=0) - np.min(np.array(df_boston[var_numericas]), axis=0)
pd.DataFrame(data=rangos_np, index=var_numericas, columns=['rango'])
# Rango de una característica específica
np.max(np.array(df_boston['MEDV'])) - np.min(np.array(df_boston['MEDV']))<jupyter_output><empty_output><jupyter_text>**Otra manera**https://numpy.org/doc/stable/reference/generated/numpy.ptp.html?highlight=ptpnumpy.ptp<jupyter_code># Rango de cada una de las variables del dataset
rango_np2 = np.ptp(np.array(df_boston[var_numericas]), axis=0)
pd.DataFrame(data=rango_np2, index=var_numericas, columns=['moda'])
# Rango de una característica específica
np.ptp(np.array(df_boston['MEDV']))<jupyter_output><empty_output><jupyter_text>**Varianza**  Varianza con Pandas<jupyter_code># Varianza de cada una de las variables del dataset
varianzas = df_boston[var_numericas].var()
varianzas
# Varianza de una característica específica
df_boston['AGE'].var()<jupyter_output><empty_output><jupyter_text>Varianza con Numpy<jupyter_code># Varianza de cada una de las variables del dataset
varianzas_np = np.var(np.array(df_boston[var_numericas]), axis=0)
pd.DataFrame(data=varianzas_np, index=[var_numericas], columns=['varianza'])
# Varianza de una característica específica
np.var(np.array(df_boston['AGE']))<jupyter_output><empty_output><jupyter_text>Varianza con stats de Scipy<jupyter_code># Varianza de cada una de las variables del dataset
pd.DataFrame(data=descrip_stat.variance, index=var_numericas, columns=['varianza'])
# Varianza de una característica específica
var = 'AGE'
est_descript_medv = stats.describe(df_boston[var])
print(f'La varianza de {var} es {float(est_descript_medv.variance)}')<jupyter_output>La varianza de AGE es 792.358398505068<jupyter_text>**Desviación estándar**  Desviación estándar con Pandas<jupyter_code># Desviación estándar de cada una de las variables del dataset
desv_ests = df_boston[var_numericas].std()    # ddof=1 por defecto
desv_ests
# Desviación estándar de una característica específica
df_boston['AGE'].std(ddof=1)
# Desviación estándar de una característica específica
df_boston['AGE'].std(ddof=0)<jupyter_output><empty_output><jupyter_text>Desviación estándar con Numpy<jupyter_code># Desviación estándar de cada una de las variables del dataset
desv_ests_np = np.std(np.array(df_boston[var_numericas]), axis=0)
pd.DataFrame(data=desv_ests_np, index=var_numericas, columns=['desv_estandar'])
# Desviación estándar de una característica específica
np.std(np.array(df_boston['AGE']))<jupyter_output><empty_output><jupyter_text>Desviación estándar con stats de Scipy<jupyter_code># Desviación estándar de cada una de las variables del dataset
pd.DataFrame(data=np.sqrt(descrip_stat.variance), index=var_numericas, columns=['desv_estandar'])
# Desviación estándar de una característica específica
var = 'AGE'
est_descript_medv = stats.describe(df_boston[var])
print(f'La desviación estándar de {var} es {float(math.sqrt(est_descript_medv.variance))}')   # válido math.sqrt o np.sqrt<jupyter_output>La desviación estándar de AGE es 28.148861406903617<jupyter_text>**Rango intercuartil**  Rango intercuartil con Pandas<jupyter_code># Rango intercuartil de cada una de las variables del dataset
rango_intercuartil = df_boston.quantile(0.75) - df_boston.quantile(0.25)
rango_intercuartil
# Rango intercuartil de una característica específica
df_boston['MEDV'].quantile(0.75) - df_boston['MEDV'].quantile(0.25)<jupyter_output><empty_output><jupyter_text>Rango intercuartil con Numpy<jupyter_code># Rango intercuartil de cada una de las variables del dataset
rango_intercuartil_np = np.quantile(np.array(df_boston[var_numericas]), q=0.75, axis=0) - np.quantile(np.array(df_boston[var_numericas]), q=0.25, axis=0)
pd.DataFrame(data=rango_intercuartil_np, index=[var_numericas], columns=['rango_intercuartil'])
# Rango intercuartil de una característica específica
np.quantile(np.array(df_boston['MEDV']), q=0.75) - np.quantile(np.array(df_boston['MEDV']), q=0.25)<jupyter_output><empty_output><jupyter_text>Rango intercuartil con stats de Scipyhttps://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.iqr.html<jupyter_code># Rango intercuartil de cada una de las variables del dataset
pd.DataFrame(data=stats.iqr(df_boston[var_numericas], axis=0), index=[var_numericas], columns=['rango_intercuartil'])
# Rango intercuartil de una característica específica
var = 'AGE'
print(f'La rango_intercuartil de {var} es {float(stats.iqr(df_boston[var]))}')   # válido math.sqrt o np.sqrt<jupyter_output>La rango_intercuartil de AGE es 49.04999999999999<jupyter_text>**Coeficiente de variación**  Coeficiente de variación con Pandas<jupyter_code># Coeficiente de variación de cada una de las variables del dataset
CVs = df_boston[var_numericas].std()/df_boston[var_numericas].mean()*100
CVs
# Coeficiente de variación de una característica específica
df_boston['MEDV'].std()/df_boston['MEDV'].mean()*100<jupyter_output><empty_output><jupyter_text>Coeficiente de variación con Numpy<jupyter_code>df_boston.head()
# Coeficiente de variación de cada una de las variables del dataset
cv_np = np.std(df_boston[var_numericas], axis=0)/np.mean(df_boston[var_numericas], axis=0)*100
pd.DataFrame(data=np.array(cv_np), index=[var_numericas], columns=['CV'])
# Coeficiente de variación de una característica específica
np.std(np.array(df_boston['MEDV']))/np.mean(np.array(df_boston['MEDV']))*100<jupyter_output><empty_output><jupyter_text>Coeficiente de variación con stats de Scipyhttps://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.variation.htmlscipy.stats.variation<jupyter_code>cv_np2 = stats.variation(np.array(df_boston[var_numericas]), axis=0)*100
pd.DataFrame(data=cv_np2, index=var_numericas, columns=['cv'])<jupyter_output><empty_output><jupyter_text>Medidas de Forma  **Simetría**  Simetría con Pandas<jupyter_code># Simetría de cada una de las variables del dataset
simetrias = df_boston.skew()
simetrias
# Simetría de una característica específica
df_boston['MEDV'].skew()     # n-1<jupyter_output><empty_output><jupyter_text>Simetría con NumpyNo existe manera  Simetría con stats de Scipy<jupyter_code># Simetría de cada una de las variables del dataset
pd.DataFrame(data=descrip_stat.skewness, index=var_numericas, columns=['simetria'])
# Simetría de una característica específica
var = 'AGE'
est_descript_medv = stats.describe(df_boston[var])
print(f'La simetría de {var} es {float(est_descript_medv.skewness)}')<jupyter_output>La simetría de AGE es -0.5971855948016143<jupyter_text>**Otra manera**<jupyter_code># Simetría de cada una de las variables del dataset
simetrias_ss = stats.skew(np.array(df_boston[var_numericas]), bias=True, axis=0)
pd.DataFrame(data=simetrias_ss, index=var_numericas, columns=['simetria'])
# Simetría de una característica específica
stats.skew(np.array(df_boston['AGE']))<jupyter_output><empty_output><jupyter_text>**Curtosis**  Curtosis con Pandas<jupyter_code># Curtosis de cada una de las variables del dataset
curtosis = df_boston.kurt()
curtosis
# Curtosis de una característica específica
df_boston['AGE'].kurt()     # n-1<jupyter_output><empty_output><jupyter_text>Curtosis con NumpyNo existe manera directa  Curtosis con stats de Scipy<jupyter_code># Curtosis de cada una de las variables del dataset
pd.DataFrame(data=descrip_stat.kurtosis, index=var_numericas, columns=['curtosis'])
# Curtosis de una característica específica
var = 'AGE'
est_descript_medv = stats.describe(df_boston[var])
print(f'La curtosis de {var} es {float(est_descript_medv.kurtosis)}')<jupyter_output>La curtosis de AGE es -0.97001392664039<jupyter_text>**Otra manera**<jupyter_code># Curtosis de cada una de las variables del dataset
curtosis_ss = stats.kurtosis(np.array(df_boston[var_numericas]), bias=True, axis=0)
pd.DataFrame(data=curtosis_ss, index=var_numericas, columns=['curtosis'])
# Curtosis de una característica específica
stats.kurtosis(np.array(df_boston['AGE']))<jupyter_output><empty_output><jupyter_text>Organización de los datos  Tablas de frecuenciashttps://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.binned_statistic.htmlscipy.stats.binned_statistic  Tabla de frecuencia: de variable categórica<jupyter_code>df_boston['CHAS'].value_counts()
df_boston[['CHAS', 'cat_RAD']].groupby('CHAS').count()
cat_f_abs = df_boston['CHAS'].value_counts()
table = {'categoria': np.array(['no', 'si']),'f_abs': cat_f_abs.values, 'f_abs_acum': np.cumsum(cat_f_abs.values),
       'f_rel': cat_f_abs.values/sum(cat_f_abs.values), 'f_rel_acum': np.cumsum(cat_f_abs.values/sum(cat_f_abs.values))}
print('Tabla de frecuencias de la cercanía al Charles River')
pd.DataFrame(data=table).set_index('categoria')
rad_f_abs = df_boston['cat_RAD'].value_counts()
table = {'categoria': rad_f_abs.index, 'f_abs': rad_f_abs.values, 
         'f_abs_acum': np.cumsum(rad_f_abs.values), 'f_rel': rad_f_abs.values/sum(rad_f_abs.values), 
         'f_rel_acum': np.cumsum(rad_f_abs.values/sum(rad_f_abs.values))}
print('Tabla de frecuencias del Índice de accesibilidad a carreteras radiales')
pd.DataFrame(data=table).set_index('categoria')<jupyter_output>Tabla de frecuencias del Índice de accesibilidad a carreteras radiales<jupyter_text>Tabla de frecuencia: de variable númerica agrupada **Un ejemplo sencillo:**<jupyter_code>values = [4,4,5,6,4,10]
bines = stats.binned_statistic(values, values, 'count', bins=3)
bines
# Intervalos: [LI,LS)
aux = {'LI': bines.bin_edges[:-1], 'LS': bines.bin_edges[1:], 'f_abs': bines.statistic, 'f_abs_acum': np.cumsum(bines.statistic),
       'f_rel': bines.statistic/sum(bines.statistic), 'f_rel_acum': np.cumsum(bines.statistic/sum(bines.statistic))}
pd.DataFrame(data=aux, index=np.arange(1, len(bines.statistic)+1))<jupyter_output><empty_output><jupyter_text>**Tabla de frecuencia para CRIM:**<jupyter_code>values = df_boston['CRIM'].values
# Regla de Sturges: para cálculo del número de intervalos
k = int(1 + math.log2(len(values)))
bines = stats.binned_statistic(values, values, 'count', bins=k)
bines
aux = {'LI': bines.bin_edges[:-1], 'LS': bines.bin_edges[1:], 'f_abs': bines.statistic, 'f_abs_acum': np.cumsum(bines.statistic),
       'f_rel': bines.statistic/sum(bines.statistic), 'f_rel_acum': np.cumsum(bines.statistic/sum(bines.statistic))}
pd.DataFrame(data=aux)<jupyter_output><empty_output><jupyter_text>Tablas de contigencia**Con Pandas (pivot_table)**- https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.pivot_table.html<jupyter_code>print('   Tabla de contigencia Limite Charles River vs \nÍndice de accesibilidad a carreteras radiales (en Fabs)')
tabla = df_boston.pivot_table(values='MEDV', index='cat_RAD', columns=['CHAS'], aggfunc='count',
                      fill_value=None, margins=False, dropna=True,
                      margins_name='All', observed=False)
tabla.rename(columns={0:'no', 1:'si'}, inplace=True)
tabla<jupyter_output>Tabla de contigencia Limite Charles River vs 
Índice de accesibilidad a carreteras radiales (en Fabs)<jupyter_text>**Frecuencias marginales con Pandas (pivot_table):**<jupyter_code>print('   Tabla de contigencia Limite Charles River vs \nÍndice de accesibilidad a carreteras radiales (en F-abs)')
tabla_marg = df_boston.pivot_table(values='MEDV', index='cat_RAD', columns=['CHAS'], aggfunc='count',
                      fill_value=None, margins=True, dropna=True,
                      margins_name='subtotal', observed=False)
tabla_marg.rename(columns={0:'no', 1:'si'}, inplace=True)
tabla_marg<jupyter_output>Tabla de contigencia Limite Charles River vs 
Índice de accesibilidad a carreteras radiales (en F-abs)<jupyter_text>**Frecuencias relativas marginales con Pandas (pivot_table):**<jupyter_code>print('   Tabla de contigencia Limite Charles River vs \nÍndice de accesibilidad a carreteras radiales (en F-rel)')
tabla_marg_rel = df_boston.pivot_table(values='MEDV', index='cat_RAD', columns=['CHAS'], aggfunc='count',
                      fill_value=None, margins=True, dropna=True,
                      margins_name='subtotal', observed=False)/len(df_boston)
tabla_marg_rel.rename(columns={0:'no', 1:'si'}, inplace=True)
tabla_marg_rel<jupyter_output>Tabla de contigencia Limite Charles River vs 
Índice de accesibilidad a carreteras radiales (en F-rel)<jupyter_text>**Con Pandas**- https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.crosstab.html<jupyter_code>pd.crosstab(df_boston["cat_RAD"], df_boston["CHAS"], values=None, colnames=['Lim River'], 
            rownames=['Ind accesib'], aggfunc=None, margins=True, margins_name= 'Subtotal',
            dropna= True, normalize=True).rename(columns={0:'no', 1:'si'})<jupyter_output><empty_output><jupyter_text>**Con Stats Models**- https://thequackdaddy.github.io/statsmodels.github.io/0.9.0/contingency_tables.html<jupyter_code>tabla_conting = sm.stats.Table.from_data(df_boston[["cat_RAD", "CHAS"]])
tabla_conting.table_orig.rename(columns={0:'no', 1:'si'})<jupyter_output><empty_output><jupyter_text>Representaciones gráficas de los datos  Gráfico  de sectoreshttps://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.pie.html **Con Matplotlib**<jupyter_code># cat_f_abs viene de las tablas de frecuencias
plt.figure(figsize=(5.5,5.5))
plt.pie(df_boston['CHAS'].value_counts(), labels=['NO', 'SI'], explode=(0,0.15), shadow=True, pctdistance=.8, startangle=90, autopct='%.2f%%')
plt.title('Frecuencia de viviendas\n en función de la cercanía al Charles River\n')
plt.show()
# cat_f_abs viene de las tablas de frecuencias
plt.figure(figsize=(5.5,5.5))
plt.pie(df_boston['CHAS'].value_counts(), labels=['NO', 'SI'], explode=(0,0.15), shadow=True, pctdistance=.8, startangle=90, 
       wedgeprops=dict(width=0.5),
       autopct='%.2f%%')
plt.title('Frecuencia de viviendas\n en función de la cercanía al Charles River\n')
plt.show()<jupyter_output><empty_output><jupyter_text>Gráfico  de bastones<jupyter_code>var_cat = 'RAD'                         # Variable categórica a graficar
frec_cat = df_boston[var_cat].value_counts()
plt.stem(np.array(frec_cat.index), np.array(frec_cat), use_line_collection=True, markerfmt=None)
plt.xlabel('Índice de accesibilidad a carreteras radiales'), plt.ylabel('Número de viviendas')
plt.title('Número de viviendas en función del \nÍndice de accesibilidad a carreteras radiales\n')
plt.show()<jupyter_output><empty_output><jupyter_text>Gráfico  de barras **Con Matplotlib**<jupyter_code>var_cat = 'CHAS'                         # Variable categórica a graficar
n_cat = df_boston[var_cat].nunique()
plt.figure(figsize=(n_cat*1.5,4))        # Definir un ancho de gráfico según el número de categorias de la variable
plt.bar(['SI','NO'], df_boston[var_cat].value_counts())
plt.xlabel('Limita con Charles River'), plt.ylabel('Número de viviendas')
plt.title('Número de viviendas\n en función de la cercanía al Charles River\n')
plt.show()<jupyter_output><empty_output><jupyter_text>**Con Seaborn**<jupyter_code>var_cat = 'CHAS'                         # Variable categórica a graficar
n_cat = df_boston[var_cat].nunique()
plt.figure(figsize=(n_cat*1.5,4))        # Definir un ancho de gráfico según el número de categorias de la variable
ax = sns.countplot(x=var_cat, data=df_boston, palette='Set1')
for p in ax.patches:
    ax.annotate('{:.0f} ({:.1f}%)'.format(p.get_height(), p.get_height()/len(df_boston)*100), (p.get_x()+0.05, p.get_height()+5))
ax.set_xticklabels(['no', 'si'], rotation=0, fontdict= {'horizontalalignment': 'center'})
plt.xlabel('Limita con Charles River'), plt.ylabel('Número de viviendas')
plt.title('Número de viviendas\n en función de la cercanía al Charles River\n')
plt.show()<jupyter_output><empty_output><jupyter_text>Histograma de Frecuencias<jupyter_code># El número de intervalos para un histograma se aconseja que sea un número entre 5 y 20, nunca menos de 5
var_sel = df_boston['CRIM']
n, b, _ = plt.hist(x=var_sel, bins=5, edgecolor='white',)# density=False, cumulative=False)
plt.xticks(b), plt.grid(color='gray', linestyle='--', linewidth=0.5)
plt.xlabel('Índice de criminalidad per cápita', fontdict={'fontsize': 14})
plt.ylabel('Frecuencias', fontdict={'fontsize': 14}),plt.title('Histograma del Índice de Criminalidad\n', fontdict={'fontsize': 18})
plt.show()<jupyter_output><empty_output><jupyter_text>Polígono de Frecuencias<jupyter_code>plt.plot([0]+list((b[:-1] + b[1:])/2)+list(b[-1:]), [0]+list(n)+[0], marker='.', linestyle='-', linewidth=2, markersize=8)
plt.xticks(b), plt.grid(color='gray', linestyle='--', linewidth=0.5)
plt.show()<jupyter_output><empty_output><jupyter_text>**Reglas para calcular el número de intervalos de un histograma (bins):**- Comparación de las reglas principales: http://www1.frm.utn.edu.ar/estadistica/documentos/09NotaClase.pdf<jupyter_code># Cálculo del número de intervalos: en base a la raíz cuadrada del número de observaciones
n_bins = int(math.sqrt(len(var_sel)))
# Regla de Sturges: para cálculo del número de intervalos
k = int(1 + math.log2(len(var_sel)))                  # Número de intervalos a considerar
a = int(round((var_sel.max() - var_sel.min())/k, 0))  # Amplitud del intervalo = rango/nro intervalos, (redondear siempre por exceso)
# El siguiente cálculo, garantiza que todos los valores queden dentro de los intervalos formados
if a*(k-1) <= var_sel.max():
    k += 1
    max_var = k*a
# De manera opcional, se puede calcular un entero minimo a partir de los valores, para ajustar el histograma
min_var = int(var_sel.min()) 
bin_edges = np.arange(min_var, max_var, a)
n, bins, batches = plt.hist(x=var_sel, bins=bin_edges, edgecolor='white', density=False, cumulative=False)
plt.xticks(bins), #plt.yticks(np.arange(0,500,50))
plt.xlabel('Índice de criminalidad per cápita', fontdict={'fontsize': 14}), plt.grid(color='gray', linestyle='--', linewidth=0.5)
plt.ylabel('Frecuencias', fontdict={'fontsize': 14}),plt.title('Histograma del Índice de Criminalidad\n', fontdict={'fontsize': 18})
plt.show()
n, bins, batches
# A partir de los valores obtenidos del histograma se puede también obtener la Tabla de Frecuencias
# Intervalos: [LI,LS)
aux = {'LI': bins[:-1], 'LS': bins[1:], 'f_abs': n, 'f_abs_acum': np.cumsum(n),'f_rel': n/sum(n), 'f_rel_acum': np.cumsum(n/sum(n))}
pd.DataFrame(data=aux, index=np.arange(1, len(n)+1))<jupyter_output><empty_output><jupyter_text>**Sturges como parámetro:**<jupyter_code>var_sel = df_boston['CRIM']
plt.figure(figsize=(10,4))
n, b, _ = plt.hist(x=var_sel, bins='sturges', edgecolor='white',)# density=False, cumulative=False)
plt.xticks(b), plt.grid(color='gray', linestyle='--', linewidth=0.5)
plt.xlabel('Índice de criminalidad per cápita', fontdict={'fontsize': 14})
plt.ylabel('Frecuencias', fontdict={'fontsize': 14}), plt.title('Histograma del Índice de Criminalidad\n', fontdict={'fontsize': 18})
plt.show()<jupyter_output><empty_output><jupyter_text>ECDF<jupyter_code>from statsmodels.distributions.empirical_distribution import ECDF
x = np.array(df_boston['AGE'])
cdf = ECDF(x)
x.sort()
F = cdf(x)
plt.step(x, F, where='post'), plt.title('Frecuencias acumuladas')
plt.show()<jupyter_output><empty_output><jupyter_text>Boxplot o Gráfico de Caja y bigotes<jupyter_code>sns.boxplot(y='CRIM', data=df_boston)
plt.ylabel('Índice de Criminalidad', fontdict={'fontsize': 12})
plt.title('Distribución del Índice de Criminalidad', fontdict={'fontsize': 16})
plt.show()<jupyter_output><empty_output><jupyter_text>Swarm Plot, Beeswarm o Gráfico de Enjambre<jupyter_code>var_numer = 'CRIM'
sns.swarmplot(y=var_numer, data=df_boston)
plt.ylabel('Distribución del Índice de Criminalidad', fontdict={'fontsize': 12})
plt.title('Índice de Criminalidad', fontdict={'fontsize': 16})
plt.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1297881481971114, 'fraction_numerical': 0.018276762402088774, 'mean_word_length': 6.867394695787832, 'pattern_counts': {'":': 0, '<': 225, '<?xml version=': 0, '>': 224, 'https://': 9, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '59', 'dir': 'jupyter-structured-clean-dedup', 'id': '395091', 'license': 'MIT', 'n_tokens_mistral': 11853, 'n_tokens_neox': 11462, 'n_words': 2402, 'path': 'Estadistica_Descriptiva_con_Python.ipynb', 'repo_name': 'ninargue/EstadisticaConPython', 'size': '30257'}