Exemplo n.º 1
0
def day_clear_sky_index(day_data, **kargs):
    """
    -> float
    
    Calcula el índice de claridad del día (radiación global) respecto a la
    radiación extraterrestre.
    
    :param DataFrame day_data:
        resgistro temporal de la radiación en el día.
    """

    # obtener radiación total en el día
    data_sum = sum(day_data.values)

    # lista de timestamps en el registro
    date_format = '%d-%m-%Y %H:%M'
    date = day_data.name
    timestamps = [date + ' ' + h for h in day_data.index]

    # calcular radiación extraterrestre
    secs = get_timestep(timestamps, date_format)

    ext_rad = [ext_irradiation(t, secs, **kargs) for t in timestamps]
    ext_sum = sum(ext_rad)

    # retornar cuociente
    return data_sum / ext_sum if ext_sum != 0.0 else 0.0
Exemplo n.º 2
0
def clearsky_variability(database,
                         timestamp,
                         timesteps,
                         side='backward',
                         **kargs):
    """
    -> float
    
    Calcula la desviacion estandar del clearsky index dentro del periodo
    especificado.
    
    :param DataFrame database:
        base de datos que contenga el resgistro temporal de la radiación.
    :param str timestamp:
        string que contiene la hora y fecha del comienzo del periodo (UTC).
    :param int timesteps:
        cantidad de puntos/timesteps a considerar en el periodo.
    :param str side: ('backward' or 'forward')
        define si el timestamp corresponde al comienzo o al fin del periodo.
        
    :returns:
        (float) desviacion estandar del clearsky index en el periodo.   
    """

    # -------------------------------------------------------------------------
    # obtener indice del timestamp en la base de datos
    timestamp = validate_date(timestamp)
    idx = get_date_index(database['Timestamp'], timestamp)

    assert (side == 'backward') or (side == 'forward')

    # definir indices del periodo
    if side == 'backward':
        data_index = np.arange((idx - timesteps), idx)
    else:
        data_index = np.arange(idx, (idx + timesteps))

    # obtener radiacion global en el periodo
    timestamps = database.loc[data_index, 'Timestamp'].values
    global_rad = database.loc[data_index, 'Global'].values

    # -------------------------------------------------------------------------
    # calcular clearsky index dentro del periodo
    date_format = '%d-%m-%Y %H:%M'
    secs = get_timestep(database['Timestamp'], date_format)

    # calcular radiacion extraterrestre
    ext_rad = [ext_irradiation(t, secs, **kargs) for t in timestamps]
    # calcular clearsky index
    clearsky = np.divide(global_rad,
                         ext_rad,
                         np.zeros_like(global_rad),
                         where=ext_rad != 0.0)
    clearsky[np.isinf(clearsky)] = 0.0

    # obtener desviacion estandar
    v = np.std(np.diff(clearsky))

    return v
Exemplo n.º 3
0
def align_radiation(database, clear_sky_days, **kargs ):
    """
    -> DataFrame
    
    Ajusta los timestamps en la base de datos tal que el perfil de radiación
    global se alinie con el de la radiación extraterrestre.
    
    :param DataFrame database:
        base de datos que contiene el registro temporal a procesar.
    :param list(str) clear_sky_days:
        lista de días en el dataset con una alto índice de claridad, en formato
        %d-%m-%Y.
    
    :returns:
        DataFrame con los timestamps modificados. 
    """
    
    date_format = '%d-%m-%Y %H:%M'
    timestamps = database['Timestamp'].values
    
    diff = []
    
    for day in clear_sky_days:
        
        # obtener ventana de datos correspondiente ----------------------------
        start_index = get_date_index(timestamps, day)
        
        next_day = datetime.strptime( validate_date(day), date_format )
        next_day = datetime.strftime( next_day + timedelta(days=1), date_format)
        stop_index = get_date_index( timestamps, next_day )
        
        day_times = timestamps[start_index:stop_index]
        
        # alinear máximos -----------------------------------------------------
        ext_rad = [ext_irradiance(t, **kargs) for t in day_times]
        ext_index = ext_rad.index( max(ext_rad) )
        try:
            rad_data = list(database['Global'].values[start_index:stop_index])
        except KeyError:
            rad_data = list(database['Potencia'].values[start_index:stop_index])
            
        rad_index = rad_data.index( max(rad_data) )
        
        # calcular diferencia entre máximos
        diff.append( ext_index - rad_index )
    
    # calular ajuste en segundos ----------------------------------------------
    timestep = get_timestep(database['Timestamp'], date_format)
    delay = round(sum(diff)/len(diff))*timestep
    print(delay)
    # modificar timestamps
    new_timestamps = [datetime.strftime( datetime.strptime(t, date_format)
                     + timedelta(seconds=delay), date_format ) for t in timestamps]
    
    # retornar base de datos modificada
    db = database
    db['Timestamp'] = new_timestamps
    return db
