In [1]:
import IPython.core.display as di
# This line will hide code by default when the notebook is exported as HTML
di.display_html('<script>jQuery(function() {if (jQuery("body.notebook_app").length == 0) { jQuery(".input_area").toggle(); jQuery(".prompt").toggle();}});</script>', raw=True)
# This line will add a button to toggle visibility of code blocks, for use with the HTML export version
di.display_html('''<button onclick="jQuery('.input_area').toggle(); jQuery('.prompt').toggle();">Show/Hide code</button>''', raw=True)
In [2]:
#Allow the created content to be interactivelly ploted inline
%matplotlib inline
#Establish width and height for all plots in the report
#pylab.rcParams['figure.figsize'] = (18, 6) #width, height
In [3]:
#Import needed libraries
import os
from os.path import join, getsize
import pandas as pd
from cycler import cycler
import matplotlib.pyplot as plt
from IPython.display import display
import numpy as np
import collections
import matplotlib as mpl
inline_rc = dict(mpl.rcParams)
#the next cell enables plotting tables without borders

# To hide warnings
import warnings
warnings.filterwarnings('ignore')
In [4]:
%%html
<style>
table,td,tr,th {border:none!important}
</style>

Summary report of the CO2MPAS WLTP to NEDC CO$_2$ emission simulation model - Automatic vehicles (v.2.0.x)

In [5]:
#Specify the output folder and file containing the CO2MPAS summary output file.
folder = r'C:\Users\komnodi\Desktop\PYTHON\batch_files_assessment\01.ORIGINAL_IPNBS_UNLEASH'
file = '20180808_100221-summary_AT_UNLEASH.xlsx'
infile = join(folder, file)
df=pd.read_excel(infile, 'anon', header=[0,1,2,3], index_col=[0], skiprows=[4])
In [6]:
#Gather and name the basic variables used in the report according to their name in the CO2MPAS output file
NEDC = df['nedc_h']['prediction']['output']['declared_value']
NEDCl = df['nedc_l']['prediction']['output']['declared_value']
NEDCt = df['nedc_h']['prediction']['target']['value']
UDC = df['nedc_h']['prediction']['output']['UDC']
UDCl = df['nedc_l']['prediction']['output']['UDC']
UDCt = df['nedc_h']['prediction']['target']['UDC']
EUDC = df['nedc_h']['prediction']['output']['EUDC']
EUDCl = df['nedc_l']['prediction']['output']['EUDC']
EUDCt = df['nedc_h']['prediction']['target']['EUDC']
#Obtain the case number and vehicle model from the input file
df['vehicle'] = df.index
cases = df['vehicle'].str.split('_').str[-1].astype('int')
model = df['vehicle'].str.split('_').str[0]
#Create a dataframe with this data
valuesDF = pd.DataFrame({'NEDC': NEDC,'NEDCt':NEDCt, 'dNEDC':NEDC-NEDCt,'dNEDCl':NEDCl-NEDCt,'UDC': UDC,'UDCt':UDCt, 'dUDC':UDC-UDCt,'dUDCl':UDCl-UDCt,'EUDC': EUDC,'EUDCt':EUDCt, 'dEUDC':EUDC-EUDCt,'dEUDCl':EUDCl-EUDCt,'Case':cases,'Model':model})   
#calculate percentages
valuesDF['NEDC-H error [%]'] = pd.Series((valuesDF.dNEDC/valuesDF.NEDCt*100), index=valuesDF.index)
valuesDF['UDC-H error [%]'] = pd.Series((valuesDF.dUDC/valuesDF.UDCt*100), index=valuesDF.index)
valuesDF['EUDC-H error [%]'] = pd.Series((valuesDF.dEUDC/valuesDF.EUDCt*100), index=valuesDF.index)
valuesDF['NEDC-L error [%]'] = pd.Series((valuesDF.dNEDCl/valuesDF.NEDCt*100), index=valuesDF.index)
valuesDF['UDC-L error [%]'] = pd.Series((valuesDF.dUDCl/valuesDF.UDCt*100), index=valuesDF.index)
valuesDF['EUDC-L error [%]'] = pd.Series((valuesDF.dEUDCl/valuesDF.EUDCt*100), index=valuesDF.index)
valuesDF = valuesDF.dropna()
In [7]:
valuesDF['FuelType'] = np.where((valuesDF['Model'] == 'Vehicle01') | (valuesDF['Model'] == 'Vehicle03') | (valuesDF['Model'] == 'Vehicle05') | (valuesDF['Model'] == 'Vehicle07'), 'Gasoline','Diesel')
In [8]:
Gasolines = valuesDF.loc[lambda valuesDF: valuesDF['FuelType'] =='Gasoline', :]
Diesels = valuesDF.loc[lambda valuesDF: valuesDF['FuelType'] =='Diesel', :]

Section 1. Performance of the model. All vehicles and test cases.

Error statistics for CO$_2$ emission per driving cycle

Error statistics for NEDC, UDC, and EUDC CO$_2$ emission

