dplyr mutate的复杂条件

时间:2017-06-12 23:00:48

标签: r if-statement dplyr mutate

示例数据:

library(dplyr)

id <- rep(LETTERS[1:5], each = 10)
x <- round(runif(50, -500, 200), digits = 0)
y <- round(runif(50, -700, 700), digits = 0)
z <- round(runif(50, 250, 300), digits = 0)

df.1 <- data.frame(id = id, x = x, y = y, z = z)
> summary(df.1)
 id           x                y                 z        
 A:10   Min.   :-497.0   Min.   :-665.00   Min.   :251.0  
 B:10   1st Qu.:-283.2   1st Qu.:-349.50   1st Qu.:261.2  
 C:10   Median :-128.0   Median : -33.50   Median :274.5  
 D:10   Mean   :-145.4   Mean   : -39.58   Mean   :275.3  
 E:10   3rd Qu.: -15.0   3rd Qu.: 293.25   3rd Qu.:288.0  
        Max.   : 171.0   Max.   : 696.00   Max.   :299.0  

我想要实现的目标是:

  1. 将每个id放入自己的数据框
  2. 创建一个名为&#34; direction&#34;的新列。这将是对以下条件的回应
  3. a - 识别x,y,z中范围最宽的列 b - 在标识的列中,根据下一行值是否大于当前行值来计算方向 - TRUE和FALSE return

    即y具有最大范围

      id    x    y   z direction
    1  A -320   31 251      TRUE
    2  A -199 -530 276     FALSE
    3  A -228  390 264      TRUE
    4  A -158  363 268      TRUE
    5  A -308  150 267     FALSE
    6  A  -47  345 261        NA
    

    在具有最大范围的列上计算方向非常重要。在示例数据中,可能的列y始终是具有最大范围的列,但在我的实际数据中,它可以是任何列。

    我想它会涉及mutate和ifelse?!但不确定我是怎么做的......我通常会使用广泛的for循环,并且上周或者两周才开始使用dplyr。试着不要再回到凌乱的for循环和严重嵌套的代码.. < / p>

    非常感谢你的帮助!谢谢!

        for (i in 1:length(unique(id)) {
    
        x <- 
          df.1 %>% 
          filter(id == unique(id)[i] %>%
          mutate(direction = ifelse())
    
        assign(unique(id)[i], x)
    
          }
    

1 个答案:

答案 0 :(得分:0)

  

将每个id放入自己的数据框

df_list = split(df.1, df.1$id)
  

创建一个名为“direction”的新列,它将响应

以下的条件      
      
  • 识别x,y,z b中最宽范围的列
  •   
  • 在标识的列中,根据下一行值是否大于当前行值来计算方向
  •   
  • TRUE和FALSE返回
  •   

让我们编写一个函数来对一个数据框执行此操作:

foo = function(df) {
  # identify column with widest range within x, y, z
  sub_df = df[c("x", "y", "z")]
  ranges = sapply(sub_df, max) - sapply(sub_df, min)
  widest = which.max(ranges)
  # see which direction it goes
  direction = diff(sub_df[[widest]]) < 0
  # add this as a column to whole df
  df$direction = c(direction, NA)
  return(df)
}

然后我们可以将此函数应用于每个数据框:

df_list = lapply(df_list foo)

在这里完成演示。为了保持紧凑,我将数据缩小了一点:

set.seed(47)
id <- rep(LETTERS[1:3], each = 6)
x <- round(runif(18, -500, 200), digits = 0)
y <- round(runif(18, -700, 700), digits = 0)
z <- round(runif(18, 250, 300), digits = 0)
df.1 <- data.frame(id = id, x = x, y = y, z = z)

df_list = split(df.1, df.1$id)

df_list = lapply(df_list, foo)
df_list
# $A
# id    x    y   z direction
# 1  A  184 -600 262     FALSE
# 2  A -238  -44 299      TRUE
# 3  A   33 -451 274     FALSE
# 4  A   76   80 284      TRUE
# 5  A  -99   22 253      TRUE
# 6  A  -16 -513 269        NA
# 
# $B
# id    x    y   z direction
# 7   B -228  265 280      TRUE
# 8   B -172 -168 297      TRUE
# 9   B -120 -653 268     FALSE
# 10  B  147 -648 260     FALSE
# 11  B -403   51 283     FALSE
# 12  B   -9  419 298        NA
# 
# $C
# id    x    y   z direction
# 13  C -386  348 269      TRUE
# 14  C  -80 -183 293     FALSE
# 15  C -146  -45 259      TRUE
# 16  C  131 -429 289     FALSE
# 17  C -220  556 253      TRUE
# 18  C -478  -84 252        NA

我没有使用dplyrdplyr擅长许多事情,但在dplyr中对列所依赖条件的列执行操作很困难,在上面编写类似foo的函数更容易。也就是说,您可以稍微调整一下这个功能并执行以下操作:

library(dplyr)
library(tidyr)
df.1 %>% group_by(id) %>% 
  do(a = foo(.)) %>%  
  ungroup() %>% 
  unnest()

如果您希望数据框分开,最后仍然是split,但lapply非常简单(并且不需要额外的包),而这似乎更复杂,没有任何好处。