#!/usr/bin/env python
# coding: utf-8

# # Parte 3: Transformación de tablas

# In[1]:


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

import warnings
warnings.filterwarnings('ignore')

pd.options.display.float_format = '{:.2f}'.format #Desactivar notación científica en pandas:
np.set_printoptions(suppress=True) #Desactivar notación científica en numpy:
pd.set_option('display.max_columns', None) #comando para mostrar todas las columnas


# In[2]:


df = pd.read_csv('./data/transacciones2.csv', sep=';', decimal=',')


# In[3]:


df


# In[4]:


df.info()


# In[5]:


df.Fecha = pd.to_datetime(df.Fecha, errors='coerce')


# In[6]:


df['mes'] = df.Fecha.dt.month


# In[7]:


df.head()


# In[8]:


# Comprobamos la existencia (o no) de registros duplicados


# In[9]:


filtro = df.duplicated(keep='first') # Booleano que podemos usar para filtrar los duplicados
filtro


# In[10]:


df.duplicated(keep='first').sum()


# In[11]:


# Podemos eliminar duplicados filtrando con filtro o a través de .drop_duplicates
df2 = df.drop_duplicates(keep='first')
print(df2.shape)
print(df.shape)
print (df.shape[0]-df2.shape[0]) # Vemos que en ambos casos, el total de registros duplicados es el mismo.


# In[12]:


# Tipos de comercios únicos
df2['Tipo de Comercio'].value_counts()


# In[13]:


# Pequeño inciso.  Simplificamos el formato del tipo de comercio.  Nos sobra es_
df2['Tipo de Comercio'] = df2['Tipo de Comercio'].str.replace('es_','')


# In[14]:


df2['Tipo de Comercio'].value_counts()


# In[15]:


# Además simplificamos los nombres de columna
df2.columns = ['fecha','cp','comercio','transacciones','importe','importetotal','mes']


# In[16]:


# Aprovechamos que value_counts() nos hace el trabajo, y filtramos por los 5 primeros comercios
tmp = df2['comercio'].value_counts()
filtro = tmp.index [0:5].values  # Los tipos de negocio son el índice del array
filtro


# # Probad a cambiar los nombres de estos 5 tipos de negocio al castellano, usando la función de mapeo vista anteriormente.

# In[17]:


# Código aquí


# In[18]:


df3 = df2 [df2['comercio'].isin(filtro)]


# In[19]:


df3['comercio'].value_counts()


# In[20]:


# Guardammos el resultado
df3.to_csv('./data/transacciones3.csv', sep=';', decimal=',', encoding='UTF-8')


# ## Unas agregaciones

# In[21]:


# Importe total por tipo de negocio
agregacion1 = pd.pivot_table(data = df3, columns='comercio', values='importetotal', aggfunc=sum).transpose()
agregacion1


# In[22]:


# Agregaciones en base a 2 valores.  Extraemos por tipo de comercio, la suma de ventas y la suma de transacciones 
agregacion2 = pd.pivot_table(data = df3, columns='comercio', values = ['importetotal', 'transacciones'], aggfunc='sum').transpose()
agregacion2


# In[23]:


# Un pelín más complicado
agsum = pd.pivot_table(data=df3, columns=['comercio','mes','cp'], values=['importetotal','transacciones'], aggfunc='sum').transpose()
agsum


# In[24]:


# Usamos otras funciones de agregación
agmean = pd.pivot_table(data=df3, columns=['comercio','mes','cp'], values=['importetotal','transacciones'], aggfunc='mean').transpose()


# # Probad vosotros a hacer una agregación donde se muestre:
# ## * Total transacciones por código postal
# ## * Total transacciones por código postal y mes
# ## * Transacciones máximas por código postal y tipo de comercio

# In[25]:


# Agregaciones en base a los percentiles
def p25(g):
    return np.percentile(g, 25)

def p75(g):
    return np.percentile(g, 75)

agpercentiles = df3.pivot_table(
    columns=['comercio'], 
    values=['importetotal'], 
    aggfunc=[p25, np.median, p75]).transpose()


# In[26]:


agpercentiles


# ## Modelado de tablas

# In[27]:


df3.head()


# In[28]:


# Pasar datos a formato ancho
pivotada = df3.pivot(index=['fecha','cp'], columns='comercio', values='importetotal')
pivotada


