<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
Step2:  Perfiles de consumo del PVPC para clientes sin registro horario
Descarga de CSV's mensuales con los perfiles finales de consumo
En la web de REE están disponibles para descarga los perfiles finales de consumo, mediante ficheros CSV comprimidos para cada mes, publicados antes de que transcurran cinco días desde el final del mes de consumo al que se refieren. 
Las correcciones de los datos de demanda, que puedan producirse con posterioridad a la publicación de los perfiles de consumo, serán tenidas en cuenta únicamente a los efectos informativos que correspondan, sin afectar en ningún caso al cálculo de estos perfiles.
link
Step4:  Descarga de CSV's mensuales con los perfiles finales de consumo
Archivos CSV
Step5:  Descarga de perfiles horarios para un intervalo dado
Con objeto de calcular el precio medio ponderado de aplicación para dicho intervalo.
Step6:  Estimación de consumo horario a partir de consumo total en un intervalo
<ASSISTANT_TASK:>
Python Code:
%matplotlib inline
%config InlineBackend.figure_format = 'retina'
import datetime as dt
import matplotlib.pyplot as plt
import pandas as pd
import pytz
import requests
from urllib.error import HTTPError
# output color
from prettyprinting import *
tz = pytz.timezone('Europe/Madrid')
url_perfiles_2017 = 'http://www.ree.es/sites/default/files/01_ACTIVIDADES/Documentos/Documentacion-Simel/perfiles_iniciales_2017.xlsx'
def _gen_ts(mes, dia, hora, año):
    Generación de timestamp a partir de componentes de fecha. 
    Ojo al DST y cambios de hora.
    try:
        return dt.datetime(año, mes, dia, hora - 1) #, tzinfo=tz)
    except ValueError as e:
        print_err('Cambio de hora (día con 25h): "{}"; el 2017-{}-{}, hora={}'.format(e, mes, dia, hora))
        return dt.datetime(2017, mes, dia, hora - 2) #, tzinfo=tz)
def get_data_coeficientes_perfilado_2017(url_perfiles_2017):
    Extrae la información de las dos hojas del Excel proporcionado por REE 
    con los perfiles iniciales para 2017.
    # Coeficientes de perfilado y demanda de referencia (1ª hoja)
    cols_sheet1 = ['Mes', 'Día', 'Hora', 
                   'Pa,0m,d,h', 'Pb,0m,d,h', 'Pc,0m,d,h', 'Pd,0m,d,h',
                   'Demanda de Referencia 2017 (MW)']
    perfiles_2017 = pd.read_excel(url_perfiles_2017, header=None, 
                                  skiprows=[0, 1], names=cols_sheet1)
    perfiles_2017['ts'] = [_gen_ts(mes, dia, hora, 2017) 
                           for mes, dia, hora in zip(perfiles_2017.Mes,
                                                     perfiles_2017.Día, 
                                                     perfiles_2017.Hora)]
    # Coefs Alfa, Beta, Gamma (2ª hoja):
    coefs_alpha_beta_gamma = pd.read_excel(url_perfiles_2017, sheetname=1)
    return perfiles_2017.set_index('ts'), coefs_alpha_beta_gamma
# Extracción:
perf_demref_2017, coefs_abg = get_data_coeficientes_perfilado_2017(url_perfiles_2017)
print_info(coefs_abg)
perf_demref_2017.head()
# Conversión de formato de dataframe de perfiles 2017 a finales (para uniformizar):
cols_usar = ['Pa,0m,d,h', 'Pb,0m,d,h', 'Pc,0m,d,h', 'Pd,0m,d,h']
perfiles_2017 = perf_demref_2017[cols_usar].copy()
perfiles_2017.columns = ['COEF. PERFIL {}'.format(p) for p in 'ABCD']
perfiles_2017.head()
Explanation: Perfiles de consumo del PVPC para clientes sin registro horario
Descarga de CSV's mensuales con los perfiles finales de consumo
En la web de REE están disponibles para descarga los perfiles finales de consumo, mediante ficheros CSV comprimidos para cada mes, publicados antes de que transcurran cinco días desde el final del mes de consumo al que se refieren. 
Las correcciones de los datos de demanda, que puedan producirse con posterioridad a la publicación de los perfiles de consumo, serán tenidas en cuenta únicamente a los efectos informativos que correspondan, sin afectar en ningún caso al cálculo de estos perfiles.
link: http://www.ree.es/es/actividades/operacion-del-sistema-electrico/medidas-electricas
Para el año 2017, se suministran los coeficientes y demanda de referencia para calcular los perfiles iniciales. 
PDF con la última resolución con la demanda de referencia: Resolución de 28 de diciembre de 2016 de la Dirección General de Política Energética y Minas (PDF, 2,37 MB)
Fichero excel con coeficientes para los perfiles iniciales para 2017:
Establecidos en la resolución anteriormente indicada, disponibles en formato Excel para su consulta en Demanda de referencia y perfiles iniciales para el año 2017 (XLSX, 705 KB)
End of explanation
def get_data_perfiles_finales_mes(año, mes=None):
    Lee el fichero CSV comprimido con los perfiles finales de consumo eléctrico para
    el mes dado desde la web de REE. Desecha columnas de fecha e información de DST.
    
    Introduce (:int: año, :int: mes) o (:datetime_obj: ts)
    
    mask_ts = 'http://www.ree.es/sites/default/files/simel/perff/PERFF_{:%Y%m}.gz'
    if (type(año) is int) and (mes is not None):
        ts = dt.datetime(año, mes, 1, 0, 0)
    else:
        ts = año
    url_perfiles_finales = mask_ts.format(ts)
    print_info('Descargando perfiles finales del mes de {:%b de %Y} en {}'
               .format(ts, url_perfiles_finales))
    # Intenta descargar perfiles finales, y si falla, recurre a los estimados para 2017:
    try:
        perfiles_finales = pd.read_csv(url_perfiles_finales, sep=';',
                                           encoding='latin_1', compression='gzip'
                                          ).dropna(how='all', axis=1)
    except HTTPError as e:
        print_warn('HTTPError: {}. Se utilizan perfiles estimados de 2017.'.format(e))
        return perfiles_2017[(perfiles_2017.index.year == ts.year) 
                             & (perfiles_2017.index.month == ts.month)]
        
    cols_date = ['MES', 'DIA', 'HORA', 'AÑO']
    zip_date = zip(*[perfiles_finales[c] for c in cols_date])
    perfiles_finales['ts'] = [_gen_ts(*args) for args in zip_date]
    cols_date.append('VERANO(1)/INVIERNO(0)')
    # perfiles_finales['dst'] = perfiles_finales['VERANO(1)/INVIERNO(0)'].astype(bool)
    return perfiles_finales.set_index('ts').drop(cols_date, axis=1)