In [9]:
#Create a dataframe with the NECD, UDC, EUDC error statistics
errorsDF = pd.DataFrame(index=['Averages','StdError','Median','Mode','StdDev','Variance','Kurtosis','Skweness','Range','Minimum','Maximum','Sum','Count','Confidence level (95%)'], columns=['NEDC-H [gCO$_2$ km$^{-1}$]','UDC-H [gCO$_2$ km$^{-1}$]', 'EUDC-H [gCO$_2$ km$^{-1}$]', 'NEDC-L [gCO$_2$ km$^{-1}$]','UDC-L [gCO$_2$ km$^{-1}$]', 'EUDC-L [gCO$_2$ km$^{-1}$]'])
errorsDF.loc['Averages'] = pd.Series({'NEDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDC.mean(),2), 'UDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDC.mean(),2), 'EUDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDC.mean(),2), 'NEDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDCl.mean(),2), 'UDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDCl.mean(),2), 'EUDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDCl.mean(),2)})
errorsDF.loc['StdError'] = pd.Series({'NEDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDC.sem(),2), 'UDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDC.sem(),2), 'EUDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDC.sem(),2), 'NEDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDCl.sem(),2), 'UDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDCl.sem(),2), 'EUDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDCl.sem(),2)})
errorsDF.loc['Median'] = pd.Series({'NEDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDC.median(),2), 'UDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDC.median(),2), 'EUDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDC.median(),2), 'NEDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDCl.median(),2), 'UDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDCl.median(),2), 'EUDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDCl.median(),2)})
errorsDF.loc['Mode'] = pd.Series({'NEDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDC.mode().iloc[0],2), 'UDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDC.mode().iloc[0],2), 'EUDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDC.mode().iloc[0],2), 'NEDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDCl.mode().iloc[0],2), 'UDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDCl.mode().iloc[0],2), 'EUDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDCl.mode().iloc[0],2)})
errorsDF.loc['StdDev'] = pd.Series({'NEDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDC.std(),2), 'UDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDC.std(),2), 'EUDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDC.std(),2), 'NEDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDCl.std(),2), 'UDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDCl.std(),2), 'EUDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDCl.std(),2)})
errorsDF.loc['Variance'] = pd.Series({'NEDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDC.var(),2), 'UDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDC.var(),2), 'EUDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDC.var(),2), 'NEDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDCl.var(),2), 'UDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDCl.var(),2), 'EUDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDCl.var(),2)})
errorsDF.loc['Kurtosis'] = pd.Series({'NEDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDC.kurtosis(),2), 'UDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDC.kurtosis(),2), 'EUDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDC.kurtosis(),2), 'NEDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDCl.kurtosis(),2), 'UDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDCl.kurtosis(),2), 'EUDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDCl.kurtosis(),2)})
errorsDF.loc['Skweness'] = pd.Series({'NEDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDC.skew(),2), 'UDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDC.skew(),2), 'EUDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDC.skew(),2), 'NEDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDCl.skew(),2), 'UDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDCl.skew(),2), 'EUDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDCl.skew(),2)})
errorsDF.loc['Range'] = pd.Series({'NEDC-H [gCO$_2$ km$^{-1}$]':round((valuesDF.dNEDC.max()-valuesDF.dNEDC.min()),2), 'UDC-H [gCO$_2$ km$^{-1}$]':round((valuesDF.dUDC.max()-valuesDF.dUDC.min()),2), 'EUDC-H [gCO$_2$ km$^{-1}$]':round((valuesDF.dEUDC.max()-valuesDF.dEUDC.min()),2), 'NEDC-L [gCO$_2$ km$^{-1}$]':round((valuesDF.dNEDCl.max()-valuesDF.dNEDCl.min()),2), 'UDC-L [gCO$_2$ km$^{-1}$]':round((valuesDF.dUDCl.max()-valuesDF.dUDCl.min()),2), 'EUDC-L [gCO$_2$ km$^{-1}$]':round((valuesDF.dEUDCl.max()-valuesDF.dEUDCl.min()),2)})
errorsDF.loc['Minimum'] = pd.Series({'NEDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDC.min(),2), 'UDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDC.min(),2), 'EUDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDC.min(),2), 'NEDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDCl.min(),2), 'UDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDCl.min(),2), 'EUDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDCl.min(),2)})
errorsDF.loc['Maximum'] = pd.Series({'NEDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDC.max(),2), 'UDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDC.max(),2), 'EUDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDC.max(),2), 'NEDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDCl.max(),2), 'UDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDCl.max(),2), 'EUDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDCl.max(),2)})
errorsDF.loc['Sum'] = pd.Series({'NEDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDC.sum(),2), 'UDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDC.sum(),2), 'EUDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDC.sum(),2), 'NEDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDCl.sum(),2), 'UDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDCl.sum(),2), 'EUDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDCl.sum(),2)})
errorsDF.loc['Count'] = pd.Series({'NEDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDC.count(),2), 'UDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDC.count(),2), 'EUDC-H [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDC.count(),2), 'NEDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dNEDCl.count(),2), 'UDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dUDCl.count(),2), 'EUDC-L [gCO$_2$ km$^{-1}$]':round(valuesDF.dEUDCl.count(),2)})
errorsDF.loc['Confidence level (95%)'] = pd.Series({'NEDC-H [gCO$_2$ km$^{-1}$]':2*round(valuesDF.dNEDC.sem(),2), 'UDC-H [gCO$_2$ km$^{-1}$]':2*round(valuesDF.dUDC.sem(),2), 'EUDC-H [gCO$_2$ km$^{-1}$]':2*round(valuesDF.dEUDC.sem(),2), 'NEDC-L [gCO$_2$ km$^{-1}$]':2*round(valuesDF.dNEDCl.sem(),2), 'UDC-L [gCO$_2$ km$^{-1}$]':2*round(valuesDF.dUDCl.sem(),2), 'EUDC-L [gCO$_2$ km$^{-1}$]':2*round(valuesDF.dEUDCl.sem(),2)})
errorsDF
Out[9]:
NEDC-H [gCO$_2$ km$^{-1}$] UDC-H [gCO$_2$ km$^{-1}$] EUDC-H [gCO$_2$ km$^{-1}$] NEDC-L [gCO$_2$ km$^{-1}$] UDC-L [gCO$_2$ km$^{-1}$] EUDC-L [gCO$_2$ km$^{-1}$]
Averages -1.39 -4.96 0.68 -1.65 -5.26 0.44
StdError 0.11 0.21 0.08 0.11 0.21 0.08
Median -2.03 -6.16 -0.04 -2.55 -6.64 -0.37
Mode -6.04 -14.55 -1.59 -5.7 -14.36 -1.82
StdDev 4.32 8.17 2.92 4.26 8.05 3.11
Variance 18.65 66.68 8.51 18.15 64.81 9.68
Kurtosis -0.29 0.13 2.24 0.6 0.62 14.16
Skweness 0.45 0.3 1.24 0.83 0.53 3.11
Range 22 45.89 19.17 25.53 47.29 23.92
Minimum -12.01 -29.36 -3.98 -11.23 -28.23 -3.96
Maximum 10 16.53 15.18 14.3 19.06 19.96
Sum -2034.29 -7257.41 991.89 -2414.91 -7689.99 640.74
Count 1463 1463 1463 1463 1463 1463
Confidence level (95%) 0.22 0.42 0.16 0.22 0.42 0.16

Error statistics for NEDC, UDC, and EUDC CO$_2$ emission

