The Louvain method for community detection

The Louvainmethod for community detection

 

Louvain method是一个非重叠社团发现的算法,该方法具有较快的执行效率。

对应的paper地址:http://arxiv.org/abs/0803.0476

Paper作者对算法的介绍网址:

http://perso.uclouvain.be/vincent.blondel/research/louvain.html

算法代码下载地址(只有c++版本和matlab版本,没有java版本):

https://sites.google.com/site/findcommunities/

 

找到c++版本时,想改成java版本,无奈发现c++版本里的数据结构略显复杂,失去耐心,就打算自己写一个java版本出来,结果自己写的不仅时间多,而且模块度值与论文中的模块度值也有一定的差距。

 

于是google到一个别人已经实现的java版本的代码

http://wiki.cns.iu.edu/display/CISHELL/Louvain+Community+Detection

除了实现Louvain方法之外,他还实现了一个slm算法,并将这几个算法实现打包成jar文件,源码可以在下面的网址中下载到

http://www.ludowaltman.nl/slm/

 

算法的总体思想是:

1.刚开始时,每一个节点形成一个小的簇

2.通过模块度函数值优化,将每一个节点归到‘最好’的簇当中去。该步骤知道所有的节点所属的簇不再变化才停止

3.将网络图进行reduce,把一个簇内的所有节点抽象成一个节点,看抽象之后的网络图是否还有优化的可能性。如果有,对抽象之后的图,继续进行第2步。

 

 

经过我对其代码的精简,Louvain算法代码如下:

ModularityOptimizer.java

[java]  view plain  copy
  1. /** 
  2.  * ModularityOptimizer 
  3.  * 
  4.  * @author Ludo Waltman 
  5.  * @author Nees Jan van Eck 
  6.  * @version 1.2.0, 05/14/14 
  7.  */  
  8.   
  9. import java.io.BufferedReader;  
  10. import java.io.BufferedWriter;  
  11. import java.io.FileReader;  
  12. import java.io.FileWriter;  
  13. import java.io.IOException;  
  14. import java.util.Arrays;  
  15. import java.util.Random;  
  16.   
  17. public class ModularityOptimizer  
  18. {  
  19.     public static void main(String[] args) throws IOException  
  20.     {  
  21.         boolean  update;  
  22.          
  23.         double modularity, maxModularity, resolution, resolution2;  
  24.         int algorithm, i, j, modularityFunction, nClusters, nIterations, nRandomStarts;  
  25.         int[] cluster;  
  26.         long beginTime, endTime;  
  27.         Network network;  
  28.         Random random;  
  29.         String inputFileName, outputFileName;  
  30.   
  31.           
  32.         inputFileName = "fb.txt";  
  33.         outputFileName = "communities.txt";  
  34.         modularityFunction = 1;  
  35.         resolution = 1.0;  
  36.         algorithm = 1;  
  37.         nRandomStarts = 10;  
  38.         nIterations = 3;  
  39.                 
  40.         System.out.println("Modularity Optimizer version 1.2.0 by Ludo Waltman and Nees Jan van Eck");  
  41.         System.out.println();  
  42.                               
  43.         System.out.println("Reading input file...");  
  44.         System.out.println();  
  45.           
  46.         network = readInputFile(inputFileName, modularityFunction);  
  47.         
  48.         System.out.format("Number of nodes: %d%n", network.getNNodes());  
  49.         System.out.format("Number of edges: %d%n", network.getNEdges() / 2);  
  50.         System.out.println();  
  51.         System.out.println("Running " + ((algorithm == 1) ? "Louvain algorithm" : ((algorithm == 2) ? "Louvain algorithm with multilevel refinement" : "smart local moving algorithm")) + "...");  
  52.         System.out.println();  
  53.           
  54.         resolution2 = ((modularityFunction == 1) ? (resolution / network.getTotalEdgeWeight()) : resolution);  
  55.   
  56.         beginTime = System.currentTimeMillis();  
  57.         cluster = null;  
  58.         nClusters = -1;  
  59.         maxModularity = Double.NEGATIVE_INFINITY;  
  60.         random = new Random(100);  
  61.         for (i = 0; i < nRandomStarts; i++)  
  62.         {  
  63.             if (nRandomStarts > 1)  
  64.                 System.out.format("Random start: %d%n", i + 1);  
  65.   
  66.             network.initSingletonClusters();       //网络初始化,每个节点一个簇  
  67.   
  68.             j = 0;  
  69.             update = true;  
  70.             do  
  71.             {  
  72.                 if (nIterations > 1)  
  73.                     System.out.format("Iteration: %d%n", j + 1);  
  74.   
  75.                 if (algorithm == 1)  
  76.                     update = network.runLouvainAlgorithm(resolution2, random);  
  77.            
  78.                 j++;  
  79.   
  80.                 modularity = network.calcQualityFunction(resolution2);  
  81.   
  82.                 if (nIterations > 1)  
  83.                     System.out.format("Modularity: %.4f%n", modularity);  
  84.             }  
  85.             while ((j < nIterations) && update);  
  86.   
  87.             if (modularity > maxModularity)  
  88.             {  
  89.              
  90.                 cluster = network.getClusters();  
  91.                 nClusters = network.getNClusters();  
  92.                 maxModularity = modularity;  
  93.             }  
  94.   
  95.             if (nRandomStarts > 1)  
  96.             {  
  97.                 if (nIterations == 1)  
  98.                     System.out.format("Modularity: %.4f%n", modularity);  
  99.                 System.out.println();  
  100.             }  
  101.         }  
  102.         endTime = System.currentTimeMillis();  
  103.   
  104.           
  105.         if (nRandomStarts == 1)  
  106.         {  
  107.             if (nIterations > 1)  
  108.                 System.out.println();  
  109.             System.out.format("Modularity: %.4f%n", maxModularity);  
  110.         }  
  111.         else  
  112.             System.out.format("Maximum modularity in %d random starts: %.4f%n", nRandomStarts, maxModularity);  
  113.         System.out.format("Number of communities: %d%n", nClusters);  
  114.         System.out.format("Elapsed time: %d seconds%n", Math.round((endTime - beginTime) / 1000.0));  
  115.         System.out.println();  
  116.         System.out.println("Writing output file...");  
  117.         System.out.println();  
  118.          
  119.   
  120.         writeOutputFile(outputFileName, cluster);  
  121.     }  
  122.   
  123.     private static Network readInputFile(String fileName, int modularityFunction) throws IOException  
  124.     {  
  125.         BufferedReader bufferedReader;  
  126.         double[] edgeWeight1, edgeWeight2, nodeWeight;  
  127.         int i, j, nEdges, nLines, nNodes;  
  128.         int[] firstNeighborIndex, neighbor, nNeighbors, node1, node2;  
  129.         Network network;  
  130.         String[] splittedLine;  
  131.   
  132.         bufferedReader = new BufferedReader(new FileReader(fileName));  
  133.   
  134.         nLines = 0;  
  135.         while (bufferedReader.readLine() != null)  
  136.             nLines++;  
  137.   
  138.         bufferedReader.close();  
  139.   
  140.         bufferedReader = new BufferedReader(new FileReader(fileName));  
  141.   
  142.         node1 = new int[nLines];  
  143.         node2 = new int[nLines];  
  144.         edgeWeight1 = new double[nLines];  
  145.         i = -1;  
  146.         for (j = 0; j < nLines; j++)  
  147.         {  
  148.             splittedLine = bufferedReader.readLine().split("\t");  
  149.             node1[j] = Integer.parseInt(splittedLine[0]);  
  150.             if (node1[j] > i)  
  151.                 i = node1[j];  
  152.             node2[j] = Integer.parseInt(splittedLine[1]);  
  153.             if (node2[j] > i)  
  154.                 i = node2[j];  
  155.             edgeWeight1[j] = (splittedLine.length > 2) ? Double.parseDouble(splittedLine[2]) : 1;  
  156.         }  
  157.         nNodes = i + 1;  
  158.   
  159.         bufferedReader.close();  
  160.   
  161.         nNeighbors = new int[nNodes];  
  162.         for (i = 0; i < nLines; i++)  
  163.             if (node1[i] < node2[i])  
  164.             {  
  165.                 nNeighbors[node1[i]]++;  
  166.                 nNeighbors[node2[i]]++;  
  167.             }  
  168.   
  169.         firstNeighborIndex = new int[nNodes + 1];  
  170.         nEdges = 0;  
  171.         for (i = 0; i < nNodes; i++)  
  172.         {  
  173.             firstNeighborIndex[i] = nEdges;  
  174.             nEdges += nNeighbors[i];  
  175.         }  
  176.         firstNeighborIndex[nNodes] = nEdges;  
  177.   
  178.         neighbor = new int[nEdges];  
  179.         edgeWeight2 = new double[nEdges];  
  180.         Arrays.fill(nNeighbors, 0);  
  181.         for (i = 0; i < nLines; i++)  
  182.             if (node1[i] < node2[i])  
  183.             {  
  184.                 j = firstNeighborIndex[node1[i]] + nNeighbors[node1[i]];  
  185.                 neighbor[j] = node2[i];  
  186.                 edgeWeight2[j] = edgeWeight1[i];  
  187.                 nNeighbors[node1[i]]++;  
  188.                 j = firstNeighborIndex[node2[i]] + nNeighbors[node2[i]];  
  189.                 neighbor[j] = node1[i];  
  190.                 edgeWeight2[j] = edgeWeight1[i];  
  191.                 nNeighbors[node2[i]]++;  
  192.             }  
  193.   
  194.      
  195.         {  
  196.             nodeWeight = new double[nNodes];  
  197.             for (i = 0; i < nEdges; i++)  
  198.                 nodeWeight[neighbor[i]] += edgeWeight2[i];  
  199.             network = new Network(nNodes, firstNeighborIndex, neighbor, edgeWeight2, nodeWeight);  
  200.         }  
  201.         
  202.   
  203.         return network;  
  204.     }  
  205.   
  206.     private static void writeOutputFile(String fileName, int[] cluster) throws IOException  
  207.     {  
  208.         BufferedWriter bufferedWriter;  
  209.         int i;  
  210.   
  211.         bufferedWriter = new BufferedWriter(new FileWriter(fileName));  
  212.   
  213.         for (i = 0; i < cluster.length; i++)  
  214.         {  
  215.             bufferedWriter.write(Integer.toString(cluster[i]));  
  216.             bufferedWriter.newLine();  
  217.         }  
  218.   
  219.         bufferedWriter.close();  
  220.     }  
  221. }  


 

