4

I have two data.frames:

pattern <- data.frame(pattern = c("A", "B", "C", "D"), val = c(1, 1, 2, 2))

match <- data.frame(match = c("A", "C"))

I want to add to my data.frame pattern another column called new_val and assign "X" to each row where the value for column pattern is in the data.frame match otherwise assign "Y"

is.element(pattern$pattern, match$match)

[1] TRUE FALSE TRUE FALSE

So, the resulting data.frame should look like:

    pattern val new_val
1   A       1   X
2   B       1   Y
3   C       2   X
4   D       2   Y

I achieved to do it with an ugly for-loop but I am sure this can be pretty much done in a one line R command using fancy stuff :-)

Is anyone able to help?

Many thanks!

user969113
  • 2,349
  • 10
  • 44
  • 51

2 Answers2

3

I'm only really posting this since Tyler said "if you wanted a one liner data.table would likely do it" and I knew it was definitely possible with a one liner in base. I am also assuming match had been renamed to mat.

  pattern$new_val <- c("Y", "X")[(pattern$pattern %in% mat)+1]
  pattern
#  pattern val new_val
#1       A   1       X
#2       B   1       Y
#3       C   2       X
#4       D   2       Y

pattern$pattern %in% mat is finding which of the elements of pattern are in mat which returns TRUE if it's in mat, FALSE if it's not. Then I add 1 to make it numeric in the range of 1-2 so that it can be used for indexing. Then we use that as an index to the self defined vector c("Y", "X") and since the index we created is always 1 or 2 we're always able to grab an element of interest. So in this case we'll grab "Y" if pattern wasn't in mat and "X" if it was - which is what you wanted.

Dason
  • 60,663
  • 9
  • 131
  • 148
2

Here's one way (I renamed your match to mat since there's a pretty important base function named match that you could actually use to solve this problem; in fact %in% is a form of match:

pattern <- data.frame(pattern = c("A", "B", "C", "D"), val = c(1, 1, 2, 2))
mat <- c("A", "C")

pattern$new_val <- "Y"                            #pre allot everything to be Y
pattern$new_val[pattern$pattern %in% mat] <- "X"  #replace any A or C with an X
pattern

PS if you wanted a one liner data.table would likely do it.

If you wanted something a little more complicated you could use a function from a package I'm working on:

library(qdap)

#original problem
pattern$new_val <- text2color(pattern$pattern, list(c("A", "C")), c("X", "Y"))

#extending it
#makes D  a 5
text2color(pattern$pattern, list(c("A", "C"), "D"), c("X", 5, "Y"))

This function really is designed to do something else but if you want to grab the essential parts of it you can look at the source code.

Tyler Rinker
  • 108,132
  • 65
  • 322
  • 519