Brandon S - 1 year ago 61
R Question

# Creative loop for filling in data frame values based on other data frame values in R

For those familiar with the Analytical Hierarchy Process, this should be a little more intuitive...

Use the following code to create the data.frame

`criteria`
:

``````c <- 5
cri_names <- c("Applicability", "Deployment", "Scalability", "Ease-of-Use", "TCO")
c1 <- data.frame(c = rep(0, c))
criteria <- data.frame(do.call("cbind", rep(c1, c)))
colnames(criteria) <- cri_names
rownames(criteria) <- cri_names

cvs <- data.frame(c1 = c(1, 5, 3, 1, 3),
c2 = c(1, 1, 1/3, 1/5, 1/5),
c3 = c(1, 1, 1, 1/3, 3),
c4 = c(1, 1, 1, 1, 5),
c5 = c(1, 1, 1, 1, 1))

for(v in c(1:ncol(cvs))) {
criteria[v, ] <- cvs[, v]
}

print(criteria)

#              Applicability Deployment Scalability Ease-of-Use TCO
#Applicability             1          5   3.0000000   1.0000000 3.0
#Deployment                1          1   0.3333333   0.2000000 0.2
#Scalability               1          1   1.0000000   0.3333333 3.0
#Ease-of-Use               1          1   1.0000000   1.0000000 5.0
#TCO                       1          1   1.0000000   1.0000000 1.0
``````

What I now want to do is replace every
`1`
to the left of
`criteria[x, x]`
with the inverse of its opposite's value. For example:

``````criteria["Deployment", "Applicability"] <- 1/criteria["Applicability", "Deployment"]
``````

The final result should look like this:

``````#              Applicability Deployment Scalability Ease-of-Use TCO
#Applicability     1.0000000          5   3.0000000   1.0000000 3.0
#Deployment        0.2000000          1   0.3333333   0.2000000 0.2
#Scalability       0.3333333          3   1.0000000   0.3333333 3.0
#Ease-of-Use       1.0000000          5   3.0000000   1.0000000 5.0
#TCO               0.3333333          5   0.3333333   0.2000000 1.0
``````

I'm pretty confident that this can be accomplished with nested for loops, but I can't quite grasp it and my time to work on this is running out.

I think this is what you're looking for:

``````l <- lower.tri(criteria)
criteria[l] <- 1/t(criteria)[l]

print(criteria)
##               Applicability Deployment Scalability Ease-of-Use TCO
## Applicability     1.0000000          5   3.0000000   1.0000000 3.0
## Deployment        0.2000000          1   0.3333333   0.2000000 0.2
## Scalability       0.3333333          3   1.0000000   0.3333333 3.0
## Ease-of-Use       1.0000000          5   3.0000000   1.0000000 5.0
## TCO               0.3333333          5   0.3333333   0.2000000 1.0
``````

FYI, this won't work:

``````criteria[lower.tri(criteria)] <- 1/criteria[upper.tri(criteria)]
``````

You want to columns of lower triangle to be filled with inverse of rows of upper triangle. However, R reads matrix columnwise so `criteria[upper.tri(criteria)]` will return the following instead:

`````` [1] 5.0000000 3.0000000 0.3333333 1.0000000 0.2000000 0.3333333 3.0000000 0.2000000 3.0000000 5.0000000
``````

This can be solved by taking the transpose and getting the lower triangle, which is equivalent to taking the rows of upper triangle.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download