Network.java

[java]  view plain  copy
  1. /** 
  2.  * Network 
  3.  * 
  4.  * @author LudoWaltman 
  5.  * @author Nees Janvan Eck 
  6.  * @version 1.2.0,05/14/14 
  7.  */  
  8.    
  9. import java.io.Serializable;  
  10. import java.util.Random;  
  11.    
  12. public class Network implements Cloneable, Serializable  
  13. {  
  14.     private staticfinal long serialVersionUID = 1;  
  15.    
  16.     private intnNodes;  
  17.     private int[]firstNeighborIndex;  
  18.     private int[]neighbor;  
  19.     private double[]edgeWeight;  
  20.    
  21.     private double[]nodeWeight;  
  22.     private intnClusters;  
  23.     private int[]cluster;  
  24.    
  25.     private double[]clusterWeight;  
  26.     private int[]nNodesPerCluster;  
  27.     private int[][]nodePerCluster;  
  28.     private booleanclusteringStatsAvailable;  
  29.    
  30.     publicNetwork(int nNodes, int[] firstNeighborIndex, int[] neighbor, double[]edgeWeight, double[] nodeWeight)  
  31.     {  
  32.         this(nNodes,firstNeighborIndex, neighbor, edgeWeight, nodeWeight, null);  
  33.     }  
  34.    
  35.     publicNetwork(int nNodes, int[] firstNeighborIndex, int[] neighbor, double[]edgeWeight, double[] nodeWeight, int[] cluster)  
  36.     {  
  37.         int i,nEdges;  
  38.    
  39.         this.nNodes= nNodes;  
  40.    
  41.        this.firstNeighborIndex = firstNeighborIndex;  
  42.        this.neighbor = neighbor;  
  43.    
  44.         if(edgeWeight == null)  
  45.         {  
  46.             nEdges =neighbor.length;  
  47.            this.edgeWeight = new double[nEdges];  
  48.             for (i =0; i < nEdges; i++)  
  49.                this.edgeWeight[i] = 1;  
  50.         }  
  51.         else  
  52.            this.edgeWeight = edgeWeight;  
  53.    
  54.         if(nodeWeight == null)  
  55.         {  
  56.            this.nodeWeight = new double[nNodes];  
  57.             for (i =0; i < nNodes; i++)  
  58.                 this.nodeWeight[i] = 1;  
  59.         }  
  60.         else  
  61.            this.nodeWeight = nodeWeight;  
  62.     
  63.     }  
  64.    
  65.    
  66.     public intgetNNodes()  
  67.     {  
  68.         returnnNodes;  
  69.     }  
  70.    
  71.     public intgetNEdges()  
  72.     {  
  73.         returnneighbor.length;  
  74.     }  
  75.    
  76.      
  77.     public doublegetTotalEdgeWeight()  
  78.     {  
  79.         doubletotalEdgeWeight;  
  80.         int i;  
  81.    
  82.        totalEdgeWeight = 0;  
  83.         for (i = 0;i < neighbor.length; i++)  
  84.            totalEdgeWeight += edgeWeight[i];  
  85.    
  86.         returntotalEdgeWeight;  
  87.     }  
  88.    
  89.     public double[] getEdgeWeights()  
  90.     {  
  91.         returnedgeWeight;  
  92.     }  
  93.    
  94.      
  95.    
  96.     public double[]getNodeWeights()  
  97.     {  
  98.         returnnodeWeight;  
  99.     }  
  100.    
  101.     public intgetNClusters()  
  102.     {  
  103.         returnnClusters;  
  104.     }  
  105.    
  106.     public int[]getClusters()  
  107.     {  
  108.         returncluster;  
  109.     }  
  110.    
  111.    
  112.     public voidinitSingletonClusters()  
  113.     {  
  114.         int i;  
  115.    
  116.         nClusters =nNodes;  
  117.         cluster =new int[nNodes];  
  118.         for (i = 0;i < nNodes; i++)  
  119.            cluster[i] = i;  
  120.    
  121.        deleteClusteringStats();  
  122.     }  
  123.    
  124.     public voidmergeClusters(int[] newCluster)  
  125.     {  
  126.         int i, j, k;  
  127.    
  128.         if (cluster== null)  
  129.             return;  
  130.    
  131.         i = 0;  
  132.         for (j = 0;j < nNodes; j++)  
  133.         {  
  134.             k =newCluster[cluster[j]];  
  135.             if (k> i)  
  136.                 i =k;  
  137.            cluster[j] = k;  
  138.         }  
  139.         nClusters =i + 1;  
  140.    
  141.        deleteClusteringStats();  
  142.     }  
  143.      
  144.      
  145.     public NetworkgetReducedNetwork()  
  146.     {  
  147.         double[]reducedNetworkEdgeWeight1, reducedNetworkEdgeWeight2;  
  148.         int i, j, k,l, m, reducedNetworkNEdges1, reducedNetworkNEdges2;  
  149.         int[]reducedNetworkNeighbor1, reducedNetworkNeighbor2;  
  150.         NetworkreducedNetwork;  
  151.    
  152.         if (cluster== null)  
  153.             returnnull;  
  154.    
  155.         if(!clusteringStatsAvailable)  
  156.            calcClusteringStats();  
  157.    
  158.        reducedNetwork = new Network();  
  159.    
  160.        reducedNetwork.nNodes = nClusters;  
  161.        reducedNetwork.firstNeighborIndex = new int[nClusters + 1];  
  162.        
  163.        reducedNetwork.nodeWeight = new double[nClusters];  
  164.    
  165.        reducedNetworkNeighbor1 = new int[neighbor.length];  
  166.        reducedNetworkEdgeWeight1 = new double[edgeWeight.length];  
  167.    
  168.        reducedNetworkNeighbor2 = new int[nClusters - 1];  
  169.        reducedNetworkEdgeWeight2 = new double[nClusters];  
  170.    
  171.        reducedNetworkNEdges1 = 0;  
  172.         for (i = 0;i < nClusters; i++)  
  173.         {  
  174.            reducedNetworkNEdges2 = 0;  
  175.             for (j = 0; j <nodePerCluster[i].length; j++)  
  176.             {  
  177.                 k =nodePerCluster[i][j];           //k是簇i中第j个节点的id  
  178.    
  179.                 for(l = firstNeighborIndex[k]; l < firstNeighborIndex[k + 1]; l++)  
  180.                 {  
  181.                     m = cluster[neighbor[l]];       //m是k的在l位置的邻居节点所属的簇id  
  182.                    if (m != i)  
  183.                    {  
  184.                        if (reducedNetworkEdgeWeight2[m] == 0)  
  185.                        {  
  186.                            reducedNetworkNeighbor2[reducedNetworkNEdges2] = m;  
  187.                            reducedNetworkNEdges2++;  
  188.                        }  
  189.                        reducedNetworkEdgeWeight2[m] += edgeWeight[l];  
  190.                    }  
  191.                 
  192.                 }  
  193.    
  194.                reducedNetwork.nodeWeight[i] += nodeWeight[k];  
  195.             }  
  196.    
  197.             for (j =0; j < reducedNetworkNEdges2; j++)  
  198.             {  
  199.                reducedNetworkNeighbor1[reducedNetworkNEdges1 + j] = reducedNetworkNeighbor2[j];  
  200.                reducedNetworkEdgeWeight1[reducedNetworkNEdges1 + j] =reducedNetworkEdgeWeight2[reducedNetworkNeighbor2[j]];  
  201.                reducedNetworkEdgeWeight2[reducedNetworkNeighbor2[j]] = 0;  
  202.             }  
  203.            reducedNetworkNEdges1 += reducedNetworkNEdges2;  
  204.    
  205.            reducedNetwork.firstNeighborIndex[i + 1] = reducedNetworkNEdges1;  
  206.         }  
  207.    
  208.        reducedNetwork.neighbor = new int[reducedNetworkNEdges1];  
  209.        reducedNetwork.edgeWeight = new double[reducedNetworkNEdges1];  
  210.        System.arraycopy(reducedNetworkNeighbor1, 0, reducedNetwork.neighbor, 0,reducedNetworkNEdges1);  
  211.        System.arraycopy(reducedNetworkEdgeWeight1, 0,reducedNetwork.edgeWeight, 0, reducedNetworkNEdges1);  
  212.    
  213.         returnreducedNetwork;  
  214.     }  
  215.      
  216.    
  217.     public doublecalcQualityFunction(double resolution)  
  218.     {  
  219.         doublequalityFunction, totalEdgeWeight;  
  220.         int i, j, k;  
  221.    
  222.         if (cluster== null)  
  223.             returnDouble.NaN;  
  224.    
  225.         if(!clusteringStatsAvailable)  
  226.            calcClusteringStats();  
  227.    
  228.        qualityFunction = 0;  
  229.                
  230.        totalEdgeWeight = 0;  
  231.         for (i = 0;i < nNodes; i++)  
  232.         {  
  233.             j =cluster[i];  
  234.             for (k =firstNeighborIndex[i]; k < firstNeighborIndex[i + 1]; k++)  
  235.             {  
  236.                 if(cluster[neighbor[k]] == j)  
  237.                    qualityFunction += edgeWeight[k];  
  238.                totalEdgeWeight += edgeWeight[k];  
  239.             }  
  240.         }  
  241.    
  242.         for (i = 0;i < nClusters; i++)  
  243.            qualityFunction -= clusterWeight[i] * clusterWeight[i] * resolution;  
  244.    
  245.        qualityFunction /= totalEdgeWeight;  
  246.    
  247.         returnqualityFunction;  
  248.     }  
  249.    
  250.      
  251.     public booleanrunLocalMovingAlgorithm(double resolution)  
  252.     {  
  253.         returnrunLocalMovingAlgorithm(resolution, new Random());  
  254.     }  
  255.    
  256.     public booleanrunLocalMovingAlgorithm(double resolution, Random random)  
  257.     {  
  258.         booleanupdate;  
  259.         doublemaxQualityFunction, qualityFunction;  
  260.         double[]clusterWeight, edgeWeightPerCluster;  
  261.         intbestCluster, i, j, k, l, nNeighboringClusters, nStableNodes, nUnusedClusters;  
  262.         int[]neighboringCluster, newCluster, nNodesPerCluster, nodeOrder, unusedCluster;  
  263.    
  264.         if ((cluster== null) || (nNodes == 1))  
  265.             returnfalse;  
  266.    
  267.         update =false;  
  268.    
  269.        clusterWeight = new double[nNodes];  
  270.        nNodesPerCluster = new int[nNodes];  
  271.         for (i = 0;i < nNodes; i++)  
  272.         {  
  273.            clusterWeight[cluster[i]] += nodeWeight[i];  
  274.            nNodesPerCluster[cluster[i]]++;  
  275.         }  
  276.    
  277.        nUnusedClusters = 0;  
  278.        unusedCluster = new int[nNodes];  
  279.         for (i = 0;i < nNodes; i++)  
  280.             if(nNodesPerCluster[i] == 0)  
  281.             {  
  282.                unusedCluster[nUnusedClusters] = i;  
  283.                nUnusedClusters++;  
  284.             }  
  285.    
  286.         nodeOrder =new int[nNodes];  
  287.         for (i = 0;i < nNodes; i++)  
  288.            nodeOrder[i] = i;  
  289.         for (i = 0;i < nNodes; i++)  
  290.         {  
  291.             j = random.nextInt(nNodes);  
  292.             k =nodeOrder[i];  
  293.            nodeOrder[i] = nodeOrder[j];  
  294.            nodeOrder[j] = k;  
  295.         }  
  296.    
  297.        edgeWeightPerCluster = new double[nNodes];  
  298.        neighboringCluster = new int[nNodes - 1];  
  299.    
  300.         nStableNodes = 0;  
  301.         i = 0;  
  302.         do  
  303.         {  
  304.             j =nodeOrder[i];  
  305.    
  306.            nNeighboringClusters = 0;  
  307.             for (k =firstNeighborIndex[j]; k < firstNeighborIndex[j + 1]; k++)  
  308.             {  
  309.                 l =cluster[neighbor[k]];  
  310.                 if(edgeWeightPerCluster[l] == 0)  
  311.                 {  
  312.                    neighboringCluster[nNeighboringClusters] = l;  
  313.                    nNeighboringClusters++;  
  314.                 }  
  315.                 edgeWeightPerCluster[l]+= edgeWeight[k];  
  316.             }  
  317.    
  318.            clusterWeight[cluster[j]] -= nodeWeight[j];  
  319.            nNodesPerCluster[cluster[j]]--;  
  320.             if(nNodesPerCluster[cluster[j]] == 0)  
  321.             {  
  322.                unusedCluster[nUnusedClusters] = cluster[j];  
  323.                nUnusedClusters++;  
  324.             }  
  325.    
  326.            bestCluster = -1;  
  327.            maxQualityFunction = 0;  
  328.             for (k =0; k < nNeighboringClusters; k++)  
  329.             {  
  330.                 l =neighboringCluster[k];  
  331.                qualityFunction = edgeWeightPerCluster[l] - nodeWeight[j] *clusterWeight[l] * resolution;  
  332.                 if((qualityFunction > maxQualityFunction) || ((qualityFunction ==maxQualityFunction) && (l < bestCluster)))  
  333.                 {  
  334.                     bestCluster = l;  
  335.                    maxQualityFunction = qualityFunction;  
  336.                 }  
  337.                edgeWeightPerCluster[l] = 0;  
  338.             }  
  339.             if(maxQualityFunction == 0)  
  340.             {  
  341.                bestCluster = unusedCluster[nUnusedClusters - 1];  
  342.                nUnusedClusters--;  
  343.             }  
  344.    
  345.            clusterWeight[bestCluster] += nodeWeight[j];  
  346.            nNodesPerCluster[bestCluster]++;  
  347.             if(bestCluster == cluster[j])  
  348.                nStableNodes++;  
  349.             else  
  350.             {  
  351.                cluster[j] = bestCluster;  
  352.                nStableNodes = 1;  
  353.                update = true;  
  354.             }  
  355.    
  356.             i = (i< nNodes - 1) ? (i + 1) : 0;  
  357.         }  
  358.         while(nStableNodes < nNodes);             //优化步骤是直到所有的点都稳定下来才结束  
  359.    
  360.         newCluster =new int[nNodes];  
  361.         nClusters =0;  
  362.         for (i = 0;i < nNodes; i++)  
  363.             if(nNodesPerCluster[i] > 0)  
  364.             {  
  365.                newCluster[i] = nClusters;  
  366.                nClusters++;  
  367.             }  
  368.         for (i = 0;i < nNodes; i++)  
  369.            cluster[i] = newCluster[cluster[i]];  
  370.    
  371.        deleteClusteringStats();  
  372.    
  373.         returnupdate;  
  374.     }  
  375.      
  376.      
  377.    
  378.     public booleanrunLouvainAlgorithm(double resolution)  
  379.     {  
  380.         return runLouvainAlgorithm(resolution,new Random());  
  381.     }  
  382.    
  383.     public booleanrunLouvainAlgorithm(double resolution, Random random)  
  384.     {  
  385.         booleanupdate, update2;  
  386.         NetworkreducedNetwork;  
  387.    
  388.         if ((cluster== null) || (nNodes == 1))  
  389.             returnfalse;  
  390.    
  391.         update =runLocalMovingAlgorithm(resolution, random);  
  392.    
  393.         if(nClusters < nNodes)  
  394.         {  
  395.            reducedNetwork = getReducedNetwork();  
  396.            reducedNetwork.initSingletonClusters();  
  397.    
  398.             update2= reducedNetwork.runLouvainAlgorithm(resolution, random);  
  399.    
  400.             if(update2)  
  401.             {  
  402.                update = true;  
  403.    
  404.                mergeClusters(reducedNetwork.getClusters());  
  405.             }  
  406.         }  
  407.    
  408.        deleteClusteringStats();  
  409.    
  410.         return update;  
  411.     }  
  412.    
  413.    
  414.     privateNetwork()  
  415.     {  
  416.     }  
  417.     
  418.    
  419.     private voidcalcClusteringStats()  
  420.     {  
  421.         int i, j;  
  422.    
  423.        clusterWeight = new double[nClusters];  
  424.        nNodesPerCluster = new int[nClusters];  
  425.        nodePerCluster = new int[nClusters][];  
  426.    
  427.         for (i = 0;i < nNodes; i++)  
  428.         {  
  429.            clusterWeight[cluster[i]] += nodeWeight[i];  
  430.            nNodesPerCluster[cluster[i]]++;  
  431.         }  
  432.    
  433.         for (i = 0;i < nClusters; i++)  
  434.         {  
  435.            nodePerCluster[i] = new int[nNodesPerCluster[i]];  
  436.            nNodesPerCluster[i] = 0;  
  437.         }  
  438.    
  439.         for (i = 0;i < nNodes; i++)  
  440.         {  
  441.             j =cluster[i];  
  442.            nodePerCluster[j][nNodesPerCluster[j]] = i;  
  443.             nNodesPerCluster[j]++;  
  444.         }  
  445.    
  446.        clusteringStatsAvailable = true;  
  447.     }  
  448.    
  449.      
  450.     private voiddeleteClusteringStats()  
  451.     {  
  452.        clusterWeight = null;  
  453.        nNodesPerCluster = null;  
  454.        nodePerCluster = null;  
  455.    
  456.        clusteringStatsAvailable = false;  
  457.     }  
  458. }  


 

