<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Nuevamente, vamos a leer primero unos datos...
Step1:  Lectura de un fichero de datos
Step2:  Lectura de un segundo fichero de datos
Step3:  Tenemos datos con una frecuencia temporal mínima de 10 minutos (wind) frente a unos segundos datos con una frecuencia temporal de 1 hora (model).
Inciso
Step4:  Si no indicamos nada, por defecto, las operaciones se realizan sobre las filas (axis = 0), es decir, se cogen todos los elementos de fila de cada columna
Step5:  Si queremos que nos dé el resultado de cada fila, es decir, se cogen todos los elementos de columna de una fila, debemos indicar que axis = 1
Step6:  Otro ejemplo
Step7:  Espero que haya quedado un poco claro con estos ejemplos simples.
Uniendo estructuras de datos pandas
Lo que vamos a ver no es evidente y, en algunos casos, es conveniente conocer algebral relacional para poder enterder qué es lo que está pasando.
Uniendo datos usando concat
Step8:  
Step9:  concat permite 'unir' estructuras de datos pandas usando filas o columnas. 
¿¿¿¡¡¡Y lo anterior no os ha quedado nada claro!!!??? ¿¿¿¡¡¡Y no habéis preguntado!!!???
Veamos un ejemplo más simple
Step10:  Normalmente uso esta última opción con nombres de columnas diferentes porque normalmente es lo que quiero hacer...
Concatenando usando el método append
Podemos hacer algo parecido a lo anterior usando el método append de las estructuras de datos
Step11:  Normalmente esto no es lo que quiero hacer. Normalmente quiero juntar con cierta lógica estructuras de datos pandas y para ello podemos usar pd.merge...
Usando pd.merge como en una base de datos SQL
Step12:  Imaginemos que queremos unir dos DataFrames usando valores de columnas
Step13:  Combinando usando el método join
Un poco más de lo mismo. El método join nos ayuda, nuevamente, a unir estructuras de datos pandas. Vamos a ver unos pocos ejemplos rápidos
Step14:  Agrupando
Podemos agrupar información de nuestras estructuras de datos de forma muy sencilla mediante el método groupby. Normalmente se sigue una estrategia de separar-aplicar-combinar (split-apply-combine). Lo que se hace es separar los datos iniciales en grupos de interés, sobre cada grupo se aplica cierta funcionalidad y el resultado se combina en una nueva estructura de datos.
Step15:  Veamos lo estructura que nos devuelve groupby
Step16:  pandas.core.groupby.DataFrameGroupBy es una especie de diccionario con superpoderes!!!
Reformando/transformando/modelando nuestras estructuras de datos
<div class="alert alert-info">
<p>Prácticamente toda esta parte la he extraído del <a href="https
Step17:  Pivotando usando varias columnas
Step18:  Qué pasa si en lo que combinamos encontramos índices repetidos. Por ejemplo
Step19:  (fuente
Step20:  pivot_table al rescate para resolver el anterior error
El anterior error lo podemos resolver usando pivot_table que es un poco más flexible que pivot
<ASSISTANT_TASK:>
Python Code:
# primero hacemos los imports de turno
import os
import datetime as dt
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import display
np.random.seed(19760812)
%matplotlib inline
Explanation: Nuevamente, vamos a leer primero unos datos...
End of explanation
# Leemos los datos del fichero 'mast.txt'
ipath = os.path.join('Datos', 'mast.txt')
def dateparse(date, time):
    YY = 2000 + int(date[:2])
    MM = int(date[2:4])
    DD = int(date[4:])
    hh = int(time[:2])
    mm = int(time[2:])
    
    return dt.datetime(YY, MM, DD, hh, mm, 0)
    
cols = ['Date', 'time', 'wspd', 'wspd_max', 'wdir',
        'x1', 'x2', 'x3', 'x4', 'x5', 
        'wspd_std']
wind = pd.read_csv(ipath, sep = "\s*", names = cols, 
                   parse_dates = {'Timestamp': [0, 1]}, index_col = 0,
                   date_parser = dateparse)
Explanation: Lectura de un fichero de datos
End of explanation
# Leemos los datos del fichero 'model.txt'
ipath = os.path.join('Datos', 'model.txt')
model = pd.read_csv(ipath, sep = "\s*", skiprows = 3,
                    parse_dates = {'Timestamp': [0, 1]}, index_col = 'Timestamp')
for c in ['x1','x2','x3','x4','x5']: # Eliminamos unas columnas innecesarias
    _ = wind.pop(c)
wind.head(3)
model.head(3)
wind['Timestamp'] = wind.index
print(wind['Timestamp'].diff().min())
del wind['Timestamp']
model['Timestamp'] = model.index
print(model['Timestamp'].diff().min())
del model['Timestamp']
Explanation: Lectura de un segundo fichero de datos
End of explanation
df = pd.DataFrame(np.array([[1, 10], [2, 20], [3,30]]), columns = ['A', 'B'])
df
Explanation: Tenemos datos con una frecuencia temporal mínima de 10 minutos (wind) frente a unos segundos datos con una frecuencia temporal de 1 hora (model).
Inciso: axis 101
En muchas ocasiones vamos a encontrar una keyword llamada axis. Veamos en un momento cómo funciona en pandas para evitarnos posibles problemas e incongruencias:
Posibilidades
axis = 0 (actúa sobre las filas/rows)
axis = 1 (actúa sobre las columnas/columns)
<span style="color:#888">axis = 2 (solo para Panel)</span>
(fuente: http://stackoverflow.com/a/25774395/5216568).
<br>
<div class="alert alert-info">
<p><b>Regla nemotécnica:</b></p> 
<p>Puedes pensar que el '1' es como una columna.</p>
<p><b>Otras opciones:</b></p> 
<p>Otra opción sería usar `axis = 'index'` (similar a `axis = 0`) o `axis = 'columns'` (similar a `axis = 1`) para `DataFrame`s. Para `Panel`es tendríamos `items`, `minor`, `major` (similar a las opciones 0, 1 o 2).</p>.
<p>Para `DataFrame`s también podéis usar `index = 'rows'`, que me parece que es más evidente que `'index'` pero no lo recomiendo ya que no está documentado en ningún sitio.</p>
<p>Además, usar `'index'`, `'rows'`, `'columns'`,..., puede llegar a ser confuso ya que en muchos sitios nos encontraremos con *keywords* que usan esa nomenclatura.</p>.
</div>
Pero, que significa que 'actúa sobre las filas/columnas'. Veamos algunos ejemplos simples para ver si nos queda un poco más claro:
End of explanation
df.sum()
# Lo anterior sería similar a 
df.sum(axis = 0)
Explanation: Si no indicamos nada, por defecto, las operaciones se realizan sobre las filas (axis = 0), es decir, se cogen todos los elementos de fila de cada columna:
End of explanation
df.sum(axis = 1)
Explanation: Si queremos que nos dé el resultado de cada fila, es decir, se cogen todos los elementos de columna de una fila, debemos indicar que axis = 1:
End of explanation
df < 10
(df < 10).all()
(df < 10).all(axis = 'columns') # en lugar de axis = 1 usamos axis = 'columns'
# Probad operaciones sobre df usando axis = 0, 1, 'index', rows', columns'
Explanation: Otro ejemplo:
End of explanation
new = pd.concat([wind, model], axis = 0, join = 'outer')
new.head(5)
new.tail(5)
new.loc['2014/01/01 00:00':'2014/01/01 02:00']
Explanation: Espero que haya quedado un poco claro con estos ejemplos simples.
Uniendo estructuras de datos pandas
Lo que vamos a ver no es evidente y, en algunos casos, es conveniente conocer algebral relacional para poder enterder qué es lo que está pasando.
Uniendo datos usando concat
End of explanation
new = pd.concat([wind, model], axis = 1, join = 'inner')
new.head(5)
new.loc['2014/01/01 00:00':'2014/01/01 02:00']
Explanation: 
End of explanation
df1 = pd.DataFrame(np.random.randn(10,2), 
                   columns = ['A', 'B'], 
                   index = np.arange(10))
df2 = pd.DataFrame(np.random.randn(4,3), 
                   columns = ['A', 'B', 'C'], 
                   index = np.arange(8, 12))
df1
df2
new = pd.concat([df1, df2], axis = 0, join = 'inner')
new
new = pd.concat([df1, df2], axis = 1, join = 'inner')
new
Explanation: concat permite 'unir' estructuras de datos pandas usando filas o columnas. 
¿¿¿¡¡¡Y lo anterior no os ha quedado nada claro!!!??? ¿¿¿¡¡¡Y no habéis preguntado!!!???
Veamos un ejemplo más simple:
End of explanation
wind.append(model)
Explanation: Normalmente uso esta última opción con nombres de columnas diferentes porque normalmente es lo que quiero hacer...
Concatenando usando el método append
Podemos hacer algo parecido a lo anterior usando el método append de las estructuras de datos:
End of explanation
pd.merge(wind, model, left_index = True, right_index = True, how = 'inner').head(5)
(pd.merge(wind, model, left_index = True, right_index = True, how = 'inner') == 
 pd.concat([wind, model], axis = 1, join = 'inner')).all().all()
Explanation: Normalmente esto no es lo que quiero hacer. Normalmente quiero juntar con cierta lógica estructuras de datos pandas y para ello podemos usar pd.merge...
Usando pd.merge como en una base de datos SQL
End of explanation
df1 = pd.DataFrame(
    np.array([
        np.arange(1, 11),
        np.random.choice([1,2,3], size = 10),
        np.arange(1, 11) * 10
    ]).T,
    columns = ['A', 'col', 'B']
)
df2 = pd.DataFrame(
    np.array([
        np.arange(11, 21),
        np.random.choice([1,2,3], size = 10),
        np.arange(1, 11) * 100
    ]).T,
    columns = ['A', 'col', 'B']
)
display(df1)
display(df2)
pd.merge(df1, df2, on = ['col'])
# Jugad un poco y mirad las keywords del pd.merge para ver otras opciones
Explanation: Imaginemos que queremos unir dos DataFrames usando valores de columnas:
End of explanation
wind.join(model).head(10)
model.join(wind).head(10)
joinA  = wind.join(model, how = 'inner') 
joinB = model.join(wind, how = 'inner').loc[:,joinA.columns]
(joinA == joinB).all().all()
Explanation: Combinando usando el método join
Un poco más de lo mismo. El método join nos ayuda, nuevamente, a unir estructuras de datos pandas. Vamos a ver unos pocos ejemplos rápidos:
End of explanation
wind['month'] = wind.index.month
wind.iloc[[0, 1000, 10000, 30000]]
wind.groupby(by = 'month').mean()
wind.groupby(by = [wind.index.year, 'month']).mean()
del wind['month']
# Jugad un poco agrupando 
# (sacad valores medios diarios de la velocidad del viento, 
# la velocidad promedio de los martes cuando la dirección es mayor que 300 y menos que 360,...)
Explanation: Agrupando
Podemos agrupar información de nuestras estructuras de datos de forma muy sencilla mediante el método groupby. Normalmente se sigue una estrategia de separar-aplicar-combinar (split-apply-combine). Lo que se hace es separar los datos iniciales en grupos de interés, sobre cada grupo se aplica cierta funcionalidad y el resultado se combina en una nueva estructura de datos.
End of explanation
grouped = wind.groupby(by=wind.index.month)
import inspect
info = inspect.getmembers(grouped, predicate=inspect.ismethod)
for stuff in info:
    print(stuff[0])
grouped
grouped.ngroups
grouped.groups.keys()
grouped.get_group(2)
Explanation: Veamos lo estructura que nos devuelve groupby
End of explanation
wind['year'] = wind.index.year
wind['month'] = wind.index.month
tmp = wind.groupby(by = ['year', 'month']).mean()
del wind['year']
del wind['month']
tmp
tmp['year'] = tmp.index.get_level_values(0)
tmp['month'] = tmp.index.get_level_values(1)
tmp
tmp.pivot(index = 'year', columns = 'month', values='wspd')
# Obtened la velocidad media de cada año 
# partiendo de tmp.pivot(index='level_0', columns='level_1', values='wspd')
Explanation: pandas.core.groupby.DataFrameGroupBy es una especie de diccionario con superpoderes!!!
Reformando/transformando/modelando nuestras estructuras de datos
<div class="alert alert-info">
<p>Prácticamente toda esta parte la he extraído del <a href="https://nikolaygrozev.wordpress.com/2015/07/01/reshaping-in-pandas-pivot-pivot-table-stack-and-unstack-explained-with-pictures/">excelente artículo</a>
<em>Reshaping in Pandas – Pivot, Pivot-Table, Stack and Unstack explained with Pictures</em> de <b>Nikolay Grozev</b>.</p>
<p>Kudos para Nikolay.</p>
<p>Kudos para mi por seguir los principios <a href="https://en.wikipedia.org/wiki/Don't_repeat_yourself">DRY</a> y <a href="https://en.wikipedia.org/wiki/KISS_principle">KISS</a>.</p>
</div>
Reshaping (transformar) sirve para cambiar nuestra estructura de datos en una nueva para realizar nuevos análisis específicos con los nuevos datos recombinados.
Pivot
Obtenemos una nueva tabla derivada de nuestra tabla inicial de datos. Por ejemplo, imaginad que quiero una tabla de velocidades medias mensuales por cada año.
End of explanation
tmp = wind.groupby(by = [wind.index.year, wind.index.month])
tmp = tmp.agg({'wspd': np.mean, 'wspd_max': 'max'})
tmp.reset_index(inplace = True)
tmp
tmp.pivot(index = 'level_1', columns = 'level_0')
tmp.pivot(index = 'level_1', columns = 'level_0').columns
Explanation: Pivotando usando varias columnas:
End of explanation
from collections import OrderedDict
table = OrderedDict((
    ("Item", ['Item0', 'Item0', 'Item0', 'Item1']),
    ('CType',['Gold', 'Bronze', 'Gold', 'Silver']),
    ('USD',  ['1$', '2$', '3$', '4$']),
    ('EU',   ['1€', '2€', '3€', '4€'])
))
df = pd.DataFrame(table)
df
Explanation: Qué pasa si en lo que combinamos encontramos índices repetidos. Por ejemplo:
End of explanation
pivoted = df.pivot(index='Item', columns='CType', values='USD')
Explanation: (fuente: https://nikolaygrozev.files.wordpress.com/2015/07/pivoting_simple_error.png)
End of explanation
table = OrderedDict((
    ("Item", ['Item0', 'Item0', 'Item0', 'Item1']),
    ('CType',['Gold', 'Bronze', 'Gold', 'Silver']),
    ('USD',  [1, 2, 3, 4]),
    ('EU',   [1.1, 2.2, 3.3, 4.4])
))
df = pd.DataFrame(table)
pivoted = df.pivot_table(index='Item', columns='CType', values='USD', aggfunc=np.min)
pivoted
Explanation: pivot_table al rescate para resolver el anterior error
El anterior error lo podemos resolver usando pivot_table que es un poco más flexible que pivot:
End of explanation
<END_TASK>