From 9889a51e1326244d5d7745e877265f9b142b4b56 Mon Sep 17 00:00:00 2001 From: Taylor Bockman Date: Wed, 16 Oct 2019 13:41:05 -0700 Subject: [PATCH] init --- .gitignore | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 5 +++ example.png | Bin 0 -> 32522 bytes main.py | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 28 +++++++++++++ run_sample.sh | 1 + 6 files changed, 273 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 example.png create mode 100644 main.py create mode 100644 requirements.txt create mode 100644 run_sample.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f717486 --- /dev/null +++ b/.gitignore @@ -0,0 +1,125 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..393edcd --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# K-Means Example + +An example project using the `kmeans` library. + +![](example.png) diff --git a/example.png b/example.png new file mode 100644 index 0000000000000000000000000000000000000000..18118e4d9038a224116da02e4a3603748002e985 GIT binary patch literal 32522 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 List: + """ + Generates random points without replacement bounded by (x_bound, y_bound) + + @param x_bound The x direction boundary. + @param y_bound The y direction boundary. + @param count The count of points. + """ + xs = random.sample(range(0, x_bound), count) + + ys = random.sample(range(0, y_bound), count) + + points = list(zip(xs, ys)) + + result = [] + for p in points: + result.append(Point(p[0], p[1])) + + return result + + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], "x:y:r:", + ['x=', 'y=', 'random=']) + except getopt.GetoptError as err: + print('Option not recognized') + sys.exit(-1) + + x = None + y = None + random = None + + for o, a in opts: + if o in ('-x', '--x'): + x = int(a) + elif o in ('-y', '--y'): + y = int(a) + elif o in ('-r', '--random'): + random = int(a) + else: + print(f'Unknown option {o}\n') + sys.exit(-1) + + if x is None or y is None or random is None: + print('x, y, and r must be specified\n') + sys.exit(-1) + + points = generate_points(x, y, random) + + print('--- INITIAL POINT PLOT ---') + xs = [p.x for p in points] + ys = [p.y for p in points] + plt.plot(xs, ys, 'o') + plt.show() + + clusters = unweighted_k_means(points, 4, 0.001) + + # Color clusters + assigned_colors = plt.cm.gist_ncar(np.linspace(0, 1, 4)) + + for i, cluster in enumerate(clusters): + cluster.color = assigned_colors[i] + + print('--- CLUSTER PLOT ---') + for cluster in clusters: + xs = [p.x for p in cluster.points] + ys = [p.y for p in cluster.points] + plt.plot(xs, ys, 'o', cluster.color) + + plt.show() + + print('--- CLUSTER PLOT WITH CONVEX HULL BOUNDARIES ---') + for cluster in clusters: + xs = [p.x for p in cluster.points] + ys = [p.y for p in cluster.points] + plt.plot(xs, ys, 'o', cluster.color) + + # Convex hull plot + if len(cluster.points) >= 4: + points = np.array([p.array() for p in cluster.points]) + + try: + hull = ConvexHull(points) + except QhullError as e: + print(str(e)) + continue + + plt.plot(points[hull.vertices, 0], + points[hull.vertices, 1], 'r--', lw=2) + + plt.plot(points[hull.vertices[0], 0], + points[hull.vertices[0], 1], 'ro') + + plt.show() + + +if __name__ == '__main__': + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b912431 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,28 @@ +asn1crypto==0.24.0 +autopep8==1.4.4 +behave==1.2.6 +certifi==2019.9.11 +cffi==1.12.3 +chardet==3.0.4 +cryptography==2.7 +cycler==0.10.0 +Cython==0.29.13 +decorator==4.4.0 +entrypoints==0.3 +flake8==3.7.8 +kiwisolver==1.1.0 +matplotlib==3.1.1 +mccabe==0.6.1 +numpy==1.17.2 +parse==1.12.1 +parse-type==0.5.2 +pycodestyle==2.5.0 +pycparser==2.19 +pyflakes==2.1.1 +pyparsing==2.4.2 +python-dateutil==2.8.0 +scipy==1.3.1 +six==1.12.0 + + +-e git+git://git.xchg.sh/angrygoats/kmeans.git@master#egg=kmeans diff --git a/run_sample.sh b/run_sample.sh new file mode 100644 index 0000000..5a46272 --- /dev/null +++ b/run_sample.sh @@ -0,0 +1 @@ +python main.py -x 100 -y 100 -r 50