【问题标题】:How to subtract every previous rows from the lead row to every five rows in R?如何将前导行中的每一行减去R中的每五行?
【发布时间】:2019-10-11 15:25:41
【问题描述】:

我有一个更大的数据框,其中包含多列和数千行。我想通过从数据帧的每五行的前导行中减去前一行的值来替换每个前导行的值。例如,第一个值应保留其值,第二行应为:second row - first row。同样,第六行应保留其值,但是,第七行将是seventh row - sixth row。这是一个示例数据框

DF = data.frame(A= c(1:11), B = c(11:21))

输出应该如下所示

> Output
    A  B
1   1 11
2   1  1
3   1  1
4   1  1
5   1  1
6   6 16
7   1  1
8   1  1
9   1  1
10  1  1
11 11 21

【问题讨论】:

  • 查看dplyr版本packageVersion('dplyr')可能会更好
  • 我安装的dplyr版本是‘0.8.0.1’
  • 能否请您更新您的版本,因为它可能会影响
  • 重新安装了这个包,它现在是'0.8.3'版本并得到了结果。但是,我也收到了这个警告:mutate_all()忽略了以下分组变量:列grp使用mutate_at(df, vars(-group_cols()), myoperation) 使消息静音。
  • 感谢@akrun 和其他所有人提供非常有用的建议。

标签: r dataframe aggregate subtraction tapply


【解决方案1】:

一种选择是创建一个分组变量,然后使用diff 进行转换,这会导致mutate_all 中选择的列的相邻元素的差异(如果只需要列的子集,请使用mutate_ifmutate_at)

library(dplyr) #v_0.8.3
DF %>% 
   group_by(grp = as.integer(gl(n(), 5, n()))) %>% 
   mutate_all(~c(first(.), diff(.))) %>%
   ungroup %>%
   select(-grp)
# A tibble: 11 x 2
#       A     B
#   <int> <int>
# 1     1    11
# 2     1     1
# 3     1     1
# 4     1     1
# 5     1     1
# 6     6    16
# 7     1     1
# 8     1     1
# 9     1     1
#10     1     1
#11    11    21

当我们在group_by 之后使用mutate_all 时,上面也给出了警告(以前它曾经可以工作 - 在新版本中,正确的语法是使用mutate_at

DF %>% 
   group_by(grp = as.integer(gl(n(), 5, n()))) %>% 
   mutate_at(vars(-group_cols()), ~c(first(.), diff(.))) %>%
   ungroup %>%
   select(-grp)

【讨论】:

  • 在执行代码 ``mutate_all()` 时收到此错误消息忽略了以下分组变量: 列 grp 使用 mutate_at(df, vars(-group_cols()), myoperation) 使消息静音。 select(., -grp) 中的错误:未使用的参数 (-grp)`
  • @Hydrologist 是否与您显示的数据相同,因为我无法用 dplyr_0.8.3 重现它
  • 我有不同的数据,但我尝试了相同的数据。得到同样的错误
  • @Hydrologist 所以,你没有得到你显示的数据的错误,对吗?您能否检查新数据的str 并与显示的数据进行比较。我有一种感觉,有一些组属性导致它。你能ungroup然后再做group_by
  • 我在使用您的代码时遇到了相同数据的错误。我正在为您提供的答案添加屏幕截图,因为我不知道是否可以将其包含在我的评论中。
【解决方案2】:
f = function(d, n = 5) ave(d, ceiling(seq_along(d)/n), FUN = function(x) c(x[1], diff(x)))
data.frame(lapply(DF, f))
#    A  B
#1   1 11
#2   1  1
#3   1  1
#4   1  1
#5   1  1
#6   6 16
#7   1  1
#8   1  1
#9   1  1
#10  1  1
#11 11 21

另一种选择是创建另一个带有移位行的 data.frame 并直接减去

ind = ave(1:nrow(DF), ceiling(1:nrow(DF)/5), FUN = function(x) c(x[1], x[-length(x)]))
DF2 = DF[ind,] * replace(rep(1, nrow(DF)), diff(ind) == 0, 0)
DF - DF2

【讨论】:

    【解决方案3】:

    您可以%/% 行号减 1 乘 5 得到组,然后使用 diff 从 @987654325 获取与前一个 x 的差异(如果没有前一个 x,则为 0) @ 代表所有列 x 代表每个组。

    library(data.table)
    setDT(DF)
    
    DF[, lapply(.SD, function(x) diff(c(0, x)))
       , (1:nrow(DF) - 1) %/% 5][, -1]
    
    #      A  B
    #  1:  1 11
    #  2:  1  1
    #  3:  1  1
    #  4:  1  1
    #  5:  1  1
    #  6:  6 16
    #  7:  1  1
    #  8:  1  1
    #  9:  1  1
    # 10:  1  1
    # 11: 11 21
    

    或者,正如@akrun 所述,您可以通过替换来避免lapply

    lapply(.SD, function(x) diff(c(0, x)))
    

    .SD - shift(.SD, fill = 0)
    

    另一个不太严重的选择:

    x <- DF[, !(.I - 1) %% 5]
    DF*(1 + x) - DF[DF[, .I - !x]]
    
    #      A  B
    #  1:  1 11
    #  2:  1  1
    #  3:  1  1
    #  4:  1  1
    #  5:  1  1
    #  6:  6 16
    #  7:  1  1
    #  8:  1  1
    #  9:  1  1
    # 10:  1  1
    # 11: 11 21
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-24
      • 1970-01-01
      • 2021-01-09
      • 1970-01-01
      • 2019-07-24
      • 1970-01-01
      相关资源
      最近更新 更多