0

Here is some toy data

x <- c("Bird","Bird","Tiger","Bird","Fish","grey","blue","orange","green","yellow","10","5","7","12","5","10","10","8","12","2","10","20","10","18","3")
m <- matrix(x,byrow = F,ncol = 5,nrow= 5)
m <- as.data.frame(m)
colnames(m) <- c("Animal","colour","length","height","weight")

y <- c("Tiger","Bird","Bird","colour","length","colour","orange","10","green","orange/black","12","light green")
new.m <- matrix(y,byrow=F,ncol=4,nrow = 3)
new.m <- as.data.frame(new.m)
colnames(new.m) <- c("Animal","attribute","value","new value")

How can I efficiently update the values in m using the data frame new.m. The final result should look like this:

z <- c("Bird","Bird","Tiger","Bird","Fish","grey","blue","orange/black"," light green","yellow","12","5","7","12","5","10","10","8","12","2","10","20","10","18","3")
update.m <- matrix(z,byrow = F,ncol = 5,nrow= 5)
update.m <- as.data.frame(update.m)
colnames(update.m) <- c("Animal","colour","length","height","weight")

For a fixed row in new.m I can achieve this easily. But can this be done in comprehensive not row based way?

math
  • 1,868
  • 4
  • 26
  • 60
  • Do also want to test the old value? (Does the value mentioned in `new.m` exists in `m`? What to do if there is another value?) – jogo Apr 26 '17 at 13:33
  • @jogo the values in new.m should exist in m. If there is no selection / other value it should not be replaced. Let's say in `new.m` is a row `c("Tiger, colour, green, orange/black)`. Then the Tiger row in `m` should stay as it is. – math Apr 26 '17 at 13:45
  • What is with more than one match for the old value? – jogo Apr 26 '17 at 13:49
  • @jogo they should all be replaced. If there is another Tiger (with different height) the colour should be changed too. Logically its: If Animal's Attribute = Value change it to new Value. – math Apr 26 '17 at 13:50
  • But a Tiger with a different color should not be changed? – Mike H. Apr 26 '17 at 13:51
  • @MikeH correct. If the animal doesnt satisfy the Attribute = Value, we will not change the attribute to the new value. – math Apr 26 '17 at 13:53

1 Answers1

3

One idea via base R. We first create a matrix with the columns we need to update the values. We use match to update the values. The nomath entries result to NA which we replace with original values and put them back in the original data frame.

m3 <- sapply(m[c(2:3)], function(i) new.m$`new value`[match(i, new.m$value)])
m[c(2:3)] <- replace(m3, is.na(m3), m[c(2,3)][which(is.na(m3), arr.ind = TRUE)])

m
#  Animal       colour length height weight
#1   Bird         grey     12     10     10
#2   Bird         blue      5     10     20
#3  Tiger orange/black      7      8     10
#4   Bird  light green     12     12     18
#5   Fish       yellow      5      2      3
Sotos
  • 51,121
  • 6
  • 32
  • 66
  • thx for the anwser. Sapply is essentially the same as looping through the rows. I was wondering if you can do it in a more comprehensive way – math Apr 26 '17 at 13:59
  • 2
    Where is your code? You say you can achieve it easily...where is it then? And what do you mean comprehensive?? Readable? Efficient? – Sotos Apr 26 '17 at 14:02
  • A loop is probably the best way since what you basically want is to do several different merges (one for each type `attribute` in `new.m`). I played around with a combination of `dcast`/`melt`/`merge` but I don't think it's dynamic since you lose some information. – Mike H. Apr 26 '17 at 14:25