In [10]:
#Create a dataframe with the NECD, UDC, EUDC error statistics
errorsDF = pd.DataFrame(index=['Averages','StdDev','Minimum','Maximum','Cases in ±4%','Cases in ±2.5%'], columns=['NEDC-H [%]','UDC-H [%]', 'EUDC-H [%]','NEDC-L [%]','UDC-L [%]', 'EUDC-L [%]'])
errorsDF.loc['Averages'] = pd.Series({'NEDC-H [%]':round(valuesDF['NEDC-H error [%]'].mean(),2), 'UDC-H [%]':round(valuesDF['UDC-H error [%]'].mean(),2), 'EUDC-H [%]':round(valuesDF['EUDC-H error [%]'].mean(),2),'NEDC-L [%]':round(valuesDF['NEDC-L error [%]'].mean(),2), 'UDC-L [%]':round(valuesDF['UDC-L error [%]'].mean(),2), 'EUDC-L [%]':round(valuesDF['EUDC-L error [%]'].mean(),2)})
errorsDF.loc['StdDev'] = pd.Series({'NEDC-H [%]':round(valuesDF['NEDC-H error [%]'].std(),2), 'UDC-H [%]':round(valuesDF['UDC-H error [%]'].std(),2), 'EUDC-H [%]':round(valuesDF['EUDC-H error [%]'].std(),2),'NEDC-L [%]':round(valuesDF['NEDC-L error [%]'].std(),2), 'UDC-L [%]':round(valuesDF['UDC-L error [%]'].std(),2), 'EUDC-L [%]':round(valuesDF['EUDC-L error [%]'].std(),2)})
errorsDF.loc['Minimum'] = pd.Series({'NEDC-H [%]':round(valuesDF['NEDC-H error [%]'].min(),2), 'UDC-H [%]':round(valuesDF['UDC-H error [%]'].min(),2), 'EUDC-H [%]':round(valuesDF['EUDC-H error [%]'].min(),2),'NEDC-L [%]':round(valuesDF['NEDC-L error [%]'].min(),2), 'UDC-L [%]':round(valuesDF['UDC-L error [%]'].min(),2), 'EUDC-L [%]':round(valuesDF['EUDC-L error [%]'].min(),2)})
errorsDF.loc['Maximum'] = pd.Series({'NEDC-H [%]':round(valuesDF['NEDC-H error [%]'].max(),2), 'UDC-H [%]':round(valuesDF['UDC-H error [%]'].max(),2), 'EUDC-H [%]':round(valuesDF['EUDC-H error [%]'].max(),2),'NEDC-L [%]':round(valuesDF['NEDC-L error [%]'].max(),2), 'UDC-L [%]':round(valuesDF['UDC-L error [%]'].max(),2), 'EUDC-L [%]':round(valuesDF['EUDC-L error [%]'].max(),2)})
errorsDF.loc['Cases in ±4%'] = pd.Series({'NEDC-H [%]':round(sum(abs(valuesDF['NEDC-H error [%]'])<4)/len(valuesDF['NEDC-H error [%]'])*100,1), 'UDC-H [%]':round(sum(abs(valuesDF['UDC-H error [%]'])<4)/len(valuesDF['UDC-H error [%]'])*100,1), 'EUDC-H [%]':round(sum(abs(valuesDF['EUDC-H error [%]'])<4)/len(valuesDF['EUDC-H error [%]'])*100,1),'NEDC-L [%]':round(sum(abs(valuesDF['NEDC-L error [%]'])<4)/len(valuesDF['NEDC-L error [%]'])*100,1), 'UDC-L [%]':round(sum(abs(valuesDF['UDC-L error [%]'])<4)/len(valuesDF['UDC-L error [%]'])*100,1), 'EUDC-L [%]':round(sum(abs(valuesDF['EUDC-L error [%]'])<4)/len(valuesDF['EUDC-L error [%]'])*100,1)})
errorsDF.loc['Cases in ±2.5%'] = pd.Series({'NEDC-H [%]':round(sum(abs(valuesDF['NEDC-H error [%]'])<2.5)/len(valuesDF['NEDC-H error [%]'])*100,1), 'UDC-H [%]':round(sum(abs(valuesDF['UDC-H error [%]'])<2.5)/len(valuesDF['UDC-H error [%]'])*100,1), 'EUDC-H [%]':round(sum(abs(valuesDF['EUDC-H error [%]'])<2.5)/len(valuesDF['EUDC-H error [%]'])*100,1),'NEDC-L [%]':round(sum(abs(valuesDF['NEDC-L error [%]'])<2.5)/len(valuesDF['NEDC-L error [%]'])*100,1), 'UDC-L [%]':round(sum(abs(valuesDF['UDC-L error [%]'])<2.5)/len(valuesDF['UDC-L error [%]'])*100,1), 'EUDC-L [%]':round(sum(abs(valuesDF['EUDC-L error [%]'])<2.5)/len(valuesDF['EUDC-L error [%]'])*100,1)})
errorsDF.loc['P75-P25'] = pd.Series({'NEDC-H [%]':round(valuesDF['NEDC-H error [%]'].quantile(0.75)-valuesDF['NEDC-H error [%]'].quantile(0.25),2), 'UDC-H [%]':round(valuesDF['UDC-H error [%]'].quantile(0.75)-valuesDF['UDC-H error [%]'].quantile(0.25),2), 'EUDC-H [%]':round(valuesDF['EUDC-H error [%]'].quantile(0.75)-valuesDF['EUDC-H error [%]'].quantile(0.25),2),'NEDC-L [%]':round(valuesDF['NEDC-L error [%]'].quantile(0.75)-valuesDF['NEDC-L error [%]'].quantile(0.25),2), 'UDC-L [%]':round(valuesDF['UDC-L error [%]'].quantile(0.75)-valuesDF['UDC-L error [%]'].quantile(0.25),2), 'EUDC-L [%]':round(valuesDF['EUDC-L error [%]'].quantile(0.75)-valuesDF['EUDC-L error [%]'].quantile(0.25),2)})
errorsDF.loc['Count'] = pd.Series({'NEDC-H [%]':round(valuesDF['NEDC-H error [%]'].count(),2), 'UDC-H [%]':round(valuesDF['UDC-H error [%]'].count(),2), 'EUDC-H [%]':round(valuesDF['EUDC-H error [%]'].count(),2),'NEDC-L [%]':round(valuesDF['NEDC-L error [%]'].count(),2), 'UDC-L [%]':round(valuesDF['UDC-L error [%]'].count(),2), 'EUDC-L [%]':round(valuesDF['EUDC-L error [%]'].count(),2)})
errorsDF.columns.name='ALL'
errorsDF
Out[10]:
ALL NEDC-H [%] UDC-H [%] EUDC-H [%] NEDC-L [%] UDC-L [%] EUDC-L [%]
Averages -0.84 -2.38 0.5 -0.97 -2.54 0.37
StdDev 2.47 3.75 2.23 2.66 3.75 2.71
Minimum -6.02 -13.57 -2.81 -5.92 -13.48 -2.83
Maximum 9.96 7.73 16.37 14.25 9.37 21.48
Cases in ±4% 89.6 57.3 96.4 91.9 56.3 98
Cases in ±2.5% 59.1 26.7 83.3 58.3 26.2 92.3
P75-P25 3.59 4.66 2.76 2.93 4 1.98
Count 1463 1463 1463 1463 1463 1463
In [11]:
#GASOLINES dataframe with the NECD, UDC, EUDC error statistics
GerrorsDF = pd.DataFrame(index=['Averages','StdDev','Minimum','Maximum','Cases in ±4%','Cases in ±2.5%'], columns=['NEDC-H [%]','UDC-H [%]', 'EUDC-H [%]','NEDC-L [%]','UDC-L [%]', 'EUDC-L [%]'])
GerrorsDF.loc['Averages'] = pd.Series({'NEDC-H [%]':round(Gasolines['NEDC-H error [%]'].mean(),2), 'UDC-H [%]':round(Gasolines['UDC-H error [%]'].mean(),2), 'EUDC-H [%]':round(Gasolines['EUDC-H error [%]'].mean(),2),'NEDC-L [%]':round(Gasolines['NEDC-L error [%]'].mean(),2), 'UDC-L [%]':round(Gasolines['UDC-L error [%]'].mean(),2), 'EUDC-L [%]':round(Gasolines['EUDC-L error [%]'].mean(),2)})
GerrorsDF.loc['StdDev'] = pd.Series({'NEDC-H [%]':round(Gasolines['NEDC-H error [%]'].std(),2), 'UDC-H [%]':round(Gasolines['UDC-H error [%]'].std(),2), 'EUDC-H [%]':round(Gasolines['EUDC-H error [%]'].std(),2),'NEDC-L [%]':round(Gasolines['NEDC-L error [%]'].std(),2), 'UDC-L [%]':round(Gasolines['UDC-L error [%]'].std(),2), 'EUDC-L [%]':round(Gasolines['EUDC-L error [%]'].std(),2)})
GerrorsDF.loc['Minimum'] = pd.Series({'NEDC-H [%]':round(Gasolines['NEDC-H error [%]'].min(),2), 'UDC-H [%]':round(Gasolines['UDC-H error [%]'].min(),2), 'EUDC-H [%]':round(Gasolines['EUDC-H error [%]'].min(),2),'NEDC-L [%]':round(Gasolines['NEDC-L error [%]'].min(),2), 'UDC-L [%]':round(Gasolines['UDC-L error [%]'].min(),2), 'EUDC-L [%]':round(Gasolines['EUDC-L error [%]'].min(),2)})
GerrorsDF.loc['Maximum'] = pd.Series({'NEDC-H [%]':round(Gasolines['NEDC-H error [%]'].max(),2), 'UDC-H [%]':round(Gasolines['UDC-H error [%]'].max(),2), 'EUDC-H [%]':round(Gasolines['EUDC-H error [%]'].max(),2),'NEDC-L [%]':round(Gasolines['NEDC-L error [%]'].max(),2), 'UDC-L [%]':round(Gasolines['UDC-L error [%]'].max(),2), 'EUDC-L [%]':round(Gasolines['EUDC-L error [%]'].max(),2)})
GerrorsDF.loc['Cases in ±4%'] = pd.Series({'NEDC-H [%]':round(sum(abs(Gasolines['NEDC-H error [%]'])<4)/len(Gasolines['NEDC-H error [%]'])*100,1), 'UDC-H [%]':round(sum(abs(Gasolines['UDC-H error [%]'])<4)/len(Gasolines['UDC-H error [%]'])*100,1), 'EUDC-H [%]':round(sum(abs(Gasolines['EUDC-H error [%]'])<4)/len(Gasolines['EUDC-H error [%]'])*100,1),'NEDC-L [%]':round(sum(abs(Gasolines['NEDC-L error [%]'])<4)/len(Gasolines['NEDC-L error [%]'])*100,1), 'UDC-L [%]':round(sum(abs(Gasolines['UDC-L error [%]'])<4)/len(Gasolines['UDC-L error [%]'])*100,1), 'EUDC-L [%]':round(sum(abs(Gasolines['EUDC-L error [%]'])<4)/len(Gasolines['EUDC-L error [%]'])*100,1)})
GerrorsDF.loc['Cases in ±2.5%'] = pd.Series({'NEDC-H [%]':round(sum(abs(Gasolines['NEDC-H error [%]'])<2.5)/len(Gasolines['NEDC-H error [%]'])*100,1), 'UDC-H [%]':round(sum(abs(Gasolines['UDC-H error [%]'])<2.5)/len(Gasolines['UDC-H error [%]'])*100,1), 'EUDC-H [%]':round(sum(abs(Gasolines['EUDC-H error [%]'])<2.5)/len(Gasolines['EUDC-H error [%]'])*100,1),'NEDC-L [%]':round(sum(abs(Gasolines['NEDC-L error [%]'])<2.5)/len(Gasolines['NEDC-L error [%]'])*100,1), 'UDC-L [%]':round(sum(abs(Gasolines['UDC-L error [%]'])<2.5)/len(Gasolines['UDC-L error [%]'])*100,1), 'EUDC-L [%]':round(sum(abs(Gasolines['EUDC-L error [%]'])<2.5)/len(Gasolines['EUDC-L error [%]'])*100,1)})
GerrorsDF.loc['P75-P25'] = pd.Series({'NEDC-H [%]':round(Gasolines['NEDC-H error [%]'].quantile(0.75)-Gasolines['NEDC-H error [%]'].quantile(0.25),2), 'UDC-H [%]':round(Gasolines['UDC-H error [%]'].quantile(0.75)-Gasolines['UDC-H error [%]'].quantile(0.25),2), 'EUDC-H [%]':round(Gasolines['EUDC-H error [%]'].quantile(0.75)-Gasolines['EUDC-H error [%]'].quantile(0.25),2),'NEDC-L [%]':round(Gasolines['NEDC-L error [%]'].quantile(0.75)-Gasolines['NEDC-L error [%]'].quantile(0.25),2), 'UDC-L [%]':round(Gasolines['UDC-L error [%]'].quantile(0.75)-Gasolines['UDC-L error [%]'].quantile(0.25),2), 'EUDC-L [%]':round(Gasolines['EUDC-L error [%]'].quantile(0.75)-Gasolines['EUDC-L error [%]'].quantile(0.25),2)})
GerrorsDF.loc['Count'] = pd.Series({'NEDC-H [%]':round(Gasolines['NEDC-H error [%]'].count(),2), 'UDC-H [%]':round(Gasolines['UDC-H error [%]'].count(),2), 'EUDC-H [%]':round(Gasolines['EUDC-H error [%]'].count(),2),'NEDC-L [%]':round(Gasolines['NEDC-L error [%]'].count(),2), 'UDC-L [%]':round(Gasolines['UDC-L error [%]'].count(),2), 'EUDC-L [%]':round(Gasolines['EUDC-L error [%]'].count(),2)})
GerrorsDF.columns.name='GASOLINES'
GerrorsDF
Out[11]:
GASOLINES NEDC-H [%] UDC-H [%] EUDC-H [%] NEDC-L [%] UDC-L [%] EUDC-L [%]
Averages -1.44 -3.62 0.43 -1.14 -3.32 0.71
StdDev 2.29 3.23 2.59 2.83 3.61 3.28
Minimum -6.02 -13.57 -2.81 -5.92 -13.48 -2.33
Maximum 9.96 7.73 16.37 14.25 9.37 21.48
Cases in ±4% 88.2 50.5 96.1 89.4 53 96.5
Cases in ±2.5% 57.9 23.7 82.4 58.6 26.2 92.3
P75-P25 3.16 3.63 2.86 2.42 3.29 1.81
Count 840 840 840 840 840 840
In [12]:
#DIESELS dataframe with the NECD, UDC, EUDC error statistics
DerrorsDF = pd.DataFrame(index=['Averages','StdDev','Minimum','Maximum','Cases in ±4%','Cases in ±2.5%'], columns=['NEDC-H [%]','UDC-H [%]', 'EUDC-H [%]','NEDC-L [%]','UDC-L [%]', 'EUDC-L [%]'])
DerrorsDF.loc['Averages'] = pd.Series({'NEDC-H [%]':round(Diesels['NEDC-H error [%]'].mean(),2), 'UDC-H [%]':round(Diesels['UDC-H error [%]'].mean(),2), 'EUDC-H [%]':round(Diesels['EUDC-H error [%]'].mean(),2),'NEDC-L [%]':round(Diesels['NEDC-L error [%]'].mean(),2), 'UDC-L [%]':round(Diesels['UDC-L error [%]'].mean(),2), 'EUDC-L [%]':round(Diesels['EUDC-L error [%]'].mean(),2)})
DerrorsDF.loc['StdDev'] = pd.Series({'NEDC-H [%]':round(Diesels['NEDC-H error [%]'].std(),2), 'UDC-H [%]':round(Diesels['UDC-H error [%]'].std(),2), 'EUDC-H [%]':round(Diesels['EUDC-H error [%]'].std(),2),'NEDC-L [%]':round(Diesels['NEDC-L error [%]'].std(),2), 'UDC-L [%]':round(Diesels['UDC-L error [%]'].std(),2), 'EUDC-L [%]':round(Diesels['EUDC-L error [%]'].std(),2)})
DerrorsDF.loc['Minimum'] = pd.Series({'NEDC-H [%]':round(Diesels['NEDC-H error [%]'].min(),2), 'UDC-H [%]':round(Diesels['UDC-H error [%]'].min(),2), 'EUDC-H [%]':round(Diesels['EUDC-H error [%]'].min(),2),'NEDC-L [%]':round(Diesels['NEDC-L error [%]'].min(),2), 'UDC-L [%]':round(Diesels['UDC-L error [%]'].min(),2), 'EUDC-L [%]':round(Diesels['EUDC-L error [%]'].min(),2)})
DerrorsDF.loc['Maximum'] = pd.Series({'NEDC-H [%]':round(Diesels['NEDC-H error [%]'].max(),2), 'UDC-H [%]':round(Diesels['UDC-H error [%]'].max(),2), 'EUDC-H [%]':round(Diesels['EUDC-H error [%]'].max(),2),'NEDC-L [%]':round(Diesels['NEDC-L error [%]'].max(),2), 'UDC-L [%]':round(Diesels['UDC-L error [%]'].max(),2), 'EUDC-L [%]':round(Diesels['EUDC-L error [%]'].max(),2)})
DerrorsDF.loc['Cases in ±4%'] = pd.Series({'NEDC-H [%]':round(sum(abs(Diesels['NEDC-H error [%]'])<4)/len(Diesels['NEDC-H error [%]'])*100,1), 'UDC-H [%]':round(sum(abs(Diesels['UDC-H error [%]'])<4)/len(Diesels['UDC-H error [%]'])*100,1), 'EUDC-H [%]':round(sum(abs(Diesels['EUDC-H error [%]'])<4)/len(Diesels['EUDC-H error [%]'])*100,1),'NEDC-L [%]':round(sum(abs(Diesels['NEDC-L error [%]'])<4)/len(Diesels['NEDC-L error [%]'])*100,1), 'UDC-L [%]':round(sum(abs(Diesels['UDC-L error [%]'])<4)/len(Diesels['UDC-L error [%]'])*100,1), 'EUDC-L [%]':round(sum(abs(Diesels['EUDC-L error [%]'])<4)/len(Diesels['EUDC-L error [%]'])*100,1)})
DerrorsDF.loc['Cases in ±2.5%'] = pd.Series({'NEDC-H [%]':round(sum(abs(Diesels['NEDC-H error [%]'])<2.5)/len(Diesels['NEDC-H error [%]'])*100,1), 'UDC-H [%]':round(sum(abs(Diesels['UDC-H error [%]'])<2.5)/len(Diesels['UDC-H error [%]'])*100,1), 'EUDC-H [%]':round(sum(abs(Diesels['EUDC-H error [%]'])<2.5)/len(Diesels['EUDC-H error [%]'])*100,1),'NEDC-L [%]':round(sum(abs(Diesels['NEDC-L error [%]'])<2.5)/len(Diesels['NEDC-L error [%]'])*100,1), 'UDC-L [%]':round(sum(abs(Diesels['UDC-L error [%]'])<2.5)/len(Diesels['UDC-L error [%]'])*100,1), 'EUDC-L [%]':round(sum(abs(Diesels['EUDC-L error [%]'])<2.5)/len(Diesels['EUDC-L error [%]'])*100,1)})
DerrorsDF.loc['P75-P25'] = pd.Series({'NEDC-H [%]':round(Diesels['NEDC-H error [%]'].quantile(0.75)-Diesels['NEDC-H error [%]'].quantile(0.25),2), 'UDC-H [%]':round(Diesels['UDC-H error [%]'].quantile(0.75)-Diesels['UDC-H error [%]'].quantile(0.25),2), 'EUDC-H [%]':round(Diesels['EUDC-H error [%]'].quantile(0.75)-Diesels['EUDC-H error [%]'].quantile(0.25),2),'NEDC-L [%]':round(Diesels['NEDC-L error [%]'].quantile(0.75)-Diesels['NEDC-L error [%]'].quantile(0.25),2), 'UDC-L [%]':round(Diesels['UDC-L error [%]'].quantile(0.75)-Diesels['UDC-L error [%]'].quantile(0.25),2), 'EUDC-L [%]':round(Diesels['EUDC-L error [%]'].quantile(0.75)-Diesels['EUDC-L error [%]'].quantile(0.25),2)})
DerrorsDF.loc['Count'] = pd.Series({'NEDC-H [%]':round(Diesels['NEDC-H error [%]'].count(),2), 'UDC-H [%]':round(Diesels['UDC-H error [%]'].count(),2), 'EUDC-H [%]':round(Diesels['EUDC-H error [%]'].count(),2),'NEDC-L [%]':round(Diesels['NEDC-L error [%]'].count(),2), 'UDC-L [%]':round(Diesels['UDC-L error [%]'].count(),2), 'EUDC-L [%]':round(Diesels['EUDC-L error [%]'].count(),2)})
DerrorsDF.columns.name='DIESELS'
DerrorsDF
Out[12]:
DIESELS NEDC-H [%] UDC-H [%] EUDC-H [%] NEDC-L [%] UDC-L [%] EUDC-L [%]
Averages -0.03 -0.72 0.59 -0.74 -1.47 -0.1
StdDev 2.47 3.76 1.62 2.4 3.67 1.56
Minimum -5.34 -9.01 -2.58 -5.38 -8.18 -2.83
Maximum 4.65 7.13 4.42 3.95 6.22 3.8
Cases in ±4% 91.5 66.5 97 95.3 60.7 100
Cases in ±2.5% 60.7 30.7 84.6 57.9 26.3 92.3
P75-P25 4.35 7.19 2.77 4.11 6.95 2.49
Count 623 623 623 623 623 623

