├── Coronavirus.pbix ├── neo4j_recommender ├── users_minimal_test.dat ├── ratings_minimal_test.dat └── movies_minimal_test.dat ├── Arxiv_graph ├── arxiv_df.pkl ├── arxiv_math_20220301.xlsx ├── graph-dbms-neo4j-Mar-18-2022-17-13-25.dump ├── README.md ├── display_graph.html └── Scrap Arxiv and insert to Neo4j v1.ipynb ├── online_retail ├── GDP.xlsx ├── customer_segments_RFM_country.pickle ├── customer_segments_buying_categories.pickle └── Online_retail_Combine_Segmentations.ipynb ├── topological_data_analysis └── README.md ├── clustering_example └── Outlier_example.R ├── README.md └── Markov_text_generation.ipynb /Coronavirus.pbix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpanagop/data_analytics_examples/master/Coronavirus.pbix -------------------------------------------------------------------------------- /neo4j_recommender/users_minimal_test.dat: -------------------------------------------------------------------------------- 1 | 1::F::1::10::48067 2 | 2::M::56::16::70072 3 | 3::M::25::15::55117 -------------------------------------------------------------------------------- /Arxiv_graph/arxiv_df.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpanagop/data_analytics_examples/master/Arxiv_graph/arxiv_df.pkl -------------------------------------------------------------------------------- /online_retail/GDP.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpanagop/data_analytics_examples/master/online_retail/GDP.xlsx -------------------------------------------------------------------------------- /Arxiv_graph/arxiv_math_20220301.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpanagop/data_analytics_examples/master/Arxiv_graph/arxiv_math_20220301.xlsx -------------------------------------------------------------------------------- /topological_data_analysis/README.md: -------------------------------------------------------------------------------- 1 | # Topological Data Analysis 2 | 3 | This folder contains code with examples of topological data analysis. 4 | -------------------------------------------------------------------------------- /online_retail/customer_segments_RFM_country.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpanagop/data_analytics_examples/master/online_retail/customer_segments_RFM_country.pickle -------------------------------------------------------------------------------- /Arxiv_graph/graph-dbms-neo4j-Mar-18-2022-17-13-25.dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpanagop/data_analytics_examples/master/Arxiv_graph/graph-dbms-neo4j-Mar-18-2022-17-13-25.dump -------------------------------------------------------------------------------- /online_retail/customer_segments_buying_categories.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpanagop/data_analytics_examples/master/online_retail/customer_segments_buying_categories.pickle -------------------------------------------------------------------------------- /neo4j_recommender/ratings_minimal_test.dat: -------------------------------------------------------------------------------- 1 | 1::1::5::978300760 2 | 1::2::5::978302109 3 | 1::4::3::978301968 4 | 2::1::5::978300760 5 | 2::2::5::978302109 6 | 3::1::4::978302109 7 | 3::10::5::978302109 -------------------------------------------------------------------------------- /neo4j_recommender/movies_minimal_test.dat: -------------------------------------------------------------------------------- 1 | 1::Toy Story (1995)::Animation|Children's|Comedy 2 | 2::Jumanji (1995)::Adventure|Children's|Fantasy 3 | 3::Grumpier Old Men (1995)::Comedy|Romance 4 | 4::Waiting to Exhale (1995)::Comedy|Drama 5 | 5::Father of the Bride Part II (1995)::Comedy 6 | 6::Heat (1995)::Action|Crime|Thriller 7 | 7::Sabrina (1995)::Comedy|Romance 8 | 8::Tom and Huck (1995)::Adventure|Children's 9 | 9::Sudden Death (1995)::Action 10 | 10::GoldenEye (1995)::Action|Adventure|Thriller -------------------------------------------------------------------------------- /clustering_example/Outlier_example.R: -------------------------------------------------------------------------------- 1 | ### Preample #### 2 | # Loading libraries 3 | library(ggplot2) 4 | library(cowplot) 5 | 6 | # Setting random generator seed 7 | set.seed(42) 8 | 9 | ### No Outlier #### 10 | # First cluster - cluster 0 11 | x1 = rnorm(20,0,0.5) 12 | y1 = rnorm(20,0,0.5) 13 | 14 | # Second cluster - cluster 1 15 | x2 =rnorm(20,2,0.5) 16 | y2 =rnorm(20,2,0.5) 17 | 18 | # Dataset creation 19 | d1=data.frame(x=x1,y=y1,c=rep(0,10)) 20 | d2=data.frame(x=x2,y=y2,c=rep(1,10)) 21 | d=rbind(d1,d2) 22 | 23 | # k-means 24 | d_clst=kmeans(d[,-3],2) 25 | 26 | g1 = ggplot(d)+ 27 | aes(x=x,y=y,color=c,shape=as.factor(d_clst$cluster))+geom_point()+ 28 | theme(legend.position="none")+ scale_color_gradient(low="blue", high="red") 29 | g1 30 | 31 | ### Outlier #### 32 | 33 | # Data 34 | out=data.frame(x=c(4),y=c(4),c=c(1)) 35 | d_out=rbind(d,out) 36 | #k-means 37 | d_out_clst=kmeans(d_out[,-3],2) 38 | # Plot 39 | g2 = ggplot(d_out)+ 40 | aes(x=x,y=y,color=c,shape=as.factor(d_out_clst$cluster))+geom_point()+ 41 | theme(legend.position="none")+ scale_color_gradient(low="blue", high="red") 42 | g2 43 | 44 | # Combining two graphs 45 | plot_grid(g1,g2, labels=c("No outlier", "Outlier"), ncol = 2, nrow = 1) 46 | -------------------------------------------------------------------------------- /Arxiv_graph/README.md: -------------------------------------------------------------------------------- 1 | # arXiv meatadata analysis with neo4j 2 | 3 | This folder contains Python code for: 4 | - extracting (scraping) metadata from arXiv 5 | - importing them in neo4j graph database, 6 | - perform analysis on them. 7 | 8 | In especial, 9 | * [Scrap Arxiv and insert to Neo4j v1.ipynb](https://github.com/dpanagop/data_analytics_examples/blob/master/Arxiv_graph/Scrap%20Arxiv%20and%20insert%20to%20Neo4j%20v1.ipynb) is a jupyter notebook that extracts (scraps) data from arXiv and imports them in neo4j graph database. The extracted data are alos stored in an excel file [arxiv_math_20220301.xlsx](https://github.com/dpanagop/data_analytics_examples/blob/master/Arxiv_graph/arxiv_math_20220301.xlsx) and in a pickle file [arxiv_df.pkl](https://github.com/dpanagop/data_analytics_examples/blob/master/Arxiv_graph/arxiv_df.pkl). 10 | * [Embedding v2.ipynb](https://github.com/dpanagop/data_analytics_examples/blob/master/Arxiv_graph/Embedding%20v2.ipynb) does the analysis. The main highlights, are creating a node embedding with node2vec and using the result with k-means and UMAP. In [Embedding v2-Stress.ipynb](https://github.com/dpanagop/data_analytics_examples/blob/master/Arxiv_graph/Embedding%20v2-Stress.ipynb) you can see the results of the sama analysis for a dataset of around 10k articles. 11 | * [display_graph.html](https://github.com/dpanagop/data_analytics_examples/blob/master/Arxiv_graph/display_graph.html) uses neovis.js to produce a graph the that depicts the relationship between different Mathematics subject classifications. 12 | * [graph-dbms-neo4j-Mar-18-2022-17-13-25.dump](graph-dbms-neo4j-Mar-18-2022-17-13-25.dump) is a dump of the neo4j database. 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # data_analytics_examples 2 | 3 | This repository contains code that is used for various data analysis/data science projects. In most cases, the code is related to a Medium post. 4 | 5 | - [online_retail](https://github.com/dpanagop/data_analytics_examples/tree/master/online_retail) has code related to 6 | an example of segmentation of wholesale customers. It is split into two parts. The [first part](https://towardsdatascience.com/customer-segmentation-part-i-2c5e2145e719) uses natural language processing 7 | to cluster clients based on their transactions. The [second part](https://towardsdatascience.com/customer-segmentation-part-ii-1c94bdc03de5) creates an RFM segmentation which is combined with the results of the first part. 8 | 9 | - [Coronavirus.pbix](https://github.com/dpanagop/data_analytics_examples/blob/master/Coronavirus.pbix) is a Power BI dashboard that about COVID-19. You can read more in the related 10 | [Medium post](https://dpanagop-53386.medium.com/covid-19-dashboard-with-power-bi-78caf8d16856?source=your_stories_page-------------------------------------). 11 | 12 | - [Markov_text_generation.ipynb](https://github.com/dpanagop/data_analytics_examples/blob/master/Markov_text_generation.ipynb) is a jupyter notebook that uses Markov chains to produce text. You can read more in 13 | the related [Medium article](https://towardsdatascience.com/using-a-transition-matrix-to-generate-text-in-python-c5e78495b09b?source=your_stories_page-------------------------------------). 14 | 15 | - [UMAP](https://github.com/dpanagop/data_analytics_examples/blob/master/UMAP.ipynb) is an example of Uniform Manifold Approximation and Projection (UMAP) (for details see [UMAP](https://umap-learn.readthedocs.io/en/latest/) algorithm) 16 | 17 | - [Arxiv_graph](https://github.com/dpanagop/data_analytics_examples/tree/master/Arxiv_graph) arXiv meatadata analysis with neo4j 18 | 19 | - [neo4j_recommender](https://github.com/dpanagop/data_analytics_examples/tree/master/neo4j_recommender) creation of movie recommenders with Neo4j 20 | -------------------------------------------------------------------------------- /Arxiv_graph/display_graph.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | DataViz 4 | 10 | 11 | 12 | 26 | 27 | 41 | 42 | 67 | 68 |
69 | 70 | " -------------------------------------------------------------------------------- /Arxiv_graph/Scrap Arxiv and insert to Neo4j v1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# Importing necessary libraries\n", 10 | "import requests\n", 11 | "import pandas as pd\n", 12 | "from bs4 import BeautifulSoup\n", 13 | "import re" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 190, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "# Queries\n", 23 | "# Fetch 50 articles in Mathematics from 2022-03-01 to 2022-03-07\n", 24 | "# query = 'https://arxiv.org/search/advanced?advanced=1&terms-0-operator=AND&terms-0-term=&terms-0-field=title&classification-mathematics=y&classification-physics_archives=all&classification-include_cross_list=include&date-year=&date-filter_by=date_range&date-from_date=2022-03-01&date-to_date=2022-03-07&date-date_type=submitted_date&abstracts=show&order=-announced_date_first'\n", 25 | "# Fetch 200 (this is the maximum) articles in Mathematics from 2022-03-01 to 2022-03-07\n", 26 | "query = 'https://arxiv.org/search/advanced?advanced=1&terms-0-term=&terms-0-operator=AND&terms-0-field=title&classification-mathematics=y&classification-physics_archives=all&classification-include_cross_list=include&date-filter_by=date_range&date-year=&date-from_date=2022-03-01&date-to_date=2022-03-07&date-date_type=submitted_date&abstracts=show&size=200&order=-announced_date_first'\n", 27 | "# Fetch next 200 articles in Mathematics from 2022-03-01 to 2022-03-01 (same date)\n", 28 | "# query = 'https://arxiv.org/search/advanced?advanced=&terms-0-operator=AND&terms-0-term=&terms-0-field=title&classification-mathematics=y&classification-physics_archives=all&classification-include_cross_list=include&date-filter_by=past_12&date-year=&date-from_date=2022-03-01&date-to_date=2022-03-01&date-date_type=submitted_date&abstracts=show&size=200&order=-announced_date_first&start=200'" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 191, 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "page = requests.get(query)\n", 38 | "soup = BeautifulSoup(page.content, 'html.parser')" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 248, 44 | "metadata": { 45 | "scrolled": false 46 | }, 47 | "outputs": [], 48 | "source": [ 49 | "arxiv_id_list = []\n", 50 | "title_list = []\n", 51 | "authors_list = []\n", 52 | "classification_list = []\n", 53 | "classification_detailed_list= []\n", 54 | "for article in soup.find_all('li',{'class':\"arxiv-result\"}):\n", 55 | " arxiv_id = article.find_all('p',{'class':\"list-title is-inline-block\"}) \n", 56 | " arxiv_id = arxiv_id[0].find_all('a',href=True)[0].get_text()\n", 57 | " title = article.find_all('p',{'class':\"title is-5 mathjax\"})\n", 58 | " title = title[0].get_text()\n", 59 | " title = title.strip()\n", 60 | " authors=article.find_all('p',{'class':\"authors\"})\n", 61 | " authors = [x.get_text().strip() for x in authors[0].find_all('a')]\n", 62 | " comments = article.find_all('p',{'class':\"comments is-size-7\"})\n", 63 | " classification_primary = article.find_all('span',{'class':'tag is-small is-link tooltip is-tooltip-top'})[0].attrs.get('data-tooltip')\n", 64 | " classification_secondary = article.find_all('span',{'class':'tag is-small is-grey tooltip is-tooltip-top'})\n", 65 | " if len(classification_secondary)>0:\n", 66 | " classification_secondary = classification_secondary[0].attrs.get('data-tooltip')\n", 67 | " classification = [classification_primary,classification_secondary]\n", 68 | " else:\n", 69 | " classification = [classification_primary]\n", 70 | " if len(comments)>0 :\n", 71 | " comments = comments[0].get_text()\n", 72 | " classification_detailed = re.search('MSC Class:\\n(.*)\\n',comments)\n", 73 | " if classification_detailed != None:\n", 74 | " classification_detailed = classification_detailed.group(1)\n", 75 | " classification_detailed = classification_detailed.strip().split(sep=';')\n", 76 | " else :\n", 77 | " classification_detailed = ['N/A']\n", 78 | " #print(title)\n", 79 | " #print(authors)\n", 80 | " #print(classification)\n", 81 | " #print(100*'-')\n", 82 | " arxiv_id_list.append(arxiv_id)\n", 83 | " title_list.append(title)\n", 84 | " authors_list.append(authors)\n", 85 | " classification_list.append(classification)\n", 86 | " classification_detailed_list.append(classification_detailed)" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": 250, 92 | "metadata": {}, 93 | "outputs": [], 94 | "source": [ 95 | "df = pd.DataFrame({'airxv_id':arxiv_id_list,\n", 96 | " 'title':title_list,\n", 97 | " 'authors':authors_list,\n", 98 | " 'classification':classification_list,\n", 99 | " 'classification_detailed':classification_detailed_list})" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": 251, 105 | "metadata": {}, 106 | "outputs": [ 107 | { 108 | "data": { 109 | "text/html": [ 110 | "
\n", 111 | "\n", 124 | "\n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | "
airxv_idtitleauthorsclassificationclassification_detailed
0arXiv:2203.07873Asymptotic Fermat for signatures $(p,p,2)$ and...[Diana Mocanu][Number Theory][11F80, 11G05, 11D41]
1arXiv:2203.05018Application of neural-network hybrid models in...[Chentong Li, Zhou Changsheng, Junmin Liu, Yao...[Dynamical Systems, Physics and Society][11F80, 11G05, 11D41]
2arXiv:2203.05017Asymmetric Duffing oscillator: jump manifold a...[Jan Kyzioł, Andrzej Okniński][Dynamical Systems][N/A]
3arXiv:2203.04148Numerical solution of optimal control of ather...[F. Nasresfahani, M. R. Eslahchi][Optimization and Control, Numerical Analysis][N/A]
4arXiv:2203.04145The structure of the linearizer of a connected...[Oleg Aristov][Group Theory][N/A]
\n", 178 | "
" 179 | ], 180 | "text/plain": [ 181 | " airxv_id title \\\n", 182 | "0 arXiv:2203.07873 Asymptotic Fermat for signatures $(p,p,2)$ and... \n", 183 | "1 arXiv:2203.05018 Application of neural-network hybrid models in... \n", 184 | "2 arXiv:2203.05017 Asymmetric Duffing oscillator: jump manifold a... \n", 185 | "3 arXiv:2203.04148 Numerical solution of optimal control of ather... \n", 186 | "4 arXiv:2203.04145 The structure of the linearizer of a connected... \n", 187 | "\n", 188 | " authors \\\n", 189 | "0 [Diana Mocanu] \n", 190 | "1 [Chentong Li, Zhou Changsheng, Junmin Liu, Yao... \n", 191 | "2 [Jan Kyzioł, Andrzej Okniński] \n", 192 | "3 [F. Nasresfahani, M. R. Eslahchi] \n", 193 | "4 [Oleg Aristov] \n", 194 | "\n", 195 | " classification classification_detailed \n", 196 | "0 [Number Theory] [11F80, 11G05, 11D41] \n", 197 | "1 [Dynamical Systems, Physics and Society] [11F80, 11G05, 11D41] \n", 198 | "2 [Dynamical Systems] [N/A] \n", 199 | "3 [Optimization and Control, Numerical Analysis] [N/A] \n", 200 | "4 [Group Theory] [N/A] " 201 | ] 202 | }, 203 | "execution_count": 251, 204 | "metadata": {}, 205 | "output_type": "execute_result" 206 | } 207 | ], 208 | "source": [ 209 | "df.head()" 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": 195, 215 | "metadata": {}, 216 | "outputs": [ 217 | { 218 | "data": { 219 | "text/plain": [ 220 | "200" 221 | ] 222 | }, 223 | "execution_count": 195, 224 | "metadata": {}, 225 | "output_type": "execute_result" 226 | } 227 | ], 228 | "source": [ 229 | "len(df.classification)" 230 | ] 231 | }, 232 | { 233 | "cell_type": "code", 234 | "execution_count": 196, 235 | "metadata": {}, 236 | "outputs": [], 237 | "source": [ 238 | "neo4j_data=[]\n", 239 | "for arxiv_id,title,author,classification in zip(arxiv_id_list,title_list,authors_list,classification_list):\n", 240 | " neo4j_data.append({'arxiv_id':arxiv_id,'title':title,'author':author,'classification':classification})" 241 | ] 242 | }, 243 | { 244 | "cell_type": "code", 245 | "execution_count": 197, 246 | "metadata": {}, 247 | "outputs": [], 248 | "source": [ 249 | "from neo4j import GraphDatabase\n", 250 | "host = 'bolt://localhost:7687'\n", 251 | "user = 'neo4j'\n", 252 | "password = 'arxiv'\n", 253 | "driver = GraphDatabase.driver(host,auth=(user, password))" 254 | ] 255 | }, 256 | { 257 | "cell_type": "code", 258 | "execution_count": 198, 259 | "metadata": {}, 260 | "outputs": [], 261 | "source": [ 262 | "def run_query(query, params={}):\n", 263 | " with driver.session() as session:\n", 264 | " result = session.run(query, params)\n", 265 | " return pd.DataFrame([r.values() for r in result], columns=result.keys())" 266 | ] 267 | }, 268 | { 269 | "cell_type": "code", 270 | "execution_count": 199, 271 | "metadata": {}, 272 | "outputs": [ 273 | { 274 | "data": { 275 | "text/html": [ 276 | "
\n", 277 | "\n", 290 | "\n", 291 | " \n", 292 | " \n", 293 | " \n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | "
\n", 299 | "
" 300 | ], 301 | "text/plain": [ 302 | "Empty DataFrame\n", 303 | "Columns: []\n", 304 | "Index: []" 305 | ] 306 | }, 307 | "execution_count": 199, 308 | "metadata": {}, 309 | "output_type": "execute_result" 310 | } 311 | ], 312 | "source": [ 313 | "run_query(\"CREATE CONSTRAINT IF NOT EXISTS ON (a:Article) ASSERT a.arxiv_id IS UNIQUE;\")\n", 314 | "run_query(\"CREATE CONSTRAINT IF NOT EXISTS ON (a:Author) ASSERT a.name IS UNIQUE;\")\n", 315 | "run_query(\"CREATE CONSTRAINT IF NOT EXISTS ON (a:classification) ASSERT a.name IS UNIQUE;\")" 316 | ] 317 | }, 318 | { 319 | "cell_type": "code", 320 | "execution_count": 200, 321 | "metadata": {}, 322 | "outputs": [], 323 | "source": [ 324 | "import_pubmed_query = \"\"\"\n", 325 | "UNWIND $data AS row\n", 326 | "// Store article\n", 327 | "MERGE (a:Article {arxiv_id: row.arxiv_id})\n", 328 | "SET a.title = row.title\n", 329 | "// Store authors \n", 330 | "FOREACH (author IN row.author |\n", 331 | " MERGE (au:Author {name: author})\n", 332 | " MERGE (a)<-[:AUTHORED]-(au))\n", 333 | "// Store classifications\n", 334 | "FOREACH (class IN row.classification |\n", 335 | " MERGE (cl:classification {name: class})\n", 336 | " MERGE (a)-[:BELONGS]->(cl))\n", 337 | "\"\"\"" 338 | ] 339 | }, 340 | { 341 | "cell_type": "code", 342 | "execution_count": 201, 343 | "metadata": {}, 344 | "outputs": [], 345 | "source": [ 346 | "result = run_query(import_pubmed_query, {'data': neo4j_data})" 347 | ] 348 | }, 349 | { 350 | "cell_type": "code", 351 | "execution_count": 202, 352 | "metadata": {}, 353 | "outputs": [ 354 | { 355 | "data": { 356 | "text/plain": [ 357 | "{'arxiv_id': 'arXiv:2203.07873',\n", 358 | " 'title': 'Asymptotic Fermat for signatures $(p,p,2)$ and $(p,p,3)$ over totally real fields',\n", 359 | " 'author': ['Diana Mocanu'],\n", 360 | " 'classification': ['11F80', ' 11G05', ' 11D41']}" 361 | ] 362 | }, 363 | "execution_count": 202, 364 | "metadata": {}, 365 | "output_type": "execute_result" 366 | } 367 | ], 368 | "source": [ 369 | "neo4j_data[0]" 370 | ] 371 | }, 372 | { 373 | "cell_type": "code", 374 | "execution_count": 246, 375 | "metadata": {}, 376 | "outputs": [ 377 | { 378 | "ename": "IndexError", 379 | "evalue": "list index out of range", 380 | "output_type": "error", 381 | "traceback": [ 382 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 383 | "\u001b[1;31mIndexError\u001b[0m Traceback (most recent call last)", 384 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mclassification_secondary\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0marticle\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfind_all\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'span'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m{\u001b[0m\u001b[1;34m'class'\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;34m'tag is-small is-blue tooltip is-tooltip-top'\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mattrs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'data-tooltip'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", 385 | "\u001b[1;31mIndexError\u001b[0m: list index out of range" 386 | ] 387 | } 388 | ], 389 | "source": [ 390 | " classification_secondary = article.find_all('span',{'class':'tag is-small is-blue tooltip is-tooltip-top'})[0].attrs.get('data-tooltip')" 391 | ] 392 | }, 393 | { 394 | "cell_type": "code", 395 | "execution_count": 245, 396 | "metadata": {}, 397 | "outputs": [ 398 | { 399 | "data": { 400 | "text/plain": [ 401 | "13" 402 | ] 403 | }, 404 | "execution_count": 245, 405 | "metadata": {}, 406 | "output_type": "execute_result" 407 | } 408 | ], 409 | "source": [ 410 | "len(classification_secondary)" 411 | ] 412 | }, 413 | { 414 | "cell_type": "code", 415 | "execution_count": null, 416 | "metadata": {}, 417 | "outputs": [], 418 | "source": [] 419 | } 420 | ], 421 | "metadata": { 422 | "kernelspec": { 423 | "display_name": "Python 3", 424 | "language": "python", 425 | "name": "python3" 426 | }, 427 | "language_info": { 428 | "codemirror_mode": { 429 | "name": "ipython", 430 | "version": 3 431 | }, 432 | "file_extension": ".py", 433 | "mimetype": "text/x-python", 434 | "name": "python", 435 | "nbconvert_exporter": "python", 436 | "pygments_lexer": "ipython3", 437 | "version": "3.7.4" 438 | }, 439 | "varInspector": { 440 | "cols": { 441 | "lenName": 16, 442 | "lenType": 16, 443 | "lenVar": 40 444 | }, 445 | "kernels_config": { 446 | "python": { 447 | "delete_cmd_postfix": "", 448 | "delete_cmd_prefix": "del ", 449 | "library": "var_list.py", 450 | "varRefreshCmd": "print(var_dic_list())" 451 | }, 452 | "r": { 453 | "delete_cmd_postfix": ") ", 454 | "delete_cmd_prefix": "rm(", 455 | "library": "var_list.r", 456 | "varRefreshCmd": "cat(var_dic_list()) " 457 | } 458 | }, 459 | "types_to_exclude": [ 460 | "module", 461 | "function", 462 | "builtin_function_or_method", 463 | "instance", 464 | "_Feature" 465 | ], 466 | "window_display": false 467 | } 468 | }, 469 | "nbformat": 4, 470 | "nbformat_minor": 2 471 | } 472 | -------------------------------------------------------------------------------- /Markov_text_generation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "Markov text generation.ipynb", 7 | "provenance": [], 8 | "collapsed_sections": [], 9 | "authorship_tag": "ABX9TyPlJht3NIGMzXO1rl324sIR", 10 | "include_colab_link": true 11 | }, 12 | "kernelspec": { 13 | "name": "python3", 14 | "display_name": "Python 3" 15 | } 16 | }, 17 | "cells": [ 18 | { 19 | "cell_type": "markdown", 20 | "metadata": { 21 | "id": "view-in-github", 22 | "colab_type": "text" 23 | }, 24 | "source": [ 25 | "\"Open" 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "metadata": { 31 | "id": "_p8TtM2IAeYR" 32 | }, 33 | "source": [ 34 | "# Text genaration using Markov chains\n", 35 | "\n", 36 | "This is a short notebook that demonstrates how to genrate text using a transition matrix." 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "metadata": { 42 | "id": "LDVxdQgOz6_8" 43 | }, 44 | "source": [ 45 | "# Import libraries\n", 46 | "import re\n", 47 | "from random import random, sample" 48 | ], 49 | "execution_count": null, 50 | "outputs": [] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": { 55 | "id": "aAeVkev_Cuob" 56 | }, 57 | "source": [ 58 | "The transition matrix is defined in a class.\n", 59 | "Actually, we are going to use a dictionary to create what is called a sparse matix. For example the table" 60 | ] 61 | }, 62 | { 63 | "cell_type": "markdown", 64 | "metadata": { 65 | "id": "pEtfPI7xHAnA" 66 | }, 67 | "source": [ 68 | "| | (am,a) | (am,happy) | (am,it) | (nice,thing)|\n", 69 | "| --- | --- | --- | --- | --- |\n", 70 | "| (i,am) | 1 | 2 | 0 | 0 |\n", 71 | "((a,nice) | 0 | 0 | 0 | 3|" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": { 77 | "id": "cnC4moEwHvY4" 78 | }, 79 | "source": [ 80 | "will be represented by the dictionary:\n", 81 | "\n", 82 | "```{ \"i,am\": {\"a\":1, \"happy\":2} \n", 83 | " , \"a,nice\": {\"thing\":3}\n", 84 | "}```\n", 85 | "\n", 86 | "Note that \n", 87 | "- we are not adding entries for cells with zero value\n", 88 | "- for in keys of the columns we are using only the next word \n", 89 | "\n", 90 | "PS. The careful reader will detect that we are not using probabilities in the matrix but instead a count. We will use this counts to calculate the corresponding probabilities." 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "metadata": { 96 | "id": "8M8p6-9zmYla" 97 | }, 98 | "source": [ 99 | "class TransitionMatrix:\n", 100 | " \"\"\" This is the transition matrix class.\n", 101 | "\n", 102 | " Attributes: \n", 103 | " SparseMatrix a dictionary in the form \n", 104 | " key: word_1, word_2\n", 105 | " value: dictionary in form {word:integer, word:integer}\n", 106 | " Methods:\n", 107 | " next_word: add a tripple of word_1, word_2, word_3 in SparseMatrix\n", 108 | " next_word: given a tuple word_1,word_2 generate (next) word with probapilities according to \n", 109 | " dictionary corresponding to key word_1,word_2 in SparseMatrix\n", 110 | " \"\"\"\n", 111 | " def __init__(self):\n", 112 | " self.SparseMatrix={}\n", 113 | " def add_tripple(self, word1,word2,word3):\n", 114 | " \"\"\" for a given tripple word1,word2,word3\n", 115 | " check if word1,word2 is a key of the dictrionary\n", 116 | " if true and word_3 is a key in the corresponding entry increment value of key word_3 by one\n", 117 | " if true and word_3 is not a key then add word_3 as a key with value one\n", 118 | " if word1,word2 is not a key, then add a key word_1,word_2 with value {word_3:1}\n", 119 | " \"\"\" \n", 120 | " key=word1+\",\"+word2\n", 121 | " if key in self.SparseMatrix:\n", 122 | " if word3 in self.SparseMatrix[key]:\n", 123 | " self.SparseMatrix[key][word3]=self.SparseMatrix[key][word3]+1\n", 124 | " else:\n", 125 | " self.SparseMatrix[key][word3]=1\n", 126 | " else:\n", 127 | " self.SparseMatrix[key]={word3:1}\n", 128 | " def next_word(self,word1,word2):\n", 129 | " \"\"\" generate next word for tuple word_1,word_2\n", 130 | " if word_1,word_2 is a key, then\n", 131 | " retrive the corresponding dictionary and based on it pick randomly a word\n", 132 | " see https://stackoverflow.com/questions/2570690/python-algorithm-to-randomly-select-a-key-based-on-proportionality-weight\n", 133 | " if word_1,word_2 is not a key, then select randomly from list [\".\",\"hence\",\"thus\",\"i\"]\n", 134 | " \"\"\"\n", 135 | " key=word1+\",\"+word2\n", 136 | " if key in self.SparseMatrix:\n", 137 | " count=sum(self.SparseMatrix[key].values())\n", 138 | " rand_val = count*random()\n", 139 | " total = 0\n", 140 | " for word,idx in self.SparseMatrix[key].items():\n", 141 | " total += idx\n", 142 | " if rand_val <= total:\n", 143 | " return word\n", 144 | " else:\n", 145 | " return sample([\".\",\",\",\"and\"],1)[0]" 146 | ], 147 | "execution_count": null, 148 | "outputs": [] 149 | }, 150 | { 151 | "cell_type": "markdown", 152 | "metadata": { 153 | "id": "bPTZIa-YJkoh" 154 | }, 155 | "source": [ 156 | "Example" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "metadata": { 162 | "colab": { 163 | "base_uri": "https://localhost:8080/" 164 | }, 165 | "id": "fzKtEEoCp-f0", 166 | "outputId": "edd910f7-320c-4d70-d433-5a430004cca2" 167 | }, 168 | "source": [ 169 | "# Assign classt to transitiontest and print contents\n", 170 | "transitiontest=TransitionMatrix()\n", 171 | "print(transitiontest.SparseMatrix)\n", 172 | "# Add the tripple (i,am,a) \n", 173 | "transitiontest.add_tripple(\"i\",\"am\",\"a\")\n", 174 | "print(transitiontest.SparseMatrix)\n", 175 | "# Increment count of tripple (i,am,a)\n", 176 | "transitiontest.add_tripple(\"i\",\"am\",\"a\")\n", 177 | "print(transitiontest.SparseMatrix)\n", 178 | "# Add trpple (i,am,happy)\n", 179 | "transitiontest.add_tripple(\"i\",\"am\",\"happy\")\n", 180 | "print(transitiontest.SparseMatrix)" 181 | ], 182 | "execution_count": null, 183 | "outputs": [ 184 | { 185 | "output_type": "stream", 186 | "text": [ 187 | "{}\n", 188 | "{'i,am': {'a': 1}}\n", 189 | "{'i,am': {'a': 2}}\n", 190 | "{'i,am': {'a': 2, 'happy': 1}}\n" 191 | ], 192 | "name": "stdout" 193 | } 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "metadata": { 199 | "colab": { 200 | "base_uri": "https://localhost:8080/" 201 | }, 202 | "id": "ip_918ohwInm", 203 | "outputId": "c3486c11-14f8-4e6b-858b-ecba9d2e432e" 204 | }, 205 | "source": [ 206 | "# Genrate next word\n", 207 | "print(f'Next word for \"i,am\" :{transitiontest.next_word(\"i\",\"am\")}')\n", 208 | "print(f'Next word for \"you,are\": {transitiontest.next_word(\"you\",\"are\")}. Note \"you,are\" is not contained in keys')" 209 | ], 210 | "execution_count": null, 211 | "outputs": [ 212 | { 213 | "output_type": "stream", 214 | "text": [ 215 | "Next word for \"i,am\" :happy\n", 216 | "Next word for \"you,are\": and. Note \"you,are\" is not contained in keys\n" 217 | ], 218 | "name": "stdout" 219 | } 220 | ] 221 | }, 222 | { 223 | "cell_type": "markdown", 224 | "metadata": { 225 | "id": "FLBiOA1qN0WF" 226 | }, 227 | "source": [ 228 | "## Text preprocessing\n", 229 | "We will need to preprocess the text input.\n", 230 | "Specificaly, we:\n", 231 | "- convert to lowwercase\n", 232 | "- remove special charaacters\n", 233 | "- remove extra spacing\n", 234 | "\n", 235 | "to this end, we define ```preprocess_sentence``` function" 236 | ] 237 | }, 238 | { 239 | "cell_type": "code", 240 | "metadata": { 241 | "id": "R_LoPOVZ0ddd" 242 | }, 243 | "source": [ 244 | "def preprocess_sentence(sentence):\n", 245 | " sentence=sentence.lower()\n", 246 | " sentence=re.sub(r\"[^\\w\\d.!?\\s]+\",'',sentence)\n", 247 | " sentence=re.sub('([.,!?])', r' \\1 ', sentence)\n", 248 | " sentence = re.sub('\\s{2,}', ' ', sentence)\n", 249 | " return sentence" 250 | ], 251 | "execution_count": null, 252 | "outputs": [] 253 | }, 254 | { 255 | "cell_type": "markdown", 256 | "metadata": { 257 | "id": "lHH8Wi2ZPbKF" 258 | }, 259 | "source": [ 260 | "For creating the matrix, we are going to use texts from [Gutenberg Project](www.gutenberg.org)." 261 | ] 262 | }, 263 | { 264 | "cell_type": "code", 265 | "metadata": { 266 | "colab": { 267 | "base_uri": "https://localhost:8080/" 268 | }, 269 | "id": "yilIVwVuKZ0B", 270 | "outputId": "4fe1c4d4-351c-403a-925f-5407894584bb" 271 | }, 272 | "source": [ 273 | "!wget http://www.gutenberg.org/cache/epub/28/pg28.txt #Aesop's Fables, by Aesop\n", 274 | "!wget https://www.gutenberg.org/files/1727/1727-0.txt #The Odyssey, by Homer\n", 275 | "!wget http://www.gutenberg.org/files/6130/6130-0.txt #The Iliad, by Homer" 276 | ], 277 | "execution_count": null, 278 | "outputs": [ 279 | { 280 | "output_type": "stream", 281 | "text": [ 282 | "--2020-12-05 05:24:55-- http://www.gutenberg.org/cache/epub/28/pg28.txt\n", 283 | "Resolving www.gutenberg.org (www.gutenberg.org)... 152.19.134.47, 2610:28:3090:3000:0:bad:cafe:47\n", 284 | "Connecting to www.gutenberg.org (www.gutenberg.org)|152.19.134.47|:80... connected.\n", 285 | "HTTP request sent, awaiting response... 200 OK\n", 286 | "Length: 86418 (84K) [text/plain]\n", 287 | "Saving to: ‘pg28.txt.1’\n", 288 | "\n", 289 | "pg28.txt.1 100%[===================>] 84.39K 310KB/s in 0.3s \n", 290 | "\n", 291 | "2020-12-05 05:24:55 (310 KB/s) - ‘pg28.txt.1’ saved [86418/86418]\n", 292 | "\n", 293 | "--2020-12-05 05:24:55-- https://www.gutenberg.org/files/1727/1727-0.txt\n", 294 | "Resolving www.gutenberg.org (www.gutenberg.org)... 152.19.134.47, 2610:28:3090:3000:0:bad:cafe:47\n", 295 | "Connecting to www.gutenberg.org (www.gutenberg.org)|152.19.134.47|:443... connected.\n", 296 | "HTTP request sent, awaiting response... 200 OK\n", 297 | "Length: 718181 (701K) [text/plain]\n", 298 | "Saving to: ‘1727-0.txt.1’\n", 299 | "\n", 300 | "1727-0.txt.1 100%[===================>] 701.35K 672KB/s in 1.0s \n", 301 | "\n", 302 | "2020-12-05 05:24:57 (672 KB/s) - ‘1727-0.txt.1’ saved [718181/718181]\n", 303 | "\n", 304 | "--2020-12-05 05:24:57-- http://www.gutenberg.org/files/6130/6130-0.txt\n", 305 | "Resolving www.gutenberg.org (www.gutenberg.org)... 152.19.134.47, 2610:28:3090:3000:0:bad:cafe:47\n", 306 | "Connecting to www.gutenberg.org (www.gutenberg.org)|152.19.134.47|:80... connected.\n", 307 | "HTTP request sent, awaiting response... 200 OK\n", 308 | "Length: 1161898 (1.1M) [text/plain]\n", 309 | "Saving to: ‘6130-0.txt.1’\n", 310 | "\n", 311 | "6130-0.txt.1 100%[===================>] 1.11M 968KB/s in 1.2s \n", 312 | "\n", 313 | "2020-12-05 05:24:58 (968 KB/s) - ‘6130-0.txt.1’ saved [1161898/1161898]\n", 314 | "\n" 315 | ], 316 | "name": "stdout" 317 | } 318 | ] 319 | }, 320 | { 321 | "cell_type": "code", 322 | "metadata": { 323 | "colab": { 324 | "base_uri": "https://localhost:8080/" 325 | }, 326 | "id": "KN0yEiMHVekw", 327 | "outputId": "6177a0a1-c6ef-4669-99ba-317764352779" 328 | }, 329 | "source": [ 330 | "#Assign class TransitionMatrix to markov_matrix\n", 331 | "Greeks_matrix=TransitionMatrix()\n", 332 | "Greeks=['pg28.txt','1727-0.txt','6130-0.txt']\n", 333 | "for FileName in Greeks:\n", 334 | " print(f'Processing {FileName}')\n", 335 | " # Open file\n", 336 | " with open(FileName) as f:\n", 337 | " content = f.readlines()\n", 338 | " #remove whitespace characters like `\\n` at the end of each line\n", 339 | " content = [x.strip() for x in content]\n", 340 | " content = [x.strip() for x in content if x!=\"\"]\n", 341 | " # Process file\n", 342 | " for text in content:\n", 343 | " doc=preprocess_sentence(text)\n", 344 | " doc=doc.split()\n", 345 | " l=len(doc)\n", 346 | " for i in range(2,l):\n", 347 | " Greeks_matrix.add_tripple(doc[i-2],doc[i-1],doc[i])" 348 | ], 349 | "execution_count": null, 350 | "outputs": [ 351 | { 352 | "output_type": "stream", 353 | "text": [ 354 | "Processing pg28.txt\n", 355 | "Processing 1727-0.txt\n", 356 | "Processing 6130-0.txt\n" 357 | ], 358 | "name": "stdout" 359 | } 360 | ] 361 | }, 362 | { 363 | "cell_type": "markdown", 364 | "metadata": { 365 | "id": "oqaJnnikSCfM" 366 | }, 367 | "source": [ 368 | "Finally, generate text" 369 | ] 370 | }, 371 | { 372 | "cell_type": "code", 373 | "metadata": { 374 | "colab": { 375 | "base_uri": "https://localhost:8080/" 376 | }, 377 | "id": "HQRUCzzfO18N", 378 | "outputId": "a818874c-03aa-4869-aa8b-9cb03ba6eb30" 379 | }, 380 | "source": [ 381 | "word1=\"it\"\n", 382 | "word2=\"is\"\n", 383 | "story=word1+\" \"+word2\n", 384 | "for i in range(50):\n", 385 | " new_word=Greeks_matrix.next_word(word1,word2)\n", 386 | " story=story+\" \"+new_word\n", 387 | " if new_word==\".\":\n", 388 | " print(story)\n", 389 | " story=\"\"\n", 390 | " word1=word2\n", 391 | " word2=new_word\n", 392 | "print(story)" 393 | ], 394 | "execution_count": null, 395 | "outputs": [ 396 | { 397 | "output_type": "stream", 398 | "text": [ 399 | "it is enchanted and you can easily find another seat near telemachus he said to her ships and shelters there .\n", 400 | " the writer as stretching all and you do or cause to fight for the soil .\n", 401 | " he fenced the raft .\n", 402 | " at last they shall have plenty of it but by\n" 403 | ], 404 | "name": "stdout" 405 | } 406 | ] 407 | }, 408 | { 409 | "cell_type": "code", 410 | "metadata": { 411 | "colab": { 412 | "base_uri": "https://localhost:8080/" 413 | }, 414 | "id": "ENX3sUhBSn3P", 415 | "outputId": "3470fdeb-ec1e-49fa-c4ee-a81eb4f6c20e" 416 | }, 417 | "source": [ 418 | "!wget http://www.gutenberg.org/files/2600/2600-0.txt #War and Peace, by Leo Tolstoy\n", 419 | "!wget http://www.gutenberg.org/files/1399/1399-0.txt #Anna Karenina, by Leo Tolstoy\n", 420 | "!wget http://www.gutenberg.org/cache/epub/4761/pg4761.txt #The Cossacks, by Leo Tolstoy" 421 | ], 422 | "execution_count": null, 423 | "outputs": [ 424 | { 425 | "output_type": "stream", 426 | "text": [ 427 | "--2020-12-05 05:25:20-- http://www.gutenberg.org/files/2600/2600-0.txt\n", 428 | "Resolving www.gutenberg.org (www.gutenberg.org)... 152.19.134.47, 2610:28:3090:3000:0:bad:cafe:47\n", 429 | "Connecting to www.gutenberg.org (www.gutenberg.org)|152.19.134.47|:80... connected.\n", 430 | "HTTP request sent, awaiting response... 200 OK\n", 431 | "Length: 3359584 (3.2M) [text/plain]\n", 432 | "Saving to: ‘2600-0.txt.2’\n", 433 | "\n", 434 | "2600-0.txt.2 100%[===================>] 3.20M 1.99MB/s in 1.6s \n", 435 | "\n", 436 | "2020-12-05 05:25:22 (1.99 MB/s) - ‘2600-0.txt.2’ saved [3359584/3359584]\n", 437 | "\n", 438 | "--2020-12-05 05:25:22-- http://www.gutenberg.org/files/1399/1399-0.txt\n", 439 | "Resolving www.gutenberg.org (www.gutenberg.org)... 152.19.134.47, 2610:28:3090:3000:0:bad:cafe:47\n", 440 | "Connecting to www.gutenberg.org (www.gutenberg.org)|152.19.134.47|:80... connected.\n", 441 | "HTTP request sent, awaiting response... 200 OK\n", 442 | "Length: 2068079 (2.0M) [text/plain]\n", 443 | "Saving to: ‘1399-0.txt.2’\n", 444 | "\n", 445 | "1399-0.txt.2 100%[===================>] 1.97M 1.30MB/s in 1.5s \n", 446 | "\n", 447 | "2020-12-05 05:25:24 (1.30 MB/s) - ‘1399-0.txt.2’ saved [2068079/2068079]\n", 448 | "\n", 449 | "--2020-12-05 05:25:24-- http://www.gutenberg.org/cache/epub/4761/pg4761.txt\n", 450 | "Resolving www.gutenberg.org (www.gutenberg.org)... 152.19.134.47, 2610:28:3090:3000:0:bad:cafe:47\n", 451 | "Connecting to www.gutenberg.org (www.gutenberg.org)|152.19.134.47|:80... connected.\n", 452 | "HTTP request sent, awaiting response... 200 OK\n", 453 | "Length: 370896 (362K) [text/plain]\n", 454 | "Saving to: ‘pg4761.txt.2’\n", 455 | "\n", 456 | "pg4761.txt.2 100%[===================>] 362.20K 492KB/s in 0.7s \n", 457 | "\n", 458 | "2020-12-05 05:25:25 (492 KB/s) - ‘pg4761.txt.2’ saved [370896/370896]\n", 459 | "\n" 460 | ], 461 | "name": "stdout" 462 | } 463 | ] 464 | }, 465 | { 466 | "cell_type": "code", 467 | "metadata": { 468 | "colab": { 469 | "base_uri": "https://localhost:8080/" 470 | }, 471 | "id": "59r5gk7pUsSw", 472 | "outputId": "86257cbd-c405-46d5-b3e6-0f29598102ce" 473 | }, 474 | "source": [ 475 | "#Assign class TransitionMatrix to markov_matrix\n", 476 | "Tolstoy_matrix=TransitionMatrix()\n", 477 | "Tolstoy=['2600-0.txt','1399-0.txt','pg4761.txt']\n", 478 | "for FileName in Tolstoy:\n", 479 | " print(f'Processing {FileName}')\n", 480 | " # Open file\n", 481 | " with open(FileName) as f:\n", 482 | " content = f.readlines()\n", 483 | " #remove whitespace characters like `\\n` at the end of each line\n", 484 | " content = [x.strip() for x in content]\n", 485 | " content = [x.strip() for x in content if x!=\"\"]\n", 486 | " # Process file\n", 487 | " for text in content:\n", 488 | " doc=preprocess_sentence(text)\n", 489 | " doc=doc.split()\n", 490 | " l=len(doc)\n", 491 | " for i in range(2,l):\n", 492 | " Tolstoy_matrix.add_tripple(doc[i-2],doc[i-1],doc[i])" 493 | ], 494 | "execution_count": null, 495 | "outputs": [ 496 | { 497 | "output_type": "stream", 498 | "text": [ 499 | "Processing 2600-0.txt\n", 500 | "Processing 1399-0.txt\n", 501 | "Processing pg4761.txt\n" 502 | ], 503 | "name": "stdout" 504 | } 505 | ] 506 | }, 507 | { 508 | "cell_type": "code", 509 | "metadata": { 510 | "colab": { 511 | "base_uri": "https://localhost:8080/" 512 | }, 513 | "id": "nlt60GI9Wjcj", 514 | "outputId": "2c785278-5a02-44d0-d467-55ea6ba77e20" 515 | }, 516 | "source": [ 517 | "word1=\"it\"\n", 518 | "word2=\"is\"\n", 519 | "story=word1+\" \"+word2\n", 520 | "for i in range(50):\n", 521 | " new_word=Tolstoy_matrix.next_word(word1,word2)\n", 522 | " story=story+\" \"+new_word\n", 523 | " if new_word==\".\":\n", 524 | " print(story)\n", 525 | " story=\"\"\n", 526 | " word1=word2\n", 527 | " word2=new_word\n", 528 | "print(story)" 529 | ], 530 | "execution_count": null, 531 | "outputs": [ 532 | { 533 | "output_type": "stream", 534 | "text": [ 535 | "it is really ended ? i am an exception .\n", 536 | " .\n", 537 | " but being with nature seeing her patient smiling face and rigid .\n", 538 | " only when they came to a longstanding impression related to the war of 1815 alexander possesses all .\n", 539 | " he could not make out something black .\n", 540 | " pierre received one\n" 541 | ], 542 | "name": "stdout" 543 | } 544 | ] 545 | } 546 | ] 547 | } -------------------------------------------------------------------------------- /online_retail/Online_retail_Combine_Segmentations.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "Online retail - Combine Segmentations.ipynb", 7 | "provenance": [], 8 | "collapsed_sections": [], 9 | "toc_visible": true, 10 | "authorship_tag": "ABX9TyM1c326tjXQeQKeoNdo9kXk", 11 | "include_colab_link": true 12 | }, 13 | "kernelspec": { 14 | "name": "python3", 15 | "display_name": "Python 3" 16 | } 17 | }, 18 | "cells": [ 19 | { 20 | "cell_type": "markdown", 21 | "metadata": { 22 | "id": "view-in-github", 23 | "colab_type": "text" 24 | }, 25 | "source": [ 26 | "\"Open" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": { 32 | "id": "vMgo0NvkNM1C" 33 | }, 34 | "source": [ 35 | "# Customer Segmentaion of online retail customers\r\n", 36 | "## Part III - Combine Segmentations" 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "metadata": { 42 | "id": "JJosaWskQR6X" 43 | }, 44 | "source": [ 45 | "## Introduction\r\n", 46 | "In this notebook wecombine the two customer segmentations of online retail customers dataset ( [Online Retail II Data Set](https://archive.ics.uci.edu/ml/datasets/Online+Retail+II) from UC Irvine Machine Learning Repository)\r\n", 47 | "\r\n", 48 | "Specifiacally, we combine\r\n", 49 | "* Customer [segmentation by category](https://github.com/dpanagop/data_analytics_examples/blob/master/online_retail/Online_retail_Segmentation_by_buying_category.ipynb) of bought items description and\r\n", 50 | "* Customer [segmentation by RFM and country](https://github.com/dpanagop/data_analytics_examples/blob/master/online_retail/Online_retail_Segmentation_by_RFM_Country.ipynb)." 51 | ] 52 | }, 53 | { 54 | "cell_type": "markdown", 55 | "metadata": { 56 | "id": "JqY04x3ePHbb" 57 | }, 58 | "source": [ 59 | "## Loading libraries and results of segmentations\r\n" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "metadata": { 65 | "id": "SQd4r1DQ23sa" 66 | }, 67 | "source": [ 68 | "import pandas as pd\r\n", 69 | "import numpy as np\r\n", 70 | "import matplotlib.pyplot as plt\r\n", 71 | "import seaborn as sns\r\n", 72 | "sns.set_style(\"whitegrid\")" 73 | ], 74 | "execution_count": 1, 75 | "outputs": [] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "metadata": { 80 | "colab": { 81 | "base_uri": "https://localhost:8080/" 82 | }, 83 | "id": "19vwadc-9Aw1", 84 | "outputId": "82657cff-6208-4f9a-bd84-e1dad2d54599" 85 | }, 86 | "source": [ 87 | "!wget github.com/dpanagop/data_analytics_examples/raw/master/online_retail/customer_segments_RFM_country.pickle\r\n", 88 | "!wget github.com/dpanagop/data_analytics_examples/raw/master/online_retail/customer_segments_buying_categories.pickle" 89 | ], 90 | "execution_count": 2, 91 | "outputs": [ 92 | { 93 | "output_type": "stream", 94 | "text": [ 95 | "--2021-01-14 03:36:11-- http://github.com/dpanagop/data_analytics_examples/raw/master/online_retail/customer_segments_RFM_country.pickle\n", 96 | "Resolving github.com (github.com)... 140.82.114.3\n", 97 | "Connecting to github.com (github.com)|140.82.114.3|:80... connected.\n", 98 | "HTTP request sent, awaiting response... 301 Moved Permanently\n", 99 | "Location: https://github.com/dpanagop/data_analytics_examples/raw/master/online_retail/customer_segments_RFM_country.pickle [following]\n", 100 | "--2021-01-14 03:36:11-- https://github.com/dpanagop/data_analytics_examples/raw/master/online_retail/customer_segments_RFM_country.pickle\n", 101 | "Connecting to github.com (github.com)|140.82.114.3|:443... connected.\n", 102 | "HTTP request sent, awaiting response... 302 Found\n", 103 | "Location: https://raw.githubusercontent.com/dpanagop/data_analytics_examples/master/online_retail/customer_segments_RFM_country.pickle [following]\n", 104 | "--2021-01-14 03:36:11-- https://raw.githubusercontent.com/dpanagop/data_analytics_examples/master/online_retail/customer_segments_RFM_country.pickle\n", 105 | "Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...\n", 106 | "Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... connected.\n", 107 | "HTTP request sent, awaiting response... 200 OK\n", 108 | "Length: 262528 (256K) [application/octet-stream]\n", 109 | "Saving to: ‘customer_segments_RFM_country.pickle’\n", 110 | "\n", 111 | "customer_segments_R 100%[===================>] 256.38K --.-KB/s in 0.03s \n", 112 | "\n", 113 | "2021-01-14 03:36:11 (7.96 MB/s) - ‘customer_segments_RFM_country.pickle’ saved [262528/262528]\n", 114 | "\n", 115 | "URL transformed to HTTPS due to an HSTS policy\n", 116 | "--2021-01-14 03:36:12-- https://github.com/dpanagop/data_analytics_examples/raw/master/online_retail/customer_segments_buying_categories.pickle\n", 117 | "Resolving github.com (github.com)... 140.82.112.4\n", 118 | "Connecting to github.com (github.com)|140.82.112.4|:443... connected.\n", 119 | "HTTP request sent, awaiting response... 302 Found\n", 120 | "Location: https://raw.githubusercontent.com/dpanagop/data_analytics_examples/master/online_retail/customer_segments_buying_categories.pickle [following]\n", 121 | "--2021-01-14 03:36:12-- https://raw.githubusercontent.com/dpanagop/data_analytics_examples/master/online_retail/customer_segments_buying_categories.pickle\n", 122 | "Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...\n", 123 | "Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... connected.\n", 124 | "HTTP request sent, awaiting response... 200 OK\n", 125 | "Length: 262338 (256K) [application/octet-stream]\n", 126 | "Saving to: ‘customer_segments_buying_categories.pickle’\n", 127 | "\n", 128 | "customer_segments_b 100%[===================>] 256.19K --.-KB/s in 0.03s \n", 129 | "\n", 130 | "2021-01-14 03:36:12 (8.23 MB/s) - ‘customer_segments_buying_categories.pickle’ saved [262338/262338]\n", 131 | "\n" 132 | ], 133 | "name": "stdout" 134 | } 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "metadata": { 140 | "id": "cwZSxK9P3PM0", 141 | "colab": { 142 | "base_uri": "https://localhost:8080/", 143 | "height": 206 144 | }, 145 | "outputId": "f2f2822d-6489-455e-ff23-4db823c5d0c7" 146 | }, 147 | "source": [ 148 | "customer_spending_per_category=pd.read_pickle('customer_segments_buying_categories.pickle')\r\n", 149 | "customer_spending_per_category.head()" 150 | ], 151 | "execution_count": 3, 152 | "outputs": [ 153 | { 154 | "output_type": "execute_result", 155 | "data": { 156 | "text/html": [ 157 | "
\n", 158 | "\n", 171 | "\n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | " \n", 179 | " \n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | " \n", 212 | " \n", 213 | " \n", 214 | " \n", 215 | " \n", 216 | " \n", 217 | " \n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | "
categoryCustomer ID0123cluster
012346.00.8417160.0000000.1582840.0000001
112347.00.8539720.1012900.0041680.0405691
212348.00.9102700.0000000.0466480.0430821
312349.00.9249070.0084460.0023160.0643311
412350.00.9389950.0610050.0000000.0000001
\n", 231 | "
" 232 | ], 233 | "text/plain": [ 234 | "category Customer ID 0 1 2 3 cluster\n", 235 | "0 12346.0 0.841716 0.000000 0.158284 0.000000 1\n", 236 | "1 12347.0 0.853972 0.101290 0.004168 0.040569 1\n", 237 | "2 12348.0 0.910270 0.000000 0.046648 0.043082 1\n", 238 | "3 12349.0 0.924907 0.008446 0.002316 0.064331 1\n", 239 | "4 12350.0 0.938995 0.061005 0.000000 0.000000 1" 240 | ] 241 | }, 242 | "metadata": { 243 | "tags": [] 244 | }, 245 | "execution_count": 3 246 | } 247 | ] 248 | }, 249 | { 250 | "cell_type": "code", 251 | "metadata": { 252 | "colab": { 253 | "base_uri": "https://localhost:8080/", 254 | "height": 238 255 | }, 256 | "id": "Z5MVReoK_Cff", 257 | "outputId": "3d50340d-cbf6-4fe1-f8af-3a4c49fbfb4a" 258 | }, 259 | "source": [ 260 | "customer_RFM_GDP=pd.read_pickle('customer_segments_RFM_country.pickle')\r\n", 261 | "customer_RFM_GDP.head()" 262 | ], 263 | "execution_count": 4, 264 | "outputs": [ 265 | { 266 | "output_type": "execute_result", 267 | "data": { 268 | "text/html": [ 269 | "
\n", 270 | "\n", 283 | "\n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | " \n", 291 | " \n", 292 | " \n", 293 | " \n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | " \n", 299 | " \n", 300 | " \n", 301 | " \n", 302 | " \n", 303 | " \n", 304 | " \n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | " \n", 330 | " \n", 331 | " \n", 332 | " \n", 333 | " \n", 334 | " \n", 335 | " \n", 336 | " \n", 337 | " \n", 338 | " \n", 339 | " \n", 340 | " \n", 341 | " \n", 342 | " \n", 343 | " \n", 344 | "
recencyfrequencymonetary_valueweighted GDPcluster
Customer ID
12346.032542.647059-3.8047062638296.00
12347.0150.375000704.16500020805.05
12348.07487.400000403.880000267856.05
12349.018147.000000880.9080001848222.02
12350.0309309.000000334.400000366386.05
\n", 345 | "
" 346 | ], 347 | "text/plain": [ 348 | " recency frequency monetary_value weighted GDP cluster\n", 349 | "Customer ID \n", 350 | "12346.0 325 42.647059 -3.804706 2638296.0 0\n", 351 | "12347.0 1 50.375000 704.165000 20805.0 5\n", 352 | "12348.0 74 87.400000 403.880000 267856.0 5\n", 353 | "12349.0 18 147.000000 880.908000 1848222.0 2\n", 354 | "12350.0 309 309.000000 334.400000 366386.0 5" 355 | ] 356 | }, 357 | "metadata": { 358 | "tags": [] 359 | }, 360 | "execution_count": 4 361 | } 362 | ] 363 | }, 364 | { 365 | "cell_type": "markdown", 366 | "metadata": { 367 | "id": "_6GYpW2j_UXE" 368 | }, 369 | "source": [ 370 | "As said in [Part I](https://github.com/dpanagop/data_analytics_examples/blob/master/online_retail/Online_retail_Segmentation_by_buying_category.ipynb), clustering based on categories spending resulted infour clusters with all of them having a high percentage of spending in category 0. In addition:\r\n", 371 | "* cluster 0 has customers with high spending in category 2,\r\n", 372 | "* cluster 1 has high spending only in category 0,\r\n", 373 | "* cluster 2 has customers with high spending in category 3,\r\n", 374 | "* cluster 3 has customers with high spending in category 1.\r\n", 375 | "\r\n" 376 | ] 377 | }, 378 | { 379 | "cell_type": "code", 380 | "metadata": { 381 | "colab": { 382 | "base_uri": "https://localhost:8080/", 383 | "height": 426 384 | }, 385 | "id": "kG8PDBIa7KO_", 386 | "outputId": "c3c359a7-adcc-458c-d3ce-fd8e06c80977" 387 | }, 388 | "source": [ 389 | "def cluster_profile(customer_spending_per_category):\r\n", 390 | " ''' profile clusters '''\r\n", 391 | " customer_clusters=customer_spending_per_category.groupby(['cluster']).agg({'Customer ID':['count'], \r\n", 392 | " 0:'median',\r\n", 393 | " 1:'median',\r\n", 394 | " 2:'median',\r\n", 395 | " 3:'median'})\r\n", 396 | " print(customer_clusters)\r\n", 397 | " print('\\n')\r\n", 398 | " customer_clusters=customer_clusters.drop([('Customer ID', 'count')],1)\r\n", 399 | " customer_clusters.columns=[0,1,2,3]\r\n", 400 | " \r\n", 401 | " customer_clusters[0]=100*customer_clusters[0]\r\n", 402 | " customer_clusters[1]=100*customer_clusters[1]\r\n", 403 | " customer_clusters[2]=100*customer_clusters[2]\r\n", 404 | " customer_clusters[3]=100*customer_clusters[3]\r\n", 405 | " \r\n", 406 | "\r\n", 407 | " sns.heatmap(customer_clusters, annot=True, linewidths=.5)\r\n", 408 | "\r\n", 409 | "cluster_profile(customer_spending_per_category)" 410 | ], 411 | "execution_count": 5, 412 | "outputs": [ 413 | { 414 | "output_type": "stream", 415 | "text": [ 416 | " Customer ID 0 1 2 3\n", 417 | " count median median median median\n", 418 | "cluster \n", 419 | "0 421 0.670152 0.007819 0.228504 0.043079\n", 420 | "1 4287 0.892189 0.015741 0.001038 0.031568\n", 421 | "2 807 0.672202 0.005246 0.017402 0.246114\n", 422 | "3 427 0.534162 0.362365 0.000000 0.009505\n", 423 | "\n", 424 | "\n" 425 | ], 426 | "name": "stdout" 427 | }, 428 | { 429 | "output_type": "display_data", 430 | "data": { 431 | "image/png": "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\n", 432 | "text/plain": [ 433 | "
" 434 | ] 435 | }, 436 | "metadata": { 437 | "tags": [], 438 | "needs_background": "light" 439 | } 440 | } 441 | ] 442 | }, 443 | { 444 | "cell_type": "code", 445 | "metadata": { 446 | "colab": { 447 | "base_uri": "https://localhost:8080/" 448 | }, 449 | "id": "iOGu1o2b_O9H", 450 | "outputId": "4a30b057-ea03-4212-9ced-d1dbdcce25e4" 451 | }, 452 | "source": [ 453 | "customer_spending_per_category['cluster'].value_counts()" 454 | ], 455 | "execution_count": 6, 456 | "outputs": [ 457 | { 458 | "output_type": "execute_result", 459 | "data": { 460 | "text/plain": [ 461 | "1 4287\n", 462 | "2 807\n", 463 | "3 427\n", 464 | "0 421\n", 465 | "Name: cluster, dtype: int64" 466 | ] 467 | }, 468 | "metadata": { 469 | "tags": [] 470 | }, 471 | "execution_count": 6 472 | } 473 | ] 474 | }, 475 | { 476 | "cell_type": "markdown", 477 | "metadata": { 478 | "id": "O3A-9wA3ALY4" 479 | }, 480 | "source": [ 481 | "As for RFM-Country clustering from [Part II](https://github.com/dpanagop/data_analytics_examples/blob/master/online_retail/Online_retail_Segmentation_by_RFM_Country.ipynb), we have four major clusters that can be ranked by RFM score (from best to to worst) as:\r\n", 482 | "\r\n", 483 | "cluster 4 > cluster 0 > cluster 5 > cluster 2\r\n", 484 | "\r\n", 485 | "and that cluster 5 has customers from countries with lower GDP than the rest.\r\n", 486 | "Thus, we will keep these four clusters plus one more into which we will merge the rest." 487 | ] 488 | }, 489 | { 490 | "cell_type": "code", 491 | "metadata": { 492 | "colab": { 493 | "base_uri": "https://localhost:8080/", 494 | "height": 748 495 | }, 496 | "id": "njWvI3bc9gd_", 497 | "outputId": "3bbc8040-7069-461f-89c1-8e26868e77e5" 498 | }, 499 | "source": [ 500 | "def cluster_profile_RFM_country(customer_clustering,cut_off=0):\r\n", 501 | " ''' profile clusters with size equal or bigger than cut_off'''\r\n", 502 | "\r\n", 503 | " customer_clusters=customer_clustering.reset_index().groupby(['cluster']).agg({'Customer ID':['count'], \r\n", 504 | " 'recency':'median',\r\n", 505 | " 'frequency':'median',\r\n", 506 | " 'monetary_value':'median',\r\n", 507 | " 'weighted GDP':'median'})\r\n", 508 | " idx= customer_clusters['Customer ID']>=cut_off\r\n", 509 | " idx=idx['count'].to_list()\r\n", 510 | " customer_clusters=customer_clusters[idx]\r\n", 511 | " print(customer_clusters)\r\n", 512 | " print('\\n')\r\n", 513 | " customer_clusters_sum=customer_clusters.sum(axis=0)\r\n", 514 | " #print(customer_clusters_sum)\r\n", 515 | " customer_clusters['monetary_value']=100*customer_clusters['monetary_value']/customer_clusters_sum['monetary_value']\r\n", 516 | " customer_clusters['frequency']=100*customer_clusters['frequency']/customer_clusters_sum['frequency']\r\n", 517 | " customer_clusters['recency']=100*customer_clusters['recency']/customer_clusters_sum['recency']\r\n", 518 | " customer_clusters['weighted GDP']=100*customer_clusters['weighted GDP']/customer_clusters_sum['weighted GDP']\r\n", 519 | " print(customer_clusters)\r\n", 520 | " print('\\n')\r\n", 521 | " \r\n", 522 | " print('HEAT map')\r\n", 523 | " print('Numbers are column percentages')\r\n", 524 | " sns.heatmap(customer_clusters.drop(['Customer ID'],axis=1), annot=True, linewidths=.5)\r\n", 525 | "cluster_profile_RFM_country(customer_RFM_GDP,cut_off=100)" 526 | ], 527 | "execution_count": 8, 528 | "outputs": [ 529 | { 530 | "output_type": "stream", 531 | "text": [ 532 | " Customer ID recency frequency monetary_value weighted GDP\n", 533 | " count median median median median\n", 534 | "cluster \n", 535 | "0 1547 389 227.333333 204.902500 2638296.0\n", 536 | "2 3549 35 58.666667 243.840000 2638296.0\n", 537 | "4 572 619 603.500000 166.050000 2638296.0\n", 538 | "5 247 79 92.125000 393.990625 503416.0\n", 539 | "\n", 540 | "\n", 541 | " Customer ID recency frequency monetary_value weighted GDP\n", 542 | " count median median median median\n", 543 | "cluster \n", 544 | "0 1547 34.670232 23.158878 20.311848 31.339994\n", 545 | "2 3549 3.119430 5.976485 24.171697 31.339994\n", 546 | "4 572 55.169340 61.479689 16.460426 31.339994\n", 547 | "5 247 7.040998 9.384948 39.056029 5.980017\n", 548 | "\n", 549 | "\n", 550 | "HEAT map\n", 551 | "Numbers are column percentages\n" 552 | ], 553 | "name": "stdout" 554 | }, 555 | { 556 | "output_type": "display_data", 557 | "data": { 558 | "image/png": "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\n", 559 | "text/plain": [ 560 | "
" 561 | ] 562 | }, 563 | "metadata": { 564 | "tags": [], 565 | "needs_background": "light" 566 | } 567 | } 568 | ] 569 | }, 570 | { 571 | "cell_type": "code", 572 | "metadata": { 573 | "colab": { 574 | "base_uri": "https://localhost:8080/" 575 | }, 576 | "id": "6bL3wYQ2Blg3", 577 | "outputId": "023d404f-951a-4002-e302-730d166ed7b5" 578 | }, 579 | "source": [ 580 | "customer_RFM_GDP['cluster'].value_counts()" 581 | ], 582 | "execution_count": 7, 583 | "outputs": [ 584 | { 585 | "output_type": "execute_result", 586 | "data": { 587 | "text/plain": [ 588 | "2 3549\n", 589 | "0 1547\n", 590 | "4 572\n", 591 | "5 247\n", 592 | "6 17\n", 593 | "1 9\n", 594 | "3 1\n", 595 | "Name: cluster, dtype: int64" 596 | ] 597 | }, 598 | "metadata": { 599 | "tags": [] 600 | }, 601 | "execution_count": 7 602 | } 603 | ] 604 | }, 605 | { 606 | "cell_type": "code", 607 | "metadata": { 608 | "colab": { 609 | "base_uri": "https://localhost:8080/" 610 | }, 611 | "id": "JpQX3zOgCwhA", 612 | "outputId": "e8474378-147e-4a1a-936b-3412eff1b955" 613 | }, 614 | "source": [ 615 | "customer_RFM_GDP['RFM_country_cluster']=5\r\n", 616 | "customer_RFM_GDP.loc[customer_RFM_GDP['cluster']==4,'RFM_country_cluster']=1\r\n", 617 | "customer_RFM_GDP.loc[customer_RFM_GDP['cluster']==0,'RFM_country_cluster']=2\r\n", 618 | "customer_RFM_GDP.loc[customer_RFM_GDP['cluster']==5,'RFM_country_cluster']=3\r\n", 619 | "customer_RFM_GDP.loc[customer_RFM_GDP['cluster']==2,'RFM_country_cluster']=4\r\n", 620 | "customer_RFM_GDP['RFM_country_cluster'].value_counts()" 621 | ], 622 | "execution_count": 8, 623 | "outputs": [ 624 | { 625 | "output_type": "execute_result", 626 | "data": { 627 | "text/plain": [ 628 | "4 3549\n", 629 | "2 1547\n", 630 | "1 572\n", 631 | "3 247\n", 632 | "5 27\n", 633 | "Name: RFM_country_cluster, dtype: int64" 634 | ] 635 | }, 636 | "metadata": { 637 | "tags": [] 638 | }, 639 | "execution_count": 8 640 | } 641 | ] 642 | }, 643 | { 644 | "cell_type": "code", 645 | "metadata": { 646 | "colab": { 647 | "base_uri": "https://localhost:8080/", 648 | "height": 260 649 | }, 650 | "id": "tITyzXxfDdHi", 651 | "outputId": "e1c91bc3-17cc-4e63-a079-fd30a4e40074" 652 | }, 653 | "source": [ 654 | "customer_RFM_GDP=customer_RFM_GDP.reset_index()\r\n", 655 | "customer_RFM_GDP=customer_RFM_GDP[['Customer ID','RFM_country_cluster']]\r\n", 656 | "print(customer_RFM_GDP.shape)\r\n", 657 | "customer_spending_per_category=customer_spending_per_category[['Customer ID','cluster']]\r\n", 658 | "customer_spending_per_category.columns=['Customer ID','item_category_cluster']\r\n", 659 | "print(customer_spending_per_category.shape)\r\n", 660 | "customer_clusters=pd.merge(customer_RFM_GDP,customer_spending_per_category)\r\n", 661 | "print(customer_clusters.shape)\r\n", 662 | "customer_clusters.head()" 663 | ], 664 | "execution_count": 11, 665 | "outputs": [ 666 | { 667 | "output_type": "stream", 668 | "text": [ 669 | "(5942, 2)\n", 670 | "(5942, 2)\n", 671 | "(5942, 3)\n" 672 | ], 673 | "name": "stdout" 674 | }, 675 | { 676 | "output_type": "execute_result", 677 | "data": { 678 | "text/html": [ 679 | "
\n", 680 | "\n", 693 | "\n", 694 | " \n", 695 | " \n", 696 | " \n", 697 | " \n", 698 | " \n", 699 | " \n", 700 | " \n", 701 | " \n", 702 | " \n", 703 | " \n", 704 | " \n", 705 | " \n", 706 | " \n", 707 | " \n", 708 | " \n", 709 | " \n", 710 | " \n", 711 | " \n", 712 | " \n", 713 | " \n", 714 | " \n", 715 | " \n", 716 | " \n", 717 | " \n", 718 | " \n", 719 | " \n", 720 | " \n", 721 | " \n", 722 | " \n", 723 | " \n", 724 | " \n", 725 | " \n", 726 | " \n", 727 | " \n", 728 | " \n", 729 | " \n", 730 | " \n", 731 | " \n", 732 | " \n", 733 | " \n", 734 | "
Customer IDRFM_country_clusteritem_category_cluster
012346.021
112347.031
212348.031
312349.041
412350.031
\n", 735 | "
" 736 | ], 737 | "text/plain": [ 738 | " Customer ID RFM_country_cluster item_category_cluster\n", 739 | "0 12346.0 2 1\n", 740 | "1 12347.0 3 1\n", 741 | "2 12348.0 3 1\n", 742 | "3 12349.0 4 1\n", 743 | "4 12350.0 3 1" 744 | ] 745 | }, 746 | "metadata": { 747 | "tags": [] 748 | }, 749 | "execution_count": 11 750 | } 751 | ] 752 | }, 753 | { 754 | "cell_type": "code", 755 | "metadata": { 756 | "colab": { 757 | "base_uri": "https://localhost:8080/", 758 | "height": 238 759 | }, 760 | "id": "B8hUIW5ODyhy", 761 | "outputId": "8a55db22-cc72-4165-c738-92da52e90ce7" 762 | }, 763 | "source": [ 764 | "pd.crosstab(customer_clusters['RFM_country_cluster'],customer_clusters['item_category_cluster'])" 765 | ], 766 | "execution_count": 12, 767 | "outputs": [ 768 | { 769 | "output_type": "execute_result", 770 | "data": { 771 | "text/html": [ 772 | "
\n", 773 | "\n", 786 | "\n", 787 | " \n", 788 | " \n", 789 | " \n", 790 | " \n", 791 | " \n", 792 | " \n", 793 | " \n", 794 | " \n", 795 | " \n", 796 | " \n", 797 | " \n", 798 | " \n", 799 | " \n", 800 | " \n", 801 | " \n", 802 | " \n", 803 | " \n", 804 | " \n", 805 | " \n", 806 | " \n", 807 | " \n", 808 | " \n", 809 | " \n", 810 | " \n", 811 | " \n", 812 | " \n", 813 | " \n", 814 | " \n", 815 | " \n", 816 | " \n", 817 | " \n", 818 | " \n", 819 | " \n", 820 | " \n", 821 | " \n", 822 | " \n", 823 | " \n", 824 | " \n", 825 | " \n", 826 | " \n", 827 | " \n", 828 | " \n", 829 | " \n", 830 | " \n", 831 | " \n", 832 | " \n", 833 | " \n", 834 | " \n", 835 | " \n", 836 | " \n", 837 | " \n", 838 | " \n", 839 | " \n", 840 | "
item_category_cluster0123
RFM_country_cluster
1154466942
2109111223690
382071022
42892501489270
502133
\n", 841 | "
" 842 | ], 843 | "text/plain": [ 844 | "item_category_cluster 0 1 2 3\n", 845 | "RFM_country_cluster \n", 846 | "1 15 446 69 42\n", 847 | "2 109 1112 236 90\n", 848 | "3 8 207 10 22\n", 849 | "4 289 2501 489 270\n", 850 | "5 0 21 3 3" 851 | ] 852 | }, 853 | "metadata": { 854 | "tags": [] 855 | }, 856 | "execution_count": 12 857 | } 858 | ] 859 | }, 860 | { 861 | "cell_type": "code", 862 | "metadata": { 863 | "colab": { 864 | "base_uri": "https://localhost:8080/", 865 | "height": 238 866 | }, 867 | "id": "F2TppJD8F821", 868 | "outputId": "4950d4ba-62ea-4da9-e2d6-e24e4b0accfd" 869 | }, 870 | "source": [ 871 | "cross_table=pd.crosstab(customer_clusters['RFM_country_cluster'],customer_clusters['item_category_cluster'])/5942*100\r\n", 872 | "cross_table" 873 | ], 874 | "execution_count": 15, 875 | "outputs": [ 876 | { 877 | "output_type": "execute_result", 878 | "data": { 879 | "text/html": [ 880 | "
\n", 881 | "\n", 894 | "\n", 895 | " \n", 896 | " \n", 897 | " \n", 898 | " \n", 899 | " \n", 900 | " \n", 901 | " \n", 902 | " \n", 903 | " \n", 904 | " \n", 905 | " \n", 906 | " \n", 907 | " \n", 908 | " \n", 909 | " \n", 910 | " \n", 911 | " \n", 912 | " \n", 913 | " \n", 914 | " \n", 915 | " \n", 916 | " \n", 917 | " \n", 918 | " \n", 919 | " \n", 920 | " \n", 921 | " \n", 922 | " \n", 923 | " \n", 924 | " \n", 925 | " \n", 926 | " \n", 927 | " \n", 928 | " \n", 929 | " \n", 930 | " \n", 931 | " \n", 932 | " \n", 933 | " \n", 934 | " \n", 935 | " \n", 936 | " \n", 937 | " \n", 938 | " \n", 939 | " \n", 940 | " \n", 941 | " \n", 942 | " \n", 943 | " \n", 944 | " \n", 945 | " \n", 946 | " \n", 947 | " \n", 948 | "
item_category_cluster0123
RFM_country_cluster
10.2524407.5058901.1612250.706833
21.83439918.7142383.9717271.514642
30.1346353.4836760.1682940.370246
44.86368242.0902058.2295524.543925
50.0000000.3534160.0504880.050488
\n", 949 | "
" 950 | ], 951 | "text/plain": [ 952 | "item_category_cluster 0 1 2 3\n", 953 | "RFM_country_cluster \n", 954 | "1 0.252440 7.505890 1.161225 0.706833\n", 955 | "2 1.834399 18.714238 3.971727 1.514642\n", 956 | "3 0.134635 3.483676 0.168294 0.370246\n", 957 | "4 4.863682 42.090205 8.229552 4.543925\n", 958 | "5 0.000000 0.353416 0.050488 0.050488" 959 | ] 960 | }, 961 | "metadata": { 962 | "tags": [] 963 | }, 964 | "execution_count": 15 965 | } 966 | ] 967 | }, 968 | { 969 | "cell_type": "code", 970 | "metadata": { 971 | "id": "F5ZqSD64GX6W", 972 | "colab": { 973 | "base_uri": "https://localhost:8080/", 974 | "height": 335 975 | }, 976 | "outputId": "4990de09-9a9e-4aed-fb3d-d3af3a56cb5b" 977 | }, 978 | "source": [ 979 | "fig, ax = plt.subplots(figsize=(8, 5))\r\n", 980 | "sns.heatmap(cross_table/100,\r\n", 981 | " annot=True,\r\n", 982 | " fmt='.2%',\r\n", 983 | " #cmap='rocket_r',\r\n", 984 | " #linewidths=.5,\r\n", 985 | " ax=ax)\r\n", 986 | "plt.show()" 987 | ], 988 | "execution_count": 22, 989 | "outputs": [ 990 | { 991 | "output_type": "display_data", 992 | "data": { 993 | "image/png": "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\n", 994 | "text/plain": [ 995 | "
" 996 | ] 997 | }, 998 | "metadata": { 999 | "tags": [], 1000 | "needs_background": "light" 1001 | } 1002 | } 1003 | ] 1004 | }, 1005 | { 1006 | "cell_type": "code", 1007 | "metadata": { 1008 | "id": "yZWpcwIRB38X" 1009 | }, 1010 | "source": [ 1011 | "" 1012 | ], 1013 | "execution_count": null, 1014 | "outputs": [] 1015 | } 1016 | ] 1017 | } --------------------------------------------------------------------------------