# In[29]:


# Eliminamos NA's pq en este caso implican ausencia de venta y por tanto el importe total de la transacción será 0
pivotada [pivotada.isnull()] = 0
pivotada

# Ojo!!!!! El paso anterior funciona, pq todas las columnas son numéricas.  Las de texto están como índice


# In[30]:


# ¿Qué pasa si intentamos pivotar una tabla en la que tenemos varios registros para un mismo dato?
df3.pivot(index=['cp'], columns='comercio', values='importetotal')


# In[31]:


# En estos casos deberemos hacer una agregación, para incluir las entradas duplicadas en una sola.
# En este ejemplo, tenemos registros donde para un CP y un Comercio, hay más de un importe total.  Varios negocios (o el mismo) puede vender varias veces el mismo día y por tanto.
pivotadacp1 = df3.pivot_table(index=['cp'], columns='comercio', values='importetotal', aggfunc=np.sum)
pivotadacp1


# In[32]:


pivotadacp2 = df3.pivot_table(index=['cp'], columns='comercio', values='importetotal', aggfunc='count').reset_index()


# In[33]:


pivotadacp2


# ## Fundido de tablas

# In[34]:


melt0 = pd.melt(pivotadacp2)
melt0


# In[35]:


# Usaremos este tipo de disposición en los datos para ejecutar test estadísticos (píntame este valor en función de esta columna, mírame si el valor de esta columna influye estadísticamente en el valor de esta otra, ...)


# In[36]:


melt0 = pd.melt(pivotada.reset_index(), id_vars='fecha')


# In[37]:


melt0


# In[38]:


# Fundimos a través de varios índices
melt1 = pd.melt(pivotada.reset_index(), id_vars = ['fecha','cp'])
melt1


# In[44]:


melt1.info()


# In[50]:


# Representamos gráficamente los resultados.
plt.rcParams['figure.figsize'] = (20, 20)
sns.regplot(x=melt1['fecha'], y=melt1['value'], fit_reg=False)


# In[57]:


plt.rcParams['figure.figsize'] = (20, 20)
sns.lineplot(x=melt1['fecha'], y=melt1['value'], hue=melt1['comercio'])


# In[165]:


# Pintamos el resultado por código postal
# Extraigo una lista ordenada de los códigos postales.
melt11 = melt1.sort_values('cp')
CP = melt1.cp.reset_index()
CP = CP['cp'].sort_values().unique()
CP


# In[157]:


melt11


# In[166]:


# No se ve muy claro, hay demasiada información.
# Pintamos los datos por código postal
plt.rcParams['figure.figsize'] = (15, 15)

for a in CP:
    datos = melt1[melt1['cp'] == a]
    sns.lineplot(x=melt1['fecha'][melt1['cp'] == a], y=melt1['value'], hue=melt1['comercio']).set(title=a)
    plt.show()


# In[107]:


tmp = melt1[(melt1.cp == 48001) | (melt1.cp == 48002)]
plt.rcParams['figure.figsize'] = (25, 25)
g = sns.FacetGrid(tmp, col="cp", height=10)

sns.lineplot(data=tmp, x='fecha', y='value', hue='comercio')


# ## Unión de tablas

# In[176]:


#Creamos los datos
df1 = pd.DataFrame({
    'idCliente':[1,2,3,4,5,6],
    'producto':['Tostadora','Tostadora','Tostadora','Radio','Radio','Radio']})
df2 = pd.DataFrame({
    'idCliente':[2,4,6,8,9],
    'provincia':['Bizkaia', 'Bizkaia','Gipuzkoa','Gipuzkoa','Gipuzkoa']})


# In[181]:


print (df1,"\n\n",df2)


# In[183]:


izquierda = pd.merge(
    left = df1,
    right = df2,
    how = 'left',
    on = 'idCliente')
izquierda


# In[184]:


derecha = pd.merge(
    left = df1,
    right = df2,
    how = 'right',
    on = 'idCliente')
derecha


# In[185]:


inner = pd.merge(
    left = df1,
    right = df2,
    how = 'inner',
    on = 'idCliente')
inner


# In[186]:


outer = pd.merge(
    left = df1,
    right = df2,
    how = 'outer',
    on = 'idCliente')
outer

