skan
skan

Reputation: 7760

R Easy and compact way to write this in a single line?

Imagine I have a dataframe called PAD. And I want to add new columns. I need to write many lines like this, (they do rowwise calculations).

 PAD[,"MV1"] <- rowMeans(PAD[,1:3], na.rm=TRUE)
 PAD[,"MV2"] <- rowMeans(PAD[,4:6], na.rm=TRUE)
 PAD[,"MV3"] <- rowMeans(PAD[,7:9], na.rm=TRUE)
 PAD[,"MV4"] <- rowMeans(PAD[,10:12], na.rm=TRUE)
 PAD[,"MV5"] <- rowMeans(PAD[,13:15], na.rm=TRUE)
 PAD[,"MV6"] <- rowMeans(PAD[,16:18], na.rm=TRUE)
 PAD[,"MV7"] <- rowMeans(PAD[,19:21], na.rm=TRUE)
 PAD[,"MV8"] <- rowMeans(PAD[,22:24], na.rm=TRUE)

or something with my own function

 PAD[,"VV1"] <- apply(PAD[,1:3], 1, function(x) min(x), na.rm=TRUE))
 PAD[,"VV2"] <- apply(PAD[,4:6], 1, function(x) min(x), na.rm=TRUE))
 PAD[,"VV3"] <- apply(PAD[,7:9], 1, function(x) min(x), na.rm=TRUE))
 PAD[,"VV4"] <- apply(PAD[,10:12], 1, function(x) min(x), na.rm=TRUE))
 PAD[,"VV5"] <- apply(PAD[,13:15], 1, function(x) min(x), na.rm=TRUE))
 PAD[,"VV6"] <- apply(PAD[,16:18], 1, function(x) min(x), na.rm=TRUE))
 PAD[,"VV7"] <- apply(PAD[,19:21], 1, function(x) min(x), na.rm=TRUE))
 PAD[,"VV8"] <- apply(PAD[,22:24], 1, function(x) min(x), na.rm=TRUE))

I know there exist ways to write it all in a single line (or two :) ). Something like a for loop but avoiding the loop, maybe we could call it, vectorized version.

How can I do it? Maybe something starting with paste0(.....) on both sides of the assignement? , or maybe creating a function and passing a vector, but I'm a little bit confused. I don't know if I have to use parse() or eval() or just generate sequences.

As you can see I'll take every N1 (here 3) columns, to calculate and assign it to N2 new ones (here 8).

And another question, is it better to assign it to ?

 c(PAD[,"VV1"], PAD[,"VV2"], PAD[,"VV3"], ...)

or to ?

 PAD[,"VV1","VV2","VV3"....]

Upvotes: 1

Views: 40

Answers (2)

maccruiskeen
maccruiskeen

Reputation: 2828

It's two lines:

cols <- split(1:24, rep(1:8, each = 3))
for (i in 1:8) PAD[[paste0("MV", i)]] <- rowMeans(PAD[, cols[[i]]], na.rm = TRUE)

Edit:

If you want to use avoid using the for loop, you can do this.

cols <- split(1:24, rep(1:8, each = 3))
tmp <- lapply(1:8, function(x) rowMeans(PAD[, cols[[x]]], na.rm = TRUE))
names(tmp) <- paste0("MV", 1:8)
PAD <- cbind(PAD, do.call(cbind, tmp))

Upvotes: 1

smci
smci

Reputation: 33970

for (i in 1:8) {
  varname = paste('MV',i,sep='')
  PAD[,varname] <- rowMeans(PAD[, (3*n-2):(3*n)], na.rm=TRUE)
}

Yes you can do a two-liner with *apply, it is less legible though.

Upvotes: 2

Related Questions