【问题标题】:generate column values with multiple conditions in R在 R 中生成具有多个条件的列值
【发布时间】:2012-12-31 20:07:50
【问题描述】:

我有一个数据框z,我想根据z 的两个旧列的值创建新列。以下是流程:

>z<-cbind(x=1:10,y=11:20,t=21:30)
> z<-as.data.frame(z)
>z
    x  y  t
1   1 11 21
2   2 12 22
3   3 13 23
4   4 14 24
5   5 15 25
6   6 16 26
7   7 17 27
8   8 18 28
9   9 19 29
10 10 20 30

# 生成列q,如果x=3 等于列t 的值乘以4,对于x 的其他值,它等于列t 的值。

for (i in 1:nrow(z)){
  z$q[i]=if (z$x[i]==4) 4*z$t[i] else z$t[i]}

但是,我的问题是我想应用多个条件:

例如,我想得到这样的东西:

(If x=2, q=t*2; x=4, q=t*4; x=7, q=t*3; for other it is equal to t) 

> z
   x  y  t  q
1   1 11 21 21
2   2 12 22 44
3   3 13 23 23
4   4 14 24 96
5   5 15 25 25
6   6 16 26 26
7   7 17 27 81
8   8 18 28 28
9   9 19 29 29
10 10 20 30 30

如何使用循环或任何其他方法获得第二个输出?

【问题讨论】:

  • 另外,使用 ifelse 比使用 for 循环更好。而不是(for i in 1:length(x)) y[i] &lt;- if ... else ... 你可以做y &lt;- ifelse(logical, true, false)
  • @Señor :根据您的建议,我发布了我自己问题的答案。谢谢!

标签: r loops multiple-columns


【解决方案1】:

通过递归构建嵌套的ifelse 函数,您可以获得迄今为止提供的两种解决方案的好处:ifelse 速度快并且可以处理任何类型的数据,而@Matthew 的解决方案功能更强大但仅限于整数和可能很慢。

decode <- function(x, search, replace, default = NULL) {

   # build a nested ifelse function by recursion
   decode.fun <- function(search, replace, default = NULL)
      if (length(search) == 0) {
         function(x) if (is.null(default)) x else rep(default, length(x))
      } else {
         function(x) ifelse(x == search[1], replace[1],
                                            decode.fun(tail(search, -1),
                                                       tail(replace, -1),
                                                       default)(x))
      }

   return(decode.fun(search, replace, default)(x))
}

注意decode 函数是如何以 SQL 函数命名的。我希望像这样的函数可以用于基础 R 包......这里有几个例子说明了它的用法:

decode(x = 1:5, search = 3, replace = -1)
# [1]  1  2 -1  4  5
decode(x = 1:5, search = c(2, 4), replace = c(20, 40), default = 3)
# [1] 3 20  3  40  3

针对您的特定问题:

transform(z, q = decode(x, search = c(2,4,7), replace = c(2,4,3), default = 1) * t)

#    x  y  t  q
# 1   1 11 21 21
# 2   2 12 22 44
# 3   3 13 23 23
# 4   4 14 24 96
# 5   5 15 25 25
# 6   6 16 26 26
# 7   7 17 27 81
# 8   8 18 28 28
# 9   9 19 29 29
# 10 10 20 30 30

