Find mines in vector but not 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 find min in df line 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 lines containing sth greater than 0. how to do this by returning 0 if there is only 0 in the line (line 5) ??

+5
source share
3 answers

We can use apply with if/else

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

Or another version of 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 if/else within 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 
+4
source

I assume that since you are looking for values ​​above zero, all of your values are> = 0 and integers . That way, we could play with log conversion to convert all zeros to Inf and thus were always the largest. This will help us to avoid performing operations using the string, rather vectorize using minus functions of max.col

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

Here is another approach that dplyr and tidyr . A little longer than the answer from @akrun. But perhaps more readable without using 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) 
0
source

All Articles