Piecewise Function Help in R - r

For a class I must create a piecewise function defined in the following way:
2x-2 , x < -1
0 , -1 <= X <= 1
x^(2)-1, x > 1
I have tried an ifelse sequence but I cant seem to make it work. I've also tried an if, elseif, else sequence, but that only seems to use the first function to calculate answers.
The end goal is to have this:
pwfun(c(-2, 0.5, 3))
2 0 8

A piece-wise function like below?
pwfun <- function(x) ifelse(x < -1, 2 * x - 2, ifelse(x <= 1, 0, x**2 - 1))
such that
> pwfun(c(-2, 0.5, 3))
[1] -6 0 8

pwfun <- function(x) ifelse(x < -1, (x * x) -2, ifelse(x <= 1, 0, x**2 - 1))
> pwfun(c(-2, 0.5, 3))
[1] -2 0 8
The above edit to ThomasIsCoding's answer gives you what you want, but I would use this approach because it communicates it's intent better:
library(dplyr)
df <- data.frame(x = c(-2, 0.5, 3))
pwfunc <- function(data){
data %>%
mutate(y =
case_when(x < -1 ~ -2,
x > 0 & x <= 1 ~ 0,
TRUE ~ x**2 - 1)) ## TRUE in a case_when basically
## means "everything that isnt caught by my specified conditions
## becomes..." so it works like the "else" clause
}
Then just call the function on your data:
df <- data.frame(x = c(-2, 0.5, 3))
pwfunc(data)
And get:

Related

judge the values crossing zero

I would like to determine whether or not the ranges of min and max values cross zero (0 = crossing zero, 1 = not crossing zero).
min <- c(0, -1, -1, 1, 1)
max <- c(1, 1, -0.1, 3, 1.5)
answer <- c(0, 0, 1, 1, 1)
data <- cbind(min,max, answer)
You can use the between function from dplyr:
library(dplyr)
min <- c(0, -1, -1, 1, 1)
max <- c(1, 1, -0.1, 3, 1.5)
df1 = data.frame(min,max) %>%
rowwise() %>%
mutate(answer = as.numeric(!between(0,min,max)))
Or using base R:
df1 = data.frame(min,max)
df1$answer = apply(df1, 1, function(x) as.numeric(!(x[1]<= 0 & x[2] >=0)))
Base R vectorised answer -
transform(data, answer = as.integer(!(min <= 0 & max > 0)))
# min max answer
#1 0 1.0 0
#2 -1 1.0 0
#3 -1 -0.1 1
#4 1 3.0 1
#5 1 1.5 1
If you prefer dplyr the same can be written as -
library(dplyr)
data %>% mutate(answer = as.integer(!(min <= 0 & max > 0)))
data
min <- c(0, -1, -1, 1, 1)
max <- c(1, 1, -0.1, 3, 1.5)
data <- data.frame(min,max)
You can simply multiply them, as to cross you either need a negative product or one being zero.
answer <- ifelse(min * max <= 0, 0, 1)
or
answer <- as.integer(min * max > 0)
# [1] 0 0 1 1 1
If your 0 and 1 are not a requirement, even shorter to get a TRUE or FALSE
answer <- min * max <= 0
# [1] TRUE TRUE FALSE FALSE FALSE

Turning sequences into plots in R

Say I have some sequence consisting of 2 numbers:
seq <- c(0, 1, 1, 1, 0, 0)
Assume I'd want to plot this into a graph in the following way:
My graph (x, y) starts in (0, 0) and has one straight line to (1, 0).
Then, the sequence comes in action:
If the number is a 0, I turn left with 1 coordinate, if the number is a 1, I turn right with 1 coordinate.
So for the example sequence, I start with:
(0, 0) -> (1, 0) -> (1, 1) -> (1, 2) -> (1, 1) -> (1, 0) etc.
It's better to draw this if you want a good idea of what I mean with turning left and right.
How would I get these points into a plot? Any tips?
Plot example of the sequence:
x = c(0, 1, 1, 1, 0, 0)
m = cbind(x = c(0, 1),
y = c(0, 0))
flag_xy = 1 #Track whether to add to x- or y- coordinate
for (i in x){
flag_direction = diff(tail(m, 2)) #Track which way the line is facing
if (i == 0){
if (flag_xy == 1){
m = rbind(m, tail(m, 1) + c(0, flag_direction[,1] * 1))
} else{
m = rbind(m, tail(m, 1) + c(flag_direction[,2] * -1, 0))
}
flag_xy = flag_xy * -1
} else{
if (flag_xy == 1){
m = rbind(m, tail(m, 1) + c(0, flag_direction[,1] * -1))
} else{
m = rbind(m, tail(m, 1) + c(flag_direction[,2]* 1, 0))
}
flag_xy = flag_xy * -1
}
}
graphics.off()
plot(m, asp = 1)
lines(m)
m
# x y
# 0 0
# 1 0
#[2,] 1 1
#[2,] 2 1
#[2,] 2 0
#[2,] 1 0
#[2,] 1 -1
#[2,] 2 -1

Combined subsetting in R?

