# Importamos pandas
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt

"""
Explanation: Carga y manipulación de datos con pandas
_ pandas es una biblioteca de análisis de datos en Python que nos provee de las estructuras de datos y herramientas para realizar análisis de manera rápida. Se articula sobre la biblioteca NumPy y nos permite enfrentarnos a situaciones en las que tenemos que manejar datos reales que requieren seguir un proceso de carga, limpieza, filtrado, reduccióń y análisis. _
En esta clase veremos como cargar y guardar datos, las características de las pricipales estructuras de pandas y las aplicaremos a algunos problemas.
Se trata de una biblioteca muy extensa y que sigue evolucionando, por lo que lleva tiempo conocer todas las posibilidades que ofrece. La mejor forma de aprender pandas es usándolo, por lo que ¡nos ahorraremos la introducción e iremos directos al grano!
End of explanation
"""


from IPython.display import HTML
HTML('<iframe src="http://www.juntadeandalucia.es/agriculturaypesca/ifapa/ria/servlet/FrontController?action=Static&url=coordenadas.jsp&c_provincia=4&c_estacion=4" width="700" height="400"></iframe>')

# Vemos qué pinta tiene el fichero
# (esto es un comando de la terminal, no de python
# y solo funcionará en Linux o MAC)
!head ../data/tabernas_meteo_data.txt

"""
Explanation: Cargando los datos y explorándolos
Trabajaremos sobre un fichero de datos metereológicos de la Consejeria Agricultura Pesca y Desarrollo Rural Andalucía.
End of explanation
"""


# Tratamos de cargarlo en pandas
pd.read_csv("../data/tabernas_meteo_data.txt").head(5)

"""
Explanation: Vemos que los datos no están en formato CSV, sino que la delimitación son espacios. Si intentamos cargarlos con pandas no tendremos mucho éxito:
End of explanation
"""


data = pd.read_csv(
    "../data/tabernas_meteo_data.txt",
    delim_whitespace=True,   # delimitado por espacios en blanco
    usecols=(0, 2, 3, 4, 5),  # columnas que queremos usar
    skiprows=2,  # saltar las dos primeras líneas
    names=['DATE', 'TMAX', 'TMIN', 'TMED', 'PRECIP'],
    parse_dates=['DATE'],
#     date_parser=lambda x: pd.datetime.strptime(x, '%d-%m-%y'),  # Parseo manual
    dayfirst=True,  # ¡Importante
    index_col=["DATE"]  # Si queremos indexar por fechas
)

# Ordenando de más antigua a más moderna
data.sort_index(inplace=True)

# Mostrando sólo las primeras o las últimas líneas
data.head()

"""
Explanation: Tenemos que hacer los siguientes cambios:

Separar los campos por un número arbitrario de espacios en blanco.
Saltar las primeras líneas.
Dar nombres nuevos a las columnas.
Descartar la columna del día del año (podemos calcularla luego).
Parsear las fechas en el formato correcto.

La aproximación clásica a este tipo de problemas es hacer una lectura línea a línea en la que vayamos "parseando" los datos del fichero, de acuerdo al formato que esperamos recibir y nos protejamos cuando, no se cumpla la estructura.
Sin embargo, gracias a pandas podremos reducir nuestro esfuerzo drásticamente, dando a la función read_csv algunas indicaciones sobre el formato de nuestros datos
End of explanation
"""


# Comprobamos los tipos de datos de la columnas
data.dtypes

# Pedomos información general del dataset
data.info()

"""
Explanation: Las fechas también se pueden parsear de manera manual con el argumento:
date_parser=lambda x: pd.datetime.strptime(x, '%d-%m-%y'),  # Parseo manual
<div class="alert alert-info">Para acordarnos de cómo parsear las fechas: http://strftime.org/</div>
End of explanation
"""


data.index.dayofweek

"""
Explanation: En una dataframe pueden convivir datos de tipo diferente en diferentes columnas: en nuestro caso, fechas (en el índice) y (flotantes en las columnas). El que un dato sea de tipo fecha y no un string u otra cosa, nos permite obtener información como el día de la semana de manera directa:
End of explanation
"""


# Descripción estadística
data.describe()

"""
Explanation: Una vez hemos cargado los datos, estamos preparados para analizarlos utilizando toda la artillería de pandas. Por ejemplo, puede que queramos una descripción estadística rápida:
End of explanation
"""


# Accediendo como clave
data['TMAX'].head()

# Accediendo como atributo
data.TMIN.head()

# Accediendo a varias columnas a la vez
data[['TMAX', 'TMIN']].head()

"""
Explanation: Accediendo a los datos
Columnas
Tenemos dos formas de acceder a las columnas: por nombre o por atributo (si no contienen espacios ni caracteres especiales).
End of explanation
"""


# Modificando valores de columnas
data[['TMAX', 'TMIN']] / 10

"""
Explanation: Del mismo modo que accedmos, podemos operar con ellos:
End of explanation
"""


