2

This is my data:

dat <- mtcars
dat$Brands <- rownames(dat)
dat$Info <- rep("Info", length(rownames(mtcars)))

I have seen that there are a lot of ways to do something into an entire data frame. mutate, sapply, etc. However, for some particular functions it doesn't work.

The closest example is if you want to do log2+1.

I have tried this...

data_log <- dat %>% mutate(across(where(is.numeric), log2+1))

But it gives me this error...

Error: Problem with mutate() input ..1. ℹ ..1 = across(where(is.numeric), log2 + 1). x non-numeric argument to binary operator Run rlang::last_error() to see where the error occurred.

Do you know if there is a way to run this type of function?

Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
emr2
  • 1,436
  • 7
  • 23

4 Answers4

7

Your approach is correct but the syntax needs some correction. Here you need to use a lambda or an anonymous function.

Using dplyr you can use across as -

library(dplyr)
dat <- dat %>% mutate(across(where(is.numeric), ~log2(.) +1))

Or in base R -

cols <- sapply(dat, is.numeric)
dat[cols] <- lapply(dat[cols], function(x) log2(x) + 1)
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
2

We can use data.table methods.

library(data.table)
cols <- names(which(sapply(dat, is.numeric)))
setDT(dat)[, (cols) := lapply(.SD, function(x) log2(x) + 1), .SDcols = cols]
akrun
  • 874,273
  • 37
  • 540
  • 662
2

Actually log2 can be directly executed over a numerical data frame, so you can try the code below

idx <- sapply(dat, is.numeric)
dat[idx] <- log2(dat[idx])+1
ThomasIsCoding
  • 96,636
  • 9
  • 24
  • 81
0

The above methods are good, but, can we not use log1p as described here:

https://www.rdocumentation.org/packages/base/versions/3.6.2/topics/log

It adds 1 to every element before computing log.

log1p(x) computes log(1+x), accurately also for |x| <<1 (copied from above link).

uSer
  • 23
  • 6