算法的效果

对karate数据集


分簇结果


在facebook,4039个数据集上的结果



 

下载的java 版本代码不好理解,尤其是 firstneighborindex 等数组表示什么意思等,于是我借鉴它,实现了一个新的版本,这里面的代码容易理解一些,并且给里面的变量、函数以及关键步骤都加了一些注释

 

而且在代码中增加了输出分簇之后的网络图的功能,输出一个gml文件,输入节点的节点和边信息都保留了,初次之外,加上了分簇的结果,即每一个节点属于哪一个簇,在node中加了一个type字段来表示,这样就可以在gephi中直接依据type字段来查看分割好的社团。

 

与下载的不一致的是,我们的输入文件第一行需要给出网络中节点的数量

以下是程序的代码

DataSet.java

[java]  view plain  copy
  1. packagecommunitydetection;  
  2.    
  3. importjava.io.*;  
  4. importjava.util.*;  
  5.    
  6. public classDataSet {  
  7.      
  8.     double weight[][];  
  9.      
  10.     LinkedList neighborlist[];  
  11.      
  12.     double totalEdgeWeights = 0;  
  13.      
  14.     int nodecount;  
  15.      
  16.     double nodeweight[];  
  17.      
  18.     DataSet(String filename) throws IOException  
  19.     {  
  20.        BufferedReader reader = newBufferedReader(new FileReader(filename));  
  21.         
  22.        String line = reader.readLine();  
  23.        nodecount = Integer.parseInt(line);    //读文件,文件第一行为节点的数量  
  24.         
  25.        weight = new double[nodecount][nodecount];       
  26.         
  27.        neighborlist = new LinkedList[nodecount];  
  28.        for(int i=0 ;i < nodecount;i++)  
  29.            neighborlist[i] = newLinkedList<Integer>();  
  30.         
  31.        nodeweight = new double[nodecount];  
  32.        for(int i=0;i<nodecount;i++)  
  33.            nodeweight[i] = 0;  
  34.         
  35.        while((line = reader.readLine())!=null)  
  36.        {  
  37.            String args[] =line.split("\t");  
  38.            int node1 =Integer.parseInt(args[0]);  
  39.            int node2 = Integer.parseInt(args[1]);  
  40.             
  41.            if(node1 != node2)  
  42.            {  
  43.               neighborlist[node1].add(node2);  
  44.               neighborlist[node2].add(node1);  
  45.            }  
  46.             
  47.            if(args.length > 2)  
  48.            {  
  49.               double we =Double.parseDouble(args[2]);  
  50.               weight[node1][node2] = we;  
  51.               weight[node2][node1] = we;              
  52.               totalEdgeWeights += we;  
  53.    
  54.               nodeweight[node1] += we;  
  55.               if(node2 != node1)  
  56.                   nodeweight[node2] += we;  
  57.                
  58.            }  
  59.            else  
  60.            {  
  61.               weight[node1][node2] = 1;  
  62.               weight[node2][node1] = 1;  
  63.               totalEdgeWeights += 1;  
  64.                
  65.               nodeweight[node1] += 1;  
  66.               if(node2 != node1)  
  67.                   nodeweight[node2] += 1;  
  68.            }  
  69.                       
  70.        }  
  71.         
  72.                
  73.        reader.close();  
  74.     }  
  75.      
  76.      
  77.      
  78. }  


 

