将负值替换为上一行/ 2

问题描述 投票:0回答:2

我想调整val列,以便不会有任何负值。

调整规则是,

  • 将负值替换为前一行的一半
  • 为每个hier做这个(group_by(hier))
  • 如果连续多个负值,则将之前的调整值除以2 xdat <- data.frame( hier = c(rep("A",5), rep("B",5) ) , val = c(4, 7, -3, 10, 5, 1, -7, -4, 5, 7) ) hier | val | val_adjust A | 4 | 4 A | 7 | 7 A | -3 | 3.5 A | 10 | 10 A | 5 | 5 B | 1 | 1 B | -7 | 0.5 B | -4 | 0.25 B | 5 | 5 B | 7 | 7
r dplyr
2个回答
2
投票

你可以使用accumulatepurrr

library(tidyverse)
 xdat%>%group_by(hier)%>%mutate(adj_val=accumulate(val,~ifelse(.y<0,.x/2,.y)))
# A tibble: 10 x 3
# Groups:   hier [2]
     hier   val adj_val
   <fctr> <dbl>   <dbl>
 1      A     4    4.00
 2      A     7    7.00
 3      A    -3    3.50
 4      A    10   10.00
 5      A     5    5.00
 6      B     1    1.00
 7      B    -7    0.50
 8      B    -4    0.25
 9      B     5    5.00
10      B     7    7.00

在基地R你可以做类似的事情:

transform(xdat,y=unlist(tapply(val,hier,FUN=Reduce,f=function(x,y)ifelse(y<0,x/2,y),accumulate=T)))
   hier val     y
A1    A   4  4.00
A2    A   7  7.00
A3    A  -3  3.50
A4    A  10 10.00
A5    A   5  5.00
B1    B   1  1.00
B2    B  -7  0.50
B3    B  -4  0.25
B4    B   5  5.00
B5    B   7  7.00

0
投票

在生成可重现的问题时找到答案

xdat %>% 
  rowid_to_column("rowid") %>% 
  group_by(hier) %>% 
  mutate(rowid = rank(rowid)) %>% 
  mutate(val_adj1 = lag(val)) %>% 
  mutate(val_adj1 = case_when(val < 0~val_adj1/2, TRUE~val)) %>% 
  mutate(val_adj2 = lag(val_adj1)) %>% 
  mutate(val_adj2 = case_when(val_adj1 < 0~val_adj2/2, TRUE~val_adj1))  

生成

   rowid   hier   val val_adj1 val_adj2
   <dbl> <fctr> <dbl>    <dbl>    <dbl>
 1     1      A     4      4.0     4.00
 2     2      A     7      7.0     7.00
 3     3      A    -3      3.5     3.50
 4     4      A    10     10.0    10.00
 5     5      A     5      5.0     5.00
 6     1      B     1      1.0     1.00
 7     2      B    -7      0.5     0.50
 8     3      B    -4     -3.5     0.25
 9     4      B     5      5.0     5.00
10     5      B     7      7.0     7.00
© www.soinside.com 2019 - 2024. All rights reserved.