You can take advantage of floating point error to add a tiny amount less than the floating point error to x
. Since log(0.00000000000000...0000223)
is 0.0000...
, inputting 0
will work. The results of other numbers will only be changed by amounts smaller than the floating point error, meaning for practical purposes not at all.
Avoiding the iteration and using .Machine$double.xmin
for a very, very small number,
df <- data.frame(sample = c("a2", "a3"),
a = 2:3,
b = c(1L, 0L),
c = c(2L, 45L))
df
#> sample a b c
#> 1 a2 2 1 2
#> 2 a3 3 0 45
df[-1] <- df[-1] * log(df[-1] + .Machine$double.xmin)
df
#> sample a b c
#> 1 a2 1.386294 0 1.386294
#> 2 a3 3.295837 0 171.299812
To check the results, let's use another approach, changing 0 values to 1 so they're return 0:
df2 <- data.frame(sample = c("a2", "a3"),
a = 2:3,
b = c(1L, 0),
c = c(2L, 45L))
df2[df2 == 0] <- 1
df2[-1] <- df2[-1] * log(df2[-1])
df2
#> sample a b c
#> 1 a2 1.386294 0 1.386294
#> 2 a3 3.295837 0 171.299812
Because the change is less than floating point error, the results are identical according to R:
identical(df, df2)
#> [1] TRUE