R как я могу рассчитать разницу между строками в кадре данных

Вот простой пример моей проблемы:

> 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

Может ли кто-нибудь сказать мне, почему эта ошибка возникает?

Ответы

Ответ 1

diff хочет получить матрицу или вектор, а не кадр данных. Попробуйте

data.frame(diff(as.matrix(df)))

Ответ 2

Возможно, вы ищете что-то вроде этого:

> 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 вместе, если они имеют одинаковые размеры. Итак, что мы делаем здесь, вычитаем один data.frame, который пропускает первую строку (tail(df, -1)), и тот, который пропускает последнюю строку (head(df, -1)) и вычитает их.

Ответ 3

Поскольку 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

Кажется маловероятным, что вы хотите рассчитать разницу в последовательных идентификаторах, поэтому вы можете применить его ко всем столбцам, кроме первого, например:

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 в качестве примера.

Ответ 4

Добавьте это через несколько лет для полноты - вы можете использовать простую подкачку [.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

Ответ 5

Другая опция, использующая dplyr, будет использовать mutate_each для циклического прохождения всех столбцов, получить разницу в столбце (.) с lag столбца (.) и удалить NA элемент вверху с na.omit()

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

Или с shift от data.table. Преобразуйте 'data.frame' в 'data.table' (setDT(df)), пропустите столбцы (lapply(.SD, ..) ) and get the difference between the column ( x ) and the lag ( shift by default gives the lag as type = "лаг" `). Удалите первое наблюдение, то есть элемент NA.

library(data.table)
setDT(df)[, lapply(.SD, function(x) (x- shift(x))[-1])]

Ответ 6

Я хотел бы показать альтернативный способ делать такие вещи, даже часто у меня такое чувство, что не стоит так делать: используя 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