35

这是我的问题的一个简单示例:

> df <- data.frame(ID=1:10,Score=4*10:1)
> df
       ID Score
    1   1    40
    2   2    36
    3   3    32
    4   4    28
    5   5    24
    6   6    20
    7   7    16
    8   8    12
    9   9     8
    10 10     4
    > diff(df)

Error in r[i1] - r[-length(r):-(length(r) - lag + 1L)] : 
  non-numeric argument to binary operator

谁能告诉我为什么会出现这个错误?

4

8 回答 8

43

diff 需要一个矩阵或向量而不是数据框。尝试

data.frame(diff(as.matrix(df)))
于 2013-04-25T10:18:35.457 回答
27

也许您正在寻找这样的东西:

> tail(df, -1) - head(df, -1)
   ID Score
2   1    -4
3   1    -4
4   1    -4
5   1    -4
6   1    -4
7   1    -4
8   1    -4
9   1    -4
10  1    -4

data.frame如果它们是相同的尺寸,您可以将两个 s 相减或相加。因此,我们在这里所做的是减去data.frame缺少第一行的一个 ( tail(df, -1)) 和一个缺少最后一行的 ( head(df, -1)) 并减去它们。

于 2013-04-25T10:18:19.620 回答
14

另一个使用选项dplyrmutate_each遍历所有列,获取列 ( .) 与lag列( ) 的差异,.并删除顶部的 NA 元素na.omit()

library(dplyr)
df %>%
    mutate_each(funs(. - lag(.))) %>%
    na.omit() 

编辑:

而不是mutate_each(不推荐使用 - 如@PatrickT所述)使用mutate_all

df %>%
    mutate_all(funs(. - lag(.))) %>%
    na.omit() 

或使用shiftfrom data.table。将 'data.frame' 转换为 'data.table' ( setDT(df)),遍历列 ( lapply(.SD, ..) ) and get the difference between the column (x ) and thelag (shift by default gives thelag astype = "lag"`)。删除第一个观察值,即 NA 元素。

library(data.table)
setDT(df)[, lapply(.SD, function(x) (x- shift(x))[-1])]
于 2016-08-05T08:40:09.437 回答
11

因为 df 适用于向量或矩阵。您可以使用 apply 跨列应用函数,如下所示:

 apply( df , 2 , diff )
   ID Score
2   1    -4
3   1    -4
4   1    -4
5   1    -4
6   1    -4
7   1    -4
8   1    -4
9   1    -4
10  1    -4

您似乎不太可能想要计算顺序 ID 的差异,因此您可以选择将其应用于 第一列之外的所有列,如下所示:

apply( df[-1] , 2 , diff )

或者你可以使用data.table(不是它在这里添加任何东西,我只是真的想开始使用它!),我再次假设你不想应用diff到 ID 列:

DT <- data.table(df)
DT[ , list(ID,Score,Diff=diff(Score))  ]
    ID Score Diff
 1:  1    40   -4
 2:  2    36   -4
 3:  3    32   -4
 4:  4    28   -4
 5:  5    24   -4
 6:  6    20   -4
 7:  7    16   -4
 8:  8    12   -4
 9:  9     8   -4
10: 10     4   -4

并且感谢@AnandaMahto,另一种语法可以更灵活地选择在哪些列上运行它可能是:

DT[, lapply(.SD, diff), .SDcols = 1:2]

.SDcols = 1:2意味着您要将diff函数应用于第 1 列和第 2 列。如果您有 20 列并且不想将其应用于 ID,您可以使用.SDcols=2:20作为示例。

于 2013-04-25T10:18:52.523 回答
5

我想展示另一种方法来做这种事情,即使我经常觉得这样做并不受欢迎:使用 sql。

sqldf(paste("SELECT a.ID,a.Score"
            ,"      , a.Score - (SELECT b.Score"
            ,"                   FROM df b"
            ,"                   WHERE b.ID < a.ID"
            ,"                   ORDER BY b.ID DESC"
            ,"                   ) diff"
            ," FROM df a"
            )
      )

代码看起来很复杂,但实际上并不复杂,它有一些优势,正如您在结果中看到的那样:

    ID Score diff
 1   1    40 <NA>
 2   2    36 -4.0
 3   3    32 -4.0
 4   4    28 -4.0
 5   5    24 -4.0
 6   6    20 -4.0
 7   7    16 -4.0
 8   8    12 -4.0
 9   9     8 -4.0
 10 10     4 -4.0

一个优点是您使用原始数据框(无需转换为其他类)并获得一个数据框(将其放入 res <- ....)。另一个优点是您仍然拥有所有行。第三个优点是您可以轻松考虑分组因素。例如:

df2 <- data.frame(ID=1:10,grp=rep(c("v","w"), each=5),Score=4*10:1)

sqldf(paste("SELECT a.ID,a.grp,a.Score"
            ,"      , a.Score - (SELECT b.Score"
            ,"                   FROM df2 b"
            ,"                   WHERE b.ID < a.ID"
            ,"                         AND a.grp = b.grp"
            ,"                   ORDER BY b.ID DESC"
            ,"                   ) diff"
     ," FROM df2 a"
     )
)


   ID grp Score diff
1   1   v    40 <NA>
2   2   v    36 -4.0
3   3   v    32 -4.0
4   4   v    28 -4.0
5   5   v    24 -4.0
6   6   w    20 <NA>
7   7   w    16 -4.0
8   8   w    12 -4.0
9   9   w     8 -4.0
10 10   w     4 -4.0
于 2015-03-16T17:22:39.763 回答
5

几年后添加它以确保完整性 - 您也可以使用简单 [.data.frame的子集来实现这一点

df[-1, ] - df[-nrow(df), ]
#    ID Score
# 2   1    -4
# 3   1    -4
# 4   1    -4
# 5   1    -4
# 6   1    -4
# 7   1    -4
# 8   1    -4
# 9   1    -4
# 10  1    -4
于 2016-08-05T08:25:30.040 回答
1

看这个答案: 计算 R 中的行之间的差异并设置零第一个差异

我认为这是最简单的方法。

df <- data.frame(ID=1:8, x2=8:1, x3=11:18, x4=c(2,4,10,0,1,1,9,12))
df$vardiff <- c(0, diff(df$x4))
df
于 2021-05-12T03:45:24.993 回答
0

我个人的简单方法是使用 pivot_wider 创建另一列,然后您可以使用 summarise 减去差异:D

全部来自 dyplr 包

于 2021-04-30T12:58:57.390 回答