Skip to content

Commit cc2499f

Browse files
authored
initial fuzzy c-means implementation (#11)
* initial genfis implementation * update tests and docs * update changelog
1 parent 26307b3 commit cc2499f

File tree

7 files changed

+87
-3
lines changed

7 files changed

+87
-3
lines changed

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ makedocs(;
167167
],
168168
"Membership functions" => "api/memberships.md",
169169
"Reading/Writing" => "api/readwrite.md",
170+
"Learning fuzzy models" => "api/genfis.md",
170171
],
171172
"Contributor's Guide" => "contributing.md",
172173
"Release notes" => "changelog.md",

docs/src/api/genfis.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Learning fuzzy models
2+
3+
```@docs
4+
fuzzy_cmeans
5+
```

docs/src/changelog.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
44

55
## unreleased
66

7-
- added support Lukasiewicz, drastic, nilpotent and Hamacher T-norms and corresponding S-norms.
7+
- ![][badge-feature] Added fuzzy c-means
8+
- ![][badge-enhancement] added support Lukasiewicz, drastic, nilpotent and Hamacher T-norms and corresponding S-norms.
89

910
## v0.1.0 -- 2023-01-10
1011

@@ -22,4 +23,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
2223
- linear and constant output for Sugeno
2324
- initial plotting functionalities
2425
- plotting variables and membership functions
25-
- plotting rules of fuzzy inference system
26+
- plotting rules of fuzzy inference system
27+
28+
[badge-breaking]: https://img.shields.io/badge/BREAKING-red.svg
29+
[badge-deprecation]: https://img.shields.io/badge/deprecation-orange.svg
30+
[badge-feature]: https://img.shields.io/badge/new%20feature-green.svg
31+
[badge-enhancement]: https://img.shields.io/badge/enhancement-blue.svg
32+
[badge-bugfix]: https://img.shields.io/badge/bugfix-purple.svg
33+
[badge-security]: https://img.shields.io/badge/security-black.svg
34+
[badge-experimental]: https://img.shields.io/badge/experimental-lightgrey.svg
35+
[badge-maintenance]: https://img.shields.io/badge/maintenance-gray.svg

src/FuzzyLogic.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ include("InferenceSystem.jl")
1111
include("parser.jl")
1212
include("evaluation.jl")
1313
include("plotting.jl")
14+
include("genfis.jl")
1415

1516
export DifferenceSigmoidMF, LinearMF, GeneralizedBellMF, GaussianMF, ProductSigmoidMF,
1617
SigmoidMF, TrapezoidalMF, TriangularMF, SShapeMF, ZShapeMF, PiShapeMF,
@@ -19,5 +20,6 @@ export DifferenceSigmoidMF, LinearMF, GeneralizedBellMF, GaussianMF, ProductSigm
1920
MinImplication, ProdImplication,
2021
MaxAggregator, ProbSumAggregator, CentroidDefuzzifier, BisectorDefuzzifier,
2122
@mamfis, MamdaniFuzzySystem, @sugfis, SugenoFuzzySystem,
22-
LinearSugenoOutput, ConstantSugenoOutput
23+
LinearSugenoOutput, ConstantSugenoOutput,
24+
fuzzy_cmeans
2325
end

src/genfis.jl

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""
2+
Performs fuzzy clustering on th data `X` using `N` clusters.
3+
4+
### Input
5+
6+
- `X` -- ``d × M`` matrix of data, each column is a data point
7+
- `N` -- number of clusters used.
8+
9+
### Keyword argumes
10+
11+
- `m` -- exponent of the fuzzy membership function, default `2.0`
12+
- `maxiter` -- maximum number of iterations, default `100`
13+
- `tol` -- absolute error for stopping condition. Stop if ``|Eₖ - Eₖ₊₁|≤tol``, where ``Eₖ``
14+
is the cost function value at the ``k``:th iteration.
15+
### Output
16+
17+
- `C` -- ``d × N``matrix of centers, each column is the center of a cluster.
18+
- `U` -- ``M × N`` matrix of membership degrees, `Uᵢⱼ`` tells has the membership degree of
19+
the ``j``th point to the ``i``th cluster.
20+
"""
21+
function fuzzy_cmeans(X::Matrix{T}, N::Int; m = 2.0, maxiter = 100,
22+
tol = 1e-5) where {T <: Real}
23+
m > 1 || throw(ArgumentError("m must be greater than 1"))
24+
e = 1 / (m - 1)
25+
M = size(X, 2)
26+
U = rand(float(T), M, N)
27+
C = X * U .^ m ./ sum(U .^ m; dims = 1)
28+
29+
J = zero(float(T))
30+
@inbounds for (j, cj) in enumerate(eachcol(C))
31+
for (i, xi) in enumerate(eachcol(X))
32+
J += U[i, j]^m * sum(abs2(k) for k in xi - cj)
33+
end
34+
end
35+
36+
@inbounds for i in 1:maxiter
37+
for (j, cj) in enumerate(eachcol(C))
38+
for (i, xi) in enumerate(eachcol(X))
39+
U[i, j] = 1 /
40+
sum(sum(abs2.(xi - cj)) / sum(abs2.(xi - ck))
41+
for ck in eachcol(C))^e
42+
end
43+
end
44+
C .= X * U .^ m ./ sum(U .^ m; dims = 1)
45+
46+
Jnew = zero(float(T))
47+
for (j, cj) in enumerate(eachcol(C))
48+
for (i, xi) in enumerate(eachcol(X))
49+
Jnew += U[i, j]^m * sum(abs2(k) for k in xi - cj)
50+
end
51+
end
52+
abs(J - Jnew) <= tol && break
53+
J = Jnew
54+
end
55+
return C, U
56+
end

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ testfiles = [
66
"test_parser.jl",
77
"test_evaluation.jl",
88
"test_plotting.jl",
9+
"test_genfis.jl",
910
"test_aqua.jl",
1011
"test_doctests.jl",
1112
]

test/test_genfis.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using FuzzyLogic, Test
2+
3+
@testset "fuzzy c-means" begin
4+
X = [-3 -3 -3 -2 -2 -2 -1 0 1 2 2 2 3 3 3;
5+
-2 0 2 -1 0 1 0 0 0 -1 0 1 -2 0 2]
6+
C, U = fuzzy_cmeans(X, 2; m = 3)
7+
@test sortslices(C; dims = 2)[-2.02767 2.02767; 0 0] atol=1e-3
8+
@test_throws ArgumentError fuzzy_cmeans(X, 3; m = 1)
9+
end

0 commit comments

Comments
 (0)