Distribution of the NEDC, UDC and EUDC errors [%]

In [13]:
mydict = ([('NEDC', 0), ('UDC', 1), ('EUDC', 2)])
mydict = collections.OrderedDict(mydict)
for cycle in mydict:
    if cycle == 'NEDC':
        boxcolor = 'green'
    elif cycle == 'UDC':
        boxcolor = 'blue'
    else:
        boxcolor = 'red'
    # Create a figure instance
    fig = plt.figure(1, figsize=(14, 7))
    # Create an axes instance
    ax = fig.add_subplot(111)
    hist = valuesDF[cycle+'-H error [%]'].hist(bins=np.arange(min(valuesDF['UDC-H error [%]']), max(valuesDF['UDC-H error [%]']) + 0.5, 0.5), color=boxcolor, label = 'High', ec='black')
    hist = valuesDF[cycle+'-L error [%]'].hist(bins=np.arange(min(valuesDF['UDC-L error [%]']), max(valuesDF['UDC-L error [%]']) + 0.5, 0.5), color=boxcolor, alpha=0.5, label='Low', ec='black')
    hist.set_xlabel(cycle+" error [%]",fontsize=14)
    hist.set_ylabel("frequency",fontsize=14)
    hist.set_ylim(0,300)
    plt.title(cycle+' CO$_2$ emission error distribution', fontsize=20)
    plt.ylabel("frequency",fontsize=18)
    plt.tick_params(axis='x', which='major', labelsize=16)
    plt.tick_params(axis='y', which='major', labelsize=16)
    ax.get_xaxis().tick_bottom()
    ax.get_yaxis().tick_left()
    ax.set_xlim(-15, 15)
    plt.legend()
    plt.show()

