{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport time\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\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, CuDNNGRU, Conv1D, RNN\nfrom keras.layers import Bidirectional, GlobalMaxPool1D\nfrom keras.models import Model\nfrom keras import initializers, regularizers, constraints, optimizers, layers","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Importing training and test data\ntrain = pd.read_csv(\"../input/twitter-sentiment-analysis-hatred-speech/train.csv\")\ntest = pd.read_csv(\"..//input/twitter-sentiment-analysis-hatred-speech/test.csv\")\nprint(\"Train shape : \",train.shape)\nprint(\"Test shape : \",test.shape)","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"# ------------Step 1 - Definig cleaning functions - URLs, Mentions, Negation handling, UF8 (BOM), Special chracters and numbers\n#!pip install bs4\n#!pip install nltk\n#!pip install et_xmlfile\n\n#!pip install lxml\nimport re\nfrom bs4 import BeautifulSoup\nfrom nltk.tokenize import WordPunctTokenizer\nTokenz = WordPunctTokenizer()\nMentions_Removal = r'@[A-Za-z0-9_]+'\nHttp_Removal = r'http(s?)://[^ ]+'\n#HttpS_Removal = r'https://[^ ]+'\nWww_Removal = r'www.[^ ]+'\n\n#Combining the above 3 removals functions\n#Combining_MentnHttp = r'|'.join((Mentions_Removal,Http_Removal))\nCombining_MentnHttp1 = r'|'.join((Http_Removal,Www_Removal))\n\n\n#Creating a negation dictionary because words with apostrophe symbol (') will (Can't > can t) \nNegation_Dictonary = {\"ain't\": \"is not\", \"aren't\": \"are not\",\"can't\": \"cannot\", \"'cause\": \"because\", \"could've\": \"could have\", \n                \"couldn't\": \"could not\", \"didn't\": \"did not\",  \"doesn't\": \"does not\", \"don't\": \"do not\", \"hadn't\": \"had not\", \n                \"hasn't\": \"has not\", \"haven't\": \"have not\", \"he'd\": \"he would\",\"he'll\": \"he will\", \"he's\": \"he is\", \"how'd\": \"how did\", \n                \"how'd'y\": \"how do you\", \"how'll\": \"how will\", \"how's\": \"how is\",  \"I'd\": \"I would\", \"I'd've\": \"I would have\", \n                \"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\",\n                \"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\", \n                \"it'd've\": \"it would have\", \"it'll\": \"it will\", \"it'll've\": \"it will have\",\"it's\": \"it is\", \"let's\": \"let us\", \n                \"ma'am\": \"madam\", \"mayn't\": \"may not\", \"might've\": \"might have\",\"mightn't\": \"might not\",\"mightn't've\": \"might not have\",\n                \"must've\": \"must have\", \"mustn't\": \"must not\", \"mustn't've\": \"must not have\", \"needn't\": \"need not\", \n                \"needn't've\": \"need not have\",\"o'clock\": \"of the clock\", \"oughtn't\": \"ought not\", \"oughtn't've\": \"ought not have\", \n                \"shan't\": \"shall not\", \"sha'n't\": \"shall not\", \"shan't've\": \"shall not have\", \"she'd\": \"she would\", \n                \"she'd've\": \"she would have\", \"she'll\": \"she will\", \"she'll've\": \"she will have\", \"she's\": \"she is\", \n                \"should've\": \"should have\", \"shouldn't\": \"should not\", \"shouldn't've\": \"should not have\", \"so've\": \"so have\",\n                \"so's\": \"so as\", \"this's\": \"this is\",\"that'd\": \"that would\", \"that'd've\": \"that would have\", \"that's\": \"that is\",\n                \"there'd\": \"there would\", \"there'd've\": \"there would have\", \"there's\": \"there is\", \"here's\": \"here is\",\n                \"they'd\": \"they would\", \"they'd've\": \"they would have\", \"they'll\": \"they will\", \"they'll've\": \"they will have\",\n                \"they're\": \"they are\", \"they've\": \"they have\", \"to've\": \"to have\", \"wasn't\": \"was not\", \"we'd\": \"we would\", \n                \"we'd've\": \"we would have\", \"we'll\": \"we will\", \"we'll've\": \"we will have\", \"we're\": \"we are\", \"we've\": \"we have\",\n                \"weren't\": \"were not\", \"what'll\": \"what will\", \"what'll've\": \"what will have\", \"what're\": \"what are\",  \n                \"what's\": \"what is\", \"what've\": \"what have\", \"when's\": \"when is\", \"when've\": \"when have\", \"where'd\": \"where did\", \n                \"where's\": \"where is\", \"where've\": \"where have\", \"who'll\": \"who will\", \"who'll've\": \"who will have\", \n                \"who's\": \"who is\", \"who've\": \"who have\", \"why's\": \"why is\", \"why've\": \"why have\", \"will've\": \"will have\", \n                \"won't\": \"will not\", \"won't've\": \"will not have\", \"would've\": \"would have\", \"wouldn't\": \"would not\", \n                \"wouldn't've\": \"would not have\", \"y'all\": \"you all\", \"y'all'd\": \"you all would\",\"y'all'd've\": \"you all would have\",\n                 \"you'll\": \"you will\", \"you'll've\": \"you will have\", \"you're\": \"you are\", \"you've\": \"you have\"}\nNegation_Joining= re.compile(r'\\b(' + '|'.join(Negation_Dictonary.keys()) + r')\\b')\n\ndef Clean_Question_Function(text):\n    BeautifulSoup_assign = BeautifulSoup(text, 'html.parser')\n    Souping = BeautifulSoup_assign.get_text()\n    try:\n        BOM_removal = Souping.decode(\"utf-8-sig\").replace(u\"\\ufffd\", \"?\")\n    except:\n        BOM_removal = Souping\n    Comb_2 = re.sub(Combining_MentnHttp1, '', BOM_removal)\n    #Comb_3 = re.sub(Www_Removal,'',Comb_2)\n    Comb_3 = re.sub(Mentions_Removal,'',Comb_2)\n    LowerCase = Comb_3.lower()\n    Negation_Handling = Negation_Joining.sub(lambda x: Negation_Dictonary[x.group()], LowerCase)\n    Letters_only = re.sub(\"[^a-zA-Z]\", \" \", Negation_Handling)\n    \n    # Removing unneccessary white- Tokenizing and joining together\n    Tokenization = [x for x  in Tokenz.tokenize(Letters_only) if len(x) > 1]\n    return (\" \".join(Tokenization)).strip()\nClean_Question_Function\n\n#Removing stop words from training and test\nfrom nltk.corpus import stopwords\nstopwords = set(stopwords.words('english')) - {'no', 'nor', 'not'}\ndef remove_stopwords(text):\n    return ' '.join([word for word in str(text).split() if word not in stopwords])\n\n# Lemmatization\nfrom nltk.stem import WordNetLemmatizer\ndef get_lemmatized_text(corpus):\n    lemmatizer = WordNetLemmatizer()\n    return [' '.join([lemmatizer.lemmatize(word) for word in review.split()]) for review in corpus]\n\n#Cleaning up the data with step 1\nxrange = range #Defining X range","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Cleaning Training data**"},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time\nxrange = range\nprint (\"Cleaning the reviews...\\n\")\nclean_review_texts = []\nfor i in xrange(0,len(test)):\n    if( (i+1)%100000 == 0 ):\n        \"Reviews %d of %d has been processed\".format( i+1, len(test) )  \n        \n    clean_review_texts.append(Clean_Question_Function(test['tweet'][i]))\n    \n#Changing into dataframe\ntest['cleaned_tweet'] = clean_review_texts","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Cleaning test data**"},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time\nxrange = range\nprint (\"Cleaning the reviews...\\n\")\nclean_review_texts = []\nfor i in xrange(0,len(train)):\n    if( (i+1)%100000 == 0 ):\n        \"Reviews %d of %d has been processed\".format( i+1, len(train) )  \n        \n    clean_review_texts.append(Clean_Question_Function(train['tweet'][i]))\n    \n#Changing into dataframe\ntrain['cleaned_tweet'] = clean_review_texts","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Stopwords: This is not quite helpful if we use pre-trained models"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Stopwords\nimport string\nfrom nltk.corpus import stopwords\neng_stopwords = set(stopwords.words(\"english\"))","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":false,"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","trusted":true},"cell_type":"code","source":"#Lemmatization\ntrain['cleaned_tweet'] = get_lemmatized_text(train['cleaned_tweet'])\ntest['cleaned_tweet'] = get_lemmatized_text(test['cleaned_tweet'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Feature Engineering** - Creating features from given text"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Number of words\ntrain['cleaned_tweet_len'] = train['cleaned_tweet'].str.len()\ntest['cleaned_tweet_len'] = test['cleaned_tweet'].str.len()\n\n## Number of unique words in the text ##\ntrain[\"num_unique_words\"] = train[\"cleaned_tweet\"].apply(lambda x: len(set(str(x).split())))\ntest[\"num_unique_words\"] = test[\"cleaned_tweet\"].apply(lambda x: len(set(str(x).split())))\n\n## Number of characters in the text ##\ntrain[\"num_chars\"] = train[\"cleaned_tweet\"].apply(lambda x: len(str(x)))\ntest[\"num_chars\"] = test[\"cleaned_tweet\"].apply(lambda x: len(str(x)))\n\n## Number of stopwords in the text ##\ntrain[\"num_stopwords\"] = train[\"cleaned_tweet\"].apply(lambda x: len([w for w in str(x).lower().split() if w in eng_stopwords]))\ntest[\"num_stopwords\"] = test[\"cleaned_tweet\"].apply(lambda x: len([w for w in str(x).lower().split() if w in eng_stopwords]))\n\n## Number of punctuations in the text ##\ntrain[\"num_punctuations\"] =train[\"tweet\"].apply(lambda x: len([c for c in str(x) if c in string.punctuation]) )\ntest[\"num_punctuations\"] =test[\"tweet\"].apply(lambda x: len([c for c in str(x) if c in string.punctuation]) )\n\n## Number of upper case words in the text ##\ntrain[\"num_words_upper\"] = train[\"tweet\"].apply(lambda x: len([w for w in str(x).split() if w.isupper()]))\ntest[\"num_words_upper\"] = test[\"tweet\"].apply(lambda x: len([w for w in str(x).split() if w.isupper()]))\n\n## Number of title case words in the text ##\ntrain[\"num_words_title\"] = train[\"tweet\"].apply(lambda x: len([w for w in str(x).split() if w.istitle()]))\ntest[\"num_words_title\"] = test[\"tweet\"].apply(lambda x: len([w for w in str(x).split() if w.istitle()]))\n\n## Average length of the words in the text ##\ntrain[\"mean_word_len\"] = train[\"cleaned_tweet\"].apply(lambda x: np.mean([len(w) for w in str(x).split()]))\ntest[\"mean_word_len\"] = test[\"cleaned_tweet\"].apply(lambda x: np.mean([len(w) for w in str(x).split()]))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Looking at the combined features of both training and test data "},{"metadata":{"trusted":true},"cell_type":"code","source":"train.groupby('label').mean()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Stopwords: They are not quite useful for when we are using pre-trained models so I am escaping these"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Stop words\n#train['cleaned_tweet'] = train['cleaned_tweet'].apply(lambda text: remove_stopwords(text))\n#test['cleaned_tweet'] = test['cleaned_tweet'].apply(lambda text: remove_stopwords(text))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train = train.sample(frac=1)\ntrain = train.reset_index(drop=True)\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test = test.sample(frac=1)\ntest = test.reset_index(drop=True)\ntest.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#train['cleaned_tweet'] = train['cleaned_tweet'].fillna(\"_##_\").values\n#test['cleaned_tweet'] = test['cleaned_tweet'].fillna(\"_##_\").values","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Parameters for models\nembed_size = 300 # how big is each word vector\nmax_features = 5000 # how many unique words to use (i.e num rows in embedding vector)\nmaxlen = 80 # max number of words in a question to use\nSEED = 1029\n\n## Tokenize the sentences\ntokenizer = Tokenizer(num_words=max_features, split=' ')\ntokenizer.fit_on_texts(train['cleaned_tweet'].values)\n\ntrain_data = tokenizer.texts_to_sequences(train['cleaned_tweet'].values)\ntest_data = tokenizer.texts_to_sequences(test['cleaned_tweet'].values)\n\n## Pad the sentences \ntrain_data_pad  = pad_sequences(train_data , maxlen=maxlen)\ntest_data_pad  = pad_sequences(test_data , maxlen=maxlen)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"\\nExamples:\")\nprint(train['cleaned_tweet'][100], '-->', train_data[100])\nprint(train['cleaned_tweet'][200], '-->', train_data[200])\nprint(train['cleaned_tweet'][300], '-->', train_data[300])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.layers import Input\ndef fit(self, X_train, y_train):\n    self.model.fit(self.preprocessing(X_train), y_train, epochs=self.epochs, batch_size=512)\n\ndef guess(self, features):\n        features = self.preprocessing(features)\n        result = self.model.predict(features).flatten()\n        return result","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Pre-trained model**"},{"metadata":{},"cell_type":"markdown","source":"**Glove **"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Importing Glove and creating vector\nEMBEDDING_FILE_GLOVE = '../input/quora-insincere-questions-classification/embeddings/glove.840B.300d/glove.840B.300d.txt'\ndef get_coefs(word,*arr): return word, np.asarray(arr, dtype='float32')\nembeddings_index = dict(get_coefs(*o.split(\" \")) for o in open(EMBEDDING_FILE_GLOVE))\nall_embs = np.stack(embeddings_index.values())\nemb_mean,emb_std = all_embs.mean(), all_embs.std()\n\nembed_size = all_embs.shape[1]\nword_index = tokenizer.word_index\nnb_words = min(max_features, len(word_index))\nembedding_matrix_glove = np.random.normal(emb_mean, emb_std, (nb_words, embed_size))\nfor word, i in word_index.items():\n    if i >= max_features: continue\n    embedding_vector = embeddings_index.get(word)\n    if embedding_vector is not None: embedding_matrix_glove[i] = embedding_vector\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Paragram**"},{"metadata":{"trusted":true},"cell_type":"code","source":"EMBEDDING_FILE_PARA = '../input/quora-insincere-questions-classification/embeddings/paragram_300_sl999/paragram_300_sl999.txt'\ndef get_coefs(word,*arr): return word, np.asarray(arr, dtype='float32')\nembeddings_index = dict(get_coefs(*o.split(\" \")) for o in open(EMBEDDING_FILE_PARA, encoding=\"utf8\", errors='ignore') if len(o)>80)\n\nall_embs = np.stack(embeddings_index.values())\n\nemb_mean,emb_std = all_embs.mean(), all_embs.std()\nembed_size = all_embs.shape[1]\n\n# word_index = tokenizer.word_index\nnb_words = min(max_features, len(word_index))\nembedding_matrix_para = np.random.normal(emb_mean, emb_std, (nb_words, embed_size))\nfor word, i in word_index.items():\n    if i >= max_features: continue\n    embedding_vector = embeddings_index.get(word)\n    if embedding_vector is not None: embedding_matrix_para[i] = embedding_vector","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Word2Vec** - Google"},{"metadata":{"trusted":true},"cell_type":"code","source":"EMBEDDING_FILE_W2V = '../input/quora-insincere-questions-classification/embeddings/wiki-news-300d-1M/wiki-news-300d-1M.vec'\ndef get_coefs(word,*arr): return word, np.asarray(arr, dtype='float32')\nembeddings_index = dict(get_coefs(*o.split(\" \")) for o in open(EMBEDDING_FILE_W2V) if len(o)>80)\n\nall_embs = np.stack(embeddings_index.values())\nemb_mean,emb_std = all_embs.mean(), all_embs.std()\nembed_size = all_embs.shape[1]\n\nword_index = tokenizer.word_index\nnb_words = min(max_features, len(word_index))\nembedding_matrix_w2v = np.random.normal(emb_mean, emb_std, (nb_words, embed_size))\nfor word, i in word_index.items():\n    if i >= max_features: continue\n    embedding_vector = embeddings_index.get(word)\n    if embedding_vector is not None: embedding_matrix_w2v[i] = embedding_vector","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Concatination Glove, W2V, and Para\nembedding_matrix = np.concatenate((embedding_matrix_glove, embedding_matrix_para,embedding_matrix_w2v), axis=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"\\nExample\")\nprint(train_data[100], '-->', train_data_pad[100])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print('\\nInput train data shape:', train_data_pad.shape)\nprint('Input test data shape:', test_data_pad.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Setting up train and test\ntrain_X = train.drop(['id','tweet','num_unique_words','num_chars','num_words_upper','num_punctuations','mean_word_len','label','cleaned_tweet'],axis=1)#Dec\ny = train['label'].values\n\ntest_X = test.drop(['id','tweet','num_unique_words','num_chars','num_words_upper','num_punctuations','mean_word_len','cleaned_tweet'],axis=1)\n\nprint(train_X.columns)\nprint(test_X.columns)\nprint(train_X.shape)\nprint(test_X.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.preprocessing import StandardScaler\nscaler = StandardScaler()\nscaler.fit(train_X.values)\nscaled_train_X = scaler.transform(train_X)\nscaled_test_X = scaler.transform(test_X)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def split_features(X):\n    \n    X_list = []\n    x_0 = train_data_pad[..., :]\n    X_list.append(x_0)\n    \n    x_1 = X[..., :]\n    X_list.append(x_1)\n\n    return X_list","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"embed_size","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.layers import Input, Dense, Dropout, Conv1D, Embedding, SpatialDropout1D, Concatenate,GRU, LSTM,Bidirectional, GlobalAveragePooling1D, GlobalMaxPooling1D,CuDNNLSTM, CuDNNGRU, Activation, Reshape\ninp1 = Input(shape=(maxlen,))\nt = Embedding(max_features, embed_size*3, weights=[embedding_matrix])(inp1)\nt = SpatialDropout1D(0.1)(t)\nt1 = Bidirectional(CuDNNLSTM(256, return_sequences=True))(t)\nt2 = Bidirectional(CuDNNGRU(128, return_sequences=True))(t)\nmax_pool1 = GlobalMaxPooling1D()(t1)\nmax_pool2 = GlobalMaxPooling1D()(t2)\nconc = Concatenate()([max_pool1, max_pool2])\nout_1 = Dense(32, activation=\"relu\")(conc)\n\n\n\ninp_2 = Input(shape=(3,))\ndense_2 = Dense(120,activation='relu')(inp_2)\nout_dense_2 = Reshape(target_shape=(120,))(dense_2)\ndense_3 = Dense(32,activation='relu')(out_dense_2)\nout_dense_3 = Reshape(target_shape=(32,))(dense_3)\n\ninput_model = [inp1, inp_2]\noutput_model = [out_1, out_dense_3]\n\noutput = Concatenate()(output_model)\noutput = Dense(16, activation='relu')(output)\noutput = Dropout(0.2)(output)\noutput = Dense(1, activation='sigmoid')(output)\n\nadam = optimizers.Adam(lr=0.007)\nmodelll = Model(inputs=input_model, outputs=output)\nmodelll.compile(loss='binary_crossentropy', optimizer=adam, metrics=['accuracy'])\nprint(modelll.summary())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"## Train the model \nmodelll.fit(split_features(train_X.values), y, batch_size=512, epochs=50,shuffle=True,validation_split=0.20)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"def split_features(X):\n    \n    X_list = []\n    x_0 = test_data_pad[..., :]\n    X_list.append(x_0)\n    \n    x_1 = X[..., :]\n    X_list.append(x_1)\n\n    return X_list","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"#Predicting on test set\npred32 = modelll.predict(split_features(test_X.values))\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Checking the accuracy\n#pred_test = modelll.predict([test_X],batch_size=512, verbose=1)\npred_test_y = (pred32>0.5).astype(int)\nout_df = pd.DataFrame({\"id\":test[\"id\"].values})\nout_df['label'] = pred_test_y\nout_df.to_csv(\"submission_wikinpara.csv\", index=False)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.6.6"}},"nbformat":4,"nbformat_minor":1}