Exemplo n.º 4
0
def compact_database(database, factor, use_average=False):
    """
    -> DataFrame
    
    Comprime la base de tiempo del set de datos sumando o ponderando los datos
    correspondientes al nuevo intervalo definido.
    
    :param DataFrame database:
        base de datos que contiene el registro temporal a procesar.
    :param int factor:
        factor por el cual se comprimirá la base de datos.
    :param bool use_average:
        permite decidir si sumar o ponderar los datos al comprimir el dataframe.
    """
    
    print('\n' + '-'*80)
    print('compacting data time series')
    print('-'*80 + '\n')
    sleep(0.25)
    
    # -------------------------------------------------------------------------
    # obtener base de tiempo de dataset
    date_format = '%d-%m-%Y %H:%M'
    timestep = get_timestep(database['Timestamp'], date_format)
    
    # -------------------------------------------------------------------------
    # compactar dataframe
    colnames = database.columns.values
    df = pd.DataFrame(0.0, index=range( ceil(len(database.index)/factor) ),
                      columns=colnames)
    df = df.astype({u'Timestamp': str})

    # obtener fecha inicial
    date_start = datetime.strptime(database.at[0, u'Timestamp'], date_format)
    next_date = date_start + timedelta(seconds = factor*timestep)
    
    df.at[0, u'Timestamp'] = datetime.strftime(date_start, date_format)
    
    # peso ponderador
    weight = 1.0/factor if use_average else 1.0
    
    bar = ProgressBar()
    for i in bar( database.index ):
        # obtener fecha
        date = datetime.strptime(database.at[i, u'Timestamp'], date_format)
        
        # si se sale del intervalo actual
        if date >= next_date:
            # añadir timestamp al nuevo dataframe
            df.at[i//factor, 'Timestamp'] = datetime.strftime(next_date, date_format)
            next_date = next_date + timedelta(seconds = factor*timestep)
        
        # sumar valores a fila correspondiente
        for c in colnames[1:]:
                df.at[i//factor, c] += database.at[i, c]*weight
    
    return df
Exemplo n.º 5
0
def correct_daylight_saving(database, start_date, end_date, positive=True):
    """
    -> DataFrame
    
    Ajusta los timestamps en la base de datos corrigiendo el periodo de cambio
    de hora por Daylight Saving Time entre date_start y date_end.
    
    :param DataFrame database:
        base de datos que contiene el registro temporal a procesar.
    :param str date_start:
        fecha y hora en la que comienza el DST, %d-%m-%Y %H:%M.
    :param str date_start:
        fecha y hora en la que termina el DST, %d-%m-%Y %H:%M. 
    
    :returns:
        DataFrame con los timestamps modificados. 
    """
    
    print('\n' + '-'*80)
    print('correcting daylight saving time')
    print('-'*80 + '\n')
    sleep(0.25)
    
    # parsing de fechas -------------------------------------------------------
    date_format = '%d-%m-%Y %H:%M'
    start_date = datetime.strptime( validate_date(start_date), date_format )
    end_date = datetime.strptime( validate_date(end_date), date_format )
    
    # procesamiento -----------------------------------------------------------
    db = database.copy()
    
    # obtner timestep
    timestep = get_timestep(database['Timestamp'], date_format)
    
    delta = (3600.0/timestep)
    delta = delta if positive else -delta
    
    # procesar
    bar = ProgressBar()
    for i in bar( db.index ):
        # obtener timestamp
        timestamp = datetime.strptime(db.at[i, 'Timestamp'], date_format)
        
        # si está en el periodo del DST
        if (timestamp >= start_date) and (timestamp <= end_date):
            try:
                db.iloc[i, 1:] = database.iloc[int(i - delta), 1:]
            except IndexError:
                continue
            
            
    # retornar base de datos
    return db
        
#------------------------------------------------------------------------------  
Exemplo n.º 6
0
def radiance_to_radiation(database):
    """
    Transforma la base de datos de radiancia (W/m2) a de radiación (Wh/m2).
    
    :param DataFrame database:
        base de datos que contiene el registro de irradiancia a procesar.
        
    :returns:
        DataFrame con los datos procesados.
    """
    
    db = database.copy()
    # obtener timestep en el dataset
    date_format = '%d-%m-%Y %H:%M'
    secs = get_timestep(db['Timestamp'], date_format)/3600
    
    db['Global'] = [ rad*secs for rad in db['Global'].values]
    db['Diffuse'] = [ rad*secs for rad in db['Diffuse'].values]
    db['Direct'] = [ rad*secs for rad in db['Direct'].values]
    
    return db

#------------------------------------------------------------------------------
Exemplo n.º 7
0
def reshape_by_day(database, colname, initial_date, final_date):
    """
    -> DataFrame
    
    Reordena el registro temporal de la base de datos separando cada día en una
    columna, siguiendo la base de tiempo indicada.
    
    :param DataFrame database:
        base de datos que contiene el registro temporal a procesar.
    :param str colname:
        nombre de la columna que contiene los datos de interés.
    :param str initial_date:
        fecha y hora desde la cual considerar los datos.
    :param str final_date:
        fecha y hora hasta la cual considerar los datos (sin incluir).
        
          
    :returns: DataFrame de la base de datos procesada
    """
    print('\n' + '-'*80)
    print('reshaping data time series')
    print('-'*80 + '\n')
    sleep(0.25)
    
    # inicializar nueva base de datos -----------------------------------------
    date_format = '%d-%m-%Y %H:%M'
    
    initial_date = datetime.strptime(validate_date(initial_date), date_format)
    final_date = datetime.strptime(validate_date(final_date), date_format)
    
    assert final_date > initial_date
    
    # columnas
    delta_days = final_date - initial_date
    num_days = delta_days.days
    dates = [initial_date + timedelta(days=x) for x in range(num_days)]
    cols = [datetime.strftime(d, '%d-%m-%Y') for d in dates]
    
    
    # filas
    timestep = get_timestep(database['Timestamp'], date_format)
    num_hours = int( 24*(3600/timestep) )
    
    initial_hour = datetime.strptime('00:00','%H:%M')
    hours = [initial_hour + timedelta(seconds=timestep*x) for x in range(num_hours)]
    rows = [datetime.strftime(h, '%H:%M') for h in hours]
    
    # obtener diferencia en segundos
    first_hour = datetime.strptime(database.at[0,'Timestamp'], date_format)
    first_hour = datetime.strftime(first_hour, '%H:%M')
    first_hour = datetime.strptime(first_hour, '%H:%M')
    
    closest_hour = min(hours, key=lambda h: abs( first_hour - h ))
    delta_sec = (closest_hour - first_hour).seconds
    delta_sec = (delta_sec - 24*3600) if delta_sec > timestep else delta_sec
    
    # DataFrame
    df = pd.DataFrame(0.0, index = rows, columns= cols)
    
    # colocar datos de radiación en el nuevo DataFrame
    bar = ProgressBar()
    for i in bar( database.index ):
        try:
            timestamp = datetime.strptime( database.at[i, 'Timestamp'], date_format)
            
            # aplicar corrección de desfase
            timestamp += timedelta(seconds=delta_sec)
            
            if (timestamp >= initial_date) and (timestamp < final_date):
                date = datetime.strftime(timestamp, '%d-%m-%Y')
                hour = datetime.strftime(timestamp, '%H:%M')

                df.at[hour, date] = database.at[i, colname]
            
        except (ValueError, TypeError):
            continue
    
    # retornar database    
    return df
Exemplo n.º 8
0
def plot_power_irradiance(db_pv, db_solar, start_date, stop_date):
    """
    -> None
    
    Plotea el gráfico de potencia PV vs irradiancia global.
    
    :param DataFrame db_pv:
        base de datos que contiene el registro de 'Potencia' fotovoltaica.
    :param DataFrame db_solar:
        base de datos que contiene el registro de irradiancia 'Global'.
        
    :return:
        None
    """
    # -------------------------------------------------------------------------
    # verificar bases de datos
    assert ('Timestamp' in db_pv.columns) and ('Sistema' in db_pv.columns)
    assert ('Timestamp' in db_solar.columns) and ('Global' in db_solar.columns)

    # verificar que los timesteps se correspondan
    date_format = '%d-%m-%Y %H:%M'

    timestep_pv = get_timestep(db_pv[u'Timestamp'], date_format)

    timestep_solar = get_timestep(db_solar[u'Timestamp'], date_format)

    assert timestep_solar == timestep_pv

    # -------------------------------------------------------------------------
    # obtener indices
    start_date = datetime.strptime(validate_date(start_date), date_format)
    stop_date = datetime.strptime(validate_date(stop_date), date_format)

    # photovoltaic
    pv_index = [-1, -1]
    for i in db_pv.index:
        date = datetime.strptime(db_pv.at[i, u'Timestamp'], date_format)

        if (date >= start_date) and (pv_index[0] == -1):
            pv_index[0] = i

        if (date >= stop_date) and (pv_index[1] == -1):
            pv_index[1] = i - 1

    # solarimetric
    solar_index = [-1, -1]
    for i in db_solar.index:
        date = datetime.strptime(db_solar.at[i, u'Timestamp'], date_format)

        if (date >= start_date) and (solar_index[0] == -1):
            solar_index[0] = i

        if (date >= stop_date) and (solar_index[1] == -1):
            solar_index[1] = i - 1

    assert (solar_index[1] - solar_index[0]) == (pv_index[1] - pv_index[0])

    # -------------------------------------------------------------------------
    # obtener datos a plotear
    global_rad = db_solar['Global']
    global_rad = global_rad.values[solar_index[0]:solar_index[1]]

    pv_power = db_pv['Sistema']
    pv_power = pv_power.values[pv_index[0]:pv_index[1]]

    timestamp = db_solar['Timestamp'].values[solar_index[0]:solar_index[1]]

    # obtener colores
    cmap = cm.get_cmap('plasma')
    colors = []
    for t in timestamp:
        # obtener minuto del día
        date = datetime.strptime(t, date_format)
        date_tt = date.timetuple()
        min_day = date_tt.tm_hour * 60.0 + date_tt.tm_min

        t_x = 1 - min_day / (24 * 60.0)
        # asignar color
        colors.append(cmap(t_x))

    # plotear
    fig = plt.figure()
    fig.set_size_inches(6, 3)

    plt.style.use(['seaborn-white', 'seaborn-paper'])
    matplotlib.rc('font', family='Times New Roman')

    plt.scatter(global_rad, pv_power, c=colors, s=0.8)

    plt.xlabel(u'Irradiancia global, W/m2')
    plt.ylabel(u'Potencia sistema, kW')
    plt.xlim([0.01, 1200])
    plt.tight_layout()

    return None
Exemplo n.º 9
0
def plot_performance_ratio(db_pv, db_solar, start_date, stop_date, **kargs):
    """
    -> None
     Plotea el gráfico de performance ratio vs claridad a partir de la base de
     datos entregada.
    
    :param DataFrame db_pv:
        base de datos que contiene el registro de 'Potencia' fotovoltaica.
    :param DataFrame db_solar:
        base de datos que contiene el registro de irradiancia 'Global'.
        
    :return:
        None
    """

    # -------------------------------------------------------------------------
    # verificar bases de datos
    assert ('Timestamp' in db_pv.columns) and ('Sistema' in db_pv.columns)
    assert ('Timestamp' in db_solar.columns) and ('Global' in db_solar.columns)

    # verificar que los timesteps se correspondan
    date_format = '%d-%m-%Y %H:%M'
    timestep_pv = get_timestep(db_pv[u'Timestamp'], date_format)

    timestep_solar = get_timestep(db_solar[u'Timestamp'], date_format)

    assert timestep_solar == timestep_pv

    # -------------------------------------------------------------------------
    # obtener indices
    start_date = datetime.strptime(validate_date(start_date), date_format)
    stop_date = datetime.strptime(validate_date(stop_date), date_format)

    # photovoltaic
    pv_index = [-1, -1]
    for i in db_pv.index:
        date = datetime.strptime(db_pv.at[i, u'Timestamp'], date_format)

        if (date >= start_date) and (pv_index[0] == -1):
            pv_index[0] = i

        if (date >= stop_date) and (pv_index[1] == -1):
            pv_index[1] = i - 1

    # solarimetric
    solar_index = [-1, -1]
    for i in db_solar.index:
        date = datetime.strptime(db_solar.at[i, u'Timestamp'], date_format)

        if (date >= start_date) and (solar_index[0] == -1):
            solar_index[0] = i

        if (date >= stop_date) and (solar_index[1] == -1):
            solar_index[1] = i - 1

    assert (solar_index[1] - solar_index[0]) == (pv_index[1] - pv_index[0])

    # -------------------------------------------------------------------------

    # obtener performance ratio
    global_rad = db_solar['Global']
    global_rad = global_rad.values[solar_index[0]:solar_index[1]]

    pv_power = db_pv['Sistema']
    pv_power = pv_power.values[pv_index[0]:pv_index[1]]

    plant_factor = 1000.0 / 16.2
    performance_ratio = []
    for i in range(len(pv_power)):
        if (global_rad[i] > 2.0):
            performance_ratio.append(plant_factor *
                                     (pv_power[i] / global_rad[i]))
        else:
            performance_ratio.append(0.0)

    performance_ratio = np.array(performance_ratio)

    # obtener claridad
    timestamp = db_solar['Timestamp'].values[solar_index[0]:solar_index[1]]
    ext_rad = [ext_irradiance(t, **kargs) for t in timestamp]

    claridad = []
    for i in range(len(pv_power)):
        if (ext_rad[i] > 2.0):
            claridad.append(global_rad[i] / ext_rad[i])
        else:
            claridad.append(0.0)

    claridad = np.array(claridad)

    # obtener colores
    cmap = cm.get_cmap('plasma')
    colors = []
    for t in timestamp:
        # obtener minuto del día
        date = datetime.strptime(t, date_format)
        date_tt = date.timetuple()
        min_day = date_tt.tm_hour * 60.0 + date_tt.tm_min

        t_x = 1 - min_day / (24 * 60.0)
        # asignar color
        colors.append(cmap(t_x))

    # plotear
    fig = plt.figure()
    fig.set_size_inches(6, 3)

    plt.style.use(['seaborn-white', 'seaborn-paper'])
    matplotlib.rc('font', family='Times New Roman')

    plt.scatter(claridad, performance_ratio, c=colors, s=0.8)

    plt.xlabel(u'Índice de claridad')
    plt.ylabel(u'Performance ratio')
    plt.xlim([0, 1.0])
    plt.ylim([0, 1.0])

    return None
Exemplo n.º 10
0
def plot_1D_radiation_data(database,
                           colname,
                           start_date,
                           stop_date,
                           extraRad=True,
                           scale_factor=1.0,
                           **kargs):
    """
    -> None
    Plotea el gráfico temporal 1D de la radiación en el tiempo. Donde el eje X
    corresponde al tiempo y el eje Y a la intensidad de la radiación.
    
    :param DataFrame database:
        base de datos que contiene el registro de radiación en el tiempo.
    :param str colname:
        nombre de la columna a graficar.
    :param str start_date:
        fecha desde la cual empezar el plot.
    :param str stop_date:
        fecha en que termina el plot.
    :param bool extraRad:
        si incluir en el plot la radiación extraterreste.
    :param float scale_factor:
        si se desea escalar los datos en algún factor.
        
    :return:
        None
    """

    # obtener limites del plot ------------------------------------------------
    tmstmp = database['Timestamp'].values
    date_format = '%d-%m-%Y %H:%M'

    start_date = datetime.strptime(validate_date(start_date), date_format)
    stop_date = datetime.strptime(validate_date(stop_date), date_format)

    start_index = get_date_index(tmstmp, start_date, nearest=True)
    stop_index = get_date_index(tmstmp, stop_date, nearest=True)

    if stop_index <= start_index:
        print('InputError: las fechas ingresadas no permiten generar un plot.')
        return None

    # plotear -----------------------------------------------------------------
    Y = database[colname][start_index:stop_index]
    timestamps = tmstmp[start_index:stop_index]
    X = range(len(timestamps))

    fig = plt.figure()
    fig.set_size_inches(6, 2.5)

    plt.style.use(['seaborn-white', 'seaborn-paper'])
    matplotlib.rc('font', family='Times New Roman')

    plt.plot(X,
             Y * scale_factor,
             c='k',
             ls='-',
             lw=0.8,
             label='Global en plano horizontal')

    # añadir readiación extraterrestre ----------------------------------------
    if extraRad:
        secs = get_timestep(timestamps, date_format)

        ext_rad = [ext_irradiance(t, **kargs) for t in timestamps]
        plt.plot(X, ext_rad, c='k', ls='--', lw=0.8, label='Extraterrestre')

    # colocar etiquetas en el gráfico -----------------------------------------
    plt.axvspan(0, len(timestamps), facecolor='white', alpha=1.0)

    plt.xlim([0, len(timestamps) - 1])
    plt.xticks([])
    plt.ylabel('Irradiancia solar, W/m2')
    plt.legend(loc='upper left')

    #plt.legend(loc='best')

    title = tmstmp[start_index] + ' - ' + tmstmp[stop_index]
    plt.title(title)
    plt.tight_layout()
    return None
Exemplo n.º 11
0
def forecast_error_evaluation(datasets,
                              output_name,
                              model,
                              data_leap,
                              cluster_labels=[],
                              img_sequence=None,
                              plot_results=True,
                              random_state=0,
                              save_path=None):
    """
    -> DataFrame
    
    retorna métricas respecto al error del modelo de forecast en base a su
    desempeño sobre el dataset entregado.
    
    :param list(DataFrame) datasets:
        lista que contiene los datasets con los atributos correspondientes a
        los inputs del model de pronóstico.
    :param str output_name:
        nombre de la columna que contiene los datos del set Y.
    :param keras.model model:
        modelo de forecasting a evaluar.
    :param int data_leap:
        define el intervalo de tiempo entre cada pronóstico a realizar.
    :param list or array_like cluster_labels:
        contiene la etiqueta que identifica el cluster da cada día en el dataset.
    :param int img_sequence: (default None)
        indice del dataset que consiste en una sequencia de imagenes.
    :param bool plot_results:
        determina si se muestran los gráficos de la evaluación.
    :param int random_state:
        permite definir el random_state en la evaluación.
    :param str save_path:
        ubicación del directorio en donde guardar los resultados.
        
    :returns:
        DataFrame
    """

    random.seed(random_state)

    # obtener lista de días
    system_ds = datasets[0]

    date_format = '%d-%m-%Y %H:%M'
    timestamps = system_ds['Timestamp'].values

    timestep = get_timestep(system_ds['Timestamp'], date_format)

    initial_date = datetime.strptime(timestamps[0], date_format)
    final_date = datetime.strptime(timestamps[-1], date_format)

    dates = pd.date_range(initial_date, final_date, freq='1D')
    dates = dates.strftime('%d-%m-%Y')

    # -------------------------------------------------------------------------
    # evaluar modelo
    print('\n' + '-' * 80)
    print('cluster evaluation summary')
    print('-' * 80 + '\n')

    try:
        n_input = int(model.input.shape[1])
    except AttributeError:
        n_input = int(model.input[0].shape[1])
    n_output = int(model.output.shape[1])

    # checkear cluster_labels
    if cluster_labels is None:
        cluster_labels = np.zeros([1, dates.size]).flatten()
        num_labels = np.max(cluster_labels) + 1

    num_labels = np.max(cluster_labels) + 1

    # inicializar metrics dataframe
    cols = []

    horizons = [
        str((h + 1) * timestep / 60.0) + ' min' for h in range(n_output)
    ]
    metrics = ['mbe', 'mae', 'rmse', 'fs', 'std', 'skw', 'kts']
    for m in metrics:
        cols += [m + ' ' + h for h in horizons]

    eval_metrics = pd.DataFrame(index=np.arange(num_labels), columns=cols)

    # para cada etiqueta resultante del clustering
    for label in np.arange(num_labels):
        # obtener fechas correspondientes a la etiqueta
        cluster_dates = dates[cluster_labels == label]

        # inicializar datos cluster
        cluster_data = []
        cluster_pred = []
        cluster_pers = []
        cluster_var = []

        # por cada una de las fechas del cluster
        for date in cluster_dates:
            # obtener forecasting_times de testing
            timeleap = timestep * data_leap

            initial_hour = datetime.strptime(date, '%d-%m-%Y')
            hours = [
                initial_hour + timedelta(seconds=timeleap * i)
                for i in range(int(24 * 3600 / timeleap))
            ]
            pred_times = [datetime.strftime(h, date_format) for h in hours]

            # calcular predicción en cada una de las horas
            for pred_time in pred_times:
                try:
                    # prediccion del modelo
                    Y_true, Y_pred = forecast_pred(datasets,
                                                   output_name,
                                                   model,
                                                   pred_time,
                                                   img_sequence=img_sequence,
                                                   verbose=False)

                    # prediccion del persistence model
                    Y_pers = beauchef_pers_predict(system_ds, pred_time,
                                                   n_output)

                    # clearsky variability
                    cs_var = clearsky_variability(system_ds, pred_time,
                                                  n_input)

                    # print progress
                    print('\revaluating cluster ' + str(int(label)) + ': ' +
                          pred_time,
                          end='')

                except TypeError:
                    continue

                # agregar datos a cluster data
                cluster_data.append(Y_true)
                cluster_pred.append(Y_pred)
                cluster_pers.append(Y_pers)
                cluster_var.append(cs_var)

        # calcular metricas del cluster
        Y_true = np.concatenate(cluster_data, axis=1)
        Y_pred = np.concatenate(cluster_pred, axis=1)
        Y_pers = np.concatenate(cluster_pers, axis=1)
        cs_var = np.array(cluster_var)

        # por cada horizonte de pronóstico
        for i, h in enumerate(horizons):
            eval_metrics.at[label, 'mbe ' + h] = mean_bias_error(
                Y_true[i, :], Y_pred[i, :])
            eval_metrics.at[label, 'mae ' + h] = mean_absolute_error(
                Y_true[i, :], Y_pred[i, :])
            eval_metrics.at[label, 'rmse ' + h] = np.sqrt(
                mean_squared_error(Y_true[i, :], Y_pred[i, :]))
            eval_metrics.at[label, 'fs ' + h] = forecast_skill(
                Y_true[i, :], Y_pred[i, :], Y_pers[i, :])
            eval_metrics.at[label,
                            'skw ' + h] = skew_error(Y_true[i, :],
                                                     Y_pred[i, :])
            eval_metrics.at[label, 'kts ' + h] = kurtosis_error(
                Y_true[i, :], Y_pred[i, :])

        # plot distribución de error
        plot_error_dist(Y_true,
                        Y_pred,
                        Y_pers,
                        horizons,
                        bins=40,
                        log=True,
                        range=(-0.5, 0.5))
        plot_error_variability(Y_true, Y_pred, cs_var, horizons, s=0.08)

    return eval_metrics
Exemplo n.º 12
0
def forecast_model_evaluation(datasets,
                              output_name,
                              model,
                              data_leap,
                              cluster_labels=None,
                              img_sequence=None,
                              plot_results=True,
                              random_state=0,
                              save_path=None):
    """
    -> DataFrame
    
    retorna métricas de evaluación del modelo de forecast entregado en base a
    su desempeño en el dataset entregado.
    
    :param list(DataFrame) datasets:
        lista que contiene los datasets con los atributos correspondientes a
        los inputs del model de pronóstico.
    :param str output_name:
        nombre de la columna que contiene los datos del set Y.
    :param keras.model model:
        modelo de forecasting a evaluar.
    :param int data_leap:
        define el intervalo de tiempo entre cada pronóstico a realizar.
    :param list or array_like cluster_labels:
        contiene la etiqueta que identifica el cluster da cada día en el dataset.
    :param int img_sequence: (default None)
        indice del dataset que consiste en una sequencia de imagenes.
    :param bool plot_results:
        determina si se muestran los gráficos de la evaluación.
    :param int random_state:
        permite definir el random_state en la evaluación.
    :param str save_path:
        ubicación del directorio en donde guardar los resultados.
        
    :returns:
        DataFrame
    """

    random.seed(random_state)

    # obtener lista de días
    system_ds = datasets[0]

    date_format = '%d-%m-%Y %H:%M'
    timestamps = system_ds['Timestamp'].values

    timestep = get_timestep(system_ds['Timestamp'], date_format)

    initial_date = datetime.strptime(timestamps[0], date_format)
    final_date = datetime.strptime(timestamps[-1], date_format)

    dates = pd.date_range(initial_date, final_date, freq='1D')
    dates = dates.strftime('%d-%m-%Y')

    # -------------------------------------------------------------------------
    # evaluar modelo
    print('\n' + '-' * 80)
    print('cluster evaluation summary')
    print('-' * 80 + '\n')

    n_output = int(model.output.shape[1])

    # checkear cluster_labels
    if cluster_labels is None:
        cluster_labels = np.zeros([1, dates.size]).flatten()
        num_labels = np.max(cluster_labels) + 1

    num_labels = np.max(cluster_labels) + 1

    # inicializar cluster_metrics
    metrics = ['mbe', 'mae', 'rmse', 'fs', 'std', 'skw', 'kts']
    eval_metrics = pd.DataFrame(index=np.arange(num_labels), columns=metrics)

    # para cada etiqueta resultante del clustering
    for label in np.arange(num_labels):
        # obtener fechas correspondientes a la etiqueta
        cluster_dates = dates[cluster_labels == label]

        # escoger una fecha de muestra al azar
        cluster_sample = random.choice(list(cluster_dates))

        # inicializar datos cluster
        cluster_data = []
        cluster_pred = []
        cluster_pers = []
        cluster_time = []

        # por cada una de las fechas del cluster
        for date in cluster_dates:
            # obtener forecasting_times de testing
            timeleap = timestep * data_leap

            initial_hour = datetime.strptime(date, '%d-%m-%Y')
            hours = [
                initial_hour + timedelta(seconds=timeleap * i)
                for i in range(int(24 * 3600 / timeleap))
            ]
            pred_times = [datetime.strftime(h, date_format) for h in hours]

            # calcular predicción en cada una de las horas
            for pred_time in pred_times:
                try:
                    # prediccion del modelo
                    Y_true, Y_pred = forecast_pred(datasets,
                                                   output_name,
                                                   model,
                                                   pred_time,
                                                   img_sequence=img_sequence)

                    # prediccion del persistence model
                    Y_pers = beauchef_pers_predict(system_ds, pred_time,
                                                   n_output)

                    # print progress
                    print('\revaluating cluster ' + str(int(label)) + ': ' +
                          pred_time,
                          end='')

                except TypeError:
                    continue

                # agregar datos a cluster data
                cluster_data.append(Y_true)
                cluster_pred.append(Y_pred)
                cluster_pers.append(Y_pers)
                cluster_time.append([pred_time] * n_output)

        # calcular metricas del cluster
        Y_true = np.concatenate(cluster_data, axis=None)
        Y_pred = np.concatenate(cluster_pred, axis=None)
        Y_pers = np.concatenate(cluster_pers, axis=None)
        Y_time = np.concatenate(cluster_time, axis=None)

        eval_metrics.at[label, 'mbe'] = mean_bias_error(Y_true, Y_pred)
        eval_metrics.at[label, 'mae'] = mean_absolute_error(Y_true, Y_pred)
        eval_metrics.at[label,
                        'rmse'] = np.sqrt(mean_squared_error(Y_true, Y_pred))
        eval_metrics.at[label, 'fs'] = forecast_skill(Y_true, Y_pred, Y_pers)
        eval_metrics.at[label, 'skw'] = skew_error(Y_true, Y_pred)
        eval_metrics.at[label, 'kts'] = kurtosis_error(Y_true, Y_pred)

        # plot cluster_sample
        plot_title = 'cluster ' + str(label)
        plot_forecast_pred(datasets,
                           output_name,
                           model,
                           cluster_sample,
                           img_sequence=img_sequence,
                           title=plot_title)

        # plot gráfico estimación
        plot_forecast_accuracy(Y_true,
                               Y_pred,
                               timestamps=Y_time,
                               title=plot_title,
                               s=0.1)

    return eval_metrics
Exemplo n.º 13
0
def persistence_predict(database,
                        forecast_date,
                        n_output,
                        power_cols,
                        lat=-33.45775,
                        lon=70.66466111,
                        Bs=0.0,
                        Zs=0.0,
                        rho=0.2,
                        verbose=False):
    """
    -> numpy.array(floats)
    
    genera un pronóstico de generación fotovoltaica dentro del horizonte
    especificado a partir del criterio de persistencia y el modelo de Perez.
    
    Se supone que tanto el índice de claridad como la fracción difusa del
    timestamp especificado se mantienen constantes dentro de todo el horizonte.
    
    :param DataFrame database:
        base de datos que contiene el registro temporal del sistema fotovoltaico.
    :param str forcast_date:
        fecha y hora en la que realizar el pronóstico %d-%m-%Y %H:%M (UTC).
    :param int n_output:
        cantidad de pronósticos a realizar desde el forcast_date especificado.
    :param str or list(str) power_cols:
        nombre de las columnas que tienen la potencia de los equipos a
        pronosticar.
        
    :param float lat:
        latitud del punto geográfico.
    :param float lon:
        longitud del punto geográfico en grados oeste [0,360).
    :param float Bs: (default, 0.0)
        inclinación de la superficie.
        ángulo de inclinación respecto al plano horizontal de la superficie 
        sobre la cual calcular la irradiancia (grados).
    :param float Zs: (default, 0.0)
        azimut de la superficie.
        ángulo entre la proyección de la normal de la superficie en el plano
        horizontal y la dirección hacia el ecuador (grados).
        
    :returns:
        array con las potencias pronosticadas dentro de el horizonte.
    """

    # -------------------------------------------------------------------------
    # obtener datos operacionales en el timestamp
    forecast_date = validate_date(forecast_date)
    date_index = get_date_index(database['Timestamp'], forecast_date)

    # checkear que los datos estén contenidos en el database
    input_index = date_index - 1
    end_index = date_index + n_output

    # checkear ventana de tiempo
    try:
        assert input_index >= 0
        assert end_index < database.shape[0]
    except AssertionError:
        print('InputError: no es posible aplicar el modelo en la ventana' +
              'de tiempo especificada')
        return None

    # obtener potencia en el timestamp de input
    power = 0.0

    # agregar la potencia de los equipos
    power_cols = list(power_cols)
    for equip in power_cols:
        power += database.at[input_index, equip]

    # obtener parámetros de irradiación
    global_rad = database.at[input_index, 'Global']
    diffuse_rad = database.at[input_index, 'Diffuse']

    # obtener timestep de la base de datos
    date_format = '%d-%m-%Y %H:%M'
    data_timestep = get_timestep(database['Timestamp'], date_format)
    input_timestamp = database.at[input_index, 'Timestamp']

    ext_rad = ext_irradiation(input_timestamp, data_timestep, lat=lat, lon=lon)

    clearsky_index = np.min([1.0, global_rad /
                             ext_rad]) if ext_rad != 0.0 else 1.0
    cloudness_index = np.min([1.0, diffuse_rad /
                              global_rad]) if global_rad != 0.0 else 1.0

    # -------------------------------------------------------------------------
    # modelo de Perez
    input_timestamp = datetime.strptime(input_timestamp, date_format)

    rad_fh = np.zeros((1, n_output + 1)).flatten()

    # incializar matriz de coeficientes
    file_dir = os.path.dirname(
        os.path.abspath(inspect.getfile(persistence_predict)))
    file_path = os.path.join(file_dir, 'perez_coefs.csv')

    coefs = read_csv_file(file_path)

    # para cada timestamp dentro del horizonte de pronostico
    for i in range(n_output + 1):
        # obtener timestamp de pronostico
        new_timestamp = input_timestamp + timedelta(seconds=data_timestep * i)
        new_timestamp = datetime.strftime(new_timestamp, date_format)

        # radiacion extraterrestre en el plano horizontal
        gho = ext_irradiation(new_timestamp, data_timestep, lat=lat, lon=lon)

        # radiacion global en el plano horizontal
        ghi = gho * clearsky_index

        # coeficiente de incidencia
        cos_theta = solar_incidence(new_timestamp,
                                    lat=lat,
                                    lon=lon,
                                    Bs=Bs,
                                    Zs=Zs)
        cos_theta_z = solar_incidence(new_timestamp, lat=lat, lon=lon)

        rb = cos_theta / cos_theta_z if cos_theta_z != 0.0 else 0.0

        # zenith
        theta_z = acos(cos_theta_z)

        # estimacion radiaciones
        dif_i = cloudness_index * ghi
        dir_i = (ghi - dif_i) * sin(pi / 2 - theta_z)

        # irradiacion difusa circumsolar
        a = np.max([0, cos_theta])
        b = np.max([cos(85.0 * pi / 180.0), cos_theta_z])

        # clearness parameter
        if dif_i == 0.0:
            eps = 1.0
        else:
            eps = ((dif_i - dir_i * rb) / dif_i + 5.535e-6 *
                   (theta_z * 180 / pi)**3) / (1 + 5.535e-6 *
                                               (theta_z * 180 / pi)**3)

        # brightness parameter
        gon = gho / cos_theta_z if cos_theta_z != 0.0 else 0.0
        brp = (1 / cos_theta_z) * (dif_i / gon) if (cos_theta_z != 0.0) and (
            gon != 0.0) else 0.0

        # obtener coeficientes
        idx = np.searchsorted(coefs['e'], eps, side='right') - 1
        f11, f12, f13 = coefs.iloc[idx, 1:4]
        f21, f22, f23 = coefs.iloc[idx, 4:7]

        # calcular brightness coeficients
        F1 = np.max([0, (f11 + f12 * brp + theta_z * f13)])
        F2 = (f21 + f22 * brp + theta_z * f23)

        # corregir angulos de la superfice
        Bs_rad = Bs * pi / 180

        # calcular irradiación total
        gti = (dir_i * rb + dif_i * (1 - F1) * (1 + cos(Bs_rad)) / 2 +
               dif_i * F1 * a / b + dif_i * F2 * sin(Bs_rad) + ghi * rho *
               (1 - cos(Bs_rad)) / 2)
        rad_fh[i] = gti

    # calcular estimaciones de potencia
    forecast_output = np.zeros((1, n_output)).flatten()

    # si hay información para realizar un pronóstico
    if not (rad_fh[0] == 0.0 or power == 0.0):
        for i in range(n_output):
            forecast_output[i] = (rad_fh[i + 1] / rad_fh[0]) * power

    # si se desea imprimir información
    if verbose:
        # radiacion global
        global_rad = database['Global'].values[date_index:end_index]

        # potencia sistema
        syst_power = np.zeros((1, n_output)).flatten()
        for equip in power_cols:
            syst_power = syst_power + database[equip].values[
                date_index:end_index]

        print('forecasted radiation: ' + str(rad_fh))
        print('global radiation: ' + str(global_rad) + '\n')
        print('forecasted power: ' + str(forecast_output))
        print('system power: ' + str(syst_power) + '\n')

    return np.reshape(forecast_output, (n_output, -1))
Exemplo n.º 14
0
def goes16_dataset(dir_path, timestamps, size, lat=-33.45775, lon=-70.66466111,
                   adjust_time=0, fix_timestamps=True):
    """
    -> pandas.DataFrame
    
    Procesa los archivos netCDF4 contenidos en el directorio especificado
    contruyendo un DataFrame de imagenes satelitales a partir de la serie de
    timestamps entregados.
    
    :param str or list dir_path:
        ubicacion de los archivos netCDF4 (.nc) que se desea procesar.
    :param list or array-like timestamps:
        serie de timestamps de las imágenes que se desean procesar.
    :param int size:
        tamaño de las imagenes resultantes en el procesamiento.
    :param float lat:
        latitud central del área de interés.
    :param float lon:
        longitud central del área de interés.
    :param str adjust_time:
        permite corregir en segundos el timestamp asociado a cada dato.
    :param bool fix_timestamps:
        si corregir la serie de timestamps en el dataset.
        
          
    :returns: DataFrame de la base de datos
    """
    print('\n' + '-'*80)
    print('processing noaa-goes16 data')
    print('-'*80 + '\n')
    
    # obtener lista de archivos netCDF4 a procesar ----------------------------
    nc_list = []
    
    # por cada una de las direcciones especificadas
    if type(dir_path) is str:
        dir_path = [dir_path]
        
    for path in list(dir_path):
        files_list = os.listdir(path)
        
        # por cada archivo en el directorio
        for f in files_list:
            file_name, ext = os.path.splitext(f)
            
            # si no es un archivo .nc
            if ext != '.nc':
                continue
            
            # obtener timestamp
            start_date, end_date = get_key_times(file_name)
            
            start_date = datetime.strptime(start_date, '%d-%m-%Y %H:%M:%S')
            end_date = datetime.strptime(end_date, '%d-%m-%Y %H:%M:%S')
            
            nc_list.append( (start_date, end_date, os.path.join(path, f)) )
        
    # ordenar
    nc_list.sort()
    
    # inicializar dataset -----------------------------------------------------
    colnames = ['Timestamp', 'Start Time', 'End Time'] + list(np.arange(size*size))
    num_data = len(timestamps)
    
    db = pd.DataFrame(0.0, index=np.arange(num_data), columns=colnames)
    db['Timestamp'] = db['Timestamp'].astype(str)
    db['Start Time'] = db['Start Time'].astype(str)
    db['End Time'] = db['End Time'].astype(str)
    
    # obtener bound indexes ---------------------------------------------------
    print('getting bounds indexes:', end =" ") 
    bound_indexes = get_bound_indexes(nc_list[0][2], lat, lon, size)
    
    print(' done\n')
    sleep(0.25)
    
     # formatear dataset -------------------------------------------------------
    date_format = '%d-%m-%Y %H:%M'
    
    bar = ProgressBar()
    for i in bar( db.index ):
        # obtener timestamp a procesar
        timestamp = validate_date(timestamps[i])
        timestamp = datetime.strptime(timestamp, date_format)
        
        # formatear timestamp
        db.at[i, u'Timestamp'] = datetime.strftime(timestamp, date_format)
        
        # obtener imagen satelital correspondiente
        for j in range( len(nc_list) ):
            # obtener timestamp de inicio del scaneo
            data_start, _, data_path = nc_list[j]
            
            # si la imagen fue tomada después del timestamp de  interés
            if timestamp < data_start:
                # la imagen correspondiente es la tomada anteriormente
                data_start, data_end, data_path = nc_list[j-1]
                break
        
        # agregar timestamps de scaneo
        db.at[i, 'Start Time'] = datetime.strftime(data_start, date_format)
        db.at[i, 'End Time'] = datetime.strftime(data_end, date_format)
        
        # formatear data
        data = bound_goes16_data(data_path, bound_indexes)

        db.at[i, 3:] = data.reshape( (1,-1) )[0]
        
    if not(fix_timestamps):
        return db
    
    # -------------------------------------------------------------------------
    # añadir timestamps faltantes
    
    # obtener timestep del dataset
    timestep = get_timestep(db['Timestamp'], date_format)
    
    time_freq = str(timestep) + 'S'
    first_date = datetime.strptime( db['Timestamp'].iloc[0], date_format)
    last_date = datetime.strptime( db['Timestamp'].iloc[-1], date_format)
    
    idx = pd.date_range(first_date, last_date, freq=time_freq)
    
    db.index = pd.DatetimeIndex( db[u'Timestamp'].values, dayfirst=True )
    db = db.reindex( idx, fill_value=0.0 )
    db[u'Timestamp'] = idx.strftime(date_format)
    
    # resetear index a enteros
    db = db.reset_index()
    db.drop('index',axis=1, inplace=True)
  
    return db