简体   繁体   中英

How to apply a function over two series of sequentially labelled variables without using column numbers?

I need to apply a function using two sets of sequentially labelled variables and attach the new set of variables to the data frame. I need to do this without referring to the column numbers in the code.

More specifically, here is the simple task I am trying to do:

dat <- data.frame(sec1 = sample(c(0:3),10,replace=T) , sec2 = sample(c(0:4),replace=T) , sec3 = sample(c(0:4),replace=T),pri1 = sample(c(0:3),10,replace=T) , pri2 = sample(c(0:4),replace=T) , pri3 = sample(c(0:4),replace=T) )
dat$rel1 <- ifelse(dat$pri1>0,dat$sec1/dat$pri1,NA)
dat

I want to repeat the "ifelse" function shown above without typing it repeatedly for each set of variables.

I must say, I asked similar questions and received helpful answers ( eg1 and eg2 ) previously but in those case the responses either used the column number in the code, or the example was on a single set of sequentially labelled variable. I could not manage to revise the suggested code to solve this particular problem.

Any suggestion is very much appreciated.

dat_n <- cbind(dat, mapply(function(x, y) ifelse(y>0,x/y,NA) ,dat[grepl("sec",names(dat))], dat[grepl("pri",names(dat))]))
> dat_n
   sec1 sec2 sec3 pri1 pri2 pri3      rel1      sec1      sec2 sec3
1     2    1    2    3    3    0 0.6666667 0.6666667 0.3333333   NA
2     3    3    4    0    2    4        NA        NA 1.5000000 1.00
3     1    0    3    1    4    4 1.0000000 1.0000000 0.0000000 0.75
4     2    4    1    3    3    2 0.6666667 0.6666667 1.3333333 0.50
5     2    0    2    3    4    1 0.6666667 0.6666667 0.0000000 2.00
6     1    1    2    1    3    0 1.0000000 1.0000000 0.3333333   NA
7     1    3    4    0    2    4        NA        NA 1.5000000 1.00
8     1    0    3    1    4    4 1.0000000 1.0000000 0.0000000 0.75
9     3    4    1    2    3    2 1.5000000 1.5000000 1.3333333 0.50
10    1    0    2    2    4    1 0.5000000 0.5000000 0.0000000 2.00

You could use Vectorize on an ifelse and clean this up a lot

set.seed(1)
dat <- data.frame(sec1 = sample(c(0:3),10,replace=T) , sec2 = sample(c(0:4),replace=T) , sec3 = sample(c(0:4),replace=T),pri1 = sample(c(0:3),10,replace=T) , pri2 = sample(c(0:4),replace=T) , pri3 = sample(c(0:4),replace=T) )
dat$rel1 <- ifelse(dat$pri1>0,dat$sec1/dat$pri1,NA)
dat

f <- Vectorize(function(x, y) ifelse(y > 0, x / y, NA))


f(dat[1:3], dat[4:6])

#           sec1 sec2      sec3
# [1,]  0.3333333 0.50 0.6666667
# [2,]         NA 0.00 1.0000000
# [3,]  1.0000000 1.50        NA
# [4,]         NA   NA 0.3333333
# [5,]  0.0000000 0.75 1.5000000
# [6,]  3.0000000 0.50 0.6666667
# [7,]         NA 0.00 1.0000000
# [8,]  2.0000000 1.50        NA
# [9,]  0.6666667   NA 0.3333333
# [10,] 0.0000000 0.75 1.5000000

v <- lapply(c('sec','pri'), function(x) grep(x, names(dat)))

cbind(dat, `colnames<-`(f(dat[v[[1]]], dat[v[[2]]]), paste0('rel',1:3)))

#    sec1 sec2 sec3 pri1 pri2 pri3      rel1      rel1 rel2      rel3
# 1     1    1    2    3    2    3 0.3333333 0.3333333 0.50 0.6666667
# 2     1    0    3    0    2    3        NA        NA 0.00 1.0000000
# 3     2    3    4    2    2    0 1.0000000 1.0000000 1.50        NA
# 4     3    1    1    0    0    3        NA        NA   NA 0.3333333
# 5     0    3    3    1    4    2 0.0000000 0.0000000 0.75 1.5000000
# 6     3    1    2    1    2    3 3.0000000 3.0000000 0.50 0.6666667
# 7     3    0    3    0    2    3        NA        NA 0.00 1.0000000
# 8     2    3    4    1    2    0 2.0000000 2.0000000 1.50        NA
# 9     2    1    1    3    0    3 0.6666667 0.6666667   NA 0.3333333
# 10    0    3    3    1    4    2 0.0000000 0.0000000 0.75 1.5000000

(yo dawg I heard you like to vectorize so we put some Vectorize in your vectorized so you can Vectorize while you vectorize)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM