California housing I - Selección de variables y análisis exploratorio de datos
Bienvenido a la primera edición de una serie de artículos que pretenden demostrar un proceso simple para obtener información de los datos, tanto con técnicas estadísticas como con la intuición a través de gráficos, usando Python y algunos amigos suyos como Pandas y Scikit-learn.
Como excusa para aplicar varias ténicas, planteamos una tarea específica: predecir el valor de una propiedad en California según los detalles de la zona en que se encuentra. Para esto, usamos parte de esta base de datos, del censo de los EE.UU. de 1990. Está disponible en Google Colab por lo que es fácil ponerse a jugar con ella. Al final de esta serie de artículos subiré el notebook con el código completo.
Vamos a revelar detalles de los datos con estadística descriptiva, seleccionar y descartar variables según su importancia para nuestra tarea y reducir la dimensionalidad haciendo proyecciones sobre nuevas variables (que mantengan aún la totalidad de la información). Para ganar más intuición sobre qué implican los resultados de algunas de esas técnicas, vamos a graficar distribuciones de variables y distribuciones conjuntas.
Lectura de los datos
Empecemos mirando una descripción de algunos estadísticos de la muestra:
home_data = pd.read_csv("sample_data/california_housing_train.csv")
home_data.describe()
longitude | latitude | housing_median_age | total_rooms | total_bedrooms | population | households | median_income | median_house_value | |
---|---|---|---|---|---|---|---|---|---|
count | 17000.000000 | 17000.000000 | 17000.000000 | 17000.000000 | 17000.000000 | 17000.000000 | 17000.000000 | 17000.000000 | 17000.000000 |
mean | -119.562108 | 35.625225 | 28.589353 | 2643.664412 | 539.410824 | 1429.573941 | 501.221941 | 3.883578 | 207300.912353 |
std | 2.005166 | 2.137340 | 12.586937 | 2179.947071 | 421.499452 | 1147.852959 | 384.520841 | 1.908157 | 115983.764387 |
min | -124.350000 | 32.540000 | 1.000000 | 2.000000 | 1.000000 | 3.000000 | 1.000000 | 0.499900 | 14999.000000 |
25% | -121.790000 | 33.930000 | 18.000000 | 1462.000000 | 297.000000 | 790.000000 | 282.000000 | 2.566375 | 119400.000000 |
50% | -118.490000 | 34.250000 | 29.000000 | 2127.000000 | 434.000000 | 1167.000000 | 409.000000 | 3.544600 | 180400.000000 |
75% | -118.000000 | 37.720000 | 37.000000 | 3151.250000 | 648.250000 | 1721.000000 | 605.250000 | 4.767000 | 265000.000000 |
max | -114.310000 | 41.950000 | 52.000000 | 37937.000000 | 6445.000000 | 35682.000000 | 6082.000000 | 15.000100 | 500001.000000 |
Demos una pequeña descripción de las variables, tal como están en la página original. Cada observación corresponde a una manzana en California. Las variables longitude
y latitude
, si les sacamos la “e” del final, se explican solas; housing_median_age
es la mediana (no media) de la edad de una vivienda en la manzana de la observación; total_rooms
es la cantidad total de ambientes en la manzana; total_bedrooms
es la cantidad total de habitaciones; households
indica cuantas viviendas hay; median_income
es la mediana del ingreso salarial en la manzana; y median_house_value
es nuestra variable objetivo, que indica la mediana del valor de una propiedad en la manzana.
Podemos ver que total_rooms
, population
, households
y total_bedrooms
tienen un dominio bastante grande. Además, sus valores mínimos y máximos son números sospechosamente lindos.
En nuestra variable de interés, median_housing_value
, podemos ver que casi la mitad de los valores se encuentra en el último cuartil y que la mediana se encuentra no muy por debajo de la media. Con estos detalles podemos intuir que la distribución no es simétrica. Miremos dónde se encuentra su moda:
home_data.median_house_value.mode()
0 500001.0
dtype: float64
Este resultado no nos dice mucho sobre la asimetría, pero propone una cuestión interesante: ¿cómo es que la media y la mediana se encuentran en valores menores al punto medio del dominio muestral pero la moda está en el valor extremo superior de este? Vamos a verlo (sí, con los ojos) más adelante.
Para hacernos una idea de qué relación tiene cada variable con la que queremos predecir, veamos el coeficiente de correlación. Este toma valores en [-1, 1]. En valores absolutos, cuanto más cercano a 1 más relacionadas están las dos variables y, cuanto más cercano a 0, menos.
home_data.corr()
longitude | latitude | housing_median_age | total_rooms | total_bedrooms | population | households | median_income | median_house_value | |
---|---|---|---|---|---|---|---|---|---|
longitude | 1.000000 | -0.925208 | -0.114250 | 0.047010 | 0.071802 | 0.101674 | 0.059628 | -0.015485 | -0.044982 |
latitude | -0.925208 | 1.000000 | 0.016454 | -0.038773 | -0.069373 | -0.111261 | -0.074902 | -0.080303 | -0.144917 |
housing_median_age | -0.114250 | 0.016454 | 1.000000 | -0.360984 | -0.320434 | -0.295890 | -0.302754 | -0.115932 | 0.106758 |
total_rooms | 0.047010 | -0.038773 | -0.360984 | 1.000000 | 0.928403 | 0.860170 | 0.919018 | 0.195383 | 0.130991 |
total_bedrooms | 0.071802 | -0.069373 | -0.320434 | 0.928403 | 1.000000 | 0.881169 | 0.980920 | -0.013495 | 0.045783 |
population | 0.101674 | -0.111261 | -0.295890 | 0.860170 | 0.881169 | 1.000000 | 0.909247 | -0.000638 | -0.027850 |
households | 0.059628 | -0.074902 | -0.302754 | 0.919018 | 0.980920 | 0.909247 | 1.000000 | 0.007644 | 0.061031 |
median_income | -0.015485 | -0.080303 | -0.115932 | 0.195383 | -0.013495 | -0.000638 | 0.007644 | 1.000000 | 0.691871 |
median_house_value | -0.044982 | -0.144917 | 0.106758 | 0.130991 | 0.045783 | -0.027850 | 0.061031 | 0.691871 | 1.000000 |
Para ejemplificar cómo podemos leer la tabla, podemos hacer la siguiente lecture: si miramos las columnas de total_rooms
, total_bedrooms
, population
y households
podemos ver que están muy correlacionadas entre sí, pero no explican mucho a nuestro objetivo median_house_value
.
Dado que nos interesan las que sí se relacionan con ella, nos enfocaremos en encontrarlas. Sin embargo, hay que tener cuidado: algunas variables que tienen alta correlación con la variable objetivo pueden ayudar durante el entrenamiento pero luego impedir una buena generalización (sobreajuste o diferencias en la distribución —data mismatch). ¿Cómo es esto? Tomemos el ejemplo de la variable latitude
, que parece ser tener buena correlación con el valor de la vivienda. Si entrenamos el modelo teniéndola en cuenta, podría llegar el caso en que un barrio antiguamente barato se encarece. El modelo no se entera de ello y sigue pensando que tales coordenadas corrsponden a un precio bajo, con lo que no será preciso. Es preferible usar variables que generalicen bien, tal vez sacrificando un poco de precisión sobre los datos de entrenamiento pero ganando sobre los datos una vez puesto “en producción” el modelo.
Mirando el resto de los valores de correlación para el valor de la vivienda, el que más lo explica es median_income
, la mediana del ingreso, seguido de la latitud, la cantidad total de habitaciones en la manzana y la mediana de la edad en ella.
Pre-procesamiento
Normalización y estandarización
Muchos algoritmos funcionan mejor con datos estandarizados (centrados en 0 y con una varianza finita), lo que hace comparables los dominios de las distintas variables. Tal es el caso, por ejemplo, de las máquinas de vectores soporte, que en el futuro usaremos.
Hay varias formas de estandarizar los datos, pero nos vamos a quedar con la normal:
df_normal = home_data.copy(deep=True)
μ = pd.Series({col: 0 for col in home_data.columns}, dtype="float32")
σ = pd.Series({col: 0 for col in home_data.columns}, dtype="float32")
for col in home_data.columns:
μ[col] = home_data[col].mean()
σ[col] = home_data[col].std()
df_normal[col] = (home_data[col] - μ[col]) / σ[col]
df_normal.head(15)
longitude | latitude | housing_median_age | total_rooms | total_bedrooms | population | households | median_income | median_house_value | |
---|---|---|---|---|---|---|---|---|---|
0 | 2.619289 | -0.671501 | -1.079639 | 1.361655 | 1.764152 | -0.361173 | -0.075996 | -1.252506 | -1.210522 |
1 | 2.539496 | -0.573248 | -0.761850 | 2.296540 | 3.230346 | -0.261858 | -0.099402 | -1.081451 | -1.096713 |
2 | 2.494612 | -0.905436 | -0.920745 | -0.882436 | -0.866931 | -0.955326 | -0.999223 | -1.170071 | -1.048430 |
3 | 2.489624 | -0.928830 | -1.159087 | -0.524171 | -0.480216 | -0.796769 | -0.715753 | -0.362590 | -1.154480 |
4 | 2.489624 | -0.961581 | -0.682402 | -0.545731 | -0.506313 | -0.701809 | -0.622130 | -1.026424 | -1.222593 |
5 | 2.484637 | -0.933509 | 0.032625 | -0.576466 | -0.719837 | -0.660863 | -0.681945 | -0.282879 | -1.149307 |
6 | 2.484637 | -0.942866 | -0.285165 | 0.120799 | 0.333545 | 0.358431 | 0.342707 | -0.632431 | -1.076883 |
7 | 2.479650 | -0.372063 | 0.985994 | -0.840233 | -0.881166 | -0.918736 | -0.892596 | -1.139989 | -1.369165 |
8 | 2.479650 | -0.942866 | 0.429862 | 0.984123 | 1.507924 | 1.484882 | 1.442778 | -0.893731 | -1.283808 |
9 | 2.474663 | -0.372063 | 1.383231 | -0.526006 | -0.546646 | -0.559805 | -0.598724 | -0.887127 | -1.372614 |
10 | 2.474663 | -0.938187 | -1.000192 | 0.503377 | 0.620616 | 0.875048 | 0.839429 | -0.630912 | -1.041533 |
11 | 2.474663 | -0.947545 | -0.602955 | -0.300771 | -0.133834 | -0.215684 | -0.167018 | -1.183644 | -1.252769 |
12 | 2.469676 | -0.367384 | 1.542126 | -0.620503 | -0.691367 | -0.740142 | -0.754763 | -0.904788 | -1.368303 |
13 | 2.469676 | -0.372063 | 0.191520 | -0.075995 | -0.178911 | -0.072809 | -0.057791 | -0.351951 | -1.180345 |
14 | 2.459702 | -1.340557 | -1.079639 | -0.548483 | -0.382944 | -0.418672 | -0.523306 | -1.585341 | -1.399342 |
Selección de variables
Existen muchos métodos para la selección o síntesis de variables, pero nosotros vamos a trabajar solamente con pruebas univariadas para hacerlo, con las que se entrega un puntaje a cada variable. Tal vez en siguientes ediciones incluso implementemos el algoritmo de eliminación recursiva de variables, un método iterativo en el que se entrena un modelo primero con todas las variables y luego se lo va haciendo más simple eliminando las que muestran ser menos importantes.
Para un problema de clasificación, algunas pruebas que se pueden usar son la de χ-cuadrado, analizar la cantidad de información mutua y ANOVA con la prueba F; para una regresión, por otro lado, podemos usar nuevamente la prueba F y la cantidad de información mutua. La librería Scikit-learn permite usar cada una como argumento dentro de SelectKBest(prueba_univariada, k=)
para calificar las variables y quedarse con las k
“mejores”.
La prueba de independencia de χ-cuadrado sirve para determinar si hay una asociación considerable entre dos variables nominales. Lo hace analizando si las frecuencias de una clase de una variable varían mucho su valor para cada clase de la segunda variable. Sirve entonces para problemas de clasificación.
La información mutua es una medida de teoría de la información que describe la dependencia mutua entre variables a través de la divergencia de Kullback-Leibler entre la distribución conjunta y el producto de las distribuciones marginales.
El test F para ANOVA analiza cómo se compara la varianza de una variable a lo largo de los valores de otra variable. Si varía mucho significa que alguno de los valores de esta última variable son más responsables por la variabilidad de la primera, mientras que otros valores lo son menos.
Los métodos basados en el test F estiman una relación lineal entre las variables, por lo que no captan dependencias alineales. Por otro lado, la información mutua sí lo hace. Como χ-cuadrado trabaja con variables nominales, no la usaremos por ahora.
En código, usando la librería Scikit-learn, hacemos los análisis con el test F y con la información mutua de la siguiente forma:
anova_filter_reg = SelectKBest(f_regression, k=5)
anova_filter_reg.fit(df_normal.drop(["median_house_value"], axis=1),
df_normal["median_house_value"])
for i in anova_filter_reg.get_support(indices=True):
print(df_normal.columns[i])
latitude
housing_median_age
total_rooms
households
median_income
Esto nos dice que las variables importantes —linealmente— son la latitude
, la edad housing_median_age
, la cantidad de ambientes total_rooms
y el ingreso median_income
, lo que se condice con la tabla de correlación.
mi_filter_reg = SelectKBest(mutual_info_regression, k=5)
mi_filter_reg.fit(df_normal.drop(["median_house_value"], axis=1), df_normal["median_house_value"])
for i in mi_filter_reg.get_support(indices=True):
print(df_normal.columns[i])
longitude
latitude
housing_median_age
total_rooms
median_income
Podemos ver que cuatro de las variables elegidas se condicen con el test previo. La única diferencia es entre la cantidad de viviendas households
y la longitude
. Esto se puede deber, como anticipamos, a alguna alinealidad capturada por información mutua y no por F.
Análisis de componentes principales (PCA)
El análisis de componentes principales es otra forma de reducir la dimensionalidad de los datos. Es una técnica de aprendizaje no supervisado (no necesitamos saber el precio de la vivienda) que proyecta los datos sobre nuevos ejes, nuevas variables, sobre los que los datos mantienen toda su información (medida en cantidad de varianza), intentando que la cantidad de variables sea menor. Matemáticamente, se realiza calculando la matriz de covarianza, obteniendo los autovalores y autovectores de ella y eligiendo aquellos responsables de la mayoría (usualmente alrededor del 99%) de la variabilidad de los datos.
pca = PCA(n_components=0.99, svd_solver='auto')
pca.fit(df_normal.drop(["median_house_value"], axis=1))
PCA(copy=True, iterated_power='auto', n_components=0.99, random_state=None,
svd_solver='auto', tol=0.0, whiten=False)
Una vez obtenidos los componentes princiales, podemos verlos con el atributo components_
del objeto PCA:
print(pca.components_)
[[ 0.07904068 -0.07631081 -0.2181667 0.48316747 0.49022067 0.47243444 0.49156034 0.04170786]
[-0.70080222 0.7013323 0.02073468 0.07747009 0.06348259 0.02977278 0.06579091 -0.03650765]
[-0.05845201 0.01421506 -0.38966987 0.09753053 -0.11547515 -0.11482791 -0.10743051 0.89272908]
[-0.06642402 -0.1028198 0.88809884 0.11535503 0.06358447 0.08414255 0.09701523 0.40305669]
[-0.10510948 -0.05497627 -0.03609806 -0.30865347 -0.37872447 0.84925327 -0.14741019 0.05446535]
[ 0.47261304 0.45743518 0.09126113 0.5681172 -0.24096963 0.12581277 -0.39828178 -0.06148691]]
En este caso vemos que con 6 variables logró mantener la variabilidad en 99%. Veamos qué tan responsable sobre ella es cada uno de los componentes:
print(f"Explained variance in data:{pca.explained_variance_},\nRatio:{pca.explained_variance_ratio_}")
Variabilidad explicada:[3.91167716 1.90686359 1.07259181 0.82308895 0.14375284 0.08117511].
Cociente:[0.48895963 0.23835794 0.13407397 0.10288612 0.0179691 0.01014689]
Mirando el segundo renglón de la salida de la consola, podemos ver que el primer autovector es responsable por casi el 49% de la varianza y cuánto nos aportan los demás. Nuevamente, 6 vectores son todavía necesarios para mantener el 99%.
Una vez que decidimos proyectar los datos sobre estos nuevos ejes, los transformamos de la siguiente manera:
df_pca = pca.transform(df_normal.drop(["median_house_value"], axis=1))
Visualización
Veamos cómo se distribuyen los datos de las variables que vimos que son importantes y cómo se relacionan con nuestra variable objetivo.
Valor
Distribución
Veamos la distribución del valor de una vivienda en un histograma.
Confirmamos la sospecha que teníamos sobre la asimetría en la distribución. También podemos ver la moda que habíamos obtenido: el valor más frecuente es el extremo superior. Esto se puede deber a que, durante la limpieza de los datos, se reemplazaron valores superiores, demasiado alejados del resto, excepcionales (outliers), por un valor menor.
Households (cantidad de viviendas)
Distribución
Miremos ahora la distribución de la cantidad de viviendas.
Vemos que esta variable es muy asimétrica. Tomemos el logaritmo para tener más resolución sobre sus “laderas”:
configure_plotly_browser_state()
pd.DataFrame(data=np.log10(home_data["households"]) \
.iplot(kind="histogram",
bins=100,
histnorm="probability",
filename="cufflinks/histogram"))
El logatimo logra volverla más simétrica. Vemos, al igual que en la tabla descriptiva del comienzo, que la media se encuentra en 500 viviendas = 10^2.7 , aproximadamente.
Cantidad de viviendas vs. valor
Veamos cómo se relaciona la cantidad de viviendas con nuestra variable de interés, el valor de ella. Lo podemos hacer con un diagrama de dispersión (scatter plot), que nos da una idea de la distribución conjunta de las variables.
Vemos que se forma un gran cúmulo (cluster) con gran variabilidad, sobre todo hacia valores mayores de valor y menores de cantidad de viviendas. Esto último no aporta información intuitiva ya que, recordemos, aplicamos el logaritmo.
Edad de las viviendas
Distribución
Realicemos el mismo análisis para la variable median_housing_age
. Esta era una de las variables más correlacionadas según los análisis de selección. El siguiente gráfico muestra la variable ya normalizada.
Nuevamente vemos un probable reemplazo de valores extremos superiores por uno límite. Si vamos a la tabla descriptiva del comienzo, vemos que el valor máximo es 52 años.
Hay muchos valores que son considerablemente más frecuentes que otros. Parecen incluso estar distribuidos casi periódicamente. Dado que se trata de una zona con actividad sísmica, resulta sorprendente que la distribución resulte simétrica (por lo menos para alguien que no sabe sobre tecnología antisísmica en la construcción).
Edad vs. valor
Para ver si podemos llegar a hacernos una idea de qué vieron los métodos de selección de variables en la edad para decir que es útil para predecir el valor, hagamos de nuevo un gráfico de dispersión.
A primera vista, la distribución de los daots parece aleatoria. Aguzando un poco la vista, podemos ver que los datos de edad no son continuos sino discretos, parece haber menos datos para manzanas de edad mediana menor a 12 años y es visible la asimetría de los datos, con prevalencia de casas más baratas. Parece haber rangos de años con menor variabilidad o asimetría y, arriesgándonos, nuevamente alguna periodicidad.
Habitaciones
Repitamos el mismo tipo de análisis para la cantidad de habitaciones por manzana.
Distribución
Acá ya tomamos el logaritmo para volver más simétrica la distribución. La media vimos ya en la tabla del comienzo que se encontraba cerca de 540 habitaciones por manzana, con un gran desvío: 421.
Habitaciones vs. valor
Observando el gráfico de dispersión de ambas variables ya normalizadas, vemos nuevamente un solo cúmulo disperso.
Ambientes
Distribución
La distribución original es altamente asimétrica, por lo que nuevamente tomamos el logaritmo para el gráfico.
La tabla descriptiva nos había arrojado una media para la cantidad de ambientes de 2644 con un desvío de 2179. El mínimo era 2 y el máximo 37937, lo que habla de la diferencia de densidades poblacionales en distintas zonas.
Ambientes vs. valor
Veamos si a simple vista hay alguna relación entre la cantidad de ambientes en la manzana y el valor de una vivienda en ella.
Nuevamente vemos un cúmulo que no parece mostrar una relación clara entre las variables, por más que haya aparecido como una variable importante durante la selección.
Ingreso
Esta fue la variable mejor puntuada por todos los métodos, veamos porqué.
Distribución
Nada sorprendente (lamentablemente) aquí.
Ingresos vs. valor
El gráfico de dispersión muestra una clara correlación positiva entre la mediana del ingreso en una manzana y el valor de una vivienda en ella. A mayor mediana del ingreso en una manzana, mayor el valor de una vivienda en ella. A valores de vivienda bajos, la distribución de ingresos muestra mayor variabilidad que a valores altos.
Intuitivamente, tiene sentido que los métodos de selección hayan priorizado esta variable.
Veamos un mapa de calor para esta distribución conjunta, sin suavizado por kernel, solamente con la densidad de la muestra.
t-SNE
Por último, el algoritmo t-distributed Stochastic Neighbor Embedding es un buen recurso para visualizar datos complejos, de alta dimensionalidad. Transforma a ellas a nuevos ejes en los que logra separar grupos de datos similares, usando medidas de semejanza para el cálculo de probabilidades conjuntas y tratando de minimizar la divergencia de Kullback-Leibler entre la probabilidad conjunta en el dominio original y en el nuevo. Esto último lo hace iterativamente a través del gradiente descendente. Como se enfoca en la estructura local de los datos, tiende a dar como resultado cúmulos.
Veamos cómo aplica a estos datos si queremos reducir las dimensiones a 2 para poder graficarlas. Para ello, creemos una nueva variable nominal a partir de la variable de valor de vivienda. La vamos a separar en 5 rangos distintos: los primeros tres cuartiles, luego un rango entre el cuantil del 0.75 y el 0.9 y finalmente uno correspondiente al cuantil entre 0.9 y 1.
tsne = TSNE(n_components=2,
perplexity=30,
early_exaggeration=20.0,
init='pca',
random_state=10, # for reproducibility
verbose=1) # for control freaks
df_normal["quantile"] = pd.qcut(home_data["median_house_value"],
[0, .25, .5, .75, .9, 1.],
labels=False)
df_tsne = tsne.fit_transform(df_normal.drop(["median_house_value"], axis=1))
df_tsne = pd.DataFrame(data={"col0":df_tsne[:, 0],
"col1":df_tsne[:, 1]})
df_tsne["value"] = home_data["median_house_value"]
df_tsne["income"] = home_data["median_income"]
df_tsne["quantile"] = df_normal["quantile"]
sample_tsne = df_tsne.sample(frac=0.01)
sample_tsne["quantile"] = sample_tsne["quantile"].astype('float16') # hot fix for cufflinks
configure_plotly_browser_state()
sample_tsne.iplot(kind="bubble",
size="income",
categories="quantile",
text="income",
x="col0", y="col1",
filename="cufflinks/simple-bubble-chart")
Si bien se puede ver que el algoritmo logró formar una suerte de estrato por cada categoría, muchas veces se entrecruzan, con lo que los vectores de las nuevas dimensiones no resultan intuitivos. Resulta claro, sin embargo, que se han formado cúmulos por cada valor que toma la categoría artificial de valor de vivienda.
Probemos entonces en tres dimensiones:
tsne3 = TSNE(n_components=3,
perplexity=30,
early_exaggeration=20.0,
init='pca',
random_state=10)
df_tsne3 = tsne3.fit_transform(df_normal.drop(["median_house_value"], axis=1))
df_tsne3 = pd.DataFrame(data={"col0":df_tsne3[:, 0],
"col1":df_tsne3[:, 1],
"col2":df_tsne3[:, 2]})
df_tsne3["value"] = home_data["median_house_value"]
df_tsne3["income"] = home_data["median_income"]
df_tsne3["quantile"] = df_normal["quantile"]
sample_tsne3 = df_tsne3.sample(frac=0.01)
sample_tsne3["quantile"] = sample_tsne3["quantile"].astype('float16')
configure_plotly_browser_state()
sample_tsne3.iplot(kind="scatter3d",
mode="markers",
categories="quantile",
text="income",
x="col0", y="col1", z='col2')
A primera vista el gráfico de dispersión no dice mucho, pero el humilde autor sugiere activar y desactivar categorías y jugar con las herramientas de zoom y rotación turntable, disponibles en la esquina superior derecha del gráfico, si el lector se encuentra en una PC o hacer click en el gráfico y luego jugar de la misma forma en el sitio de Plotly si se encuentra en un teléfono móvil o tablet.
Con las rotaciones y eliminando categorías se hace evidente que el algoritmo logró hacer casi linealmente separables a los grupos de datos de distintas categorías, lo que es digno de loas dada, por un lado, la aritifialidad de la variable nominal de valor de vivienda y por otro el carácter continuo de todas las variables.
Conclusiones
Con esto damos por finalizada la primera edición de esta serie de posteos sobre un proceso simple de extracción de conocimiento sobre una base de datos. Hemos cubierto cómo obtener algunas intuiciones a partir de un resumen descriptivo de la muestra, gracias al método describe
de un dataframe de Pandas. También vimos cómo hacerse una idea rápida de qué variables son más responsables por la variación en otra a través de la correlación con el método corr
del dataframe. Vimos luego cómo implementar dos métodos de selección de variables con Scikit-learn: ANOVA con test F y cantidad de información mutua. Se mostró otro método de reducción de dimensionalidad, el análisis de componentes principales. Finalmente, vimos cómo a veces los gráficos pueden decir menos que los números y cómo a veces transmiten más ideas.
En la siguiente edición haremos comparaciones entre distintos algoritmos para esta tarea de predicción de valor de una vivienda.