<jupyter_start><jupyter_text>Sprint 1: Data analysis and supervised learning Tijdens deze eerste sprint wordt enkel gefocust op het classificeren op basis van de verschillende product en issue categorieën. In de volgende sprints zullen ook de classificatie van sub-producten en sub-issues aan bod komen.  Exploratory Data Analysis Inlezen van het CSV bestand naar een DataFrame.<jupyter_code>import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import csv
import re, string

rows_to_read = None # Gewenst aantal rijen inlezen (None = allemaal)

complaints = pd.read_csv('data/complaints.csv', delimiter=',', nrows=rows_to_read)

rows, cols = complaints.shape

print(f'Er zijn {rows} rijen en {cols} kolommen')<jupyter_output>Er zijn 485701 rijen en 18 kolommen<jupyter_text>Om een overzicht te krijgen van de gebruikte kolommen en de hoeveelheid data, maken we hier gebruik van de info() methode.<jupyter_code>complaints.info()<jupyter_output><class 'pandas.core.frame.DataFrame'>
RangeIndex: 485701 entries, 0 to 485700
Data columns (total 18 columns):
Date received                   485701 non-null object
Product                         485701 non-null object
Sub-product                     485701 non-null object
Issue                           485701 non-null object
Sub-issue                       485701 non-null object
Consumer complaint narrative    485701 non-null object
Company public response         485701 non-null object
Company                         485701 non-null object
State                           485701 non-null object
ZIP code                        485701 non-null object
Tags                            485701 non-null object
Consumer consent provided?      485701 non-null object
Submitted via                   485701 non-null object
Date sent to company            485701 non-null object
Company response to consumer    485701 non-null object
Timely response?                485701 non-null object
Consumer [...]<jupyter_text>De Dataframe aanpassen naar de belangrijkste kolommen.- Product- Sub-product- Issue- Sub-issue- Consumer complaint narrative<jupyter_code>complaints_df = complaints[['Product', 'Sub-product', 'Issue', 'Sub-issue', 'Consumer complaint narrative']].copy()

# Kolommen een simpelere naam geven
complaints_df.columns = ['Product', 'Sub_Product', 'Issue', 'Sub_Issue', 'Narrative'] 
complaints_df.head()<jupyter_output><empty_output><jupyter_text>Aantal klachten per categorie van producten<jupyter_code>complaints_df.Product.unique()<jupyter_output><empty_output><jupyter_text>Er zijn meer dan 10 verschillende categorieën voor de producten. Sommige zijn echter heel erg gerelateerd aan elkaar. Daarom kan het nuttig zijn om sommige categorieën samen te nemen om de accuraatheid van het te bekomen model te verbeteren.- 'Credit reporting, repair, or other'    - 'Credit reporting, credit repair services, or other personal consumer reports'    - 'Credit reporting'- 'Credit card or prepaid card'    - 'Credit card'    - 'Prepaid card'- 'Payday loan, title loan, or personal loan    - 'Payday loan'- 'Money transfer, virtual currency, or money service'    - 'Money transfer'     - 'Virtual currency'<jupyter_code>complaints_df.replace({'Product': 
             {'Credit reporting, credit repair services, or other personal consumer reports': 
              'Credit reporting, repair, or other', 
              'Credit reporting': 'Credit reporting, repair, or other',
             'Credit card': 'Credit card or prepaid card',
             'Prepaid card': 'Credit card or prepaid card',
             'Payday loan': 'Payday loan, title loan, or personal loan',
             'Money transfer': 'Money transfer, virtual currency, or money service',
             'Virtual currency': 'Money transfer, virtual currency, or money service'}}, 
            inplace= True)
complaints_df.Product.unique()<jupyter_output><empty_output><jupyter_text>Er blijven nu slechts 13 product categorieën over. Om het mogelijk te maken om een model te ontwikkelen gaan we elke categorie die in tekstvorm in de dataset staat, gaan voorstellen als een getal. Hiervoor voegen we een nieuwe kolom toe met als naam 'Category_Id'.<jupyter_code>complaints_df['Category_Id'] = complaints_df['Product'].factorize()[0]

