def define_holiday_regressors(X, dates, holidays=None): """ Add columns to the predictor matrix X for a specified list of holidays :param X: (Array) Predictor matrix without columns for the holidays :param dates: Dates :param holidays: (List) holidays :return: Updated predictor matrix """ if holidays is not None: if len(holidays) > 0: if X is None: n = len(dates) else: n = X.shape[0] for holiday in holidays: cal = AbstractHolidayCalendar() cal.rules = [holiday] x = np.zeros(n) x[dates.isin(cal.holidays())] = 1 if X is None: X = x else: X = np.c_[X, x] return X else: return X else: return X
def __init__( self, rate_info: dict, default_price: float = .13, holiday_calendar: AbstractHolidayCalendar = USFederalHolidayCalendar() ): """ Creates a RateSchedule object. :param rate_info: Rate information captured from the json result for a particular Rate. :type rate_info: ``dict`` :param default_price: (Optional) A fallback price that the object should use should no other pricing information be found. This only applies to energy use rates, not demand or coincident charges. Defaults to 13 cents. (0.13) :type default_price: ``float`` :param holiday_calendar: A Pandas holiday calendar used for calculating holiday times for determining appropiate rates. Defaults to using the [Pandas US federal holiday calendar](https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html). :type holiday_calendar: ``pandas.tseries.holiday.AbstractHolidayCalendar`` """ logger.info('Loading RateSchedule for {} ({})'.format( rate_info.get('name'), rate_info.get('utility'))) # Parse the rate information from a dict response begin_dt = rate_info.get('startdate', None) end_dt = rate_info.get('enddate', None) self.features = set({}) if begin_dt and end_dt: self.holidays = holiday_calendar.holidays( start=pd.Timestamp.fromtimestamp(begin_dt), end=pd.Timestamp.fromtimestamp(end_dt)) else: self.holidays = holiday_calendar.holidays() self.label = rate_info.get('label') # A fallback price in case things get weird. self.default_energy_price = default_price # Units self.flat_demand_unit = rate_info.get('flatdemandunit', 'kW') self.demand_rate_unit = rate_info.get('demandrateunit', 'kW') self.coincident_rate_unit = rate_info.get('coincidentrateunit', 'kW') self.energy_demand_unit = rate_info.get('demandrateunit', 'kWh') self.energy_unit = 'kWh' # Demand ceiling and floor for demand charges self.demand_minimum = rate_info.get('peakkwcapacitymin', 0) self.demand_maximum = rate_info.get('peakkwcapacitymax', 0) # How long is our window for demand? (in minutes). self.demand_window = rate_info.get('demandratewindow', RateSchedule.default_demand_window) # Rate Structures # A rate structure is essentially a list of lists with rate information # The outer array's indexes refer to the period ID, with Tiers and members # The inner array (Tier) is an array of attributes # Each rate structure's attributes are a bit different. # Demand charges d_rate_struct = rate_info.get('demandratestructure') self.demand_rates = RateSchedule.build_rate_structure(d_rate_struct) d_flat_struct = rate_info.get('flatdemandstructure') self.flat_demand_rates = RateSchedule.build_rate_structure( d_flat_struct) # Coincident c_rate_struct = rate_info.get('coincidentratestructure') self.coincident_rates = __class__.build_rate_structure(c_rate_struct) # Energy rate e_rate_struct = rate_info.get('energyratestructure') if not e_rate_struct: e_rate_struct = [[{'rate': default_price}]] logger.warn( 'Energy pricing structure not found. Falling back to default price!' ) self.energy_rates = __class__.build_rate_structure(e_rate_struct) # TOUs # Get the TOU schedules default_tou = np.zeros((12, 24), dtype=np.uint8) # Demand d_wd_sched = rate_info.get('demandweekdayschedule') d_we_sched = rate_info.get('demandweekendschedule') d_flat_sched = rate_info.get('flatdemandmonths') self.demand_weekday_schedule = np.array( d_wd_sched, dtype=np.uint8) if d_wd_sched else None self.demand_weekend_schedule = np.array( d_we_sched, dtype=np.uint8) if d_we_sched else None self.flat_demand_months = np.array( d_flat_sched, dtype=np.uint8) if d_flat_sched else None e_wd_sched = rate_info.get('energyweekdayschedule') e_we_sched = rate_info.get('energyweekendschedule') if not e_wd_sched: logger.warn( 'Could not load weekday energy TOU schedule. Falling back to default!' ) if not e_we_sched: logger.warn( 'Could not load weekend energy TOU schedule. Falling back to default!' ) self.energy_weekday_schedule = np.array( e_wd_sched, dtype=np.uint8) if e_wd_sched else np.copy(default_tou) self.energy_weekend_schedule = np.array( e_we_sched, dtype=np.uint8) if e_we_sched else np.copy(default_tou) c_sched = rate_info.get('coincidentrateschedule') self.coincident_schedule = np.array( c_sched, dtype=np.uint8) if c_sched else None self.demand_ratchet_pct = np.array(rate_info.get( 'demandrachetpercentage', [0.0 for i in range(12)]), dtype=np.float32) # Fixed monthly charges self.fixed_monthly_charge = rate_info.get('fixedmonthlycharge', 0) self.monthly_min_charge = rate_info.get('minmonthlycharge', 0) self.annual_min_charge = rate_info.get('annualmincharge', 0) self.fixed_attrs = rate_info.get('fixedattrs', None) # Net metering? self.use_net_metering = rate_info.get('usenetmetering', False)