Having the following vector:
t <- c(2, 6, 8, 20, 22, 30, 40, 45, 60)
I would like to find the values that fall between the following intervals:
g <- list(c(1,20), c(20, 40))
The desired output is:
1, 20 c(2, 6, 8)
20, 40 c(20, 22, 30)
Using the dplyr library, I do the following:
library(dplyr)
for(i in t){
for(h in g){
if(between(i, h[[1]], h[[2]])==TRUE){print(c(i, h[[1]], h[[2]]))}
}}
Is there a better way of doing this in R?
We can loop over the list 'g' and extract the 't' elements based on the first and second values by creating a logical vector with >/< and extract the elements of 't'
lapply(g, function(x) t[t >= x[1] & t < x[2]])
-output
[[1]]
[1] 2 6 8
[[2]]
[1] 20 22 30
library(purrr)
library(dplyr)
map(g,~keep(t,between(t,.[1],.[2])))
[[1]]
[1] 2 6 8 20
[[2]]
[1] 20 22 30 40
You may find findInterval() from base R useful:
g <- c(1, 20, 40)
t <- c(2, 6, 8, 20, 22, 30, 40, 45, 60)
findInterval(t, g)
#> [1] 1 1 1 2 2 2 3 3 3
So t[1], t[2] and t[3] are in the first interval, t[4], t[5] and
t[6] in the second, and t[7], t[8] and t[9] the third (meaning that
these values are bigger than the right end point of the second interval.)
If you had values lower than one they would be labelled by 0:
t2 <- c(-1, 0, 2, 6, 8, 20, 22, 30, 40, 45, 60)
findInterval(t2, g)
#> [1] 0 0 1 1 1 2 2 2 3 3 3
You can save the result of findInterval() as e.g. y and use which(y==1) to find which entries correspond to the first interval.
We can try cut + is.na like below
lapply(
g,
function(x) {
t[!is.na(cut(t, x, include.lowest = TRUE))]
}
)
which gives
[[1]]
[1] 2 6 8 20
[[2]]
[1] 20 22 30 40
Related
I need to create the following sequence:
> A
1, 2, 3, 11, 12, 13, 21, 22, 23, 31, 32, 33
> B
-1, 2, -3, 4, -5, 6, -7, 8, -9, 10
I've tried to use seq() function like this:
seq(1:3, 31:33, by = 10)
But it only allows to input 1 number in "from" and "to"
Maybe, someone knows how to use this or other functions to create the given sequence. Thank you in advance.
You can use :
A <- c(sapply(seq(0, 30, 10), `+`, 1:3))
A
#[1] 1 2 3 11 12 13 21 22 23 31 32 33
B <- 1:10 * c(-1, 1)
B
#[1] -1 2 -3 4 -5 6 -7 8 -9 10
Here's one way to get to A:
A <- rep(1:3, 3) + rep(c(0, 10, 20), each=3)
or to generalize to n
A <- rep(1:n, n) + rep(seq(0, by=10, length.out=n), each=n)
For B, I can't find anything truly elegant:
B <- 1:10 * (-1)^(1:10 %% 2)
That's the best I got
I have a vector v like:
v <- c(1, 2, 46, 6, 3, 5, 67, 2, ..., 9)
I want to add the numbers three by three, so I would have the results of adding 1+6+67...
Thank you!
I would suggest creating a sequence by the width you want (in this case 3) which will start from 1 to the length of your vector and then sum:
#Data
v <- c(1, 2, 46, 6, 3, 5, 67, 2, 9)
#Seq
seqv <- seq(1,length(v),by = 3)
#Sum
sum(v[seqv])
Output:
[1] 74
You could create a sequence of values by three and use that to index the vector v and then sum the result.
v <- 10:19
s <- seq(1,9, by=3)
> v
[1] 10 11 12 13 14 15 16 17 18 19
> s
[1] 1 4 7
> sum(v[s])
[1] 39
I have two list of numbers like below.
x <- c(1, 5, 10, 17, 21, 30)
y <- c(2, 7, 19)
In my dataset, x divides 1 to 30 in different segments (from 1-5, 5-10, 10-17, 17-21, 21-30). Would it be possible to match these segments to numbers in y? (In this case, I'd want to get c(1,5,17) as an output because 2 is between 1 and 5, 7 is between 5 and 10, and 19 is in between 17 and 21.)
?findInterval to the rescue:
x[findInterval(y,x)]
#[1] 1 5 17
Using cut is another option
cut(y, breaks = x, labels = x[-length(x)])
#[1] 1 5 17
Could be also done with labels = FALSE
x[cut(y, breaks = x, labels = FALSE)]
#[1] 1 5 17
You can do this with sapply and a simple function
sapply(y, function(a) x[max(which(x<a))])
[1] 1 5 17
I apologize for the poor phrasing of this question, I am still a beginner in R and I am still getting used to the proper terminology. I have provided sample data below:
mydata <- data.frame(x = c(1, 2, 7, 19, 45), y=c(10, 12, 15, 19, 24))
View(mydata)
My intention is to find the x speed, and for this I would need to find the difference between 1 and 2, 2 and 7, 7 and 19, and so on. How would I do this?
You can use the diff function.
> diffs <- as.data.frame(diff(as.matrix(mydata)))
> diffs
x y
1 1 2
2 5 3
3 12 4
4 26 5
> mean(diffs$x)
[1] 11
You can use dplyr::lead() and dplyr::lag() depending on how you want the calculations to line up
library(dplyr)
mydata <- data.frame(x = c(1, 2, 7, 19, 45), y=c(10, 12, 15, 19, 24))
View(mydata)
mydata %>%
mutate(x_speed_diff_lead = lead(x) - x
, x_speed_diff_lag = x - lag(x))
# x y x_speed_diff_lead x_speed_diff_lag
# 1 1 10 1 NA
# 2 2 12 5 1
# 3 7 15 12 5
# 4 19 19 26 12
# 5 45 24 NA 26
Say I have a matrix of 5 x 100 of numbers between 0 and 100 for instance:
1 5 10 15 3
2 15 3 8 27
1 22 34 45 35
28 27 32 3 8
......
I would like to find repeated "patterns" of numbers (mainly couples or triplets).
So in my example I would have the couple 3,15 appearing twice and the triplet 3, 8, 27 also appearing twice (I don't care about the order).
How would you implement that in R?
I would like to have couples and triplets separately and have their count.
thanks
nico
Here is one way. For each row of your 100-row matrix, you find all pairs/triples of numbers (using combn ) and do a frequency-count (using table) of the pairs/triples. The pasteSort function I defined creates a string out of a vector after sorting it. We apply this function to each pair/tuple in each row, and collect all pairs/tuples from the matrix before doing the frequency-count. Note that if a pair repeats on the same row, it's counted as a "repeat".
> mtx <- matrix( c(1,5,10,15,3,
2, 15, 3, 8, 27,
1, 22, 34, 45, 35,
28, 27, 32, 3, 8), ncol=5, byrow=TRUE)
> pasteSort <- function( x ) do.call(paste, as.list( sort( x) ) )
> pairs <- c( apply(mtx, 1, function(row) apply( combn(row, 2), 2, pasteSort)) )
> pairFreqs <- table(pairs)
> pairFreqs[ pairFreqs > 1 ]
3 15 3 27 3 8 8 27
2 2 2 2
> triples <- c( apply(mtx, 1, function(row) apply( combn(row, 3), 2, pasteSort)) )
> tripleFreqs <- table( triples )
> tripleFreqs[ tripleFreqs > 1 ]
3 8 27
2