{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# **Quora Insincere Questions Classification**\n\n1. Mô tả bài toán\n  - Kaggle có cung cấp một số công cụ Embeddings. Do đó em sẽ sử dụng các tool Embeddings kết hợp với hình của mình .\n\n  - Ta thấy đây là một bài toán phân loại nhị phân. Theo như yêu cầu bài toán, nếu câu hỏi đó là insincere question thì label = 1, còn nếu nó là sincere question thì có  label = 0.\n  \n  Như vậy, từ bài toán này, ta thấy được:\n  - Đầu vào: một câu hỏi trên Quora.\n  - Đầu ra: kết quả của bài toán để xem câu hỏi có phải sincere hay không, nó có giá trị là 0 hoặc 1.\n  ","metadata":{"papermill":{"duration":0.048188,"end_time":"2021-05-06T11:21:57.445836","exception":false,"start_time":"2021-05-06T11:21:57.397648","status":"completed"},"tags":[],"id":"conceptual-elizabeth"}},{"cell_type":"markdown","source":"Đầu tiên, import các thư viện và print ra địa chỉ của các directory","metadata":{"papermill":{"duration":0.049418,"end_time":"2021-05-06T11:21:57.54371","exception":false,"start_time":"2021-05-06T11:21:57.494292","status":"completed"},"tags":[],"id":"continued-injury"}},{"cell_type":"code","source":"# Import các thư viện cần thiết\nimport os\nimport time\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport seaborn as sns\nimport matplotlib.pyplot as plt \ncolor = sns.color_palette()\n%matplotlib inline\n\nfrom plotly import tools\nimport plotly.offline as py\npy.init_notebook_mode(connected=True)\nimport plotly.graph_objs as go\nfrom tqdm import tqdm\nimport math\nfrom sklearn.model_selection import train_test_split\nfrom sklearn import metrics\n\nfrom keras.preprocessing.text import Tokenizer\nfrom keras.preprocessing.sequence import pad_sequences\nfrom keras.layers import Dense, Input, LSTM, Embedding, Dropout, Activation, Conv1D, LSTM, GRU\nfrom keras.layers import Bidirectional, GlobalMaxPool1D\nfrom keras.models import Model, Sequential\nfrom keras import initializers, regularizers, constraints, optimizers, layers\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","papermill":{"duration":0.064959,"end_time":"2021-05-06T11:21:57.657161","exception":false,"start_time":"2021-05-06T11:21:57.592202","status":"completed"},"tags":[],"id":"systematic-samba","outputId":"aa7167c2-9ccc-4eb8-978d-4f22783813f3","execution":{"iopub.status.busy":"2021-06-10T17:20:18.033709Z","iopub.execute_input":"2021-06-10T17:20:18.034123Z","iopub.status.idle":"2021-06-10T17:20:18.066903Z","shell.execute_reply.started":"2021-06-10T17:20:18.034088Z","shell.execute_reply":"2021-06-10T17:20:18.065224Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"  Sau đó, ta sẽ cho đọc các file csv (train.csv và test.csv) bằng read_csv và tạo các dataframe (trainData và testData), sau đó in ra shape của chúng.","metadata":{"papermill":{"duration":0.049124,"end_time":"2021-05-06T11:21:57.854373","exception":false,"start_time":"2021-05-06T11:21:57.805249","status":"completed"},"tags":[],"id":"excellent-timer"}},{"cell_type":"code","source":"train_df = pd.read_csv(\"../input/quora-insincere-questions-classification/train.csv\")\ntest_df = pd.read_csv(\"../input/quora-insincere-questions-classification/test.csv\")\nprint(\"Train shape : \",train_df.shape)\nprint(\"Test shape : \",test_df.shape)","metadata":{"papermill":{"duration":5.026171,"end_time":"2021-05-06T11:22:02.931029","exception":false,"start_time":"2021-05-06T11:21:57.904858","status":"completed"},"tags":[],"id":"accomplished-princess","outputId":"6e882eea-2b91-491e-98e2-d506b7f37e83","execution":{"iopub.status.busy":"2021-06-10T16:52:24.839203Z","iopub.execute_input":"2021-06-10T16:52:24.839618Z","iopub.status.idle":"2021-06-10T16:52:28.634903Z","shell.execute_reply.started":"2021-06-10T16:52:24.839585Z","shell.execute_reply":"2021-06-10T16:52:28.633678Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":" Như vậy, ta có thể thấy được,có tổng cộng 1306122 câu hỏi trong tập train và tập test có 375806 câu hỏi. Tiếp theo, em sẽ tải thử các dataframe trainData và testData","metadata":{"papermill":{"duration":0.049893,"end_time":"2021-05-06T11:22:03.030887","exception":false,"start_time":"2021-05-06T11:22:02.980994","status":"completed"},"tags":[],"id":"early-clone"}},{"cell_type":"code","source":"train_df","metadata":{"papermill":{"duration":0.075065,"end_time":"2021-05-06T11:22:03.155429","exception":false,"start_time":"2021-05-06T11:22:03.080364","status":"completed"},"tags":[],"id":"positive-exemption","outputId":"2cba39fc-7926-4393-f413-10ba36ebd6ac","execution":{"iopub.status.busy":"2021-06-10T16:52:30.366627Z","iopub.execute_input":"2021-06-10T16:52:30.367008Z","iopub.status.idle":"2021-06-10T16:52:30.382168Z","shell.execute_reply.started":"2021-06-10T16:52:30.366977Z","shell.execute_reply":"2021-06-10T16:52:30.381123Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Trong trainData:\n- qid là mã câu hỏi\n- question_text là nội dung câu hỏi\n- target là chính là label","metadata":{"papermill":{"duration":0.049784,"end_time":"2021-05-06T11:22:03.254821","exception":false,"start_time":"2021-05-06T11:22:03.205037","status":"completed"},"tags":[],"id":"aboriginal-nicholas"}},{"cell_type":"markdown","source":"Sau đó, em sẽ cho in số lần label 0 và label 1 tương ứng với câu hỏi sincere và insincere\nxuất hiện ở tập train bằng hàm np.bincount","metadata":{"papermill":{"duration":0.050256,"end_time":"2021-05-06T11:22:03.568919","exception":false,"start_time":"2021-05-06T11:22:03.518663","status":"completed"},"tags":[],"id":"vanilla-system"}},{"cell_type":"code","source":"a,b = np.bincount(train_df['target'])\nprint(\"Number of sincere question: \",a)\nprint(\"Number of insincere question: \",b)","metadata":{"papermill":{"duration":0.0636,"end_time":"2021-05-06T11:22:03.682608","exception":false,"start_time":"2021-05-06T11:22:03.619008","status":"completed"},"tags":[],"id":"molecular-attack","outputId":"65f23ba9-2aa1-4bf6-aa4d-e9c5faa03f4d","execution":{"iopub.status.busy":"2021-06-10T16:52:33.466764Z","iopub.execute_input":"2021-06-10T16:52:33.467172Z","iopub.status.idle":"2021-06-10T16:52:33.479041Z","shell.execute_reply.started":"2021-06-10T16:52:33.467134Z","shell.execute_reply":"2021-06-10T16:52:33.477919Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cnt_srs = train_df['target'].value_counts()\n\n## target distribution ##\nlabels = (np.array(cnt_srs.index))\nsizes = (np.array((cnt_srs / cnt_srs.sum())*100))\n\ntrace = go.Pie(labels=labels, values=sizes)\nlayout = go.Layout(\n    title='Target distribution',\n    font=dict(size=18),\n    width=400,\n    height=600,\n)\ndata = [trace]\nfig = go.Figure(data=data, layout=layout)\npy.iplot(fig, filename=\"usertype\")","metadata":{"execution":{"iopub.status.busy":"2021-06-10T16:52:41.81883Z","iopub.execute_input":"2021-06-10T16:52:41.819216Z","iopub.status.idle":"2021-06-10T16:52:41.873744Z","shell.execute_reply.started":"2021-06-10T16:52:41.819183Z","shell.execute_reply":"2021-06-10T16:52:41.872489Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Nhìn vào biểu đồ ta có thể thấy 2 nhãn không những không đồng đều mà còn có chênh lệch lớn\n- Sincere question(93,8%) chiếm gấp nhiều lần insincere question(6,19%)\n- Vấn đề đặt ra: Dữ liệu đang có sự chênh lệch lớn. \n- Cách giải quyết: Đánh giá mô hình bằng F1-score thay vì Accuracy","metadata":{}},{"cell_type":"code","source":"test_df","metadata":{"papermill":{"duration":0.063397,"end_time":"2021-05-06T11:22:03.367695","exception":false,"start_time":"2021-05-06T11:22:03.304298","status":"completed"},"tags":[],"id":"inner-lincoln","outputId":"0ebfe68b-3d91-44ae-f32c-e8a713e4cde7","execution":{"iopub.status.busy":"2021-06-10T16:52:45.506905Z","iopub.execute_input":"2021-06-10T16:52:45.507253Z","iopub.status.idle":"2021-06-10T16:52:45.521451Z","shell.execute_reply.started":"2021-06-10T16:52:45.507221Z","shell.execute_reply":"2021-06-10T16:52:45.520274Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Trong testData:\n- qid là mã câu hỏi\n- question_text là nội dung câu hỏi","metadata":{"papermill":{"duration":0.050818,"end_time":"2021-05-06T11:22:03.468579","exception":false,"start_time":"2021-05-06T11:22:03.417761","status":"completed"},"tags":[],"id":"active-brighton"}},{"cell_type":"markdown","source":"**2. Preprocessing**\n\n Từ dữ liệu ở tập train và tập test, chỉ dùng mỗi câu hỏi không thì máy không thể hiểu được. Vì vậy, em phải biến đổi các câu hỏi trong train set và test set thành các ký tự mà máy có thể hiểu được.\n \n- Đầu tiên em sẽ chia tập train thành 2 phần là train và validate\n- Sau đó em sẽ đặt một số biến để dùng lúc sau, trong đó: \n    \n    max_len sẽ là số lượng các từ tối đa có thể có trong một câu. Thông thường thì các câu có độ dài rất khác nhau, câu  thì quá dài, câu thì rất ngắn, vì vậy việc đặt max_len sẽ thống nhất các câu có cùng một độ dài nhất định\n    \n    embed_size sẽ là độ lớn của các vector mà đại diện cho mỗi từ vựng có trong các câu hỏi","metadata":{"papermill":{"duration":0.052293,"end_time":"2021-05-06T11:22:04.215644","exception":false,"start_time":"2021-05-06T11:22:04.163351","status":"completed"},"tags":[],"id":"shared-accountability"}},{"cell_type":"code","source":"# lay ra 10% train de lam validate\ntrain_df, val_df = train_test_split(train_df, test_size=0.1, random_state=2021)\n\n# dat mot so bien \nembed_size = 300 # Độ dài của mỗi vector từ\nmax_features = 50000 # Số lượng từ tối đa trong từ điển sẽ sử dụng\nmax_len = 100 # Số lượng từ tối đa trong một câu\n","metadata":{"papermill":{"duration":0.059806,"end_time":"2021-05-06T11:22:04.326783","exception":false,"start_time":"2021-05-06T11:22:04.266977","status":"completed"},"tags":[],"id":"wanted-sitting","execution":{"iopub.status.busy":"2021-06-10T16:53:25.636525Z","iopub.execute_input":"2021-06-10T16:53:25.637601Z","iopub.status.idle":"2021-06-10T16:53:26.644903Z","shell.execute_reply.started":"2021-06-10T16:53:25.637521Z","shell.execute_reply":"2021-06-10T16:53:26.644037Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"1. Vấn đề đặt ra: Nếu để dữ liệu là các chuỗi thì máy sẽ không hiểu được. \n2. Cách giải quyết: Em nghĩ đến việc biến đổi mỗi từ thành kí tự mà máy có thể hiểu được. \n- Hàm dưới đây là hàm clean_special_chars dùng để biến đổi các ký tự đặc biệt trong các câu. Hàm này sử dụng một dict chứa các key là các ký tự đặc biệt còn các value là các ký tự mà có thể biểu diễn được dưới dạng các vector. \n- Sau đó, đối với từng từ thì sẽ được kiểm tra, nếu nó là là ký tự đặc biệt có trong dict này thì sẽ bị đổi sang dạng value của nó. \n- Sau đó, đối với các từ bị dích với các ký tự đặc biệt thì tách các ký tự đặc biệt.\n","metadata":{}},{"cell_type":"code","source":"def clean_special_chars(text):\n    punct = \"/-'?!.,#$%\\'()*+-/:;<=>@[\\\\]^_`{|}~\" + '\"\"“”’' + '∞θ÷α•à−β∅³π‘₹´°£€\\×™√²—–&'\n    \n    punct_mapping = {\n        \"‘\": \"'\", \"₹\": \"e\", \"´\": \"'\", \"°\": \"\", \"€\": \"e\", \"™\": \"tm\", \"√\": \" sqrt \", \"×\": \"x\", \"²\": \"2\", \n        \"—\": \"-\", \"–\": \"-\", \"’\": \"'\", \"_\": \"-\", \"`\": \"'\", '“': '\"', '”': '\"', '“': '\"', \"£\": \"e\", '∞': 'infinity', \n        'θ': 'theta', '÷': '/', 'α': 'alpha', '•': '.', 'à': 'a', '−': '-', 'β': 'beta', '∅': '', '³': '3', 'π': 'pi',\n        '\\u200b': ' ', '…': ' ... ', '\\ufeff': '', 'करना': '', 'है': ''\n    }\n    \n    for p in punct_mapping:\n        text = text.replace(p, punct_mapping[p])\n    \n    for p in punct:\n        text = text.replace(p, f' {p} ')\n    \n    return text","metadata":{"execution":{"iopub.status.busy":"2021-06-10T16:53:29.05912Z","iopub.execute_input":"2021-06-10T16:53:29.059721Z","iopub.status.idle":"2021-06-10T16:53:29.068135Z","shell.execute_reply.started":"2021-06-10T16:53:29.059683Z","shell.execute_reply":"2021-06-10T16:53:29.067374Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Hàm dưới đây là hàm correct_spelling, nó có cơ chế hoạt động gần giống với hàm clean_special_chars, nó cũng có một dict riêng có key là hàng loạt các từ bị sai chính tả và value là các từ đó nhưng là đúng chính tả, sau đó nó soát trong các câu hỏi, nếu có từ nào là key trong dict này thì sẽ đổi chỗ cho value của nó.","metadata":{}},{"cell_type":"code","source":"def correct_spelling(x):\n    mispell_dict = {\n        'colour': 'color', 'centre': 'center', 'favourite': 'favorite', 'travelling': 'traveling', \n        'counselling': 'counseling', 'theatre': 'theater', 'cancelled': 'canceled', 'labour': 'labor', \n        'organisation': 'organization', 'wwii': 'world war 2', 'citicise': 'criticize', 'youtu ': 'youtube ', \n        'Qoura': 'Quora', 'sallary': 'salary', 'Whta': 'What', 'narcisist': 'narcissist', 'howdo': 'how do', \n        'whatare': 'what are', 'howcan': 'how can', 'howmuch': 'how much', 'howmany': 'how many', 'whydo': 'why do', \n        'doI': 'do I', 'theBest': 'the best', 'howdoes': 'how does', 'mastrubation': 'masturbation', \n        'mastrubate': 'masturbate', \"mastrubating\": 'masturbating', 'pennis': 'penis', 'Etherium': 'Ethereum', \n        'narcissit': 'narcissist', 'bigdata': 'big data', '2k17': '2017', '2k18': '2018', 'qouta': 'quota', \n        'exboyfriend': 'ex boyfriend', 'airhostess': 'air hostess', \"whst\": 'what', 'watsapp': 'whatsapp', \n        'demonitisation': 'demonetization', 'demonitization': 'demonetization', 'demonetisation': 'demonetization', \n        'pokémon': 'pokemon'\n    }\n    for word in mispell_dict.keys():\n        x = x.replace(word, mispell_dict[word])\n    return x","metadata":{"execution":{"iopub.status.busy":"2021-06-10T16:53:30.758856Z","iopub.execute_input":"2021-06-10T16:53:30.759479Z","iopub.status.idle":"2021-06-10T16:53:30.767572Z","shell.execute_reply.started":"2021-06-10T16:53:30.759442Z","shell.execute_reply":"2021-06-10T16:53:30.766798Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Hàm dataHandling dưới đây được dùng để xử lý tập train và tập set, và nó có đầu ra là tập train, tập val, tập test, label của tập train, label của tập test và cuối cùng là word_index của tập từ vựng trong các câu hỏi của tập train. Hàm dataHandling sẽ xử lý các việc sau: \n* Lấy ra label của tập train, label của tập test\n* Dùng các hàm lower, clean_special_chars và correct_spelling đã nói ở trên để biến đổi tập train, tập val và tập test\n* Dùng Tokenizer để tạo word index của các từ qua fit_on_texts và biến đổi các câu thành sequence các số \n* Dùng pad_sequences để chỉnh độ dài của các sequence vừa tạo dựa vào chỉ số max_len","metadata":{}},{"cell_type":"code","source":"def dataHandling(trainData, testData, maxfeatures, maxlen):\n    Traindf, Valdf = train_test_split(trainData, test_size=0.1, random_state=2018)\n    Train_y = Traindf['target'].values\n    Val_y = Valdf['target'].values\n    Train_X = Traindf['question_text'].apply(lambda x: x.lower())\n    Train_X = Train_X.apply(lambda x: clean_special_chars(x))\n    Train_X = Train_X.apply(lambda x: correct_spelling(x))\n    Val_X = Valdf['question_text'].apply(lambda x: x.lower())\n    Val_X = Val_X.apply(lambda x: clean_special_chars(x))\n    Val_X = Val_X.apply(lambda x: correct_spelling(x))\n    Test_X = testData['question_text'].apply(lambda x: x.lower())\n    Test_X = Test_X.apply(lambda x: clean_special_chars(x))\n    Test_X = Test_X.apply(lambda x: correct_spelling(x))\n    tokenizer = Tokenizer(num_words=max_features)\n    tokenizer.fit_on_texts(list(Train_X))\n    Train_X = tokenizer.texts_to_sequences(Train_X)\n    Val_X = tokenizer.texts_to_sequences(Val_X)\n    Test_X = tokenizer.texts_to_sequences(Test_X)\n    Train_X = pad_sequences(Train_X, maxlen=maxlen)\n    Val_X = pad_sequences(Val_X, maxlen=maxlen)\n    Test_X = pad_sequences(Test_X, maxlen=maxlen)\n    return Train_X, Train_y, Test_X, Val_X, Val_y, tokenizer.word_index","metadata":{"execution":{"iopub.status.busy":"2021-06-10T16:53:32.542806Z","iopub.execute_input":"2021-06-10T16:53:32.543305Z","iopub.status.idle":"2021-06-10T16:53:32.553499Z","shell.execute_reply.started":"2021-06-10T16:53:32.543271Z","shell.execute_reply":"2021-06-10T16:53:32.552208Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Dùng hàm dataHandling này để lấy được các giá trị nói ở trên: Train_X, Train_y, Test_X, Val_X, Val_y, WordIndex","metadata":{}},{"cell_type":"code","source":"Train_X, Train_y, Test_X, Val_X, Val_y, WordIndex = dataHandling(train_df, test_df, max_features, max_len)","metadata":{"execution":{"iopub.status.busy":"2021-06-10T16:53:34.94266Z","iopub.execute_input":"2021-06-10T16:53:34.943139Z","iopub.status.idle":"2021-06-10T16:55:36.737893Z","shell.execute_reply.started":"2021-06-10T16:53:34.943107Z","shell.execute_reply":"2021-06-10T16:55:36.73695Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Ta xét đến các file được kaggle cung cấp trong file zip nên ta unzip file embeddings.zip và sẽ in ra các file có trong file zip này","metadata":{}},{"cell_type":"code","source":"from zipfile import ZipFile\nfile_name='/kaggle/input/quora-insincere-questions-classification/embeddings.zip'\nz=ZipFile(file_name)\nprint(z.namelist())","metadata":{"execution":{"iopub.status.busy":"2021-06-10T16:56:31.079204Z","iopub.execute_input":"2021-06-10T16:56:31.079604Z","iopub.status.idle":"2021-06-10T16:56:31.094863Z","shell.execute_reply.started":"2021-06-10T16:56:31.079571Z","shell.execute_reply":"2021-06-10T16:56:31.093503Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Tiếp theo, em sẽ extract các file trong file zip ra để lưu các file embedding vào các biến GLOVE_FILE, PARAGRAM_FILE, WIKI_NEWS_FILE.","metadata":{}},{"cell_type":"code","source":"GLOVE_FILE = z.extract('glove.840B.300d/glove.840B.300d.txt')\nPARAGRAM_FILE = z.extract('paragram_300_sl999/paragram_300_sl999.txt')\nWIKI_NEWS_FILE = z.extract('wiki-news-300d-1M/wiki-news-300d-1M.vec')","metadata":{"execution":{"iopub.status.busy":"2021-06-10T16:56:40.358604Z","iopub.execute_input":"2021-06-10T16:56:40.359009Z","iopub.status.idle":"2021-06-10T16:59:26.772026Z","shell.execute_reply.started":"2021-06-10T16:56:40.358973Z","shell.execute_reply":"2021-06-10T16:59:26.771188Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Hàm embeddingsIndex được dùng để convert các file embedding sang dạng index hoặc là dạng dict để có thể biểu diễn nó dưới dạng key: value, trong đó value sẽ là một array với 300 element. \n- Trong đó, hàm split sẽ tách key (các từ có trong vocabulary) với các số còn lại trong dòng. \n- Sau đó, hàm fromstring để biến các số đó thành một array, ta gọi array này là value. \n- Sau đó gán các key và value lại thành một embeddings_index.","metadata":{}},{"cell_type":"code","source":"def embeddingsIndex(file):\n    embeddings_index = {}\n    f = open(file, encoding = 'latin')\n    for line in f:\n        word, coefs = line.split(maxsplit=1)\n        coefs = np.fromstring(coefs, \"f\", sep=\" \")\n        embeddings_index[word] = coefs\n    f.close()\n    print('Found %s word vectors.' % len(embeddings_index))\n    return embeddings_index","metadata":{"execution":{"iopub.status.busy":"2021-06-10T16:59:52.991421Z","iopub.execute_input":"2021-06-10T16:59:52.992079Z","iopub.status.idle":"2021-06-10T16:59:52.998032Z","shell.execute_reply.started":"2021-06-10T16:59:52.992026Z","shell.execute_reply":"2021-06-10T16:59:52.997193Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Hàm embeddingsIndexF có cơ chế hoạt động gần giống với hàm embeddingsIndex do nó cũng dựa vào việc liên tục thêm vào các phần tử có dạng (key:value) vào trong một dictionary nào đó và trả ra đầu ra chính là dictionary đó.","metadata":{}},{"cell_type":"code","source":"def embeddingsIndexF(file):\n    embeddings_index = {}\n    f = open(file, encoding = 'latin')\n    for line in f:\n        if(len(line) > 100):\n            word, coefs = line.split(maxsplit=1)\n            coefs = np.fromstring(coefs, \"f\", sep=\" \")\n            embeddings_index[word] = coefs\n    f.close()\n    print('Found %s word vectors.' % len(embeddings_index))\n    return embeddings_index","metadata":{"execution":{"iopub.status.busy":"2021-06-10T17:00:02.347494Z","iopub.execute_input":"2021-06-10T17:00:02.348058Z","iopub.status.idle":"2021-06-10T17:00:02.353531Z","shell.execute_reply.started":"2021-06-10T17:00:02.348023Z","shell.execute_reply":"2021-06-10T17:00:02.352774Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Sau đó, em dùng hàm embeddingsIndex đã tạo để tạo ra 3 index riêng cho Glove, Paragram và Fasttext","metadata":{}},{"cell_type":"code","source":"glove_index = embeddingsIndex(GLOVE_FILE)\nparagram_index = embeddingsIndex(PARAGRAM_FILE)\nfasttext_index = embeddingsIndexF(WIKI_NEWS_FILE)","metadata":{"execution":{"iopub.status.busy":"2021-06-10T17:09:20.954896Z","iopub.execute_input":"2021-06-10T17:09:20.95559Z","iopub.status.idle":"2021-06-10T17:16:18.833719Z","shell.execute_reply.started":"2021-06-10T17:09:20.955537Z","shell.execute_reply":"2021-06-10T17:16:18.83245Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Trong hàm embeddingsMatrix, em sẽ gọi từng từ có trong word_index vừa được tạo từ hàm dataHandling và dùng từ vừa được gọi để tra từ đó trong một embedding index, từ đó, em sẽ có một vector tương ứng với từ đó. Sau đó, em thêm các giá trị của value này vào một ma trận gọi là embedding_matrix, theo thứ tự đúng với thứ tự của các từ trong word_index. Cuối cùng, hàm này sẽ có output chính là cái embedding_matrix.","metadata":{}},{"cell_type":"code","source":"def embeddingsMatrix(word_index, embeddings_index):\n    embedding_matrix = np.zeros((len(word_index) + 1, 300))\n    for word, i in word_index.items():\n        embedding_vector = embeddings_index.get(word)\n        if embedding_vector is not None and (embedding_matrix[i].shape == embedding_vector.shape):\n            embedding_matrix[i] = embedding_vector\n    return embedding_matrix","metadata":{"execution":{"iopub.status.busy":"2021-06-10T17:17:01.183057Z","iopub.execute_input":"2021-06-10T17:17:01.183659Z","iopub.status.idle":"2021-06-10T17:17:01.189353Z","shell.execute_reply.started":"2021-06-10T17:17:01.183621Z","shell.execute_reply":"2021-06-10T17:17:01.188518Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Sau đó, em dùng hàm embeddingsMatrix vừa tạo để tạo ra các matrix cho từng embedding một","metadata":{}},{"cell_type":"code","source":"glove_matrix = embeddingsMatrix(WordIndex, glove_index)\nparagram_matrix = embeddingsMatrix(WordIndex, paragram_index)\nfasttext_matrix = embeddingsMatrix(WordIndex, fasttext_index)","metadata":{"execution":{"iopub.status.busy":"2021-06-10T17:17:03.910098Z","iopub.execute_input":"2021-06-10T17:17:03.910701Z","iopub.status.idle":"2021-06-10T17:17:07.024416Z","shell.execute_reply.started":"2021-06-10T17:17:03.910664Z","shell.execute_reply":"2021-06-10T17:17:07.02366Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Sau đó em sẽ xóa các biến glove_index, paragram_index, fasttext_index, trainData, WordIndex","metadata":{}},{"cell_type":"code","source":"del glove_index, paragram_index, fasttext_index, train_df, WordIndex\nimport gc\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2021-06-10T17:17:12.966166Z","iopub.execute_input":"2021-06-10T17:17:12.966686Z","iopub.status.idle":"2021-06-10T17:17:17.021264Z","shell.execute_reply.started":"2021-06-10T17:17:12.966651Z","shell.execute_reply":"2021-06-10T17:17:17.020082Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"3. Model\n- Đặt vấn đề: Sự dụng mô hình\n- Hướng tiếp cận: Đây là một bài toán phân loại nhị phân Một số mô hình ta có thể nghĩ đến là Logistic Regression, SVM, .. nhưng em nghĩ đây là một bài toán về chuỗi nên việc xử lý chuỗi như thế nào trước khi huấn luyện quan trọng hơn là sử dụng mô hình nào. Để kết hợp với Embeddings,em sẽ sử dụng model neural network của keras để train dữ liệu này dựa trên các embeddings_matrix vừa được tạo\n- Phân tích: Trong đó, model của keras gồm có rất nhiều layer và việc chọn thứ tự các layer sẽ phụ thuộc vào người lập trình. Vì vậy, em sẽ chọn model có chứa một số layer cơ bản. Trong đó, layer không thể thiếu chính là layer embedding dùng để biến đổi các từ trong tập train (lúc này, các từ đã được biểu diễn ở dạng các array qua hàm Tokenizer của keras\n\n\n","metadata":{}},{"cell_type":"code","source":"def myModel(maxlen, embed_size, embedding_matrix):\n    model = Sequential()\n    model.add(Embedding(len(embedding_matrix), embed_size, weights=[embedding_matrix], input_shape=(maxlen,)))\n    model.add(Bidirectional(GRU(64, return_sequences=True)))\n    model.add(GlobalMaxPool1D())\n    model.add(Dense(16, activation=\"relu\"))\n    model.add(Dropout(0.1))\n    model.add(Dense(1, activation=\"sigmoid\"))\n    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])\n\n    print(model.summary())\n    return model","metadata":{"execution":{"iopub.status.busy":"2021-06-10T17:18:43.7862Z","iopub.execute_input":"2021-06-10T17:18:43.786607Z","iopub.status.idle":"2021-06-10T17:18:43.794468Z","shell.execute_reply.started":"2021-06-10T17:18:43.786574Z","shell.execute_reply":"2021-06-10T17:18:43.793478Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = myModel(max_len, embed_size, glove_matrix)","metadata":{"execution":{"iopub.status.busy":"2021-06-10T17:20:22.753207Z","iopub.execute_input":"2021-06-10T17:20:22.753593Z","iopub.status.idle":"2021-06-10T17:20:23.851845Z","shell.execute_reply.started":"2021-06-10T17:20:22.753531Z","shell.execute_reply":"2021-06-10T17:20:23.85073Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Từ summary của model ta có thể thấy:\n- Input sẽ là các vector chuỗi tương ứng với các câu hỏi. \n- Một chuỗi sẽ có 100 từ tương ứng với vector 100 chiều. \n- Tầng Embedding sẽ giúp máy học được nghĩa của các từ là gì. Embedding sẽ chuyển mỗi từ thành 1 vector 1x300 thể hiện nghĩa của từ đấy. Nghĩa là một câu sẽ là một vector số 100x300. \n- Tầng Bidirection sẽ giúp máy học được nghĩa của mỗi câu dựa trên thứ tự của các từ trên mạng noron. \n- Sau đó với mỗi đặc trưng trong 128 đặc trưng, tầng global sẽ chọn ra từ có đặc trưng đó tốt nhất. Các tầng còn lại trong mô hình dùng để phân loại.","metadata":{}},{"cell_type":"markdown","source":"Sau khi tạo các model xong, em sẽ xóa các biến là embeddings_matrix do không còn cần đến chúng nữa.","metadata":{}},{"cell_type":"code","source":"del glove_matrix, paragram_matrix, fasttext_matrix\nimport gc\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2021-06-10T17:20:34.405636Z","iopub.execute_input":"2021-06-10T17:20:34.4062Z","iopub.status.idle":"2021-06-10T17:20:34.763693Z","shell.execute_reply.started":"2021-06-10T17:20:34.406153Z","shell.execute_reply":"2021-06-10T17:20:34.762483Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Model này khi dự đoán sẽ cho các kết quả là các số thực ở tập [0,1], vì vậy, em sẽ phải biến các kết quả về tập 0 và 1 sao cho f1 score là cao nhất bằng cách đặt ra một đại lượng là threshhold, trong đó, nếu là kết quả lớn hơn threshhold thì là 1, còn lại là 0. Tại đây, để tìm được best threshold thì em sẽ dùng hàm best thresh để kiểm tra với các threshhold chạy từ 0.1 đến 0.5 thì threshhold nào sẽ cho ra kết quả cao nhất, sau đó em sẽ cho in ra với một threshhold sẽ có một f1 score tương ứng của nó.","metadata":{}},{"cell_type":"code","source":"def bestThresh(Val_y, pred_val_y): \n    best_threshhold = 0\n    bestf1 = 0\n    for thresh in np.arange(0.1, 0.501, 0.01):\n        thresh = np.round(thresh, 2)\n        f1 = metrics.f1_score(Val_y, (pred_val_y>thresh).astype(int))\n        print(\"F1 score at threshold {0} is {1}\".format(thresh,f1))\n        if(f1 > bestf1): \n            best_threshhold = thresh\n            bestf1 = f1\n    return best_threshhold","metadata":{"execution":{"iopub.status.busy":"2021-06-10T17:21:15.930054Z","iopub.execute_input":"2021-06-10T17:21:15.930426Z","iopub.status.idle":"2021-06-10T17:21:15.937275Z","shell.execute_reply.started":"2021-06-10T17:21:15.930392Z","shell.execute_reply":"2021-06-10T17:21:15.936109Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Bắt đầu train với tệp train_X train_Y dùng để train. Đưa dữ liệu vào mạng neural network 2 lần. Mỗi lần đưa chia nhỏ ra thành các batch_size là 1024 câu. Dữ liệu dùng để kiểm thử là val_X và val_y.","metadata":{}},{"cell_type":"code","source":"model.fit(Train_X, Train_y, batch_size=1024, epochs = 2, validation_data=(Val_X, Val_y))","metadata":{"execution":{"iopub.status.busy":"2021-06-10T17:21:38.249875Z","iopub.execute_input":"2021-06-10T17:21:38.250277Z","iopub.status.idle":"2021-06-10T18:46:40.018026Z","shell.execute_reply.started":"2021-06-10T17:21:38.250244Z","shell.execute_reply":"2021-06-10T18:46:40.016593Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred_val_y = model.predict([Val_X], batch_size=1024, verbose=1)\nfor thresh in np.arange(0.1, 0.501, 0.01):\n    thresh = np.round(thresh, 2)\n    print(\"F1 score at threshold {0} is {1}\".format(thresh, metrics.f1_score(Val_y, (pred_val_y>thresh).astype(int))))","metadata":{"execution":{"iopub.status.busy":"2021-06-10T18:53:24.333082Z","iopub.execute_input":"2021-06-10T18:53:24.333754Z","iopub.status.idle":"2021-06-10T18:54:38.224658Z","shell.execute_reply.started":"2021-06-10T18:53:24.333708Z","shell.execute_reply":"2021-06-10T18:54:38.223357Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred_y = (model.predict([Test_X], batch_size=1024, verbose=1) > bestThresh(Val_y, pred_val_y)).astype(int)","metadata":{"execution":{"iopub.status.busy":"2021-06-10T18:56:13.612626Z","iopub.execute_input":"2021-06-10T18:56:13.613028Z","iopub.status.idle":"2021-06-10T19:00:27.947863Z","shell.execute_reply.started":"2021-06-10T18:56:13.612996Z","shell.execute_reply":"2021-06-10T19:00:27.946521Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Ta thấy F1-score trong khoảng threshold 0.26-0.4 là khá tốt. ","metadata":{}},{"cell_type":"markdown","source":"Cuối cùng, em sẽ cho in ra bảng csv tương ứng với kết quả của model:","metadata":{}},{"cell_type":"code","source":"out_df = pd.DataFrame({\"qid\":test_df[\"qid\"].values})\nout_df['prediction'] = pred_y\nout_df.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2021-06-10T19:01:43.648443Z","iopub.execute_input":"2021-06-10T19:01:43.648885Z","iopub.status.idle":"2021-06-10T19:01:44.549112Z","shell.execute_reply.started":"2021-06-10T19:01:43.648849Z","shell.execute_reply":"2021-06-10T19:01:44.548132Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Dưới đây là bảng kết quả của model dùng glove","metadata":{}},{"cell_type":"code","source":"out_df","metadata":{"execution":{"iopub.status.busy":"2021-06-10T19:01:47.828098Z","iopub.execute_input":"2021-06-10T19:01:47.828499Z","iopub.status.idle":"2021-06-10T19:01:47.84457Z","shell.execute_reply.started":"2021-06-10T19:01:47.828467Z","shell.execute_reply":"2021-06-10T19:01:47.843663Z"},"trusted":true},"execution_count":null,"outputs":[]}]}