Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R expression to manage NA's when summing columns

Tags:

r

I have 5 columns of numeric data (m1,m2,m3,m4,m5) and I want to generate a new column with the mean value of all the m's in the same row. That is:

(m1 + m2 + m3 + m4 + m5)/5

I have a problem with the management of NA values: I want the mean value to be NA if, and only if, all the individual values of the m's are NA. But, if I use na.rm, then NA's are substituted by zeroes and no NA is in the column of means. On the other hand, if I don't use na.rm, the column of means is NA if ANY of the m's is NA.

I have done the following:

m <- rowSums(data.frame(m1,m2,m3,m4,m5)/5, na.rm=TRUE)

for (i in 1:length(m)) {
    if ( all(is.na(c(m1[i],m2[i],m3[i],m4[i],m5[i])))) {
        m[i] <- NA
    }
}

It works, but I'm almost sure that R can do it in a better way. How can it be done without loops?

Maybe the question sounds a little bit trivial. Sorry for that, but I am new in R.

Thanks in advance.

like image 893
lfuente Avatar asked Apr 05 '11 10:04

lfuente


2 Answers

Use rowMeans instead of rowSums :

Df <- data.frame(
  m1 = c(NA,1:10,NA),
  m2 = c(10:5,NA,4:1,NA),
  m3 = c(11,12,NA,13:20,NA)
)
rowMeans(Df,na.rm=T)
[1] 10.500000  7.333333  5.000000  7.666667  8.000000  8.333333 11.000000 
    9.333333  9.666667 10.000000 10.333333        NA
like image 57
Joris Meys Avatar answered Nov 01 '22 14:11

Joris Meys


The answer is quite simple and you'll kick yourself when I reveal all ;-)

First a reproducible example:

set.seed(1)
dat <- matrix(runif(100*5), ncol = 5)
## add some random NA
dat[sample(NROW(dat) * NCOL(dat), 100)] <- NA
dat <- data.frame(dat)
names(dat) <- paste("m", 1:5, sep = "")
## make 1 row all NA
dat[10, ] <- rep(NA, NCOL(dat))

The solution is to use rowMeans() not rowSums():

> rowMeans(dat, na.rm = TRUE)
  [1] 0.5040661 0.2447789 0.5785721 0.6552587 0.5000273 0.6553183
  [7] 0.5017969 0.5961018 0.3778305        NA 0.7843261 0.3118411
 [13] 0.6023241 0.7230658 0.4849793 0.3579792 0.5321065 0.5891246
 [19] 0.5985094 0.6450797 0.5884122 0.3308921 0.4659702 0.3595603
 [25] 0.6291160 0.5420563 0.3555441 0.3922415 0.4554090 0.6912613
 [31] 0.5849739 0.1436432 0.3363359 0.5620860 0.4845476 0.6243143
 [37] 0.6453576 0.3102552 0.6801590 0.5730385 0.6595771 0.4125847
 [43] 0.5950305 0.3908888 0.5228980 0.4290490 0.3219740 0.4941847
 [49] 0.3203416 0.6077816 0.6725149 0.6037703 0.4706785 0.3780164
 [55] 0.2773157 0.2887002 0.5679866 0.5216224 0.4181383 0.4182203
 [61] 0.3985725 0.4043380 0.3024113 0.5441925 0.6163834 0.5365182
 [67] 0.3324975 0.5444736 0.6809868 0.5073465 0.4122997 0.6164483
 [73] 0.4803133 0.3044119 0.2990064 0.5280371 0.5925953 0.6079630
 [79] 0.5144217 0.7415579 0.4059379 0.3966217 0.7344768 0.7502413
 [85] 0.4064067 0.2837371 0.6139601 0.3669062 0.5450748 0.4665940
 [91] 0.3618159 0.4623254 0.5885807 0.4686613 0.4246080 0.6322250
 [97] 0.2747088 0.4716259 0.4306550 0.1015050

Compare the entry for row 10 using both approaches:

> rowMeans(dat, na.rm = TRUE)[10]
[1] NA
> rowSums(dat/5, na.rm = TRUE)[10]
[1] 0
like image 38
Gavin Simpson Avatar answered Nov 01 '22 15:11

Gavin Simpson