3
votes

I've been trying to implement Affinity Propagation in Java for the past week. I did exactly as the original paper by frey and dueck describes yet I do not get good exemplars.

The research paper can be found here: http://www.psi.toronto.edu/affinitypropagation/FreyDueckScience07.pdf

Here is the code I wrote for the similarity function (clustering sentences from the research paper.)

public static void calculateSimilarity(){

                try{    
                    for(int i=0; i<tweets.size(); i++){//For each tweet

                        for(int j=0; j<tweets.size(); j++){//and the one next to it, split both into tokens

                            String[]firstTokens=tweets.get(i).toLowerCase().split(" ");
                            String[]secondTokens=tweets.get(j).toLowerCase().split(" ");//tokenize it

                            //store summed cost in respective matrix.
                            if(i==j){//calculate self similarity{
                                similarity[i][j]=firstTokens.length*NEGATIVE_LOG_OF_DICTIONARY+ADJUSTMENT_FACTOR;
                                System.out.println(similarity[i][j]);
                            }
                            else{
                                //The costC per word. These will be summed
                                double Cost=compare(firstTokens, secondTokens);//compare
                                similarity[i][j]=Cost;//assign the similarity
                            }


                    }//end inner for



                }//end outer for
            }//end try
            catch(Exception e){
                System.out.println(temp);
                e.printStackTrace();
            }//end catch

            }//end method


        public static double compare(String[]firstString,String[]secondString){


            double Cost=0;
            for(int k=0; k<firstString.length; k++){//for first tweet tokens

                for(int l=0; l<secondString.length;l++){//compare to second tweet tokens

                    //Look at words that are greater than 2 characters
                if(firstString[k].length()>=5 &&secondString[l].length()>=5){
                        if(firstString[k].contains(secondString[l])){
                            //increment the cost
                            Cost+=-Math.log10(secondString.length);
                        }
                        else//Cost of the word if no word is similar
                            {   
                                Cost+=NEGATIVE_LOG_OF_DICTIONARY;

                            }
                    }//end big if

                    }//end l for loop
            }//end inner inner for

            return Cost;
        }

And here is how they say they calculated similarity between two data points (sentences): The similarity of sentence i to sentence k was set to the negative sum of the information-theoretic costs (S5) of encoding every word in sentence i using the words in sentence k and a dictionary of all words in the manuscript. For each word in sentence i, if the word matched a word in sentence k, the coding cost for the word was set to the neg- ative logarithm of the number of words in sentence k (the cost of coding the index of the 5 matched word), and otherwise it was set to the negative logarithm of the number of words in the manuscript dictionary (the cost of coding the index of the word in the manuscript dictionary). A word was considered to match another word if either word was a substring of the other.

I also wrote the availability and responsibility function.

AVAILABILITY: public static double updateAvalibility(int datapoint, int candidate,double[][] a, double[][] r,double aOld){ double availibity; //ArrayListtemp=new ArrayList(); double total=0;

            //*For self availibility
            if(datapoint==candidate){

                    for(int j=0; j<tweets.size(); j++){

                        if(j==datapoint)
                            continue;                           
                        else if(r[j][candidate]<0)//skip negative terms
                            continue;
                        else
                            total+=(r[j][candidate]);//sum up r of rows

                    }//end for
                availibity=total;//The total becjomes the A
                System.out.println("Availibility :"+availibity);
            }//end if
            else{//else
                for(int j=0; j<tweets.size(); j++){

                    if(j==candidate||j==datapoint)
                        continue;
                    else if(r[j][candidate]<0)//skip negative terms
                        continue;
                    else
                        total+=r[j][candidate];//else sum all R of all rows

                }//end for

                availibity=(r[candidate][candidate]+total);//A is set to self R + the sum

                if(availibity<0)//if not positive ignore
                    availibity=0;
                }//end else

            return (1-LAM)*availibity+(LAM*aOld);//Return with Adjustment factor
        }

RESPONSIBILITY:

//updates responsibility. Takes the two competeing datapoints, s, r, and a
        //returns the responsibility of i to k
        public static double updateResponsibility(int datapoint, int candidate, double[][] s, double[][] a,double rOld){

            double responsibility;

            //A temporary array 
            ArrayList<Double>temp=new ArrayList<Double>();
            double max;//The max of the a(i,k')+r(i,k')

            //################################
            //SETTING THE SELF RESPONSIBILITY
            if(datapoint==candidate){

                for(int k=0;k<tweets.size(); k++){

                    if(k==candidate)
                        continue;
                    else
                    temp.add(s[datapoint][k]);//store all the similarites b/w this point
                    //others
                }
                max=Collections.max(temp);//The max of the similarity

                responsibility=(similarity[datapoint][candidate])-max;
                System.out.println("s:"+similarity[datapoint][candidate]+"- m:"+max+"= responsibility: "+responsibility);
            }   
            else{
                    for(int j=0; j<tweets.size();j++){  
                            //store the A + S
                        if(j==candidate)
                            continue;
                        else
                            temp.add(a[datapoint][j]+s[datapoint][j]);// a(i,k')+r(i,k') Max will be calculated later   

                    }//end inner for

                //Max of the a+r of other k's. 
                max=Collections.max(temp);//Then get the max

                responsibility=s[datapoint][candidate]-max;//then the similarity - the max
            }//end else
            return ((1-LAM)*responsibility)-(LAM*rOld);//Dampen responsibility and return
        }//end method

Why do I get crappy exemplars even when I use the adjutment factors listed in the paper? What am I doing wrong?

Any help would be greatly appreciated.

1
did you ever find the problem? - Simon
Yes I did. The algorithm was wrong and I didn't interpret it correctly from the paper. - user2654569
og great can you share the working version? - Simon

1 Answers

0
votes

I could not find your problem, but you can use the following library instead:

Official site, GitHub site and the Community site.

It contains a good Affinity Propagation algorithm.