NetWork.java

[java]  view plain  copy
  1. package communitydetection;  
  2. import java.util.*;  
  3. import java.io.*;  
  4.    
  5. public class NetWork {  
  6.    
  7.        double weight[][];                    //图中两节点的连接边的权重  
  8.         
  9.        LinkedListneighborlist[];            //每个节点的邻居节点有哪些  
  10.                
  11.        doublenodeweight[];                  //每个节点的权值  
  12.                
  13.        intnodecount;                        //图中节点的总数量  
  14.         
  15.        intcluster[];                        //记录每个节点属于哪一个簇  
  16.         
  17.        intclustercount;                     //簇的总数量  
  18.         
  19.        doubleclusterweight[];               //每一个簇的权重  
  20.         
  21.        booleanclusteringStatsAvailable ;    //当前的网络信息是否完全  
  22.         
  23.        intnodecountsPercluster[];           //每个簇有多少个节点  
  24.        intnodePercluster[][];               //nodePercluster[i][j]表示簇i中第j个节点的id  
  25.         
  26.        NetWork(Stringfilename) throws IOException  
  27.        {  
  28.               DataSetds = new DataSet(filename);         //ds是用来读取输入文件内容的  
  29.               weight= ds.weight;  
  30.               neighborlist= ds.neighborlist;  
  31.         
  32.               nodecount= ds.nodecount;             
  33.               nodeweight= ds.nodeweight;  
  34.                
  35.               initSingletonClusters();             
  36.                       
  37.        }  
  38.         
  39.        NetWork()  
  40.        {  
  41.                
  42.        }  
  43.         
  44.        publicdouble getTotalEdgeWeight()            //获取网络图中所有的边的权值之和, 返回的结果实际上是2倍  
  45.     {                                                                             //因为每一条边被计算了2次  
  46.         doubletotalEdgeWeight;  
  47.         int i;  
  48.    
  49.        totalEdgeWeight = 0;  
  50.    
  51.         for (i= 0; i < nodecount; i++)  
  52.         {  
  53.              for(intj=0;j<neighborlist[i].size();j++)  
  54.              {  
  55.                     int neighborid =(Integer)neighborlist[i].get(j);  
  56.                     totalEdgeWeight +=weight[i][neighborid];  
  57.              }  
  58.         }  
  59.    
  60.         returntotalEdgeWeight;  
  61.     }  
  62.    
  63.           
  64.     publicvoid initSingletonClusters()           //给每个节点指派一个簇  
  65.     {  
  66.         int i;  
  67.    
  68.        clustercount = nodecount;  
  69.        cluster = new int[nodecount];  
  70.         for (i= 0; i < nodecount; i++)  
  71.            cluster[i] = i;  
  72.    
  73.        deleteClusteringStats();                    
  74.     }  
  75.         
  76.                
  77.     privatevoid calcClusteringStats()             //统计好每个簇有多少个节点,以及每个簇中的节点都有哪些  
  78.     {  
  79.         int i,j;  
  80.    
  81.        clusterweight = new double[clustercount];  
  82.        nodecountsPercluster = new int[clustercount];  
  83.        nodePercluster = new int[clustercount][];  
  84.    
  85.         for (i= 0; i < nodecount; i++)  
  86.         {    
  87.              //计算每一个簇的权值,簇的权值是其中的节点的权值之和  
  88.            clusterweight[cluster[i]] += nodeweight[i];  
  89.            nodecountsPercluster[cluster[i]]++;  
  90.         }  
  91.    
  92.         for (i= 0; i < clustercount; i++)  
  93.         {  
  94.            nodePercluster[i] = new int[nodecountsPercluster[i]];  
  95.            nodecountsPercluster[i] = 0;  
  96.         }  
  97.    
  98.         for (i= 0; i < nodecount; i++)  
  99.         {  
  100.             j= cluster[i];            //j是簇编号, 记录每一个簇中的第几个节点的id  
  101.            nodePercluster[j][nodecountsPercluster[j]] = i;  
  102.           nodecountsPercluster[j]++;  
  103.         }  
  104.    
  105.        clusteringStatsAvailable = true;  
  106.     }  
  107.      
  108.       
  109.         
  110.     privatevoid deleteClusteringStats()  
  111.     {  
  112.        clusterweight = null;  
  113.        nodecountsPercluster = null;  
  114.        nodePercluster = null;  
  115.    
  116.        clusteringStatsAvailable = false;  
  117.     }  
  118.    
  119.     publicint[] getClusters()  
  120.     {  
  121.         returncluster;  
  122.     }  
  123.      
  124.      
  125.     publicdouble calcQualityFunction(double resolution)       //计算模块度的值, 如果所有边的权重之和为m  
  126.     {                                                                                                  //那么resolution就是1/(2m)    
  127.         doublequalityFunction, totalEdgeWeight;  
  128.         int i,j, k;  
  129.    
  130.         if(cluster == null)  
  131.            return Double.NaN;  
  132.    
  133.         if(!clusteringStatsAvailable)  
  134.            calcClusteringStats();  
  135.    
  136.        qualityFunction = 0;  
  137.          
  138.        totalEdgeWeight = 0;  
  139.      
  140.         for (i= 0; i < nodecount; i++)  
  141.         {  
  142.             j= cluster[i];  
  143.              
  144.            for( k=0;k<neighborlist[i].size();k++)  
  145.             {  
  146.                 int neighborid =(Integer)neighborlist[i].get(k);  
  147.                 if(cluster[neighborid] == j)  
  148.                        qualityFunction += weight[i][neighborid];  
  149.                 totalEdgeWeight += weight[i][neighborid];  
  150.             }                                                                                      //最终的totalEdgeWeight也是  
  151.                                                                                                          //图中所有边权重之和的2倍  
  152.         }  
  153.    
  154.         for (i= 0; i < clustercount; i++)  
  155.            qualityFunction -= clusterweight[i] * clusterweight[i] * resolution;  
  156.    
  157.        qualityFunction /= totalEdgeWeight;  
  158.    
  159.         returnqualityFunction;  
  160.     }  
  161.    
  162.     public intgetNClusters()  
  163.     {  
  164.         returnclustercount;  
  165.     }  
  166.      
  167.     public voidmergeClusters(int[] newCluster) //newcluster是reduced之后的reducednetwork中的所属簇信息  
  168.     {                                                                           
  169.         int i,j, k;                                                
  170.    
  171.         if(cluster == null)  
  172.            return;  
  173.    
  174.         i = 0;  
  175.         for (j= 0; j < nodecount; j++)  
  176.         {  
  177.             k= newCluster[cluster[j]];      //reducednetwork中的newcluster的一个下标相当于        
  178.             if(k > i)                                          //reduce之前的网络中的每一个簇  
  179.                i = k;  
  180.            cluster[j] = k;  
  181.         }  
  182.        clustercount = i + 1;  
  183.    
  184.        deleteClusteringStats();  
  185.     }  
  186.      
  187.     publicNetWork getReducedNetwork()            //将整个网络进行reduce操作  
  188.     {  
  189.        double[] reducedNetworkEdgeWeight2;  
  190.         int i,j, k, l, m,reducedNetworkNEdges2;  
  191.        int[]  reducedNetworkNeighbor2;  
  192.        NetWork reducedNetwork;  
  193.    
  194.         if (cluster== null)  
  195.            return null;  
  196.    
  197.         if(!clusteringStatsAvailable)  
  198.            calcClusteringStats();  
  199.    
  200.        reducedNetwork = new NetWork();  
  201.    
  202.        reducedNetwork.nodecount = clustercount;    //reduce之后,原来的一个簇就是现在的一个节点  
  203.     
  204.        reducedNetwork.neighborlist = new LinkedList[clustercount];  
  205.         for(i=0;i<clustercount;i++)  
  206.              reducedNetwork.neighborlist[i] = newLinkedList();  
  207.          
  208.          
  209.        reducedNetwork.nodeweight = new double[clustercount];  
  210.          
  211.        reducedNetwork.weight = new double[clustercount][clustercount];  
  212.          
  213.          
  214.        reducedNetworkNeighbor2 = new int[clustercount -1];  
  215.        reducedNetworkEdgeWeight2 = new double[clustercount];  
  216.    
  217.    
  218.         for (i= 0; i < clustercount; i++)  
  219.         {  
  220.            reducedNetworkNEdges2 = 0;  
  221.            for (j = 0; j < nodePercluster[i].length; j++)  
  222.             {  
  223.                k = nodePercluster[i][j];          //k是原来的簇i中第j个节点的id  
  224.    
  225.                for( l=0;l<neighborlist[k].size();l++)  
  226.                 {  
  227.                   int nodeid =(Integer)neighborlist[k].get(l);  
  228.                   m = cluster[nodeid];  
  229.                    
  230.                   if( m != i)    //reduce之前簇i与簇m相连,应为它们之间有边存在,edge(k,nodeid)  
  231.                   {  
  232.                          if(reducedNetworkEdgeWeight2[m]== 0)  
  233.                          {  
  234.                                 //以前的簇邻居变成了现在的节点邻居  
  235.                                 reducedNetworkNeighbor2[reducedNetworkNEdges2]= m;  
  236.                                 reducedNetworkNEdges2++;  
  237.                                 //reducedNetworkEdges记录在新的图中新的节点i(原来的簇i)有多少个邻居  
  238.                          }  
  239.                          reducedNetworkEdgeWeight2[m]+= weight[k][nodeid];  
  240.                          //新的节点i与新的邻居节点m的之间的边权重的更新  
  241.                   }  
  242.                                                  
  243.                }  
  244.                  
  245.                reducedNetwork.nodeweight[i] += nodeweight[k];  
  246.                //现在的节点i是以前的簇i, 以前的节点k在以前的簇i中,所以现在的节点i的权重包含以前节点k的权重  
  247.             }  
  248.             
  249.             
  250.            for (j = 0; j < reducedNetworkNEdges2; j++)  
  251.             {  
  252.                reducedNetwork.neighborlist[i].add(reducedNetworkNeighbor2[j]);  
  253.                reducedNetwork.weight[i][reducedNetworkNeighbor2[j]] =reducedNetworkEdgeWeight2[reducedNetworkNeighbor2[j]];  
  254.                reducedNetworkEdgeWeight2[reducedNetworkNeighbor2[j]] = 0;                 
  255.                // =0是为了数组复用,不然每次都要开辟新的数组存放与新的邻居节点之间的边的权值  
  256.             }  
  257.              
  258.         }  
  259.                     
  260.         returnreducedNetwork;  
  261.     }  
  262.      
  263.     
  264.     publicboolean runLocalMovingAlgorithm(double resolution)  
  265.     {  
  266.         returnrunLocalMovingAlgorithm(resolution, new Random());  
  267.     }  
  268.      
  269.     //将每一个节点移入到'最好'的簇当中去  
  270.     publicboolean runLocalMovingAlgorithm(double resolution, Random random)  
  271.     {  
  272.        boolean update;  
  273.         doublemaxQualityFunction, qualityFunction;  
  274.        double[] clusterWeight, edgeWeightPerCluster;  
  275.         intbestCluster, i, j, k, l, nNeighboringClusters, nStableNodes, nUnusedClusters;  
  276.         int[]neighboringCluster, newCluster, nNodesPerCluster, nodeOrder, unusedCluster;  
  277.    
  278.         if((cluster == null) || (nodecount == 1))  
  279.            return false;  
  280.    
  281.         update= false;  
  282.    
  283.        clusterWeight = new double[nodecount];  
  284.        nNodesPerCluster = new int[nodecount];       //记录每一个簇中有多少个节点  
  285.         for (i = 0; i < nodecount; i++)  
  286.         {  
  287.            clusterWeight[cluster[i]] += nodeweight[i];  
  288.            nNodesPerCluster[cluster[i]]++;  
  289.         }  
  290.    
  291.        nUnusedClusters = 0;  
  292.        unusedCluster = new int[nodecount];        //统计在整个过程当中,哪些簇一个节点也没有  
  293.         for (i= 0; i <nodecount; i++)             //这些簇在之后会被消除  
  294.             if(nNodesPerCluster[i] == 0)  
  295.             {  
  296.                unusedCluster[nUnusedClusters] = i;  
  297.                nUnusedClusters++;  
  298.             }  
  299.    
  300.        nodeOrder = new int[nodecount];  
  301.         for (i= 0; i < nodecount; i++)  
  302.            nodeOrder[i] = i;  
  303.         for (i= 0; i < nodecount; i++)    //nodeOrder将节点顺序打乱,防止由于顺序问题得不到最好的结果  
  304.         {  
  305.             j= random.nextInt(nodecount);  
  306.             k= nodeOrder[i];  
  307.            nodeOrder[i] = nodeOrder[j];  
  308.            nodeOrder[j] = k;  
  309.         }  
  310.    
  311.        edgeWeightPerCluster = new double[nodecount];  
  312.        neighboringCluster = new int[nodecount -1];  
  313.    
  314.        nStableNodes = 0;  
  315.         i = 0;  
  316.         do  
  317.         {  
  318.             j= nodeOrder[i];             //j是某一个节点的编号  
  319.    
  320.            nNeighboringClusters = 0;  
  321.             
  322.              
  323.            for(k = 0; k<neighborlist[j].size();k++)  
  324.             {  
  325.                 int nodeid =(Integer)neighborlist[j].get(k);  //nodeid是j的一个邻居节点的编号  
  326.                 l = cluster[nodeid];                            //l是nodeid所属的簇编号  
  327.              
  328.                 if(edgeWeightPerCluster[l] == 0)           //统计与节点j相连的簇有哪些  
  329.                 {  
  330.                         neighboringCluster[nNeighboringClusters] = l;  
  331.                         nNeighboringClusters++;  
  332.                 }  
  333.                  
  334.                 edgeWeightPerCluster[l] +=weight[j][nodeid];  
  335.                 //edgeWeightperCluster[l]记录的是如果将节点j加入到簇l当中,簇l内部的边权值的增量大小  
  336.             }  
  337.              
  338.             //节点j之前所属的簇做相应的变更  
  339.            clusterWeight[cluster[j]] -= nodeweight[j];  
  340.            nNodesPerCluster[cluster[j]]--;  
  341.              
  342.             if(nNodesPerCluster[cluster[j]] == 0)  
  343.             {  
  344.                unusedCluster[nUnusedClusters] = cluster[j];  
  345.                nUnusedClusters++;  
  346.             }  
  347.    
  348.            bestCluster = -1;              //最好的加入的簇下标  
  349.            maxQualityFunction = 0;  
  350.            for (k = 0; k < nNeighboringClusters; k++)  
  351.             {  
  352.                 l = neighboringCluster[k];  
  353.                qualityFunction = edgeWeightPerCluster[l] - nodeweight[j] *clusterWeight[l] * resolution;  
  354.                if ((qualityFunction > maxQualityFunction) || ((qualityFunction ==maxQualityFunction) && (l < bestCluster)))  
  355.                {  
  356.                    bestCluster = l;  
  357.                    maxQualityFunction = qualityFunction;  
  358.                }  
  359.                edgeWeightPerCluster[l] = 0;  
  360.                // =0是为了数组复用,  
  361.             }  
  362.             if(maxQualityFunction == 0)   //无论到哪一簇都不会有提升  
  363.             {  
  364.                bestCluster = unusedCluster[nUnusedClusters - 1];  
  365.                nUnusedClusters--;  
  366.             }  
  367.    
  368.            clusterWeight[bestCluster] += nodeweight[j];  
  369.             nNodesPerCluster[bestCluster]++;  //最佳簇的节点数量+1  
  370.             if(bestCluster == cluster[j])   
  371.                nStableNodes++;        //还在原来的簇当中,表示该节点是稳定的,稳定节点的数量+1  
  372.            else  
  373.             {  
  374.                cluster[j] = bestCluster;  
  375.                nStableNodes = 1;  
  376.                update = true;       //能移动到新的簇当中去,然后需要重新考虑每个节点是否稳定  
  377.             }  
  378.    
  379.             i= (i < nodecount - 1) ? (i + 1) : 0;  
  380.         }  
  381.         while(nStableNodes < nodecount);            //优化步骤是直到所有的点都稳定下来才结束  
  382.    
  383.        newCluster = new int[nodecount];  
  384.        clustercount = 0;  
  385.         for (i= 0; i < nodecount; i++)  
  386.             if(nNodesPerCluster[i] > 0)  
  387.             {                                                                 //统计以前的簇编号还有多少能用,然后从0开始重新对它们编号  
  388.                newCluster[i] = clustercount;  
  389.                clustercount++;  
  390.             }  
  391.         for (i= 0; i < nodecount; i++)  
  392.            cluster[i] = newCluster[cluster[i]];  
  393.    
  394.        deleteClusteringStats();  
  395.    
  396.         returnupdate;  
  397.     }  
  398.      
  399.      
  400.      
  401.     publicboolean runLouvainAlgorithm(double resolution)  
  402.     {  
  403.         returnrunLouvainAlgorithm(resolution, new Random());  
  404.     }  
  405.    
  406.     publicboolean runLouvainAlgorithm(double resolution, Random random)  
  407.     {  
  408.        boolean update, update2;  
  409.        NetWork reducedNetwork;  
  410.    
  411.         if((cluster == null) || (nodecount == 1))  
  412.            return false;  
  413.    
  414.         update= runLocalMovingAlgorithm(resolution, random);  
  415.        //update表示是否有节点变动,即是否移动到了新的簇当中去  
  416.                  
  417.         if(clustercount < nodecount)   //簇的数量小于节点的数量,说明可以进行reduce操作,ruduce不会改变  
  418.         {                                                    //modularity的值  
  419.            reducedNetwork = getReducedNetwork();  
  420.            reducedNetwork.initSingletonClusters();  
  421.    
  422.            update2 = reducedNetwork.runLouvainAlgorithm(resolution, random);  
  423.            //update2表示在reduce之后的网络中是否有节点移动到新的簇当中去  
  424.              
  425.             if(update2)  
  426.             {  
  427.                update = true;  
  428.    
  429.                mergeClusters(reducedNetwork.getClusters());  
  430.                //有变动的话,至少是簇的顺序变掉了,或者是簇的数量减少了  
  431.                  
  432.             }  
  433.         }  
  434.    
  435.        deleteClusteringStats();  
  436.    
  437.         returnupdate;  
  438.     }  
  439.    
  440.      
  441.     publicvoid generategml() throws IOException  
  442.     {  
  443.            
  444.           BufferedWriter writer = newBufferedWriter(new FileWriter("generated.gml"));  
  445.            
  446.           writer.append("graph\n");  
  447.           writer.append("[\n");  
  448.           for(int i=0;i<nodecount;i++)  
  449.           {  
  450.                  writer.append("  node\n");  
  451.                  writer.append("  [\n");  
  452.                  writer.append("    id "+i+"\n");  
  453.                  writer.append("    type "+cluster[i]+"\n");  
  454.                  writer.append("  ]\n");  
  455.           }  
  456.            
  457.           for(int i=0;i<nodecount;i++)  
  458.                  for(int j=i+1;j<nodecount;j++)  
  459.                  {  
  460.                         if(weight[i][j] != 0)  
  461.                         {  
  462.                                writer.append("  edge\n");  
  463.                            writer.append("  [\n");  
  464.                            writer.append("    source "+i+"\n");  
  465.                            writer.append("    target "+j+"\n");  
  466.                            writer.append("  ]\n");  
  467.                                                           
  468.                         }  
  469.                          
  470.                          
  471.                  }  
  472.            
  473.           writer.append("]\n");  
  474.            
  475.            
  476.           writer.close();  
  477.     }  
  478.      
  479.      
  480.         
  481. }  


