按组计算连续行之间的值差异

84

这是我的一个df(数据框):

group value
1     10
1     20
1     25
2     5
2     10
2     15 

我需要按组计算相邻行之间的值的差异。

因此,我需要一个这样的结果。

group value diff
1     10    NA # because there is a no previous value
1     20    10 # value[2] - value[1]
1     25    5  # value[3] value[2]
2     5     NA # because group is changed
2     10    5  # value[5] - value[4]
2     15    5  # value[6] - value[5]

虽然我可以使用ddply来处理这个问题,但它需要太多时间。这是因为我的df中有很多组。(在我的df中有超过1,000,000个组)

是否还有其他有效的方法来解决这个问题?

4个回答

138

data.table可以使用shift函数相当快地完成此操作。

require(data.table)
df <- data.table(group = rep(c(1, 2), each = 3), value = c(10,20,25,5,10,15))
#setDT(df) #if df is already a data frame

df[ , diff := value - shift(value), by = group]    
#   group value diff
#1:     1    10   NA
#2:     1    20   10
#3:     1    25    5
#4:     2     5   NA
#5:     2    10    5
#6:     2    15    5
setDF(df) #if you want to convert back to old data.frame syntax

或者使用 dplyr 中的 lag 函数

df %>%
    group_by(group) %>%
    mutate(Diff = value - lag(value))
#   group value  Diff
#   <int> <int> <int>
# 1     1    10    NA
# 2     1    20    10
# 3     1    25     5
# 4     2     5    NA
# 5     2    10     5
# 6     2    15     5

如需 data.table::shiftdplyr::lag 前的备选方法,请参见编辑。


1
你知道有没有ddply的解决方案吗?我一直在做这个工作,直到我想出可能需要一个不同的函数…… - Jack Ryan
3
我认为这应该是类似于ddply(df, .(group), transform, diff=c(NA,diff(value)))的东西。 - Blue Magister
你如何修改这个程序来计算百分比变化? - Hardik Gupta
你可以在这里应用任何函数。例如,如果这是我们的函数:perc_change <- function(x, y) { return(x/y*100) },那么我们可以像这样调用它:df[ , perc_diff := perc_change(value, shift(value)), by = group] - srctaha
你如何将NA替换为下一个值,以便第一行的“Diff”也像第二行一样为10? - Manasi Shah
@ManasiShah: library(dplyr),第二行: df$Diff <- as.data.frame((df %>% group_by(group) %>% mutate(Diff = value - lag(value)))[ , 3]) 第三行: df$Diff[is.na(df$Diff)] <- unlist((df %>% group_by(group) %>%summarise(start.values = first(value)))[ , 2]) - InColorado

23

您可以使用基本函数 ave() 来实现此操作

df <- data.frame(group=rep(c(1,2),each=3),value=c(10,20,25,5,10,15))
df$diff <- ave(df$value, factor(df$group), FUN=function(x) c(NA,diff(x)))

它返回

  group value diff
1     1    10   NA
2     1    20   10
3     1    25    5
4     2     5   NA
5     2    10    5
6     2    15    5

相关问题:https://dev59.com/4Ivda4cB1Zd3GeqPVB6- 我发现这两个线程都很有帮助。对于日期,您可以使用以下代码: df$diff <- ave(as.numeric(df$Datevalue), factor(df$group), FUN=function(x) c(NA,diff(x))) 此外,如果您想让组中的最后一行具有NA,则可以交换NA的位置。 df$diff <- ave(as.numeric(df$Datevalue), factor(df$group), FUN=function(x) c(diff(x), NA)) - Brian D

4

使用tapply尝试一下

df$diff<-as.vector(unlist(tapply(df$value,df$group,FUN=function(x){ return (c(NA,diff(x)))})))

3
我需要做的是:df$diff <- unlist(tapply(df$value, df$group, function(x) c(NA,diff(x)))) - Tyler Rinker

0

自从 dplyr 1.1.0 版本以来,你可以使用 .by 来缩短 dplyr 版本中的内联临时分组:

mutate(df, diff = value - lag(value), .by = group)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接