{"cells":[{"metadata":{},"cell_type":"markdown","source":"# **Introduktion**\n\nAtt vara anonym på internet gör det möjligt för människor att säga väldigt hatfulla saker som de normalt inte hade sagt i person. Dessa hatfulla kommentarer kan ha en stor effekt på människor och därför är syftet med detta projekt att försöka filtrera ut hatfulla kommentarer. Detta projekt är baserat på en öppen tävling på Kaggle vid namn \"Jigsaw Multilingual Toxic Comment Classification\" - alltså så skall en klassifiering göras av hatfulla kommentarer i flertal språk. Genom att identifiera och filtrera hatfulla kommentarer online så kan vi få en säkrare online-upplevelse som leder till högre produktivitet och nöje.\n\nProjektet utförs här på Kaggle för enkelhetens skull då vid försök att använda collab för att lösa problemet så har flertal problem uppstått.\n\nKaggle Tävling Länk:\n\nhttps://www.kaggle.com/c/jigsaw-multilingual-toxic-comment-classification/data","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"# Metod","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"Vi börjar som vanligt med att hämta nödvändiga bibliotek","execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"%matplotlib inline\n\nfrom tqdm.notebook import tqdm\nfrom sklearn.model_selection import train_test_split\nimport tensorflow as tf\nfrom keras.models import Sequential\nfrom keras.layers.recurrent import GRU,SimpleRNN,LSTM\nfrom keras.layers.core import Dense, Activation, Dropout\nfrom keras.layers.embeddings import Embedding\nfrom keras.layers.normalization import BatchNormalization\nfrom keras.utils import np_utils\nfrom sklearn import preprocessing, decomposition, model_selection, metrics, pipeline\nfrom keras.layers import GlobalMaxPooling1D, Conv1D, MaxPooling1D, Flatten, Bidirectional, SpatialDropout1D\nfrom keras.preprocessing import sequence, text\nfrom keras.callbacks import EarlyStopping\n\nimport sys\nimport os\nimport numpy as np\nimport pandas as pd\nimport IPython\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom plotly import graph_objs as go\nimport plotly.express as px\nimport plotly.figure_factory as ff\nfrom wordcloud import WordCloud","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Data undersökning och visualisering**\n\nDet är viktigt att vi undersöker vår data så att vi enklare kan arbeta med den och nå en så bra lösning som möjligt. Enligt själva tävlingens instruktioner så är den primära datan för tävlingen, i varje tillgänglig fil, själva comment_text kolumnen. Denna kolumn innehåller texten av en kommentar som har blivit klassificerad som 'toxic' eller 'non-toxic' (0 eller 1 i toxic kolumnen). Vårt träning set's kommentarer är enbart på engelska och kommer antingen från 'Civil' kommentarer eller Wikipedia talk page edits. Vårt test set's kommentarer är dock inte i engelska och består istället av ett flertal andra språk.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"**Hämtar tränings, validerings och test dataset (CSV filer) **","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"valid = pd.read_csv(\"/kaggle/input/jigsaw-multilingual-toxic-comment-classification/validation-processed-seqlen128.csv\")\ntrain = pd.read_csv(\"/kaggle/input/jigsaw-multilingual-toxic-comment-classification/jigsaw-toxic-comment-train-processed-seqlen128.csv\")\ntest = pd.read_csv(\"/kaggle/input/jigsaw-multilingual-toxic-comment-classification/test-processed-seqlen128.csv\")\nsubmit = pd.read_csv(\"/kaggle/input/jigsaw-multilingual-toxic-comment-classification/sample_submission.csv\")\ntrain = train[['id', 'comment_text', 'input_word_ids', 'input_mask','all_segment_id', 'toxic']].iloc[:20000] #limit på tränings set","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Vi kikar på vårt tränings dataset och dess format.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train.info()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Här ser vi tabellen för vårt träningsdata och därmed några exempel på hur kommentarerna kan se ut. Vi ser att alla är, som tidigare nämnt, på engelska och att vissa är hatfulla (toxic) och vissa inte.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train.tail(12)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"När vi tittar på vårt valideringsdata så ser vi att kommentarerna nu istället är i språken turkiska, spanska och italienska. Precis som tidigare så är kommentarerna även här antingen hatfulla eller inte. Dessa tre språk är inte de ända i denna data, enligt tävlingens sida så ser uppdelningen ut såhär för vårt valideringsdata:\n\nTurkiska = 38%\n\nSpanska = 31%\n\nAndra språk = 31%","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"valid.tail(12)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Vårt testdata visar här kommentarer med flera olika språk.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"test.tail(12)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Det kan vara bra om vi ser om det finns null värden i vår testdata. Om det finns null värden så bör vi ersätta dom innan vi går vidare - om vi lämnar null värdena som dom är så kan det skapa problem för oss i senare stadier.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train.isnull().any(),test.isnull().any() # test om det finns null värden i vår träningsdata","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Det verkar som att vi inte behöver ta itu med några null värden, vilket är positivt.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"I ovanstående tabeller så har vi sett att det finns både hatfulla och icke-hatfulla kommentarer i vår tränings- och validerings dataset, dock så verkar det som att de flesta kommentarer i vår data är icke-hatfulla. Nedanstående kod är till för att belysa hur uppdelningen faktiskt ser ut rent procentmässigt.\n\nVi ser att vårt tränings set består av cirka 85-90% icke-hatfulla kommentarer och därmed ca. 10-15% kommentarer som är hatfulla. Vår validerings set är närmare 80-82% när det kommer till icke-hatfulla kommentarer och ca. 18% hatfulla kommentarer.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train_distribution = train[\"toxic\"].value_counts().values\nvalid_distribution = valid[\"toxic\"].value_counts().values\n\nnon_toxic = [train_distribution[0] / sum(train_distribution) * 100, valid_distribution[0] / sum(valid_distribution) * 100]\ntoxic = [train_distribution[1] / sum(train_distribution) * 100, valid_distribution[1] / sum(valid_distribution) * 100]\n\nplt.figure(figsize=(9,6))\nplt.bar([0, 1], non_toxic, alpha=.4, color=\"r\", width=0.35, label=\"non-toxic\")\nplt.bar([0.4, 1.4], toxic, alpha=.4, width=0.35, label=\"toxic\")\nplt.xlabel(\"Dataset\")\nplt.ylabel(\"Percentage\")\nplt.xticks([0.2, 1.2], [\"train\", \"valid\"])\nplt.legend(loc=\"upper right\")\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Istället för att gå på ögonmått så kan vi ta fram de exakta procentvärdena för vår data...\n\nVi vet nu att vår träningsdata består av 9,74% hatfulla kommentarer och att i vår valideringsdata så är detta värde istället 15,38%.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"print(f\"Träningsdata: \\nnon-toxic rate: {train_distribution[0] / sum(train_distribution) * 100: .2f} %\\ntoxic rate: {train_distribution[1] / sum(train_distribution) * 100: .2f} %\")\nprint(f\"Valideringsdata: \\nnon-toxic rate: {valid_distribution[0] / sum(valid_distribution) * 100: .2f} %\\ntoxic rate: {valid_distribution[1] / sum(valid_distribution) * 100: .2f} %\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Då kommentarerna är texter i olika storlekar så är jag nyfiken om hur mycket längden på kommentarerna faktiskt varierar i vår data.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# möjliggör unndersökning av längden på kommentarerna i träningsdata\ntrain['char_length'] = train['comment_text'].apply(lambda x: len(str(x)))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Tittar vi på vårt histogram ser vi att de flesta kommentarerna är inom 500 tecken samtidigt som vissa går mot 2000+ tecken.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# visar plottad histogram för längd på kommentarer (antal tecken)\nsns.set()\ntrain['char_length'].hist()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Wordcloud är en funktion som gör det möjligt att se vilka ord som är mest frekventa i en datamängd av texter, vilket är perfekt att använda i vår sits där vi undersöker hatfulla ord bland en större mängd icke-hatfulla ord.\n\nTittar vi vår Wordcloud nedan ser vi att de mest frekventa orden (större) är icke-hatfulla med ord som *article, page, wikipedia* och att det är svårare att hitta hatfulla ord bland dessa. Detta överensstämmer med vår tidigare framtagna statistik om uppdelningen av hatfulla och icke-hatfulla kommentarer i vår träningsdata.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def nonan(x):\n    if type(x) == str:\n        return x.replace(\"\\n\", \"\")\n    else:\n        return \"\"\n\ntext = ' '.join([nonan(abstract) for abstract in train[\"comment_text\"]])\nwordcloud = WordCloud(max_font_size=None, background_color='black', collocations=False,\n                      width=1200, height=1000).generate(text)\nfig = px.imshow(wordcloud)\nfig.update_layout(title_text='Frekventa ord i kommentarer')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Då det är svårt att hitta hatfulla kommentarer bland de icke-hatfulla i en Wordcloud som inte separerar bland de två så gör vi nu två stycken nya Wordcloud's.\n\nVåra första Wordcloud visar nu endast ord som är frekventa i icke-hatfulla kommentarer, dessa ord känner vi igen från förra Wordclouden.\n\nVåran andra Worldcloud visar därmed endast frekventa ord i hatfulla kommentarer.\n\nDet blir tydligt att kommentarer som har klassats som icke-hatfulla inte innehåller någon form av svärord eller liknande medans kommentarer som har klassats som hatfulla innehåller en mängd olika ord som kan klassas som hatfulla. T.ex. 'fuck', 'ni**er', 'dickhead' och 'cunt'.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"subset = train.query(\"toxic == 0\")\ntext = subset.comment_text.values\nwc = WordCloud(background_color=\"black\",max_words=1500)\nwc.generate(\" \".join(text))\nplt.figure(figsize=(7.5, 7.5))\nplt.axis(\"off\")\nplt.title(\"Frekventa ord i icke-hatfulla kommentarer\", fontsize=16)\nplt.imshow(wc.recolor(colormap= 'viridis' , random_state=17))\nplt.show()\n\nsubset = train.query(\"toxic == 1\")\ntext = subset.comment_text.values\nwc = WordCloud(background_color=\"black\",max_words=1500)\nwc.generate(\" \".join(text))\nplt.figure(figsize=(7.5, 7.5))\nplt.axis(\"off\")\nplt.title(\"Frekventa ord i hatfulla kommentarer\", fontsize=16)\nplt.imshow(wc.recolor(colormap= 'viridis' , random_state=17))\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Modellering**","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"Vårt tränings set delar upp hatfulla kommentarer i olika klasser:\n\nsevere toxic\n\nobscene\n\nthreat\n\ninsult\n\nidentity hate\n\nFör att göra det lättare att tackla detta problem så kommer jag att ta bort dessa 5 klassificeringar och istället tackla problemet som ett binärt klassificerings problem - d.v.s. så är antingen en kommentar hatfull eller inte. Samt så kommer vi att göra vår träning på en delmäng av vårt dataset för att göra det enklare att träna modellen.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train = pd.read_csv('/kaggle/input/jigsaw-multilingual-toxic-comment-classification/jigsaw-toxic-comment-train.csv')\nvalidation = pd.read_csv('/kaggle/input/jigsaw-multilingual-toxic-comment-classification/validation.csv')\ntest = pd.read_csv('/kaggle/input/jigsaw-multilingual-toxic-comment-classification/test.csv')\n\ntrain.drop(['severe_toxic','obscene','threat','insult','identity_hate'], axis=1, inplace=True) # droppar klassificeringar av hatfulla kommentarer","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train = train.loc[:15000,:] #bestämmer delmäng\ntrain.shape #hämtar form på tränings set","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Vi undersöker vad max antal tecken kan vara i en kommentar vilket kan underlätta för oss senare med padding.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train['comment_text'].apply(lambda x:len(str(x).split())).max() # hämtar max antal tecken i kommentar","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Förbereder vår data","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"xtrain, xvalid, ytrain, yvalid = train_test_split(train.comment_text.values, train.toxic.values, \n                                                  stratify=train.toxic.values, \n                                                  random_state=42, \n                                                  test_size=0.2, shuffle=True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Från vad jag har sett här på Kaggle så används AUC score för själva valideringen, nedanstående kod skapar en funktion som hämtar AUC score som kommer att användas. AUC värdet ligger mellan 0 och 1, en modell med 100% fel predictions har ett AUC på 0.0; en modell som har 100% rätt har en AUC på 1.0. AUC är därmed ett sätt att mäta prestation för en modell och är ett sammanlagt mått på prestanda över alla möjliga klassificeringsgränser.\n\n*\"AUC stands for \"Area under the ROC Curve.\" That is, AUC measures the entire two-dimensional area underneath the entire ROC curve (think integral calculus) from (0,0) to (1,1).\" - Machine Learning Crash Course Google*","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def roc_auc(predictions,target):\n    '''\n    This methods returns the AUC Score when given the Predictions\n    and Labels\n    '''\n    \n    fpr, tpr, thresholds = metrics.roc_curve(target, predictions)\n    roc_auc = metrics.auc(fpr, tpr)\n    return roc_auc","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Tokenization\n\nI en RNN så sker vår input av en mening ord för ord, keras tokenizer tar alla unika ord och formar i princip en ordbok med ord och dess antal förekomster som värden. Sedan så sorteras ordboken i fallande ordningsföljd och tilldelar det första värdet 1, andra värdet 2 och så vidare. Till exempel, vi säger att av alla kommentarer så användes ordet \"article\" mest, den hade då fått index 1 och vektorn som representerar order \"article\" hade varit en så kallad \"one-hot\" vektor med värdet 1 på position 1, resterande värden 0.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# använder keras tokenizer\ntoken = text.Tokenizer(num_words=None)\nmax_len = 1500\n\ntoken.fit_on_texts(list(xtrain) + list(xvalid))\nxtrain_seq = token.texts_to_sequences(xtrain)\nxvalid_seq = token.texts_to_sequences(xvalid)\n\n#zero paddar sekvenserna\nxtrain_pad = sequence.pad_sequences(xtrain_seq, maxlen=max_len)\nxvalid_pad = sequence.pad_sequences(xvalid_seq, maxlen=max_len)\n\nword_index = token.word_index","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Nedanstående kod försöker att använda Kaggle TPU och därefter returnerna lämplig distruberings strategi","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Upptäck hårdvara, returnera lämplig distributionsstrategi\ntry:\n    # TPU detection. No parameters necessary if TPU_NAME environment variable is\n    # set: this is always the case on Kaggle.\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n    print('Running on TPU ', tpu.master())\nexcept ValueError:\n    tpu = None\n\nif tpu:\n    tf.config.experimental_connect_to_cluster(tpu)\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n    strategy = tf.distribute.experimental.TPUStrategy(tpu)\nelse:\n    # Default distribution strategy in Tensorflow. Works on CPU and single GPU.\n    strategy = tf.distribute.get_strategy()\n\nprint(\"REPLICAS: \", strategy.num_replicas_in_sync)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Prövar först med en enkel modell för att se vilket resultat som nås\n\nmodel.Sequential() säger åt keras att vi kommer bygga vårt nätverk sekventiellt. Sedan så lägger vi först till vårt Embedding lager som är ett lager av neuroner som tar in en input som är en 'one hot' vektor av varje ord och konverterar den till en 300 dimensionell vektor. Den ger oss word embedding som liknar word2vec - word2vec gör om text till en numerisk form så att neural networks kan förstå. I denna modell så är vårt embedding lager inte pre-trained; pre-trained embedding är en embedding som har tränats i en task för att sedan användas i en liknande task. Dessa embeddings är tränade på stora datauppsättningar, lagrade, och används sedan för att lösa andra problem. Sedan så har vi ett SimpleRNN lager med 100 units, notera att vi i denna modell inte använder dropout. Sist så har vi vårt Dense layer med en sigmoid aktiveringsfunktion som tar outputen från det tidigare lagret för att göra en prediction.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# En enkel modell (SimpleRNN) med ett dense layer\n\nwith strategy.scope():\n    \n    model = Sequential() #sekventiellt nätverk\n    model.add(Embedding(len(word_index) + 1, #konverterar till 300 dimensionell vektor\n                     300,\n                     input_length=max_len))\n    model.add(SimpleRNN(100))\n    model.add(Dense(1, activation='sigmoid'))\n    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])\n    \nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Träning av modellen","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model.fit(xtrain_pad, ytrain, nb_epoch=5, batch_size=64)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Beräkna AUC Score","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"scores = model.predict(xvalid_pad)\nprint(\"AUC: %.2f%%\" % (roc_auc(scores,yvalid)))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Vi använder oss utav Word embeddings\n\nWord embeddings är en typ av ord representation som tillåter ord med liknande mening att ha liknande representation\n\nMer specifikt så använder vi oss utav GloVe, vilket är ett av de förtränade embeddings som jag tidigare nämnde i vår mer enkla modell. För att förenkla allt så kan man säga att meningen bakom GloVe som ett pre-trained word embedding är att härleda förhållandet mellan ord från global statistik.\n\n\"GloVe is an unsupervised learning algorithm for obtaining vector representations for words. Training is performed on aggregated global word-word co-occurrence statistics from a corpus, and the resulting representations showcase interesting linear substructures of the word vector space.\" - Stanford","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# load the GloVe vectors in a dictionary:\n\nembeddings_index = {}\nf = open('/kaggle/input/glove840b300dtxt/glove.840B.300d.txt','r',encoding='utf-8') #precis som vår data för kommentarer så lägger vi till GloVe i vår Kaggle-databas\nfor line in tqdm(f):\n    values = line.split(' ')\n    word = values[0]\n    coefs = np.asarray([float(val) for val in values[1:]])\n    embeddings_index[word] = coefs\nf.close()\n\nprint('Found %s word vectors.' % len(embeddings_index))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# skapa en embedding matris för orden vi har i vår datauppsättning\nembedding_matrix = np.zeros((len(word_index) + 1,300))\nfor word, i in tqdm(word_index.items()):\n    embedding_vector = embeddings_index.get(word)\n    if embedding_vector is not None:\n        embedding_matrix[i] = embedding_vector","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Mer komplex modell\n\nFörst så beräknar vi vår embedding matris för vår orduppsättning från den pre-trained GloVe vektorn. Sedan, medans vi bygger vårt embedding lager så passerar vi embedding matrisen som weights till lagret istället för att träna den över orduppsättningen; därför så sätter vi trainable = False. Resterande delar av modellen är likande bortsett från att vi nu anävnder 3 stycken LSTM layers med 100 units istället för en enstaka SimpleRNN. Jag har valt i båda modellerna att använda mig av binary crossentropy som förlustfunktion, detta är för att det vi försöker lösa är, om vi förenklar det, binärt. Med det menar jag att antingen så är en kommentar toxic (1) eller non-toxic (0). Förlustfunktionen binary crossentropy kändes då lämplig då den används för ja/nej klassificeringar.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time\nwith strategy.scope():\n    \n    model = Sequential() # sekventiellt nätverk\n    model.add(Embedding(len(word_index) + 1, # embedding lager som nu använder GloVe istället\n                     300,\n                     weights=[embedding_matrix],\n                     input_length=max_len,\n                     trainable=False))\n\n    model.add(LSTM(100, dropout=0.3, recurrent_dropout=0.3,return_sequences=True)) # tre LSTM lager med 100 units, dropout har lagts till\n    model.add(LSTM(100, dropout=0.3, recurrent_dropout=0.3,return_sequences=True))\n    model.add(LSTM(100, dropout=0.3, recurrent_dropout=0.3))\n    model.add(Dense(1, activation='sigmoid'))\n    \n    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])\n    \nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.fit(xtrain_pad, ytrain, nb_epoch=5, batch_size=64)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"scores = model.predict(xvalid_pad)\nprint(\"Auc: %.2f%%\" % (roc_auc(scores,yvalid)))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Resultat\n\nResults – What answer was found to the research question; what did the study find? Was the tested hypothesis true?\n\n**Resultat första, enkla, modell**\n\nEpoch 5/5\n\n12000/12000 [==============================] - 189s 16ms/step - loss: 0.0015 - accuracy: 0.9999\n\nAUC: 0.89\n\nVi kan se att vår modell når en noggrannhet på 1 vilket självklart tyder på att vi övertränar extremt mycket. Detta visar att vi bör kanske använda en mer avancerad modell och t.ex. använda dropout för att nå bättre resultat. Även fast modellen är simpel och övertränar så nåddes fortfarande ett AUC score på 0.82 utan mycket ansträngning.\n\n**Resultat andra, mer komplexa, modell**\n\nEpoch 5/5\n12000/12000 [==============================] - 801s 67ms/step - loss: 0.1069 - accuracy: 0.9589\n\nAUC: 0.97\n\nDenna modell presterar bättre jämfört med den tidigare. Tittar vi på vår förlust och noggrannhet för båda modellerna så ser vi en stor skillnad i resultat.\n\nUrsprunglig modell:\n\nloss: 0.0015 accuracy: 0.9999\n\nNy modell:\n\nloss: 0.1069 accuracy: 0.9589\n\nResultaten från den första modellen är icke-trovärdigt och visar tecken på överträning, om ens noggrannhet ligger på 1 så är det något som inte stämmer helt enkelt.\n\nI vår andra modell så ser resultaten mycket mer trovärdiga ut med en förlust på 0.1069 och en noggrannhet på 0.9589. Samt så nådde vi en AUC på 0.97 vilket är betydligt bättre än vår första modell som till och med var extremt övertränad. Detta syftar på att vår nya modell har presterat bra för vårt problem.\n","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"# Diskussion\n\n**Vad för slutsatser kan vi göra?**\n\nDet är klart och tydligt att en allt för simpel modell inte kommer prestera bra för vårt problem då det är en stor datamängd och ett komplext problem. Vår andra modell som var lite mer anpassad för problemet presterade bättre och nådde bra resultet för AUC. Dock så är såklart inte modellen perfekt på något vis, jag tror att det går att lösa problemet allt bättre med en mer advancerad lösning/modell. Något som kommer till tanke efter duggorna vi hade är BERT och dess förmåga att lösa sådana här problem effektivt. BERT har setts som en ny era inom Natural Language Processing (NLP) och är en modell som har slagit nya rekord för hur bra en modell kan hantera språkbaserade problem. BERT-modellen är open-sourced och därmed tillgänglig för alla att ladda ner versioner av modellen som redan har blivit tränade på stora datauppsättningar. Detta gör det möjligt för att vem som helst som bygger en machine learning modell för språkbehandling att använda denna kraftfulla komponent vilket sparar tid, energi, kunskap och resurser som hade gått till att träna en språkbehandlings modell från grunden. Jag skulle säga att mitt perspektiv framåt är att implementera BERT för detta problem och se vad man hade fått för resultat och hur smidigt det skulle vara jämfört med mitt ursprungliga tillvägagångsätt. Jag har inte jobbat med NLP till denna grad förr men det verkar väldigt intressant och användbart, detta känns som att detta är endast ett scenario där det kan vara smart att implementera lösningar med NLP. Hatfulla kommentarar tror jag påverkar människor allt mer än vad man tror och ser, speciellt online där människor oftast är anonyma när dessa kommentarer görs. Det går från person till person, personligen tror jag inte att jag skulle bli allt för påverkad av sådana kommentarer, men det är naturligt att många människor skulle bli det och därför så är det viktigt att sådana här problem undersöks mer så att vi effektivt kan motverka hatfulla kommentarer online för att människor ska få en bättre upplevelse!\n\n\n**Litteratur och kod som använts:**\n\nBinary crossentropy\n\nhttps://peltarion.com/knowledge-center/documentation/modeling-view/build-an-ai-model/loss-functions/binary-crossentropy\n\nPretrained word embedding NLP\n\nhttps://www.analyticsvidhya.com/blog/2020/03/pretrained-word-embeddings-nlp/\n\nWord2Vec\n\nhttps://pathmind.com/wiki/word2vec\n\nGloVe (datauppsättning och information)\n\nhttps://nlp.stanford.edu/projects/glove/\n\nAUC\n\nhttps://developers.google.com/machine-learning/crash-course/classification/roc-and-auc\n\nNLP och Wordcloud's\n\nhttps://www.kaggle.com/arthurtok/spooky-nlp-and-topic-modelling-tutorial\n\nKaggle Tävlingen som detta projekt är baserat på, datauppsättningen har hämtats härifrån\n\nhttps://www.kaggle.com/c/jigsaw-multilingual-toxic-comment-classification/overview\n\nExploratory Data Analysis (EDA), bra förklaring och visualisering av data.\n\nhttps://www.kaggle.com/jagangupta/stop-the-s-toxic-comments-eda\n\nEn kernel för liknande äldre tävling\n\nhttps://www.kaggle.com/rhodiumbeng/classifying-multi-label-comments-0-9741-lb\n","execution_count":null}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}