# Building a Recommendation System

## Introduction

Recommendation systems are everywhere: YouTube, Netflix, Supermarket coupons, Amazon, BestBuy, search engines, etc. They are often used to offer carefully selected products to the consumer and relevant information to web users. In today's blog, I will walk you through a recommendation code I implemented to help car shop employees select the correct label in the billing system. You can also follow along the

[GitHub Repository](https://github.com/LeoMier/portfolio/blob/6814a54476bc4718345d755fd784173c9c6730ab/label_recommendation/label_recommendation.ipynb)

## Data Set

The data set has been obtained from the said car shop. This is comprised of a sample of a database of descriptions generated over thirteen years (around 5 thousand bills). The data, stored in a DataFrame, contains the bill description and a label (Appendix B)- which can take on or multiple values of the 9 total categories. The first five rows of the DataFrame:

|  | description | label |
| --- | --- | --- |
| 0 | upstream 02 sensor | 5 |
| 1 | install dual pipes | 9 |
| 2 | cqs 18 818285 front struts | 1 |
| 3 | oil change / mount 4 tires & ballance | 2,8 |
| 4 | labor on racks & pinion | 9 |

## Model

Due to the nonbinary nature of our categories, a one vs. all (or one vs. rest) classifier with a logistic regressor as the base classifier will be used - This classifier will create 5 logistic classifiers and will output the label with the highest probability.

To feed the data into the classifier, the labels have to be properly formatted (Appendix A) - in a "one hot" encoding string. Once formatted, the data set is split into the training and testing sets to be fed into the OneVsRestClassifier() with the next lines of code:

```python
from sklearn.model_selection import train_test_split


X_train, X_test, Y_train, Y_test = train_test_split(DF['description'],
                    DF['emb_label'], test_size=0.25)

from sklearn.multiclass import OneVsRestClassifier
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression


vectorizer = TfidfVectorizer()
vectorizer.fit(X_train)
X_train_tfidf = vectorizer.transform(X_train)
X_test_tfidf = vectorizer.transform(X_test)

base_classifier = LogisticRegression()
clf = OneVsRestClassifier(base_classifier)
clf.fit(X_train_tfidf, Y_train)
```

Despite an accuracy of 68%, the classifier is extremely useful for our purpose. We will suggest not only the best guest from the classifier but also a collection of the best. To retrieve the top recommendation the probabilities of each class must be sorted, this process is done with the help of the next lines of code:

```python
def top_label_recommendation(description: str, number_of_recommenmdations = 3):
    probability_values = clf.predict_proba(vectorizer.transform([description]))
    probability_values_DF = pd.DataFrame(probability_values.transpose(), columns=['probability']) #WE WILL TAKE ADVANTAGE OF THE DATAFRAMES PROPETIES TO ORGANIZE THE PROBABILITIES AND                                                                                                  
    probability_values_DF.sort_values(by='probability', ascending=False, inplace=True, ignore_index=False)#                            TO CONSERVE THE INDEX LINKED TO THE CLASS PREDICTION

    label_recommendation=[]
    for index in probability_values_DF.index[:number_of_recommenmdations]:
        label_recommendation += one_hot_to_label_description(clf.classes_[index])
    return(list(set(label_recommendation)))
```

## Results

The code works as expected and here you have a few examples:

```python
#EX: 1
for element in top_label_recommendation('oil change, rear tie rod pass side'):
    print(element)
#OUTPUT
#Oil Change, Ignition, Fuel System
#No category
#Shocks, Control Arms, Tires, Alignment
```

```python
#EX: 2
for element in top_label_recommendation('oxygen sensor up stream replacement', 4):
    print(element)
#OUTPUT
#ABS Control Module, Brake Lines, Brake Pads
#Oil Change, Ignition, Fuel System
#No category
#Check Engine Light, Inspections
```

## Appendix

(A) Label formatting code:

```python
#WE CREATE A NEW COLUMN WITH A PROPER LABEL TO ENCODE
def one_hot_label(label: str):
    place_holder_list = [0 for _ in range(9)]
    for ind_label in label.split(','):
        if int(ind_label)<=9:
            place_holder_list[int(ind_label)-1] = 1
    return ','.join(list(map(str, place_holder_list)))

DF['emb_label'] = DF['label'].apply(one_hot_label)
```

(B) Category table

| index | category |
| --- | --- |
| 0 | Shocks, Control Arms, Tires, Alignmen |
| 1 | Oil Change, Ignition, Fuel System |
| 2 | Manufacturer Service Intervals |
| 3 | Dashboard, Door Locks, Windows |
| 4 | Check Engine Light, Inspections |
| 5 | Alternator, Battery, Starter, Switches |
| 6 | AC System, Blower Motor |
| 7 | ABS Control Module, Brake Lines, Brake Pads |
| 8 | No category |
