2

I have the following data frame

   id f1 f2
1  a  1  3
2  b  3  5
3  c  4  7

I would like to replace all rows which have f1>3 with a row (id = x, f1 = 0, f2 = 0) So the above would map to

   id f1 f2
1  a  1  3
2  b  3  5
3  x  0  0

But when I tried

replace(x,which(x$f1>3),data.frame(id = 'x',f1=0,f2=0))

It didn't do it right, it gave

   id f1 f2
1  a  1  x
2  b  3  x
3  c  4  x
Warning message:
In `[<-.data.frame`(`*tmp*`, list, value = list(id = 1L, f1 = 0,  :
  provided 3 variables to replace 1 variables

Could someone suggest a way to do this at scale? Thanks.

Jaap
  • 81,064
  • 34
  • 182
  • 193
broccoli
  • 4,738
  • 10
  • 42
  • 54
  • I see no content relating to either 'plyr' or 'apply'. Suggest you remove those tags. `replace` only takes a vector as first argument, not a data.frame. – IRTFM Sep 13 '12 at 17:31

2 Answers2

10

Something like this:

 x[x$f1 > 3,] <- data.frame('x', 0, 0)

should do the trick!


as per @DWin's comment, this won't work with a factor id column. Using this same technique can work like this though:

levels(x$id) <- c(levels(x$id), 'x')
x[x$f1 > 3,] <- data.frame('x', 0, 0)
droplevels(x$id)
Justin
  • 42,475
  • 9
  • 93
  • 111
1

Here's another approach (taking into account @DWin's comment)

dfrm <- data.frame(id=letters[1:3], f1=c(1,3,4), f2=c(3,5,7))

dfrm[dfrm$f1>3, -1] <- 0
levels(dfrm$id) <- c(levels(dfrm$id), 'x')
dfrm[,1]<- with(dfrm, replace(id, f1==0, 'x')) ; dfrm

     id f1 f2
  1  a  1  3
  2  b  3  5
  3  x  0  0

Using some more data:

set.seed(007); N <- 12
 f1 <- sample(1:9, N, replace=TRUE)
 f2 <- sample(1:9, N, replace=TRUE)
 dfrm2 <- data.frame(id=letters[1:N], f1=f1, f2=f2)

 dfrm2[dfrm2$f1>3, -1] <- 0
 levels(dfrm2$id) <- c(levels(dfrm2$id), 'x')
 dfrm2[,1]<- with(dfrm2, replace(id, f1==0, 'x')) ; dfrm2
   id f1 f2
1   x  0  0
2   x  0  0
3   c  2  5
4   d  1  1
5   e  3  6
6   x  0  0
7   x  0  0
8   x  0  0
9   i  2  6
10  x  0  0
11  k  2  9
12  l  3  9

I deleted my previous code, because they weren't useful for this question.

Jilber Urbina
  • 58,147
  • 10
  • 114
  • 138
  • Neither of these will replace all the instances when there are multiple such rows. Try it with rbind(dfrm,dfrm). – IRTFM Sep 13 '12 at 17:33
  • Thank you @DWin, I've just edited my answer, it's not as elegant as Justin's but it works (I hope). – Jilber Urbina Sep 13 '12 at 18:10