# Dictionary aanmaken die de 'Category_Id - Product' combinaties bevat
categories = dict(complaints_df[['Category_Id', 'Product']].drop_duplicates().values)
categories
# Nieuwe DataFrame met de extra kolom weergeven
complaints_df.head()<jupyter_output><empty_output><jupyter_text>Vervolgens gaan we het aantal complaints per product tellen.<jupyter_code># Aantal products
product_counts = pd.DataFrame({'Count': complaints_df.groupby(['Product']).size()})
product_counts
fig = plt.figure(figsize=(10, 5))
product_counts.plot.barh(title="Aantal klachten per product categorie", legend=None)<jupyter_output><empty_output><jupyter_text>De verdeling van de data over de verschillende categorieën is niet gebalanceerd. Dit kan voor problemen zorgen bij het classificeren aangezien de kleine categorieën als uitschieters gezien kunnen worden. We zouden deze categorieën kunnen oversampelen zodat de dataset gebalanceerd wordt, maar aangezien de categorieën die het meest voorkomen ook het meest waarschijnlijk voorkomen tijdens het classificeren, zullen we dit niet doen. Om deze categorieën van producten en sub-producten beter te begrijpen, gaan we het verband tussen beiden gaan onderzoeken.<jupyter_code>sub_product_counts = pd.DataFrame({'Count': complaints_df.groupby(['Product', 'Sub_Product']).size()})
sub_product_counts.head(10)
sub_product_counts.unstack().plot(kind='barh', stacked=True, legend=None, title="Aantal klachten per sub-product categorie")<jupyter_output><empty_output><jupyter_text>Aantal klachten per categorie van issues Hieronder worden het aantal complaints per issue geteld en worden de distributies van de sub-issues getoond.<jupyter_code>issue_counts = complaints_df.groupby('Issue')['Issue'].count()
issue_counts.sort_values(ascending=False)
subissue_counts = pd.DataFrame({'Count': complaints_df.groupby(['Issue', 'Sub_Issue'])['Sub_Issue'].count()})
subissue_counts.sort_values(by=['Issue','Count'],ascending=[True,False])<jupyter_output><empty_output><jupyter_text>Voor een duidelijker overzicht worden de 20 meest voorkomende issues geplot in een histogram.<jupyter_code>fig = plt.figure(figsize=(8,6))
issue_counts.sort_values(ascending=False).head(20).plot.barh(title="Aantal klachten per issue")
plt.xlabel('Aantal klachten', fontsize = 10);<jupyter_output><empty_output><jupyter_text>Zoals je ziet zijn er veel verschillende issues (161) en is de data ongebalanceerd. Daarom zullen we enkel de 20 meest voorkomende issues gebruiken om het model te trainen. Dit is namelijk 71% van alle data. Hier worden ze nog eens getoond.<jupyter_code>som = 0
for aantal in issue_counts.sort_values(ascending=False).head(20):
    som += aantal
print('Percentage: ' + str(round(som/len(complaints_df.index)*100)) + '%')
issue_counts.sort_values(ascending=False).head(20)<jupyter_output>Percentage: 71%<jupyter_text>Wat opvalt is dat sommige categorieën een andere naam krijgen maar dat de data eigenlijk onder dezelfde categorie zou mogen geplaatst worden. Dit is bijvoorbeeld het geval bij 'Attempts to collect debt not owed' en 'Cont'd attempts collect debt not owed'. Daarom zullen we deze kolommen samen nemen onder dezelfde noemer.<jupyter_code>complaints_df.replace({'Issue': 
            {'Cont\'d attempts collect debt not owed':'Attempts to collect debt not owed',
            'Dealing with my lender or servicer':'Dealing with your lender or servicer'}}, 
            inplace= True)
