Suppose x is a real number, or a vector. i is valued-False. Then x[i] will return numeric(0). I would like to treat this as a real number 0, or integer 0, which are both fit for addition.
numeric(0) added to any real number will return numeric(0), whereas I wish to obtain the real number being added as the result. What can I do to convert the numeric (0) value? Thanks in advance!
It is only when we do the +, it is a problem. This can be avoided if we use sum
sum(numeric(0), 5)
#[1] 5
sum(numeric(0), 5, 10)
#[1] 15
Or if we need to use +, an easy option is to concatenate with 0, select the first element. If the element is numeric(0), that gets replaced by 0, for other cases, the first element remain intact
c(numeric(0), 0)[1]
#[1] 0
Using a small example
lst1 <- list(1, 3, numeric(0), 4, numeric(0))
out <- 0
for(i in seq_along(lst1)) {
out <- out + c(lst1[[i]], 0)[1]
}
out
#[1] 8
You can use max/min with 0 to get 0 as output when input is numeric(0).
x <- 1:10
max(x[FALSE], 0)
#[1] 0
min(x[FALSE], 0)
#[1] 0
Related
Let's say we have a few vectors containing some numeric data.
For example:
vect1<- c(0, 0, 0, 60, 40, 80, 0)
vect2<- c(100, 0, 0, 80, 40)
vect3<- c(0,0,1,2,3)
I would like to count the number of "leading zeros" in this vector... so In this case I would like to have a value of 3 returned for vect1, a value of 0 returned for vect2, and a value of 2 returned for vect3. How would I go about implementing this in R?
Thanks in advance!
You can use a simple for loop with a counter here.
counter <- 0
for (i in vect){
if (i == 0){
counter<-counter+1
} else {
break()
}
print(counter)
You could easily wrap this in a function for reuse and just replace the print with return.
There are several ways to do this. One option is to get the cumulative sum where the vector is not 0, then, convert it to a logical and get the sum
f1 <- function(x) sum(cumsum(x != 0) == 0)
-testing
> f1(vect1)
[1] 3
> f1(vect2)
[1] 0
> f1(vect3)
[1] 2
Or may also use rle
f2 <- function(x) with(rle(x == 0), lengths[1][values[1]][1])
For time series analysis I handle data that often contains leading and trailing zero elements. In this example, there are 3 zeros at the beginning an 2 at the end. I want to get rid of these elements, and filter for the contents in the middle (that also may contain zeros)
vec <- c(0, 0, 0, 1, 2, 0, 3, 4, 0, 0)
I did this by looping from the beginning and end, and masking out the unwanted elements.
mask <- rep(TRUE, length(vec))
# from begin
i <- 1
while(vec[i] == 0 && i <= length(vec)) {
mask[i] <- FALSE
i <- i+1
}
# from end
i <- length(vec)
while(i >= 1 && vec[i] == 0) {
mask[i] <- FALSE
i <- i-1
}
cleanvec <- vec[mask]
cleanvec
[1] 1 2 0 3 4
This works, but I wonder if there is a more efficient way to do this, avoiding the loops.
vec[ min(which(vec != 0)) : max(which(vec != 0)) ]
Basically the which(vec != 0) part gives the positions of the numbers that are different from 0, and then you take the min and max of them.
We could use the range and Reduce to get the sequence
vec[Reduce(`:`, range(which(vec != 0)))]
#[1] 1 2 0 3 4
Take the cumsum forward and backward of abs(vec) and keep only elements > 0. if it were known that all elements of vec were non-negative, as in the question, then we could optionally omit abs.
vec[cumsum(abs(vec)) > 0 & rev(cumsum(rev(abs(vec)))) > 0]
## [1] 1 2 0 3 4
I have a data.frame column with hourly values and want to count all negative values, if they are in a sequence of at least six consecutive negatives.
Example:
df <- data.frame(Values=c(-2, 2, 3, 4,-1,-1,-2,-3,
-1,-1,-1, 5, 4, 2,-4,-2,
-3,-4,-1, 3, 4, 4,-3,-1,
-2,-2,-3,-4))
The expected result would be 13, since the middle sequence of consecutive negatives contains only five negatives and is thus not counted.
You could use the base function rle() along with sign(). The sign() function converts negatives and positives to -1 and 1, respectively. This makes a nice vector to pass to rle() to get the run-lengths. Then we can subset the run-lengths with the desired condition and take the sum.
with(rle(sign(df$Values)), sum(lengths[lengths >= 6 & values < 0]))
# [1] 13
Try:
library(cgwtools)
res <- seqle(which(df<0))
sum(res$lengths[res$lengths>=6])
[1] 13
you can always define your own function and call it.
NegativeValues <- function(x) {
count <- 0
innercount <- 0
for (i in c(x, 0)) {
if (i < 0) {
innercount <- innercount + 1
}
else {
if (innercount >= 6)
count <- count + innercount
innercount <- 0
}
}
return(count)
}
NegativeValues(df$Values)
Suppose I have a vector, say:
x <- c(1, 0, 1, 0, 0, 0, 1, 1, 0, 0,1,1,1,1,0,1,1,0,1,0,0,0,0,0,1,0,1,0,1,0)
and I would like to obtain a vector that sums the values that falls between two zeros, i.e. the output should look like:
y = c(1,2,4,1,1,1)
Note that all ones should have zero at the beginning and zero at the end, otherwise it will not be counted. so the string 01010 only produce 1.
I tried to use run length with an index of zeros.
Thanks in Advance
sum.between.zeroes <- function(x) {
library(stringr)
x.str <- paste(x, collapse = "")
nchar(str_extract_all(x.str, "01+0")[[1]]) - 2L
}
sum.between.zeroes(c(1,0,1,0,0,0,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,0,1,0,1,0,1,0))
# [1] 1 2 4 1 1 1
sum.between.zeroes(c(0,1,0,1,0))
# [1] 1
sum.between.zeroes(c(1,1))
# integer(0)
If you want to remain within the base package, you can use gregexpr and regmatches:
sum.between.zeroes <- function(x) {
x.str <- paste(x, collapse = "")
nchar(regmatches(x.str, gregexpr("01+0", x.str))[[1]]) - 2L
}
I have a numeric vector in R, which consists of both negative and positive numbers. I want to separate the numbers in the list based on sign (ignoring zero for now), into two seperate lists:
a new vector containing only the negative numbers
another vector containing only the positive numbers
The documentation shows how to do this for selecting rows/columns/cells in a dataframe - but this dosen't work with vectors AFAICT.
How can it be done (without a for loop)?
It is done very easily (added check for NaN):
d <- c(1, -1, 3, -2, 0, NaN)
positives <- d[d>0 & !is.nan(d)]
negatives <- d[d<0 & !is.nan(d)]
If you want exclude both NA and NaN, is.na() returns true for both:
d <- c(1, -1, 3, -2, 0, NaN, NA)
positives <- d[d>0 & !is.na(d)]
negatives <- d[d<0 & !is.na(d)]
It can be done by using "square brackets".
A new vector is created which contains those values which are greater than zero. Since a comparison operator is used, it will denote values in Boolean. Hence square brackets are used to get the exact numeric value.
d_vector<-(1,2,3,-1,-2,-3)
new_vector<-d_vector>0
pos_vector<-d_vector[new_vector]
new1_vector<-d_vector<0
neg_vector<-d_vector[new1_vector]
purrrpackage includes some useful functions for filtering vectors:
library(purrr)
test_vector <- c(-5, 7, 0, 5, -8, 12, 1, 2, 3, -1, -2, -3, NA, Inf, -Inf, NaN)
positive_vector <- keep(test_vector, function(x) x > 0)
positive_vector
# [1] 7 5 12 1 2 3 Inf
negative_vector <- keep(test_vector, function(x) x < 0)
negative_vector
# [1] -5 -8 -1 -2 -3 -Inf
You can use also discard function