user2472414
user2472414

Reputation: 141

Find the ratio between each column entry and the following entry, for every column, for a list of data.frames in R

I have a dataset that looks like this, where there are ~500 dataframes in a list:

1   1   1   1   1   1   1   1   1
1   1   1   1   1   1   1   1   2
1   1   1   1   1   1   1   1   1
1   1   1   1   1   1   1   1   2
1   1   1   1   1   1   1   1   1
1   1   1   1   1   1   1   1   2
1   1   1   1   1   1   1   1   1
1   1   1   1   1   1   1   1   2
1   1   1   1   1   1   1   1   1
1   1   1   1   1   1   1   1   2
1   1   1   1   1   1   1   1   1
1   1   1   1   1   1   1   1   2
1   1   1   1   1   1   1   1   1
1   1   1   1   1   1   1   1   2
1   1   1   1   1   1   1   1   1
1   1   1   1   1   1   1   1   2
1   1   1   1   1   1   1   1   1
1   1   1   1   1   1   1   1   2
1   1   1   1   1   1   1   1   1
1   1   1   1   1   1   1   1   2

Within each column, I want to find the ratio of the first value to the second value, then the third value to the fourth, then the fifth value to the six, etc. Then I want to do that to every column, and output it to a new data frame. Like this:


1   1   1   1   1   1   1   1   0.5                         
1   1   1   1   1   1   1   1   0.5
1   1   1   1   1   1   1   1   0.5
1   1   1   1   1   1   1   1   0.5
1   1   1   1   1   1   1   1   0.5
1   1   1   1   1   1   1   1   0.5 
1   1   1   1   1   1   1   1   0.5
1   1   1   1   1   1   1   1   0.5
1   1   1   1   1   1   1   1   0.5                         
1   1   1   1   1   1   1   1   0.5

And I want to be able to apply it to the list of data frames at one time.

The closest I've gotten is with one data frame, and only one column... where I would also have to delete every other value (which is ok, I can do that in post processing).

ratio = df[[1]][,1]/lag(df[[1]][,1],1)

But again, it needs to do every column into the new data frame, applied to a list of data frames.

Note that the actual values can be anything from 0 to 2000, they are not necessarily all 1's and 2's.

data

df <- data.frame(cbind(1, 1, 1, 1, 1, 1, 1, 1, rep(1:2, 10)))
ll <- list(df, df, df)

Upvotes: 1

Views: 60

Answers (1)

bouncyball
bouncyball

Reputation: 10761

We can use the apply function, and work with the seq function. The key is in what we're doing with the seq function. The first one we're iterating from 1 to n by steps of 2 (1, 3, 5, ...), the next we're iterating from 2 to n by steps of 2 (2, 4, 6, ...). This might cause issues if your row count is not an even number.

apply(d, 2, 
      FUN = function(x) x[seq(1, length(x), by = 2)] / x[seq(2, length(x), by= 2)])

      V1 V2 V3 V4 V5 V6 V7 V8  V9
 [1,]  1  1  1  1  1  1  1  1 0.5
 [2,]  1  1  1  1  1  1  1  1 0.5
 [3,]  1  1  1  1  1  1  1  1 0.5
 [4,]  1  1  1  1  1  1  1  1 0.5
 [5,]  1  1  1  1  1  1  1  1 0.5
 [6,]  1  1  1  1  1  1  1  1 0.5
 [7,]  1  1  1  1  1  1  1  1 0.5
 [8,]  1  1  1  1  1  1  1  1 0.5
 [9,]  1  1  1  1  1  1  1  1 0.5
[10,]  1  1  1  1  1  1  1  1 0.5

Using the list you added to your question:

lapply(ll, 
       FUN = function(d) 
           apply(d, 2, 
                 FUN = 
                     function(x) x[seq(1, length(x), by = 2)] / x[seq(2, length(x), by= 2)]))

Upvotes: 2

Related Questions