2

In the data frame "days", I want to apply the function called 'round.numbers' to all columns except the column named 'id'.

According to the comment,

days[,-'id'][, lapply(X = .SD, FUN = round.numbers)] This works successfully

However it creates a new table instead of replacing the original data.

days[,-'id'] <- days[,-'id'][, lapply(X = .SD, FUN = round.numbers)] Failed.

Harold
  • 373
  • 2
  • 12
  • 2
    It looks like you are using `data.table`, try `days[, -"id"][, lapply(X = .SD, FUN = round.numbers']` – J.R. Oct 05 '17 at 21:35
  • Thanks. it works! But it seems that it generate a new data.table instead of replacing the origin. How can I replace them. (with the id column maintain the same, the rest columns changed by the function) days[, -'id'] <- days[, -'id'][,lapply(X = .SD, FUN = 'round.numbers')] This does not work... – Harold Oct 05 '17 at 21:51
  • Because I want to keep the id column. – Harold Oct 05 '17 at 22:31
  • I assume we preserve all rows. In that case you might just use the by statement, but if that is too hacky then maybe: `newDays <- days[, -"id"][, lapply(.SD, round.numbers][, id := days[, id]]` – J.R. Oct 05 '17 at 22:42
  • 2
    `DT[, id := NULL]; DT[, names(DT) := lapply(.SD, f)]` ? The `:=` symbol is for replacing columns in data.table. There's also a utility function `?set`, useful if you have many columns.. example here: https://stackoverflow.com/questions/16846380/how-to-apply-same-function-to-every-specified-column-in-a-data-table/16846530#16846530 – Frank Oct 05 '17 at 23:05

1 Answers1

6

I assume you use data.table. Then you can use setdiff as in the following example:

> days = data.table(a = 1:2, b = 3:4, id = c(1, 1))
> 
> days <- days[, lapply(X = .SD, FUN = identity), 
+              .SDcols = setdiff(colnames(days), "id")]
> days
   a b
1: 1 3
2: 2 4

or just drop id to start with

> days = data.table(a = 1:2, b = 3:4, id = c(1, 1))
> days <- days[, id := NULL][, lapply(X = .SD, FUN = identity)]
> days
   a b
1: 1 3
2: 2 4

If you want to keep the id column then this should do (I added this after seeing your comment)

> set.seed(23812349)
> days = data.table(a = rnorm(2), b = rnorm(2), id = c(1, 1))
> days
           a         b id
1: -1.461587 0.2130853  1
2:  1.062314 0.8523587  1
> 
> .cols <- setdiff(colnames(days), "id")
> days[, (.cols) := lapply(.SD, round, digits = 1), .SDcols = .cols]
> days
      a   b id
1: -1.5 0.2  1
2:  1.1 0.9  1
  • 1
    Thanks. But I want to keep the original id column.. The situation is like I already have a table with three columns: id, weight, height. And I only want to round weight and height to 1 digit. And I still need id in my table, rather than drop it. – Harold Oct 05 '17 at 22:33
  • Changed my answer so you can keep the `id` the column – Benjamin Christoffersen Oct 06 '17 at 12:43