# Sums-of-Squares (total, between, within): how to compute them from a Distance Matrix?

I am having trouble understanding the concept of Sum of Squares in the context of distance matrices (Studer et al. 2010).

The Sum of Squares I am familiar with is the classical $SS$ from ANOVA, performed on contingency table, such as

 sex    FE employment joblessness school
1    16          4           0      0
2     8          3           1      8


From which I can quickly compute the ANOVA Sum of Squares with

dtm = melt(dt, id.vars = c('sex'))
dtmcount = count(dtm, sex, value)

dtmcount %>% group_by() %>%
mutate(grandmean = mean(n)) %>%
group_by(sex) %>%
mutate(SumSqtTotal = (n - grandmean)^2) %>%
group_by(sex) %>% mutate(groupmean = mean(n)) %>%
mutate(SSW = (n - groupmean)^2) %>%
group_by(sex) %>% mutate(SSB = ( grandmean - groupmean)^2) %>%
group_by() %>%
summarise(SST = sum(SumSqtTotal), SSW = sum(SSW), SSB = sum(SSB))

# results #

SST =  SSW    SSB
53     20     33


The Sum of Squares makes sense to me because I understand that we are comparing means and decomposing means.

However, when it comes to distance matrices, I don't understand what the "mean" becomes.

Consider the same data, but this time we are comparing sequences.

   sex     Sep.93     Oct.93     Nov.93     Dec.93
1    1     school     school     school     school
2    1   training   training   training   training
3    1     school     school     school     school
4    1   training   training   training   training
5    1     school     school     school     school
6    2         FE         FE         FE         FE
7    2         FE         FE         FE         FE
8    2   training   training   training   training
9    2     school     school     school     school
10   2 employment employment employment employment


In a classical sequence analysis, we would use a distance algorithm to compute pairwise dissimilarities and end up with a distance matrix, like this one (from Hamming distance)

     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,]    0    4    0    4    0    4    4    4    0     4
[2,]    4    0    4    0    4    4    4    0    4     4
[3,]    0    4    0    4    0    4    4    4    0     4
[4,]    4    0    4    0    4    4    4    0    4     4
[5,]    0    4    0    4    0    4    4    4    0     4
[6,]    4    4    4    4    4    0    0    4    4     4
[7,]    4    4    4    4    4    0    0    4    4     4
[8,]    4    0    4    0    4    4    4    0    4     4
[9,]    0    4    0    4    0    4    4    4    0     4
[10,]   4    4    4    4    4    4    4    4    4     0


The analysis of variance for sequence analysis was developed by Studer et al. (2010).

From the paper (2010), I quote the following :

According to Batagelj (1988), the notion of a gravity center holds for any kind of distances and objects, even though it is not clearly defined for complex nonnumeric objects such as sequences. It is likely that the gravity center does not itself belong to the object space, exactly as the mean of integer values may be a real noninteger value. [...] Even though the gravity center may not be observable, equation (4) provides a comprehensive way to compute the most central sequence, the medoid, of a set using weights. Searching the x that minimizes equation (4) is equivalent to minimizing the sum of the weighted distances from x to all other sequences. (p.8).

They developed a R function in the library TraMineR. It actually enables to get p.values from co-variates using permutation tests.

The output looks like this :

Pseudo ANOVA table:
SS df      MSE
Exp    1.7  1 1.700000
Res    9.6  8 1.200000
Total 11.3  9 1.255556


However, I fail to completely understand how to compute the Sum of Squares for such matrix (manually if possible), for both the Total and the Explanatory ? What is the "mean" or "center" in this context ?

Thank you.

Data and codes

library(dplyr)
library(reshape2)
library(TraMineR)

# data from TraMineR #

dt = structure(list(sex = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L,
2L, 2L, 2L), .Label = c("1", "2"), class = "factor"), Sep.93 = structure(c(3L,
4L, 3L, 4L, 3L, 1L, 1L, 4L, 3L, 2L), .Label = c("FE", "employment",
"school", "training"), class = "factor"), Oct.93 = structure(c(3L,
4L, 3L, 4L, 3L, 1L, 1L, 4L, 3L, 2L), .Label = c("FE", "employment",
"school", "training"), class = "factor"), Nov.93 = structure(c(3L,
4L, 3L, 4L, 3L, 1L, 1L, 4L, 3L, 2L), .Label = c("FE", "employment",
"school", "training"), class = "factor"), Dec.93 = structure(c(3L,
4L, 3L, 4L, 3L, 1L, 1L, 4L, 3L, 2L), .Label = c("FE", "employment",
"school", "training"), class = "factor")), .Names = c("sex",
"Sep.93", "Oct.93", "Nov.93", "Dec.93"), row.names = c(NA, -10L
), class = "data.frame")

# To transform the data into COUNT data #

dtm = melt(dt, id.vars = c('sex'))
dtmcount = count(dtm, sex, value)

# The SS is easily compute with #

dtmcount %>% group_by() %>%
mutate(grandmean = mean(n)) %>% group_by(sex) %>%
mutate(SumSqtTotal = (n - grandmean)^2) %>%
group_by(sex) %>% mutate(groupmean = mean(n)) %>%
mutate(SSW = (n - groupmean)^2) %>%
group_by(sex) %>% mutate(SSB = ( grandmean - groupmean)^2) %>% group_by() %>%
summarise(SST = sum(SumSqtTotal), SSW = sum(SSW), SSB = sum(SSB))

# Hamming distance function #

Ham = function(d){
mat = matrix(0, nrow(d), nrow(d))

len = nrow(d)
mat = matrix(0, len, len)

for(k in 1:len){
for(i in 1:len){
mat[k,i] = sum( ifelse( as.numeric( d[k, ] == d[i, ] ) == 1, 0 , 1) )
}
}
return(mat)
}

used in the example, like this
Ham(dt[,-1])

# The TraMineR Example #