2015-08-31 2 views
5

Моего ДФА не нравится этанайти мин в векторе, но не 0

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

, что я хочу сделать, это найти min в df строки, но не 0 я

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


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

, но он работает, но не для строк, которые содержат sth больше 0. как сделать это возвратом 0, если в строке (строка 5) всего 0?

+0

А вы значение всегда целые числа> = 0? –

ответ

4

Мы можем использовать apply с if/else условием

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

Или другой вариант rowMins от library(matrixStats). Заменит значение '0' в наборе данных с NA, используйте rowMins с na.rm=TRUE и заменить ценности 'Inf' с 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 

Мы также можем использовать if/else в пределах 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 
+0

Большое спасибо. Мне нравится 'dplyr', поэтому я помечаю этот ответ – Mateusz1981

+0

@ Mateusz1981 Нет проблем. Рад помочь вам. – akrun

4

Я предполагаю, что, поскольку вы ищете значения выше нуля, все ваши значения are> = 0 и целые числа. Таким образом, мы могли бы сыграть с преобразованием журнала, чтобы преобразовать все нули в Inf и, таким образом, всегда быть самым большим. Это поможет нам избежать запуска операций ряда, а векторизации с использованием минуса max.col функции

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

, берущее абсолютное значение журнала, зачеркнет упорядочение - сравните 'abs (log (0.2))' vs 'abs (log (1.2))' – eddi

+0

@eddi, что истинно только для нецелых значений. Я отредактировал ответ –

+0

Не нужно быть целыми числами, просто не должно быть чисел от 0 до 1. Возможно, вы можете исправить с помощью smth, как 'log (df) + 1000' - я думаю, что он покрывает наименьшие числа R может представлять. – eddi

0

Вот другой подхода, который использует dplyr и tidyr. Немного длиннее ответа от @akrun. Но, возможно, более удобный для чтения без использования 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)