issue_counts = complaints_df.groupby('Issue')['Issue'].count()
#door 2 issues gelijk te stellen aan andere issues houden we er nog 18 verschillende over
issue_counts.sort_values(ascending=False).head(18)<jupyter_output><empty_output><jupyter_text>Nu filteren we de complaints zodat enkel degene met de meest voorkomende issues overblijven.<jupyter_code>issue_list = ['Incorrect information on your report',
       'Attempts to collect debt not owed',
       'Problem with a credit reporting company\'s investigation into an existing problem',
       'Incorrect information on credit report',
       'Improper use of your report',
       'Dealing with your lender or servicer',
       'Loan servicing, payments, escrow account',
       'Communication tactics',
       'Trouble during payment process',
       'Written notification about debt',
       'Loan modification,collection,foreclosure',
       'False statements or representation',
       'Managing an account',
       'Struggling to pay mortgage',
       'Took or threatened to take negative or legal action',
       'Disclosure verification of debt',
       'Managing the loan or lease',
       'Problem with a purchase shown on your statement']
complaints_df_ = complaints_df[complaints_df['Issue'].isin(issue_list)]
complaints_df.head()<jupyter_output><empty_output><jupyter_text>Data pre-processing Via volgende methode kunnen we alle speciale tekens en specifieke tekens ten gevolge van anonimisering (XXX ...) uit de dataset weghalen.<jupyter_code>from sklearn.feature_extraction.stop_words import ENGLISH_STOP_WORDS
from sklearn.preprocessing import LabelEncoder
stop_words = ENGLISH_STOP_WORDS

def clean_tokenized(string):
    # Omzetten naar lowercase 
    string =string.lower()
    # Alles wat niet gelijk is aan een lowercase of whitespace eruit filteren
    string = re.sub(r'[^\w\s]','',string)
    # Alle getallen eruit filteren
    string = re.sub(r'[0-9]|,','',string)
    # Returns en newlines eruithalen
    string = string.replace('\r',' ')
    string = string.replace('\n',' ')
    # Kaart nummers staan in de tekst als volgt XXX XXX ..., deze eruit filteren
    string = re.sub(r'[X|x]{2,}',' ',string)
    # de string splitten om de stop woorden er afzonderlijk uit te halen
    words = string.split(' ')
    no_stop = [w for w in words if w not in stop_words]
    return no_stop

def clean_string(string):
    inp=clean_tokenized(string)
    return " ".join(inp)
complaints_df['Narrative_clean'] = complaints_df['Narrative'].apply(clean_string)
complaints_df['Narrative_clean_tokenized'] = complaints_df['Narrative'].apply(clean_tokenized)<jupyter_output><empty_output><jupyter_text>Meest voorkomende woorden in elk product categorie Om tekst als invoer te gebruiken voor algoritmes, moeten we deze gaan converteren naar bruikbare data. We berekenen hiervoor de Term Frequency en Inverse Document Frequency (TF-IDF).- Term Frequency: beschrijft relatief hoeveel keer een gegeven woord in een document voorkomt ten opzichte van het totaal aantal woorden- Inverse Document Frequency: beschrijft het aantal keer een bepaalde term voorkomt over meerdere documenten    - Hoge IDF: term komt slechts voor in een paar documenten    - Lage IDF: term komt in veel documenten voor TfidfVectorizer class wordt geïnitialiseerd met de volgende paramters:- `min_df`: verwijder de termen die in minder dan deze waarde aantal documenten voorkomt- `sublinear_tf`: term frequentie op een logaritmische schaal plaatsen- `stop_words`: verwijder specifieke (vaak voorkomende) stop woorden uit het Engels- `ngram_range`: (1, 2) geeft aan dat zowel termen uit 1 woord (unigram), als termen die uit 2 woorden (bigram) bestaat kunnen gebruikt worden Om dit te realiseren gaan we eerst elke klacht narrative omvormen naar een array van termen (= features).<jupyter_code>from sklearn.feature_extraction.text import TfidfVectorizer

