Reputation: 749
I have a data frame which has a column:
> head(df$lengths,5)
[[1]]
[1] "28"
[[2]]
[1] "33"
[[3]]
[1] "47" "37" "42" "41"
[[4]]
[1] "41" "39" "64" "54"
[[5]]
[1] "45" "22" "23"
I would like to operate on the elements in the vectors, to obtain the ratios of the element(i) to the element(i-k) in each vector. Where a ratio cannot be obtained because element(i-k) has invalid index, the result should be NA. The desired output is like this, where I specified k=1:
[[1]]
[1] NA
[[2]]
[1] NA
[[3]]
[1] NA (37/47) (42/37) (41/42)
[[4]]
[1] NA (39/41) (64/39) (54/64)
[[5]]
[1] NA (22/45) (23/22)
as for k=2:
[[1]]
[1] NA
[[2]]
[1] NA
[[3]]
[1] NA NA (42/47) (41/37)
[[4]]
[1] NA NA (64/41) (54/39)
[[5]]
[1] NA NA (23/45)
I have little clue on how to approach this, I would think to perform some loops, but in R, it seems complicated. Please advice.
Upvotes: 1
Views: 1868
Reputation: 887213
We loop through the list
elements (lapply(..
), if
the length
of the list
element is 1, we return 'NA' or else
divide the next value by the current value and concatenate with NA
. We convert to numeric
as the original list
elements were character
class.
lapply(df$lengths, function(x) if(length(x)==1) NA
else c(NA, as.numeric(x[-1])/as.numeric(x[-length(x)])))
We could use the lag/lead
function in dplyr/data.table
for k values greater than 1.
library(dplyr)
k <- 2
lapply(df$lengths, function(x) {x <- as.numeric(x)
if(length(x)==1) NA
else c(rep(NA,k), na.omit(lead(x,k)))/na.omit(lag(x,k))})
#[[1]]
#[1] NA
#[[2]]
#[1] NA
#[[3]]
#[1] NA NA 0.893617 1.108108
#[[4]]
#[1] NA NA 1.560976 1.384615
#[[5]]
#[1] NA NA 0.5111111
Or without using any packages, we can do with head/tail
functions
lapply(lst, function(x) {x <- as.numeric(x)
if(length(x)==1) NA
else c(rep(NA, k), tail(x, -k)/head(x,-k))})
Upvotes: 1