├── README.md
├── fraudml.JPG
├── LICENSE
├── Blockchain and XGBoosted K-means for Fraud Detection.ipynb
└── Fraud Detection Using KMeans.ipynb
/README.md:
--------------------------------------------------------------------------------
1 | # Credit-card-fraud-detection-using-blockchain-and-ml
2 |
--------------------------------------------------------------------------------
/fraudml.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PrudhviGNV/Credit-card-fraud-detection-using-blockchain-and-ml/main/fraudml.JPG
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/Blockchain and XGBoosted K-means for Fraud Detection.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "#
Blockchain and Machine Learning for Fraud Detection: Employing Artificial Intelligence in the Banking Sector"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "### Blockchain Integrated with an XGBoosted K-means Model"
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | "#### Import Libraries & Packages"
22 | ]
23 | },
24 | {
25 | "cell_type": "code",
26 | "execution_count": null,
27 | "metadata": {},
28 | "outputs": [],
29 | "source": [
30 | "import pandas as pd\n",
31 | "import pandas.testing as tm\n",
32 | "import numpy as np\n",
33 | "from numpy import loadtxt\n",
34 | "from sklearn.cluster import KMeans\n",
35 | "from sklearn.preprocessing import LabelEncoder\n",
36 | "from sklearn.preprocessing import MinMaxScaler\n",
37 | "import xgboost\n",
38 | "from xgboost import XGBClassifier\n",
39 | "import hashlib\n",
40 | "import json\n",
41 | "from time import time\n",
42 | "from urllib.parse import urlparse\n",
43 | "from uuid import uuid4\n",
44 | "import requests\n",
45 | "from flask import Flask, jsonify, request"
46 | ]
47 | },
48 | {
49 | "cell_type": "markdown",
50 | "metadata": {},
51 | "source": [
52 | "### Data Wrangling"
53 | ]
54 | },
55 | {
56 | "cell_type": "code",
57 | "execution_count": 7,
58 | "metadata": {},
59 | "outputs": [],
60 | "source": [
61 | "#concatenate data into a single data frame\n",
62 | "\n",
63 | "account= pd.read_csv(\"account.csv\")\n",
64 | "order= pd.read_csv(\"order.csv\")\n",
65 | "transaction= pd.read_csv(\"transaction.csv\")\n",
66 | "\n",
67 | "X= pd.concat([account,order,transaction], axis=0)\n",
68 | "\n",
69 | "#dividing the data into train and test sets for the k-means model\n",
70 | "\n",
71 | "X_new= X.copy() #create a copy of your data \n",
72 | "\n",
73 | "x_train = X_new.sample(frac=0.40, random_state=0)\n",
74 | "x_test = X_new.drop(x_train.index)"
75 | ]
76 | },
77 | {
78 | "cell_type": "markdown",
79 | "metadata": {},
80 | "source": [
81 | "### Blockchain"
82 | ]
83 | },
84 | {
85 | "cell_type": "code",
86 | "execution_count": null,
87 | "metadata": {},
88 | "outputs": [],
89 | "source": [
90 | "#Create a class to store the block chain\n",
91 | "\n",
92 | "class Blockchain:\n",
93 | " def __init__(self):\n",
94 | " self.current_trans = []\n",
95 | " self.chain = []\n",
96 | " self.nodes = set()\n",
97 | "\n",
98 | " #Create the genesis block\n",
99 | " self.new_block(prev_hash='1', proof=100)\n",
100 | "\n",
101 | " def new_node(self, address):\n",
102 | " \"\"\"\n",
103 | " Add a new node. View the node here:'http://192.168.0.5:5000'\n",
104 | " \"\"\"\n",
105 | "\n",
106 | " parsed_url = urlparse(address)\n",
107 | " if parsed_url.netloc:\n",
108 | " self.nodes.add(parsed_url.netloc)\n",
109 | " elif parsed_url.path:\n",
110 | " self.nodes.add(parsed_url.path)\n",
111 | " else:\n",
112 | " raise ValueError('Invalid URL. Please try again.')\n",
113 | "\n",
114 | "\n",
115 | " def valid_chain(self, chain):\n",
116 | " \"\"\"\n",
117 | " Determine if blockchain is valid.\n",
118 | " \"\"\"\n",
119 | "\n",
120 | " prev_block = chain[0]\n",
121 | " current_index = 1\n",
122 | "\n",
123 | " while current_index < len(chain):\n",
124 | " block = chain[current_index]\n",
125 | " print(f'{prev_block}')\n",
126 | " print(f'{block}')\n",
127 | " print(\"\\n-----------\\n\")\n",
128 | " #Check that the hash of the block is correct\n",
129 | " prev_block_hash = self.hash(prev_block)\n",
130 | " if block['prev_hash'] != prev_block_hash:\n",
131 | " return False\n",
132 | "\n",
133 | " #Check that the Proof of Work is correct\n",
134 | " if not self.valid_proof(prev_block['proof'], block['proof'], prev_block_hash):\n",
135 | " return False\n",
136 | "\n",
137 | " prev_block = block\n",
138 | " current_index += 1\n",
139 | "\n",
140 | " return True\n",
141 | "\n",
142 | " def conflict_resolution(self):\n",
143 | " \"\"\"\n",
144 | " Resolves conflicts by replacing current chain with the longest one in the network.\n",
145 | " \"\"\"\n",
146 | "\n",
147 | " neighbours = self.nodes\n",
148 | " new_chain = None\n",
149 | "\n",
150 | " #Identifying long chains\n",
151 | " max_length = len(self.chain)\n",
152 | "\n",
153 | " #Grab and verify the chains from all the nodes in the network\n",
154 | " for node in neighbours:\n",
155 | " response = requests.get(f'http://{node}/chain')\n",
156 | "\n",
157 | " if response.status_code == 200:\n",
158 | " length = response.json()['length']\n",
159 | " chain = response.json()['chain']\n",
160 | "\n",
161 | " #Check if the length is longer and the chain is valid\n",
162 | " if length > max_length and self.valid_chain(chain):\n",
163 | " max_length = length\n",
164 | " new_chain = chain\n",
165 | "\n",
166 | " #Replace chain if a valid longer chain is discovered\n",
167 | " if new_chain:\n",
168 | " self.chain = new_chain\n",
169 | " return True\n",
170 | "\n",
171 | " return False\n",
172 | "\n",
173 | " def new_block(self, proof, prev_hash):\n",
174 | "\n",
175 | " block = {\n",
176 | " 'index': len(self.chain) + 1,\n",
177 | " 'timestamp': time(),\n",
178 | " 'transactions': self.current_trans,\n",
179 | " 'proof': proof,\n",
180 | " 'prev_hash': prev_hash or self.hash(self.chain[-1]),\n",
181 | " }\n",
182 | "\n",
183 | " #Reset the current list of transactions\n",
184 | " self.current_trans = []\n",
185 | "\n",
186 | " self.chain.append(block)\n",
187 | " return block\n",
188 | "\n",
189 | " def new_trans(self, sender, recipient, amount):\n",
190 | " \"\"\"\n",
191 | " Creates a new transaction to go into the next mined Block.\n",
192 | " \"\"\"\n",
193 | " self.current_trans.append({\n",
194 | " 'sender': sender,\n",
195 | " 'recipient': recipient,\n",
196 | " 'amount': amount,\n",
197 | " })\n",
198 | "\n",
199 | " return self.prev_block['index'] + 1\n",
200 | "\n",
201 | " @property\n",
202 | " def prev_block(self):\n",
203 | " return self.chain[-1]\n",
204 | "\n",
205 | " @staticmethod\n",
206 | " def hash(block):\n",
207 | " \"\"\"\n",
208 | " SHA-256 encryption\n",
209 | " \"\"\"\n",
210 | "\n",
211 | " #Ensure that dictionary is ordered, to avoid inconsistent hashes.\n",
212 | " block_str = json.dumps(block, sort_keys=True).encode()\n",
213 | " return hashlib.sha256(block_str).hexdigest()\n",
214 | "\n",
215 | " def proof_of_work(self, prev_block):\n",
216 | " \n",
217 | " #Proof of Work Algorithm:\n",
218 | " #- Find a number p' such that hash(pp') contains leading 4 zeroes\n",
219 | " #- Where p is the previous proof, and p' is the new proof\n",
220 | "\n",
221 | " prev_proof = prev_block['proof']\n",
222 | " prev_hash = self.hash(prev_block)\n",
223 | "\n",
224 | " proof = 0\n",
225 | " while self.valid_proof(prev_proof, proof, prev_hash) is False:\n",
226 | " proof += 1\n",
227 | "\n",
228 | " return proof\n",
229 | "\n",
230 | " @staticmethod\n",
231 | " def valid_proof(prev_proof, proof, prev_hash):\n",
232 | "\n",
233 | " #Validates Proof\n",
234 | "\n",
235 | " guess = f'{prev_proof}{proof}{prev_hash}'.encode()\n",
236 | " guess_hash = hashlib.sha256(guess).hexdigest()\n",
237 | " return guess_hash[:4] == \"0000\""
238 | ]
239 | },
240 | {
241 | "cell_type": "markdown",
242 | "metadata": {},
243 | "source": [
244 | "### Integration of XGBoosted KMeans with Blockchain"
245 | ]
246 | },
247 | {
248 | "cell_type": "code",
249 | "execution_count": null,
250 | "metadata": {},
251 | "outputs": [],
252 | "source": [
253 | "#Instantiate the Node\n",
254 | "app = Flask(__name__)\n",
255 | "\n",
256 | "#Generate a globally unique address for this node\n",
257 | "node_id = str(uuid4()).replace('-', '')\n",
258 | "\n",
259 | "#Instantiate the Blockchain\n",
260 | "blockchain = Blockchain()\n",
261 | "\n",
262 | "\n",
263 | "@app.route('/mine', methods=['GET'])\n",
264 | "def mine():\n",
265 | " #Run the proof of work algorithm to get the next proof...\n",
266 | " prev_block = blockchain.prev_block\n",
267 | " proof = blockchain.proof_of_work(prev_block)\n",
268 | "\n",
269 | " #Receive a reward for finding the proof.\n",
270 | " #The sender is \"0\" to signify a new transaction.\n",
271 | " blockchain.new_trans(\n",
272 | " sender=\"0\",\n",
273 | " recipient=node_id,\n",
274 | " amount=1,\n",
275 | " )\n",
276 | "\n",
277 | " #Forge the new Block by adding it to the chain\n",
278 | " prev_hash = blockchain.hash(prev_block)\n",
279 | " block = blockchain.new_block(proof, prev_hash)\n",
280 | "\n",
281 | " response = {\n",
282 | " 'message': \"New Block Forged\",\n",
283 | " 'index': block['index'],\n",
284 | " 'transactions': block['transactions'],\n",
285 | " 'proof': block['proof'],\n",
286 | " 'prev_hash': block['prev_hash'],\n",
287 | " }\n",
288 | " return jsonify(response), 200\n",
289 | "\n",
290 | "\n",
291 | "@app.route('/transactions/new', methods=['POST'])\n",
292 | "def new_trans():\n",
293 | " values = request.get_json()\n",
294 | "\n",
295 | " #Check that the required fields are in the POST'ed data\n",
296 | " required = ['sender', 'recipient', 'amount']\n",
297 | " if not all(k in values for k in required):\n",
298 | " return 'Missing values', 400\n",
299 | "\n",
300 | " #Create a new Transaction\n",
301 | " index = blockchain.new_trans(values['sender'], values['recipient'], values['amount'])\n",
302 | "\n",
303 | " response = {'message': f'Transaction will be added to Block {index}'}\n",
304 | " \n",
305 | " #Kmeans clustering is implemented on the newly formed chain\n",
306 | "\n",
307 | "\n",
308 | " #Building the k-means model\n",
309 | "\n",
310 | " kmeans = KMeans(n_clusters=2)\n",
311 | " kmeans.fit(x_train)\n",
312 | " KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,\n",
313 | " n_clusters=2, n_init=10, n_jobs=1, precompute_distances='auto',\n",
314 | " random_state=None, tol=0.0001, verbose=0)\n",
315 | " correct = 0\n",
316 | " for i in range(len(x_test)):\n",
317 | " predict_me = np.array(test_x[i].astype(float))\n",
318 | " predict_me = predict_me.reshape(-1, len(predict_me))\n",
319 | " prediction = kmeans.predict(predict_me)\n",
320 | " if prediction[0] == y[i]:\n",
321 | " correct += 1\n",
322 | "\n",
323 | " print(correct/len(x_test))\n",
324 | " return jsonify(response), 201\n",
325 | "\n",
326 | " #fit model no training data\n",
327 | " model = XGBClassifier()\n",
328 | "\n",
329 | "@app.route('/chain', methods=['GET'])\n",
330 | "def full_chain():\n",
331 | " response = {\n",
332 | " 'chain': blockchain.chain,\n",
333 | " 'length': len(blockchain.chain),\n",
334 | " }\n",
335 | " return jsonify(response), 200\n",
336 | " \n",
337 | "@app.route('/nodes/register', methods=['POST'])\n",
338 | "def new_nodes():\n",
339 | " values = request.get_json()\n",
340 | "\n",
341 | " nodes = values.get('nodes')\n",
342 | " if nodes is None:\n",
343 | " return \"Error: Please supply a valid list of nodes\", 400\n",
344 | "\n",
345 | " for node in nodes:\n",
346 | " blockchain.new_node(node)\n",
347 | "\n",
348 | " response = {\n",
349 | " 'message': 'New nodes have been added',\n",
350 | " 'total_nodes': list(blockchain.nodes),\n",
351 | " }\n",
352 | " return jsonify(response), 201\n",
353 | "\n",
354 | "\n",
355 | "@app.route('/nodes/resolve', methods=['GET'])\n",
356 | "def consensus():\n",
357 | " replaced = blockchain.conflict_resolution()\n",
358 | "\n",
359 | " if replaced:\n",
360 | " response = {\n",
361 | " 'message': 'Our chain was replaced',\n",
362 | " 'new_chain': blockchain.chain\n",
363 | " }\n",
364 | " else:\n",
365 | " response = {\n",
366 | " 'message': 'Our chain is authoritative',\n",
367 | " 'chain': blockchain.chain\n",
368 | " }\n",
369 | "\n",
370 | " return jsonify(response), 200\n",
371 | "\n",
372 | "\n",
373 | "if __name__ == '__main__':\n",
374 | " from argparse import ArgumentParser\n",
375 | "\n",
376 | " parser = ArgumentParser()\n",
377 | " parser.add_argument('-p', '--port', default=5000, type=int, help='port to listen on')\n",
378 | " args = parser.parse_args()\n",
379 | " port = args.port\n",
380 | "\n",
381 | " app.run(host='0.0.0.0', port=port)"
382 | ]
383 | }
384 | ],
385 | "metadata": {
386 | "kernelspec": {
387 | "display_name": "Python 3",
388 | "language": "python",
389 | "name": "python3"
390 | },
391 | "language_info": {
392 | "codemirror_mode": {
393 | "name": "ipython",
394 | "version": 3
395 | },
396 | "file_extension": ".py",
397 | "mimetype": "text/x-python",
398 | "name": "python",
399 | "nbconvert_exporter": "python",
400 | "pygments_lexer": "ipython3",
401 | "version": "3.7.4"
402 | },
403 | "latex_envs": {
404 | "LaTeX_envs_menu_present": true,
405 | "autoclose": false,
406 | "autocomplete": true,
407 | "bibliofile": "biblio.bib",
408 | "cite_by": "apalike",
409 | "current_citInitial": 1,
410 | "eqLabelWithNumbers": true,
411 | "eqNumInitial": 1,
412 | "hotkeys": {
413 | "equation": "Ctrl-E",
414 | "itemize": "Ctrl-I"
415 | },
416 | "labels_anchors": false,
417 | "latex_user_defs": false,
418 | "report_style_numbering": false,
419 | "user_envs_cfg": false
420 | }
421 | },
422 | "nbformat": 4,
423 | "nbformat_minor": 2
424 | }
425 |
--------------------------------------------------------------------------------
/Fraud Detection Using KMeans.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Blockchain and Machine Learning for Fraud Detection: Employing Artificial Intelligence in the Banking Sector"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "## By Vinita Silaparasetty"
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | "#### Credits\n",
22 | "\n",
23 | "##### Source: http://lisp.vse.cz/pkdd99/berka.html\n",
24 | "\n",
25 | "##### Prepared by: Petr Berka and Marta Sochorova."
26 | ]
27 | },
28 | {
29 | "cell_type": "markdown",
30 | "metadata": {},
31 | "source": [
32 | "## Fraud Detection Using KMeans"
33 | ]
34 | },
35 | {
36 | "cell_type": "markdown",
37 | "metadata": {},
38 | "source": [
39 | "#### Import Libraries"
40 | ]
41 | },
42 | {
43 | "cell_type": "code",
44 | "execution_count": 1,
45 | "metadata": {},
46 | "outputs": [],
47 | "source": [
48 | "import numpy as np\n",
49 | "import scipy\n",
50 | "import pandas as pd\n",
51 | "import matplotlib\n",
52 | "%matplotlib inline\n",
53 | "import matplotlib.pyplot as plt\n",
54 | "import seaborn as sns\n",
55 | "import sklearn\n",
56 | "from sklearn.model_selection import train_test_split\n",
57 | "from sklearn.cluster import KMeans\n",
58 | "from sklearn.preprocessing import StandardScaler\n",
59 | "from sklearn.datasets import make_moons\n",
60 | "from sklearn.cluster import SpectralClustering"
61 | ]
62 | },
63 | {
64 | "cell_type": "markdown",
65 | "metadata": {},
66 | "source": [
67 | "#### Import Data"
68 | ]
69 | },
70 | {
71 | "cell_type": "code",
72 | "execution_count": 2,
73 | "metadata": {},
74 | "outputs": [],
75 | "source": [
76 | "order= pd.read_csv(\"order.csv\")\n",
77 | "account= pd.read_csv(\"account.csv\")\n",
78 | "transaction= pd.read_csv(\"transaction.csv\")"
79 | ]
80 | },
81 | {
82 | "cell_type": "markdown",
83 | "metadata": {},
84 | "source": [
85 | "## Process Demo\n",
86 | "\n",
87 | "Demonstration of the working of KMeans clustering with visualization of the output."
88 | ]
89 | },
90 | {
91 | "cell_type": "markdown",
92 | "metadata": {},
93 | "source": [
94 | "### Order & Account Dataframes"
95 | ]
96 | },
97 | {
98 | "cell_type": "code",
99 | "execution_count": 8,
100 | "metadata": {},
101 | "outputs": [],
102 | "source": [
103 | "#working with 'order' dataframe and 'account' dataframe\n",
104 | "x = (order['account_id'],order['account_to'],order['amount'])\n",
105 | "y = (account['account_id'],account['district_id'],account['frequency'])"
106 | ]
107 | },
108 | {
109 | "cell_type": "code",
110 | "execution_count": 9,
111 | "metadata": {},
112 | "outputs": [],
113 | "source": [
114 | "# Splitting the dataset into the Training set and Test set\n",
115 | "X_train, X_test, y_train, y_test = train_test_split(x, y, test_size = 0.2, random_state = 0)"
116 | ]
117 | },
118 | {
119 | "cell_type": "code",
120 | "execution_count": 10,
121 | "metadata": {},
122 | "outputs": [],
123 | "source": [
124 | "# Feature Scaling\n",
125 | "from sklearn.preprocessing import StandardScaler\n",
126 | "sc_X = StandardScaler()\n",
127 | "X_train = sc_X.fit_transform(X_train)\n",
128 | "X_test = sc_X.transform(X_test)\n",
129 | "sc_y = StandardScaler()\n",
130 | "y_train = sc_y.fit_transform(y_train)"
131 | ]
132 | },
133 | {
134 | "cell_type": "markdown",
135 | "metadata": {},
136 | "source": [
137 | "#### Applying KMeans"
138 | ]
139 | },
140 | {
141 | "cell_type": "code",
142 | "execution_count": 11,
143 | "metadata": {},
144 | "outputs": [],
145 | "source": [
146 | "kmeans = KMeans(n_clusters = 3, init = 'k-means++', random_state = 42)\n",
147 | "y_kmeans = kmeans.fit_predict(x)"
148 | ]
149 | },
150 | {
151 | "cell_type": "markdown",
152 | "metadata": {},
153 | "source": [
154 | "#### Visualize the Clusters"
155 | ]
156 | },
157 | {
158 | "cell_type": "code",
159 | "execution_count": 12,
160 | "metadata": {},
161 | "outputs": [
162 | {
163 | "data": {
164 | "image/png": "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\n",
165 | "text/plain": [
166 | ""
167 | ]
168 | },
169 | "metadata": {
170 | "needs_background": "light"
171 | },
172 | "output_type": "display_data"
173 | }
174 | ],
175 | "source": [
176 | "x, y = make_moons(200, noise=.05, random_state=0)\n",
177 | "labels = KMeans(2, random_state=0).fit_predict(x)\n",
178 | "plt.scatter(x[:, 0], x[:, 1], c=labels,\n",
179 | " s=50, cmap='viridis');"
180 | ]
181 | },
182 | {
183 | "cell_type": "markdown",
184 | "metadata": {},
185 | "source": [
186 | "### -------------------- End of Demo --------------------"
187 | ]
188 | },
189 | {
190 | "cell_type": "markdown",
191 | "metadata": {},
192 | "source": [
193 | "###### I skipped the visualizations for the rest of the analysis procedure as it is not needed for the main program."
194 | ]
195 | },
196 | {
197 | "cell_type": "markdown",
198 | "metadata": {},
199 | "source": [
200 | "### Order & Transaction Dataframes"
201 | ]
202 | },
203 | {
204 | "cell_type": "code",
205 | "execution_count": 13,
206 | "metadata": {},
207 | "outputs": [],
208 | "source": [
209 | "# working with 'order' dataframe and 'transaction' dataframe\n",
210 | "a = (order['account_id'],order['account_to'],order['amount'])\n",
211 | "b = (transaction['account_id'],transaction['balance'],transaction['amount'])"
212 | ]
213 | },
214 | {
215 | "cell_type": "code",
216 | "execution_count": 14,
217 | "metadata": {},
218 | "outputs": [],
219 | "source": [
220 | "# Splitting the dataset into the Training set and Test set\n",
221 | "X_train, X_test, y_train, y_test = train_test_split(a, b, test_size = 0.2, random_state = 0)"
222 | ]
223 | },
224 | {
225 | "cell_type": "code",
226 | "execution_count": 15,
227 | "metadata": {},
228 | "outputs": [],
229 | "source": [
230 | "# Feature Scaling\n",
231 | "from sklearn.preprocessing import StandardScaler\n",
232 | "sc_X = StandardScaler()\n",
233 | "X_train = sc_X.fit_transform(X_train)\n",
234 | "X_test = sc_X.transform(X_test)\n",
235 | "sc_y = StandardScaler()\n",
236 | "y_train = sc_y.fit_transform(y_train)"
237 | ]
238 | },
239 | {
240 | "cell_type": "code",
241 | "execution_count": 16,
242 | "metadata": {},
243 | "outputs": [],
244 | "source": [
245 | "kmeans = KMeans(n_clusters = 3, init = 'k-means++', random_state = 42)\n",
246 | "y_kmeans = kmeans.fit_predict(a)"
247 | ]
248 | },
249 | {
250 | "cell_type": "markdown",
251 | "metadata": {},
252 | "source": [
253 | "### Account & Transaction Dataframes"
254 | ]
255 | },
256 | {
257 | "cell_type": "code",
258 | "execution_count": 19,
259 | "metadata": {},
260 | "outputs": [],
261 | "source": [
262 | "# working with 'account' dataframe and 'transaction' dataframe\n",
263 | "e = (account['account_id'],account['district_id'])\n",
264 | "f = (transaction['account_id'],transaction['amount'])"
265 | ]
266 | },
267 | {
268 | "cell_type": "code",
269 | "execution_count": 20,
270 | "metadata": {},
271 | "outputs": [],
272 | "source": [
273 | "# Splitting the dataset into the Training set and Test set\n",
274 | "X_train, X_test, y_train, y_test = train_test_split(e,f, test_size = 0.2, random_state = 0)"
275 | ]
276 | },
277 | {
278 | "cell_type": "code",
279 | "execution_count": 21,
280 | "metadata": {},
281 | "outputs": [],
282 | "source": [
283 | "# Feature Scaling\n",
284 | "from sklearn.preprocessing import StandardScaler\n",
285 | "sc_X = StandardScaler()\n",
286 | "X_train = sc_X.fit_transform(X_train)\n",
287 | "X_test = sc_X.transform(X_test)\n",
288 | "sc_y = StandardScaler()\n",
289 | "y_train = sc_y.fit_transform(y_train)"
290 | ]
291 | },
292 | {
293 | "cell_type": "code",
294 | "execution_count": 23,
295 | "metadata": {},
296 | "outputs": [],
297 | "source": [
298 | "kmeans = KMeans(n_clusters = 2, init = 'k-means++', random_state = 42)\n",
299 | "y_kmeans = kmeans.fit_predict(e)"
300 | ]
301 | },
302 | {
303 | "cell_type": "markdown",
304 | "metadata": {},
305 | "source": [
306 | "##### Note: \n",
307 | "The dataset consisists of several csv files, but I have used only three of the files they serve the pupose of my research. the files I used are:\n",
308 | "\n",
309 | "1) order.csv\n",
310 | "\n",
311 | "2) account.csv\n",
312 | "\n",
313 | "3) transaction.csv\n",
314 | " "
315 | ]
316 | }
317 | ],
318 | "metadata": {
319 | "kernelspec": {
320 | "display_name": "Python 3",
321 | "language": "python",
322 | "name": "python3"
323 | },
324 | "language_info": {
325 | "codemirror_mode": {
326 | "name": "ipython",
327 | "version": 3
328 | },
329 | "file_extension": ".py",
330 | "mimetype": "text/x-python",
331 | "name": "python",
332 | "nbconvert_exporter": "python",
333 | "pygments_lexer": "ipython3",
334 | "version": "3.7.3"
335 | }
336 | },
337 | "nbformat": 4,
338 | "nbformat_minor": 2
339 | }
340 |
--------------------------------------------------------------------------------