{"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":"code","source":"from pandas import read_csv, DataFrame, get_dummies\nfrom numpy import array, concatenate\nfrom os.path import exists\nfrom os import listdir\nimport json\nfrom tensorflow.keras.preprocessing.text import Tokenizer, tokenizer_from_json\nfrom tensorflow.keras.preprocessing.sequence import pad_sequences\nfrom numpy import absolute\n\nclass Tokenize:\n    def __init__(self,num_words=None):\n        self.num_words=num_words\n        if self.num_words!=None:\n            self.tokenizer=Tokenizer(num_words=self.num_words)\n        else:\n            self.tokenizer=Tokenizer()\n    def fit(self,words):\n        self.tokenizer.fit_on_texts(words)\n    def getSequences(self,inputs):\n        return self.tokenizer.texts_to_sequences(inputs)\n    def padSequences(self,seq,maxlen=150,padding='pre'):\n        return pad_sequences(seq,maxlen=maxlen,padding=padding)\n    def save(self,fname='tokenizer.json'):\n        #print(self.tokenizer.to_json())\n        with open(fname,'w') as config_file:\n            json.dump(self.tokenizer.to_json(),config_file)\n    def load_from_config(self,fname='tokenizer.json'):\n        with open(fname,'r') as config_file:\n            config=json.load(config_file)\n        self.tokenizer = tokenizer_from_json(config)\n    def getVocabSize(self):\n        return len(self.tokenizer.word_index.keys())\n\n\nclass Preprocessing:\n    def __init__(self,dataset_path='/kaggle/input/feedback-prize-effectiveness/'):\n        self.train_file_path = dataset_path + \"train.csv\"\n        self.test_file_path = dataset_path + \"test.csv\"\n        self.tokenizer_config = '/kaggle/working/tokenizer.json'\n        if exists(self.tokenizer_config):\n            self.tokenizer = Tokenize()\n            self.tokenizer.load_from_config(self.tokenizer_config)    \n        else:\n            self.tokenizer = Tokenize()\n            self.tokenize()\n        self.vocab_size = self.tokenizer.getVocabSize()\n    \n    def read_data(self):\n        assert exists(self.train_file_path) == True, \"Train file does not exists!\"\n        assert exists(self.test_file_path) == True, \"Test file does not exists!\"\n        self.dataset_train = read_csv(self.train_file_path)\n        self.dataset_test = read_csv(self.test_file_path)\n    \n    def checkSparsity(self, return_type=0):\n        sparsity_train = {}\n        sparsity_test = {}\n        for column in self.dataset_train.columns:\n            sparsity_train[column] =  [self.dataset_train[column].isnull().sum()]\n        for column in self.dataset_test.columns:\n            sparsity_test[column] =  [self.dataset_test[column].isnull().sum()]\n        if return_type == 0:\n            return sparsity_train, sparsity_test\n        else:\n            return DataFrame(sparsity_train), DataFrame(sparsity_test)\n\n    def checkDataType(self, return_type=0):\n        dtype_train = {}\n        dtype_test = {}\n        for column in self.dataset_train.columns:\n            dtype_train[column] =  [self.dataset_train[column].dtype]\n        for column in self.dataset_test.columns:\n            dtype_test[column] =  [self.dataset_test[column].dtype]\n        if return_type == 0:\n            return dtype_train, dtype_test\n        else:        \n            return DataFrame(dtype_train), DataFrame(dtype_test)\n\n    def missingDataImputation(self, target_column='discourse_effectiveness'):\n        sparsity_train, sparsity_test = self.checkSparsity()\n        dtype_train, dtype_test = self.checkSparsity()\n        for column in self.dataset_train.columns:\n            if column == target_column:\n                continue\n            if sparsity_train[column][0] != 0:\n                if dtype_train[column][0] == 'object':\n                    self.dataset_train[column] = self.dataset_train[column].fillna('NA')\n                else:\n                    self.dataset_train[column] = self.dataset_train[column].fillna(0)\n        for column in self.dataset_test.columns:\n            if sparsity_test[column][0] != 0:\n                if dtype_test[column][0] == 'object':\n                    self.dataset_test[column] = self.dataset_test[column].fillna('NA')\n                else:\n                    self.dataset_test[column] = self.dataset_test[column].fillna(0)\n\n    def stringEncoding(self,column_list):\n        for column in column_list:\n            if column in self.dataset_train.columns:\n                distincts=self.dataset_train[column].nunique()\n                if distincts <= 2:\n                    mapping = {distincts[i] : i for i in range(len(distincts))}\n                    self.dataset_train[column].replace(mapping,inplace=True)\n                else:\n                    self.dataset_train = get_dummies(self.dataset_train,columns=[column])\n            if column in self.dataset_test.columns:\n                distincts=self.dataset_test[column].nunique()\n                if distincts <= 2:\n                    mapping = {distincts[i] : i for i in range(len(distincts))}\n                    self.dataset_test[column].replace(mapping,inplace=True)\n                else:\n                    self.dataset_test = get_dummies(self.dataset_test,columns=[column])\n    def clean_text(self,text):\n        stop_symbols = ['.','?',',',';','\\'','\\\"','-','!','&','#','%']\n        for symbol in stop_symbols:\n            text = text.replace(symbol,'')\n        return text.lower()\n    def tokenize(self,path = '/kaggle/input/feedback-prize-effectiveness/train/'):\n        words = []\n        for file in listdir(path):\n            fd = open(path + file,'r')\n            data = list(set(map(self.clean_text,fd.read().split(' '))))\n            fd.close()\n            for word in data:\n                if word not in words:\n                    words.append(word)\n            #print(f\"{file} has {len(data)} unique words.\")\n        self.tokenizer.fit(words)\n        self.tokenizer.save(self.tokenizer_config)\n    def generateTokens(self, sentence):\n        data = ' '.join(list(map(self.clean_text,sentence.split(' '))))\n        sequence = self.tokenizer.getSequences([data])\n        #print(f\"Generated sequence for {data} is {sequence[0]}\")\n        return self.tokenizer.padSequences(sequence)[0]\n    def getX(self,mode=0):\n        if mode == 0:\n            df = self.dataset_train\n        else:\n            df = self.dataset_test\n        feature_columns = []\n        for column in df.columns:\n            if 'discourse_type' in column:\n                feature_columns.append(column)\n        feature_columns = list(set(feature_columns).difference(set(['discourse_type_Rebuttal','discourse_type_Counterclaim'])))\n        sequence = array(list(map(self.generateTokens, df['discourse_text'].values)))\n        for column in feature_columns:\n            data =  array(df[column].values).reshape(-1,1)\n            sequence = concatenate((sequence,data),axis=1)\n        return sequence\n    def getY(self):\n        target = []\n        for column in self.dataset_train.columns:\n            if 'discourse_effectiveness' in column:\n                target.append(self.dataset_train[column].values)\n        return array(target).T\n    \n    def generateSubmission(self,Y,fname='submission.csv'):\n        result={}\n        result['discourse_id'] = self.dataset_test['discourse_id']\n        Y=Y.T\n        result['Ineffective'] = absolute(Y[2])\n        result['Adequate'] = absolute(Y[0])\n        result['Effective'] = absolute(Y[1])\n        result = DataFrame(result)\n        result.to_csv(f\"{fname}\", index=False)","metadata":{"_uuid":"91c77a69-eb34-4010-89f3-cf1981b51e5b","_cell_guid":"1939e856-69bc-4a6f-8be2-fc64d352ae4f","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2022-07-01T08:26:07.488203Z","iopub.execute_input":"2022-07-01T08:26:07.489373Z","iopub.status.idle":"2022-07-01T08:26:18.069348Z","shell.execute_reply.started":"2022-07-01T08:26:07.489235Z","shell.execute_reply":"2022-07-01T08:26:18.068148Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow.keras.models import Sequential, load_model\nfrom tensorflow.keras.layers import Dense, LSTM, Conv1D, Flatten, Dropout, Embedding, MaxPool1D\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.losses import CategoricalCrossentropy\nfrom tensorflow.keras.metrics import AUC, CategoricalAccuracy\nfrom os.path import exists\n\nclass Model:\n    def __init__(self, fname=None):\n        self.fname = fname\n        if self.fname != None:\n            assert exists(fname) == True, f\"{fname} model file does not exists!\"\n            self.model = load_model(fname)\n    def cnn(self, vocab_size, embedding_dim, max_sequence_length, output_classes, learning_rate = 1e-3,dropout_p = 0.2,cnn_architecture = [16, 32, 64, 128], dense_architecture = [2048, 512, 32, 16]):\n        self.model = Sequential()\n        self.model.add(Embedding(\n            input_dim = vocab_size + 1,\n            output_dim = embedding_dim,\n            input_length = max_sequence_length,\n            mask_zero = True\n        ))\n        self.model.add(Conv1D(cnn_architecture[0], 3,activation='relu', input_shape=(max_sequence_length,embedding_dim), padding='valid'))\n        self.model.add(MaxPool1D())\n        for i in range(1,len(cnn_architecture)):\n            self.model.add(Conv1D(cnn_architecture[i], 3,activation='relu', padding='valid'))\n            self.model.add(MaxPool1D())\n        self.model.add(Flatten())\n        for i in range(len(dense_architecture)):\n            self.model.add(Dense(dense_architecture[i],activation='relu'))\n            self.model.add(Dropout(dropout_p))\n        self.model.add(Dense(output_classes,activation='softmax'))\n        self.model.compile(optimizer=Adam(learning_rate=learning_rate), loss=CategoricalCrossentropy(),metrics = [AUC(multi_label=True) ,CategoricalAccuracy()])\n    def lstm(self, vocab_size, embedding_dim, max_sequence_length, output_classes, learning_rate = 1e-3,dropout_p = 0.2,lstm_architecture = [64, 32, 16], dense_architecture = [16, 8]):\n        self.model = Sequential()\n        self.model.add(Embedding(\n            input_dim = vocab_size + 1,\n            output_dim = embedding_dim,\n            input_length = max_sequence_length,\n            mask_zero = True\n        ))\n        for i in range(len(lstm_architecture)):\n            self.model.add(LSTM(lstm_architecture[i], return_sequences=True, activation='relu'))\n        self.model.add(Flatten())\n        for i in range(len(dense_architecture)):\n            self.model.add(Dense(dense_architecture[i],activation='relu'))\n            self.model.add(Dropout(dropout_p))\n        self.model.add(Dense(output_classes,activation='softmax'))\n        self.model.compile(optimizer=Adam(learning_rate=learning_rate), loss=CategoricalCrossentropy(),metrics = [AUC(multi_label=True) ,CategoricalAccuracy()]) # Experiment with Binary classification variant.\n    def metrics(self,Y_actual, Y_pred):\n        acc = CategoricalAccuracy()\n        acc.update_state(Y_actual, Y_pred)\n        return acc.result().numpy()\n    def save_model(self):\n        self.model.save(self.fname)\n    def fit(self, X, Y, batch_size = 128, epochs = 5):\n        return self.model.fit(X,Y,batch_size=batch_size, epochs=epochs)\n    def predict(self, X):\n        return self.model.predict(X)","metadata":{"execution":{"iopub.status.busy":"2022-07-01T08:30:18.561006Z","iopub.execute_input":"2022-07-01T08:30:18.561492Z","iopub.status.idle":"2022-07-01T08:30:18.58103Z","shell.execute_reply.started":"2022-07-01T08:30:18.561444Z","shell.execute_reply":"2022-07-01T08:30:18.579888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nfrom matplotlib import pyplot as plt\n\n\npreprocessor = Preprocessing()\npreprocessor.read_data()\npreprocessor.stringEncoding(['discourse_type','discourse_effectiveness'])\nX = preprocessor.getX()\nY = preprocessor.getY()\nvocab_size = preprocessor.vocab_size\nX_train, X_test, Y_train, Y_test = train_test_split(X,Y,test_size=0.1,shuffle=True,random_state=42)\nmodel = Model()\nmodel.cnn(vocab_size, 16, X.shape[-1], Y.shape[-1])\nhistory = model.fit(X_train, Y_train)\npredictions = model.predict(X_test)\nprint(\"Accuracy on validation split : \",model.metrics(Y_test, predictions))\nX = preprocessor.getX(mode = 1)\npredictions = model.predict(X)\npreprocessor.generateSubmission(predictions)","metadata":{"execution":{"iopub.status.busy":"2022-07-01T08:30:18.834593Z","iopub.execute_input":"2022-07-01T08:30:18.835035Z","iopub.status.idle":"2022-07-01T08:31:49.963715Z","shell.execute_reply.started":"2022-07-01T08:30:18.834994Z","shell.execute_reply":"2022-07-01T08:31:49.962634Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}