perfiles_finales_2016_11 = get_data_perfiles_finales_mes(2016, 11)
print_ok(perfiles_finales_2016_11.head())
perfiles_2017_02 = get_data_perfiles_finales_mes(2017, 2)
perfiles_2017_02.head()
Explanation: Descarga de CSV's mensuales con los perfiles finales de consumo
Archivos CSV: 'http://www.ree.es/sites/default/files/simel/perff/PERFF_{año}{mes}.gz'
End of explanation
def extract_perfiles_intervalo(t0, tf):
    t_ini = pd.Timestamp(t0)
    t_fin = pd.Timestamp(tf)
    assert(t_fin > t_ini)
    marca_fin = '{:%Y%m}'.format(t_fin)
    marca_ini = '{:%Y%m}'.format(t_ini)
    if marca_ini == marca_fin:
        perfiles = get_data_perfiles_finales_mes(t_ini)
    else:
        dates = pd.DatetimeIndex(start=t_ini.replace(day=1), 
                                 end=t_fin.replace(day=1), freq='MS')
        perfiles = pd.concat([get_data_perfiles_finales_mes(t) for t in dates])
    return perfiles.loc[t_ini:t_fin].iloc[:-1]
Explanation: Descarga de perfiles horarios para un intervalo dado
Con objeto de calcular el precio medio ponderado de aplicación para dicho intervalo.
End of explanation
# Ejemplo de generación de valores de consumo horario a partir de consumo total y perfiles de uso:
t0, tf = '2016-10-31', '2017-01-24'
consumo_total_interv_kWh = 836.916
print_secc('Consumo horario estimado para el intervalo {} -> {}, con E={:.3f} kWh'
           .format(t0, tf, consumo_total_interv_kWh))
# perfiles finales:
perfs_interv = extract_perfiles_intervalo(t0, tf)
print_ok(perfs_interv.head())
print_ok(perfs_interv.tail())
# Estimación con perfil A:
suma_perfiles_interv = perfs_interv['COEF. PERFIL A'].sum()
mch_pa = perfs_interv['COEF. PERFIL A'] * consumo_total_interv_kWh / suma_perfiles_interv
consumo_diario_est = mch_pa.groupby(pd.TimeGrouper('D')).sum()
print_red('CHECK CONSUMO TOTAL: {:.3f} == {:.3f} == {:.3f} kWh'
          .format(consumo_total_interv_kWh, consumo_diario_est.sum(), mch_pa.sum()))
# Plot del consumo diario estimado en el intervalo:
print_secc('Consumo horario diario estimado:')
ax = consumo_diario_est.plot(figsize=(16, 9), color='blue', lw=2)
params_lines = dict(lw=1, linestyle=':', alpha=.6)
xlim = consumo_diario_est[0], consumo_diario_est.index[-1]
ax.hlines([consumo_diario_est.mean()], *xlim, color='orange', **params_lines)
ax.hlines([consumo_diario_est.max()], *xlim, color='red', **params_lines)
ax.hlines([consumo_diario_est.min()], *xlim, color='green', **params_lines)
ax.set_title('Consumo diario estimado (Total={:.1f} kWh)'.format(consumo_total_interv_kWh))
ax.set_ylabel('kWh/día')
ax.set_xlabel('')
ax.set_ylim((0, consumo_diario_est.max() * 1.1))
ax.grid('on', axis='x');
# Copia a otro notebook:
pd.DataFrame(mch_pa.rename('kWh')).to_clipboard()
# Consumo medio por día de la semana (patrón semanal de consumo):
media_diaria = mch_pa.groupby(pd.TimeGrouper('D')).sum()
media_semanal = media_diaria.groupby(lambda x: x.weekday).mean().round(1)
días_semana = ['Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo']
media_semanal.columns = días_semana
print_ok(media_semanal)
ax = media_semanal.T.plot(kind='bar', figsize=(16, 9), color='orange', legend=False)
ax.set_xticklabels(días_semana, rotation=0)
ax.set_title('Patrón semanal de consumo')
ax.set_ylabel('kWh/día')
ax.grid('on', axis='y')
ax.hlines([media_diaria.mean()], -1, 7, lw=3, color='blue', linestyle=':');
# Comprobación de perfiles al cabo del año:
perfiles_2016 = extract_perfiles_intervalo('2016-01-01', '2016-12-31')
print_ok(perfiles_2016.sum())
perfiles_2017.sum()
Explanation: Estimación de consumo horario a partir de consumo total en un intervalo
End of explanation
<END_TASK>