Comparative emission error per driving cycle (%)

In [14]:
#Alternatively show boxplots
toboxplot = [valuesDF['NEDC-H error [%]'],valuesDF['NEDC-L error [%]'],valuesDF['UDC-H error [%]'],valuesDF['UDC-L error [%]'],
            valuesDF['EUDC-H error [%]'],valuesDF['EUDC-L error [%]']]
# Create a figure instance
fig = plt.figure(1, figsize=(14, 7))
# Create an axes instance
ax = fig.add_subplot(111)
# Create the boxplot with fill color
bp = ax.boxplot(toboxplot, sym='', patch_artist=True, whis=10000, showmeans=True, meanprops=(dict(marker='o',markerfacecolor='yellow')))
for box in bp['boxes']:
    # change outline color
    box.set( color='black', linewidth=1)
    # change fill color
    box.set( facecolor = '#b78adf' )
    ## Custom x-axis labels
ax.set_xticklabels(['NEDC-H','NEDC-L', 'UDC-H','UDC-L','EUDC-H','EUDC-L'],fontsize=20)
## Remove top axes and right axes ticks
ax.get_xaxis().tick_bottom()
ax.get_yaxis().tick_left()
#Set y axis title
plt.title('CO$_2$ emission error by driving cycle', fontsize=20)
plt.ylabel("error [%]",fontsize=18)
plt.tick_params(axis='y', which='major', labelsize=16)
ax.set_ylim(-25, 25)
plt.setp(bp['medians'], color = 'purple', linewidth = 2)
plt.show()
print('The purple box represents the 1st and 3rd quartile.\nThe dark purple line is the median.\nThe yellow dot is the mean.\nthe whiskers show the min and max values.')
The purple box represents the 1st and 3rd quartile.
The dark purple line is the median.
The yellow dot is the mean.
the whiskers show the min and max values.

Error statistics per technology type

