! ********************************************************************** ! File Name: agglomerative.f ! Author: Ahmad Alhamed ! University of Oklahoma ! School of Computer Science ! Date: 2000 ! Modified by: Nusrat Yussouf ! CIMMS/OU/NSSL ! Date: September, 2002 ! ! Purpose: Execute clustering method ! Input: ! N : no. of initial clusters (col. in data matrix) ! Method : used method, it can be one of the following ! (1) : Single-link ! (2) : Complete-link ! (3) : UPGMA (group average) ! (4) : WPGMA (weighted average) ! (5) : UPGMC (unweighted centroid) ! (6) : WPGMC (weighted centroid) ! (7) : Ward's method (minimum variance) ! Coeff : resemblance coefficient ! Dissim : Dissimilarity coefficient or similarity coefficient ! Res : Resemblance matrix ! Ooutput: ! Hierarchy : result of clustering to be used to draw tree ! ********************************************************************** ! SUBROUTINE Agglomerative(N, Method, Coeff, Dissim, Res, Hierarchy,cluster) USE Global IMPLICIT NONE INTEGER, INTENT(IN) :: N, Method, Coeff LOGICAL, INTENT(IN) :: Dissim REAL, DIMENSION(N*(N-1)/2), INTENT(IN) :: Res TYPE(Merge), DIMENSION(N-1), INTENT(OUT) :: Hierarchy ! Local Variables REAL :: LargeDissimilarity, SmallSimilarity INTEGER :: Offset ! Func. returns index in Resemblance Matrix REAL :: UpdateResDeg ! Func. returns new degree of resemblance INTEGER :: Index, I, J, K, L, AllocatStatus, Len, iclus REAL :: Degree REAL, ALLOCATABLE, DIMENSION(:) :: Temp, Resemblance INTEGER, ALLOCATABLE, DIMENSION(:) :: Members LOGICAL, ALLOCATABLE, DIMENSION(:) :: Exist integer ncluster integer nm,ntime,nfile parameter(nm=26,nfile=nm+1,ntime=30) parameter (ncluster = 6) integer, dimension(ncluster,nm), INTENT(out) :: cluster integer index1,ntemp integer icount integer nidx(ncluster) integer yy3(ntime),mm3(ntime),dd3(ntime),hh3(ntime) integer kftime(nfile,ntime) character*6 mem (nm) common /c2/yy3,mm3,dd3,hh3,kftime,mem Len = N*(N-1) / 2 LargeDissimilarity = 32.0E+23 SmallSimilarity = -32.0E+23 ! Allocate memory space for arrays ALLOCATE( Members(N), STAT = AllocatStatus ) IF ( AllocatStatus /= 0 ) STOP "(Members)** No Enough Memory **" ALLOCATE( Exist(N), STAT = AllocatStatus ) IF ( AllocatStatus /= 0 ) STOP "(Exist)** No Enough Memory **" ALLOCATE( Resemblance(N*(N-1)/2), STAT = AllocatStatus ) IF ( AllocatStatus /= 0 ) STOP "(Temp)** No Enough Memory **" ALLOCATE( Temp(N*(N-1)/2), STAT = AllocatStatus ) IF ( AllocatStatus /= 0 ) STOP "(Resemblance)** No Enough Memory **" Resemblance = Res ! Initialize Members and Exist Members = 1 Exist = .TRUE. ! Execute agglomerative clustering DO I = 1, N-1 Temp = Resemblance ! Find the most similar pair IF (Dissim) THEN Degree = MINVAL(Resemblance) DO L=1, Len IF (Resemblance(L) == Degree) THEN Index = L EXIT END IF END DO ELSE Degree = MAXVAL(Resemblance) DO L=1, Len IF (Resemblance(L) == Degree) THEN Index = L EXIT END IF END DO END IF ! Find corresponding cluster for this Index CALL ClustersOfIndex(N, Index, J, K) ! Update Hierarchy Hierarchy(I)%MergedCluster1 = J Hierarchy(I)%MergedCluster2 = K Hierarchy(I)%NewLable = J IF (Method /= 7 ) THEN ! for methods other than Ward's Hierarchy(I)%ResDegree = Degree ELSE ! for Ward's IF (I>1) THEN IF (Coeff == 2) THEN ! for square Euc Hierarchy(I)%ResDegree = SQRT(Hierarchy(I-1)%ResDegree**2.0 & + Degree/2.0) ELSE Hierarchy(I)%ResDegree = Hierarchy(I-1)%ResDegree & + Degree END IF ELSE IF (Coeff == 2) THEN ! for square Euc Hierarchy(I)%ResDegree = SQRT(Degree/2.0) ELSE Hierarchy(I)%ResDegree = Degree END IF END IF END IF ! Set the corresponding index of K in Exist array to False Exist(K) = .FALSE. ! Update Resemblance matrix DO L = 1, N IF ( L/=J .AND. L/=K .AND. Exist(L) ) THEN Index = Offset(N, L, J) Resemblance(Index) = UpdateResDeg(N, L, J, K, & & Method, Members, Temp) Index = Offset(N, L, K) IF (Dissim) THEN Resemblance(Index) = LargeDissimilarity ELSE Resemblance(Index) = SmallSimilarity END IF END IF END DO ! Cancel the value of the larger index of the newly merged ! cluster in the Resemblance matrix Index = Offset(N, J, K) IF (Dissim) THEN Resemblance(Index) = LargeDissimilarity ELSE Resemblance(Index) = SmallSimilarity END IF ! Change no. of members with respect to the newly ! merged clusters Members(J) = Members(J) + Members(K) Members(K) = 0 WRITE (7, *) '---------------------------------------------------& &----------------' WRITE (7, *) 'Resemblance at step:', I CALL PrintResemblanceMatrix(N, Resemblance) WRITE (7, 10) Hierarchy(I)%MergedCluster1, & & Hierarchy(I)%MergedCluster2, & & Hierarchy(I)%NewLable, Hierarchy(I)%ResDegree 10 FORMAT ('Merge ',I2,' and ',I2,' to form ',I2,' at ==> ',F10.2) END DO ! six clusters members of each cluster do I =1, ncluster do J =1, N cluster (I,j) = 0 end do end do cluster (1,1) = Hierarchy(N-1)%MergedCluster1 cluster (2,1) = Hierarchy(N-1)%MergedCluster2 do I=2,ncluster-1 index1 = 0 do J=1,I if (Hierarchy(N-I)%MergedCluster1 == cluster(J,1)) then index1 = 1 end if enddo if (index1 == 1) then cluster (I+1,1) = Hierarchy(N-I)%MergedCluster2 else cluster (I+1,1) = Hierarchy(N-I)%MergedCluster1 end if enddo do J = 1, 6 K = 1 icount = 1 1211 continue do I=N-ncluster,1, -1 if (Hierarchy(I)%NewLable == cluster(j,k) ) then icount = icount + 1 if(Hierarchy(I)%Mergedcluster1 == cluster(j,k)) then cluster(j,icount) = Hierarchy(I)%MergedCluster2 else cluster(j,icount) = Hierarchy(I)%MergedCluster1 end if endif enddo if (icount > K) then K=K+1 go to 1211 endif enddo do I=1,ncluster do k=1,n-1 do j=k+1,n if (cluster(I,k) > cluster(i,j)) then ntemp = cluster (i,k) cluster(I,K)=cluster(I,j) cluster(I,J)=ntemp endif enddo enddo enddo do i =1, ncluster nidx(i) = 0 enddo do I=1,ncluster j=1 1202 continue if(cluster(i,j) == 0 ) then j=j+1 goto 1202 else nidx(i)=cluster(i,j) end if enddo do i = 1, ncluster-1 do j = i,ncluster if(nidx(i) > nidx(j)) then ntemp = nidx(i) nidx(i) = nidx(j) nidx(j)= ntemp do k =1, n ntemp = cluster(i,k) cluster(i,k) = cluster(j,k) cluster(j,k) = ntemp enddo endif enddo enddo write(7,*) '*********************************' ! write(777,*) '*********************************' do I=1,ncluster write(7,*) '*****************cluster ',I iclus=0 do K=1,N if (cluster(I,K) /= 0) then iclus=iclus+1 write(7,*) cluster(I,k),'----',mem(cluster(i,k)) end if enddo ! write(777,*) ' Cluster #',I,'has',iclus,'forecasts containing the following members:' write(777,779) ' Cluster # ',I,' has ',iclus,' forecasts containing the following members:' 779 format(1a,i1,1a,i2,1a) do K=1,N if (cluster(I,K) /= 0) then write(777,*) ' ',mem(cluster(i,k)),' (',cluster(I,k),')' end if enddo enddo ! Deallocate arrays DEALLOCATE( Members, STAT = AllocatStatus ) IF ( AllocatStatus /= 0 ) STOP "(Members)** Deallocation Error **" DEALLOCATE( Exist, STAT = AllocatStatus ) IF ( AllocatStatus /= 0 ) STOP "(Exist)** Deallocation Error **" DEALLOCATE( Resemblance, STAT = AllocatStatus ) IF ( AllocatStatus /= 0 ) STOP "(Resemblance)** Deallocation Error **" DEALLOCATE( Temp, STAT = AllocatStatus ) IF ( AllocatStatus /= 0 ) STOP "(Temp)** Deallocation Error **" END SUBROUTINE Agglomerative ! ====================================================================== ! ********************************************************************** ! ClustersOfIndex: ! Finds the corresponding clusters of an index in the Resemblance matrix ! INPUTS: ! N : No. of clusters in the Resemblance matrix ! I : Index in the Resemblance matrix ! OUTPUTS ! J, K : Clusters correspond to I ! ********************************************************************** SUBROUTINE ClustersOfIndex(N, I, J, K) IMPLICIT NONE INTEGER, INTENT(IN) :: N, I INTEGER, INTENT(OUT) :: J, K INTEGER :: Prev, Loc, R Prev = 0 Loc = 0 DO R =1, N-1 Prev = Loc Loc = Loc + (N-R) IF (I <= Loc) THEN J = R EXIT END IF END DO K = J + (I-Prev) END SUBROUTINE ClustersOfIndex ! ==================================================================== ! ******************************************************************** ! UpdateResDeg: ! Returns new resemblnace using Lance and Williams' formula which ! given in : ! A. Jain, R. Dubes, "Algorithms for Clustering Data", Prentice Hall, ! 1988, PP. 79-80 ! INPUTS: ! N : Original no. of clusters = no. of col in Data matrix ! K : Existing cluster ! R, S : newly formed cluster ! Method : used method, it can be one of the following ! (1) : Single-link ! (2) : Complete-link ! (3) : UPGMA (group average) ! (4) : WPGMA (weighted average) ! (5) : UPGMC (unweighted centroid) ! (6) : WPGMC (weighted centroid) ! (7) : Ward's method (minimum variance) ! Members: no. of members in each cluster ! Res : Resemblance matrix ! OUTPUT: ! returns the new resemblance degree ! ******************************************************************** REAL FUNCTION UpdateResDeg(N, K, R, S, Method, Members, Res) IMPLICIT NONE INTEGER, INTENT(IN) :: N, K, R, S, Method INTEGER, DIMENSION(N), INTENT(IN) :: Members REAL, DIMENSION(N*(N-1)/2), INTENT(IN) :: Res REAL :: AlphaR, AlphaS, Beta, Gamma INTEGER :: Offset ! Func. returns index in Resemblance Matrix SELECT CASE(Method) CASE (1) AlphaR = 0.50 AlphaS = 0.50 Beta = 0.0 Gamma = -0.50 CASE (2) AlphaR = 0.50 AlphaS = 0.50 Beta = 0.0 Gamma = 0.50 CASE (3) AlphaR = REAL(Members(R)) / ( REAL(Members(R)) & & + REAL(Members(S)) ) AlphaS = REAL(Members(S)) / ( REAL(Members(R)) & & + REAL(Members(S)) ) Beta = 0.0 Gamma = 0.0 CASE (4) AlphaR = 0.50 AlphaS = 0.50 Beta = 0.0 Gamma = 0.0 CASE (5) AlphaR = REAL(Members(R)) / ( REAL(Members(R)) & & + REAL(Members(S)) ) AlphaS = REAL(Members(S)) / ( REAL(Members(R)) & & + REAL(Members(S)) ) Beta = -1.0*REAL(Members(R))*REAL(Members(S)) & & / ( REAL(Members(R)) + REAL(Members(S)) )**2.0 Gamma = 0.0 CASE (6) AlphaR = 0.50 AlphaS = 0.50 Beta = -0.250 Gamma = 0.0 CASE (7) AlphaR =( REAL(Members(R))+REAL(Members(K)) ) & & / ( REAL(Members(R))+REAL(Members(S)) & & +REAL(Members(K)) ) AlphaS =( REAL(Members(S))+REAL(Members(K)) ) & & / ( REAL(Members(R))+REAL(Members(S)) & & +REAL(Members(K)) ) Beta = ( -1.0*REAL(Members(K)) )/( REAL(Members(R)) & & +REAL(Members(S))+REAL(Members(K)) ) Gamma = 0.0 END SELECT UpdateResDeg = AlphaR*Res(Offset(N,K,R)) + AlphaS*Res(Offset(N,K,S)) & & + Beta*Res(Offset(N,R,S)) + Gamma*ABS(Res(Offset(N,K,R)) & & - Res(Offset(N,K,S)) ) END FUNCTION UpdateResDeg ! ================================================================== ! ****************************************************************** ! Return index of clusters J, and K in the Resemblance matrix ! INPUTS: ! N : No. of clusters in the Resemblance matrix ! J, K : Clusters to find their index in the Resemblance matrix ! OUTPUT: ! Returns index of J, and K in the Resemblance matrix ! ******************************************************************* INTEGER FUNCTION Offset(N, J, K) IMPLICIT NONE INTEGER, INTENT(IN) :: N, J, K INTEGER :: P, Q P = MIN(J, K) Q = MAX(J, K) Offset = Q + (P-1) * N - (P*(P+1)) / 2 END FUNCTION Offset ! ==================================================================