jay.sf
jay.sf

Reputation: 73397

How to do use `replace` properly in complex cases?

I've learned about the replace function that could become my friend

dat1 <- data.frame(matrix(1:12, 3, 4))
rpl <- c(2, 4, 1)
t(sapply(seq_along(rpl), function(x) replace(dat1[x, ], rpl[x], NA)))
#      X1 X2 X3 X4
# [1,] 1  NA 7  10
# [2,] 2  5  8  NA
# [3,] NA 6  9  12

but I didn't get it to work in more complex replacement situations:

(M <- structure(c(3L, 9L, 14L, 16L, 6L, 8L, 10L, 15L, 1L, 4L, 11L, 
                 13L, 2L, 5L, 7L, 12L), .Dim = c(4L, 4L), .Dimnames = list(NULL, 
                                                                           NULL)))
#      [,1] [,2] [,3] [,4]
# [1,]    3    6    1    2
# [2,]    9    8    4    5
# [3,]   14   10   11    7
# [4,]   16   15   13   12

dat2 <- data.frame(x=matrix(NA, 16))

> sapply(1:4, function(j) replace(dat2$x, M[, j], j))
      [,1] [,2] [,3] [,4]
 [1,]   NA   NA    3   NA
 [2,]   NA   NA   NA    4
 [3,]    1   NA   NA   NA
 [4,]   NA   NA    3   NA
 [5,]   NA   NA   NA    4
 [6,]   NA    2   NA   NA
 [7,]   NA   NA   NA    4
 [8,]   NA    2   NA   NA
 [9,]    1   NA   NA   NA
[10,]   NA    2   NA   NA
[11,]   NA   NA    3   NA
[12,]   NA   NA   NA    4
[13,]   NA   NA    3   NA
[14,]    1   NA   NA   NA
[15,]   NA    2   NA   NA
[16,]    1   NA   NA   NA

The results are distributed in a matrix instead of changing just the column, whereas the for loop or the sapply give me what I want:

for (j in 1:4) dat2$x[M[, j]] <- j
# or
sapply(1:4, function(j) dat2$x[M[, j]] <<- j)

> dat3
   x
1  3
2  4
3  1
4  3
5  4
6  2
7  4
8  2
9  1
10 2
11 3
12 4
13 3
14 1
15 2
16 1

How can I properly use replace in this / such a more complex case?

BTW, why does <<- have such a bad reputation even though it fulfills its purpose, at least in this case? (Or is it just a thinking problem because I've "heard" something??). Is there an example where it's really bad practice, if it is not being used in a function that accidentally destroys something in the global environment?

Upvotes: 4

Views: 70

Answers (1)

G. Grothendieck
G. Grothendieck

Reputation: 269905

This isn't a problem with replace. The problem is that sapply works in parallel (not in the sense of paraellel processing but just conceptually) rather than applying one iteration on the result of the prior iteration. To do that use Reduce.

transform(dat2, x = Reduce(function(x, i) replace(x, M[, i], i), init = x, 1:ncol(M)))

Upvotes: 1

Related Questions