This package was built was to facilitate direct maximum likelihood estimation of the normal-gamma and normal-Nakagami stochastic frontier models using closed-form expressions for the log-likelihood functions and efficiency predictors in terms of the parabolic cylinder function, as explored in the paper:
- Stead AD. 2024. Maximum likelihood estimation of normal-gamma and normal-Nakagami stochastic frontier models. Journal of Productivity Analysis. DOI: 10.1007/s11123-024-00742-2
The package however also includes options to estimate other stochastic frontier specifications, and may be of more general use to anyone who wishes to use Python for stochastic frontier analysis. All results in the paper were obtained using this package.
The package produces parameter estimates, standard errors, log-likelihoods, efficiency predictors, and more in a convenient format.
Currently the package is limited to models of the form
All distributional parameters are assumed to be scalars by default, but may be modelled as a function of a vector of covariates, e.g.
The package may be extended in future in order to accomodate additional specifications.
Provided you have the git
package installed, you can install FronPy
by entering:
pip install git+https://github.com/AlexStead/FronPy.git
The code block below prints the help text explaining the use of the fronpy.dataset() and fronpy.estimate() functions:
import fronpy
help(fronpy.dataset)
help(fronpy.estimate)
The code block below loads a built-in dataset, does some basic data transformation, estimates the normal-gamma stochastic frontier model, and demonstrates the package's basic syntax:
import fronpy
import numpy as np
electricity_df = fronpy.dataset('electricity_df.csv',dataframe=True)
electricity_df[f'lnc'] = np.log((electricity_df['cost']/electricity_df['cost'].mean())/(electricity_df['fprice']/electricity_df['fprice'].mean()))
electricity_df[f'q'] = electricity_df['output'] / electricity_df['output'].mean()
electricity_df[f'lnq'] = np.log(electricity_df['output'] / electricity_df['output'].mean())
electricity_df[f'lnw'] = np.log((electricity_df['lprice']/electricity_df['lprice'].mean())/(electricity_df['fprice']/electricity_df['fprice'].mean()))
electricity_df[f'lnr'] = np.log((electricity_df['cprice']/electricity_df['cprice'].mean())/(electricity_df['fprice']/electricity_df['fprice'].mean()))
nexpmodel = fronpy.estimate(electricity,cost=True,model='nexp')
ngmodel = fronpy.estimate(electricity_df,frontier='lnc~np.log(q)+I(np.log(q)**2)+lnw+lnr',cost=True,model='ng',
startingvalues=np.append(nexpmodel.theta,[0,0]))
ngmodel
In the final line, ngmodel
produces rather a lot of output, but is useful to see all of the outputs produced by the fronpy.estimate
. For example, we can see that ngmodel.lnlikelihood
would give us the log-likelihood, ngmodel.beta
would give us the estimated frontier parameters, ngmodel.eff_bc
would give us fronpy.estimate
requires a numpy.ndarray
with rows representing observations and columns representing variables, where:
- all data are numeric.
- the first column contains the dependent variable.
- columns 2,...,n contain the independent variables, including a constant if desired.
- there are no missing,
NaN
,inf
,-inf
or similarly invalid values.
Alternatively, the following command may be used to launch a graphical user interface. Note that this is very rudimentary, and needs further development to incorporate all of the options available using the command line interface:
import fronpy
fronpy.launch_gui()