tfidfVector = TfidfVectorizer(sublinear_tf=True, min_df=5, ngram_range=(1, 2), stop_words='english')

features = tfidfVector.fit_transform(complaints_df.head(10000)['Narrative_clean']).toarray()
labels = complaints_df.head(10000).Category_Id

print("De %d verschillende klachten worden voorgeteld door %d features" %(features.shape))<jupyter_output>De 10000 verschillende klachten worden voorgeteld door 24471 features<jupyter_text>Vervolgens gaan we voor elke categorie de meest voorkomende termen gaan selecteren aan de hand van de Chi-square verdeling.- Unigrams: termen die slechts uit 1 woord bestaan- Bigrams: termen die uit 2 woorden bestaanDe parameters voor de Chi-square verdeling zijn als volgt:- X: features: (Category_Id, [features]) tuples- y: labels (Category_Id)- returns: (chi2_values, pvalues) tuplesHiermee kunnen de Chi-square waarden berekend worden voor elke feature per categorie. Vervolgens kunnen we de features sorteren op de hoogste waarde om zo de features met hoogste frequentie te bepalen. Hier schrijven we telkens voor elke categorie de 3 meest voorkomende features uit.<jupyter_code>from sklearn.feature_selection import chi2

N = 3
for Category_Id, Product in sorted(categories.items()):
    features_chi2 = chi2(features, labels == Category_Id)
    indices = np.argsort(features_chi2[0])
    feature_names = np.array(tfidfVector.get_feature_names())[indices]
    unigrams = [v for v in feature_names if len(v.split(' ')) == 1]
    bigrams = [v for v in feature_names if len(v.split(' ')) == 2]
    
    print("\n%s:" %(Product))
    print("\tUnigrams: %s" %(', '.join(unigrams[-N:])))
    print("\tBigrams: %s" %(', '.join(bigrams[-N:])))<jupyter_output>Credit reporting, repair, or other:
	Unigrams: equifax, reporting, report
	Bigrams: identity theft, credit file, credit report

Debt collection:
	Unigrams: collect, collection, debt
	Bigrams: debt collection, collection agency, collect debt

Payday loan, title loan, or personal loan:
	Unigrams: tower, borrowed, loan
	Bigrams: installment loan, pay loan, title loan

Mortgage:
	Unigrams: foreclosure, escrow, mortgage
	Bigrams: loan modification, mortgage company, escrow account

Credit card or prepaid card:
	Unigrams: citi, express, card
	Bigrams: new card, american express, credit card

Checking or savings account:
	Unigrams: savings, branch, deposit
	Bigrams: direct deposit, savings account, checking account

Student loan:
	Unigrams: loans, student, navient
	Bigrams: student loans, student loan, loan forgiveness

Vehicle loan or lease:
	Unigrams: ally, vehicle, car
	Bigrams: ally financial, santander consumer, consumer usa

Money transfer, virtual currency, or money service:
	Unigrams[...]<jupyter_text>Een alternatieve benadering voor feature selection wordt hieronder uitgewerkt Eerst stellen we een dataframe op voor elke category. Elke dataframe wordt bijgehouden in de df_categorieen lijst.<jupyter_code>df_categorieen = []
for cat in complaints_df.Product.unique():
    df_cat = complaints_df.head(10000).loc[complaints_df['Product'] == cat]
    df_categorieen.append(df_cat)

df_categorieen[0]
complaints_df.head(10000).Product.unique()<jupyter_output><empty_output><jupyter_text>Via volgende functie kunnen we de 15 meest gebruikte woorden berekenen van een categorie.<jupyter_code>from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer

