Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find the number of times row elements switch from negative to positive (cycles) for each factor level

Tags:

r

I want to calculate the number of times elements in my data frame go from <=0 to >0 for each factor/level.

A simple code to calculate the number of times the values switch sign is not sufficient, because I am interested in including values of 0. I also only want the number of times values go from <=0 to >0, and not include the number of times it goes from >0 to <=0. Anyone know a good way to approach this?

My data is set up as follows:

factor<-c(1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3)
value<-c(2,-1,0,-1,3,-1,0,-1,2,-1,4,5,-1,-1,2,2,-3,-2)

df <- cbind(factor,value)

I want a table with the factors and the number of cycles (times it goes from <=0 to >0) like this.

     factor cycles
[1,]      1      1
[2,]      2      2
[3,]      3      1
like image 249
Alyssa.r Avatar asked Aug 05 '19 21:08

Alyssa.r


3 Answers

Here's a simple approach in base R:

df <- data.frame(factor,value)
df$signish = value <= 0
foo = function(x) sum(x[-length(x)] > x[-1])

# use tapply or aggregate to apply the function by group
tapply(df$signish, df$factor, FUN = foo)
# 1 2 3 
# 1 2 1

aggregate(signish ~ factor, data = df, foo)
#   factor signish
# 1      1       1
# 2      2       2
# 3      3       1

Of course, you could use dplyr or data.table to easily do the grouped operation if you prefer.

like image 83
Gregor Thomas Avatar answered Oct 16 '22 08:10

Gregor Thomas


One possibility involving dplyr could be:

df %>%
 group_by(factor) %>%
 mutate(value = sign(value)) %>%
 summarise(value = sum(value == 1 & lag(value, default = first(value)) <= 0))

Or:

df %>%
 group_by(factor) %>%
 summarise(value = sum(diff(sign(value)) == 2))

The continuation of that idea with base R:

aggregate(value ~ factor, 
          FUN = function(x) sum(diff(sign(x)) == 2),
          data = df)

  factor value
   <dbl> <int>
1      1     1
2      2     2
3      3     1

Sample data:

df <- data.frame(factor, value,
                 stringsAsFactors = FALSE)
like image 21
tmfmnk Avatar answered Oct 16 '22 10:10

tmfmnk


Another option using base:

aggregate(val ~ fct, dat, function(x) sum(diff(x <= 0) < 0))

#   fct val
# 1   1   1
# 2   2   2
# 3   3   1


dat <- data.frame(
  fct = c(1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3),
  val = c(2, -1, 0, -1, 3, -1, 0, -1, 2, -1, 4, 5, -1, -1, 2, 2, -3, -2)
)
like image 3
utubun Avatar answered Oct 16 '22 08:10

utubun