Reputation: 281
I'm trying to transform the values in a matrix by dividing each value by the lesser of the maximum values of its column or row name. I am having trouble because I don't know how to query the row/column for a particular value from inside a larger function.
A small cut of the data looks like this: a weighted (symmetrical) adjacency matrix, mat:
Acousmatic Acoustic Afro-beat Alternative Ambient
Acousmatic 125 11 3 3 1
Acoustic 11 112398 1810 24216 3824
Afro-beat 3 1810 10386 1220 298
Alternative 3 24216 1220 103286 2838
Ambient 1 3824 298 2838 20400
As an example, I want to transform the value of "Alternative-Acoustic" (24216) by finding the maximum value for "Acoustic" given by its diagonal (112398) and the maximum value for "Alternative" given by its diagonal (103286), and by dividing "Alternative-Acoustic" (24216) by the lesser of those two numbers. So in this case, the lesser would be "Alternative," so I want to transform the "Alternative-Acoustic" value with 24216/103286=~.2345.
I want to automatically perform this transformation for all values in this matrix, which would result in a matrix with values ranging from 0-1 with the diagonals as all 1's.
I tried the following in many different iterations with "mat" as both a matrix and a data frame, but I do not know how to correctly query the row and column maximums for each value in the matrix. This is using nonexistent functions ('colmax' and 'rowmax'), but I think it most clearly expresses what I want to do:
transformedmat <- apply(mat,1:2, function(x) x/min(colmax(x),rowmax(x)))
I also tried to write an embedded function, but that ended poorly, and I'm wondering if there's a simpler solution:
rescalemat <- function(mat){
apply(mat, 1, function(x){
colmax<-apply(mat, 2, function(x) max(x))
rowmax<-apply(mat, 1, function(x) max(x))
x/min(colmax,rowmax)
mat
})
}
Any help would be greatly appreciated.
Thanks.
Upvotes: 9
Views: 6457
Reputation: 106
Try this code:
maxcol <- Rfast::colMaxs(x)
maxrow <- Rfast::rowMaxs(x)
Rfast::eachrow(x, min(maxcol, maxrow), oper = "/")
Upvotes: 2
Reputation: 13122
Unless I've missed something, this approach looks valid too:
res = diag(mat)
#names(res) = colnames(mat)
mat / outer(res, res, pmin)
# Acousmatic Acoustic Afro.beat Alternative Ambient
#Acousmatic 1.000 0.0880000 0.02400000 0.0240000 0.00800000
#Acoustic 0.088 1.0000000 0.17427306 0.2344558 0.18745098
#Afro-beat 0.024 0.1742731 1.00000000 0.1174658 0.02869247
#Alternative 0.024 0.2344558 0.11746582 1.0000000 0.13911765
#Ambient 0.008 0.1874510 0.02869247 0.1391176 1.00000000
Where mat
is:
mat = structure(c(125L, 11L, 3L, 3L, 1L, 11L, 112398L, 1810L, 24216L,
3824L, 3L, 1810L, 10386L, 1220L, 298L, 3L, 24216L, 1220L, 103286L,
2838L, 1L, 3824L, 298L, 2838L, 20400L), .Dim = c(5L, 5L), .Dimnames = list(
c("Acousmatic", "Acoustic", "Afro-beat", "Alternative", "Ambient"
), c("Acousmatic", "Acoustic", "Afro.beat", "Alternative",
"Ambient")))
Upvotes: 6
Reputation: 3462
try this:
A1 = mat/apply(mat,1,max)
A2 = t(t(mat)/apply(mat,2,max))
result = ifelse(A1>A2,A1,A2)
Upvotes: 6