{"cells":[{"metadata":{"_uuid":"35dfe7ed52e520d178edb350512e8b4f3cc3d231","trusted":false},"cell_type":"code","source":"import warnings\nwarnings.filterwarnings('ignore')\n\nimport os\nimport json\nimport numpy as np\nimport pandas as pd\nfrom pandas.io.json import json_normalize\nimport matplotlib.pyplot as plt\n\nimport seaborn as sns\ncolor = sns.color_palette()\n\n%matplotlib inline\npd.options.mode.chained_assignment = None\npd.options.display.max_columns = 999\n\nfrom IPython.display import HTML, display\nimport tabulate\nfrom plotly import tools\nimport plotly.offline as py\npy.init_notebook_mode(connected=True)\nfrom plotly.offline import init_notebook_mode, iplot\ninit_notebook_mode(connected=True)\nimport plotly.graph_objs as go\nimport plotly.offline as offline\noffline.init_notebook_mode()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5c0d9e48dc6fd1ea7c0a3ef072525ca3eafd09ac"},"cell_type":"markdown","source":"<h3>Objective of the notebook:</h3>\n\nIn this notebook, We will \n* perform analysis on data, \n* perform missing data imputation and \n* perform simple EDA  \n\n<h3>Objective of the competition:</h3>\n\nIn this competition, we a’re challenged to analyze a Google Merchandise Store (also known as GStore, where Google swag is sold) customer dataset to predict revenue per customer."},{"metadata":{"_uuid":"c98bb488393c1810839705bf004f40df96977459"},"cell_type":"markdown","source":"<h3>File Descriptions</h3>\n\n* train.csv - the training set - contains the same data as the BigQuery rstudio_train_set.\n\n* test.csv - the test set - contains the same data as the BigQuery rstudio_test_set.\n\n<h3>Data Fields</h3>\n\n* fullVisitorId- A unique identifier for each user of the Google Merchandise Store.\n\n* channelGrouping - The channel via which the user came to the Store.\n\n* date - The date on which the user visited the Store.\n\n* device - The specifications for the device used to access the Store.\n\n* geoNetwork - This section contains information about the geography of the user.\n\n* sessionId - A unique identifier for this visit to the store.\n\n* socialEngagementType - Engagement type, either \"Socially Engaged\" or \"Not Socially Engaged\".\n\n* totals - This section contains aggregate values across the session.\n\n* trafficSource - This section contains information about the Traffic Source from which the session originated.\n\n* visitId - An identifier for this session. This is part of the value usually stored as the _utmb cookie. This is only unique to the user. For a completely unique ID, you should use a combination of fullVisitorId and visitId.\n\n* visitNumber - The session number for this user. If this is the first session, then this is set to 1.\n\n* visitStartTime - The timestamp (expressed as POSIX time).\n\n***_Credit Note_*** - Using code from [kernal Quick start: read csv and flatten json fields](https://www.kaggle.com/julian3833/1-quick-start-read-csv-and-flatten-json-fields) by [Julián Peller1](https://www.kaggle.com/julian3833)"},{"metadata":{"_uuid":"2d50751183fd6a6601d7a7e31aa727ecb8dae707","trusted":false},"cell_type":"code","source":"def load_df(csv_path='../input/train.csv', nrows=None):\n    JSON_COLUMNS = ['device', 'geoNetwork', 'totals', 'trafficSource']\n    \n    df = pd.read_csv(csv_path, \n                     converters={column: json.loads for column in JSON_COLUMNS}, \n                     dtype={'fullVisitorId': 'str'}, # Important!!\n                     nrows=nrows)\n    \n    for column in JSON_COLUMNS:\n        column_as_df = json_normalize(df[column])\n        column_as_df.columns = [f\"{column}.{subcolumn}\" for subcolumn in column_as_df.columns]\n        df = df.drop(column, axis=1).merge(column_as_df, right_index=True, left_index=True)\n    print(f\"Loaded {os.path.basename(csv_path)}. Shape: {df.shape}\")\n    return df","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e3f9380aeebe3f1b0ca444cab7ba6580cabf888c","trusted":false},"cell_type":"code","source":"%%time\ntrain_df = load_df()\ntest_df = load_df(\"../input/test.csv\")","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ec49909cb03226298f2cbba636a6ed53d060fd6f","trusted":false},"cell_type":"code","source":"print('size of training data : ', train_df.shape)\nprint('size of testing data  : ', test_df.shape)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a63e74ce8460267218413bbe0abbbe572191fb4f"},"cell_type":"markdown","source":"** Train Data snippets : **"},{"metadata":{"_uuid":"dc7b6ff9c23e59943fa52ddddfe7dd3149e73b46","trusted":false},"cell_type":"code","source":"train_df.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3e6efda5134aa7bb1e90545b3da52874d897a9dd"},"cell_type":"markdown","source":"** Train Data snippets : **"},{"metadata":{"_uuid":"c2f69387ca7c4ac6b1fd6fbe1c6a17e989d3c04d","trusted":false},"cell_type":"code","source":"test_df.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ca61757846d1e21be1e5a68fe9e12bf384f2e159"},"cell_type":"markdown","source":"<h2>Missing values assesment</h2>\n\nIn this section we will display the counts and percentage of missing value and impute the missing values using the pervious kernal [Simple Missing Data Analysis - GACRP](https://www.kaggle.com/nakapoor/simple-missing-data-analysis-gacrp)"},{"metadata":{"_uuid":"fa5302d2c4e2b8fe00e3d871fe37e07857056141"},"cell_type":"markdown","source":"<h4>Below statatistics shows that there are 8 columns with more than 97% missing values</h4>\n\nNext task is to analyse the missing attribute and try to recommnd on imputing the missing values"},{"metadata":{"_uuid":"9ab95280dac4df2bf2f3a99b0acd70e9c00a51ca","trusted":false},"cell_type":"code","source":"total = train_df.isnull().sum().sort_values(ascending = False)\npercent = (train_df.isnull().sum() / train_df.isnull().count()*100).sort_values(ascending = False)\nmissing_application_train_data  = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])\nmissing_application_train_data.head(20)\n\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0a2a6f17bd78f488cc6a378b1520c750ed325906"},"cell_type":"markdown","source":"<h3> <span style=\"color:,brown\">Feature # 1 : trafficSource.campaignCode </span></h3>\n\n*** Recomendation : ***   Removing this feature from train Dataframe."},{"metadata":{"trusted":false,"_uuid":"6bd84c117034f9ed0075e1c5ef10c2285dd1ab7a"},"cell_type":"code","source":"del train_df['trafficSource.campaignCode']","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"29e81a75777fe315f5b5c8424b67e781bca1607a"},"cell_type":"markdown","source":"<h3> <span style=\"color:,brown\"> Feature # 2 : totals.transactionRevenue : </span></h3>\n\nNow This is the Target attribute . \n\n**Recomendation : ** 5332 datapoints has valid numerical values and rest all datapoints can be populated with value 0\n"},{"metadata":{"_uuid":"ef97d5e438f87869ccca43a09befc2a2f2a28409","trusted":false},"cell_type":"code","source":"train_df['totals.transactionRevenue'].fillna(0, inplace=True)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"dbfdfc705b7b96d04a2339eaa410c1f4c8ca4cf6"},"cell_type":"markdown","source":"<h3> <span style=\"color:,brown\">Feature # 3 : trafficSource.adwordsClickInfo.page : </span></h3>\n\n*** Recomendation : *** _With my experience I never go beyond 3 / 4  pages of search results so this feature is a good candidate for binning._ therefore binning it into 3 classes 1) Missing values : -99999, 2) Ads on first page, 3) Any other class \n"},{"metadata":{"_uuid":"8aa65546a1a96ab2c3a49721dd7e7628e104828b","trusted":false},"cell_type":"code","source":"train_df['trafficSource.adwordsClickInfo.page'].fillna(-99999, inplace=True)\ntest_df['trafficSource.adwordsClickInfo.page'].fillna(-99999, inplace=True)\nprint(train_df['trafficSource.adwordsClickInfo.page'].value_counts())\nprint(test_df['trafficSource.adwordsClickInfo.page'].value_counts())","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"22623005fc08f9e9313b66f72076c561baf00b0e"},"cell_type":"markdown","source":"<h3> <span style=\"color:,brown\">Feature # 4 : trafficSource.adwordsClickInfo.adNetworkType : </span></h3>\n\n*** Recomendation : *** Binning the whole data into 2 bins ***1)*** Google Search and ***2)*** Others"},{"metadata":{"_uuid":"0f507e60c222dcf5b47ec14fcaa3b627960f1e1d","trusted":false},"cell_type":"code","source":"train_df['trafficSource.adwordsClickInfo.adNetworkType'].fillna('Others', inplace=True)\ntest_df['trafficSource.adwordsClickInfo.adNetworkType'].fillna('Others', inplace=True)\ntrain_df['trafficSource.adwordsClickInfo.adNetworkType'] = np.where(train_df['trafficSource.adwordsClickInfo.adNetworkType'] != 'Google Search' , 'Others',train_df['trafficSource.adwordsClickInfo.adNetworkType'])\ntest_df['trafficSource.adwordsClickInfo.adNetworkType'] = np.where(test_df['trafficSource.adwordsClickInfo.adNetworkType'] != 'Google Search'  , 'Others',test_df['trafficSource.adwordsClickInfo.adNetworkType'])\nprint(train_df['trafficSource.adwordsClickInfo.adNetworkType'].value_counts())\nprint(test_df['trafficSource.adwordsClickInfo.adNetworkType'].value_counts())","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"257030bed6dc59b5d63747d0830ca809507b3ccd"},"cell_type":"markdown","source":"<h3> <span style=\"color:,brown\">Feature # 5 : trafficSource.adwordsClickInfo.slot : </span></h3>\n\n*** Recomendation : ***  We can replace all NaN's and Google Display Network with unique value class."},{"metadata":{"_uuid":"311b9c06fcaf3cfe84f5273f92f52e8b2e3089a1","trusted":false},"cell_type":"code","source":"train_df['trafficSource.adwordsClickInfo.slot'].fillna('NA', inplace=True)\ntest_df['trafficSource.adwordsClickInfo.slot'].fillna('NA', inplace=True)\n#train_df['trafficSource.adwordsClickInfo.slot'] = np.where(train_df['trafficSource.adwordsClickInfo.slot'] != [\"RHS\", \"Top\"] , 'NA',train_df['trafficSource.adwordsClickInfo.slot'])\ntest_df['trafficSource.adwordsClickInfo.slot'] = np.where(test_df['trafficSource.adwordsClickInfo.slot'] ==  \"Google Display Network\" , 'NA',test_df['trafficSource.adwordsClickInfo.slot'])\nprint(train_df['trafficSource.adwordsClickInfo.slot'].value_counts())\nprint(test_df['trafficSource.adwordsClickInfo.slot'].value_counts())","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b328c8257fdeb3ceae99edce90e90c02e64589de"},"cell_type":"markdown","source":"<h3> <span style=\"color:,brown\">Feature # 6 : trafficSource.adwordsClickInfo.isVideoAd : </span></h3>\n\n***Recomendation:*** In train and test Dataframe user can replace all NaN's with True."},{"metadata":{"_uuid":"40fc47011909e9739e9f1fca7a9b53fc1b9c6dc0","trusted":false},"cell_type":"code","source":"train_df['trafficSource.adwordsClickInfo.isVideoAd'].fillna(True, inplace=True)\ntest_df['trafficSource.adwordsClickInfo.isVideoAd'].fillna(True, inplace=True)\nprint(train_df['trafficSource.adwordsClickInfo.isVideoAd'].value_counts())\nprint(test_df['trafficSource.adwordsClickInfo.isVideoAd'].value_counts())","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a291aee1479775e786777a79a5a989919f853af8"},"cell_type":"markdown","source":"<h3> <span style=\"color:,brown\"> Feature # 7 : trafficSource.isTrueDirect : </span></h3>\n\n\n\n***Recomendation:*** In train and test Dataframe user can replace all NaN's with False.\n\n"},{"metadata":{"_uuid":"64335b3fd3fb52992a0781e340fb65bb9bd72fb7","trusted":false},"cell_type":"code","source":"train_df['trafficSource.isTrueDirect'].fillna(False, inplace=True)\ntest_df['trafficSource.isTrueDirect'].fillna(False, inplace=True)\nprint(train_df['trafficSource.isTrueDirect'].value_counts())\nprint(test_df['trafficSource.isTrueDirect'].value_counts())\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"91a75982dfd097dc22d2448a66ef198748ee3c7a"},"cell_type":"markdown","source":"<h3> <span style=\"color:,brown\">Feature # 8 : totals.bounces : </span></h3>\n\n***Recomendation :***  Replace all NaN's with _0_"},{"metadata":{"_uuid":"75d5ceccf972e3f1ba30263df47745b456ff3791","trusted":false},"cell_type":"code","source":"train_df['totals.bounces'].fillna(0, inplace=True)\ntest_df['totals.bounces'].fillna(0, inplace=True)\nprint(train_df['totals.bounces'].value_counts())\nprint(test_df['totals.bounces'].value_counts())","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f88b7f5b93dc06cf349393ec4df248786f4dc26f"},"cell_type":"markdown","source":"<h3> <span style=\"color:,brown\">Feature # 9 : totals.newVisits : </span></h3>\n\n***Recomendation :*** replace all NaN's with _0_"},{"metadata":{"_uuid":"adc45259fd3dc25f57562e9880e09b79e831694a","trusted":false},"cell_type":"code","source":"train_df['totals.newVisits'].fillna(0, inplace=True)\ntest_df['totals.newVisits'].fillna(0, inplace=True)\nprint(train_df['totals.newVisits'].value_counts())\nprint(test_df['totals.newVisits'].value_counts())","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ffdccb5f1b5dd03e17aabdb2d806f89cf0e72ffd"},"cell_type":"markdown","source":"<h3> Revisiting the missing values</h3>"},{"metadata":{"trusted":false,"_uuid":"ae1ae019b7e5029790d21b5f4976e08f74a370b3"},"cell_type":"code","source":"total = train_df.isnull().sum().sort_values(ascending = False)\npercent = (train_df.isnull().sum() / train_df.isnull().count()*100).sort_values(ascending = False)\nmissing_application_train_data  = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])\nmissing_application_train_data.loc[missing_application_train_data['Percent'] > 0]\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"3e72bfddd82c44df576c7efb8da9bc8bd6c578b4"},"cell_type":"code","source":"del missing_application_train_data","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7627181829979cd58245fb2aaaef1778957b7055"},"cell_type":"markdown","source":"<h3> Pre processing and data check </h3>"},{"metadata":{"_uuid":"5403a740f9db5cd3d23019f5e56218574dcee972"},"cell_type":"markdown","source":"<h5> Remove constant features </h5>"},{"metadata":{"trusted":false,"_uuid":"a328e5f4ccccc404ebc4f68b99adffe35ea38f9a"},"cell_type":"code","source":"feats_counts = train_df.nunique(dropna = False).sort_values(ascending = False)\nvalues = feats_counts.values\ntrace1 = go.Bar(\n    x = feats_counts.index,\n    y = values ,\n)\n\ndata = [trace1]\n\nlayout = go.Layout(\n    title = \"# of unique values in each column in dataframe\",\n    xaxis=dict(\n        title='Features Names',\n        domain=[0, 0.5]\n    ),\n    \n    yaxis=dict(\n        title='# of unique constant values'\n        \n    )\n)\n\nfig = go.Figure(data=data, layout=layout)\npy.iplot(fig, filename='Campaign code')\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"de8119cf3ae46e15549711b558afc6a8f4b56bce"},"cell_type":"markdown","source":"We found that there are **19 constant features** as represented in above plot and names below in the data set. We can go ahead and remove the same for fast processing."},{"metadata":{"trusted":false,"_uuid":"14db8f0365326a5277c76e08dd32c153826e74fc"},"cell_type":"code","source":"constant_features = feats_counts.loc[feats_counts==1].index.tolist()\nprint (constant_features)\ntrain_df.drop(constant_features,axis = 1,inplace=True)\ntest_df.drop(constant_features,axis = 1,inplace=True)\ndel constant_features","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"7dc9d0b0d701d10fccc7e210a08a9b157513ee25"},"cell_type":"code","source":"feats_counts = train_df.nunique(dropna = False).sort_values(ascending = False)\nprint(feats_counts)\ndel feats_counts","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9d7c5da7d2b72d63958c5368e33a76c98b3efcab"},"cell_type":"markdown","source":"<h3>Target variable analysis</h3>"},{"metadata":{"trusted":false,"_uuid":"289d131ec98e1404352370e867b5bb097cbaa516"},"cell_type":"code","source":"train_df[\"totals.transactionRevenue\"] = train_df[\"totals.transactionRevenue\"].astype('float')\nrevnSum = train_df.groupby(\"fullVisitorId\")[\"totals.transactionRevenue\"].sum().sort_values(ascending = True).reset_index()\n#revnSum = np.log1p(revnSum['totals.transactionRevenue']/1000000)\nrevnSum = np.log1p(revnSum['totals.transactionRevenue'])\nplt.figure(figsize=(8,6))\nplt.scatter(revnSum.index, revnSum.values)\nplt.xlabel('index', fontsize=12)\nplt.ylabel('TransactionRevenue for visitors', fontsize=12)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"18a2197a0a8d65ccf2143bd8013df64f8f0e80c2"},"cell_type":"markdown","source":"We know that total # of visitors are 723803 and from the above plot we can see that there are more 70000 visitors with  transactionRevenue = 0. Lets plot the percentage of visitors having no transactionRevenue Vs transactionRevenue > 0"},{"metadata":{"trusted":false,"_uuid":"9fa41fb263d6b297c2a4d886cf1d729d9cfca8c8"},"cell_type":"code","source":"train_df['if_TransRev'] = np.where(train_df['totals.transactionRevenue'] > 0.0 , 1,0)\nfeats_counts = train_df['if_TransRev'].value_counts()\nvalues = (feats_counts/feats_counts.sum())*100\ntrace1 = go.Bar(\n    x = feats_counts.index,\n    y = values ,\n)\n\ndata = [trace1]\n\nlayout = go.Layout(\n    title = \"% of visitors with transaction vs Non transaction\",\n    xaxis=dict(\n        title='TransactionRevenue',\n        domain=[0, 0.5]\n    ),\n    \n    yaxis=dict(\n        title='% of visitors'\n        \n    )\n)\n\nfig = go.Figure(data=data, layout=layout)\npy.iplot(fig, filename='Campaign code')\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d0819b706627f1e49dc79fbbe9df997b9e33ec2c"},"cell_type":"markdown","source":"***This shows this is a highly imbalance problem.*** As visitors ***not contributing towards the revenue*** are ***98.73%*** whereas the visitors ***contributing towards the revenue*** are only ***1.27%*** . "},{"metadata":{"trusted":false,"_uuid":"9d97ae3b787d04772ae23da1dbf6848026dab783"},"cell_type":"code","source":"#train_df.to_csv(\"filterTrain_df.csv\", index=False)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7a7123cd8c9c56d767e2d3b743750270dba8c139"},"cell_type":"markdown","source":"<H3>Analysis on transactions that contributes towards revenue</h3>\n\na) Contribution of Mobile ads where customer visit is converted into revenue\n\nb) When customer made a new visit and the visit is converted into revenue\n\nc) Contribution of video Ads where customer visit is converted into revenue\n\nd) Contribution of direct visits where customer visit is converted into revenue"},{"metadata":{"trusted":false,"_uuid":"99fda65d7ddeaa9be2a1154177489271a57a92ab"},"cell_type":"code","source":"tempTrain_df = train_df[train_df['totals.transactionRevenue'] > 0.0]\ntempTrain_df['device.isMobile'] = np.where(tempTrain_df['device.isMobile'] == True , 1,0)\ntempTrain_df['totals.newVisits'] = np.where(tempTrain_df['totals.newVisits'] == True , 1,0)\ntempTrain_df['trafficSource.adwordsClickInfo.isVideoAd'] = np.where(tempTrain_df['trafficSource.adwordsClickInfo.isVideoAd'] == True , 1,0)\ntempTrain_df['trafficSource.isTrueDirect'] = np.where(tempTrain_df['trafficSource.isTrueDirect'] == True , 1,0)\ntempTrain_df['totals.bounces'] = np.where(tempTrain_df['totals.bounces'] == True , 1,0)\ntempTrain_df.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"860580eab42a5b4035f4f83cf0e55707871042f1"},"cell_type":"code","source":"def bar_chart(lables, values):\n    trace = go.Bar(\n        x=lables,\n        y=values,\n        showlegend=False,\n        marker=dict(\n            color='rgba(28,32,56,0.84)',\n        )\n    )\n    return trace\n\nfeats_counts = tempTrain_df['device.isMobile'].value_counts()\ntrace1 = bar_chart(lables = feats_counts.index, values = (feats_counts/feats_counts.sum())*100)\n\nfeats_counts = tempTrain_df['trafficSource.adwordsClickInfo.isVideoAd'].value_counts()\ntrace2 = bar_chart(lables = feats_counts.index, values = (feats_counts/feats_counts.sum())*100)\n\nfeats_counts = tempTrain_df['totals.newVisits'].value_counts()\ntrace3 = bar_chart(lables = feats_counts.index, values = (feats_counts/feats_counts.sum())*100)\n\nfeats_counts = tempTrain_df['trafficSource.isTrueDirect'].value_counts()\ntrace4 = bar_chart(lables = feats_counts.index, values = (feats_counts/feats_counts.sum())*100)\n\nfeats_counts = tempTrain_df['totals.bounces'].value_counts()\ntrace5 = bar_chart(lables = feats_counts.index, values = (feats_counts/feats_counts.sum())*100)\n\nfig = tools.make_subplots(rows=3, cols=2, vertical_spacing=0.06, \n                          subplot_titles=[\"Mobile Ads\", \"Video Ads\",\"New Visit\", \"Direct Visit\",\"if user bounced\"])\n\nfig.append_trace(trace1, 1, 1)\nfig.append_trace(trace2, 1, 2)\nfig.append_trace(trace3, 2, 1)\nfig.append_trace(trace4, 2, 2)\nfig.append_trace(trace5, 3, 1)\n\n\nfig['layout'].update(height=1200, width=800, paper_bgcolor='rgb(233,233,233)', title=\"Impact of 5 binary features on transactions with revenue\")\n\npy.iplot(fig, filename='plots_2')\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ea88f0d77af7f0de667e1df9ed37adbff084477f"},"cell_type":"markdown","source":"<h3>Snippets from the above analysis : </h3>\n\n* Only 9% of the transactions contributing to revenue are Mobile Ads.\n* ~ 96 % of the transactions contributing to revenue are Video ads.\n* Only 38% of the transactions contributing to revenue are by New visitors\n* ~ 61% of the transactions contributing to revenue are by direct visit to google Store\n* It is very obvious if user bounsed(visitors who enter the site and then leave)the transactions will not contribute to any revenue. \n\n"},{"metadata":{"trusted":false,"_uuid":"29e573269ad55f68997212f88977e37c3b8bab99"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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}