In [15]:
#Print a dictionary with the tested technologies and their identification codes
tec = pd.DataFrame(index=['Base case','Gear configuration A','Gear configuration B','No Start/Stop','No Break energy recuperation','Variable valve lifting','Direct injection/Multipoint injection','No Lean Burn','Thermal management'])
tec['Technology code'] = ['BC','GCA','GCB','NOSS','NOBERS','VVL','DI/MPI','NOLB','ThM']
tec.columns.name='Technology type'
tec
Out[15]:
Technology type Technology code
Base case BC
Gear configuration A GCA
Gear configuration B GCB
No Start/Stop NOSS
No Break energy recuperation NOBERS
Variable valve lifting VVL
Direct injection/Multipoint injection DI/MPI
No Lean Burn NOLB
Thermal management ThM
In [16]:
#Function that assigns the number of case to the specific technology tested for each vehicle model
def assign_technol_perCarAndCase(df):
    #looks for the case # in the input file and assigns a technology
    df_basecase = df[valuesDF['Case'] <= 27]
    df_basecase.loc[:,'Tecno'] = 'BC'
    #some vehicles have more possible technologies than others (extrashort, short, long, extralong) and an additional technology assignment is performed for the groups that have it
    In_extrashort = (valuesDF['Model'] == 'Vehicle05')
    In_short = (valuesDF['Model'] == 'Vehicle06')|(valuesDF['Model'] == 'Vehicle08')| (valuesDF['Model'] == 'Vehicle02')| (valuesDF['Model'] == 'Vehicle04')
    In_long = (valuesDF['Model'] == 'Vehicle01') | (valuesDF['Model'] == 'Vehicle07')
    In_extralong = (valuesDF['Model'] == 'Vehicle03')
    #assign technologies per car group
    I_gbc1 = (valuesDF['Case'] >= 28) & (valuesDF['Case'] <= 54)
    I_gbcA = (I_gbc1 & In_short) | (I_gbc1 & In_long) | (I_gbc1 & In_extralong)
    df_gbcA = df[I_gbcA]
    df_gbcA.loc[:,'Tecno'] = 'GCA'
    I_gbc2 = (valuesDF['Case'] >= 55) & (valuesDF['Case'] <= 81)
    I_gbcB = (I_gbc2 & In_short) |(I_gbc2 & In_long) | (I_gbc2 & In_extralong)
    df_gbcB = df[I_gbcB]
    df_gbcB.loc[:,'Tecno'] = 'GCB'
    I_noss_reg = (valuesDF['Case'] >= 82) & (valuesDF['Case'] <= 108)
    I_noss_extrashort = (valuesDF['Case'] >= 28) & (valuesDF['Case'] <= 54)
    I_noss = (I_noss_extrashort & In_extrashort) | (I_noss_reg & In_short)| (I_noss_reg & In_long) | (I_noss_reg & In_extralong)
    df_noss = df[I_noss]
    df_noss.loc[:,'Tecno'] = 'NOSS'
    I_nobers_reg = (valuesDF['Case'] >= 109) & (valuesDF['Case'] <= 135)
    I_nobers_extrashort = (valuesDF['Case'] >= 55) & (valuesDF['Case'] <= 81)
    I_nobers = (I_nobers_extrashort & In_extrashort) | (I_nobers_reg & In_short)| (I_nobers_reg & In_long) | (I_nobers_reg & In_extralong)
    df_nobers = df[I_nobers]
    df_nobers.loc[:,'Tecno'] = 'NOBERS'
    I_vvl_reg = (valuesDF['Case'] >= 136) & (valuesDF['Case'] <= 162)
    I_vvl_extrashort = (valuesDF['Case'] >= 82) & (valuesDF['Case'] <= 108)
    I_vvl = (I_vvl_extrashort & In_extrashort) | (I_vvl_reg & In_long)| (I_vvl_reg & In_extralong)
    df_vvl = df[I_vvl]
    df_vvl.loc[:,'Tecno'] = 'VVL'
    I_dimpi_reg = (valuesDF['Case'] >= 163) & (valuesDF['Case'] <= 189)
    I_dimpi_extrashort = (valuesDF['Case'] >= 109) & (valuesDF['Case'] <= 135)
    I_dimpi = (I_dimpi_extrashort & In_extrashort) | (I_dimpi_reg & In_long)| (I_dimpi_reg & In_extralong)
    df_dimpi = df[I_dimpi]
    df_dimpi.loc[:,'Tecno'] = 'DI/MPI'
    I_nolb_extralong = (valuesDF['Case'] >= 190) & (valuesDF['Case'] <= 216)
    I_nolb = (I_nolb_extralong & In_extralong)
    df_nolb = df[I_nolb]
    df_nolb.loc[:,'Tecno'] = 'NOLB'
    I_extrashort_tm = (valuesDF['Case'] >= 136)
    I_short_tm = (valuesDF['Case'] >= 136)
    I_long_tm = (valuesDF['Case'] >= 190)
    I_extralong_tm = (valuesDF['Case'] >= 244)
    I_tm = (In_extrashort & I_extrashort_tm) | (In_short & I_short_tm)|(In_long & I_long_tm) | (In_extralong & I_extralong_tm)
    df_tm = df[I_tm]
    df_tm.loc[:,'Tecno'] = 'ThM'
    #Append to the original DF a column with the technology IDcode
    pd.options.mode.chained_assignment = None  # default='warn'
    bigdata = pd.concat([df_basecase,df_gbcA,df_gbcB,df_noss,df_nobers,df_vvl,df_dimpi,df_nolb,df_tm], ignore_index=False)
    return bigdata
In [17]:
#Plot the NEDC errors per technology type in a boxplot
tech = assign_technol_perCarAndCase(valuesDF)
techBC = tech[tech['Tecno'] == 'BC']
techGCA = tech[tech['Tecno'] == 'GCA']
techGCB = tech[tech['Tecno'] == 'GCB']
techNOSS = tech[tech['Tecno'] == 'NOSS']
techBERS = tech[tech['Tecno'] == 'NOBERS']
techVVL = tech[tech['Tecno'] == 'VVL']
techDIMPI = tech[tech['Tecno'] == 'DI/MPI']
techNOLB = tech[tech['Tecno'] == 'NOLB']
techThM = tech[tech['Tecno'] == 'ThM']
mydict = ([('NEDC', 0), ('UDC', 1), ('EUDC', 2)])
mydict = collections.OrderedDict(mydict)
for cycle in mydict:
    techboxplot = [techBC[cycle+'-H error [%]'],techGCA[cycle+'-H error [%]'],techGCB[cycle+'-H error [%]'],techNOSS[cycle+'-H error [%]'],techBERS[cycle+'-H error [%]'],techVVL[cycle+'-H error [%]'],techDIMPI[cycle+'-H error [%]'],techNOLB[cycle+'-H error [%]'],techThM[cycle+'-H error [%]']]
    if cycle == 'NEDC':
        boxcolor = 'green'
    elif cycle == 'UDC':
        boxcolor = 'blue'
    else:
        boxcolor = 'red'
    # Create a figure instance
    fig = plt.figure(1, figsize=(14, 7))
    # Create an axes instance
    ax = fig.add_subplot(111)
    # Create the boxplot with fill color
    bp = ax.boxplot(techboxplot, sym='', patch_artist=True, whis=10000, showmeans=True, meanprops=(dict(marker='o',markerfacecolor='yellow')))
    for box in bp['boxes']:
        # change outline color
        box.set( color='black', linewidth=1)
        # change fill color
        box.set(facecolor = boxcolor)            
        ## Custom x-axis labels
    ax.set_xticklabels(['BC', 'GCA', 'GCB','NOSS','NOBERS','VVL','DI/MPI','NOLB','ThM'],fontsize=20)
    ## Remove top axes and right axes ticks
    ax.get_xaxis().tick_bottom()
    ax.get_yaxis().tick_left()
    #Set y axis title
    plt.title(cycle+' CO$_2$ emission error by technology type', fontsize=20)
    plt.ylabel("error [%]",fontsize=18)
    plt.tick_params(axis='y', which='major', labelsize=18)
    ax.set_ylim(-20, 20)
    plt.setp(bp['medians'], color = 'purple', linewidth = 2)
    plt.show()
    print('The green box represents the 1st and 3rd quartile.\nThe dark purple line is the median.\nThe yellow dot is the mean.\nthe whiskers show the min and max values.')
    print('\nDescriptive statistics for '+cycle+' CO2 emission error per technology type')
    grouped = tech.groupby('Tecno')
    gmean = grouped[cycle+'-H error [%]'].mean()
    gsem = grouped[cycle+'-H error [%]'].sem()
    gmedian = grouped[cycle+'-H error [%]'].median()
    gstd = grouped[cycle+'-H error [%]'].std()
    gvar = grouped[cycle+'-H error [%]'].var()
    gskew = grouped[cycle+'-H error [%]'].skew()
    grange = (grouped[cycle+'-H error [%]'].max()-grouped[cycle+'-H error [%]'].min())
    gmin = grouped[cycle+'-H error [%]'].min()
    gmax = grouped[cycle+'-H error [%]'].max()
    gsum = grouped[cycle+'-H error [%]'].sum()
    gcount = grouped[cycle+'-H error [%]'].count()
    gCI95 = 2*grouped[cycle+'-H error [%]'].sem()
    errorsTec = pd.DataFrame(index=['Averages','StdError','Median','StdDev','Variance','Kurtosis','Skweness','Range','Minimum','Maximum','Sum','Count','Confidence level (95%)'], columns=['BC','GCA', 'GCB','NOSS','NOBERS','VVL','DI/MPI','NOLB','ThM'])
    errorsTec.loc['Averages'] = pd.Series.round(gmean,2)
    errorsTec.loc['StdError'] = pd.Series.round(gsem,2)
    errorsTec.loc['Median'] = pd.Series.round(gmedian,2)
    errorsTec.loc['StdDev'] = pd.Series.round(gstd,2)
    errorsTec.loc['Variance'] = pd.Series.round(gvar,2)
    errorsTec.loc['Kurtosis'] = [round(techBC[cycle+'-H error [%]'].kurtosis(),2),round(techGCA[cycle+'-H error [%]'].kurtosis(),2),round(techGCB[cycle+'-H error [%]'].kurtosis(),2),round(techNOSS[cycle+'-H error [%]'].kurtosis(),2),round(techBERS[cycle+'-H error [%]'].kurtosis(),2),round(techVVL[cycle+'-H error [%]'].kurtosis(),2),round(techDIMPI[cycle+'-H error [%]'].kurtosis(),2),round(techNOLB[cycle+'-H error [%]'].kurtosis(),2),round(techThM[cycle+'-H error [%]'].kurtosis(),2)]
    errorsTec.loc['Skweness'] = pd.Series.round(gskew,2)
    errorsTec.loc['Range'] = pd.Series.round(grange,2)
    errorsTec.loc['Minimum'] = pd.Series.round(gmin,2)
    errorsTec.loc['Maximum'] = pd.Series.round(gmax,2)
    errorsTec.loc['Sum'] = pd.Series.round(gsum)
    errorsTec.loc['Count'] = pd.Series.round(gcount)
    errorsTec.loc['Confidence level (95%)'] = pd.Series.round(gCI95,2)
    errorsTec.columns.name=cycle+' error [%]'
    display(errorsTec)
