{"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":"> # Mục lục  :\n\n* Tổng quan vấn đề\n\n* Phân tích dữ liệu\n\n* Xử lí dữ liệu\n\n* Xây dựng mô hình \n\n* Tổng kết\n","metadata":{}},{"cell_type":"markdown","source":"# Tổng quan vấn đề  :\n\n\n* Một vấn đề tồn tại đối với bất kỳ trang web lớn nào hiện nay là làm thế nào để xử lý nội dung toxic. Quora muốn giải quyết vấn đề này trực tiếp để giữ cho nền tảng của họ trở thành một nơi mà người dùng có thể cảm thấy an toàn khi chia sẻ kiến thức của họ với thế giới.\n* Một thách thức quan trọng là loại bỏ những câu hỏi toxic hơn là tìm kiếm những câu trả lời hữu ích.\n* Mục tiêu :\n* Xây dựng một mô hình để dự đoán liệu một câu hỏi được hỏi trên Quora có phải câu hỏi toxic hay không.\n\n**Mô tả bài toán**\n\n* Đầu vào : dữ liệu các câu hỏi dưới dạng text\n* Đầu ra : phân loại được câu hỏi là insincere hay sincere ","metadata":{}},{"cell_type":"code","source":"%matplotlib inline\nimport warnings\nwarnings.filterwarnings('ignore')\n\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\nfrom subprocess import check_output\n\n%matplotlib inline\nimport plotly.offline as py\npy.init_notebook_mode(connected=True)\nimport plotly.graph_objs as go\nimport plotly.tools as tls\n\nimport os\nimport gc\nimport csv\nimport re\nimport string\n\nfrom tqdm import tqdm\nfrom collections import Counter\nfrom wordcloud import WordCloud, STOPWORDS\nfrom scipy.sparse import hstack\nfrom IPython.display import Image\nfrom tqdm import tqdm_notebook\ntqdm_notebook().pandas()\n\nfrom nltk.corpus import stopwords\nfrom nltk.stem import PorterStemmer, SnowballStemmer, WordNetLemmatizer\nfrom nltk.stem.lancaster import LancasterStemmer\nfrom nltk.util import ngrams","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:16:35.377757Z","iopub.execute_input":"2021-06-11T03:16:35.378294Z","iopub.status.idle":"2021-06-11T03:16:37.250160Z","shell.execute_reply.started":"2021-06-11T03:16:35.378200Z","shell.execute_reply":"2021-06-11T03:16:37.249343Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import nltk\nnltk.download('wordnet')\nnltk.download('punkt')\nnltk.download('stopwords')","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:16:37.251574Z","iopub.execute_input":"2021-06-11T03:16:37.252089Z","iopub.status.idle":"2021-06-11T03:16:37.484809Z","shell.execute_reply.started":"2021-06-11T03:16:37.252056Z","shell.execute_reply":"2021-06-11T03:16:37.484072Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Đọc dữ liệu và các số liệu thống kê cơ bản**","metadata":{}},{"cell_type":"code","source":"#Đọc dữ liệu từ file data\ntrain = pd.read_csv(\"../input/quora-insincere-questions-classification/train.csv\")\n#Đọc dữ liệu từ file test \ntest=pd.read_csv(\"../input/quora-insincere-questions-classification/test.csv\")\nprint(\"Number of train data points:\",train.shape[0])\nprint(\"Number of test data points:\",test.shape[0])\nprint(\"Shape of Train Data:\", train.shape)\nprint(\"Shape of Test Data:\", test.shape)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:16:37.486375Z","iopub.execute_input":"2021-06-11T03:16:37.486850Z","iopub.status.idle":"2021-06-11T03:16:43.787646Z","shell.execute_reply.started":"2021-06-11T03:16:37.486818Z","shell.execute_reply":"2021-06-11T03:16:43.786679Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Nhận xét :\n* Tập dữ liệu train bao gồm 1.3 triệu dòng và 3 cột\n* Tập dữ liệu test hơn 300 nghìn dòng và 2 cột ","metadata":{}},{"cell_type":"code","source":"train.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:16:43.789500Z","iopub.execute_input":"2021-06-11T03:16:43.789953Z","iopub.status.idle":"2021-06-11T03:16:43.814609Z","shell.execute_reply.started":"2021-06-11T03:16:43.789909Z","shell.execute_reply":"2021-06-11T03:16:43.813533Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Có 3 trường dữ liệu :**\n* qid: mã định danh câu hỏi \n* question_text : Các câu hỏi trên quora \n* target : một câu hỏi có nhãn \"toxic\" có giá trị là 1 , nếu không là 0","metadata":{}},{"cell_type":"code","source":"train.info()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:16:43.815882Z","iopub.execute_input":"2021-06-11T03:16:43.816162Z","iopub.status.idle":"2021-06-11T03:16:44.072910Z","shell.execute_reply.started":"2021-06-11T03:16:43.816136Z","shell.execute_reply":"2021-06-11T03:16:44.071807Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Sự phân bố dữ liệu**","metadata":{}},{"cell_type":"code","source":"train.groupby(\"target\")['qid'].count().plot.bar()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:16:44.074084Z","iopub.execute_input":"2021-06-11T03:16:44.074380Z","iopub.status.idle":"2021-06-11T03:16:44.395435Z","shell.execute_reply.started":"2021-06-11T03:16:44.074353Z","shell.execute_reply":"2021-06-11T03:16:44.394455Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('~> Percentage of Sincere Questions (is_duplicate = 0):\\n   {}%'.format(100 - round(train['target'].mean()*100, 2)))\nprint('\\n~> Percentage of Insincere Questions (is_duplicate = 1):\\n   {}%'.format(round(train['target'].mean()*100, 2)))","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:16:44.396714Z","iopub.execute_input":"2021-06-11T03:16:44.396999Z","iopub.status.idle":"2021-06-11T03:16:44.406642Z","shell.execute_reply.started":"2021-06-11T03:16:44.396972Z","shell.execute_reply":"2021-06-11T03:16:44.405616Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Nhận xét\n* Dữ liệu về câu hỏi toxic chiếm 93.81% trong khi đó dữ liệu về câu hỏi không toxic chỉ chiếm 6.19%\n* Dữ liệu rất mất cân bằng và có rất ít câu hỏi được đánh dấu là toxic trong tập dữ liệu\n\n**Hướng giải quyết**\n* Chia lại tập dữ liệu sao cho câu hỏi toxic và không toxic trở nên cân bằng hơn ","metadata":{}},{"cell_type":"markdown","source":"# Phân tích dữ liệu trước khi xử lí","metadata":{}},{"cell_type":"markdown","source":"Dữ liệu thô không xem được nên cần thêm 1 số nhãn để phân tích rõ dữ liệu\n* freq_id : tần suất xuất hiện của id\n* q_len : độ dài của các câu hỏi \n* n_words : số từ trong câu hỏi\n* numeric_words : số lượng các chữ số trong câu \n* sp_char_words : số lượng các kí tự đặc biệt trong câu\n* char_words : số lượng các kí tự trong câu \n* unique_words : số lượng các từ duy nhất trong câu ","metadata":{}},{"cell_type":"code","source":"    train['freq_qid'] = train.groupby('qid')['qid'].transform('count') \n    train['qlen'] = train['question_text'].str.len() \n    train['n_words'] = train['question_text'].apply(lambda row: len(row.split(\" \")))\n    train['numeric_words'] = train['question_text'].apply(lambda row: sum(c.isdigit() for c in row))\n    train['sp_char_words'] = train['question_text'].str.findall(r'[^a-zA-Z0-9 ]').str.len()\n    train['char_words'] = train['question_text'].apply(lambda row: len(str(row)))\n    train['unique_words'] = train['question_text'].apply(lambda row: len(set(str(row).split())))\n    \ntrain.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:16:44.409221Z","iopub.execute_input":"2021-06-11T03:16:44.409599Z","iopub.status.idle":"2021-06-11T03:17:07.488254Z","shell.execute_reply.started":"2021-06-11T03:16:44.409570Z","shell.execute_reply":"2021-06-11T03:17:07.487256Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Độ dài bé nhất của câu hỏi \nprint (\"Minimum length of the questions: \" , min(train['n_words']))\n# Độ dài lớn nhất của câu hỏi\nprint (\"Maximum length of the questions: \" , max(train['n_words']))\n# Độ dài trung bình của câu hỏi\nprint (\"Number of Questions with minimum length:\", train[train['n_words']== 1].shape[0])","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:07.489906Z","iopub.execute_input":"2021-06-11T03:17:07.490179Z","iopub.status.idle":"2021-06-11T03:17:07.912643Z","shell.execute_reply.started":"2021-06-11T03:17:07.490155Z","shell.execute_reply":"2021-06-11T03:17:07.911545Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Biểu đồ phân bố về nhãn 'n_word'**","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(8, 8))\nsns.violinplot(x = 'target', y = 'n_words', data = train[0:])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:07.913763Z","iopub.execute_input":"2021-06-11T03:17:07.914038Z","iopub.status.idle":"2021-06-11T03:17:10.960624Z","shell.execute_reply.started":"2021-06-11T03:17:07.914011Z","shell.execute_reply":"2021-06-11T03:17:10.959518Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Nhận xét \n* Hầu hết các câu hỏi có độ dài chủ yếu từ 12-20\n* Những câu hỏi toxic có độ dài không quá 80 và độ dài trung bình ngắn hơn so với câu hỏi không toxic ","metadata":{}},{"cell_type":"markdown","source":"**Biểu đồ phân bố về nhãn 'numeric_word'**","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(8, 8))\nsns.violinplot(x = 'target', y = 'numeric_words', data = train[0:])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:10.961908Z","iopub.execute_input":"2021-06-11T03:17:10.962193Z","iopub.status.idle":"2021-06-11T03:17:13.580994Z","shell.execute_reply.started":"2021-06-11T03:17:10.962164Z","shell.execute_reply":"2021-06-11T03:17:13.580247Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Nhận xét\n* Các từ là số trong câu hỏi không toxic dao động từ 0 đến hơn 200\n* Các từ là số trong câu hỏi toxic dao động từ 0 đến gần 100 ","metadata":{}},{"cell_type":"markdown","source":"**Biểu đồ phân bố về nhãn 'sp_char_words'**","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(4, 4))\nsns.violinplot(x = 'target', y = 'sp_char_words', data = train[0:])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:13.581982Z","iopub.execute_input":"2021-06-11T03:17:13.582362Z","iopub.status.idle":"2021-06-11T03:17:16.225919Z","shell.execute_reply.started":"2021-06-11T03:17:13.582333Z","shell.execute_reply":"2021-06-11T03:17:16.224546Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Nhận xét\n* Ở câu hỏi toxic số kí tự đặc biệt nhiều hơn gấp đôi so với câu hỏi không toxic\n* Câu hỏi không toxic có số lượng kí tự đặc biệt dao động từ 0 đến 150 và thường chỉ đa số chỉ có từ 0-1 kí tự đặc biệt\ntrong câu\n* Câu hỏi toxic có số lượng kí tự đặc biệt dao động từ 0-400 và đa số có từ 1-3 kí tự đặc biệt trong câu\n","metadata":{}},{"cell_type":"markdown","source":"**Biểu đồ phân bố về nhãn 'unique_words'**\n","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(8, 8))\nsns.violinplot(x = 'target', y = 'unique_words', data = train[0:])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:16.227285Z","iopub.execute_input":"2021-06-11T03:17:16.227663Z","iopub.status.idle":"2021-06-11T03:17:19.293513Z","shell.execute_reply.started":"2021-06-11T03:17:16.227629Z","shell.execute_reply":"2021-06-11T03:17:19.292785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Biểu đồ phân bố về nhãn 'char_words'**\n","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(4, 4))\nsns.violinplot(x = 'target', y = 'char_words', data = train[0:])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:19.294768Z","iopub.execute_input":"2021-06-11T03:17:19.295349Z","iopub.status.idle":"2021-06-11T03:17:22.270921Z","shell.execute_reply.started":"2021-06-11T03:17:19.295304Z","shell.execute_reply":"2021-06-11T03:17:22.269862Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Nhận xét :\nSố lượng kí tự ở câu hỏi toxic từ 0 đến 1000 và tập trung trong đoạn 0-200\nSố lượng kí tự ở câu hỏi không toxic từ 0-gần 700 và tập trung trong đoạn 0-150","metadata":{}},{"cell_type":"code","source":"# Set up the matplotlib figure\nf, ax = plt.subplots(figsize=(11, 9))\n \ncorr = train.corr()\n\n# Draw the heatmap\nsns.heatmap(corr, ax=ax)\n\nplt.title(\"Correlation matrix\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:22.272356Z","iopub.execute_input":"2021-06-11T03:17:22.272674Z","iopub.status.idle":"2021-06-11T03:17:22.918035Z","shell.execute_reply.started":"2021-06-11T03:17:22.272645Z","shell.execute_reply":"2021-06-11T03:17:22.916855Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Quan sát:\n* Những câu hỏi insincere có nhiều từ và kí tự hơn\n* Những câu hỏi insincere có nhiều unique words hơn so với câu hỏi sincere","metadata":{}},{"cell_type":"markdown","source":"* Sau khi xem xét các biểu đồ phân tích ở trên , ta thấy ở một số nhãn có chỉ số vượt ngưỡng do đó ta sẽ lọc nó ra khỏi tập train","metadata":{}},{"cell_type":"code","source":"train = train[(train['n_words']<70.0) & (train['char_words']<600.0) &\n(train['sp_char_words']<12.0)]","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:22.919534Z","iopub.execute_input":"2021-06-11T03:17:22.919890Z","iopub.status.idle":"2021-06-11T03:17:23.036304Z","shell.execute_reply.started":"2021-06-11T03:17:22.919858Z","shell.execute_reply":"2021-06-11T03:17:23.034938Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# in ra một mẫu câu hỏi ngẫu nhiên có nhãn bằng 1\nimport random\n\nindex = random.sample(train.index[train.target == 1].tolist(), 5)\nfor i in index:\n    print(train.iloc[i, 1])","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:23.037927Z","iopub.execute_input":"2021-06-11T03:17:23.038399Z","iopub.status.idle":"2021-06-11T03:17:23.055478Z","shell.execute_reply.started":"2021-06-11T03:17:23.038343Z","shell.execute_reply":"2021-06-11T03:17:23.054384Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"qids = train.sort_values('sp_char_words', ascending=False)['qid'].head(20).values\nfor id in qids:\n    row = train[train['qid'].values == id]\n    if row['target'].values[0] == 1: \n        color = '\\033[31m'\n    else:\n        color = '\\033[0m'\n    print(color, row['question_text'].values[0], '\\n')","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:23.056742Z","iopub.execute_input":"2021-06-11T03:17:23.057043Z","iopub.status.idle":"2021-06-11T03:17:24.569142Z","shell.execute_reply.started":"2021-06-11T03:17:23.057015Z","shell.execute_reply":"2021-06-11T03:17:24.568117Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Xử lí mất cân bằng dữ liệu**\n* Hai cách tiếp cận để tạo ra một tập dữ liệu cân bằng trong một tập dữ liệu không cân bằng là under-sampling và oversampling.\n1. Under-sampling\n\n* Việc lấy mẫu làm cân bằng tập dữ liệu bằng cách giảm kích thước của lớp trội. Phương pháp này được sử dụng khi số lượng dữ liệu là đủ. Bằng cách giữ tất cả các mẫu trong lớp hiếm và chọn ngẫu nhiên một số trong lớp trội, một tập dữ liệu cân bằng mới có thể được lấy ra để lập mô hình tiếp theo.\n\n2. Over-sampling\n\n* Ngược lại, oversampling được sử dụng khi số lượng dữ liệu không đủ. Nó cố gắng cân bằng số liệu bằng cách tăng kích thước của các mẫu hiếm. Thay vì loại bỏ các mẫu phong phú, các mẫu hiếm mới được tạo ra ","metadata":{}},{"cell_type":"code","source":"from sklearn.utils import resample\nsincere = train[train.target == 0]\ninsincere = train[train.target == 1]\n# Tỉ lệ 4:1 cho kết quả tốt nhất\nx = pd.concat([resample(sincere,replace = True,n_samples = len(insincere)*4), insincere])","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:24.570349Z","iopub.execute_input":"2021-06-11T03:17:24.570640Z","iopub.status.idle":"2021-06-11T03:17:24.895253Z","shell.execute_reply.started":"2021-06-11T03:17:24.570613Z","shell.execute_reply":"2021-06-11T03:17:24.894314Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y = x['target']\ny.value_counts().plot(kind='bar', rot=0)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:24.896549Z","iopub.execute_input":"2021-06-11T03:17:24.896897Z","iopub.status.idle":"2021-06-11T03:17:25.023117Z","shell.execute_reply.started":"2021-06-11T03:17:24.896867Z","shell.execute_reply":"2021-06-11T03:17:25.022151Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Sau khi chia lại dữ liệu ta thấy tập dữ liệu đã cân bằng hơn trước","metadata":{}},{"cell_type":"markdown","source":"# Data Preperation\n","metadata":{}},{"cell_type":"markdown","source":"1. Word Tokenization\n* Bước đầu tiên để chuẩn bị dữ liệu là phân tách nó thành các từ. Đây là bước cần thiết nhất để xử lý văn bản. Các câu được chia thành từ ngữ, phân chia các từ cùng với các ký tự đặc biệt được coi là một từ. Điều này giúp tách các câu thành danh sách các từ được phân tách bằng dấu phẩy một cách hiệu quả.\n\n\n2. Loại bỏ stopword\n* Từ dừng là những từ được sử dụng để thêm nghĩa cho câu như “a”, ”an” ”in”, ”of”. Nó không có bất kỳ giá trị nào. Do đó, điều quan trọng là phải loại bỏ chúng khi chúng có thể ảnh hưởng đến kết quả của các mô hình. Gói NLTK có các từ dừng cho các ngôn ngữ khác nhau. Sau khi tách các câu và loại bỏ các từ dừng, nhiệm vụ tiếp theo là xác định gốc của tất cả các từ. \n\n3. Tìm gốc của từ\n* Từ gốc là những từ mà nhờ từ đó để xây dựng lên các từ khác . Ví dụ dance là từ gốc của dancing, dances, danced, v.v. Sử dụng các từ gốc thay cho các từ dẫn xuất dẫn đến một tỷ lệ chính xác tốt hơn. Có hai cách tiếp cận để đạt được điều này đó là Lemmatization và Stemming.\n\n> Lemmatization : Nó là một phương pháp nhóm các từ thành một thuật ngữ duy nhất dựa trên sự biến đổi của chúng. Wordnet Lemmatizer được sử dụng cho mục đích này. Gói NLTK có WordNet Lemmatizer để xử lí các từ .\n\n> Stemming : Đây là phương pháp khác được sử dụng để liên kết các từ với các từ gốc. Đó là quá trình xác định các biến thể của các từ cơ sở. Có hai phương pháp tạo gốc được sử dụng trong dự án này như sau :\n> * Porter Stemmer : Cách tiếp cận gốc này đã được xuất bản trong 1980 sử dụng cho ngôn ngữ tiếng Anh ban đầu . Sau đó, nhiều ngôn ngữ khác cũng được phát hành để sử dụng trong Snowball, là một framework cho các thuật toán stemming. Nó cũng là một trong những loại stemmer được sử dụng phổ biến nhất.\n> * Lancaster Stemmer : Cách tiếp cận này đã được phát triển vào cuối những năm 1980, là một trình tạo gốc lặp đi lặp lại và có các quy tắc rất nghiêm ngặt\n\n* Cả hai cách tiếp cận này đều đúng và trong dự án này sẽ sử dụng cả Lemmatization và Stemming để đạt hiệu quả cao nhất\n\n4. Text Vectorization \n* Text Vectorization giúp chuyển đổi văn bản dữ liệu thành một chuỗi các số để xử lý. Hai cách tiếp cận phổ biến nhất là TF-IDF và Bag of Words ( Sẽ được trình bày kĩ ở phần dưới)\n\n5. Chia tập dữ liệu\n* Tập dữ liệu sẽ được chia theo tỉ lệ 80:20, cái trước bao gồm tập train và cái sau là tập test\n\n6. Modeling \n* Mô hình được sử dụng cho bài toán này là Logistic Regression , Gradient Boosting ","metadata":{}},{"cell_type":"markdown","source":"**Xử lí dữ liệu**\n** Qua phân tích ở trên ta thấy dữ liệu có có những tác nhân gây nhiễu hoặc không cần thiết , dư thừa để xác nhận xem câu hỏi có phải toxic hay không . Qua đó chúng ta sẽ tìm cách loại bỏ nó :**\n* Loại bỏ những kí tự đặc biệt có trong câu\n* Loại bỏ dấu câu \n* Loại bỏ chữ số \n* Thay thế những từ sai chính tả\n* Thay thế các từ viết tắt \n* Loại bỏ những từ là stop word ( ví dụ \"a\" , \"an\", \"the\" ,...)\n* Biến đổi 1 từ về dạng gốc (được gọi là stem hoặc root form) bằng cách loại bỏ 1 số ký tự nằm ở cuối từ mà nó nghĩ rằng là biến thể của từ\n* giống như trên nhưng xử lý bằng cách loại bỏ các ký tự cuối từ theo thuật toán heuristic (lemmatization)","metadata":{}},{"cell_type":"code","source":"puncts=[',', '.', '\"', ':', ')', '(', '-', '!', '?', '|', ';', \"'\", '$', '&', '/', '[', ']', '>', '%', '=', '#', '*', '+', '\\\\', \n        '•', '~', '@', '£', '·', '_', '{', '}', '©', '^', '®', '`', '<', '→', '°', '€', '™', '›', '♥', '←', '×', '§', '″', '′', \n        '█', '…', '“', '★', '”', '–', '●', '►', '−', '¢', '¬', '░', '¡', '¶', '↑', '±', '¿', '▾', '═', '¦', '║', '―', '¥', '▓', \n        '—', '‹', '─', '▒', '：', '⊕', '▼', '▪', '†', '■', '’', '▀', '¨', '▄', '♫', '☆', '¯', '♦', '¤', '▲', '¸', '⋅', '‘', '∞', \n        '∙', '）', '↓', '、', '│', '（', '»', '，', '♪', '╩', '╚', '・', '╦', '╣', '╔', '╗', '▬', '❤', '≤', '‡', '√', '◄', '━', \n        '⇒', '▶', '≥', '╝', '♡', '◊', '。', '✈', '≡', '☺', '✔', '↵', '≈', '✓', '♣', '☎', '℃', '◦', '└', '‟', '～', '！', '○', \n        '◆', '№', '♠', '▌', '✿', '▸', '⁄', '□', '❖', '✦', '．', '÷', '｜', '┃', '／', '￥', '╠', '↩', '✭', '▐', '☼', '☻', '┐', \n        '├', '«', '∼', '┌', '℉', '☮', '฿', '≦', '♬', '✧', '〉', '－', '⌂', '✖', '･', '◕', '※', '‖', '◀', '‰', '\\x97', '↺', \n        '∆', '┘', '┬', '╬', '،', '⌘', '⊂', '＞', '〈', '⎙', '？', '☠', '⇐', '▫', '∗', '∈', '≠', '♀', '♔', '˚', '℗', '┗', '＊', \n        '┼', '❀', '＆', '∩', '♂', '‿', '∑', '‣', '➜', '┛', '⇓', '☯', '⊖', '☀', '┳', '；', '∇', '⇑', '✰', '◇', '♯', '☞', '´', \n        '↔', '┏', '｡', '◘', '∂', '✌', '♭', '┣', '┴', '┓', '✨', '\\xa0', '˜', '❥', '┫', '℠', '✒', '［', '∫', '\\x93', '≧', '］', \n        '\\x94', '∀', '♛', '\\x96', '∨', '◎', '↻', '⇩', '＜', '≫', '✩', '✪', '♕', '؟', '₤', '☛', '╮', '␊', '＋', '┈', '％', \n        '╋', '▽', '⇨', '┻', '⊗', '￡', '।', '▂', '✯', '▇', '＿', '➤', '✞', '＝', '▷', '△', '◙', '▅', '✝', '∧', '␉', '☭', \n        '┊', '╯', '☾', '➔', '∴', '\\x92', '▃', '↳', '＾', '׳', '➢', '╭', '➡', '＠', '⊙', '☢', '˝', '∏', '„', '∥', '❝', '☐', \n        '▆', '╱', '⋙', '๏', '☁', '⇔', '▔', '\\x91', '➚', '◡', '╰', '\\x85', '♢', '˙', '۞', '✘', '✮', '☑', '⋆', 'ⓘ', '❒', \n        '☣', '✉', '⌊', '➠', '∣', '❑', '◢', 'ⓒ', '\\x80', '〒', '∕', '▮', '⦿', '✫', '✚', '⋯', '♩', '☂', '❞', '‗', '܂', '☜', \n        '‾', '✜', '╲', '∘', '⟩', '＼', '⟨', '·', '✗', '♚', '∅', 'ⓔ', '◣', '͡', '‛', '❦', '◠', '✄', '❄', '∃', '␣', '≪', '｢', \n        '≅', '◯', '☽', '∎', '｣', '❧', '̅', 'ⓐ', '↘', '⚓', '▣', '˘', '∪', '⇢', '✍', '⊥', '＃', '⎯', '↠', '۩', '☰', '◥', \n        '⊆', '✽', '⚡', '↪', '❁', '☹', '◼', '☃', '◤', '❏', 'ⓢ', '⊱', '➝', '̣', '✡', '∠', '｀', '▴', '┤', '∝', '♏', 'ⓐ', \n        '✎', ';', '␤', '＇', '❣', '✂', '✤', 'ⓞ', '☪', '✴', '⌒', '˛', '♒', '＄', '✶', '▻', 'ⓔ', '◌', '◈', '❚', '❂', '￦', \n        '◉', '╜', '̃', '✱', '╖', '❉', 'ⓡ', '↗', 'ⓣ', '♻', '➽', '׀', '✲', '✬', '☉', '▉', '≒', '☥', '⌐', '♨', '✕', 'ⓝ', \n        '⊰', '❘', '＂', '⇧', '̵', '➪', '▁', '▏', '⊃', 'ⓛ', '‚', '♰', '́', '✏', '⏑', '̶', 'ⓢ', '⩾', '￠', '❍', '≃', '⋰', '♋', \n        '､', '̂', '❋', '✳', 'ⓤ', '╤', '▕', '⌣', '✸', '℮', '⁺', '▨', '╨', 'ⓥ', '♈', '❃', '☝', '✻', '⊇', '≻', '♘', '♞', \n        '◂', '✟', '⌠', '✠', '☚', '✥', '❊', 'ⓒ', '⌈', '❅', 'ⓡ', '♧', 'ⓞ', '▭', '❱', 'ⓣ', '∟', '☕', '♺', '∵', '⍝', 'ⓑ', \n        '✵', '✣', '٭', '♆', 'ⓘ', '∶', '⚜', '◞', '்', '✹', '➥', '↕', '̳', '∷', '✋', '➧', '∋', '̿', 'ͧ', '┅', '⥤', '⬆', '⋱', \n        '☄', '↖', '⋮', '۔', '♌', 'ⓛ', '╕', '♓', '❯', '♍', '▋', '✺', '⭐', '✾', '♊', '➣', '▿', 'ⓑ', '♉', '⏠', '◾', '▹', \n        '⩽', '↦', '╥', '⍵', '⌋', '։', '➨', '∮', '⇥', 'ⓗ', 'ⓓ', '⁻', '⎝', '⌥', '⌉', '◔', '◑', '✼', '♎', '♐', '╪', '⊚', \n        '☒', '⇤', 'ⓜ', '⎠', '◐', '⚠', '╞', '◗', '⎕', 'ⓨ', '☟', 'ⓟ', '♟', '❈', '↬', 'ⓓ', '◻', '♮', '❙', '♤', '∉', '؛', \n        '⁂', 'ⓝ', '־', '♑', '╫', '╓', '╳', '⬅', '☔', '☸', '┄', '╧', '׃', '⎢', '❆', '⋄', '⚫', '̏', '☏', '➞', '͂', '␙', \n        'ⓤ', '◟', '̊', '⚐', '✙', '↙', '̾', '℘', '✷', '⍺', '❌', '⊢', '▵', '✅', 'ⓖ', '☨', '▰', '╡', 'ⓜ', '☤', '∽', '╘', \n        '˹', '↨', '♙', '⬇', '♱', '⌡', '⠀', '╛', '❕', '┉', 'ⓟ', '̀', '♖', 'ⓚ', '┆', '⎜', '◜', '⚾', '⤴', '✇', '╟', '⎛', \n        '☩', '➲', '➟', 'ⓥ', 'ⓗ', '⏝', '◃', '╢', '↯', '✆', '˃', '⍴', '❇', '⚽', '╒', '̸', '♜', '☓', '➳', '⇄', '☬', '⚑', \n        '✐', '⌃', '◅', '▢', '❐', '∊', '☈', '॥', '⎮', '▩', 'ு', '⊹', '‵', '␔', '☊', '➸', '̌', '☿', '⇉', '⊳', '╙', 'ⓦ', \n        '⇣', '｛', '̄', '↝', '⎟', '▍', '❗', '״', '΄', '▞', '◁', '⛄', '⇝', '⎪', '♁', '⇠', '☇', '✊', 'ி', '｝', '⭕', '➘', \n        '⁀', '☙', '❛', '❓', '⟲', '⇀', '≲', 'ⓕ', '⎥', '\\u06dd', 'ͤ', '₋', '̱', '̎', '♝', '≳', '▙', '➭', '܀', 'ⓖ', '⇛', '▊', \n        '⇗', '̷', '⇱', '℅', 'ⓧ', '⚛', '̐', '̕', '⇌', '␀', '≌', 'ⓦ', '⊤', '̓', '☦', 'ⓕ', '▜', '➙', 'ⓨ', '⌨', '◮', '☷', \n        '◍', 'ⓚ', '≔', '⏩', '⍳', '℞', '┋', '˻', '▚', '≺', 'ْ', '▟', '➻', '̪', '⏪', '̉', '⎞', '┇', '⍟', '⇪', '▎', '⇦', '␝', \n        '⤷', '≖', '⟶', '♗', '̴', '♄', 'ͨ', '̈', '❜', '̡', '▛', '✁', '➩', 'ா', '˂', '↥', '⏎', '⎷', '̲', '➖', '↲', '⩵', '̗', '❢', \n        '≎', '⚔', '⇇', '̑', '⊿', '̖', '☍', '➹', '⥊', '⁁', '✢']","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:25.024280Z","iopub.execute_input":"2021-06-11T03:17:25.024720Z","iopub.status.idle":"2021-06-11T03:17:25.062627Z","shell.execute_reply.started":"2021-06-11T03:17:25.024669Z","shell.execute_reply":"2021-06-11T03:17:25.061424Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#loại bỏ kí tự đặc biệt\ndef clean_punct(x):\n    for punct in puncts:\n        if punct in x:\n            x = x.replace(punct, '{}' .format(punct))\n    return x","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:25.064180Z","iopub.execute_input":"2021-06-11T03:17:25.064614Z","iopub.status.idle":"2021-06-11T03:17:25.081263Z","shell.execute_reply.started":"2021-06-11T03:17:25.064567Z","shell.execute_reply":"2021-06-11T03:17:25.080034Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#loại bỏ chữ số \ndef clean_numbers(x):\n    if bool(re.search(r'\\d', x)):\n        x = re.sub('[0-9]{5,}', '#####', x)\n        x = re.sub('[0-9]{4}', '####', x)\n        x = re.sub('[0-9]{3}', '###', x)\n        x = re.sub('[0-9]{2}', '##', x)\n    return x","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:25.085391Z","iopub.execute_input":"2021-06-11T03:17:25.085814Z","iopub.status.idle":"2021-06-11T03:17:25.093503Z","shell.execute_reply.started":"2021-06-11T03:17:25.085778Z","shell.execute_reply":"2021-06-11T03:17:25.092500Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mispell_dict = {'colour': 'color', 'centre': 'center', 'favourite': 'favorite', 'travelling': 'traveling', 'counselling': 'counseling', 'theatre': 'theater', 'cancelled': 'canceled', 'labour': 'labor', 'organisation': 'organization', 'wwii': 'world war 2', 'citicise': 'criticize', 'youtu ': 'youtube ', 'Qoura': 'Quora', 'sallary': 'salary', 'Whta': 'What', 'narcisist': 'narcissist', 'howdo': 'how do', 'whatare': 'what are', 'howcan': 'how can', 'howmuch': 'how much', 'howmany': 'how many', 'whydo': 'why do', 'doI': 'do I', 'theBest': 'the best', 'howdoes': 'how does', 'mastrubation': 'masturbation', 'mastrubate': 'masturbate', \"mastrubating\": 'masturbating', 'pennis': 'penis', 'Etherium': 'bitcoin', 'narcissit': 'narcissist', 'bigdata': 'big data', '2k17': '2017', '2k18': '2018', 'qouta': 'quota', 'exboyfriend': 'ex boyfriend', 'airhostess': 'air hostess', \"whst\": 'what', 'watsapp': 'whatsapp', 'demonitisation': 'demonetization', 'demonitization': 'demonetization', 'demonetisation': 'demonetization', \n                'electroneum':'bitcoin','nanodegree':'degree','hotstar':'star','dream11':'dream','ftre':'fire','tensorflow':'framework','unocoin':'bitcoin',\n                'lnmiit':'limit','unacademy':'academy','altcoin':'bitcoin','altcoins':'bitcoin','litecoin':'bitcoin','coinbase':'bitcoin','cryptocurency':'cryptocurrency',\n                'simpliv':'simple','quoras':'quora','schizoids':'psychopath','remainers':'remainder','twinflame':'soulmate','quorans':'quora','brexit':'demonetized',\n                'iiest':'institute','dceu':'comics','pessat':'exam','uceed':'college','bhakts':'devotee','boruto':'anime',\n                'cryptocoin':'bitcoin','blockchains':'blockchain','fiancee':'fiance','redmi':'smartphone','oneplus':'smartphone','qoura':'quora','deepmind':'framework','ryzen':'cpu','whattsapp':'whatsapp',\n                'undertale':'adventure','zenfone':'smartphone','cryptocurencies':'cryptocurrencies','koinex':'bitcoin','zebpay':'bitcoin','binance':'bitcoin','whtsapp':'whatsapp',\n                'reactjs':'framework','bittrex':'bitcoin','bitconnect':'bitcoin','bitfinex':'bitcoin','yourquote':'your quote','whyis':'why is','jiophone':'smartphone',\n                'dogecoin':'bitcoin','onecoin':'bitcoin','poloniex':'bitcoin','7700k':'cpu','angular2':'framework','segwit2x':'bitcoin','hashflare':'bitcoin','940mx':'gpu',\n                'openai':'framework','hashflare':'bitcoin','1050ti':'gpu','nearbuy':'near buy','freebitco':'bitcoin','antminer':'bitcoin','filecoin':'bitcoin','whatapp':'whatsapp',\n                'empowr':'empower','1080ti':'gpu','crytocurrency':'cryptocurrency','8700k':'cpu','whatsaap':'whatsapp','g4560':'cpu','payymoney':'pay money',\n                'fuckboys':'fuck boys','intenship':'internship','zcash':'bitcoin','demonatisation':'demonetization','narcicist':'narcissist','mastuburation':'masturbation',\n                'trignometric':'trigonometric','cryptocurreny':'cryptocurrency','howdid':'how did','crytocurrencies':'cryptocurrencies','phycopath':'psychopath',\n                'bytecoin':'bitcoin','possesiveness':'possessiveness','scollege':'college','humanties':'humanities','altacoin':'bitcoin','demonitised':'demonetized',\n                'brasília':'brazilia','accolite':'accolyte','econimics':'economics','varrier':'warrier','quroa':'quora','statergy':'strategy','langague':'language',\n                'splatoon':'game','7600k':'cpu','gate2018':'gate 2018','in2018':'in 2018','narcassist':'narcissist','jiocoin':'bitcoin','hnlu':'hulu','7300hq':'cpu',\n                'weatern':'western','interledger':'blockchain','deplation':'deflation', 'cryptocurrencies':'cryptocurrency', 'bitcoin':'blockchain cryptocurrency',}","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:25.095672Z","iopub.execute_input":"2021-06-11T03:17:25.096261Z","iopub.status.idle":"2021-06-11T03:17:25.113612Z","shell.execute_reply.started":"2021-06-11T03:17:25.096223Z","shell.execute_reply":"2021-06-11T03:17:25.112502Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Thay thế các từ sai chính tả\ndef _get_mispell(mispell_dict):\n    mispell_re = re.compile('(%s)' % '|'.join(mispell_dict.keys()))\n    return mispell_dict, mispell_re\n\nmispellings, mispellings_re = _get_mispell(mispell_dict)\ndef replace_typical_misspell(text):\n    def replace(match):\n        return mispellings[match.group(0)]\n    return mispellings_re.sub(replace, text)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:25.114912Z","iopub.execute_input":"2021-06-11T03:17:25.115375Z","iopub.status.idle":"2021-06-11T03:17:25.136685Z","shell.execute_reply.started":"2021-06-11T03:17:25.115343Z","shell.execute_reply":"2021-06-11T03:17:25.135582Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"contraction_dict = {\"ain't\": \"is not\", \"aren't\": \"are not\",\"can't\": \"cannot\", \"'cause\": \"because\", \"could've\": \"could have\", \"couldn't\": \"could not\", \"didn't\": \"did not\",  \"doesn't\": \"does not\", \"don't\": \"do not\", \"hadn't\": \"had not\", \"hasn't\": \"has not\", \"haven't\": \"have not\", \"he'd\": \"he would\",\"he'll\": \"he will\", \"he's\": \"he is\", \"how'd\": \"how did\", \"how'd'y\": \"how do you\", \"how'll\": \"how will\", \"how's\": \"how is\",  \"I'd\": \"I would\", \"I'd've\": \"I would have\", \"I'll\": \"I will\", \"I'll've\": \"I will have\",\"I'm\": \"I am\", \"I've\": \"I have\", \"i'd\": \"i would\", \"i'd've\": \"i would have\", \"i'll\": \"i will\",  \"i'll've\": \"i will have\",\"i'm\": \"i am\", \"i've\": \"i have\", \"isn't\": \"is not\", \"it'd\": \"it would\", \"it'd've\": \"it would have\", \"it'll\": \"it will\", \"it'll've\": \"it will have\",\"it's\": \"it is\", \"let's\": \"let us\", \"ma'am\": \"madam\", \"mayn't\": \"may not\", \"might've\": \"might have\",\"mightn't\": \"might not\",\"mightn't've\": \"might not have\", \"must've\": \"must have\", \"mustn't\": \"must not\", \"mustn't've\": \"must not have\", \"needn't\": \"need not\", \"needn't've\": \"need not have\",\"o'clock\": \"of the clock\", \"oughtn't\": \"ought not\", \"oughtn't've\": \"ought not have\", \"shan't\": \"shall not\", \"sha'n't\": \"shall not\", \"shan't've\": \"shall not have\", \"she'd\": \"she would\", \"she'd've\": \"she would have\", \"she'll\": \"she will\", \"she'll've\": \"she will have\", \"she's\": \"she is\", \"should've\": \"should have\", \"shouldn't\": \"should not\", \"shouldn't've\": \"should not have\", \"so've\": \"so have\",\"so's\": \"so as\", \"this's\": \"this is\",\"that'd\": \"that would\", \"that'd've\": \"that would have\", \"that's\": \"that is\", \"there'd\": \"there would\", \"there'd've\": \"there would have\", \"there's\": \"there is\", \"here's\": \"here is\",\"they'd\": \"they would\", \"they'd've\": \"they would have\", \"they'll\": \"they will\", \"they'll've\": \"they will have\", \"they're\": \"they are\", \"they've\": \"they have\", \"to've\": \"to have\", \"wasn't\": \"was not\", \"we'd\": \"we would\", \"we'd've\": \"we would have\", \"we'll\": \"we will\", \"we'll've\": \"we will have\", \"we're\": \"we are\", \"we've\": \"we have\", \"weren't\": \"were not\", \"what'll\": \"what will\", \"what'll've\": \"what will have\", \"what're\": \"what are\",  \"what's\": \"what is\", \"what've\": \"what have\", \"when's\": \"when is\", \"when've\": \"when have\", \"where'd\": \"where did\", \"where's\": \"where is\", \"where've\": \"where have\", \"who'll\": \"who will\", \"who'll've\": \"who will have\", \"who's\": \"who is\", \"who've\": \"who have\", \"why's\": \"why is\", \"why've\": \"why have\", \"will've\": \"will have\", \"won't\": \"will not\", \"won't've\": \"will not have\", \"would've\": \"would have\", \"wouldn't\": \"would not\", \"wouldn't've\": \"would not have\", \"y'all\": \"you all\", \"y'all'd\": \"you all would\",\"y'all'd've\": \"you all would have\",\"y'all're\": \"you all are\",\"y'all've\": \"you all have\",\"you'd\": \"you would\", \"you'd've\": \"you would have\", \"you'll\": \"you will\", \"you'll've\": \"you will have\", \"you're\": \"you are\", \"you've\": \"you have\"}","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:25.138260Z","iopub.execute_input":"2021-06-11T03:17:25.138686Z","iopub.status.idle":"2021-06-11T03:17:25.153898Z","shell.execute_reply.started":"2021-06-11T03:17:25.138650Z","shell.execute_reply":"2021-06-11T03:17:25.152838Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Thay thế các từ viết tắt\ndef _get_contractions(contraction_dict):\n    contraction_re = re.compile('(%s)' % '|'.join(contraction_dict.keys()))\n    return contraction_dict, contraction_re\n\ncontractions, contractions_re = _get_contractions(contraction_dict)\n\ndef replace_contractions(text):\n    def replace(match):\n        return contractions[match.group(0)]\n    return contractions_re.sub(replace, text)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:25.155254Z","iopub.execute_input":"2021-06-11T03:17:25.155624Z","iopub.status.idle":"2021-06-11T03:17:25.174963Z","shell.execute_reply.started":"2021-06-11T03:17:25.155592Z","shell.execute_reply":"2021-06-11T03:17:25.173888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#loại bỏ các từ trong stopword\nstopword_list = nltk.corpus.stopwords.words('english')\ndef remove_stopwords(text, is_lower_case=True):\n    tokenizer = ToktokTokenizer()\n    tokens = tokenizer.tokenize(text)\n    tokens = [token.strip() for token in tokens]\n    if is_lower_case:\n        filtered_tokens = [token for token in tokens if token not in stopword_list]\n    else:\n        filtered_tokens = [token for token in tokens if token.lower() not in stopword_list]\n    filtered_text = ' '.join(filtered_tokens)\n    return filtered_text","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:25.176360Z","iopub.execute_input":"2021-06-11T03:17:25.177021Z","iopub.status.idle":"2021-06-11T03:17:25.200017Z","shell.execute_reply.started":"2021-06-11T03:17:25.176986Z","shell.execute_reply":"2021-06-11T03:17:25.198830Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Stemming\nfrom nltk.stem import  SnowballStemmer\nfrom nltk.tokenize.toktok import ToktokTokenizer\ndef stem_text(text):\n    tokenizer = ToktokTokenizer()\n    stemmer = SnowballStemmer('english')\n    tokens = tokenizer.tokenize(text)\n    tokens = [token.strip() for token in tokens]\n    tokens = [stemmer.stem(token) for token in tokens]\n    return ' '.join(tokens)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:25.201377Z","iopub.execute_input":"2021-06-11T03:17:25.201895Z","iopub.status.idle":"2021-06-11T03:17:25.207542Z","shell.execute_reply.started":"2021-06-11T03:17:25.201863Z","shell.execute_reply":"2021-06-11T03:17:25.206486Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Lemmatization\nfrom nltk.stem import WordNetLemmatizer\nfrom nltk.tokenize.toktok import ToktokTokenizer\nwordnet_lemmatizer = WordNetLemmatizer()\ndef lemma_text(text):\n    tokenizer = ToktokTokenizer()\n    tokens = tokenizer.tokenize(text)\n    tokens = [token.strip() for token in tokens]\n    tokens = [wordnet_lemmatizer.lemmatize(token) for token in tokens]\n    return ' '.join(tokens)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:25.208792Z","iopub.execute_input":"2021-06-11T03:17:25.209115Z","iopub.status.idle":"2021-06-11T03:17:25.220341Z","shell.execute_reply.started":"2021-06-11T03:17:25.209086Z","shell.execute_reply":"2021-06-11T03:17:25.219212Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def clean_sentence(x):\n    x = x.lower()\n    x = clean_punct(x)\n    x = clean_numbers(x)\n    x = replace_typical_misspell(x)\n#   x = remove_stopwords(x)\n    x = replace_contractions(x)\n    x = stem_text(x)\n    x = lemma_text(x)\n    x = x.replace(\"'\",\"\")\n    return x","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:25.221643Z","iopub.execute_input":"2021-06-11T03:17:25.221990Z","iopub.status.idle":"2021-06-11T03:17:25.232391Z","shell.execute_reply.started":"2021-06-11T03:17:25.221957Z","shell.execute_reply":"2021-06-11T03:17:25.231411Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Xử lí dữ liệu trên cả tập train và tập test \nx['question_text'] = x['question_text'].apply(lambda x: clean_sentence(x))\ntest['question_text'] = test['question_text'].apply(lambda x: clean_sentence(x))","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:17:25.233450Z","iopub.execute_input":"2021-06-11T03:17:25.233741Z","iopub.status.idle":"2021-06-11T03:24:13.705966Z","shell.execute_reply.started":"2021-06-11T03:17:25.233715Z","shell.execute_reply":"2021-06-11T03:24:13.704890Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Phân tích các nhãn được trích xuất bằng word cloud**\n* Tạo word cloud để thấy được các từ xuất hiện thường xuyên nhất trong những câu hỏi toxic hay không toxic\n* Các từ có kích thước càng lớn thì tần suất xuất hiện càng nhiều","metadata":{}},{"cell_type":"code","source":"\ndef cloud(text, title, size = (10,7)):\n    words_list = text.unique().tolist()\n    words = ' '.join(words_list)\n    \n    wordcloud = WordCloud(width=800, height=400,\n                          collocations=False\n                         ).generate(words)\n    \n    fig = plt.figure(figsize=size, dpi=80, facecolor='k',edgecolor='k')\n    plt.imshow(wordcloud,interpolation='bilinear')\n    plt.axis('off')\n    plt.title(title, fontsize=25,color='w')\n    plt.tight_layout(pad=0)\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:24:13.707209Z","iopub.execute_input":"2021-06-11T03:24:13.707523Z","iopub.status.idle":"2021-06-11T03:24:13.714830Z","shell.execute_reply.started":"2021-06-11T03:24:13.707494Z","shell.execute_reply":"2021-06-11T03:24:13.713613Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cloud(train[train['target']==0]['question_text'], 'Sincere Questions On Question_text')","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:24:13.716081Z","iopub.execute_input":"2021-06-11T03:24:13.716369Z","iopub.status.idle":"2021-06-11T03:24:40.608307Z","shell.execute_reply.started":"2021-06-11T03:24:13.716342Z","shell.execute_reply":"2021-06-11T03:24:40.606815Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cloud(x[x['target']==0]['question_text'], 'Sincere Questions On Question_text')","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:24:40.610164Z","iopub.execute_input":"2021-06-11T03:24:40.610625Z","iopub.status.idle":"2021-06-11T03:24:47.230164Z","shell.execute_reply.started":"2021-06-11T03:24:40.610576Z","shell.execute_reply":"2021-06-11T03:24:47.229012Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Nhận xét :\n* Đối với câu hỏi sincere , trước khi xử lí dữ liệu stopword có tần suất xuất hiện nhiều \n* Các từ dẫn xuất sau khi được xử lí sẽ được chuyển về từ gốc ","metadata":{}},{"cell_type":"code","source":"cloud(train[train['target']==1]['question_text'], 'Insincere Questions On question_text')","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:24:47.231877Z","iopub.execute_input":"2021-06-11T03:24:47.232291Z","iopub.status.idle":"2021-06-11T03:24:50.535777Z","shell.execute_reply.started":"2021-06-11T03:24:47.232252Z","shell.execute_reply":"2021-06-11T03:24:50.534881Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cloud(x[x['target']==1]['question_text'], 'Insincere Questions On question_text')","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:24:50.537286Z","iopub.execute_input":"2021-06-11T03:24:50.538127Z","iopub.status.idle":"2021-06-11T03:24:53.709811Z","shell.execute_reply.started":"2021-06-11T03:24:50.538079Z","shell.execute_reply":"2021-06-11T03:24:53.708819Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Nhận xét :\n* Đối với câu hỏi insincere ta thấy các từ về sắc tộc , tôn giáo , giới tính xuất hiện nhiều : white , black , muslim , islam , ....","metadata":{}},{"cell_type":"markdown","source":"# ","metadata":{}},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix\nfrom sklearn.metrics import accuracy_score, log_loss\nfrom sklearn.feature_extraction.text import CountVectorizer\nfrom sklearn.model_selection import train_test_split\nimport math\nfrom sklearn.metrics import normalized_mutual_info_score\nfrom sklearn.model_selection import cross_val_score\nfrom sklearn import model_selection\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.metrics import precision_recall_curve, auc, roc_curve\nfrom sklearn.metrics import f1_score","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:24:53.711594Z","iopub.execute_input":"2021-06-11T03:24:53.712290Z","iopub.status.idle":"2021-06-11T03:24:53.719064Z","shell.execute_reply.started":"2021-06-11T03:24:53.712244Z","shell.execute_reply":"2021-06-11T03:24:53.718278Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Chia tập dữ liệu train , test với test_size = 0.2","metadata":{}},{"cell_type":"code","source":"train_x, test_x,train_y, test_y = train_test_split(x['question_text'], x['target'], test_size=0.2, random_state=0)\nprint('x_train: ', train_x.shape, train_y.shape)\nprint('x_test: ',test_x.shape, test_y.shape)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:24:53.720538Z","iopub.execute_input":"2021-06-11T03:24:53.720991Z","iopub.status.idle":"2021-06-11T03:24:53.801763Z","shell.execute_reply.started":"2021-06-11T03:24:53.720940Z","shell.execute_reply":"2021-06-11T03:24:53.800912Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Text Vectorization**","metadata":{}},{"cell_type":"markdown","source":"**Hướng tiếp cận : CountVectorizer**\n* Các giải thuật Machine Learning chỉ làm việc được với số, nên sẽ convert text về định dạng số :\n\n* Chúng ta chia câu hỏi thành các từ. Trong mã hóa thì từ là đơn vị cơ sở. Chúng ta cần một bộ tokenizer có kích thước bằng toàn bộ các từ xuất hiện trong văn bản hoặc bằng toàn bộ các từ có trong từ điển. Một câu văn sẽ được biểu diễn bằng một sparse vector mà mỗi một phần tử đại diện cho một từ, giá trị của nó bằng 0 hoặc 1 tương ứng với từ không xuất hiện hoặc có xuất hiện.\n\n* Chúng ta sử dụng các túi từ (bags of words) để tạo ra một vector có độ dài bằng độ dài của tokenizer và mỗi phần tử của túi từ sẽ đếm số lần xuất hiện của một từ trong câu và sắp xếp chúng theo một vị trí phù hợp trong vector\n\n* Học trên tập từ vựng của toàn bộ tập train và test, vector đếm có thể phải mã hoá những từ có ở tập test và tập train\n\n* Hạn chế : Các biểu diễn theo túi từ có hạn chế đó là không phân biệt được 2 câu văn có cùng các từ bởi túi từ không phân biệt thứ tự trước sau của các từ trong một câu. ví dụ như ‘you have no dog’ và ‘no, you have dog’ là 2 câu văn có biểu diễn giống nhau mặc dù có ý nghĩa trái ngược nhau","metadata":{}},{"cell_type":"code","source":"vectorizer = CountVectorizer()\nbow_train = vectorizer.fit_transform(train_x) \nprint(bow_train.shape)\nbow_test = vectorizer.transform(test_x)\nprint(bow_test.shape)\nprint(\"Done creating Bag-of-Words\")","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:24:53.802872Z","iopub.execute_input":"2021-06-11T03:24:53.803320Z","iopub.status.idle":"2021-06-11T03:25:02.317598Z","shell.execute_reply.started":"2021-06-11T03:24:53.803279Z","shell.execute_reply":"2021-06-11T03:25:02.316886Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Evaluation**\n\n* Đối với dữ liệu mất cân bằng thì sự đánh giá sẽ không tập trung vào Accuracy, thay vào đó ta sẽ tập trung vào điểm F1 , Precision và Recall\n\n* Công thức tính điểm F1 : F1 = 2 * (precision * recall) / (precision + recall)\n\n* Bằng việc sử dụng sklearn.metrics ta sẽ tính được f1-score , accuracy_score","metadata":{}},{"cell_type":"markdown","source":"# Xây dựng mô hình","metadata":{}},{"cell_type":"markdown","source":"**Logistic Regression**\n\n* Mô hình đầu tiên được sử dụng là logistic regression , đây là một thuật toán trong học có giám sát nhằm mục đích phân loại dữ liệu và rất phổ biến cho bài toán phân loại tuyến tính\n\n* Hồi quy logistic là một phương pháp phân tích thống kê được sử dụng để dự đoán giá trị dữ liệu dựa trên các quan sát trước đó của tập dữ liệu.\n\n* Mục đích của hồi quy logistic là ước tính xác suất của các sự kiện, bao gồm xác định mối quan hệ giữa các tính năng từ đó đự đoán xác suất của các kết quả, nên đối với hồi quy logistic ta sẽ có:\n\n>  Input: dữ liệu input (ta sẽ coi có hai nhãn là 0 và 1).\n\n>  Output : Xác suất dữ liệu input rơi vào nhãn 0 hoặc nhãn 1.\n\n![](https://media.geeksforgeeks.org/wp-content/uploads/estimated-regression-result.png)\n\n* Ở hình trên ta gọi các điểm màu xanh là nhãn 0 và các điểm màu đỏ là nhãn 1 đối với hồi quy logistic ta sẽ biết được với mỗi điểm thì xác xuất rơi vào nhãn 0 là bao nhiêu và xác suất rơi vào nhãn 1 là bao nhiêu\n\n* Nhận xét : Việc sử dụng logistic regression trong bài toán này là hợp lí \n\n* Đầu ra dự đoán của mô hình Logistic Regression : $f(\\mathbf{x})=\\mathbf{w}^{T} \\mathbf{x}$\n\n* sẽ có một bộ trọng số w và hai nhãn, nhãn 0 là sincere và nhãn 1 là insincere việc học của mô hình chính là việc điều chỉnh bộ trọng số w sao cho dự đoán đầu ra theo đúng ý muốn của\n\n* Trong số các hàm số logistic thì hàm sigmoid được sử dụng nhiều nhất, vì nó bị chặn trong khoảng (0,1):\n $f(s)=\\frac{1}{1+e^{-s}} \\triangleq \\sigma(s)$","metadata":{}},{"cell_type":"code","source":"print(f\"xResults of logistic regression on full bag-of-words\")\nlogistic = LogisticRegression(penalty=\"l2\", C=1) \nlogistic.fit(bow_train, train_y) \ntrain_predictions = logistic.predict(bow_train)\ntrain_acc = accuracy_score(train_y, train_predictions)  \ntrain_f1 = f1_score(train_y, train_predictions) \nprint(f\"Training accuracy: {train_acc:.2%}, F1: {train_f1:.4f}\") \ntest_predictions = logistic.predict(bow_test)\ntest_acc = accuracy_score(test_y, test_predictions) \ntest_f1 = f1_score(test_y, test_predictions) \nprint(f\"Testing accuracy:  {test_acc:.2%}, F1: {test_f1:.4f}\")","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:25:02.318557Z","iopub.execute_input":"2021-06-11T03:25:02.319011Z","iopub.status.idle":"2021-06-11T03:25:16.051175Z","shell.execute_reply.started":"2021-06-11T03:25:02.318981Z","shell.execute_reply":"2021-06-11T03:25:16.050105Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Nhận xét:\n* Tỉ lệ accuracy cao\n* Sau khi chia lại dữ liệu ta thấy kết quả tốt hơn dự đoán câu hỏi insincere tăng \n* f1-score tăng lên đáng kể sau khi chia lại dữ liệu","metadata":{}},{"cell_type":"markdown","source":"**Gradient Boosting**\n\n* Ý tưởng cơ bản của thuật toán Gradient Boosting là lần lượt thêm các decision trees nối tiếp nhau. Tree thêm vào sau sẽ cố gắng giải quyết những sai sót của tree trước đó.\n\n* Xây dựng một lượng lớn các model (thường là cùng loại). Mỗi model sau sẽ học cách sửa những lỗi của model trước (dữ liệu mà model trước dự đoán sai) -> tạo thành một chuỗi các model mà model sau sẽ tốt hơn model trước bởi trọng số được update qua mỗi model (cụ thể ở đây là trọng số của những dữ liệu dự đoán đúng sẽ không đổi, còn trọng số của những dữ liệu dự đoán sai sẽ được tăng thêm) . Chúng ta sẽ lấy kết quả của model cuối cùng trong chuỗi model này làm kết quả trả về.","metadata":{}},{"cell_type":"code","source":"from sklearn.ensemble import GradientBoostingClassifier\nprint(f\"Results of gradient boosting on full bag-of-words\")\ngbc = GradientBoostingClassifier() \ngbc.fit(bow_train, train_y) \ntrain_predictions_gbc = gbc.predict(bow_train)\ntrain_acc_gbc = accuracy_score(train_y, train_predictions_gbc) \ntrain_f1_gbc = f1_score(train_y, train_predictions_gbc) \nprint(f\"Training accuracy: {train_acc_gbc:.2%}, F1: {train_f1_gbc:.4f}\") \ntest_predictions_gbc = gbc.predict(bow_test)\ntest_acc_gbc = accuracy_score(test_y, test_predictions_gbc) \ntest_f1_gbc = f1_score(test_y, test_predictions_gbc) \nprint(f\"Testing accuracy:  {test_acc_gbc:.2%}, F1: {test_f1_gbc:.4f}\")","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:25:16.052325Z","iopub.execute_input":"2021-06-11T03:25:16.052593Z","iopub.status.idle":"2021-06-11T03:26:49.287727Z","shell.execute_reply.started":"2021-06-11T03:25:16.052567Z","shell.execute_reply":"2021-06-11T03:26:49.286493Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Nhận xét**\n* F1-score thấp hơn hẳn so với logistic regression\n\n* tỉ lệ accuracy thấp \n\n* không phù hợp với bài toán này","metadata":{}},{"cell_type":"markdown","source":"# Tổng kết\n\n* Đối với bài toán mất cân bằng dữ liệu cần dùng resampling để tăng hiệu quả của đầu ra . Sau nhiều lần chạy với các tỉ lệ khác nhau thì tỉ lệ 4:1 đem lại kết quả cao nhất\n\n* Bài báo cáo đã xử lí được các yếu tố gây nhiễu trong dữ liệu , sử dụng CountVectorizer để phân tách và chuyển đổi câu hỏi trước khi đưa vào học . \n\n* Đối với bài toán trên ta thấy được mô hình Logistic Regression hiệu quả hơn so với các model cơ bản khác","metadata":{}},{"cell_type":"markdown","source":"# Submission","metadata":{}},{"cell_type":"code","source":"x_val = vectorizer.transform(test['question_text'])\nvalidation_predictions = logistic.predict(x_val)\nsubmission = pd.DataFrame({'qid':test['qid'], 'prediction':validation_predictions })\nsubmission.to_csv('submission.csv', index=False)\nsubmission","metadata":{"execution":{"iopub.status.busy":"2021-06-11T03:26:49.289033Z","iopub.execute_input":"2021-06-11T03:26:49.289326Z","iopub.status.idle":"2021-06-11T03:26:57.694051Z","shell.execute_reply.started":"2021-06-11T03:26:49.289298Z","shell.execute_reply":"2021-06-11T03:26:57.692963Z"},"trusted":true},"execution_count":null,"outputs":[]}]}