Source code for get_context_data

import pandas as pd


[docs]class GetFuelPrices: """ The GetFuelPrices class grabs the appropriate fuel prices from the aeo folder, cleans up some naming and creates a fuel_prices DataFrame for use in operating costs. Parameters: input_file: String; the file containing fuel price data.\n aeo_case: String; from the General Inputs sheet - the AEO fuel case to use (a CSV of fuel prices must exist in the aeo directory).\n id_col: String; the column name where id data can be found.\n fuels: String(s); the AEO descriptor for the fuel prices needed in the project (e.g., Motor Gasoline, Diesel). Note: This class assumes a file structured like those published by EIA in the Annual Energy Outlook. """ def __init__(self, input_file, aeo_case, id_col, *fuels): self.input_file = input_file self.aeo_case = aeo_case self.id_col = id_col self.fuels = fuels self.fuel_dict = {'Motor Gasoline': 1, 'Diesel': 2, 'CNG': 3, } def __repr__(self): return f'\n{self.__class__.__name__}: AEO {self.aeo_case}'
[docs] def aeo_dollars(self): """ Returns: An integer value representing the dollar basis of the AEO report. """ return int(self.input_file.at[0, 'units'][0: 4])
[docs] def select_aeo_table_rows(self, df_source, row): """ Parameters: df_source: DataFrame; contains the AEO fuel prices.\n row: String; the specific row to select. Returns: A DataFrame of the specific fuel price row. """ df_return = df_source.loc[df_source[self.id_col] == row[self.id_col], :] df_return = df_return.iloc[:, :-1] return df_return
[docs] def row_dict(self, fuel): """ Parameters: fuel: String; the fuel (gasoline/diesel). Returns: A dictionary of fuel prices. """ return_dict = dict() return_dict['retail_prices'] = {self.id_col: f'Price Components: {fuel}: End-User Price: {self.aeo_case}'} return_dict['distribution_costs'] = {self.id_col: f'Price Components: {fuel}: End-User Price: Distribution Costs: {self.aeo_case}'} return_dict['wholesale_price'] = {self.id_col: f'Price Components: {fuel}: End-User Price: Wholesale Price: {self.aeo_case}'} # return_dict['tax_allowance'] = {self.id_col: f'Price Components: {fuel}: End-User Price: Tax/Allowance: {self.aeo_case}'} return return_dict
[docs] def melt_df(self, df, value_name): """ Parameters: df: DataFrame; the fuel prices to melt.\n value_name: String; the name of the melted values. Returns: A DataFrame of melted value_name data by year. """ df = pd.melt(df, id_vars=[self.id_col], value_vars=[col for col in df.columns if '20' in col], var_name='yearID', value_name=value_name) df['yearID'] = df['yearID'].astype(int) return df
[docs] def get_prices(self): """ Returns: A DataFrame of fuel prices for the given AEO case. Note that CNG prices are set equivalent to gasoline prices. """ fuel_prices_dict = dict() fuel_prices_df = pd.DataFrame() for fuel in self.fuels: retail_prices = self.select_aeo_table_rows(self.input_file, self.row_dict(fuel)['retail_prices']) fuel_prices_dict[fuel] = self.melt_df(retail_prices, 'retail_fuel_price') distribution_costs = self.select_aeo_table_rows(self.input_file, self.row_dict(fuel)['distribution_costs']) fuel_prices_dict[fuel] = fuel_prices_dict[fuel].merge(self.melt_df(distribution_costs, 'distribution_costs'), on='yearID') wholesale_price = self.select_aeo_table_rows(self.input_file, self.row_dict(fuel)['wholesale_price']) fuel_prices_dict[fuel] = fuel_prices_dict[fuel].merge(self.melt_df(wholesale_price, 'wholesale_price'), on='yearID') # tax_allowance = self.select_aeo_table_rows(prices_full, self.row_dict(fuel)['tax_allowance']) # fuel_prices_dict[fuel] = fuel_prices_dict[fuel].merge(self.melt_df(tax_allowance, 'tax_allowance'), on='yearID') fuel_prices_dict[fuel].insert(len(fuel_prices_dict[fuel].columns), 'pretax_fuel_price', fuel_prices_dict[fuel]['distribution_costs'] + fuel_prices_dict[fuel]['wholesale_price']) fuel_prices_dict[fuel].insert(0, 'fuelTypeID', self.fuel_dict[fuel]) fuel_prices_df = pd.concat([fuel_prices_df, fuel_prices_dict[fuel]], ignore_index=True, axis=0) fuel_prices_dict['CNG'] = fuel_prices_dict['Motor Gasoline'].copy() fuel_prices_dict['CNG']['fuelTypeID'] = self.fuel_dict['CNG'] fuel_prices_df = pd.concat([fuel_prices_df, fuel_prices_dict['CNG']], ignore_index=True, axis=0) fuel_prices_df = fuel_prices_df[['yearID', 'fuelTypeID', 'retail_fuel_price', 'pretax_fuel_price']] fuel_prices_df.insert(fuel_prices_df.columns.get_loc('yearID') + 1, 'DollarBasis', self.aeo_dollars()) fuel_prices_df.insert(fuel_prices_df.columns.get_loc('yearID') + 1, 'AEO Case', self.aeo_case) return fuel_prices_df
[docs]class GetDeflators: """ The GetDeflators class returns the GDP Implicit Price Deflators for use in adjusting monetized values to a consistent cost basis. Parameters: input_file: String; the file containing price deflator data.\n id_col: String; the column name where id data can be found.\n id_value: the value within id_col to return. Note: This class assumes a file structured like those published by the Bureau of Economic Analysis. """ def __init__(self, input_file, id_col, id_value): self.input_file = input_file self.id_col = id_col self.id_value = id_value def __repr__(self): return f'{self.__class__.__name__}: {self.id_value}'
[docs] def deflator_df(self): """ Returns: A DataFrame consisting of only the data for the given AEO case; the name of the AEO case is also removed from the 'full name' column entries. """ df_return = pd.DataFrame(self.input_file) df_return = pd.DataFrame(df_return.loc[df_return[self.id_col].str.endswith(f'{self.id_value}'), :]).reset_index(drop=True) # df_return.replace({self.id_col: f': {self.id_value}'}, {self.id_col: ''}, regex=True, inplace=True) # above line changed to below due to new general_functions.read_input_files() which skips on_bad_lines while prior to that they were allowed without raising an error df_return.replace({self.id_col: f': {self.id_value}'}, regex=True, inplace=True) return df_return
[docs] def melt_df(self, value_name, drop_col=None): """ Parameters: value_name: String; the name for the resultant data column.\n drop_col: String; the name of any columns to be dropped after melt. Returns: The melted DataFrame with a column of data named value_name. """ deflator_df = self.deflator_df() melt_df = pd.melt(deflator_df, id_vars=[self.id_col], value_vars=[col for col in deflator_df.columns if '20' in col], var_name='yearID', value_name=value_name) melt_df['yearID'] = melt_df['yearID'].astype(int) if drop_col: melt_df.drop(columns=drop_col, inplace=True) return melt_df
[docs] def calc_adjustment_factors(self, dollar_basis): """ Parameters: dollar_basis: Numeric; the dollar basis for the analysis set via the General Inputs sheet. Returns: A dictionary of deflators and adjustment_factors to apply to monetized values to put them all on a consistent dollar basis. """ deflators = self.melt_df('price_deflator', self.id_col) deflators['price_deflator'] = deflators['price_deflator'].astype(float) basis_factor_df = pd.DataFrame(deflators.loc[deflators['yearID'] == dollar_basis, 'price_deflator']).reset_index(drop=True) basis_factor = basis_factor_df.at[0, 'price_deflator'] deflators.insert(len(deflators.columns), 'adjustment_factor', basis_factor / deflators['price_deflator']) deflators = deflators.set_index('yearID') deflators_dict = deflators.to_dict('index') return deflators_dict
if __name__ == '__main__': """ This tests the context data creation if run as a script (python -m bca_tool_code.get_context_data). """ from pathlib import Path import bca_tool_code.general_functions as gen_fxns path_project = Path(__file__).parent.parent path_dev = path_project / 'dev' path_dev.mkdir(exist_ok=True) path_inputs = path_project / 'inputs' input_files_df = gen_fxns.read_input_files(path_inputs, 'Input_Files.csv', usecols=lambda x: 'Notes' not in x, index_col=0) input_files_dict = input_files_df.to_dict('index') fuel_prices_file = gen_fxns.read_input_files(path_inputs, input_files_dict['fuel_prices_file']['UserEntry.csv'], skiprows=4, reset_index=True) deflators_file = gen_fxns.read_input_files(path_inputs, input_files_dict['deflators_file']['UserEntry.csv'], skiprows=4, reset_index=True) aeo_case_1 = 'Reference case' fuel_prices_obj = GetFuelPrices(fuel_prices_file, aeo_case_1, 'full name', 'Motor Gasoline', 'Diesel') fuel_prices = fuel_prices_obj.get_prices() fuel_prices.to_csv(path_dev / f'fuel_prices_{aeo_case_1}.csv', index=False) aeo_case_2 = 'High oil price' fuel_prices_obj = GetFuelPrices(fuel_prices_file, aeo_case_2, 'full name', 'Motor Gasoline', 'Diesel') fuel_prices = fuel_prices_obj.get_prices() fuel_prices.to_csv(path_dev / f'fuel_prices_{aeo_case_2}.csv', index=False) aeo_case_3 = 'Low oil price' fuel_prices_obj = GetFuelPrices(fuel_prices_file, aeo_case_3, 'full name', 'Motor Gasoline', 'Diesel') fuel_prices = fuel_prices_obj.get_prices() fuel_prices.to_csv(path_dev / f'fuel_prices_{aeo_case_3}.csv', index=False) deflators_obj = GetDeflators(deflators_file, 'Unnamed: 1', 'Gross domestic product') dollar_basis_analysis = fuel_prices_obj.aeo_dollars() deflators = deflators_obj.calc_adjustment_factors(dollar_basis_analysis) deflators = pd.DataFrame(deflators) deflators.to_csv(path_dev / f'gdp_deflators.csv', index=True) print(f'\nFuel prices in {dollar_basis_analysis} dollars have been saved to the {path_dev} folder.')