├── .gitignore ├── LICENSE ├── README.md ├── lbg.py └── lbg_test.ipynb /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | __pycache__/ 3 | *.pyc 4 | .ipynb_checkpoints/ 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python Implementation for Linde-Buzo-Gray / Generalized Lloyd Algorithm 2 | 3 | This is a small set of Python functions that implement the 4 | [Generalized-Lloyd or Linde-Buzo-Gray Algorithm](https://en.wikipedia.org/wiki/Linde%E2%80%93Buzo%E2%80%93Gray_algorithm) 5 | for vector quantization. It allows clustering of vectors of any dimension. This is helpful for example for 6 | image classification when using the SIFT or SURF algorithms where you can cluster the feature vectors. It might 7 | be also useful if you want to cluster a large amount of points on a map. 8 | 9 | See also: http://mkonrad.net/projects/gen_lloyd.html 10 | 11 | See also my original [Java implementation](https://github.com/internaut/JGenLloydCluster). 12 | 13 | The repository also contains an IPython notebook to visualize how this algorithm works. 14 | 15 | The source-code is provided under [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0). 16 | -------------------------------------------------------------------------------- /lbg.py: -------------------------------------------------------------------------------- 1 | """ 2 | Linde-Buzo-Gray / Generalized Lloyd algorithm implementation in Python *3*. 3 | Heuristic process that can be used to generate cluster points from a big amount of multidimensional vectors. 4 | """ 5 | 6 | import math 7 | from functools import reduce 8 | from collections import defaultdict 9 | 10 | _size_data = 0 11 | _dim = 0 12 | 13 | 14 | def generate_codebook(data, size_codebook, epsilon=0.00001): 15 | """ 16 | Generate codebook of size with convergence value . Will return a tuple with the 17 | generated codebook, a vector with absolute weights and a vector with relative weights (the weight denotes how many 18 | vectors for are in the proximity of the codevector. 19 | :param data: input data with N k-dimensional vectors 20 | :param size_codebook: codebook size. Because the codevectors are split on each iteration, this should be a 21 | power-of-2-value 22 | :param epsilon: convergence value 23 | :return tuple of: codebook of size , absolute weights, relative weights 24 | """ 25 | global _size_data, _dim 26 | 27 | _size_data = len(data) 28 | assert _size_data > 0 29 | 30 | _dim = len(data[0]) 31 | assert _dim > 0 32 | 33 | codebook = [] 34 | codebook_abs_weights = [_size_data] 35 | codebook_rel_weights = [1.0] 36 | 37 | # calculate initial codevector: average vector of whole input data 38 | c0 = avg_vec_of_vecs(data, _dim, _size_data) 39 | codebook.append(c0) 40 | 41 | # calculate the average distortion 42 | avg_dist = avg_distortion_c0(c0, data) 43 | 44 | # split codevectors until we have have enough 45 | while len(codebook) < size_codebook: 46 | codebook, codebook_abs_weights, codebook_rel_weights, avg_dist = split_codebook(data, codebook, 47 | epsilon, avg_dist) 48 | 49 | return codebook, codebook_abs_weights, codebook_rel_weights 50 | 51 | 52 | def split_codebook(data, codebook, epsilon, initial_avg_dist): 53 | """ 54 | Split the codebook so that each codevector in the codebook is split into two. 55 | :param data: input data 56 | :param codebook: input codebook. its codevectors will be split into two. 57 | :param epsilon: convergence value 58 | :param initial_avg_dist: initial average distortion 59 | :return Tuple with new codebook, codebook absolute weights and codebook relative weights 60 | """ 61 | 62 | # split codevectors 63 | new_codevectors = [] 64 | for c in codebook: 65 | # the new codevectors c1 and c2 will moved by epsilon and -epsilon so to be apart from each other 66 | c1 = new_codevector(c, epsilon) 67 | c2 = new_codevector(c, -epsilon) 68 | new_codevectors.extend((c1, c2)) 69 | 70 | codebook = new_codevectors 71 | len_codebook = len(codebook) 72 | abs_weights = [0] * len_codebook 73 | rel_weights = [0.0] * len_codebook 74 | 75 | # print('> splitting to size', len_codebook) 76 | 77 | # try to reach a convergence by minimizing the average distortion. this is done by moving the codevectors step by 78 | # step to the center of the points in their proximity 79 | avg_dist = 0 80 | err = epsilon + 1 81 | num_iter = 0 82 | while err > epsilon: 83 | # find closest codevectors for each vector in data (find the proximity of each codevector) 84 | closest_c_list = [None] * _size_data # list that contains the nearest codevector for each input data vector 85 | vecs_near_c = defaultdict(list) # list with codevector index -> input data vector mapping 86 | vec_idxs_near_c = defaultdict(list) # list with codevector index -> input data index mapping 87 | for i, vec in enumerate(data): # for each input vector 88 | min_dist = None 89 | closest_c_index = None 90 | for i_c, c in enumerate(codebook): # for each codevector 91 | d = euclid_squared(vec, c) 92 | if min_dist is None or d < min_dist: # found new closest codevector 93 | min_dist = d 94 | closest_c_list[i] = c 95 | closest_c_index = i_c 96 | vecs_near_c[closest_c_index].append(vec) 97 | vec_idxs_near_c[closest_c_index].append(i) 98 | 99 | # update codebook: recalculate each codevector so that it sits in the center of the points in their proximity 100 | for i_c in range(len_codebook): # for each codevector index 101 | vecs = vecs_near_c.get(i_c) or [] # get its proximity input vectors 102 | num_vecs_near_c = len(vecs) 103 | if num_vecs_near_c > 0: 104 | new_c = avg_vec_of_vecs(vecs, _dim) # calculate the new center 105 | codebook[i_c] = new_c # update in codebook 106 | for i in vec_idxs_near_c[i_c]: # update in input vector index -> codevector mapping list 107 | closest_c_list[i] = new_c 108 | 109 | # update the weights 110 | abs_weights[i_c] = num_vecs_near_c 111 | rel_weights[i_c] = num_vecs_near_c / _size_data 112 | 113 | # recalculate average distortion value 114 | prev_avg_dist = avg_dist if avg_dist > 0 else initial_avg_dist 115 | avg_dist = avg_distortion_c_list(closest_c_list, data) 116 | 117 | # recalculate the new error value 118 | err = (prev_avg_dist - avg_dist) / prev_avg_dist 119 | # print(closest_c_list) 120 | # print('> iteration', num_iter, 'avg_dist', avg_dist, 'prev_avg_dist', prev_avg_dist, 'err', err) 121 | 122 | num_iter += 1 123 | 124 | return codebook, abs_weights, rel_weights, avg_dist 125 | 126 | 127 | def avg_vec_of_vecs(vecs, dim=None, size=None): 128 | """ 129 | Calculcate average vector (center vector) for input vectors . 130 | :param vecs: input vectors 131 | :param dim: dimension of if it was already calculated 132 | :param size: size of if it was already calculated 133 | :return average vector (center vector) for input vectors 134 | """ 135 | size = size or len(vecs) 136 | dim = dim or len(vecs[0]) 137 | avg_vec = [0.0] * dim 138 | for vec in vecs: 139 | for i, x in enumerate(vec): 140 | avg_vec[i] += x / size 141 | 142 | return avg_vec 143 | 144 | 145 | def new_codevector(c, e): 146 | """ 147 | Create a new codevector based on but moved by factor 148 | :param c: base codevector 149 | :param e: move factor 150 | :return new codevector 151 | """ 152 | return [x * (1.0 + e) for x in c] 153 | 154 | 155 | def avg_distortion_c0(c0, data, size=None): 156 | """ 157 | Average distortion of in relation to (i.e. how good does describe ?). 158 | :param c0: comparison vector 159 | :param data: sample data 160 | :param size: size of if it was already calculated 161 | :return average distortion 162 | """ 163 | size = size or _size_data 164 | return reduce(lambda s, d: s + d / size, 165 | (euclid_squared(c0, vec) 166 | for vec in data), 167 | 0.0) 168 | 169 | 170 | def avg_distortion_c_list(c_list, data, size=None): 171 | """ 172 | Average distortion between input samples and a list that contains a codevector for each point in 173 | . 174 | :param c_list: list that contains a codevector for each point in 175 | :param data: input samples 176 | :param size: Size of if it was already calculated 177 | :return: 178 | """ 179 | size = size or _size_data 180 | return reduce(lambda s, d: s + d / size, 181 | (euclid_squared(c_i, data[i]) 182 | for i, c_i in enumerate(c_list)), 183 | 0.0) 184 | 185 | 186 | def euclid_squared(a, b): 187 | return sum((x_a - x_b) ** 2 for x_a, x_b in zip(a, b)) 188 | 189 | 190 | # def euclid(a, b): 191 | # return math.sqrt(euclid_squared(a, b)) 192 | -------------------------------------------------------------------------------- /lbg_test.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Linde-Buzo-Gray Lib Tests\n", 8 | "\n", 9 | "## Generate codebooks of different size from fixed 3D-data" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 2, 15 | "metadata": { 16 | "collapsed": false 17 | }, 18 | "outputs": [ 19 | { 20 | "name": "stdout", 21 | "output_type": "stream", 22 | "text": [ 23 | "generating codebook for size 1\n", 24 | "output:\n", 25 | "> [0.375, -0.375, 0.6624999999999999], abs_weight=8, rel_weight=1.000000\n", 26 | "generating codebook for size 2\n", 27 | "output:\n", 28 | "> [0.5, 1.625, 3.4499999999999997], abs_weight=4, rel_weight=0.500000\n", 29 | "> [0.25, -2.375, -2.125], abs_weight=4, rel_weight=0.500000\n", 30 | "generating codebook for size 4\n", 31 | "output:\n", 32 | "> [-0.25, 2.0, 5.3], abs_weight=2, rel_weight=0.250000\n", 33 | "> [1.25, 1.25, 1.6], abs_weight=2, rel_weight=0.250000\n", 34 | "> [1.0, -2.5, -2.833333333333333], abs_weight=3, rel_weight=0.375000\n", 35 | "> [-2.0, -2.0, 0.0], abs_weight=1, rel_weight=0.125000\n", 36 | "generating codebook for size 8\n", 37 | "output:\n", 38 | "> [1.0, 2.0, 5.6], abs_weight=1, rel_weight=0.125000\n", 39 | "> [-1.5, 2.0, 5.0], abs_weight=1, rel_weight=0.125000\n", 40 | "> [1.0, 1.0, 2.0], abs_weight=1, rel_weight=0.125000\n", 41 | "> [1.5, 1.5, 1.2], abs_weight=1, rel_weight=0.125000\n", 42 | "> [1.0, -2.5, -4.5], abs_weight=1, rel_weight=0.125000\n", 43 | "> [1.0, -2.5, -2.0], abs_weight=2, rel_weight=0.250000\n", 44 | "> [-2.00002, -2.00002, 0.0], abs_weight=0, rel_weight=0.000000\n", 45 | "> [-2.0, -2.0, 0.0], abs_weight=1, rel_weight=0.125000\n" 46 | ] 47 | } 48 | ], 49 | "source": [ 50 | "import lbg \n", 51 | "\n", 52 | "testdata = [(-1.5, 2.0, 5.0),\n", 53 | " (-2.0, -2.0, 0.0),\n", 54 | " (1.0, 1.0, 2.0),\n", 55 | " (1.5, 1.5, 1.2),\n", 56 | " (1.0, 2.0, 5.6),\n", 57 | " (1.0, -2.0, -2.0),\n", 58 | " (1.0, -3.0, -2.0),\n", 59 | " (1.0, -2.5, -4.5)]\n", 60 | "\n", 61 | "for cb_size in (1, 2, 4, 8):\n", 62 | " print('generating codebook for size', cb_size)\n", 63 | " cb, cb_abs_w, cb_rel_w = lbg.generate_codebook(testdata, cb_size)\n", 64 | " print('output:')\n", 65 | " for i, c in enumerate(cb):\n", 66 | " print('> %s, abs_weight=%d, rel_weight=%f' % (c, cb_abs_w[i], cb_rel_w[i]))" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "metadata": {}, 72 | "source": [ 73 | "## Generate codebook for random Gauss distribution" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 8, 79 | "metadata": { 80 | "collapsed": false 81 | }, 82 | "outputs": [ 83 | { 84 | "name": "stdout", 85 | "output_type": "stream", 86 | "text": [ 87 | "CPU times: user 6.89 ms, sys: 139 µs, total: 7.03 ms\n", 88 | "Wall time: 7.17 ms\n" 89 | ] 90 | }, 91 | { 92 | "data": { 93 | "image/png": "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\n", 94 | "text/plain": [ 95 | "" 96 | ] 97 | }, 98 | "metadata": {}, 99 | "output_type": "display_data" 100 | } 101 | ], 102 | "source": [ 103 | "import matplotlib.pyplot as plt\n", 104 | "\n", 105 | "import random\n", 106 | "import lbg\n", 107 | "\n", 108 | "%matplotlib inline\n", 109 | "\n", 110 | "N = 40 # population size\n", 111 | "SIZE_CODEBOOK = 8\n", 112 | "\n", 113 | "random.seed(0)\n", 114 | "\n", 115 | "# generate random Gauss distribution with µ=0, sigma=1\n", 116 | "population = [(random.gauss(0, 1), random.gauss(0, 1))\n", 117 | " for _ in range(N)]\n", 118 | "\n", 119 | "# display population as blue crosses\n", 120 | "plt.scatter([p[0] for p in population], [p[1] for p in population], marker='x', color='blue')\n", 121 | "\n", 122 | "# generate codebook\n", 123 | "%time cb, cb_abs_w, cb_rel_w = lbg.generate_codebook(population, SIZE_CODEBOOK)\n", 124 | "\n", 125 | "# display codebook as red filled circles\n", 126 | "# codevectors with higher weight (more points near them) get bigger radius\n", 127 | "plt.scatter([p[0] for p in cb], [p[1] for p in cb], s=[((w+1) ** 5) * 40 for w in cb_rel_w], marker='o', color='red')\n", 128 | "\n", 129 | "plt.show()" 130 | ] 131 | }, 132 | { 133 | "cell_type": "markdown", 134 | "metadata": {}, 135 | "source": [ 136 | "## Generate codebook for population that is centered in several areas" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": 10, 142 | "metadata": { 143 | "collapsed": false 144 | }, 145 | "outputs": [ 146 | { 147 | "name": "stdout", 148 | "output_type": "stream", 149 | "text": [ 150 | "CPU times: user 8.75 ms, sys: 227 µs, total: 8.98 ms\n", 151 | "Wall time: 8.87 ms\n" 152 | ] 153 | }, 154 | { 155 | "data": { 156 | "image/png": "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\n", 157 | "text/plain": [ 158 | "" 159 | ] 160 | }, 161 | "metadata": {}, 162 | "output_type": "display_data" 163 | } 164 | ], 165 | "source": [ 166 | "import random\n", 167 | "import matplotlib.pyplot as plt\n", 168 | "\n", 169 | "import lbg\n", 170 | "\n", 171 | "%matplotlib inline\n", 172 | "\n", 173 | "NUM_AREAS = 8\n", 174 | "NUM_POINTS_PER_AREA = 10\n", 175 | "SIZE_CODEBOOK = 8\n", 176 | "AREA_MIN_MAX = ((-20, 20), (-20, 20))\n", 177 | "\n", 178 | "random.seed(0)\n", 179 | "\n", 180 | "# create random centroids for NUM_AREAS areas\n", 181 | "area_centroids = [(random.uniform(*AREA_MIN_MAX[0]), random.uniform(*AREA_MIN_MAX[1]))\n", 182 | " for _ in range(NUM_AREAS)]\n", 183 | "\n", 184 | "# display random centroids as orange cicles\n", 185 | "plt.scatter([p[0] for p in area_centroids], [p[1] for p in area_centroids], marker='o', color='orange')\n", 186 | "\n", 187 | "# create whole population\n", 188 | "population = []\n", 189 | "for c in area_centroids:\n", 190 | " # create random points around the centroid c\n", 191 | " area_points = [(random.gauss(c[0], 1.0), random.gauss(c[1], 1.0)) for _ in range(NUM_POINTS_PER_AREA)]\n", 192 | " population.extend(area_points)\n", 193 | "\n", 194 | "# display the population as blue crosses\n", 195 | "plt.scatter([p[0] for p in population], [p[1] for p in population], marker='x', color='blue')\n", 196 | "\n", 197 | "# generate codebook\n", 198 | "%time cb, cb_abs_w, cb_rel_w = lbg.generate_codebook(population, SIZE_CODEBOOK)\n", 199 | "\n", 200 | "# display codebook as red filled circles\n", 201 | "# codevectors with higher weight (more points near them) get bigger radius\n", 202 | "plt.scatter([p[0] for p in cb], [p[1] for p in cb], s=[((w+1) ** 5) * 40 for w in cb_rel_w], marker='o', color='red')\n", 203 | "\n", 204 | "plt.show()\n" 205 | ] 206 | }, 207 | { 208 | "cell_type": "code", 209 | "execution_count": null, 210 | "metadata": { 211 | "collapsed": true 212 | }, 213 | "outputs": [], 214 | "source": [] 215 | } 216 | ], 217 | "metadata": { 218 | "kernelspec": { 219 | "display_name": "Python 3", 220 | "language": "python", 221 | "name": "python3" 222 | }, 223 | "language_info": { 224 | "codemirror_mode": { 225 | "name": "ipython", 226 | "version": 3 227 | }, 228 | "file_extension": ".py", 229 | "mimetype": "text/x-python", 230 | "name": "python", 231 | "nbconvert_exporter": "python", 232 | "pygments_lexer": "ipython3", 233 | "version": "3.4.4" 234 | } 235 | }, 236 | "nbformat": 4, 237 | "nbformat_minor": 0 238 | } 239 | --------------------------------------------------------------------------------