Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shifting a data frame in R

Tags:

r

i have a data frame like this

A B value
1 1 0.123
2 1 0.213
3 1 0.543
1 2 0.313
2 2 0.123
3 2 0.412

what i want to do is to create a function that shift this data frame by a value. for example:

if the value of shifting is 1 the data frame will become:

A B value
3 2 0.412
1 1 0.123
2 1 0.213
3 1 0.543
1 2 0.313
2 2 0.123

etc...

the function should be like this.

shift<-function(dataframe,shiftvalue)

is there any simple way to do this in R without entering in a lot of loops??

like image 722
smack Avatar asked Jun 12 '11 14:06

smack


4 Answers

There's a shift function in taRifx that works on vectors. Applying it results in coersion of all columns to character if any are character, so we'll use a trick from plyr. I'll likely write a data.frame method for it soon:

dd <- data.frame(b = seq(4),
      x = c("A", "D", "A", "C"), y = c('a','b','c','d'),
      z = c(1, 1, 1, 2),stringsAsFactors=FALSE)

> dd
  b x y z
1 1 A a 1
2 2 D b 1
3 3 A c 1
4 4 C d 2

library(taRifx)
library(plyr)
shift.data.frame <- colwise(shift)
> shift.data.frame(dd)
  b x y z
1 2 D b 1
2 3 A c 1
3 4 C d 2
4 1 A a 1
> shift(dd,n=-1)
  b x y z
1 4 C d 2
2 1 A a 1
3 2 D b 1
4 3 A c 1
> shift(dd,n=-1,wrap=FALSE)
  b x y z
1 1 A a 1
2 2 D b 1
3 3 A c 1
> shift(dd,n=-1,wrap=FALSE,pad=TRUE)
   b    x    y  z
1 NA <NA> <NA> NA
2  1    A    a  1
3  2    D    b  1
4  3    A    c  1

The advantage of shift is that it takes a bunch of options:

  • n can be positive or negative to wrap from left/right
  • wrap can be turned on or off
  • If wrap is turned off, pad can be turned on to pad with NAs so vector remains the same length
like image 64
Ari B. Friedman Avatar answered Nov 06 '22 09:11

Ari B. Friedman


You can do it many ways, but one way is to use head and tail:

df <- data.frame(a=1:10, b = 11:20)

shift <- function(d, k) rbind( tail(d,k), head(d,-k), deparse.level = 0 )


> shift(df,3)
    a  b
4   4 14
5   5 15
6   6 16
7   7 17
8   8 18
9   9 19
10 10 20
1   1 11
2   2 12
3   3 13
like image 21
Prasad Chalasani Avatar answered Nov 06 '22 09:11

Prasad Chalasani


I prefer plain old modulo ;-)

shift<-function(df,offset) df[((1:nrow(df))-1-offset)%%nrow(df)+1,]

It is pretty straightforward, the only quirk is R's from-one indexing. Also it works for offsets like 0, -7 or 7*nrow(df)...

like image 40
mbq Avatar answered Nov 06 '22 10:11

mbq


here is my implementation:

> shift <- function(df, sv = 1) df[c((sv+1):nrow(df), 1:sv),]
> head(shift(iris, 3))
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa
7          4.6         3.4          1.4         0.3  setosa
8          5.0         3.4          1.5         0.2  setosa
9          4.4         2.9          1.4         0.2  setosa
> tail(shift(iris, 3))
    Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
148          6.5         3.0          5.2         2.0 virginica
149          6.2         3.4          5.4         2.3 virginica
150          5.9         3.0          5.1         1.8 virginica
1            5.1         3.5          1.4         0.2    setosa
2            4.9         3.0          1.4         0.2    setosa
3            4.7         3.2          1.3         0.2    setosa
>

Updated:

> shift <- function(df, sv = 1) df[c((nrow(df)-sv+1):nrow(df), 1:(nrow(df)-sv)),]
> head(shift(iris, 3))
    Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
148          6.5         3.0          5.2         2.0 virginica
149          6.2         3.4          5.4         2.3 virginica
150          5.9         3.0          5.1         1.8 virginica
1            5.1         3.5          1.4         0.2    setosa
2            4.9         3.0          1.4         0.2    setosa
3            4.7         3.2          1.3         0.2    setosa
> tail(shift(iris, 3))
    Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
142          6.9         3.1          5.1         2.3 virginica
143          5.8         2.7          5.1         1.9 virginica
144          6.8         3.2          5.9         2.3 virginica
145          6.7         3.3          5.7         2.5 virginica
146          6.7         3.0          5.2         2.3 virginica
147          6.3         2.5          5.0         1.9 virginica
like image 26
kohske Avatar answered Nov 06 '22 11:11

kohske