def word_count(df,amount):
    try:
        count_vect = CountVectorizer(analyzer='word',stop_words="english", ngram_range=(amount, amount),min_df=1, max_df=1.0)
        df['Narrative']
        X_train_counts = count_vect.fit_transform(df['Narrative_clean'])

        feature_names=count_vect.get_feature_names()
        feature_names

        word_count=[]
        for i in range(len(feature_names)):
            word_count.append(0)

        for complaint in X_train_counts.toarray():
            counter = 0
            for word in complaint:
                word_count[counter] += word
                counter += 1

        df_wc =  pd.DataFrame({'name':feature_names, 'count':word_count})
        df_wc = df_wc.sort_values(by=["count"],ascending=False).head(n=15)
        return df_wc.reset_index(drop=True)
    except ValueError:
        print("Empty vocabulary")<jupyter_output><empty_output><jupyter_text>Nu overlopen we de dataframes van alle categorieën.Telkens krijgen we de meest gebruikte woorden van de categorie terug in een dataframe door middel van bovenstaande functie.Vervolgens concateneren we al deze dataframes om een overzicht van de meest gebruikte woorden te bekomen.<jupyter_code>top_words_percat = []
for df_cat in df_categorieen:
    top_words_percat.append(word_count(df_cat,1))
col_names_wordcount = []
for cat in complaints_df.head(10000).Product.unique():
    col_names_wordcount.append(cat)
    col_names_wordcount.append('count')
df_wc_single = pd.concat(top_words_percat, axis=1)
df_wc_single.columns = col_names_wordcount
df_wc_single<jupyter_output><empty_output><jupyter_text>Op een analoge manier bepalen we de meeste gebruikte bigrams bepalen per categorie.<jupyter_code>top_words_percat_double = []
for df_cat in df_categorieen:
    top_words_percat_double.append(word_count(df_cat,2))
df_wc_double = pd.concat(top_words_percat_double, axis=1)
df_wc_double.columns = col_names_wordcount
df_wc_double<jupyter_output>Empty vocabulary
Empty vocabulary
Empty vocabulary<jupyter_text>Hier worden de frequenties van de unigrams op een alternatieve manier berekend.<jupyter_code>from collections import Counter
from sklearn.preprocessing import LabelEncoder

def word_freq(tokens, n):
    merged = [item for sublist in tokens for item in sublist]
    counts = Counter(merged)
    top = counts.most_common(n)
    word = [w[0] for w in top]
    num = [w[1] for w in top]
    return pd.DataFrame([word, num]).T

#lijsten van dataframes
dataframes = []
test_dataframes = []

#elke issue overlopen
for i in range(len(issue_list)):
    #nieuwe dataframe voor specifieke issue
    new = complaints_df.loc[complaints_df['Issue'] == issue_list[i]]
    #eerste 5 rijen opzij houden om later te testen
    test_dataframes.append(new.iloc[:5])
    #andere rijen toevo
    dataframes.append(new.iloc[5:])

#dataframes terug aan elkaar hangen
df = pd.concat(dataframes)
test_df = pd.concat(test_dataframes)

#nummer toewijzen aan issues
LE = LabelEncoder()
complaints_df['Issue_Id'] = LE.fit_transform(complaints_df['Issue'])

#Top 20 woorden per issue

n = 20
frequencies = []

#elke issue overlopen
for i in range(len(issue_list)):
    tokens = dataframes[i]['Narrative_clean_tokenized'].tolist()
    #word_freq functie toepassen
    frequencies.append(word_freq(tokens, n))

df_freq = pd.concat(frequencies, axis=1)
#kolomnamen duidelijker maken
col_names = []
for issue in issue_list:
    col_names.append(issue)
    col_names.append('freq')
df_freq.columns = col_names
df_freq<jupyter_output><empty_output><jupyter_text>Classification Experiments: Multi-Class Text Classification Multi-Classification modellen die we zullen evalueren:- Random Forest- Linear Support Vector Machine- Multinomial Naive Bayes- Logistic Regression- K-nearest neighbors  Product bepalen via classificatie We maken een schatting van de accuraatheid van de verschillende classificatie algoritmen aan de hand van cross-validatie: De cross-validatie functie wordt voor elk model met de volgende parameters uitgevoerd:- `estimator`: het object die gebruikt wordt om de data te fitten (het model)- `X`: de features die gefit moeten worden- `y`: de target die we proberen te voorspellen (supervised learning)- `scoring`: het score object die gebruikt moet worden- `cv`: splitting strategie instellen (default = 5) om de data in sequenties van train en test stukken op te delen<jupyter_code>from sklearn.naive_bayes import MultinomialNB
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import LinearSVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import cross_val_score