I trying to subset 3 ys for when xs are -1, 0, and 1 in my code below. But I was hoping to do this all at once using y[c(x == -1, x == 0, x == 1)] which apparently does not work (see below).
Any better way to do this subsetting all at once?
x = seq(-1, 1, l = 1e4)
y = dcauchy(x, 0, sqrt(2)/2)
y[c(x == -1, x == 0, x == 1)] ## This subsetting format doesn't work
We can do this.
y[x == -1| x == 0| x == 1]
Or this
y[x %in% c(-1, 0, 1)]

ifelse function in r not giving proper output [duplicate]

I am attempting to assign a number from 1 through 10 to a series of vectors based on what quantile they're in in a dataframe.
So far I have tried
quants <- quantile(Data$Avg, c(.1, .2, .3, .4, .5, .6, .7, .8, .9))
Data$quant <- for ( i in nrow(Data) ) {
ifelse(Data$Avg [i] < quants[1], Data$quant[1] = 1 ,
ifelse(Data$Avg [i] > quants[1] & Data$Avg[i] < quants[2], Data$quant[1] = 2, Data$quant = 3
))}
I get the following mistake:
Can anyone spot the mistake I am making here?
You might be better off using cut rather than a loop:
Data = data.frame(Avg = runif(100))
quantpoints <- seq(0.1, 0.9, 0.1)
quants <- quantile(Data$Avg, quantpoints)
cutpoints <- c(-Inf, quants, Inf)
cut(Data$Avg, breaks = cutpoints, labels = seq(1, length(cutpoints) - 1))
This should work:
Data$quant <- for ( i in nrow(Data) ) {
Data$quant[1] <- ifelse(Data$Avg [i] < quants[1], 1, ifelse(Data$Avg [i] > quants[1] & Data$Avg[i] < quants[2], 2, 3))
}
Or equivalently (inside the for loop):
if(Data$Avg [i] < quants[1])
Data$quant[1] <- 1
else{
if(Data$Avg [i] > quants[1] & Data$Avg[i] < quants[2])
Data$quant[1] <- 2
else
Data$quant[1] <- 3
}
You should assign the output of ifelse conditions outside of it. That is:
output <- ifelse(a > b, a, b)

Buy Low Sell High

I've a data like this:
library("xts")
close <- c(0, -0.5, -0.75, -1, -0.75, -1.5, -2, -2.5, -3, -3.5, -3, -2.5, -2, -1, 0, 1, 1.5, 2, 2.5, 3, 2.5, 2, 0)
data <- xts(close, Sys.Date()-23:1)
colnames(data) <- "close"
I'd like to generate another column which will give me a trade signal based on the logic below:
Buy when the close is # or below -1, -2 and -3.
Sell all the 3 when close is # or above 0.
Short Sell when the close is # or above 1, 2 and 3
Buy all the 3 when close is # or below 0.
For this i've tried
data$trade <- 0
data$trade[data$close <= -1] <- 1
data$trade[data$close <= -2] <- 2
data$trade[data$close <= -3] <- 3
data$trade[data$close >= 1] <- -1
data$trade[data$close >= 2] <- -2
data$trade[data$close >= 3] <- -3
data trade column is giving me (0,0,0,1,0,1,2,2,,3,3,3,2,2,1,0,-1,-1,-2,-2,-3,-2,-2,0)
but i want that it should give me ((0,0,0,1,1,1,2,2,3,3,3,3,3,3,0,-1,-1,-2,-2,-3,-3,-3,0)
i want that when i buy # say -1 or -2 the trade signal should be on till we reach 0 or above and similarly when we short sell it # say -1, -2 etc the trade signal should be on till we reach 0 or below. Kindly help i've tried lots of combinations, but not getting the required result.
If I've understood correctly, this is hard to do efficiently because the choice depends upon the past. It's not elegant but this code gives the output you require,
library("xts")
close <- c(0, -0.5, -0.75, -1, -0.75, -1.5, -2, -2.5, -3, -3.5, -3, -2.5, -2, -1, 0, 1, 1.5, 2, 2.5, 3, 2.5, 2, 0)
data <- xts(close, Sys.Date()-23:1)
colnames(data) <- "close"
sig.buy <- c(F,F,F)
sig.short <- c(F,F,F)
for(i in 1:length(data))
{
if(data$close[i] <= -1) sig.buy[1] <- T
if(data$close[i] <= -2) sig.buy[2] <- T
if(data$close[i] <= -3) sig.buy[3] <- T
if(sig.buy[1] && data$close[i] >= 0) sig.buy[1] <- F
if(sig.buy[2] && data$close[i] >= 0) sig.buy[2] <- F
if(sig.buy[3] && data$close[i] >= 0) sig.buy[3] <- F
if(data$close[i] >= 1) sig.short[1] <- T
if(data$close[i] >= 2) sig.short[2] <- T
if(data$close[i] >= 3) sig.short[3] <- T
if(sig.short[1] && data$close[i] <= 0) sig.short[1] <- F
if(sig.short[2] && data$close[i] <= 0) sig.short[2] <- F
if(sig.short[3] && data$close[i] <= 0) sig.short[3] <- F
data$trade[i] <- sum(sig.buy) - sum(sig.short)
}

Resources