Main.java

[java]  view plain  copy
  1. package communitydetection;  
  2. import java.io.*;  
  3. import java.util.*;  
  4.    
  5. public class Main {  
  6.                       
  7.        staticvoid detect() throws IOException  
  8.        {  
  9.                NetWork network;  
  10.                
  11.                
  12.               Stringfilename = "karate_club_network.txt";  
  13.                
  14.               doublemodularity, resolution, maxModularity;  
  15.                
  16.               doublebeginTime, endTime;  
  17.           
  18.               int[]cluster;  
  19.                
  20.               intnRandomStarts = 5;  
  21.                
  22.               intnIterations = 3;  
  23.                
  24.               network= new NetWork(filename);  
  25.                
  26.               resolution= 1.0/network.getTotalEdgeWeight();  
  27.                
  28.               beginTime= System.currentTimeMillis();  
  29.        cluster = null;  
  30.         int nClusters= -1;  
  31.         inti,j;  
  32.        maxModularity = Double.NEGATIVE_INFINITY;  
  33.         Randomrandom = new Random(100);  
  34.         for (i= 0; i < nRandomStarts; i++)  
  35.         {  
  36.             if( (nRandomStarts > 1))  
  37.                System.out.format("Random start: %d%n", i + 1);  
  38.    
  39.            network.initSingletonClusters();      //网络初始化,每个节点一个簇  
  40.    
  41.             j= 0;  
  42.            boolean update = true;         //update表示网络是否有节点移动  
  43.             do  
  44.             {  
  45.                if ( (nIterations > 1))  
  46.                    System.out.format("Iteration: %d%n", j + 1);  
  47.        
  48.                update = network.runLouvainAlgorithm(resolution, random);  
  49.           
  50.                j++;  
  51.    
  52.                modularity = network.calcQualityFunction(resolution);  
  53.    
  54.                if ((nIterations > 1))  
  55.                    System.out.format("Modularity: %.4f%n", modularity);  
  56.             }  
  57.            while ((j < nIterations) && update);  
  58.             
  59.                  
  60.             if(modularity > maxModularity)  
  61.             {  
  62.            
  63.                cluster = network.getClusters();  
  64.                nClusters = network.getNClusters();  
  65.                maxModularity = modularity;  
  66.             }  
  67.    
  68.             if((nRandomStarts > 1))  
  69.             {  
  70.                if (nIterations == 1)  
  71.                    System.out.format("Modularity: %.4f%n", modularity);  
  72.                System.out.println();  
  73.             }  
  74.         }  
  75.        endTime = System.currentTimeMillis();  
  76.          
  77.        network.generategml();  
  78.          
  79.         if(nRandomStarts == 1)  
  80.         {  
  81.             if(nIterations > 1)  
  82.                System.out.println();  
  83.            System.out.format("Modularity: %.4f%n", maxModularity);  
  84.         }  
  85.         else  
  86.            System.out.format("Maximum modularity in %d random starts:%.4f%n", nRandomStarts, maxModularity);  
  87.        System.out.format("Number of communities: %d%n", nClusters);  
  88.        System.out.format("Elapsed time: %f seconds%n", (endTime -beginTime) / 1000.0);  
  89.        System.out.println();  
  90.         System.out.println("Writingoutput file...");  
  91.        System.out.println();  
  92.          
  93.  //      writeOutputFile("communities.txt", cluster);  
  94.                                            
  95.        }  
  96.         
  97.        //将每一个节点所属的簇的下标写到文件当中去  
  98.     privatestatic void writeOutputFile(String fileName, int[] cluster) throws IOException  
  99.     {  
  100.            
  101.        BufferedWriter bufferedWriter;  
  102.         int i;  
  103.    
  104.        bufferedWriter = new BufferedWriter(new FileWriter(fileName));  
  105.    
  106.         for (i= 0; i < cluster.length; i++)  
  107.         {  
  108.            bufferedWriter.write(Integer.toString(cluster[i]));  
  109.            bufferedWriter.newLine();  
  110.         }  
  111.    
  112.        bufferedWriter.close();  
  113.         
  114.            
  115.            
  116.     }  
  117.          
  118.        publicstatic void main(String args[]) throws IOException  
  119.        {  
  120.                
  121.               detect();  
  122.                
  123.        }  
  124.    
  125. }  


 

算法运行结果

Karate结果


分簇结果

 

生成的gml文件

 

导入到Gephi中,按照节点的type分割的结果

 


Facebook上4039个数据的结果

 

将生成的gml文件导入到Gephi中,并依据节点的type分割的结果

 


 

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值