【讨论】:

  • 非常好。我正在考虑做一个这样的递归函数定义,但把它留给“以后”可能永远不会。
  • 如果你把它概括起来更好,这样search 可以是目标向量的列表(例如search=list(c("apple","orange"),c("carrot","potato")), replace=c("fruit","root")(甚至是search=list(fruit=c("apple","orange"),root=c("carrot","potato")),尽管这只适用于字符串替换)。我认为car 包有一个 recode 用于因子,但它是基于字符串且笨重的......
【解决方案2】:

生成多重向量:

tt <- rep(1, max(z$x))
tt[2] <- 2
tt[4] <- 4
tt[7] <- 3

这是您的新专栏:

> z$t * tt[z$x]
 [1] 21 44 23 96 25 26 81 28 29 30

> z$q <- z$t * tt[z$x]
> z
    x  y  t  q
1   1 11 21 21
2   2 12 22 44
3   3 13 23 23
4   4 14 24 96
5   5 15 25 25
6   6 16 26 26
7   7 17 27 81
8   8 18 28 28
9   9 19 29 29
10 10 20 30 30

如果z$x 中有负值,这将不起作用。

已编辑

这里是上面的一个概括,其中一个函数用于生成乘数向量。实际上,我们是根据参数创建一个函数。

我们要转换以下值:

2 -> 2
4 -> 4
7 -> 3

否则将采用默认值 1。

这是一个生成所需函数的函数:

f <- function(default, x, y) {
  x.min <- min(x)
  x.max <- max(x)
  y.vals <- rep(default, x.max-x.min+1)
  y.vals[x-x.min+1] <- y

  function(z) {
    result <- rep(default, length(z))
    tmp <- z>=x.min & z<=x.max
    result[tmp] <- y.vals[z[tmp]-x.min+1]
    result
  }
}

我们是这样使用它的:

x <- c(2,4,7)
y <- c(2,4,3)

g <- f(1, x, y)

g 是我们想要的函数。应该清楚的是,任何映射都可以通过xy 参数提供给f

g(z$x)
## [1] 1 2 1 4 1 1 3 1 1 1

g(z$x)*z$t
## [1] 21 44 23 96 25 26 81 28 29 30

应该清楚这仅适用于整数值。

【讨论】:

    【解决方案3】:

    根据Señor的建议:

    > z$q <- ifelse(z$x == 2, z$t * 2,
             ifelse(z$x == 4, z$t * 4,
             ifelse(z$x == 7, z$t * 3,
                              z$t * 1)))
    > z
        x  y  t  q
    1   1 11 21 21
    2   2 12 22 44
    3   3 13 23 23
    4   4 14 24 96
    5   5 15 25 25
    6   6 16 26 26
    7   7 17 27 81
    8   8 18 28 28
    9   9 19 29 29
    10 10 20 30 30
    

    【讨论】:

      【解决方案4】:

      这是一个简单的解决方案,只需一个 ifelse 命令:

      计算t的乘数:

      ifelse(z$x == 7, 3, z$x ^ (z$x %in% c(2, 4)))
      

      完整的命令:

      transform(z, q = t * ifelse(x == 7, 3, x ^ (x %in% c(2, 4))))
      
          x  y  t  q
      1   1 11 21 21
      2   2 12 22 44
      3   3 13 23 23
      4   4 14 24 96
      5   5 15 25 25
      6   6 16 26 26
      7   7 17 27 81
      8   8 18 28 28
      9   9 19 29 29
      10 10 20 30 30
      

      【讨论】:

        【解决方案5】:

        我真的很喜欢 frodel 博客上发布的“dinre”答案:

        for (i in 1:length(data_Array)){
        data_Array[i] <- switch(data_Array[i], banana="apple", orange="pineapple", "fig")
        }
        

        警告请仔细阅读switch 的帮助页面以获取整数参数。

        【讨论】:

          【解决方案6】:

          你可以在

          • 基础R
          • 一行
          • 其中的映射在代码中非常清晰易读
          • 没有辅助函数(好吧,一个匿名函数)
          • 方法适用于底片
          • 方法适用于任何原子向量(实数、字符)

          像这样:

          > transform(z,q=t*sapply(as.character(x),function(x) switch(x,"2"=2,"4"=4,"7"=3,1)))
              x  y  t  q
          1   1 11 21 21
          2   2 12 22 44
          3   3 13 23 23
          4   4 14 24 96
          5   5 15 25 25
          6   6 16 26 26
          7   7 17 27 81
          8   8 18 28 28
          9   9 19 29 29
          10 10 20 30 30
          

          【讨论】:

            【解决方案7】:

            您也可以使用匹配来执行此操作。在将 col、pch 和 cex 等参数分配给散点图中的点时,我倾向于使用它

            searchfor<-c(2,4,7)
            replacewith<-c(2,4,3)
            
            # generate multiplier column
            # q could also be an existing vector where you want to replace certain entries
            q<-rep(1,nrow(z))
            #
            id<-match(z$x,searchfor)
            id<-replacewith[id]
            # Apply the matches to q
            q[!is.na(id)]<-id[!is.na(id)]
            # apply to t
            z$q<-q*z$t
            

            【讨论】:

              【解决方案8】:

              这是 R 中用于字符向量(未经因子测试)的 SQL decode 版本,其操作与 SQL 版本一样。即它采用任意数量的目标/替换对,以及作为默认值的可选最后一个参数(请注意,默认值不会覆盖 NA)。

              我可以看到它与dplyrmutate 操作结合使用非常有用。

              > x <- c("apple","apple","orange","pear","pear",NA)
              
              > decode(x, apple, banana)
              [1] "banana" "banana" "orange" "pear"   "pear"   NA      
              
              > decode(x, apple, banana, fruit)
              [1] "banana" "banana" "fruit"  "fruit"  "fruit"  NA      
              
              > decode(x, apple, banana, pear, passionfruit)
              [1] "banana"       "banana"       "orange"       "passionfruit" "passionfruit" NA            
              
              > decode(x, apple, banana, pear, passionfruit, fruit)
              [1] "banana"       "banana"       "fruit"        "passionfruit" "passionfruit" NA  
              

              这是我正在使用的代码,我会在这里更新一个要点 (link)。

              decode <- function(x, ...) {
              
                args <- as.character((eval(substitute(alist(...))))
              
                replacements <- args[1:length(args) %% 2 == 0]
                targets      <- args[1:length(args) %% 2 == 1][1:length(replacements)]
              
                if(length(args) %% 2 == 1)
                  x[! x %in% targets & ! is.na(x)] <- tail(args,1)
              
                for(i in 1:length(targets))
                  x <- ifelse(x == targets[i], replacements[i], x)
              
                return(x)
              
              }
              

              【讨论】:

                猜你喜欢
                • 2020-02-10
                • 1970-01-01
                • 2013-08-04
                • 2020-04-24
                • 1970-01-01
                • 2019-11-30
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多