在 R 中将数据帧的最后 N 个值设置为 NA

Jag*_*age 5 r dataframe dplyr

我正在尝试对数据帧进行分组,并将每组中一列的最后 N 个值设置为 NA。我可以像这样 N = 1 这样做:

df %>% group_by(ID) %>% mutate(target = c(target[-n()], NA))
Run Code Online (Sandbox Code Playgroud)

但我正在努力让它适用于任何 N

这是我目前的尝试:

df %>% group_by(ID) %>% mutate(target = c(target[1:(abs(n()-1))], NA))
Run Code Online (Sandbox Code Playgroud)

但这对于规模为 1 的组来说似乎失败了

我也尝试过:

df %>% group_by(ID) %>% mutate(target = ifelse(n()==1, target, c(target[1:(abs(n()-1))], NA)))
Run Code Online (Sandbox Code Playgroud)

但 else 子句永远不会生效。

任何建议将不胜感激,谢谢。

Gre*_*reg 5

您可以使用case_when()中的矢量化解决方案dplyr

library(dplyr)

df %>%
  group_by(ID) %>%
  mutate(target = case_when(row_number() <= n() - N ~ target))
Run Code Online (Sandbox Code Playgroud)

我感谢@akrun指出默认为正确类型的case_when()an ,因此自动用s填充最后一个。NAcase_when()NNA

更新

@akrun解决方案性能更高:当对每个重复进行基准测试时times = 50

library(microbenchmark)

big_df <- tibble(ID = rep(letters, 100000)) %>%
  mutate(target = row_number()) %>%
  group_by(ID)

microbenchmark(
  times = 50,
  Greg = {
    big_df %>%
      mutate(target = case_when(row_number() <= n() - N ~ target))
  },
  akrun = {
    big_df %>%
      mutate(target = replace(target, tail(row_number(), N), NA))
  }
)
Run Code Online (Sandbox Code Playgroud)

2600000在规模(行)上它比我的快大约 35% :

Unit: milliseconds
  expr     min      lq      mean   median       uq      max neval
  Greg 82.6337 90.9669 128.93278 96.35760 213.3593 258.8570    50
 akrun 52.4519 55.8314  63.40997 61.43945  64.1082 196.4069    50
Run Code Online (Sandbox Code Playgroud)


akr*_*run 5

我们可以使用

library(dplyr)
df %>% 
   group_by(ID) %>%
   mutate(target = replace(target, tail(row_number(), N), NA))
Run Code Online (Sandbox Code Playgroud)