Normalize each row of data.table to R

It seems like this should be easy, but I cannot find the answer :(. I am trying to normalize each row of data_table as follows:

normalize <- function(x) {
  s = sum(x)
  if (s>0) {
    return(x/s)
  } else {
    return 0
  }
}

How can I call this function on each row of the data table and get the normalized data.table? I can do a for loop, but this is certainly not the case, and apply(data, 1, normalize)as I understand it, it will convert my data.table to a matrix that will be very successful.

+4
source share
4 answers

Here is one way to avoid matrix coercion:

cols = names(DT)
DT[, s := Reduce("+",.SD)]
DT[s >= 0, (cols) := lapply(.SD,"/",s), .SDcols = cols]
DT[s <  0, (cols) := 0]
DT[, s := NULL]

This is what I would do if there was a good reason to use a matrix data table (at a later stage).

+2
source

( , , )

set.seed(123) 
DT <- data.table(x = rnorm(10), y = rnorm(10), z = rnorm(10))

vecotrize rowSums, -

DT[, names(DT) := {temp = rowSums(.SD) ; (.SD / temp) * (temp > 0)}]
DT
#              x          y          z
#  1:  0.0000000  0.0000000  0.0000000
#  2:  0.0000000  0.0000000  0.0000000
#  3:  1.6697906  0.4293327 -1.0991233
#  4:  0.0000000  0.0000000  0.0000000
#  5:  0.0000000  0.0000000  0.0000000
#  6:  0.9447911  0.9843707 -0.9291618
#  7:  0.2565558  0.2771142  0.4663301
#  8:  0.0000000  0.0000000  0.0000000
#  9:  0.0000000  0.0000000  0.0000000
# 10: -1.3289000 -1.4097961  3.7386962

, temp, , rowSums(.SD) . *(temp > 0) - if else. TRUE/FALSE, 1/0, (.SD/temp)

+7

. ( ), rep(0, length(x)) 0.

set.seed(123); DT <- data.table(x=rnorm(1e3), y=rnorm(1e3), z=rnorm(1e3))
> DT
                x           y          z
   1: -0.56047565 -0.99579872 -0.5116037
   2: -0.23017749 -1.03995504  0.2369379
   3:  1.55870831 -0.01798024 -0.5415892
   4:  0.07050839 -0.13217513  1.2192276
   5:  0.12928774 -2.54934277  0.1741359
  ---                                   
 996: -0.08997520  0.07664366  1.0609662
 997:  1.07051604  0.25516476 -0.4455056
 998: -1.35110039  0.27744682 -0.4291802
 999: -0.52261670  0.53685602  1.1890118
1000: -0.24919068 -0.46048557  0.8342941
> DT[, c('x', 'y', 'z') := as.list(normalize(c(x, y, z))), by=1:nrow(DT)]                                                                             
> DT
                x           y          z
   1:  0.00000000  0.00000000  0.0000000
   2:  0.00000000  0.00000000  0.0000000
   3:  1.56005167 -0.01799574 -0.5420559
   4:  0.06091117 -0.11418417  1.0532730
   5:  0.00000000  0.00000000  0.0000000
  ---                                   
 996: -0.08588413  0.07315877  1.0127254
 997:  1.21625341  0.28990225 -0.5061557
 998:  0.00000000  0.00000000  0.0000000
 999: -0.43433718  0.44617122  0.9881660
1000: -1.99963905 -3.69518205  6.6948211
0

This is probably an easier (and faster) way to apply this, but this method works. I think this is also more readable, but this is just my opinion.

# Creating sample data.
myDF <- data.frame(a = seq(1, 50), b = seq(1, 100, 2) , c = seq(1, 200, 4))
# Going through each row and dividing its contents by the sum of that row.
for (row in rownames(myDF)) { myDF[row, ] <- myDF[row, ] / sum(myDF[row, ]) }

Note. This requires your growth names to be numbers.

0
source

Source: https://habr.com/ru/post/1607712/


All Articles