【问题标题】:Cumsum with conditions in RCumsum 与 R 中的条件
【发布时间】:2018-04-08 14:21:15
【问题描述】:
set.seed(123)
df <- data.frame(loc.id = rep(1:3,each = 3*5), 
             year = rep(rep(1981:1983, each = 5), times = 3), 
             week = rep(rep(20:24, times = 3), times = 3),
             cumsum.val = runif(min  = -2, max = 4, 5*3*3))

数据包含3 locations X 3 years X 5 weeks 和一个名为cumsum.val 的值。对于每个位置和年份,我想找到cumsum.val &gt; 1 所在的周数。然后,如果连续出现cumsum.val &gt; 1 的两周,则选择第一周。一个例子

  test <- df[df$loc.id == 1 & df$year == 1981,]
  test$cumsum.test <- test$cumsum.val > 1 # weeks where cumsum.val > 1
  head(test)
    loc.id year   week cumsum.val cumsum.test
 1      1 1981   20 -0.2745349       FALSE
 2      1 1981   21  2.7298308        TRUE
 3      1 1981   22  0.4538615       FALSE
 4      1 1981   23  3.2981044        TRUE
 5      1 1981   24  3.6428037        TRUE

现在选择 TRUE 连续出现两次的第一周,在上述情况下是周 23(因为周 2324 都是 TRUE)。

如何为df 实现此功能。可能没有连续两周出现cumusm.val &gt; 1。在这种情况下,只需选择cumsum.val &gt; 1 所在的第一周

【问题讨论】:

  • 试试inx &lt;- rev(c(FALSE, diff(rev(test$cumsum.test)) == 0)); test[inx, ]
  • 这行得通。我如何为整个 df 实现这个

标签: r dplyr data.table cumsum


【解决方案1】:

一个基于dplyr 的解决方案可以解决这个问题。请注意cumsum.test 已计算为numeric,因此default 的值laglead 可以使用0/1 以外的其他值。

df %>% mutate(cumsum.test = as.numeric(cumsum.val>1)) %>%
  group_by(loc.id, year) %>%
  mutate(SelctCond = ifelse(cumsum.test == 1 & 
                       cumsum.test == lead(cumsum.test, default = -1L) &
                       cumsum.test != lag(cumsum.test, default = -1L), TRUE , FALSE )) %>%
  filter(SelctCond) %>%
  select(-SelctCond)
# # Groups: loc.id, year [6]
# loc.id  year  week cumsum.val cumsum.test
# <int> <int> <int>      <dbl>       <dbl>
# 1      1  1981    23       3.30        1.00
# 2      1  1982    21       1.17        1.00
# 3      1  1983    22       2.07        1.00
# 4      2  1982    20       3.34        1.00
# 5      2  1983    20       2.25        1.00
# 6      3  1981    20       3.78        1.00

【讨论】:

  • 快速提问:-1L 在您的解决方案中是什么意思
  • @Crop89 我添加了 cmets。 01 在您的情况下对应于 FALSETRUE。现在第一行 lag 不可用,因此不应将其视为匹配值。我将default 用于lead/lag 作为-1L,这样它就不会匹配真/假条件。
  • @Crop89 我希望您提供的数据中的结果应该符合您的期望。请确认。
【解决方案2】:
set.seed(123)
df <- data.frame(loc.id = rep(1:3,each = 3*5), 
                 year = rep(rep(1981:1983, each = 5), times = 3), 
                 week = rep(rep(20:24, times = 3), times = 3),
                 cumsum.val = runif(min  = -2, max = 4, 5*3*3))

View(df)
b <- unique(df$loc.id)
data <- data.frame()
for(i in seq_along(b)){
  check=0
  for(j in 1:length(df$loc.id)){
    if(df$cumsum.val[j]>1 && df$loc.id[j]==b[i]){
      check=check+1
    }
    else if(df$loc.id[j]==b[i]){
      check=0
    }
    if(check>=2){
      data1 <- data.frame(week1=df$week[j-1],idd=df$loc.id[j])
      data <- rbind(data,data1)
    }
  } 
}

【讨论】:

    【解决方案3】:

    data.table 方法:

    require(data.table) # load package
    setDT(df) # Convert to data.table
    df[, cumsum.test := cumsum.val > 1] # create new variable
    
    # Find consecutive values, check they are indeed cumsum.val > 1, and return the first row of them:
    df[c(diff(cumsum.test), NA) == 0 & cumsum.test == TRUE, .SD[1, ]]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-04
      相关资源
      最近更新 更多