models = [
    RandomForestClassifier(n_estimators=100, max_depth=5, random_state=0),
    LinearSVC(),
    MultinomialNB(),
    LogisticRegression(random_state=0),
    KNeighborsClassifier()
]

CV = 5
cv_df = pd.DataFrame(index=range(CV * len(models)))

entries = []
for model in models:
    model_name = model.__class__.__name__
    accuracies = cross_val_score(model, features, labels, scoring='accuracy', cv=CV)
    for fold_idx, accuracy in enumerate(accuracies):
        entries.append((model_name, fold_idx, accuracy))
    
cv_df = pd.DataFrame(entries, columns=['model_name', 'fold_idx', 'accuracy'])
mean_accuracy = cv_df.groupby('model_name').accuracy.mean()
std_accuracy = cv_df.groupby('model_name').accuracy.std()

acc = pd.concat([mean_accuracy, std_accuracy], axis= 1, ignore_index=True)
acc.columns = ['Mean Accuracy', 'Standard deviation']
acc
plt.figure(figsize=(8,5))
sns.boxplot(x='model_name', y='accuracy', data=cv_df, showmeans=True)
plt.title("Mean Accuracy (cv = 5)\n", size=14);<jupyter_output><empty_output><jupyter_text>We kunnen besluiten dat linear support vector classificatie de hoogste accuraatheid heeft en dus de voorkeur heeft. Om een classificatie model te bekomen aan de hand van supervised learning, dienen we de originele dataset op te splitsen in train en test subsets. Op die manier kan het model getraind en getest worden op twee verschillende datasets. Zo kunnen we het algoritme gaan testen op een dataset die het algoritme nog niet gezien heeft.<jupyter_code>from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size=0.25)

print(X_train.shape)
print(y_train.shape)

print(X_test.shape)
print(y_test.shape)<jupyter_output>(3750, 12794)
(3750,)
(1250, 12794)
(1250,)<jupyter_text>Nu kunnen we de uitkomsten van classificatie gaan voorspellen op de test subset met het getrainde model.<jupyter_code>model = LinearSVC()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)<jupyter_output><empty_output><jupyter_text>Vervolgens gaan we deze voorspellingen gaan vergelijken met onze target en hieruit een rapport genereren die evalueert hoe goed ons classificatie model werkt.<jupyter_code>from sklearn import metrics

print(metrics.classification_report(y_test, y_pred, target_names= complaints_df['Product'].unique()))<jupyter_output>precision    recall  f1-score   support

                Credit reporting, repair, or other       0.85      0.92      0.88       595
                                   Debt collection       0.79      0.78      0.78       268
         Payday loan, title loan, or personal loan       0.80      0.27      0.40        15
                                          Mortgage       0.91      0.89      0.90       114
                       Credit card or prepaid card       0.84      0.81      0.83       114
                       Checking or savings account       0.72      0.74      0.73        66
                                      Student loan       0.82      0.72      0.77        25
                             Vehicle loan or lease       0.69      0.34      0.46        32
Money transfer, virtual currency, or money service       0.75      0.43      0.55        21

                                          accuracy                           0[...]<jupyter_text>Om te gaan visualiseren hoe goed het model de categorieën voorspeld heeft, gaan we een confusion matrix genereren. Indien alle categorieën correct zouden voorspeld zijn, zouden enkel de cellen die op de diagonaal liggen een waarde mogen hebben.<jupyter_code>from sklearn.metrics import confusion_matrix

