{"metadata":{"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":7391,"databundleVersionId":44328,"sourceType":"competition"},{"sourceId":3442322,"sourceType":"datasetVersion","datasetId":2073626}],"dockerImageVersionId":30626,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true},"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.12.0"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport seaborn as sns\n\n#warnings\nimport warnings\nwarnings.simplefilter('ignore')\n# Ignore all warnings about later execution ¶\nwarnings.filterwarnings(\"ignore\", category=FutureWarning)\n# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session\n\n","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:12.127986Z","iopub.execute_input":"2024-01-02T16:01:12.128320Z","iopub.status.idle":"2024-01-02T16:01:12.136393Z","shell.execute_reply.started":"2024-01-02T16:01:12.128291Z","shell.execute_reply":"2024-01-02T16:01:12.135535Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv(\"/kaggle/input/ford-car-price-prediction/ford.csv\")\n\ndf[\"model\"]=df[\"model\"].str.strip()\ndf.info()","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:12.140903Z","iopub.execute_input":"2024-01-02T16:01:12.141306Z","iopub.status.idle":"2024-01-02T16:01:12.183980Z","shell.execute_reply.started":"2024-01-02T16:01:12.141274Z","shell.execute_reply":"2024-01-02T16:01:12.182125Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We reorder df to better look","metadata":{}},{"cell_type":"code","source":"\ncols = [\n     'price',\n     'year', 'mileage' ,'mpg','tax','engineSize',  \n     'transmission','fuelType','model'\n       \n       ]\ndf = df[cols] \ndf_init=df\nprint(df.info())","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:12.191771Z","iopub.execute_input":"2024-01-02T16:01:12.192118Z","iopub.status.idle":"2024-01-02T16:01:12.213878Z","shell.execute_reply.started":"2024-01-02T16:01:12.192089Z","shell.execute_reply":"2024-01-02T16:01:12.212420Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"As you can see we have no null-value. <br>\nTarget =Y=price <br>\n5 Numerical Input(x) <br>\n1 Categorical input\n\n***","metadata":{}},{"cell_type":"markdown","source":"### Dealing with outliers","metadata":{}},{"cell_type":"code","source":"sns.histplot( data=df,x='price', kde=True)\n","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:12.215815Z","iopub.execute_input":"2024-01-02T16:01:12.216086Z","iopub.status.idle":"2024-01-02T16:01:12.737337Z","shell.execute_reply.started":"2024-01-02T16:01:12.216063Z","shell.execute_reply":"2024-01-02T16:01:12.735677Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"remove right outlier","metadata":{}},{"cell_type":"code","source":"q99 = df['price'].quantile(0.99)\ndf = df[df['price']<q99]\nsns.histplot( data=df,x='price', kde=True)","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:12.739018Z","iopub.execute_input":"2024-01-02T16:01:12.739810Z","iopub.status.idle":"2024-01-02T16:01:13.281129Z","shell.execute_reply.started":"2024-01-02T16:01:12.739732Z","shell.execute_reply":"2024-01-02T16:01:13.280120Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sns.histplot( data=df,x='year', kde=True)","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:13.283707Z","iopub.execute_input":"2024-01-02T16:01:13.284307Z","iopub.status.idle":"2024-01-02T16:01:14.169065Z","shell.execute_reply.started":"2024-01-02T16:01:13.284241Z","shell.execute_reply":"2024-01-02T16:01:14.167080Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"remove year<2022 and left outlier","metadata":{}},{"cell_type":"code","source":"df=df[df[\"year\"]<2022]\nq01 = df['year'].quantile(0.01)\ndf = df[df['year']>q01]\nsns.histplot( data=df,x='year', kde=True)","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:14.171047Z","iopub.execute_input":"2024-01-02T16:01:14.171484Z","iopub.status.idle":"2024-01-02T16:01:14.573487Z","shell.execute_reply.started":"2024-01-02T16:01:14.171449Z","shell.execute_reply":"2024-01-02T16:01:14.572596Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nsns.histplot( data=df,x='tax', kde=True)","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:14.574940Z","iopub.execute_input":"2024-01-02T16:01:14.575485Z","iopub.status.idle":"2024-01-02T16:01:14.990580Z","shell.execute_reply.started":"2024-01-02T16:01:14.575452Z","shell.execute_reply":"2024-01-02T16:01:14.989668Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"q99 = df['tax'].quantile(0.99)\ndf = df[df['tax']<q99]\nsns.histplot( data=df,x='tax', kde=True)","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:14.992224Z","iopub.execute_input":"2024-01-02T16:01:14.992607Z","iopub.status.idle":"2024-01-02T16:01:15.329624Z","shell.execute_reply.started":"2024-01-02T16:01:14.992571Z","shell.execute_reply":"2024-01-02T16:01:15.328789Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nsns.histplot( data=df,x='engineSize', kde=True)","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:15.330825Z","iopub.execute_input":"2024-01-02T16:01:15.331580Z","iopub.status.idle":"2024-01-02T16:01:15.741819Z","shell.execute_reply.started":"2024-01-02T16:01:15.331542Z","shell.execute_reply":"2024-01-02T16:01:15.740057Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sns.histplot( data=df,x='mileage', kde=True)","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:15.743427Z","iopub.execute_input":"2024-01-02T16:01:15.743974Z","iopub.status.idle":"2024-01-02T16:01:16.165187Z","shell.execute_reply.started":"2024-01-02T16:01:15.743948Z","shell.execute_reply":"2024-01-02T16:01:16.164173Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"q99 = df['mileage'].quantile(0.99)\ndf = df[df['mileage']<q99]\nsns.histplot( data=df,x='mileage', kde=True)\n","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:16.169469Z","iopub.execute_input":"2024-01-02T16:01:16.170585Z","iopub.status.idle":"2024-01-02T16:01:16.506171Z","shell.execute_reply.started":"2024-01-02T16:01:16.170516Z","shell.execute_reply":"2024-01-02T16:01:16.504778Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nsns.histplot( data=df,x='mpg', kde=True)","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:16.507599Z","iopub.execute_input":"2024-01-02T16:01:16.509248Z","iopub.status.idle":"2024-01-02T16:01:17.013686Z","shell.execute_reply.started":"2024-01-02T16:01:16.509209Z","shell.execute_reply":"2024-01-02T16:01:17.011592Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.describe()","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:17.016168Z","iopub.execute_input":"2024-01-02T16:01:17.016840Z","iopub.status.idle":"2024-01-02T16:01:17.047990Z","shell.execute_reply.started":"2024-01-02T16:01:17.016805Z","shell.execute_reply":"2024-01-02T16:01:17.046360Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"we have 17k row without outlier","metadata":{}},{"cell_type":"markdown","source":"## Checking the OLS assumptions","metadata":{}},{"cell_type":"code","source":"f, ax = plt.subplots(2, 3, sharey=True, figsize =(15,3)) #sharey -> share 'Price' as y\nax[0,0].scatter(df['year'],df['price'])\nax[0,0].set_title('Price and Year')\nax[0,1].scatter(df['mpg'],df['price'])\nax[0,1].set_title('Price and mpg')\nax[0,2].scatter(df['mileage'],df['price'])\nax[0,2].set_title('Price and Mileage')\n\nax[1,0].scatter(df['engineSize'],df['price'])\nax[1,0].set_title('Price and engineSize')\n\nax[1,1].scatter(df['tax'],df['price'])\nax[1,1].set_title('Price and tax')\n\n","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:17.050023Z","iopub.execute_input":"2024-01-02T16:01:17.050456Z","iopub.status.idle":"2024-01-02T16:01:18.197468Z","shell.execute_reply.started":"2024-01-02T16:01:17.050420Z","shell.execute_reply":"2024-01-02T16:01:18.196335Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Dont look linear well . so we transfer price to log scale","metadata":{}},{"cell_type":"code","source":"df['log_price'] = np.log(df['price'])\ndf = df.drop(['price'],axis=1)\n\nf, ax = plt.subplots(2, 3, sharey=True, figsize =(15,3)) #sharey -> share 'Price' as y\nax[0,0].scatter(df['year'],df['log_price'])\nax[0,0].set_title('Price and Year')\nax[0,1].scatter(df['mpg'],df['log_price'])\nax[0,1].set_title('Price and mpg')\nax[0,2].scatter(df['mileage'],df['log_price'])\nax[0,2].set_title('Price and Mileage')\n\nax[1,0].scatter(df['engineSize'],df['log_price'])\nax[1,0].set_title('Price and engineSize')\n\nax[1,1].scatter(df['tax'],df['log_price'])\nax[1,1].set_title('Price and tax')","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:18.198682Z","iopub.execute_input":"2024-01-02T16:01:18.199697Z","iopub.status.idle":"2024-01-02T16:01:19.354311Z","shell.execute_reply.started":"2024-01-02T16:01:18.199615Z","shell.execute_reply":"2024-01-02T16:01:19.351978Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now it looks better","metadata":{}},{"cell_type":"markdown","source":"## Multicollinearity","metadata":{}},{"cell_type":"code","source":"from statsmodels.stats.outliers_influence import variance_inflation_factor\n\nvariables = df[['mileage','year','mpg','tax','engineSize']]\nvif = pd.DataFrame()\n\n# here we make use of the variance_inflation_factor, which will basically output the respective VIFs \nvif[\"VIF\"] = [variance_inflation_factor(variables.values, i) for i in range(variables.shape[1])]\n# Finally, I like to include names so it is easier to explore the result\nvif[\"Features\"] = variables.columns\nvif ","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:19.356121Z","iopub.execute_input":"2024-01-02T16:01:19.356407Z","iopub.status.idle":"2024-01-02T16:01:19.530427Z","shell.execute_reply.started":"2024-01-02T16:01:19.356381Z","shell.execute_reply":"2024-01-02T16:01:19.529515Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"drop all col VIF>10","metadata":{}},{"cell_type":"code","source":"df = df.drop(['year','engineSize','mpg'],axis=1)","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:19.531899Z","iopub.execute_input":"2024-01-02T16:01:19.532262Z","iopub.status.idle":"2024-01-02T16:01:19.539024Z","shell.execute_reply.started":"2024-01-02T16:01:19.532230Z","shell.execute_reply":"2024-01-02T16:01:19.538012Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Create dummy variables","metadata":{}},{"cell_type":"code","source":"df = pd.get_dummies(df, drop_first=True)\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:19.540611Z","iopub.execute_input":"2024-01-02T16:01:19.540992Z","iopub.status.idle":"2024-01-02T16:01:19.581508Z","shell.execute_reply.started":"2024-01-02T16:01:19.540959Z","shell.execute_reply":"2024-01-02T16:01:19.580795Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Linear regression model","metadata":{}},{"cell_type":"code","source":"# The target(s) (dependent variable) is 'log price'\ntargets = df['log_price']\n\n# The inputs are everything BUT the dependent variable, so we can simply drop it\ninputs = df.drop(['log_price'],axis=1)\n\nfrom sklearn.preprocessing import StandardScaler\n\n# Create a scaler object\nscaler = StandardScaler()\n# Fit the inputs (calculate the mean and standard deviation feature-wise)\nscaler.fit(inputs)\ninputs_scaled = scaler.transform(inputs)\n\n# Import the module for the split\nfrom sklearn.model_selection import train_test_split\n\n# Split the variables with an 80-20 split and some random state\n# To have the same split as mine, use random_state = 365\nx_train, x_test, y_train, y_test = train_test_split(inputs_scaled, targets, test_size=0.2, random_state=365)\n\n# Create a linear regression object\nfrom sklearn.linear_model import LinearRegression\nreg = LinearRegression()\n# Fit the regression with the scaled TRAIN inputs and targets\nreg.fit(x_train,y_train)\ny_hat = reg.predict(x_train)","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:19.582945Z","iopub.execute_input":"2024-01-02T16:01:19.583485Z","iopub.status.idle":"2024-01-02T16:01:20.120437Z","shell.execute_reply.started":"2024-01-02T16:01:19.583454Z","shell.execute_reply":"2024-01-02T16:01:20.119256Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.scatter(y_train, y_hat,alpha=0.2)\n# Let's also name the axes\nplt.xlabel('Targets (y_train)',size=18)\nplt.ylabel('Predictions (y_hat)',size=18)\n# Sometimes the plot will have different scales of the x-axis and the y-axis\n# This is an issue as we won't be able to interpret the '45-degree line'\n# We want the x-axis and the y-axis to be the same\np0=min(min(y_train),min(y_hat))-0.1\np1=max(max(y_train),max(y_hat))+0.1\n\n\nplt.xlim(p0,p1)\nplt.ylim(p0,p1)\n\n# y=x\npoint_1 = [p0,p0]\npoint_2 = [p1,p1]\n\nx_values = [[point_1[0]], [point_2[0]]]\ny_values = [[point_1[1]], [point_2[1]]]\n\nplt.plot(x_values, y_values, 'red')\n\n\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:20.125461Z","iopub.execute_input":"2024-01-02T16:01:20.127064Z","iopub.status.idle":"2024-01-02T16:01:20.419361Z","shell.execute_reply.started":"2024-01-02T16:01:20.127015Z","shell.execute_reply":"2024-01-02T16:01:20.418414Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"In this chart every point which is  near to red line (y=x) has better prediction","metadata":{}},{"cell_type":"code","source":"sns.distplot(y_train - y_hat)\n\n# Include a title\nplt.title(\"Residuals PDF\", size=18)","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:20.420354Z","iopub.execute_input":"2024-01-02T16:01:20.420749Z","iopub.status.idle":"2024-01-02T16:01:20.946846Z","shell.execute_reply.started":"2024-01-02T16:01:20.420713Z","shell.execute_reply":"2024-01-02T16:01:20.945855Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Normal distribution . left and right tail almost the same","metadata":{}},{"cell_type":"code","source":"def adj_r2(x,y):\n    r2 = reg.score(x,y)\n    n = x.shape[0]\n    p = x.shape[1]\n    adjusted_r2 = 1-(1-r2)*(n-1)/(n-p-1)\n    return adjusted_r2\n\nprint(f\"adj_r2 = {adj_r2(x_train,y_train):.4f}\")","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:20.948408Z","iopub.execute_input":"2024-01-02T16:01:20.948914Z","iopub.status.idle":"2024-01-02T16:01:20.965255Z","shell.execute_reply.started":"2024-01-02T16:01:20.948886Z","shell.execute_reply":"2024-01-02T16:01:20.964450Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"adj_r2=76% Its good","metadata":{}},{"cell_type":"markdown","source":"### Finding the weights and bias","metadata":{}},{"cell_type":"code","source":"reg_summary = pd.DataFrame(inputs.columns.values, columns=['Features'])\nreg_summary['Weights'] = reg.coef_\nreg_summary.loc[len(reg_summary)]=['Intercept_',reg.intercept_]\nreg_summary","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:20.966434Z","iopub.execute_input":"2024-01-02T16:01:20.966730Z","iopub.status.idle":"2024-01-02T16:01:20.998140Z","shell.execute_reply.started":"2024-01-02T16:01:20.966705Z","shell.execute_reply":"2024-01-02T16:01:20.997308Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Every Categorical col in dummy mode has benchmark(deleted from dummy)\nWith compare with original df We can see benchmark transmission is \"Automatic\"","metadata":{}},{"cell_type":"code","source":"df_init['transmission'].unique()","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:20.999263Z","iopub.execute_input":"2024-01-02T16:01:20.999550Z","iopub.status.idle":"2024-01-02T16:01:21.010692Z","shell.execute_reply.started":"2024-01-02T16:01:20.999525Z","shell.execute_reply":"2024-01-02T16:01:21.009689Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Testing","metadata":{}},{"cell_type":"code","source":"# to get a proper result, we must reset the index and drop the old indexing\ny_test = y_test.reset_index(drop=True)\ny_hat_test = reg.predict(x_test)","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:21.011910Z","iopub.execute_input":"2024-01-02T16:01:21.012208Z","iopub.status.idle":"2024-01-02T16:01:21.020360Z","shell.execute_reply.started":"2024-01-02T16:01:21.012182Z","shell.execute_reply":"2024-01-02T16:01:21.019388Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.scatter(y_test, y_hat_test, alpha=0.2)\nplt.xlabel('Targets (y_test)',size=18)\nplt.ylabel('Predictions (y_hat_test)',size=18)\np0=min(min(y_train),min(y_hat))-0.1\np1=max(max(y_train),max(y_hat))+0.1\n\n\nplt.xlim(p0,p1)\nplt.ylim(p0,p1)\n\n# y=x\npoint_1 = [p0,p0]\npoint_2 = [p1,p1]\n\nx_values = [[point_1[0]], [point_2[0]]]\ny_values = [[point_1[1]], [point_2[1]]]\n\nplt.plot(x_values, y_values, 'red')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:21.021448Z","iopub.execute_input":"2024-01-02T16:01:21.021772Z","iopub.status.idle":"2024-01-02T16:01:21.287458Z","shell.execute_reply.started":"2024-01-02T16:01:21.021743Z","shell.execute_reply":"2024-01-02T16:01:21.286793Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"In this chart every point near to red line (y=x) has better prediction","metadata":{}},{"cell_type":"code","source":"df_pf = pd.DataFrame(np.exp(y_hat_test), columns=['Prediction'])\ndf_pf['Target'] = np.exp(y_test)\ndf_pf['Residual'] = df_pf['Target'] - df_pf['Prediction']\ndf_pf['Difference%'] = np.absolute(df_pf['Residual']/df_pf['Target']*100)\n\npd.options.display.float_format = '{:.4f}'.format\ndf_pf.head()","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:21.288479Z","iopub.execute_input":"2024-01-02T16:01:21.289137Z","iopub.status.idle":"2024-01-02T16:01:21.304142Z","shell.execute_reply.started":"2024-01-02T16:01:21.289111Z","shell.execute_reply":"2024-01-02T16:01:21.302483Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_pf.describe()","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:21.305324Z","iopub.execute_input":"2024-01-02T16:01:21.306129Z","iopub.status.idle":"2024-01-02T16:01:21.325393Z","shell.execute_reply.started":"2024-01-02T16:01:21.306098Z","shell.execute_reply":"2024-01-02T16:01:21.324749Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Average differnce=13% error<br>\nIQR(50%) error=[5-19]%","metadata":{}},{"cell_type":"code","source":"df_pf.sort_values(by=['Difference%'],ascending=False,inplace=True)\ndf_pf.head()","metadata":{"execution":{"iopub.status.busy":"2024-01-02T16:01:21.329130Z","iopub.execute_input":"2024-01-02T16:01:21.329931Z","iopub.status.idle":"2024-01-02T16:01:21.341487Z","shell.execute_reply.started":"2024-01-02T16:01:21.329902Z","shell.execute_reply":"2024-01-02T16:01:21.340688Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can study row with the most error  % & look for new col to modify model","metadata":{}}]}