The green box represents the 1st and 3rd quartile.
The dark purple line is the median.
The yellow dot is the mean.
the whiskers show the min and max values.

Descriptive statistics for NEDC CO2 emission error per technology type
NEDC error [%] BC GCA GCB NOSS NOBERS VVL DI/MPI NOLB ThM
Averages -0.8 0.22 0.1 -0.15 -2.92 -1.61 -1.93 -2.33 -0.02
StdError 0.13 0.16 0.19 0.16 0.14 0.16 0.13 0.1 0.19
Median -1.34 0.1 0.91 -0.63 -3.69 -1.85 -2.25 -2.24 -1.14
StdDev 2.01 2.25 2.41 2.4 2.02 1.67 1.32 0.51 2.84
Variance 4.06 5.06 5.8 5.74 4.08 2.79 1.73 0.26 8.05
Kurtosis -0.68 -0.98 -1.14 -0.9 -0.47 -1.3 0.39 -0.89 0.18
Skweness 0.58 0.25 -0.51 0.6 0.78 0.29 0.88 -0.23 0.91
Range 7.51 7.95 7.74 7.79 7.62 6.15 5.99 1.98 13.72
Minimum -3.97 -3.56 -4.56 -3.14 -6.02 -3.9 -4.16 -3.39 -3.76
Maximum 3.53 4.4 3.18 4.65 1.6 2.25 1.83 -1.4 9.96
Sum -179 42 17 -31 -628 -174 -209 -63 -4
Count 224 189 162 216 215 108 108 27 214
Confidence level (95%) 0.27 0.33 0.38 0.33 0.28 0.32 0.25 0.19 0.39
The green box represents the 1st and 3rd quartile.
The dark purple line is the median.
The yellow dot is the mean.
the whiskers show the min and max values.

Descriptive statistics for UDC CO2 emission error per technology type
UDC error [%] BC GCA GCB NOSS NOBERS VVL DI/MPI NOLB ThM
Averages -2.15 -0.77 -0.19 -0.91 -5.75 -3.98 -3.92 -3.72 -2.05
StdError 0.2 0.26 0.33 0.27 0.22 0.18 0.18 0.2 0.21
Median -2.92 -1.32 -0.28 -2.03 -6.07 -4.37 -3.63 -3.62 -2.73
StdDev 3.05 3.59 4.16 3.99 3.27 1.88 1.83 1.02 3.07
Variance 9.32 12.85 17.29 15.96 10.67 3.53 3.37 1.05 9.43
Kurtosis -0.41 -1.18 -1.19 -0.79 -0.51 -0.68 -0.45 -1.26 -0.41
Skweness 0.63 0.16 -0.12 0.81 -0.05 0.45 0.12 -0.21 0.7
Range 11.76 13.18 15.46 14.24 13.79 7.91 8.95 3.43 11.78
Minimum -7.38 -7.27 -7.73 -7.11 -13.57 -7.19 -7.44 -5.49 -7.26
Maximum 4.38 5.91 7.73 7.13 0.22 0.72 1.52 -2.06 4.52
Sum -482 -146 -31 -196 -1237 -430 -424 -100 -438
Count 224 189 162 216 215 108 108 27 214
Confidence level (95%) 0.41 0.52 0.65 0.54 0.45 0.36 0.35 0.39 0.42
The green box represents the 1st and 3rd quartile.
The dark purple line is the median.
The yellow dot is the mean.
the whiskers show the min and max values.

Descriptive statistics for EUDC CO2 emission error per technology type
EUDC error [%] BC GCA GCB NOSS NOBERS VVL DI/MPI NOLB ThM
Averages 0.35 1.13 0.5 0.7 -0.57 0.36 -0.28 -1 1.61
StdError 0.11 0.12 0.13 0.11 0.1 0.18 0.15 0.05 0.27
Median 0.03 0.74 0.05 0.34 -1.08 0.35 -0.65 -0.92 0.08
StdDev 1.57 1.65 1.6 1.65 1.49 1.87 1.54 0.25 3.98
Variance 2.48 2.73 2.56 2.72 2.23 3.48 2.37 0.06 15.82
Kurtosis -1.07 -0.81 -0.18 -1.28 -0.79 -1.26 -0.17 -0.91 3.15
Skweness 0.28 0.7 0.54 0.27 0.52 -0.12 0.95 -0.49 1.94
Range 6.18 5.54 8.06 5.96 5.72 6.2 5.48 0.82 18.32
Minimum -2.16 -1.12 -1.71 -1.81 -2.81 -2.64 -2.32 -1.47 -1.95
Maximum 4.01 4.42 6.34 4.15 2.9 3.56 3.16 -0.66 16.37
Sum 79 214 81 151 -122 39 -30 -27 345
Count 224 189 162 216 215 108 108 27 214
Confidence level (95%) 0.21 0.24 0.25 0.22 0.2 0.36 0.3 0.09 0.54

Section 2. Performance of the model. Statistics per vehicle model and case test.

Glossary of vehicle models and number of test cases considered in the report

In [18]:
mod_cases_stats = valuesDF.groupby(['Model'],as_index=False).count() 
cols = mod_cases_stats.columns.tolist()
cols = cols[-1:-1] + cols[:2]
mod_cases_stats = mod_cases_stats[cols]
mod_cases_stats
Out[18]:
Model NEDC
0 Vehicle01 216
1 Vehicle02 163
2 Vehicle03 244
3 Vehicle04 135
4 Vehicle05 163
5 Vehicle06 163
6 Vehicle07 217
7 Vehicle08 162

NEDC, UDC, and EUDC CO$_2$ emission error per vehicle model

