<jupyter_start><jupyter_text>Notebook 01: Limpieza inicial de datos.Las tareas realizadas son:-Correccion de nombres, caracteres especiales, formato de datos.-Estandarización de Precios, por metro cuadrado.-Despliegue de columnas dummies según listas extraídas.<jupyter_code>import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from tqdm import tqdm
import seaborn as sns
import re
import warnings
pd.set_option('display.max_columns', None) #Para mostrar todas las columnas

df = pd.read_csv('../data/raw_database_urbania.csv')
df.drop(['Unnamed: 0','Unnamed: 0.1'],inplace=True,axis=1)

#Columnas a reemplazar.
nuevas_cols = ['Adicionales', 'Ambientes', 'Antiguedad', 'Anunciante','Area_Terreno','Balneario','NroBanios',
               'Nro_pisos','Cocheras','Descripcion','Direccion','Disposicion','Dormitorios','EsCondominio',
              'Estado de Inmueble', 'Fecha_pub', 'Fila', 'Fondo','Frente', 'Generales', 'Luminosidad', 
               'Mantenimiento', 'Mascotas','Medidas','NoTieneAlgunDatoExtra','Pisos_construibles','TipoPuertaCochera',
               'Precio','Referencia','Servicios','Tipo','TipoCochera','Ubicacion','Urbaniz',
               'Uso_comercial','Uso_profesional','latitud','longitud','Area_constr','Area_total','Areas_comunes']

df.columns = nuevas_cols<jupyter_output><empty_output><jupyter_text>Corrigiendo malos formatos.<jupyter_code>df.Dormitorios = df.Dormitorios.replace({'5 a mÃ¡s':'5+'}) #Reemplazo

#Usamos expresiones regulares para corregir algunas columnas. 
df['Antiguedad'] = df['Antiguedad'].str.extract('(\d)', expand = True).astype('float32')

#Limpiar area de m2
pattern_m2 = '(\d{0,3}.?)'
for column_m2 in ['Area_constr_m2','Area_constr','Area_Terreno']:
    df[column_m2] = df[column_m2].str.extract(pattern_m2)
dict_replacement = {"Ã³":"o","Ã±":"ni","Ã©":"e",
                    "Ã\xad":"i","Ã\x81":"A","Ã":"a","\\":"n","aº":"u","Ã¼":"u","¼":"u",
                    "Acceso para personas con discapacidad":"Acceso personas discapacidad",
                   "anx81rea ":"Area","\\r":" " ,"a¡":"a",'"':'',',':'','\n':'','\t':'','    ':'','  ':''}

for word, initial in dict_replacement.items():
    df['Servicios'] = df['Servicios'].str.replace(word, initial)
    df['Ambientes'] = df['Ambientes'].str.replace(word,initial)
    df['Areas_comunes'] = df['Areas_comunes'].str.replace(word,initial)
    df['Generales'] = df['Generales'].str.replace(word,initial)
    df['Adicionales'] = df['Adicionales'].str.replace(word,initial)
    df['Descripcion'] = df['Descripcion'].str.replace(word,initial)
    df['longitud'] = df['longitud'].str.replace(word,initial)
    df['latitud'] = df['latitud'].str.replace(word,initial)
drop_condominio = df[df.latitud.isna()].index
df.drop(drop_condominio,inplace=True,axis=0)
df['Ubicacion'] = df['Ubicacion'].replace({'BreÃ±a-Lima':'Brenia-Lima', 'San Vicente De CaÃ±ete-Lima':'Caniete-Lima',
                                          'PariÃ±as-Piura':'Parianias-Piura','Los BaÃ±os Del Inca-Cajamarca':'Los Banios Del Inca-Cajamarca',
                                          'CaÃ±ete-Lima':'Caniete-Lima'})
df['Ubicacion'] = df['Ubicacion'].str.replace(' ','')  #Para que no existan discordancias entre los strings
dist_prov = df['Ubicacion'].str.extractall(r'(\w*?)?-(\w*)')
dist_prov.columns = ['Distrito','Provincia']
dist_prov.reset_index(inplace = True)
dist_prov.drop(columns = ['match'],inplace=True)
dist_prov.set_index('level_0',inplace=True)
#Haré split a las columnas que tienen valores como listas.
ola1 = df['Servicios'].str.extractall('(\[\'\w*\s?\w*?\s?\w*?\'),?\]?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?')
ola2 = df['Ambientes'].str.extractall('(\[\'\w*\s?\w*?\s?\w*?\'),?\]?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?')
ola3 = df['Areas_comunes'].str.extractall('(\[\'\w*\s?\w*?\s?\w*?\'),?\]?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?')
ola4 = df['Generales'].str.extractall('(\[\'\w*\s?\w*?\s?\w*?\'),?\]?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?')
ola5 = df['Adicionales'].str.extractall('(\[\'\w*\s?\w*?\s?\w*?\'),?\]?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?,?\s?(\'\w*\s?\w*?\s?\w*?\')?\]?')
#Hacer el reemplazo para solo una moneda
df['Precio']=df['Precio'].str.replace(",","")
index_casas_soles = df[(df['Precio'].str.startswith('US') == False) & (df['Precio'].str.startswith('Consultar') == False)].index
#Hasta acà los tengo almacenados en memoria.
#Limpio los US$ y S/ solo seleccionando los digits con regex
df['Precio'] = df['Precio'].str.extract('(\d{0,3},?\d{0,3},?\d{1,3}$)')<jupyter_output><empty_output><jupyter_text>Ahora haremos join a las tablas que hemos creado<jupyter_code>tipo_de_cambio_actual = 3.37
warnings.filterwarnings('ignore')
df['Precio'] = df['Precio'].astype('float64')
df.iloc[index_casas_soles - 1]['Precio'] = df.iloc[index_casas_soles -1]['Precio'].apply(lambda x: x*tipo_de_cambio_actual)
df['Area_constr_m2'] = df['Area_constr_m2'].astype('float64') 
df['Area_total_m2'] = df['Area_total_m2'].astype('float64')
df['Area_Terreno_m2'] = df['Area_Terreno_m2'].astype('float64')<jupyter_output><empty_output><jupyter_text>plt.figure(figsize = (10,8))ax = sns.scatterplot(x='Area_total_m2',y='Precio',data= df)y_max = df['Precio'].max()ticks = [0, 0.25*y_max, 0.5*y_max, 0.75*y_max, y_max]ax.set_ylim(ax.get_ylim())  set second y axis to have the same limits as the first y axisax.set_yticks(ticks) ax.set_yticklabels(ticks)  set the labelsax.grid(True)<jupyter_code>df.head()<jupyter_output><empty_output><jupyter_text>Outliers<jupyter_code>index_ = df[(df['Precio']<=10000)&(df['Ubicacion']=='Cusco-Cusco')].index #Los que tienes de ubicación Cusco
index_2 = df[(df['Precio']<=10000)].index #Los que tiene un precio que no es lógico

