【问题标题】:How to apply a function over two series of sequentially labelled variables without using column numbers?如何在不使用列号的情况下对两个按顺序标记的变量应用函数?
【发布时间】:2014-12-02 01:14:13
【问题描述】:

我需要使用两组按顺序标记的变量来应用一个函数,并将新的一组变量附加到数据框中。我需要在不参考代码中的列号的情况下执行此操作。

更具体地说,这是我正在尝试做的简单任务:

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

我想重复上面显示的“ifelse”函数,而不是为每组变量重复输入。

我必须说,我之前曾问过类似的问题并收到了有用的答案(eg1eg2),但在这种情况下,答案要么使用代码中的列号,要么示例位于一组顺序标记变量。我无法修改建议的代码来解决这个特定问题。

非常感谢任何建议。

【问题讨论】:

    标签: r function loops repeat


    【解决方案1】:
    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
    

    【讨论】:

    • Map 而不是 mapply 在这种情况下可能会更好,但这肯定是答案的核心。
    • 非常感谢!您是否认为可以修改此代码以使其不引用列号(例如 dat[1:3]?这是长期更改代码的一部分,并且由于添加/删除变量,列号会不断变化。这就是为什么我在不使用列号的情况下寻求解决方案。
    • @Eva - 当然,类似:dat[grepl("^sec\\d{1,}",names(dat))] 将抓住每个组。
    • @RStudent - 我已经使正则表达式更加具体
    • 是的,我想你的意思是这样的,它工作正常(再次感谢!)但返回具有相同名称的变量?我想我之后必须更改列名。 (例如从 sec1, sec2.. 到 rel1, rel2,..) : dat_n 0,x/y,NA) ,dat[grepl(" ^sec\\d{1,}",names(dat))] , dat[grepl("^pri\\d{1,}",names(dat))] )) dat[grepl("^sec\ \d{1,}",names(dat))]
    【解决方案2】:

    您可以在 ifelse 上使用 Vectorize 并对其进行大量清理

    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
    

    (哟 dawg,我听说你喜欢矢量化,所以我们在你的矢量化中添加了一些 Vectorize,这样你就可以在矢量化的同时 Vectorize

    【讨论】:

    • 谢谢!我不知道 Vectorize。显然,我的实际数据集中还有其他变量,其中包括字符“sec”或“pri”,所以我稍微编辑了你的代码(用 c('^sec.*' 替换了 c('sec','pri') ,'^pri.*') ),它工作得非常好!很有帮助!
    • Vectorize 是一个辅助函数,它将接受一个函数并用mapply 包装它,所以这个答案与另一个答案基本相同,只是不必知道mapply 语法
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-15
    • 2022-11-13
    • 2016-04-28
    • 1970-01-01
    • 2020-08-12
    • 2016-05-20
    相关资源
    最近更新 更多