conf_mat = confusion_matrix(y_test, y_pred)
fig, ax = plt.subplots(figsize=(8,8))
sns.heatmap(conf_mat, annot=True, cmap="Blues", fmt='d', xticklabels=categories.values(), yticklabels=categories.values())
plt.ylabel('Correcte categorie')
plt.xlabel('Voorspelde categorie')
plt.title("Confusion Matrix", size=16);<jupyter_output><empty_output><jupyter_text>De diagonaal is duidelijk zichtbaar waardoor we kunnen besluiten dat ons classificatie model naar behoren werkt.  Issue bepalen via classificatie Uit de woordfrequenties van het vorige onderdeel kunnen we nu een aantal features berekenen. Term frequency en inverse document frequency (tf-idf) zijn goede features om te bepalen hoe belangrijk bepaalde woorden zijn voor een categorie. We berekenen ze aan de hand van de hulpfunctie TfidfVectorizer.<jupyter_code>from sklearn.feature_extraction.text import TfidfVectorizer

tokens = df.head(10000)['Narrative_clean_tokenized'].astype('str')

#woorden die in meer dan 95% van de narratives voorkomen en woorden die in 5 of minder narratives voorkomen negeren 
#ook bigrams in rekening nemen
tfidf_vectorizer = TfidfVectorizer(ngram_range=(1,2),
                                    min_df = 5, 
                                    max_df = .95)

#dit zijn alle features
X = tfidf_vectorizer.fit_transform(tokens)
#target
y = df.head(10000)['Issue_Id'].values

print(X.shape)
print(y.shape)<jupyter_output>(10000, 18945)
(10000,)<jupyter_text>We passen dimensionality reduction toe om de beste features uit te kiezen. Nu hebben we namelijk meer dan 18000 unieke unigrams en bigrams over 10000 rijen data, waarvan er waarschijnlijk veel niet veel nut hebben. Hiervoor gebruiken we Latent Semantic Analysis (LSA).<jupyter_code>#imports
from sklearn.decomposition import TruncatedSVD

lsa = TruncatedSVD(n_components=1000)

X = lsa.fit_transform(X)
X.shape<jupyter_output><empty_output><jupyter_text>Nu kunnen we enkele classifiers uittesten. De 5 classification modellen die eerder werden opgesomd worden hier getest.<jupyter_code>from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score

models = [
    RandomForestClassifier(n_estimators=100, random_state=3),
    #LinearSVC(),
    #MultinomialNB(),
    #LogisticRegression(random_state=0),
    KNeighborsClassifier()
]

#training en test data opsplitsen
X_train, X_test, Y_train, Y_test = train_test_split(X, 
                                                    y, 
                                                    test_size = .3, 
                                                    shuffle = True, 
                                                    stratify = y, 
                                                    random_state = 3)

model_names, accuracies, precisions, recalls, f1s = [], [], [], [], []
comparison_df = pd.DataFrame()
for model in models:
    model_names.append(model.__class__.__name__)
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    accuracies.append(accuracy_score(y_test, y_pred))
    precisions.append(precision_score(y_test, y_pred, average='macro'))
    recalls.append(recall_score(y_test, y_pred, average='macro'))
    f1s.append(f1_score(y_test, y_pred, average='macro'))

comparison_df = pd.DataFrame([model_names, accuracies, precisions, recalls, f1s]).T
comparison_df.columns = ['model', 'accuracy', 'precision', 'recall', 'f1']
comparison_df.sort_values(by='f1', ascending=False)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08404521207147386, 'fraction_numerical': 0.0170104823367031, 'mean_word_length': 4.313776015857284, 'pattern_counts': {'":': 0, '<': 109, '<?xml version=': 0, '>': 109, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '29', 'dir': 'jupyter-structured-clean-dedup', 'id': '393286', 'license': 'MIT', 'n_tokens_mistral': 8797, 'n_tokens_neox': 8319, 'n_words': 2518, 'path': 'notebooks/sprint1_supervised-learning/sprint1.ipynb', 'repo_name': 'WouterStemgee/ugent_applied-machine-learning-consumer-complaints-database', 'size': '26807'}