##Corrigiendo los precios que no veo que sean lógicos...
a = df[df['Precio']<=10000]['Precio']*df[(df['Precio']<=10000)]['Area_total_m2'] #Corrijo ese precio (m2*Precio(m2))

df.iloc[index_2]['Precio'] = a #Reemplazo los precios que he corregido por sus valores en general.<jupyter_output><empty_output><jupyter_text>Asunciones:- Las variables más importantes son:    - Tipo_Casa    - Dormitorios    - Area_constr    - Distrito    - Departamento    - Estado_inmueble    - Ambientes<jupyter_code>def merge_my_dummies(df_):
    """
    En los datos crudos existe una columna con la lista de features extras característicos del inmueble.
    Esta función sacará cada valor de esos features y creará una columna por cada feature.
    
    Para ordenar mis dummies voy a tener que:

    1.- Sacar una lista de valores únicos para cada nombre comenzando desde adelante.
    
    2.- Iterar por sobre cada columna y cada elemento de la lista única, matcheando cuando los nombres son iguales.

    3.- En cada iteración ubicar las columnas iguales y sumarlas entre sí

    4.- Esta última suma, agregarla a un diccionario y posteriormente a un df
    """
    df_cols = list(df_.columns) #Las columnas en lista
    data = pd.get_dummies(df_, columns = df_cols) #Hago dummies
    data_cols = list(data.columns)
    cols_limpias = [w.replace('[','') for w in data_cols] #Limpio los nombres
    lista_unica_elem = list(set(nombre_col.split('_')[1] for nombre_col in cols_limpias)) #Hago lista única
    dicc_inter = {}
    for nombre_col in lista_unica_elem:
        cols_to_sum = data.columns[data.columns.str.contains(nombre_col)] #para cada iteración agarra las cols que contienen lo q quiero
        series_to_join = data[cols_to_sum].iloc[:,:].sum(axis = 1) #Acà tengo la serie
        dicc_inter[nombre_col] = series_to_join #Lo agrego a un dict
    dataframe = pd.DataFrame.from_dict(dicc_inter) #Lo convierto a un dframe
    return dataframe
df_servicios = merge_my_dummies(df1)
df_ambientes = merge_my_dummies(df2)
df_arcomunes = merge_my_dummies(df3)
df_generales = merge_my_dummies(df4)
df_adicional = merge_my_dummies(df5)<jupyter_output><empty_output><jupyter_text>Agregamos esta data al df original<jupyter_code>#Todos los features extras en un dataframe.
df_features = pd.concat([df_ambientes, df_servicios,df_arcomunes, df_generales, df_adicional], axis=1, sort=False)
df_features.fillna('NaN', inplace = True)
df_features.head()
df_features.reset_index(inplace = True)

#Vamos a hacer el cambio de las variables para poder hacer el respectivo join
df_features.set_index('level_0', inplace = True)
df_features.index.names = ['index']
df.index.names = ['index']

df_final = df.join(df_features,how='inner')
df_final = df_final.join(dist_prov,how='inner')

#Ahora borraremos las columnas de las que vienen nuestras dummies:
df_final.drop(['Servicios','Ambientes','Areas_comunes','Adicionales','Generales'],axis=1,inplace=True)<jupyter_output><empty_output><jupyter_text>Ahora que tenemos la data algo procesada, procederemos a limpiar los valores nulos en el siguiento notebook. La forma en la que quedaron los datos al final fue:<jupyter_code>#Lo exporto en otro csv para poder limpiar los datos con más facilidad.
df_final.to_csv('../data/notebook01_output_data.csv')
df_final<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.2702754399387911, 'fraction_numerical': 0.010424636572302984, 'mean_word_length': 4.69553376906318, 'pattern_counts': {'":': 14, '<': 37, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '607791', 'license': 'MIT', 'n_tokens_mistral': 4780, 'n_tokens_neox': 4697, 'n_words': 628, 'path': 'notebooks/Notebook01_Formateo_limpieza.ipynb', 'repo_name': 'PBenavides/House_pricing_Lima', 'size': '10456'}