Map numbers to smallest in a vector of numbers in R - r

Given a vector of numbers, I'd like to map each to the smallest in a separate vector that the number does not exceed. For example:
# Given these
v1 <- 1:10
v2 <- c(2, 5, 11)
# I'd like to return
result <- c(2, 2, 5, 5, 5, 11, 11, 11, 11, 11)

Try
cut(v1, c(0, v2), labels = v2)
[1] 2 2 5 5 5 11 11 11 11 11
Levels: 2 5 11
which can be converted to a numeric vector using as.numeric(as.character(...)).

Another way (Thanks for the edit #Ananda)
v2[findInterval(v1, v2 + 1) + 1]
# [1] 2 2 5 5 5 11 11 11 11 11]

Related

How do I operate basic functions within a column in R?

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

Multiply each element of a special column of a data frame with the corresponding elements of other columns of the data frame

I have a data frame df with four columns; three integer columns and a special column containing a list:
df <- data.frame(w= 1:3, x=3:5, y=6:8, z = I(list(1:2, 1:3, 1:4)))
> df
w x y z
1 1 3 6 1, 2
2 2 4 7 1, 2, 3
3 3 5 8 1, 2, 3, 4
>class(df$z)
[1] "AsIs"
I want to transform each element of the column df["z"] by separately multiplying it with the corresponding element (same row number) of each of the other columns (df["w"], df["x"], df["y"]) of the same data frame df.
I have found the possibility of using Map("*", df$z, df$x), but it can only perform the required multiplication with one other column at a time. My data set is too large to let me perform the multiplication in such small steps.
> Map("*", df$z, df$x)
[[1]]
[1] 3 6
[[2]]
[1] 4 8 12
[[3]]
[1] 5 10 15 20
Can anyone please provide a hint on how to multiply df["z"] with each of the other columns at once while preserving the data frame structure?
I expect the output to be a data frame df1 with column names w,x,y.
>df1
w x y
1 2 3 6 6 12
2 4 6 4 8 12 7 14 21
3 6 9 12 5 10 15 20 8 16 24 32
Thank you.
We can use transmute_at
library(tidyverse)
df %>%
transmute_at(vars(w, x, y), funs(map2(z, ., `*`)))
# w x y
#1 1, 2 3, 6 6, 12
#2 2, 4, 6 4, 8, 12 7, 14, 21
#3 3, 6, 9, 12 5, 10, 15, 20 8, 16, 24, 32
Or as #Ryan mentioned if there are more columns and the multiplier list column is single, we can use one_of within transmute_at to select other columns except the 'z'
df %>%
transmute_at(vars(-one_of('z')), funs(map2(z, .,`*`)))

Consecutive Sum of a Vector

This is a question following a previous one. In that question, it is suggested to use rollapply to calculate sum of the 1st, 2nd, 3rd entry of a vector; then 2nd, 3rd, 4th; and so on.
My question is how calculate sum of the 1st, 2nd and 3rd; then the 4th, 5th and 6th. That is, rolling without overlapping. Can this be easily done, please?
Same idea. You just need to specify the by argument. Default is 1.
x <-c(1, 5, 4, 5, 7, 8, 9, 2, 1)
zoo::rollapply(x, 3, by = 3, sum)
#[1] 10 20 12
#or another Base R option
sapply(split(x, ceiling(seq_along(x)/3)), sum)
# 1 2 3
#10 20 12
Using tapply in base R:
set.seed(1)
vec <- sample(10, 20, replace = TRUE)
#[1] 3 4 6 10 3 9 10 7 7 1 3 2 7 4 8 5 8 10 4 8
unname(tapply(vec, (seq_along(vec)-1) %/% 3, sum))
# [1] 13 22 24 6 19 23 12
Alternatively,
colSums(matrix(vec[1:(ceiling(length(vec)/3)*3)], nrow = 3), na.rm = TRUE)
#[1] 13 22 24 6 19 23 12
vec[1:(ceiling(length(vec)/3)*3)] fills in the vector with NA if the length is not divisible by 3. Then, you simply ignore NAs in colSums.
Yet another one using cut and aggregate:
x <- ceiling(length(vec)/3)*3
df <- data.frame(vec=vec[1:x], col=cut(1:x, breaks = seq(0,x,3)))
aggregate(vec~col, df, sum, na.rm = TRUE)[[2]]
#[1] 13 22 24 6 19 23 12
We can use roll_sum from RcppRoll which would be very efficient
library(RcppRoll)
roll_sum(x, n=3)[c(TRUE, FALSE, FALSE)]
#[1] 10 20 12
data
x <-c(1, 5, 4, 5, 7, 8, 9, 2, 1)
you can define the window size, and do:
x <-c(1, 5, 4, 5, 7, 8, 9, 2, 1)
n <- 3
diff(c(0, cumsum(x)[slice.index(x, 1)%%n == 0]))
p.s. using the input from the answer by #Sotos

how to get index of sorted array elements

Say I have an array in R : c(10, 7, 4, 3, 8, 2)
Upon sorting, this would be : c(2, 3, 4, 7, 8, 10)
What is the best way in R to return the indices for the sorted array elements from the original array. I'm looking for an output like :
6(index of 2), 4(index of 3), 3(index of 4), 2(index of 7), 5(index of 8), 1(index of 10)
The function you're looking for is order:
> x
[1] 10 7 4 3 8 2
> order(x)
[1] 6 4 3 2 5 1
sort has index.return argument, which by default is FALSE
x <- c(10,7,4,3,8,2)
sort(x, index.return=TRUE) #returns a list with `sorted values`
#and `$ix` as index.
#$x
#[1] 2 3 4 7 8 10
#$ix
#[1] 6 4 3 2 5 1
You can extract the index by
sort(x, index.return=TRUE)$ix
#[1] 6 4 3 2 5 1

Extract a numeric vector from data frame in R

I have a data.frame like following example. I want to write a function to do these two tasks for me in one function in R? first extract the value of data frame which is same for x and y and I want to save it as a numeric vector and also make the rest as a data frame.
d = data.frame(x = c(1,7, 2, 9, 11),y=c(6, 7, 8, 9,10))
v = c(7, 9)
w = data.frame(x=c(1, 2, 11), y=c(6, 8, 10))
My desire result as follows:
> result
$v
[1] 7 9
$w
x y
1 1 6
2 2 8
3 11 10
Maybe with is what you want?
with(d, list(v = x[x==y] ,w=d[x!=y,]))
$v
[1] 7 9
$w
x y
1 1 6
3 2 8
5 11 10
Something along these lines should do this too
splitdf <- function(df) {
if (ncol(df) != 2) stop("df must have 2 columns")
ind <- do.call("==", df)
list(v = df[ind, 1], w = df[!ind, ])
}
d <- data.frame(x = c(1, 7, 2, 9, 11), y = c(6, 7, 8, 9, 10))
splitdf(d)
## $v
## [1] 7 9
## $w
## x y
## 1 1 6
## 3 2 8
## 5 11 10
df <- data.frame(x = c(1, 7, 2, 9, 11), z = c(7, 8, 10, 9, 12))
splitdf(df)
## $v
## [1] 9
## $w
## x z
## 1 1 7
## 2 7 8
## 3 2 10
## 5 11 12

Resources