A few weeks ago, I introduced a **target-based categorical encoder** for Statistical/Machine Learning based on correlations + **Cholesky decomposition**. That is, a way to convert explanatory variables such as the `x`

below, to **numerical variables which can be digested by ML models**.

```
# Have:
x <- c("apple", "tomato", "banana", "apple", "pineapple", "bic mac",
"banana", "bic mac", "quinoa sans gluten", "pineapple",
"avocado", "avocado", "avocado", "avocado!", ...)
# Need:
new_x <- c(0, 1, 2, 0, 3, 4, 2, ...)
```

This week, I use the `tips`

dataset (available here). Imagine that **you work in a restaurant**, and also have access to the following billing information:

```
total_bill tip sex smoker day time size
0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.50 Male No Sun Dinner 3
3 23.68 3.31 Male No Sun Dinner 2
4 24.59 3.61 Female No Sun Dinner 4
.. ... ... ... ... ... ... ...
239 29.03 5.92 Male No Sat Dinner 3
240 27.18 2.00 Female Yes Sat Dinner 2
241 22.67 2.00 Male Yes Sat Dinner 2
242 17.82 1.75 Male No Sat Dinner 2
243 18.78 3.00 Female No Thur Dinner 2
[244 rows x 7 columns]
```

Based on this information, you’d like to **understand how to maximize your tip** ^^. In a Statistical/Machine Learning model, nnetsauce’s Ridge2Regressor in this post, the response to be understood is the numerical variable `tip`

. The explanatory variables are `total_bill`

, `sex`

, `smoker`

, `day`

, `time`

, `size`

. However, `sex`

, `smoker`

, `day`

, `time`

are not digestible as is; they need to be numerically encoded.

So, if we let `df`

be a data frame containing all the previous information on tips, and `pseudo_tip`

be the pseudo target created as explained in this previous post using R, then by using the querier, a numerical data frame `df_numeric`

can be obtained from `df`

as:

```
import numpy as np
import pandas as pd
import querier as qr
Z = qr.select(df, 'total_bill, sex, smoker, day, time, size')
df_numeric = pd.DataFrame(np.zeros(Z.shape),
columns=Z.columns)
col_names = Z.columns.values
if (qr.select(Z, col).values.dtype == np.object): # if column is not numerical
# average a pseudo-target instead of the real response
Z_temp = qr.summarize(df, req = col + ', avg(pseudo_tip)',
group_by = col)
levels = np.unique(qr.select(Z, col).values)
for l in levels:
qrobj = qr.Querier(Z_temp)
val = qrobj\
.filtr(col + '== "' + l + '"')\
.select("avg_pseudo_tip")\
.df.values
df_numeric.at[np.where(Z[col] == l)[0], col] = np.float(val)
else:
df_numeric[col] = Z[col]
```

Below **on the left**, we can observe the distribution of tips, ranging approximately from 1 to 10. **On the right**, I obtained Ridge2Regressor’s cross-validation root mean squared error (RMSE) for different values of the target correlation (50 repeats each):

Surprisingly (or not?), the result is not compatible with my intuition. Considering that we are **constructing encoded explanatory variables by using the response** (a form of subtle overfitting), I was expecting a lower cross-validation error for low target correlations – close to 0 or slightly negative. But the lowest 5-fold cross-validation error is obtained for a target correlation equal to 0.7. It will be interesting to see **how these results generalize**. Though, it’s worth noticing that accross target correlations, the volatility of Ridge2Regressor cross-validation errors – adjusted with default parameters here – remains low.