# Aplicando una función a una columna entera (ej. media numpy)
import numpy as np
np.mean(data.TMAX)

# Calculando la media con pandas
data.TMAX.mean()

"""
Explanation: e introducirlos en funciones:
End of explanation
"""


# Accediendo a una fila por índice
data.iloc[1]

# Accediendo a una fila por etiqueta
data.loc["2016-09-02"]

"""
Explanation: Filas
Para acceder a las filas tenemos dos métodos: .loc (basado en etiquetas), .iloc (basado en posiciones enteras) ~~y .ix (que combina ambos)~~ (.ix ha desaparecido en la versión 0.20).
End of explanation
"""


data.loc["2016-12-01":]

"""
Explanation: Puedo incluso hacer secciones basadas en fechas:
End of explanation
"""


# Comprobando que registros carecen de datos válidos
data.TMIN.isnull().head()

# Accediendo a los registros que cumplen una condición
data.loc[data.TMIN.isnull()]

# Valores de precipitación por encima de la media:
print(data.PRECIP.mean())
data[data.PRECIP > data.PRECIP.mean()]

"""
Explanation: Filtrando los datos
También puedo indexar utilizando arrays de valores booleanos, por ejemplo procedentes de la comprobación de una condición:
End of explanation
"""


# Calcular la media de la columna TMAX
data.TMAX.head(15)

# Media trimensual centrada
data.TMAX.rolling(5, center=True).mean().head(15)

"""
Explanation: Funciones "rolling"
Por último, pandas proporciona métodos para calcular magnitudes como medias móviles usando el método rolling:
End of explanation
"""


# Agruparemos por año y día: creemos dos columnas nuevas
data['year'] = data.index.year
data['month'] = data.index.month

"""
Explanation: Creación de nuevas columnas
End of explanation
"""


# Creamos la agrupación
monthly = data.groupby(by=['year', 'month'])

# Podemos ver los grupos que se han creado
monthly.groups.keys()

"""
Explanation: Creando agrupaciones
En muchas ocasiones queremos realizar agrupaciones de datos en base a determinados valores como son fechas, o etiquetas (por ejemplo, datos que pertenecen a un mismo ensayo o lugar)
Podemos agrupar nuestros datos utilizando groupby:
End of explanation
"""


# Accedemos a un grupo
monthly.get_group((2016,3)).head()

# Hhacemos una agregación de los datos:
monthly_mean = monthly.mean()
monthly_mean.head(24)

"""
Explanation: Con estos grupos podemos hacer hacer varias cosas:

Acceder a sus datos individualmente (por ejemplo, comprobar qué pasó cada día de marzo de 2016) 
Realizar una reducción de datos, para comparar diversos grupos (por, ejemplo caracterizar el tiempo de cada mes a lo largo de los años)
End of explanation
"""


# Dejar los años como índices y ver la media mensual en cada columna
monthly_mean.reset_index().pivot(index='year', columns='month')

"""
Explanation: Creando agrupaciones
En ocasiones podemos querer ver nuestros datos de forma diferente o necesitamos organizarlos así para utilizar determinadas funciones de pandas. Una necesidad típica es la de pivotar una tabla.
Imagina que queremos acceder a los mismos datos que en el caso anterior, pero que ahora queremos ver los años en las filas y para cada variable (TMAX, TMED...) los calores de cada mes en una columna. ¿Cómo lo harías?
End of explanation
"""


# Pintar la temperatura máx, min, med
data.plot(y=["TMAX", "TMIN", "TMED"])
plt.title('Temperaturas')

"""
Explanation: La línea anterior no es sencilla y no se escribe de una sola vez sin errores (sobre todo si estás empezando). Esto es una ejemplo de que pandas es una librería potente, pero que lleva tiempo aprender. Pasarás muchas horas peleando contra problemas de este tipo, pero afortunadamente mucha gente lo ha pasado mal antes y su experiencia ha quedado plasmada en cientos de preguntas de stack overflow y en la documentación de pandas
Plotting
Líneas
End of explanation
"""


data.loc[:, 'TMAX':'PRECIP'].plot.box()

"""
Explanation: Cajas
End of explanation
"""


group_daily = data.groupby(['month', data.index.day])

daily_agg = group_daily.agg({'TMED': 'mean', 'TMAX': 'max', 'TMIN': 'min', 'PRECIP': 'mean'})
daily_agg.head()

daily_agg.plot(y=['TMED', 'TMAX', 'TMIN'])

"""
Explanation: Pintando los datos de un "típíco día d del mes m del año a
Pintando la temperatura máxima de las máximas, mínima de las mínimas, media de las medias para cada día del año de los años disponnibles
End of explanation
"""


# scatter_matrix
from pandas.tools.plotting import scatter_matrix
axes = scatter_matrix(data.loc[:, "TMAX":"TMED"])

"""
Explanation: Visualizaciones especiales
End of explanation
"""


