From 097fd048d9a04a5ad3481d66bf76e9bd69fed367 Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Tue, 3 May 2022 13:49:48 -0500 Subject: [PATCH 01/22] Add zenodo permanent doi to README --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 05d2b6bd..6da26790 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,13 @@ A Julia package for Adaptive Resonance Theory (ART) algorithms. | **Dependents** | **Date** | **Status** | | [![deps][deps-img]][deps-url] | [![version][version-img]][version-url] | [![pkgeval][pkgeval-img]][pkgeval-url] | +| **Zenodo DOI** | +| :------------: | +| [![DOI][zenodo-img]][zenodo-url] | + +[zenodo-img]: https://zenodo.org/badge/DOI/10.5281/zenodo.5748453.svg +[zenodo-url]: https://doi.org/10.5281/zenodo.5748453 + [deps-img]: https://juliahub.com/docs/AdaptiveResonance/deps.svg [deps-url]: https://juliahub.com/ui/Packages/AdaptiveResonance/Sm0We?t=2 From 034825a97e83060868cedaa2618a03d3e929e1ea Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Tue, 3 May 2022 13:59:36 -0500 Subject: [PATCH 02/22] Test only 1.6 LTS and latest Julia versions --- .github/workflows/CI.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index b1c8e78a..53dc7dea 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -15,8 +15,7 @@ jobs: fail-fast: false matrix: version: - # - "1.0" # LTS - - "1.5" + - "1.6" # LTS - "1" # Latest Release os: - ubuntu-latest From c75cd51dee32a7da8dae2b3803f47c015e8f4e34 Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Tue, 3 May 2022 14:01:50 -0500 Subject: [PATCH 03/22] Clean up CI comments --- .github/workflows/CI.yml | 120 +-------------------------------------- 1 file changed, 2 insertions(+), 118 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 53dc7dea..bfddbacf 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -1,8 +1,8 @@ name: CI # Run on master, tags, or any pull request on: - # schedule: - # - cron: '0 2 * * *' # Daily at 2 AM UTC (8 PM CST) +# schedule: +# - cron: '0 2 * * *' # Daily at 2 AM UTC (8 PM CST) push: branches: [master] tags: ["*"] @@ -78,119 +78,3 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: lcov.info - - # slack: - # name: Notify Slack Failure - # needs: test - # runs-on: ubuntu-latest - # if: always() && github.event_name == 'schedule' - # steps: - # - uses: technote-space/workflow-conclusion-action@v2 - # - uses: voxmedia/github-action-slack-notify-build@v1 - # if: env.WORKFLOW_CONCLUSION == 'failure' - # with: - # channel: nightly-dev - # status: FAILED - # color: danger - # env: - # SLACK_BOT_TOKEN: ${{ secrets.DEV_SLACK_BOT_TOKEN }} - - # docs: - # name: Documentation - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v2 - # - uses: julia-actions/setup-julia@v1 - # with: - # version: '1' - # - run: | - # git config --global user.name name - # git config --global user.email email - # git config --global github.user username - # - run: | - # julia --project=docs -e ' - # using Pkg - # Pkg.develop(PackageSpec(path=pwd())) - # Pkg.instantiate()' - # - run: | - # julia --project=docs -e ' - # using Documenter: doctest - # using PkgTemplates - # doctest(PkgTemplates)' - # - run: julia --project=docs docs/make.jl - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} - -# # This is a basic workflow to help you get started with Actions - -# name: Unit Test - -# # Controls when the action will run. -# on: -# # Triggers the workflow on push or pull request events but only for the master branch -# push: -# branches: [ master ] -# pull_request: -# branches: [ master ] - -# # Allows you to run this workflow manually from the Actions tab -# workflow_dispatch: - -# # A workflow run is made up of one or more jobs that can run sequentially or in parallel -# jobs: -# # This workflow contains a single job called "build" -# build: -# # The type of runner that the job will run on -# # runs-on: ubuntu-latest -# strategy: -# matrix: -# julia: [1.5, latest] -# # Steps represent a sequence of tasks that will be executed as part of the job -# steps: -# # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it -# - uses: actions/checkout@v2 - -# # Runs a single command using the runners shell -# - name: Run a one-line script -# run: echo Hello, world! - -# # Runs a set of commands using the runners shell -# - name: Run a multi-line script -# run: | -# echo Add other actions to build, -# echo test, and deploy your project. - - -# name: Python package - -# on: [push] - -# jobs: -# build: - -# runs-on: ubuntu-latest -# strategy: -# matrix: -# python-version: [2.7, 3.5, 3.6, 3.7, 3.8] - -# steps: -# - uses: actions/checkout@v2 -# - name: Set up Python ${{ matrix.python-version }} -# uses: actions/setup-python@v2 -# with: -# python-version: ${{ matrix.python-version }} -# - name: Install dependencies -# run: | -# python -m pip install --upgrade pip -# pip install flake8 pytest -# if [ -f requirements.txt ]; then pip install -r requirements.txt; fi -# - name: Lint with flake8 -# run: | -# # stop the build if there are Python syntax errors or undefined names -# flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics -# # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide -# flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics -# - name: Test with pytest -# run: | -# pytest From 3b857baeadc8b94efdf93a6ea771b1606419d9f4 Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Tue, 3 May 2022 14:45:54 -0500 Subject: [PATCH 04/22] Raise flag for x86 CI testing --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index bfddbacf..cd020659 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -23,7 +23,7 @@ jobs: - windows-latest arch: - x64 - # - x86 + - x86 # exclude: # Test 32-bit only on Linux # - os: macOS-latest From 3a9078bde4c41ef22191118228a6027b800dffd7 Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Tue, 3 May 2022 14:51:23 -0500 Subject: [PATCH 05/22] Raise the flag for macOS CI testing --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index bfddbacf..0aa72250 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -19,7 +19,7 @@ jobs: - "1" # Latest Release os: - ubuntu-latest - # - macOS-latest + - macOS-latest - windows-latest arch: - x64 From 43708298c955b69dacded9df552529c00c72a5d9 Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Tue, 3 May 2022 16:18:06 -0500 Subject: [PATCH 06/22] Exclude 32-bit macOS from CI due to Julia support --- .github/workflows/CI.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 3f0743da..3ce89aab 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -24,10 +24,10 @@ jobs: arch: - x64 - x86 - # exclude: - # Test 32-bit only on Linux - # - os: macOS-latest - # arch: x86 + exclude: + # Exclude 32-bit macOS due to Julia support + - os: macOS-latest + arch: x86 # - os: windows-latest # arch: x86 # include: From 875927a44a16cc411c1bd1860e1b269fd5d0e8e2 Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Thu, 5 May 2022 13:05:03 -0500 Subject: [PATCH 07/22] Update Documentation CI script --- .github/workflows/Documentation.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/Documentation.yml b/.github/workflows/Documentation.yml index 1f11a53c..2aa1b278 100644 --- a/.github/workflows/Documentation.yml +++ b/.github/workflows/Documentation.yml @@ -15,18 +15,16 @@ jobs: # Cancel ongoing documentation build if pushing to branch again before the previous # build is finished. - name: Cancel ongoing documentation builds for previous commits - uses: styfle/cancel-workflow-action@0.6.0 + uses: styfle/cancel-workflow-action@0.9.1 with: access_token: ${{ github.token }} - uses: actions/checkout@v2 - uses: julia-actions/setup-julia@latest with: - version: '1.4' + version: '1.6' - name: Install dependencies - run: | - pip install scipy - julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' + run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' - name: Build and deploy env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # For authentication with GitHub Actions token From 4c153596d846a70b68cb663ca96b3db91fc0b0ad Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Thu, 5 May 2022 13:05:23 -0500 Subject: [PATCH 08/22] Update README with reference column, reorganize --- README.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 6da26790..bcc0b88f 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,20 @@ # AdaptiveResonance A Julia package for Adaptive Resonance Theory (ART) algorithms. +d -| **Documentation** | **Build Status** | **Coverage** | -|:------------------:|:----------------:|:------------:| -| [![Stable][docs-stable-img]][docs-stable-url] | [![Build Status][ci-img]][ci-url] | [![Codecov][codecov-img]][codecov-url] | -| [![Dev][docs-dev-img]][docs-dev-url] | [![Build Status][appveyor-img]][appveyor-url] | [![Coveralls][coveralls-img]][coveralls-url] | -| **Dependents** | **Date** | **Status** | -| [![deps][deps-img]][deps-url] | [![version][version-img]][version-url] | [![pkgeval][pkgeval-img]][pkgeval-url] | +| **Documentation** | **Testing Status** | **Coverage** | **Reference** | +|:------------------:|:----------------:|:------------:|:-------------:| +| [![Stable][docs-stable-img]][docs-stable-url] | [![Build Status][ci-img]][ci-url] | [![Codecov][codecov-img]][codecov-url] | [![DOI][joss-img]][joss-url] | +| [![Dev][docs-dev-img]][docs-dev-url] | [![Build Status][appveyor-img]][appveyor-url] | [![Coveralls][coveralls-img]][coveralls-url] | [![DOI][zenodo-img]][zenodo-url] | +| **Documentation Build** | **JuliaHub Status** | **Dependents** | **Release** | +| [![Documentation][doc-status-img]][doc-status-url] | [![pkgeval][pkgeval-img]][pkgeval-url] | [![deps][deps-img]][deps-url] | [![version][version-img]][version-url] | -| **Zenodo DOI** | -| :------------: | -| [![DOI][zenodo-img]][zenodo-url] | +[joss-img]: https://joss.theoj.org/papers/10.21105/joss.03671/status.svg +[joss-url]: https://doi.org/10.21105/joss.03671 + +[doc-status-img]: https://github.com/AP6YC/AdaptiveResonance.jl/actions/workflows/Documentation.yml/badge.svg +[doc-status-url]: https://github.com/AP6YC/AdaptiveResonance.jl/actions/workflows/Documentation.yml [zenodo-img]: https://zenodo.org/badge/DOI/10.5281/zenodo.5748453.svg [zenodo-url]: https://doi.org/10.5281/zenodo.5748453 From 687b88a38c8aae6a237e8acdc40087ae33eb6b75 Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Thu, 5 May 2022 14:09:17 -0500 Subject: [PATCH 09/22] Add PyPlot dep, update plots to use pyplot backend --- docs/Project.toml | 1 + docs/examples/adaptive_resonance/options.jl | 8 ++++++-- docs/src/getting-started/basic-example.md | 4 ++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/Project.toml b/docs/Project.toml index e5bf2d7a..0ed792ac 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -8,3 +8,4 @@ MLDataUtils = "cc2ba9b6-d476-5e6d-8eaf-a92d5412d41d" MLDatasets = "eb30cadb-4394-5ae3-aed4-317e484a6458" MultivariateStats = "6f286f6a-111f-5878-ab1e-185364afe411" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" diff --git a/docs/examples/adaptive_resonance/options.jl b/docs/examples/adaptive_resonance/options.jl index e6611a96..24d554bc 100644 --- a/docs/examples/adaptive_resonance/options.jl +++ b/docs/examples/adaptive_resonance/options.jl @@ -1,7 +1,7 @@ # --- # title: ART Options Example # id: options -# cover: ../assets/art.png +# cover: options-cover.png # date: 2021-12-2 # author: "[Sasha Petrenko](https://github.com/AP6YC)" # julia: 1.6 @@ -91,7 +91,8 @@ using MLDatasets # Iris dataset using MLDataUtils # Shuffling and splitting using Printf # Formatted number printing using MultivariateStats # Principal component analysis (PCA) -using Plots # Plotting +using Plots # Plotting frontend +pyplot() # Use PyPlot backend # We will download the Iris dataset for its small size and benchmark use for clustering algorithms. Iris.download(i_accept_the_terms_of_use=true) @@ -156,3 +157,6 @@ X_test_pca = transform(M, X_test) p1 = scatter(X_test_pca[1,:], X_test_pca[2,:], group=y_hat_1, title=@sprintf "FuzzyART rho = %.1f" rho_1) p2 = scatter(X_test_pca[1,:], X_test_pca[2,:], group=y_hat_2, title=@sprintf "FuzzyART rho = %.1f" rho_2) plot(p1, p2, layout=(1, 2), legend = false, xtickfontsize=6, xguidefontsize=8, titlefont=font(8)) + +# Super neat! +png("options-cover") #hide \ No newline at end of file diff --git a/docs/src/getting-started/basic-example.md b/docs/src/getting-started/basic-example.md index 70e08b21..95f39c68 100644 --- a/docs/src/getting-started/basic-example.md +++ b/docs/src/getting-started/basic-example.md @@ -1,7 +1,10 @@ # Basic Example +This page demonstrates a full basic example of an `AdaptiveResonance.jl` workflow. In the example below, we create a dataset generated from two multivariate Gaussian distributions in two dimensions, showing how an ART module can be used in unsupervised or simple supervised modes alongside an ARTMAP module that is explicitly supervised-only. +For more examples that you can run yourself in Julia notebooks, see the [Examples](@ref examples) page. + ```@example # Copyright © 2021 Alexander L. Hayes # MIT License @@ -10,6 +13,7 @@ using AdaptiveResonance using Distributions, Random using MLDataUtils using Plots +pyplot() """ Demonstrates Unsupervised DDVFA, Supervised DDVFA, and (Supervised) SFAM on a toy problem From b704a039142a145e43e26f1d70e9482ed06ee0fd Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Thu, 5 May 2022 14:09:32 -0500 Subject: [PATCH 10/22] Add combo convenience script, reorganize --- docs/combo.jl | 12 ++++++++++++ docs/serve.jl | 5 +---- 2 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 docs/combo.jl diff --git a/docs/combo.jl b/docs/combo.jl new file mode 100644 index 00000000..0df0e931 --- /dev/null +++ b/docs/combo.jl @@ -0,0 +1,12 @@ +""" + combo.jl + +This is a convenience script for docs development that makes and live serves the docs locally. +""" + + +# Make the documentation +include("make.jl") + +# Host the documentation locally +include("serve.jl") diff --git a/docs/serve.jl b/docs/serve.jl index 0a4b860c..6e893a0c 100644 --- a/docs/serve.jl +++ b/docs/serve.jl @@ -1,13 +1,10 @@ """ serve.jl -This is a convenience script for docs development that +Convenience script that serves the locally built documentation. """ using LiveServer -# Make the documentation -include("make.jl") - # Serve the documentation for development serve(dir="build") From 510ccfdcd58324ee2f3f4f399d1c6552a6886b25 Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Thu, 5 May 2022 16:19:03 -0500 Subject: [PATCH 11/22] Develop example generated figures --- .../adaptive_resonance/incremental-batch.jl | 40 ++++++++++++++++++- docs/examples/adaptive_resonance/options.jl | 36 ++++++++++++++--- 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/docs/examples/adaptive_resonance/incremental-batch.jl b/docs/examples/adaptive_resonance/incremental-batch.jl index 65bcc207..c22a5fb0 100644 --- a/docs/examples/adaptive_resonance/incremental-batch.jl +++ b/docs/examples/adaptive_resonance/incremental-batch.jl @@ -1,7 +1,7 @@ # --- # title: Incremental vs. Batch Example # id: incremental_batch -# cover: ../assets/art.png +# cover: incremental-batch-cover.png # date: 2021-12-1 # author: "[Sasha Petrenko](https://github.com/AP6YC)" # julia: 1.6 @@ -109,3 +109,41 @@ perf_test_incremental = performance(y_hat_incremental, y_test) @printf "Incremental training performance: %.4f\n" perf_train_incremental @printf "Batch testing performance: %.4f\n" perf_test_batch @printf "Incremental testing performance: %.4f\n" perf_test_incremental + +# Let's plot! +using Printf # Formatted number printing +using MultivariateStats # Principal component analysis (PCA) +using Plots # Plotting frontend +pyplot() # Use PyPlot backend + +## Train a PCA model +M = fit(PCA, features; maxoutdim=2) + +## Apply the PCA model to the testing set +X_test_pca = transform(M, X_test) + +# Plot + +## Create a scatterplot object from the data +p1 = scatter( + X_test_pca[1, :], # PCA dimension 1 + X_test_pca[2, :], # PCA dimension 2 + group = y_hat_batch, # labels belonging to each point + markersize = 8, # size of scatter points + title = @sprintf "DDVFA" # formatted title +) + +## Plot the scatterplot with some additonal formatting options +plot( + p1, # the scatterplot object + legend = false, # no legend + xtickfontsize = 12, # x-tick size + ytickfontsize = 12, # y-tick size + dpi = 300, # Set the dots-per-inch + xlims = :round, # Round up the x-limits to the nearest whole number + xlabel = "\$PCA_1\$", # x-label + ylabel = "\$PCA_2\$", # y-label +) + +# Neat! +png("incremental-batch-cover") #hide \ No newline at end of file diff --git a/docs/examples/adaptive_resonance/options.jl b/docs/examples/adaptive_resonance/options.jl index 24d554bc..dfcec2b5 100644 --- a/docs/examples/adaptive_resonance/options.jl +++ b/docs/examples/adaptive_resonance/options.jl @@ -154,9 +154,35 @@ M = fit(PCA, features; maxoutdim=2) X_test_pca = transform(M, X_test) # We can now plot the PCA'ed test set and label them according to the two FuzzyART's -p1 = scatter(X_test_pca[1,:], X_test_pca[2,:], group=y_hat_1, title=@sprintf "FuzzyART rho = %.1f" rho_1) -p2 = scatter(X_test_pca[1,:], X_test_pca[2,:], group=y_hat_2, title=@sprintf "FuzzyART rho = %.1f" rho_2) -plot(p1, p2, layout=(1, 2), legend = false, xtickfontsize=6, xguidefontsize=8, titlefont=font(8)) -# Super neat! -png("options-cover") #hide \ No newline at end of file +## Create the two scatterplot objects +p1 = scatter( + X_test_pca[1, :], + X_test_pca[2, :], + group=y_hat_1, + markersize=8, + title=@sprintf "FuzzyART \$\\rho\$ = %.1f" rho_1 +) +p2 = scatter( + X_test_pca[1, :], # PCA dimension 1 + X_test_pca[2, :], # PCA dimension 2 + group = y_hat_2, # labels belonging to each point + markersize = 8, # size of scatter points + title=@sprintf "FuzzyART \$\\rho\$ = %.1f" rho_2 # formatted title +) + +## Plot the two scatterplots together +plot( + p1, p2, # scatterplot objects + layout = (1, 2), # plot side-by-side + legend = false, # no legend + xtickfontsize = 12, # x-tick size + ytickfontsize = 12, # y-tick size + dpi = 300, # Set the dots-per-inch + xlims = :round, # Round up the x-limits to the nearest whole number + xlabel = "\$PCA_1\$", # x-label + ylabel = "\$PCA_2\$", # y-label +) + +# We can see that the two different vigilance values result in similar resutls on the whole, though they differ in how they classify certain samples that straddle the border between +png("options-cover") #hide From 8fdd2f395191d91de9afa2db775e1663734048a3 Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Thu, 5 May 2022 16:28:28 -0500 Subject: [PATCH 12/22] Comment more in incremental-batch --- .../adaptive_resonance/incremental-batch.jl | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/examples/adaptive_resonance/incremental-batch.jl b/docs/examples/adaptive_resonance/incremental-batch.jl index c22a5fb0..e5b69c8e 100644 --- a/docs/examples/adaptive_resonance/incremental-batch.jl +++ b/docs/examples/adaptive_resonance/incremental-batch.jl @@ -110,7 +110,18 @@ perf_test_incremental = performance(y_hat_incremental, y_test) @printf "Batch testing performance: %.4f\n" perf_test_batch @printf "Incremental testing performance: %.4f\n" perf_test_incremental -# Let's plot! +# ## Visualization + +# So we showed that the performance and behavior of modules are identical in incremental and batch modes. +# Great! +# However, illustrating this point doesn't lend itself to visualization in any meaningful way. +# Nonetheless, we would like a pretty picture at the end of the experiment to verify that these identical solutions work in the first place. + +# To do this, we will reduce the dimensionality of the dataset to two dimensions and show in a scatter plot how the modules classify the test data into groups. +# This will be done with principal component analysis (PCA) to cast the points into a 2-D space while trying to preserve the relative distances between points in the higher dimension. +# The process isn't perfect by any means, but it suffices for visualization. + +## Import visualization utilities using Printf # Formatted number printing using MultivariateStats # Principal component analysis (PCA) using Plots # Plotting frontend @@ -122,7 +133,7 @@ M = fit(PCA, features; maxoutdim=2) ## Apply the PCA model to the testing set X_test_pca = transform(M, X_test) -# Plot +# Now that we have the test points cast into a 2-D set of points, we can create a scatter plot that shows how each point is categorized by the modules. ## Create a scatterplot object from the data p1 = scatter( @@ -145,5 +156,5 @@ plot( ylabel = "\$PCA_2\$", # y-label ) -# Neat! -png("incremental-batch-cover") #hide \ No newline at end of file +# This plot shows that the DDVFA modules do well at identifying the structure of the three clusters despite not achieving 100% test performance. +png("incremental-batch-cover") #hide From 5e93a54b45d4468136eb26e757d24647390623b8 Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Thu, 5 May 2022 16:37:44 -0500 Subject: [PATCH 13/22] Add asset folders for democard categories --- docs/examples/adaptive_resonance/assets/.gitkeep | 0 docs/examples/adaptive_resonance/incremental-batch.jl | 6 +++--- docs/examples/adaptive_resonance/options.jl | 4 ++-- docs/examples/art/assets/.gitkeep | 0 docs/examples/artmap/assets/.gitkeep | 0 5 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 docs/examples/adaptive_resonance/assets/.gitkeep create mode 100644 docs/examples/art/assets/.gitkeep create mode 100644 docs/examples/artmap/assets/.gitkeep diff --git a/docs/examples/adaptive_resonance/assets/.gitkeep b/docs/examples/adaptive_resonance/assets/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/examples/adaptive_resonance/incremental-batch.jl b/docs/examples/adaptive_resonance/incremental-batch.jl index e5b69c8e..e771759a 100644 --- a/docs/examples/adaptive_resonance/incremental-batch.jl +++ b/docs/examples/adaptive_resonance/incremental-batch.jl @@ -1,7 +1,7 @@ # --- # title: Incremental vs. Batch Example # id: incremental_batch -# cover: incremental-batch-cover.png +# cover: assets/incremental-batch-cover.png # date: 2021-12-1 # author: "[Sasha Petrenko](https://github.com/AP6YC)" # julia: 1.6 @@ -141,7 +141,7 @@ p1 = scatter( X_test_pca[2, :], # PCA dimension 2 group = y_hat_batch, # labels belonging to each point markersize = 8, # size of scatter points - title = @sprintf "DDVFA" # formatted title + title = @sprintf "DDVFA Iris Clusters" # formatted title ) ## Plot the scatterplot with some additonal formatting options @@ -157,4 +157,4 @@ plot( ) # This plot shows that the DDVFA modules do well at identifying the structure of the three clusters despite not achieving 100% test performance. -png("incremental-batch-cover") #hide +png("assets/incremental-batch-cover") #hide diff --git a/docs/examples/adaptive_resonance/options.jl b/docs/examples/adaptive_resonance/options.jl index dfcec2b5..0293973b 100644 --- a/docs/examples/adaptive_resonance/options.jl +++ b/docs/examples/adaptive_resonance/options.jl @@ -1,7 +1,7 @@ # --- # title: ART Options Example # id: options -# cover: options-cover.png +# cover: assets/options-cover.png # date: 2021-12-2 # author: "[Sasha Petrenko](https://github.com/AP6YC)" # julia: 1.6 @@ -185,4 +185,4 @@ plot( ) # We can see that the two different vigilance values result in similar resutls on the whole, though they differ in how they classify certain samples that straddle the border between -png("options-cover") #hide +png("assets/options-cover") #hide diff --git a/docs/examples/art/assets/.gitkeep b/docs/examples/art/assets/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/examples/artmap/assets/.gitkeep b/docs/examples/artmap/assets/.gitkeep new file mode 100644 index 00000000..e69de29b From 07c0a238cf34d5f00b1fabf78c86ba242c35a547 Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Thu, 5 May 2022 16:39:44 -0500 Subject: [PATCH 14/22] LaTeX data config line --- docs/examples/adaptive_resonance/data_config.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/examples/adaptive_resonance/data_config.jl b/docs/examples/adaptive_resonance/data_config.jl index d43badcd..4c2105ce 100644 --- a/docs/examples/adaptive_resonance/data_config.jl +++ b/docs/examples/adaptive_resonance/data_config.jl @@ -17,7 +17,7 @@ # Preprocessing of the features occurs as follows: # 1. The features are linearly normalized from 0 to 1 with respect to each feature with `linear_normalization`. # This is done according to some known bounds that each feature has. -# 2. The features are then complement coded, meaning that the feature vector is appended to its 1-complement (i.e., x -> [x, 1-x]) with `complement_code`. +# 2. The features are then complement coded, meaning that the feature vector is appended to its 1-complement (i.e., $x \rightarrow \left[x, 1-x\right]$) with `complement_code`. # This preprocessing has the ultimate consequence that the input features must be bounded. # This many not be a problem in some offline applications with a fixed dataset, but in others where the bounds are not known, techniques such as sigmoidal limiting are often used to place an artificial limit. From 967216c72c323db5aa420dc424ca422b9a92d7f5 Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Thu, 12 May 2022 15:31:37 -0500 Subject: [PATCH 15/22] Remove pyplot backend for docs figures --- docs/Project.toml | 1 - .../adaptive_resonance/incremental-batch.jl | 15 +++----- docs/examples/adaptive_resonance/options.jl | 36 ++++++++++--------- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/docs/Project.toml b/docs/Project.toml index 0ed792ac..e5bf2d7a 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -8,4 +8,3 @@ MLDataUtils = "cc2ba9b6-d476-5e6d-8eaf-a92d5412d41d" MLDatasets = "eb30cadb-4394-5ae3-aed4-317e484a6458" MultivariateStats = "6f286f6a-111f-5878-ab1e-185364afe411" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" diff --git a/docs/examples/adaptive_resonance/incremental-batch.jl b/docs/examples/adaptive_resonance/incremental-batch.jl index e771759a..4fc5beb0 100644 --- a/docs/examples/adaptive_resonance/incremental-batch.jl +++ b/docs/examples/adaptive_resonance/incremental-batch.jl @@ -114,8 +114,9 @@ perf_test_incremental = performance(y_hat_incremental, y_test) # So we showed that the performance and behavior of modules are identical in incremental and batch modes. # Great! -# However, illustrating this point doesn't lend itself to visualization in any meaningful way. +# Sadly, illustrating this point doesn't lend itself to visualization in any meaningful way. # Nonetheless, we would like a pretty picture at the end of the experiment to verify that these identical solutions work in the first place. +# Sanity checks are meaningful in their own right, right? # To do this, we will reduce the dimensionality of the dataset to two dimensions and show in a scatter plot how the modules classify the test data into groups. # This will be done with principal component analysis (PCA) to cast the points into a 2-D space while trying to preserve the relative distances between points in the higher dimension. @@ -125,7 +126,6 @@ perf_test_incremental = performance(y_hat_incremental, y_test) using Printf # Formatted number printing using MultivariateStats # Principal component analysis (PCA) using Plots # Plotting frontend -pyplot() # Use PyPlot backend ## Train a PCA model M = fit(PCA, features; maxoutdim=2) @@ -135,18 +135,12 @@ X_test_pca = transform(M, X_test) # Now that we have the test points cast into a 2-D set of points, we can create a scatter plot that shows how each point is categorized by the modules. -## Create a scatterplot object from the data -p1 = scatter( +## Create a scatterplot object from the data with some additional formatting options +scatter( X_test_pca[1, :], # PCA dimension 1 X_test_pca[2, :], # PCA dimension 2 group = y_hat_batch, # labels belonging to each point markersize = 8, # size of scatter points - title = @sprintf "DDVFA Iris Clusters" # formatted title -) - -## Plot the scatterplot with some additonal formatting options -plot( - p1, # the scatterplot object legend = false, # no legend xtickfontsize = 12, # x-tick size ytickfontsize = 12, # y-tick size @@ -154,6 +148,7 @@ plot( xlims = :round, # Round up the x-limits to the nearest whole number xlabel = "\$PCA_1\$", # x-label ylabel = "\$PCA_2\$", # y-label + title = (@sprintf "DDVFA Iris Clusters"), # formatted title ) # This plot shows that the DDVFA modules do well at identifying the structure of the three clusters despite not achieving 100% test performance. diff --git a/docs/examples/adaptive_resonance/options.jl b/docs/examples/adaptive_resonance/options.jl index 0293973b..b5696936 100644 --- a/docs/examples/adaptive_resonance/options.jl +++ b/docs/examples/adaptive_resonance/options.jl @@ -92,7 +92,6 @@ using MLDataUtils # Shuffling and splitting using Printf # Formatted number printing using MultivariateStats # Principal component analysis (PCA) using Plots # Plotting frontend -pyplot() # Use PyPlot backend # We will download the Iris dataset for its small size and benchmark use for clustering algorithms. Iris.download(i_accept_the_terms_of_use=true) @@ -154,34 +153,37 @@ M = fit(PCA, features; maxoutdim=2) X_test_pca = transform(M, X_test) # We can now plot the PCA'ed test set and label them according to the two FuzzyART's +# We will do so by creating a function for the subplots first as they will share the same format, and we dare not duplicate code. +# Then, we will plot those subplots side-by-side. + +## Create a function for our subplots +function fuzzyart_scatter(data, labels, rho) + p = scatter( + data[1, :], # PCA dimension 1 + data[2, :], # PCA dimension 2 + group=labels, # labels belonging to each point + markersize=8, # size of scatter points + xlims = [-4, 4], # manually set the x-limits + title=(@sprintf "FuzzyART \$\\rho\$ = %.1f" rho), # formatted title + ) + return p +end ## Create the two scatterplot objects -p1 = scatter( - X_test_pca[1, :], - X_test_pca[2, :], - group=y_hat_1, - markersize=8, - title=@sprintf "FuzzyART \$\\rho\$ = %.1f" rho_1 -) -p2 = scatter( - X_test_pca[1, :], # PCA dimension 1 - X_test_pca[2, :], # PCA dimension 2 - group = y_hat_2, # labels belonging to each point - markersize = 8, # size of scatter points - title=@sprintf "FuzzyART \$\\rho\$ = %.1f" rho_2 # formatted title -) +p1 = fuzzyart_scatter(X_test_pca, y_hat_1, rho_1) +p2 = fuzzyart_scatter(X_test_pca, y_hat_2, rho_2) ## Plot the two scatterplots together plot( p1, p2, # scatterplot objects layout = (1, 2), # plot side-by-side + ##layout = [a, b], # plot side-by-side legend = false, # no legend xtickfontsize = 12, # x-tick size ytickfontsize = 12, # y-tick size - dpi = 300, # Set the dots-per-inch - xlims = :round, # Round up the x-limits to the nearest whole number xlabel = "\$PCA_1\$", # x-label ylabel = "\$PCA_2\$", # y-label + dpi = 300, # Set the dots-per-inch ) # We can see that the two different vigilance values result in similar resutls on the whole, though they differ in how they classify certain samples that straddle the border between From e8e7f181cd61fc8bcfc9b428e4942405509a1b66 Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Thu, 12 May 2022 16:52:22 -0500 Subject: [PATCH 16/22] Remove pyplot from basic example --- docs/src/getting-started/basic-example.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/src/getting-started/basic-example.md b/docs/src/getting-started/basic-example.md index 95f39c68..08c9af11 100644 --- a/docs/src/getting-started/basic-example.md +++ b/docs/src/getting-started/basic-example.md @@ -13,7 +13,6 @@ using AdaptiveResonance using Distributions, Random using MLDataUtils using Plots -pyplot() """ Demonstrates Unsupervised DDVFA, Supervised DDVFA, and (Supervised) SFAM on a toy problem From c271e376ca3a95b886ff431b1bbb07f3dc4f2f8e Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Thu, 12 May 2022 17:07:37 -0500 Subject: [PATCH 17/22] Update construction methods, remove redundancies --- src/ART/DDVFA.jl | 17 ++++------------- src/ART/DVFA.jl | 21 ++++++++------------- src/ART/FuzzyART.jl | 17 ++++------------- src/ARTMAP/DAM.jl | 33 ++++++++++++++++++++------------- src/ARTMAP/FAM.jl | 29 ++++++++++++++++------------- src/ARTMAP/SFAM.jl | 33 ++++++++++++++++++++------------- 6 files changed, 72 insertions(+), 78 deletions(-) diff --git a/src/ART/DDVFA.jl b/src/ART/DDVFA.jl index 21969094..2f7634ae 100644 --- a/src/ART/DDVFA.jl +++ b/src/ART/DDVFA.jl @@ -105,11 +105,12 @@ end # DDVFA <: ART # --------------------------------------------------------------------------- # """ - DDVFA() + DDVFA(;kwargs...) -Implements a DDVFA learner with default options. +Implements a DDVFA learner with optional keyword arguments. # Examples +By default: ```julia-repl julia> DDVFA() DDVFA @@ -117,18 +118,8 @@ DDVFA subopts: opts_FuzzyART ... ``` -""" -function DDVFA() - opts = opts_DDVFA() - DDVFA(opts) -end # DDVFA() - -""" - DDVFA(;kwargs...) -Implements a DDVFA learner with keyword arguments. - -# Examples +or with keyword arguments: ```julia-repl julia> DDVFA(rho_lb=0.4, rho_ub = 0.75) DDVFA diff --git a/src/ART/DVFA.jl b/src/ART/DVFA.jl index 76506adf..17a6050f 100644 --- a/src/ART/DVFA.jl +++ b/src/ART/DVFA.jl @@ -87,30 +87,25 @@ mutable struct DVFA <: ART epoch::Int end # DVFA +# --------------------------------------------------------------------------- # +# CONSTRUCTORS +# --------------------------------------------------------------------------- # + """ - DVFA() + DVFA(;kwargs...) -Implements a DVFA learner with default options. +Implements a DVFA learner with optional keyword arguments. # Examples +By default: ```julia-repl julia> DVFA() DVFA opts: opts_DDVFA ... ``` -""" -function DVFA() - opts = opts_DVFA() - DVFA(opts) -end # DVFA() -""" - DVFA(;kwargs...) - -Implements a DVFA learner with keyword arguments. - -# Examples +or with keyword arguments: ```julia-repl julia> DVFA(rho=0.7) DVFA diff --git a/src/ART/FuzzyART.jl b/src/ART/FuzzyART.jl index aaf7cfbf..6b1863ff 100644 --- a/src/ART/FuzzyART.jl +++ b/src/ART/FuzzyART.jl @@ -97,29 +97,20 @@ end # FuzzyART <: ART # --------------------------------------------------------------------------- # """ - FuzzyART() + FuzzyART(;kwargs...) -Implements a Gamma-Normalized Fuzzy ART learner. +Implements a Gamma-Normalized Fuzzy ART learner with optional keyword arguments. # Examples +By default: ```julia-repl julia> FuzzyART() FuzzyART opts: opts_FuzzyART ... ``` -""" -function FuzzyART() - opts = opts_FuzzyART() - FuzzyART(opts) -end # FuzzyART() - -""" - FuzzyART(;kwargs...) -Implements a Gamma-Normalized Fuzzy ART learner with keyword arguments. - -# Examples +or with keyword arguments: ```julia-repl julia> FuzzyART(rho=0.7) FuzzyART diff --git a/src/ARTMAP/DAM.jl b/src/ARTMAP/DAM.jl index 21427e1d..f511eaf7 100644 --- a/src/ARTMAP/DAM.jl +++ b/src/ARTMAP/DAM.jl @@ -8,6 +8,10 @@ References: [1] G. P. Amis and G. A. Carpenter, “Default ARTMAP 2,” IEEE Int. Conf. Neural Networks - Conf. Proc., vol. 2, no. September 2007, pp. 777-782, Mar. 2007, doi: 10.1109/IJCNN.2007.4371056. """ +# --------------------------------------------------------------------------- # +# OPTIONS +# --------------------------------------------------------------------------- # + """ opts_DAM(;kwargs) @@ -39,6 +43,10 @@ Implements a Default ARTMAP learner's options. max_epochs::Int = 1 end # opts_DAM() +# --------------------------------------------------------------------------- # +# STRUCTS +# --------------------------------------------------------------------------- # + """ DAM <: ARTMAP @@ -68,30 +76,25 @@ mutable struct DAM <: ARTMAP epoch::Int end # DAM <: ARTMAP +# --------------------------------------------------------------------------- # +# CONSTRUCTORS +# --------------------------------------------------------------------------- # + """ - DAM() + DAM(;kwargs...) -Implements a Default ARTMAP learner. +Implements a Default ARTMAP learner with optional keyword arguments. # Examples +By default: ```julia-repl julia> DAM() DAM opts: opts_DAM ... ``` -""" -function DAM() - opts = opts_DAM() - DAM(opts) -end # DAM() -""" - DAM(;kwargs...) - -Implements a Default ARTMAP learner with keyword arguments. - -# Examples +or with keyword arguments: ```julia-repl julia> DAM() DAM @@ -129,6 +132,10 @@ function DAM(opts::opts_DAM) ) end # DAM(opts::opts_DAM) +# --------------------------------------------------------------------------- # +# ALGORITHMIC METHODS +# --------------------------------------------------------------------------- # + # Incremental DAM training method function train!(art::DAM, x::RealVector, y::Integer ; preprocessed::Bool=false) # Run the sequential initialization procedure diff --git a/src/ARTMAP/FAM.jl b/src/ARTMAP/FAM.jl index 840118fe..4513af01 100644 --- a/src/ARTMAP/FAM.jl +++ b/src/ARTMAP/FAM.jl @@ -8,6 +8,10 @@ References: [1] G. A. Carpenter, S. Grossberg, N. Markuzon, J. H. Reynolds, and D. B. Rosen, “Fuzzy ARTMAP: A Neural Network Architecture for Incremental Supervised Learning of Analog Multidimensional Maps,” IEEE Trans. Neural Networks, vol. 3, no. 5, pp. 698-713, 1992, doi: 10.1109/72.159059. """ +# --------------------------------------------------------------------------- # +# OPTIONS +# --------------------------------------------------------------------------- # + """ opts_FAM(;kwargs) @@ -39,6 +43,10 @@ Implements a Fuzzy ARTMAP learner's options. max_epochs::Int = 1 end # opts_FAM() +# --------------------------------------------------------------------------- # +# STRUCTS +# --------------------------------------------------------------------------- # + """ FAM <: ARTMAP @@ -68,30 +76,25 @@ mutable struct FAM <: ARTMAP epoch::Int end # FAM <: ARTMAP +# --------------------------------------------------------------------------- # +# CONSTRUCTORS +# --------------------------------------------------------------------------- # + """ - FAM() + FAM(;kwargs...) -Implements a Fuzzy ARTMAP learner. +Implements a Fuzzy ARTMAP learner with optional keyword arguments. # Examples +By default: ```julia-repl julia> FAM() FAM opts: opts_FAM ... ``` -""" -function FAM() - opts = opts_FAM() - FAM(opts) -end # FAM() -""" - FAM(;kwargs...) - -Implements a Fuzzy ARTMAP learner with keyword arguments. - -# Examples +or with keyword arguments: ```julia-repl julia> FAM(rho=0.7) FAM diff --git a/src/ARTMAP/SFAM.jl b/src/ARTMAP/SFAM.jl index 9b212061..d52cc42b 100644 --- a/src/ARTMAP/SFAM.jl +++ b/src/ARTMAP/SFAM.jl @@ -8,6 +8,10 @@ References: [1] G. A. Carpenter, S. Grossberg, N. Markuzon, J. H. Reynolds, and D. B. Rosen, “Fuzzy ARTMAP: A Neural Network Architecture for Incremental Supervised Learning of Analog Multidimensional Maps,” IEEE Trans. Neural Networks, vol. 3, no. 5, pp. 698-713, 1992, doi: 10.1109/72.159059. """ +# --------------------------------------------------------------------------- # +# OPTIONS +# --------------------------------------------------------------------------- # + """ opts_SFAM(;kwargs) @@ -39,6 +43,10 @@ Implements a Simple Fuzzy ARTMAP learner's options. max_epochs::Int = 1 end # opts_SFAM() +# --------------------------------------------------------------------------- # +# STRUCTS +# --------------------------------------------------------------------------- # + """ SFAM <: ARTMAP @@ -68,30 +76,25 @@ mutable struct SFAM <: ARTMAP epoch::Int end # SFAM <: ARTMAP +# --------------------------------------------------------------------------- # +# CONSTRUCTORS +# --------------------------------------------------------------------------- # + """ - SFAM() + SFAM(;kwargs...) -Implements a Simple Fuzzy ARTMAP learner. +Implements a Simple Fuzzy ARTMAP learner with optional keyword arguments. # Examples +By default: ```julia-repl julia> SFAM() SFAM opts: opts_SFAM ... ``` -""" -function SFAM() - opts = opts_SFAM() - SFAM(opts) -end # SFAM() -""" - SFAM(;kwargs...) - -Implements a Simple Fuzzy ARTMAP learner with keyword arguments. - -# Examples +or with keyword arguments: ```julia-repl julia> SFAM() SFAM @@ -129,6 +132,10 @@ function SFAM(opts::opts_SFAM) ) end # SFAM(opts::opts_SFAM) +# --------------------------------------------------------------------------- # +# ALGORITHMIC METHODS +# --------------------------------------------------------------------------- # + # SFAM incremental training method function train!(art::SFAM, x::RealVector, y::Integer ; preprocessed::Bool=false) # Run the sequential initialization procedure From 399c37ac61eb356f4af45948a11cfb50c3742d29 Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Thu, 12 May 2022 17:19:45 -0500 Subject: [PATCH 18/22] Add MLDataset compat entry to docs --- docs/Project.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/Project.toml b/docs/Project.toml index e5bf2d7a..b9c7dc28 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -8,3 +8,6 @@ MLDataUtils = "cc2ba9b6-d476-5e6d-8eaf-a92d5412d41d" MLDatasets = "eb30cadb-4394-5ae3-aed4-317e484a6458" MultivariateStats = "6f286f6a-111f-5878-ab1e-185364afe411" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" + +[compat] +MLDatasets = "0.6" From 78b84615bc19caf8fdcc7248810f5696469fd0bb Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Thu, 12 May 2022 17:21:41 -0500 Subject: [PATCH 19/22] Update Iris usage in all examples --- docs/examples/adaptive_resonance/data_config.jl | 4 ++-- docs/examples/adaptive_resonance/incremental-batch.jl | 4 ++-- docs/examples/adaptive_resonance/options.jl | 4 ++-- docs/examples/art/ddvfa_supervised.jl | 4 ++-- docs/examples/art/ddvfa_unsupervised.jl | 4 ++-- docs/examples/artmap/sfam_iris.jl | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/examples/adaptive_resonance/data_config.jl b/docs/examples/adaptive_resonance/data_config.jl index 4c2105ce..00470c3c 100644 --- a/docs/examples/adaptive_resonance/data_config.jl +++ b/docs/examples/adaptive_resonance/data_config.jl @@ -48,8 +48,8 @@ fieldnames(AdaptiveResonance.DataConfig) using MLDatasets ## We will download the Iris dataset for its small size and benchmark use for clustering algorithms. -Iris.download(i_accept_the_terms_of_use=true) -features, labels = Iris.features(), Iris.labels() +iris = Iris() +features, labels = iris.features(), iris.labels() ## We will then train the FuzzyART module in unsupervised mode and see that the data config is now set y_hat_train = train!(art, features) diff --git a/docs/examples/adaptive_resonance/incremental-batch.jl b/docs/examples/adaptive_resonance/incremental-batch.jl index 4fc5beb0..e2e86bb6 100644 --- a/docs/examples/adaptive_resonance/incremental-batch.jl +++ b/docs/examples/adaptive_resonance/incremental-batch.jl @@ -27,8 +27,8 @@ using MLDataUtils # Shuffling and splitting using Printf # Formatted number printing # We will download the Iris dataset for its small size and benchmark use for clustering algorithms. -Iris.download(i_accept_the_terms_of_use=true) -features, labels = Iris.features(), Iris.labels() +iris = Iris() +features, labels = iris.features(), iris.labels() # Because the MLDatasets package gives us Iris labels as strings, we will use the `MLDataUtils.convertlabel` method with the `MLLabelUtils.LabelEnc.Indices` type to get a list of integers representing each class: labels = convertlabel(LabelEnc.Indices{Int}, labels) diff --git a/docs/examples/adaptive_resonance/options.jl b/docs/examples/adaptive_resonance/options.jl index b5696936..b1d1a395 100644 --- a/docs/examples/adaptive_resonance/options.jl +++ b/docs/examples/adaptive_resonance/options.jl @@ -94,8 +94,8 @@ using MultivariateStats # Principal component analysis (PCA) using Plots # Plotting frontend # We will download the Iris dataset for its small size and benchmark use for clustering algorithms. -Iris.download(i_accept_the_terms_of_use=true) -features, labels = Iris.features(), Iris.labels() +iris = Iris() +features, labels = iris.features(), iris.labels() # Because the MLDatasets package gives us Iris labels as strings, we will use the `MLDataUtils.convertlabel` method with the `MLLabelUtils.LabelEnc.Indices` type to get a list of integers representing each class: labels = convertlabel(LabelEnc.Indices{Int}, labels) diff --git a/docs/examples/art/ddvfa_supervised.jl b/docs/examples/art/ddvfa_supervised.jl index e946739e..6722e0be 100644 --- a/docs/examples/art/ddvfa_supervised.jl +++ b/docs/examples/art/ddvfa_supervised.jl @@ -18,8 +18,8 @@ using MLDataUtils # Shuffling and splitting using Printf # Formatted number printing # We will download the Iris dataset for its small size and benchmark use for clustering algorithms. -Iris.download(i_accept_the_terms_of_use=true) -features, labels = Iris.features(), Iris.labels() +iris = Iris() +features, labels = iris.features(), iris.labels() # Because the MLDatasets package gives us Iris labels as strings, we will use the `MLDataUtils.convertlabel` method with the `MLLabelUtils.LabelEnc.Indices` type to get a list of integers representing each class: labels = convertlabel(LabelEnc.Indices{Int}, labels) diff --git a/docs/examples/art/ddvfa_unsupervised.jl b/docs/examples/art/ddvfa_unsupervised.jl index 3988254a..68669dc5 100644 --- a/docs/examples/art/ddvfa_unsupervised.jl +++ b/docs/examples/art/ddvfa_unsupervised.jl @@ -15,8 +15,8 @@ using AdaptiveResonance using MLDatasets # We will download the Iris dataset for its small size and benchmark use for clustering algorithms. -Iris.download(i_accept_the_terms_of_use=true) -features, labels = Iris.features(), Iris.labels() +iris = Iris() +features, labels = iris.features(), iris.labels() # Next, we will instantiate a DDVFA module. # We could create an options struct for reuse with `opts=opts_DDVFA(...)`, but for now we will use the direct keyword arguments approach. diff --git a/docs/examples/artmap/sfam_iris.jl b/docs/examples/artmap/sfam_iris.jl index f06df232..677719ef 100644 --- a/docs/examples/artmap/sfam_iris.jl +++ b/docs/examples/artmap/sfam_iris.jl @@ -18,8 +18,8 @@ using MLDataUtils # Shuffling and splitting using Printf # Formatted number printing # We will download the Iris dataset for its small size and benchmark use for clustering algorithms. -Iris.download(i_accept_the_terms_of_use=true) -features, labels = Iris.features(), Iris.labels() +iris = Iris() +features, labels = iris.features(), iris.labels() # Because the MLDatasets package gives us Iris labels as strings, we will use the `MLDataUtils.convertlabel` method with the `MLLabelUtils.LabelEnc.Indices` type to get a list of integers representing each class: labels = convertlabel(LabelEnc.Indices{Int}, labels) From 49b208835ea9979a76911d4f8ef568e5f20ed21a Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Thu, 12 May 2022 18:09:25 -0500 Subject: [PATCH 20/22] Fix iris usage further --- docs/Project.toml | 1 + docs/examples/adaptive_resonance/data_config.jl | 9 +++++---- docs/examples/adaptive_resonance/incremental-batch.jl | 4 ++-- docs/examples/adaptive_resonance/options.jl | 4 ++-- docs/examples/art/ddvfa_supervised.jl | 4 ++-- docs/examples/art/ddvfa_unsupervised.jl | 2 +- docs/examples/artmap/sfam_iris.jl | 4 ++-- 7 files changed, 15 insertions(+), 13 deletions(-) diff --git a/docs/Project.toml b/docs/Project.toml index b9c7dc28..2a33d4b5 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -6,6 +6,7 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" LiveServer = "16fef848-5104-11e9-1b77-fb7a48bbb589" MLDataUtils = "cc2ba9b6-d476-5e6d-8eaf-a92d5412d41d" MLDatasets = "eb30cadb-4394-5ae3-aed4-317e484a6458" +MLUtils = "f1d291b0-491e-4a28-83b9-f70985020b54" MultivariateStats = "6f286f6a-111f-5878-ab1e-185364afe411" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" diff --git a/docs/examples/adaptive_resonance/data_config.jl b/docs/examples/adaptive_resonance/data_config.jl index 00470c3c..d62eaea4 100644 --- a/docs/examples/adaptive_resonance/data_config.jl +++ b/docs/examples/adaptive_resonance/data_config.jl @@ -46,14 +46,15 @@ fieldnames(AdaptiveResonance.DataConfig) ## Load data using MLDatasets +using MLUtils ## We will download the Iris dataset for its small size and benchmark use for clustering algorithms. iris = Iris() -features, labels = iris.features(), iris.labels() +features, labels = Matrix(iris.features), Matrix{String}(iris.targets) -## We will then train the FuzzyART module in unsupervised mode and see that the data config is now set -y_hat_train = train!(art, features) -art.config +# Because the MLDatasets package gives us Iris labels as strings, we will use the `MLDataUtils.convertlabel` method with the `MLLabelUtils.LabelEnc.Indices` type to get a list of integers representing each class: +labels = convertlabel(LabelEnc.Indices{Int}, vec(labels)) +unique(labels) # !!! note # This automatic detection of feature characteristics only occurs if the `config` is not already setup. diff --git a/docs/examples/adaptive_resonance/incremental-batch.jl b/docs/examples/adaptive_resonance/incremental-batch.jl index e2e86bb6..6450392a 100644 --- a/docs/examples/adaptive_resonance/incremental-batch.jl +++ b/docs/examples/adaptive_resonance/incremental-batch.jl @@ -28,10 +28,10 @@ using Printf # Formatted number printing # We will download the Iris dataset for its small size and benchmark use for clustering algorithms. iris = Iris() -features, labels = iris.features(), iris.labels() +features, labels = Matrix(iris.features), Matrix{String}(iris.targets) # Because the MLDatasets package gives us Iris labels as strings, we will use the `MLDataUtils.convertlabel` method with the `MLLabelUtils.LabelEnc.Indices` type to get a list of integers representing each class: -labels = convertlabel(LabelEnc.Indices{Int}, labels) +labels = convertlabel(LabelEnc.Indices{Int}, vec(labels)) unique(labels) # Next, we will create a train/test split with the `MLDataUtils.stratifiedobs` utility: diff --git a/docs/examples/adaptive_resonance/options.jl b/docs/examples/adaptive_resonance/options.jl index b1d1a395..e4756b5d 100644 --- a/docs/examples/adaptive_resonance/options.jl +++ b/docs/examples/adaptive_resonance/options.jl @@ -95,10 +95,10 @@ using Plots # Plotting frontend # We will download the Iris dataset for its small size and benchmark use for clustering algorithms. iris = Iris() -features, labels = iris.features(), iris.labels() +features, labels = Matrix(iris.features), Matrix{String}(iris.targets) # Because the MLDatasets package gives us Iris labels as strings, we will use the `MLDataUtils.convertlabel` method with the `MLLabelUtils.LabelEnc.Indices` type to get a list of integers representing each class: -labels = convertlabel(LabelEnc.Indices{Int}, labels) +labels = convertlabel(LabelEnc.Indices{Int}, vec(labels)) unique(labels) # Next, we will create a train/test split with the `MLDataUtils.stratifiedobs` utility: diff --git a/docs/examples/art/ddvfa_supervised.jl b/docs/examples/art/ddvfa_supervised.jl index 6722e0be..db86c3f4 100644 --- a/docs/examples/art/ddvfa_supervised.jl +++ b/docs/examples/art/ddvfa_supervised.jl @@ -19,10 +19,10 @@ using Printf # Formatted number printing # We will download the Iris dataset for its small size and benchmark use for clustering algorithms. iris = Iris() -features, labels = iris.features(), iris.labels() +features, labels = Matrix(iris.features), Matrix{String}(iris.targets) # Because the MLDatasets package gives us Iris labels as strings, we will use the `MLDataUtils.convertlabel` method with the `MLLabelUtils.LabelEnc.Indices` type to get a list of integers representing each class: -labels = convertlabel(LabelEnc.Indices{Int}, labels) +labels = convertlabel(LabelEnc.Indices{Int}, vec(labels)) unique(labels) # Next, we will create a train/test split with the `MLDataUtils.stratifiedobs` utility: diff --git a/docs/examples/art/ddvfa_unsupervised.jl b/docs/examples/art/ddvfa_unsupervised.jl index 68669dc5..4d2c21b5 100644 --- a/docs/examples/art/ddvfa_unsupervised.jl +++ b/docs/examples/art/ddvfa_unsupervised.jl @@ -16,7 +16,7 @@ using MLDatasets # We will download the Iris dataset for its small size and benchmark use for clustering algorithms. iris = Iris() -features, labels = iris.features(), iris.labels() +features, labels = Matrix(iris.features), Matrix{String}(iris.targets) # Next, we will instantiate a DDVFA module. # We could create an options struct for reuse with `opts=opts_DDVFA(...)`, but for now we will use the direct keyword arguments approach. diff --git a/docs/examples/artmap/sfam_iris.jl b/docs/examples/artmap/sfam_iris.jl index 677719ef..d0011bd9 100644 --- a/docs/examples/artmap/sfam_iris.jl +++ b/docs/examples/artmap/sfam_iris.jl @@ -19,10 +19,10 @@ using Printf # Formatted number printing # We will download the Iris dataset for its small size and benchmark use for clustering algorithms. iris = Iris() -features, labels = iris.features(), iris.labels() +features, labels = Matrix(iris.features), Matrix{String}(iris.targets) # Because the MLDatasets package gives us Iris labels as strings, we will use the `MLDataUtils.convertlabel` method with the `MLLabelUtils.LabelEnc.Indices` type to get a list of integers representing each class: -labels = convertlabel(LabelEnc.Indices{Int}, labels) +labels = convertlabel(LabelEnc.Indices{Int}, vec(labels)) unique(labels) # Next, we will create a train/test split with the `MLDataUtils.stratifiedobs` utility: From 0319097df889893a4b86974c108771c8b74b201d Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Thu, 12 May 2022 19:27:24 -0500 Subject: [PATCH 21/22] Correct remaining data errors in democard examples --- docs/Project.toml | 1 - docs/examples/adaptive_resonance/data_config.jl | 10 ++++++---- docs/examples/adaptive_resonance/incremental-batch.jl | 6 ++++-- docs/examples/adaptive_resonance/options.jl | 6 ++++-- docs/examples/art/ddvfa_supervised.jl | 6 ++++-- docs/examples/art/ddvfa_unsupervised.jl | 9 ++++++--- docs/examples/artmap/sfam_iris.jl | 6 ++++-- docs/src/man/full-index.md | 2 +- 8 files changed, 29 insertions(+), 17 deletions(-) diff --git a/docs/Project.toml b/docs/Project.toml index 2a33d4b5..b9c7dc28 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -6,7 +6,6 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" LiveServer = "16fef848-5104-11e9-1b77-fb7a48bbb589" MLDataUtils = "cc2ba9b6-d476-5e6d-8eaf-a92d5412d41d" MLDatasets = "eb30cadb-4394-5ae3-aed4-317e484a6458" -MLUtils = "f1d291b0-491e-4a28-83b9-f70985020b54" MultivariateStats = "6f286f6a-111f-5878-ab1e-185364afe411" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" diff --git a/docs/examples/adaptive_resonance/data_config.jl b/docs/examples/adaptive_resonance/data_config.jl index d62eaea4..ccada8fc 100644 --- a/docs/examples/adaptive_resonance/data_config.jl +++ b/docs/examples/adaptive_resonance/data_config.jl @@ -45,15 +45,17 @@ fieldnames(AdaptiveResonance.DataConfig) # In batch training mode, the minimums and maximums are detected automatically; the minimum and maximum values for every feature are saved and used for the preprocessing step at every subsequent iteration. ## Load data -using MLDatasets -using MLUtils +using MLDatasets # Iris dataset +using MLDataUtils # Shuffling and splitting ## We will download the Iris dataset for its small size and benchmark use for clustering algorithms. +## Get the iris dataset as a DataFrame iris = Iris() -features, labels = Matrix(iris.features), Matrix{String}(iris.targets) +## Manipulate the features and labels into a matrix of features and a vector of labels +features, labels = Matrix(iris.features)', vec(Matrix{String}(iris.targets)) # Because the MLDatasets package gives us Iris labels as strings, we will use the `MLDataUtils.convertlabel` method with the `MLLabelUtils.LabelEnc.Indices` type to get a list of integers representing each class: -labels = convertlabel(LabelEnc.Indices{Int}, vec(labels)) +labels = convertlabel(LabelEnc.Indices{Int}, labels) unique(labels) # !!! note diff --git a/docs/examples/adaptive_resonance/incremental-batch.jl b/docs/examples/adaptive_resonance/incremental-batch.jl index 6450392a..364ff4e2 100644 --- a/docs/examples/adaptive_resonance/incremental-batch.jl +++ b/docs/examples/adaptive_resonance/incremental-batch.jl @@ -27,11 +27,13 @@ using MLDataUtils # Shuffling and splitting using Printf # Formatted number printing # We will download the Iris dataset for its small size and benchmark use for clustering algorithms. +## Get the iris dataset as a DataFrame iris = Iris() -features, labels = Matrix(iris.features), Matrix{String}(iris.targets) +## Manipulate the features and labels into a matrix of features and a vector of labels +features, labels = Matrix(iris.features)', vec(Matrix{String}(iris.targets)) # Because the MLDatasets package gives us Iris labels as strings, we will use the `MLDataUtils.convertlabel` method with the `MLLabelUtils.LabelEnc.Indices` type to get a list of integers representing each class: -labels = convertlabel(LabelEnc.Indices{Int}, vec(labels)) +labels = convertlabel(LabelEnc.Indices{Int}, labels) unique(labels) # Next, we will create a train/test split with the `MLDataUtils.stratifiedobs` utility: diff --git a/docs/examples/adaptive_resonance/options.jl b/docs/examples/adaptive_resonance/options.jl index e4756b5d..3083cc20 100644 --- a/docs/examples/adaptive_resonance/options.jl +++ b/docs/examples/adaptive_resonance/options.jl @@ -94,11 +94,13 @@ using MultivariateStats # Principal component analysis (PCA) using Plots # Plotting frontend # We will download the Iris dataset for its small size and benchmark use for clustering algorithms. +## Get the iris dataset as a DataFrame iris = Iris() -features, labels = Matrix(iris.features), Matrix{String}(iris.targets) +## Manipulate the features and labels into a matrix of features and a vector of labels +features, labels = Matrix(iris.features)', vec(Matrix{String}(iris.targets)) # Because the MLDatasets package gives us Iris labels as strings, we will use the `MLDataUtils.convertlabel` method with the `MLLabelUtils.LabelEnc.Indices` type to get a list of integers representing each class: -labels = convertlabel(LabelEnc.Indices{Int}, vec(labels)) +labels = convertlabel(LabelEnc.Indices{Int}, labels) unique(labels) # Next, we will create a train/test split with the `MLDataUtils.stratifiedobs` utility: diff --git a/docs/examples/art/ddvfa_supervised.jl b/docs/examples/art/ddvfa_supervised.jl index db86c3f4..c26e11c6 100644 --- a/docs/examples/art/ddvfa_supervised.jl +++ b/docs/examples/art/ddvfa_supervised.jl @@ -18,11 +18,13 @@ using MLDataUtils # Shuffling and splitting using Printf # Formatted number printing # We will download the Iris dataset for its small size and benchmark use for clustering algorithms. +## Get the iris dataset as a DataFrame iris = Iris() -features, labels = Matrix(iris.features), Matrix{String}(iris.targets) +## Manipulate the features and labels into a matrix of features and a vector of labels +features, labels = Matrix(iris.features)', vec(Matrix{String}(iris.targets)) # Because the MLDatasets package gives us Iris labels as strings, we will use the `MLDataUtils.convertlabel` method with the `MLLabelUtils.LabelEnc.Indices` type to get a list of integers representing each class: -labels = convertlabel(LabelEnc.Indices{Int}, vec(labels)) +labels = convertlabel(LabelEnc.Indices{Int}, labels) unique(labels) # Next, we will create a train/test split with the `MLDataUtils.stratifiedobs` utility: diff --git a/docs/examples/art/ddvfa_unsupervised.jl b/docs/examples/art/ddvfa_unsupervised.jl index 4d2c21b5..1f6b203a 100644 --- a/docs/examples/art/ddvfa_unsupervised.jl +++ b/docs/examples/art/ddvfa_unsupervised.jl @@ -11,12 +11,15 @@ # DDVFA is an unsupervised clustering algorithm by definition, so it can be used to cluster a set of samples all at once in batch mode. # We begin with importing AdaptiveResonance for the ART modules and MLDatasets for loading some data. -using AdaptiveResonance -using MLDatasets +using AdaptiveResonance # ART +using MLDatasets # Iris dataset +using MLDataUtils # Shuffling and splitting # We will download the Iris dataset for its small size and benchmark use for clustering algorithms. +## Get the iris dataset as a DataFrame iris = Iris() -features, labels = Matrix(iris.features), Matrix{String}(iris.targets) +## Manipulate the features and labels into a matrix of features and a vector of labels +features, labels = Matrix(iris.features)', vec(Matrix{String}(iris.targets)) # Next, we will instantiate a DDVFA module. # We could create an options struct for reuse with `opts=opts_DDVFA(...)`, but for now we will use the direct keyword arguments approach. diff --git a/docs/examples/artmap/sfam_iris.jl b/docs/examples/artmap/sfam_iris.jl index d0011bd9..6a3a066d 100644 --- a/docs/examples/artmap/sfam_iris.jl +++ b/docs/examples/artmap/sfam_iris.jl @@ -18,11 +18,13 @@ using MLDataUtils # Shuffling and splitting using Printf # Formatted number printing # We will download the Iris dataset for its small size and benchmark use for clustering algorithms. +## Get the iris dataset as a DataFrame iris = Iris() -features, labels = Matrix(iris.features), Matrix{String}(iris.targets) +## Manipulate the features and labels into a matrix of features and a vector of labels +features, labels = Matrix(iris.features)', vec(Matrix{String}(iris.targets)) # Because the MLDatasets package gives us Iris labels as strings, we will use the `MLDataUtils.convertlabel` method with the `MLLabelUtils.LabelEnc.Indices` type to get a list of integers representing each class: -labels = convertlabel(LabelEnc.Indices{Int}, vec(labels)) +labels = convertlabel(LabelEnc.Indices{Int}, labels) unique(labels) # Next, we will create a train/test split with the `MLDataUtils.stratifiedobs` utility: diff --git a/docs/src/man/full-index.md b/docs/src/man/full-index.md index 30fb4eb5..c4a6a43f 100644 --- a/docs/src/man/full-index.md +++ b/docs/src/man/full-index.md @@ -27,7 +27,7 @@ Public = true ```@docs AdaptiveResonance train! -classify +AdaptiveResonance.classify data_setup! performance complement_code From 821fb6212024f7673f50b3e5a6a16d023d84f076 Mon Sep 17 00:00:00 2001 From: Sasha Petrenko Date: Thu, 12 May 2022 20:03:55 -0500 Subject: [PATCH 22/22] Bump --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 0fe0ad95..913eacb6 100644 --- a/Project.toml +++ b/Project.toml @@ -2,7 +2,7 @@ name = "AdaptiveResonance" uuid = "3d72adc0-63d3-4141-bf9b-84450dd0395b" authors = ["Sasha Petrenko"] description = "A Julia package for Adaptive Resonance Theory (ART) algorithms." -version = "0.5.0" +version = "0.5.1" [deps] Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"