In [19]:
#In order to create statistic tables and plots for each model car, a numeric car ID 'cid' has to be assigned to each vehicle
tech = assign_technol_perCarAndCase(valuesDF)
Carlist = list(sorted(tech['Model'].unique()))
Cidlist = list(range(len(Carlist)))
tech.cid = tech['Model'].replace(Carlist, Cidlist, regex = True)
tech['cod'] = tech.cid
dictecnos = {'BC':'o', 'GCA':'s', 'GCB':'v', 'NOSS':'p','NOBERS':'D','VVL':'4','DI/MPI':'+','NOLB':'h','ThM':'*'}
#Create a table with the error statistics for each car model
for x in Carlist:
    Car = tech[tech['Model'] == x]
    grouped = Car.groupby('Tecno')
    CarDF = pd.DataFrame(index=['Averages','Median', 'StdDev'], columns=['NEDC [gCO$_2$ km$^{-1}$]','UDC [gCO$_2$ km$^{-1}$]', 'EUDC [gCO$_2$ km$^{-1}$]'])
    CarDF.loc['Averages'] = pd.Series({'NEDC [gCO$_2$ km$^{-1}$]':round(Car.dNEDC.mean(),2), 'UDC [gCO$_2$ km$^{-1}$]':round(Car.dUDC.mean(),2), 'EUDC [gCO$_2$ km$^{-1}$]':round(Car.dEUDC.mean(),2)})
    CarDF.loc['Median'] = pd.Series({'NEDC [gCO$_2$ km$^{-1}$]':round(Car.dNEDC.median(),2), 'UDC [gCO$_2$ km$^{-1}$]':round(Car.dUDC.median(),2), 'EUDC [gCO$_2$ km$^{-1}$]':round(Car.dEUDC.median(),2)})
    CarDF.loc['StdDev'] = pd.Series({'NEDC [gCO$_2$ km$^{-1}$]':round(Car.dNEDC.std(),2), 'UDC [gCO$_2$ km$^{-1}$]':round(Car.dUDC.std(),2), 'EUDC [gCO$_2$ km$^{-1}$]':round(Car.dEUDC.std(),2)})
    CarDF.columns.name=Car.iat[0,13]
    display(CarDF)
    pCarDF = pd.DataFrame(index=['Averages','Median', 'StdDev'], columns=['NEDC-H [%]','NEDC-L [%]'])
    pCarDF.loc['Averages'] = pd.Series({'NEDC-H [%]':round(Car['NEDC-H error [%]'].mean(),2), 'NEDC-L [%]':round(Car['NEDC-L error [%]'].mean(),2)})
    pCarDF.loc['Median'] = pd.Series({'NEDC-H [%]':round(Car['NEDC-H error [%]'].median(),2), 'NEDC-L [%]':round(Car['NEDC-L error [%]'].median(),2)})
    pCarDF.loc['StdDev'] = pd.Series({'NEDC-H [%]':round(Car['NEDC-H error [%]'].std(),2), 'NEDC-L [%]':round(Car['NEDC-L error [%]'].std(),2)})
    pCarDF.columns.name=Car.iat[0,13]
    display(pCarDF)
    #plot the CO2 emission error histogram per vehicle model and cycle
    mydict = ([('NEDC', 0), ('UDC', 1), ('EUDC', 2)])
    mydict = collections.OrderedDict(mydict)
    for cycle in mydict:
        if cycle == 'NEDC':
            boxcolor = 'green'
        elif cycle == 'UDC':
            boxcolor = 'blue'
        else:
            boxcolor = 'red'
        fig = plt.figure(1, figsize=(14, 7))
        plt.title(Car.iat[0,13],fontsize=20)
        plot = fig.add_subplot(111)
        plot.tick_params(axis='x', which='major', labelsize=14)
        plot.tick_params(axis='y', which='major', labelsize=14)
        plot.set_xlim(-15, 15)
        plot.get_xaxis().tick_bottom()
        plot.get_yaxis().tick_left()
        car_hist = Car[cycle+'-H error [%]'].hist(bins=25, color=boxcolor, ec='black')
        car_hist.set_xlabel(cycle+" CO$_2$ emission error [%]",fontsize=20)
        car_hist.set_ylabel("frequency",fontsize=20)
        plt.show()
    #plot the emission error per case, model, and cycle
        fig = plt.figure(1, figsize=(14, 7))
        plt.title(Car.iat[0,13],fontsize=20)
        plot = fig.add_subplot(111)
        plot.tick_params(axis='x', which='major', labelsize=14)
        plot.tick_params(axis='y', which='major', labelsize=14)
        plot.set_xlim(0, 220)
        plot.set_ylim(-20,20)
        plot.get_xaxis().tick_bottom()
        plot.get_yaxis().tick_left()
        for key, group in grouped:
            plt.plot(group['Case'], group[cycle+'-H error [%]'], color=boxcolor, marker=dictecnos[key], label = key, linestyle='')
            first_legend = plt.legend(numpoints=1, bbox_to_anchor=(1.0, 1.), loc=1, borderaxespad=0.)
            plot.ax = plt.gca().add_artist(first_legend)
        plot.set_xlabel("Case #",fontsize=20)
        plot.set_ylabel(cycle+" error [%]",fontsize=20)
        line1 = plot.axhline(y=-2.5, color='grey', linestyle='-.', label='± 2.5 %')
        line2 = plot.axhline(y=2.5, color='grey', linestyle='-.')
        line3 = plot.axhline(y=-4, color='black', linestyle='--', label='± 4.0 %')
        line4 = plot.axhline(y=4, color='black', linestyle='--')
        plt.legend(handles=[line1, line3], loc = 3)
        plt.show()
Vehicle01 NEDC [gCO$_2$ km$^{-1}$] UDC [gCO$_2$ km$^{-1}$] EUDC [gCO$_2$ km$^{-1}$]
Averages -2.84 -3.9 -2.21
Median -3.99 -6.46 -2.52
StdDev 3.62 8.04 1.11
Vehicle01 NEDC-H [%] NEDC-L [%]
Averages -1.7 -0.78
Median -2.4 -1.65
StdDev 2.16 2.57
Vehicle02 NEDC [gCO$_2$ km$^{-1}$] UDC [gCO$_2$ km$^{-1}$] EUDC [gCO$_2$ km$^{-1}$]
Averages -2.91 -7.47 -0.26
Median -2.65 -6.97 -0.09
StdDev 1.73 3.43 0.93
Vehicle02 NEDC-H [%] NEDC-L [%]
Averages -1.79 -3.06
Median -1.64 -2.83
StdDev 1.06 1.03
Vehicle03 NEDC [gCO$_2$ km$^{-1}$] UDC [gCO$_2$ km$^{-1}$] EUDC [gCO$_2$ km$^{-1}$]
Averages -0.79 -5.22 1.78
Median -0.52 -5.2 1.81
StdDev 2.01 2.76 1.95
Vehicle03 NEDC-H [%] NEDC-L [%]
Averages -0.44 -0.81
Median -0.31 -0.82
StdDev 1.16 0.94
Vehicle04 NEDC [gCO$_2$ km$^{-1}$] UDC [gCO$_2$ km$^{-1}$] EUDC [gCO$_2$ km$^{-1}$]
Averages -3.71 -7.46 -1.53
Median -3.7 -7.9 -1.36
StdDev 1.23 2.48 0.69
Vehicle04 NEDC-H [%] NEDC-L [%]
Averages -2.55 -2.29
Median -2.54 -2.34
StdDev 0.84 0.78
Vehicle05 NEDC [gCO$_2$ km$^{-1}$] UDC [gCO$_2$ km$^{-1}$] EUDC [gCO$_2$ km$^{-1}$]
Averages -0.01 -5.57 3.18
Median -0.23 -5.36 2.08
StdDev 3.22 4.46 3.72
Vehicle05 NEDC-H [%] NEDC-L [%]
Averages 0.03 0.59
Median -0.21 -0.57
StdDev 3 4.64
Vehicle06 NEDC [gCO$_2$ km$^{-1}$] UDC [gCO$_2$ km$^{-1}$] EUDC [gCO$_2$ km$^{-1}$]
Averages 6.23 8.1 5.16
Median 6.24 8.46 4.91
StdDev 2.18 4.53 1.41
Vehicle06 NEDC-H [%] NEDC-L [%]
Averages 3.04 2.43
Median 3.06 2.46
StdDev 1.06 1.02
Vehicle07 NEDC [gCO$_2$ km$^{-1}$] UDC [gCO$_2$ km$^{-1}$] EUDC [gCO$_2$ km$^{-1}$]
Averages -6.74 -16.4 -1.15
Median -6.33 -15.39 -1.07
StdDev 1.77 4.02 0.78
Vehicle07 NEDC-H [%] NEDC-L [%]
Averages -3.4 -3.17
Median -3.2 -2.98
StdDev 0.87 0.88
Vehicle08 NEDC [gCO$_2$ km$^{-1}$] UDC [gCO$_2$ km$^{-1}$] EUDC [gCO$_2$ km$^{-1}$]
Averages 1.21 1.44 1.08
Median 1.52 1.62 1.06
StdDev 2.38 4.95 1.55
Vehicle08 NEDC-H [%] NEDC-L [%]
Averages 0.74 -0.32
Median 0.98 -0.13
StdDev 1.44 1.37