{"cells":[{"metadata":{"_uuid":"e44b2089bf0f7ef32a9c50acf230ba1e37dbc283"},"cell_type":"markdown","source":"**INTRODUCTION**\n\nThis is my first kernel on Kaggle, and I will be attempting to predict the test data using a comparison of Supervised Learning ML models.\n\nThis is largely for beginners who are keen on learning ML, and are interested to learn a methodical workflow that covers importation of libraires and data cleaning to actual modelling. \n\nSure, this is dataset done to depth on Kaggle, but if you are keen to see my approach, feel free to stay and give me an upvote.** I'll be explaining things in layman terms** so if that's what you are looking for, good for you :)"},{"metadata":{"_kg_hide-input":false,"_uuid":"b87c47d2447d4559d2c999e9a91f85ac780b3e7c"},"cell_type":"markdown","source":"**STEP 1**\n\nImport the necessary libraries into this notebook/console\n\nA notebook/console is just a place where you can type, execute and edit code. Think of it as an environment that everything else takes place in.\n\nLibraries are exactly what they mean - pre made sets of code that are readily available for use. Without libraries, you'll have to write alot more code than you do now!\n\nNotice that I also imported a dataset (ie the 'train') data to train our models. I labelled this 'df'."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load in \n\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n%matplotlib inline\ndf = pd.read_csv('../input/train.csv')\n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\n\nimport os\nprint(os.listdir(\"../input\"))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"fe3e0968b09a3649d17c58efae26637a3007cb33"},"cell_type":"code","source":"df.info()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8f578a82196df5f30138760461040b8fcf71c426"},"cell_type":"markdown","source":"**STEP 2**\n\nCheck for missing data. Looks abit complex here, but nothing to worry about. I simply used seaborn, a python visualisation library, to run a heat map on missing values. The rest of the code is for aesthetic purposes."},{"metadata":{"trusted":true,"_uuid":"afc8d7c4a0df58e83e7cc3c7ad4e50bb46bc64e5"},"cell_type":"code","source":"sns.heatmap(df.isnull(), yticklabels = False, cbar = False, cmap = 'viridis')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4e555a62f694fc28e4c049e6b38ea684048d9787"},"cell_type":"markdown","source":"It is apparent that 'Age' and 'Cabin' are missing alot of values. Let's keep this in mind while we proceed to do some Exploratory Data Analysis.\n\nThereafter, we will proceed onto Data Cleaning."},{"metadata":{"trusted":true,"_uuid":"bfae67abd1f9a1bbd3a3e0c9b933f6bb4cc74e58"},"cell_type":"markdown","source":"**STEP 3**\n\nExploratory Data Analysis (EDA)\n\nFor those of you unsure with EDA, it is just a way to visualise your training data, and look at the relationships between different variables. \n\nThis is primarily done here once again using seaborn (ie. sns)"},{"metadata":{"_kg_hide-input":false,"_kg_hide-output":false,"trusted":true,"_uuid":"ec781f8457fc554f4adeb09808657001c7e0a34f"},"cell_type":"code","source":"sns.set_style('whitegrid')\nsns.countplot(x='Survived',data=df,palette='RdBu_r')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3796c5d096a4e8440256597d3a487249d23e6b28"},"cell_type":"code","source":"sns.set_style('whitegrid')\nsns.countplot(x='Survived',hue='Sex',data=df,palette='RdBu_r')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"bb9d2c9829d2be5ac4742c63209f639923048b9a"},"cell_type":"code","source":"sns.set_style('whitegrid')\nsns.countplot(x='Survived',hue='Pclass',data=df,palette='rainbow')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c6b08ee035ef941f9282cfa398d2878000bd3eed"},"cell_type":"code","source":"df['Age'].hist(bins=30,color='darkred',alpha=0.7)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"40d879018f9469c3a9d1cd7641cb16deb97e1e46"},"cell_type":"markdown","source":"**STEP 4**\n\nData Cleaning\n\nWe will attempt to impute values into the missing age values to run our model. We do this by first associating a relationship between age and passenger class.\n\nOur boxplot shows the median age values for each passenger class.\n\nNext, we create a function to impute these median age values into the missing slots as seen on our heatmap earlier.\n\nLastly, we apply this function to the age column of the training dataframe."},{"metadata":{"trusted":true,"_uuid":"1277239b26504cd40ac0be6122f2c8eba674661d"},"cell_type":"code","source":"sns.boxplot(x='Pclass',y='Age',data=df,palette='winter')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"bcc111b2d56d612f268c3f0012d398a4ce26d4f6"},"cell_type":"code","source":"def impute_age(cols):\n    Age = cols[0]\n    Pclass = cols[1]\n    \n    if pd.isnull(Age) :\n        \n        if Pclass == 1 :\n            return 37\n        if Pclass == 2 :\n            return 29\n        else :\n            return 24\n        \n    else : \n        return Age\n    \ndf['Age'] = df[['Age','Pclass']].apply(impute_age, axis =1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2eb342c419889cdf9616410c8d0e5e765a1990c7"},"cell_type":"code","source":"sns.heatmap(df.isnull(),yticklabels=False,cbar=False,cmap='viridis')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c8797b7988c37f73c7a0c4e46be6e640278066ab"},"cell_type":"markdown","source":"As the heatmap shows, we have successfully filled up the appropriate missing values under the Age column.\n\nWe will now drop the Cabin column as it has too many missing pieces of data."},{"metadata":{"trusted":true,"_uuid":"51b5abfd78b3618316f8e8efd1864b29a93c29a0"},"cell_type":"code","source":"df.drop('Cabin',axis =1, inplace = True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c6c6b6be2ad143e25cfb9158d533d3a53b9f8570"},"cell_type":"code","source":"sns.heatmap(df.isnull(),yticklabels=False,cbar=False,cmap='viridis')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"85b870e9bfb09c2ffc2a4d5227de4774dfef6a04"},"cell_type":"markdown","source":"**STEP 5**\n\nConverting Categorical Variables into dummy variables\n\nTo put it simply, categorical variables like sex = male/ female are written in words, and very unfriendly to our ML model.Our model can't process words as training data.\n\nWe are going to convert these variables into numbers 1 & 0 for our model to process with ease."},{"metadata":{"trusted":true,"_uuid":"80e55d6a629e4dbedd1b7504cebe7b332cc1bdcc"},"cell_type":"code","source":"df.info()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"fd6a63a119c561b9cbbd61537745949a5e8609a1"},"cell_type":"code","source":"sex = pd.get_dummies(df['Sex'],drop_first=True)\nembark = pd.get_dummies(df['Embarked'],drop_first=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b1403f791924b2fea5ac9eaf2b4b5c24acad3c02"},"cell_type":"code","source":"df.drop(['Sex','Embarked','Name','Ticket'],axis=1,inplace=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7e52d8b6411fbd06abf8dfef08a56a1f9e9b57ec"},"cell_type":"code","source":"df = pd.concat([df,sex,embark],axis=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e397178c6bdcddc0b1cfde80116719f349d0681a"},"cell_type":"code","source":"df.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b69198e5775f1fb3a0e6e577be71459ac5829bd8"},"cell_type":"markdown","source":"An explanation : \n\nAs you can see, we have converted the variables 'sex' and 'embark' into dummy variables.\n\nWe have also dropped the initial columns (sex, embark, name, ticket).\n\nThis is because name and ticket are variables that intuitively do not affect survival, and they can't be converted to dummy variables as well.\n\nWe then join the newly made 'sex' and 'embark' columns (showing dummy variables) back into the dataframe. \n\n"},{"metadata":{"_uuid":"31955ab8c000cb28e4877a162e9c85ff8f274bd9"},"cell_type":"markdown","source":"**STEP 6**\n\nBuilding and executing a Logistic Regression Model.\n"},{"metadata":{"_uuid":"f58904bbdb5857abfcb578d5255dbb116dd6be57"},"cell_type":"markdown","source":"**STEP 6a. ** : Import Logistic Regression Model from Sci-Kit Learn\n\nSci-Kit Learn (aka sklearn) is a machine learning and data science library with pre-built prediction models. To code the regression formula as a full function using numpy is tedious and beyond the scope of this tutorial.\n\nRemember, the goal of our model is one of classification - to predict which class of survival passengers in the test data will fall into."},{"metadata":{"trusted":true,"_uuid":"03c5502ba6a938cafc48c1c91fc7d789c178ff1a"},"cell_type":"code","source":"from sklearn.linear_model import LogisticRegression","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"dc94d6b96b45dbb16dafcd2fad70fbabcb24f8f5"},"cell_type":"markdown","source":"**STEP 6b. ** : Train Test Split\n\nWhat this step does is split the training data given by kaggle into a training data set and a test data set internally. \n\nWe shall use this test data to gauge the predictive value of our model before we apply it to Kaggle's test data under the Titanic data set competition.\n\nThe model will then compare and find a relationship (based on logistic regression) between X_train (ie the training features) and y_train (ie the label).\n\nWe start by importing train_test_split from sklearn and then assigning examples in our current df dataframe to either 'train' or 'test' data sets for our model to run on. "},{"metadata":{"trusted":true,"_uuid":"fa4fd19a7d138c7b0f6290d196fddc610d46a66e"},"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nX_train, X_test, y_train, y_test = train_test_split(df.drop('Survived',axis=1), \n                                                    df['Survived'], test_size=0.30, \n                                                    random_state=42)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"156135cffa3bf6eb5ce2f1a95c74d7e13c12f99d"},"cell_type":"markdown","source":"Notice we has to remove the 'Survived' column from our 'X' as it is the label of the training examples, and not a feature/variable itself."},{"metadata":{"_uuid":"e9ad9e9b93f809990b2d0ac02249eaa342a9d3b8"},"cell_type":"markdown","source":"**STEP 6c. ** : Fit data into Model\n\nFirst we instantise the model as a function. This just means we can use other functions like '.fit' on it to fit our training data."},{"metadata":{"trusted":true,"_uuid":"04651566d8eac46a7039d69b62b5291dda49d2d7"},"cell_type":"code","source":"logmodel = LogisticRegression()\nlogmodel.fit(X_train, y_train)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8690dd6a9c615948800f008ee7266a5a0e0f13f5"},"cell_type":"markdown","source":"**STEP 6d. ** : Import and run predictions on test data\n\nWe shall now use the trained model above to predict the y_test values from the X_test examples and features. \n\nWe will then compare it to the true y_test labels and see how accurate our model is.\n\nRemember, the goal of our model is one of classification - to predict which class of survival passengers in the test data will fall into."},{"metadata":{"trusted":true,"_uuid":"94bc00c0b3ea09894497401fad4bf0a370375d93"},"cell_type":"code","source":"predictions = logmodel.predict(X_test)\n\nfrom sklearn import metrics\n\nfrom sklearn.metrics import confusion_matrix, classification_report\n\nprint('The accuracy of the Logistic Regression is',metrics.accuracy_score(predictions, y_test))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a87c8ea1fea77dc7f41e70af61ee0c3500930683"},"cell_type":"code","source":"print(classification_report(y_test,predictions))\nprint(confusion_matrix(y_test, predictions))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f31c62bec426f2a75fbd0ddd3f05ceaef065607a"},"cell_type":"markdown","source":"**NOT TOO SHABBY! About an 80% prediction rate. ;)**"},{"metadata":{"_uuid":"7f3cb604a617271631add515763ec29788dd0f4d"},"cell_type":"markdown","source":"**STEP 7**\n\n**Support Vector Machines (SVM)**\n\nWe shall run similar steps to STEP 6 above, but this time, importing and using SVMs in the place of Logistic Regression, to see if it has a higher predictive value. "},{"metadata":{"trusted":true,"_uuid":"5f2db262b26015687e7cc3a5119fa717215d30f3"},"cell_type":"code","source":"from sklearn.svm import SVC","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8035e31ddcd0052a394d31ac7b6306ccf84fc4ef"},"cell_type":"code","source":"SVCmodel = SVC()\nSVCmodel.fit(X_train, y_train)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"192d185a2225ab5546069ffa0fbb377060c7119a"},"cell_type":"code","source":"predictionsSVC = SVCmodel.predict(X_test)\nprint('The accuracy of the Support Vector Machine is',metrics.accuracy_score(predictionsSVC, y_test))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0e9c2bbbeb321cf37389ea1f697cc16f13dc3eb2"},"cell_type":"code","source":"print(classification_report(y_test,predictionsSVC))\nprint(confusion_matrix(y_test, predictionsSVC))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8b007074f67bfe46e1f487bc905267920765a7f8"},"cell_type":"markdown","source":"As you can see, SVM has a much lousier predictive value in this instance. This might be due to the nature of the data and its suitability to fit into SVMs.  However, before we give up, we have a few tricks up our sleeve to see if we can boost the effectivness of SVMs. \n\nWhat we are going to do is run something called a Grid Search. What this does is run through many possible combinations that make up the parameters of this SVM model, and find the most effective one. \n\nParameters are basically settings in a model that affects the model's behaviour. They are not directly a source fo data/ training example, but rather, contro lthe way the model processes data, such as prioritizing certain features over others to make a prediction. "},{"metadata":{"trusted":true,"_uuid":"2316b43c14461b7a5bc6797229f9bfd790b245f0"},"cell_type":"code","source":"param_grid = {'C': [0.1,1, 10, 100, 1000], 'gamma': [1,0.1,0.01,0.001,0.0001], 'kernel': ['rbf']}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"19ada2aeed965c5a34c437d3cbbd6dcdb96fbdc1"},"cell_type":"code","source":"from sklearn.model_selection import GridSearchCV","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"18eb8b5ae5c0e1fd4830c05719d7322bc8bb083d"},"cell_type":"code","source":"grid = GridSearchCV(SVC(),param_grid,refit=True,verbose=3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"cb92e08a68e95683398052db58d458c250f6d530"},"cell_type":"code","source":"grid.fit(X_train,y_train)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"04b51e65b1d9c4f90ca3d76cae302ab4c007b7ae"},"cell_type":"code","source":"grid.best_params_","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9a2274fe7db9dd256aed2fa08f6191cca009a970"},"cell_type":"code","source":"grid_predictions = grid.predict(X_test)\nprint('The accuracy of the Support Vector Machine with Grid Search is',metrics.accuracy_score(grid_predictions, y_test))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d58244f2f7bb1270e364320d810ecdfe02168696"},"cell_type":"code","source":"print(classification_report(y_test,grid_predictions))\nprint(confusion_matrix(y_test, grid_predictions))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"fd4606beedc7baf13b7dcbf016f820303c486b61"},"cell_type":"markdown","source":"**As you can see, predictive value has certainly increased to 75 % ! **"},{"metadata":{"_uuid":"8988781a144ed85a48f5d709d81a1e34abcb6e61"},"cell_type":"markdown","source":"**STEP 8**\n\n**K Nearest Neighbours (KNN)**\n\nFinally, we shall attempt to a KNN model on this data set and see if it yields good results. Following the same procedures as before :"},{"metadata":{"trusted":true,"_uuid":"27c3d282e93cc5a10e0fe69fde9021b6f91257b4"},"cell_type":"code","source":"from sklearn.neighbors import KNeighborsClassifier","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"553fc17d167f6867d40d7c865d8ff18c4d548eb5"},"cell_type":"code","source":"knn = KNeighborsClassifier(n_neighbors = 1)\nknn.fit(X_train,y_train)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"36babbbb84ca9cc4ec1ccea1dd438f48b7d1e198"},"cell_type":"code","source":"KNNpredictions = knn.predict(X_test)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"fb77f7e2255bdd928275a3674259fec3d26122bd"},"cell_type":"code","source":"print('The accuracy of KNN with 1 neighbor is',metrics.accuracy_score(KNNpredictions, y_test))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"11b09e51ca493cb37161c20a232f8102d69e188a"},"cell_type":"markdown","source":"Now, just like he SVM before, a poor result is not the end of the world! We can once again adjust the settings of a model (in this case the n_neighbors) to get an optimal result, \n\n**Before we proceed, do be reminded that KNN is not a parametric model! So we can't exactly call the n_neighbors a 'parameter'.**\n\nNow, let's plot a graph showing the error rate of the model against the K value (ie the n_neighbors).\n\nFrom here, we can find the K value with the lowest error rates! \n\nThis also shows the importance of visualisation when it comes to data science. "},{"metadata":{"trusted":true,"_uuid":"cfdb51dcd89d14a3b2c5518a85d2385c1564f9a7"},"cell_type":"code","source":"error_rate = []\n\nfor i in range(1,40):\n    \n    knn = KNeighborsClassifier(n_neighbors=i)\n    knn.fit(X_train,y_train)\n    pred_i = knn.predict(X_test)\n    error_rate.append(np.mean(pred_i != y_test))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"bc73a2d3ed69cf5e8e03886153c1ae309d40a702"},"cell_type":"code","source":"plt.figure(figsize=(10,6))\nplt.plot(range(1,40),error_rate,color='blue', linestyle='dashed', marker='o',\n         markerfacecolor='red', markersize=10)\nplt.title('Error Rate vs. K Value')\nplt.xlabel('K')\nplt.ylabel('Error Rate')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ac29879aff76065ace0f4159e08dc7102a5539f0"},"cell_type":"markdown","source":"**Now we see that a K value of 7 yields a low error rate. Let's use 7 in our model. **"},{"metadata":{"trusted":true,"_uuid":"76b3370b718ec5ceb4b6a0284d3e1b21bdfa4960"},"cell_type":"code","source":"knn2 = KNeighborsClassifier(n_neighbors = 7)\nknn2.fit(X_train,y_train)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5623046068663141adf977d9092bcf848a5aef85"},"cell_type":"code","source":"KNN2predictions = knn2.predict(X_test)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8e3f0be173efb05f229e537d7dc8cb68351f545d"},"cell_type":"code","source":"print('The accuracy of KNN with 7 neighbors is',metrics.accuracy_score(KNN2predictions, y_test))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2396201d962fa110fd1b5962323f67d4dbab65a0"},"cell_type":"markdown","source":"**SLIGHTLY BETTER! But nowhere near Logistic Regression ;)**"},{"metadata":{"_uuid":"0d90f4a326e6fc88d3379a35ad060d521b538383"},"cell_type":"markdown","source":"And now, it has come to the time to explain the reasons behind the results. \n\nFirst off, KNN did poorly in this instance as it is traditionally an unsupervised learning algorithm. However, because we are feeding our model labels for the training data (in the form of \"Survived\"), our problem is one suited for Supervised Learning, Simply classifying the passengers based on their features without a reference label can place emphasis on classification leaning towards other traits and group characteristics over survivability (our label).  While I have seen other kernels pull off >80% predictions with KNN, I can't seem to replicate the results.  Several sites have also shown the KNN classifier to be effective for the titanic dataset, so if anyone knows why, I would love to hear your answer.\n\nSVMs didn't do much better as well. SVMs have their foundations in a technique called the \"kernel trick\", an act of using a kernel to preserve linearity between variables and labels. However, most SVMs require further engineering of the kernel, and various techniques to choose the appropriate hyperparamters to allow for sufficient generalisation performance. \n\nIf you are interested, feel free to learn more about the various ML models here : \n\nhttp://web.mit.edu/6.034/wwwbob/svm-notes-long-08.pdf [](http://web.mit.edu/6.034/wwwbob/svm-notes-long-08.pdf)\n\nhttps://medium.com/@adi.bronshtein/a-quick-introduction-to-k-nearest-neighbors-algorithm-62214cea29c7 [](https://medium.com/@adi.bronshtein/a-quick-introduction-to-k-nearest-neighbors-algorithm-62214cea29c7)\n\nA great book to read on ML/DL from a mathematicakl perspective : \nhttps://www.deeplearningbook.org/ [](https://www.deeplearningbook.org/)\n"},{"metadata":{"_uuid":"4315d8238311e0262f091410cff231cf720fc0d4"},"cell_type":"markdown","source":"**THANKS FOR TUNING IN AND SEE YOU IN MY NEXT KERNEL! **"},{"metadata":{"trusted":true,"_uuid":"becbc081c285412f5410bfa69e4a9b0c003095ee"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c08905d28178e02c5adb5262ca2b87a9a6464b39"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3d43bd7031bc015f6d59fa1720584060c3f39400"},"cell_type":"markdown","source":""},{"metadata":{"_uuid":"cd38e8fdb6c7d861bb1287f79efcc66a06b4e401"},"cell_type":"markdown","source":""}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}