Is a Fuzzy C-Means algorithm available for Python?
Asked Answered
T

4

12

I have some dots in a 3 dimensional space and would like to cluster them. I know Pythons module "cluster", but it has only K-Means. Do you know a module which has FCM (Fuzzy C-Means)?

(If you know some other python modules which are related to clustering you could name them as a bonus. But the important question is the one for a FCM-algorithm in python.)

Matlab

It seems to be quite easy to use FCM in Matlab (example). Isn't something like this available for Python?

NumPy, SciPy and Sage

I didn't find FCM in NumPy, SciPy or Sage. I've downloaded the documentation and searched for it. No results

Python-cluster

It seems like the cluster module will add fuzzy C-Means with the next version (see Roadmap). But I need it now

Timothee answered 18/7, 2011 at 16:47 Comment(2)
I'd look at numpy and scipy.Tchad
Some of the options under this other question might be useful for you.Hermes
T
7

PEACH will provide some Fuzzy C-Means functionality: http://code.google.com/p/peach/

However there doesn't seem to be any usable documentation as the wiki is empty. An example for using FCM with PEACH can be found on its website.

Templas answered 18/7, 2011 at 17:3 Comment(2)
I've just installed it and called the help: class FuzzyCMeans - Use this class to instantiate a fuzzy c-means object. The object must be given a training set and initial conditions. I don't have a training-set.Timothee
You can also see the code and help at peach.googlecode.com/svn/trunk/peach/fuzzy/cmeans.py, it says that the training set is just the data you want to be clustered. the provided example shows, that you can chose the initial conditions randomlyTemplas
S
7

Have a look at scikit-fuzzy package. It has the very basic fuzzy logic functionality, including fuzzy c-means clustering.

Sure answered 17/5, 2015 at 3:54 Comment(0)
A
2

Python

There is a fuzzy-c-means package in the PyPI. Check out the link : fuzzy-c-means Python

This is the simplest way to use FCM in python. Hope it helps.

Alyosha answered 19/7, 2019 at 12:20 Comment(0)
D
1

I have done it from scratch, using K++ initialization (with fixed seeds and 5 centroids. It should't be too difficult to addapt it to your desired number of centroids):

# K++ initialization Algorithm:
import random
def initialize(X, K):
    C = [X[0]]
    for k in range(1, K):
        D2 = scipy.array([min([scipy.inner(c-x,c-x) for c in C]) for x in X])
        probs = D2/D2.sum()
        cumprobs = probs.cumsum()
        np.random.seed(20)            # fixxing seeds
        #random.seed(0)               # fixxing seeds
        r = scipy.rand()        
        for j,p in enumerate(cumprobs):
            if r < p:
                i = j
                break
        C.append(X[i])
    return C

a = initialize(data2,5)   # "a" is the centroids initial array... I used 5 centroids

# Now the Fuzzy c means algorithm:
m = 1.5     # Fuzzy parameter (it can be tuned)
r = (2/(m-1))

# Initial centroids:
c1,c2,c3,c4,c5 = a[0],a[1],a[2],a[3],a[4]

# prepare empty lists to add the final centroids:
cc1,cc2,cc3,cc4,cc5 = [],[],[],[],[]

n_iterations = 10000

for j in range(n_iterations):
    u1,u2,u3,u4,u5 = [],[],[],[],[]

    for i in range(len(data2)):
        # Distances (of every point to each centroid):
        a = LA.norm(data2[i]-c1)    
        b = LA.norm(data2[i]-c2)
        c = LA.norm(data2[i]-c3)
        d = LA.norm(data2[i]-c4)
        e = LA.norm(data2[i]-c5)

        # Pertenence matrix vectors:
        U1 = 1/(1 + (a/b)**r + (a/c)**r + (a/d)**r + (a/e)**r) 
        U2 = 1/((b/a)**r + 1 + (b/c)**r + (b/d)**r + (b/e)**r)
        U3 = 1/((c/a)**r + (c/b)**r + 1 + (c/d)**r + (c/e)**r)
        U4 = 1/((d/a)**r + (d/b)**r + (d/c)**r + 1 + (d/e)**r)
        U5 = 1/((e/a)**r + (e/b)**r + (e/c)**r + (e/d)**r + 1)

        # We will get an array of n row points x K centroids, with their degree of pertenence       
        u1.append(U1)
        u2.append(U2)
        u3.append(U3)
        u4.append(U4)
        u5.append(U5)        

    # now we calculate new centers:
    c1 = (np.array(u1)**2).dot(data2) / np.sum(np.array(u1)**2)
    c2 = (np.array(u2)**2).dot(data2) / np.sum(np.array(u2)**2)
    c3 = (np.array(u3)**2).dot(data2) / np.sum(np.array(u3)**2)
    c4 = (np.array(u4)**2).dot(data2) / np.sum(np.array(u4)**2)
    c5 = (np.array(u5)**2).dot(data2) / np.sum(np.array(u5)**2)

    cc1.append(c1)
    cc2.append(c2)
    cc3.append(c3)
    cc4.append(c4)
    cc5.append(c5) 

    if (j>5):  
        change_rate1 = np.sum(3*cc1[j] - cc1[j-1] - cc1[j-2] - cc1[j-3])/3
        change_rate2 = np.sum(3*cc2[j] - cc2[j-1] - cc2[j-2] - cc2[j-3])/3
        change_rate3 = np.sum(3*cc3[j] - cc3[j-1] - cc3[j-2] - cc3[j-3])/3
        change_rate4 = np.sum(3*cc4[j] - cc4[j-1] - cc4[j-2] - cc4[j-3])/3
        change_rate5 = np.sum(3*cc5[j] - cc5[j-1] - cc5[j-2] - cc5[j-3])/3        
        change_rate = np.array([change_rate1,change_rate2,change_rate3,change_rate4,change_rate5])
        changed = np.sum(change_rate>0.0000001)
        if changed == 0:
            break

print(c1)  # to check a centroid coordinates   c1 - c5 ... they are the last centroids calculated, so supposedly they converged.
print(U)  # this is the degree of pertenence to each centroid (so n row points x K centroids columns).

I know it is not very pythonic, but I hope it can be a starting point for your complete fuzzy C means algorithm. I think that "soft clustering" is the way to go when data is not easily separable (for example, when "t-SNE visualization" show all data together instead of showing groups clearly separated. In this case, forcing data to pertain strictly to only one clustering can be dangerous). I would give a try with m = 1.1, to m = 2.0, so you can see how the fuzzy parameter affects to the pertenence matrix.

Drome answered 11/7, 2018 at 13:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.