Mateusz1981
Mateusz1981

Reputation: 1867

find the min in the vector but no 0

My df is like this

  df <- data.frame(t1 = c(10, 20, 30, 1, 0), t2 = c(30, 0, 40, 0, 0), t3 = c(10, 0, 3, 10, 0))

what I want to do is to find the min in the df row but not 0 I do

df<- df%>% rowwise() %>%
  do({
    th <- c(.$t1, .$t2, .$t3,)


    data.frame(., t_s_last = min(th[th > 0))
  })

but it works but not for the rows that contain sth more than 0. how to make this returning 0 if there are just 0 in the row (row 5)?

Upvotes: 5

Views: 675

Answers (3)

David Arenburg
David Arenburg

Reputation: 92282

I'm guessing that because you are looking for values above zero, all your values are >=0 and integers. Thus, we could play around with log transformation in order to convert all the zeroes to Inf and thus being always the largest. This will help us avoid running by row operations, rather vectorize using the minus of the max.col function

df[cbind(1:nrow(df), max.col(-abs(log(df))))]
## [1] 10 20  3  1  0

Upvotes: 4

davechilders
davechilders

Reputation: 9123

Here is another approach that uses dplyr and tidyr. A bit longer than answer from @akrun. But possibly more readable without the use of do:

library(dplyr)
library(tidyr)

df %>%
  mutate(id = row_number()) %>%
  gather(time, value, t1:t3) %>%
  group_by(id) %>%
  mutate(ts = ifelse(all(value == 0), 0, min(value[value != 0])))  %>%
  spread(time, value)

Upvotes: 0

akrun
akrun

Reputation: 886938

We can use apply with an if/else condition

 apply(df, 1, function(x) if(all(x==0)) 0 else min(x[x> 0]))

Or another option is rowMins from library(matrixStats). We replace the '0' values in the dataset with NA, use rowMins with na.rm=TRUE, and replace the 'Inf' values with 0.

 library(matrixStats)
 is.na(df) <- df==0
 v1 <- rowMins(as.matrix(df), na.rm=TRUE)
 v1[is.infinite(v1)] <- 0
 v1
 #[1] 10 20  3  1  0

We can also use the if/else within the do

library(dplyr)
df %>%
    rowwise() %>%
    do({th <- unlist(.[.>0])
       data.frame(., t_s_last = if(all(th==0)) 0 else min(th))})
#  t1 t2 t3 t_s_last
#1 10 30 10       10
#2 20  0  0       20
#3 30 40  3        3
#4  1  0 10        1
#5  0  0  0        0

Upvotes: 4

Related Questions