Отфильтровывать строки с определенным значением для каждого столбца выборки

#r #dplyr

#r #dplyr

Вопрос:

Сохраняйте строки (Obs), значение Obs которых превышает пороговое значение выборки, ПО КРАЙНЕЙ МЕРЕ, В ТРЕХ ВЫБОРКАХ. Удалите строки, содержащие 2 или менее.

т.е..

  • Obs 1 имеет только S5 выше порогового значения, поэтому будет отфильтрован;
  • Obs2 имеет 4, а Obs 3 имеет 3, поэтому они останутся в df.

.

 df <- data.frame(column=c("threshold", "Obs1", "Obs2", "Obs3"), S1 = c(1.7,1.4,1.9,1.3), S2= c(0.9,0.8,2,1), S3=c(2.5,2.4,2.1,0.5), S4=c(0.4,0.5,0.6,0.9), S5=c(1.2,1.4,1.3,1.6))
 df

    column      S1  S2  S3  S4  S5
    threshold  1.7 0.9 2.5 0.4 1.2 
    Obs1       1.4 0.8 2.4 0.5 1.4 
    Obs2       1.9 2.0 2.1 0.6 1.3
    Obs3       1.3 1.0 0.5 0.9 1.6
  

Желаемый результат:

 column      S1  S2  S3  S4  S5
 
Obs2       1.9 2.0 2.1 0.6 1.3
Obs3       1.3 1.0 0.5 0.9 1.6
  

Я не знаю, как это закодировать, но мне интересно, использует ли какая-то логика, подобная этой:

 logic <- if df (S1-5)>= threshold value then =1; if df (S1-5) < threhold then = 0 

library(dplyr)
logic  %>% rowwise %%
    filter(sum(c_across(where(is.numeric))) >= 3) %>%
    ungroup
  

Комментарии:

1. Первая строка df, называемая «пороговым значением», включает пороговое значение для каждого столбца

Ответ №1:

Если мы используем rowwise with c_across , только slice строки без строки «порог», а затем выполните сравнение > с соответствующим slice общим набором данных с «пороговыми» строками

 library(dplyr)
df %>% 
    slice(-1) %>% 
    rowwise %>%
    filter(sum(c_across(where(is.numeric)) 
                > 
                  (df %>% 
                      slice(1) %>%
                   select(-1))) >=3) %>%
    ungroup
  

-вывод

 # A tibble: 2 x 6
#  column    S1    S2    S3    S4    S5
#  <chr>  <dbl> <dbl> <dbl> <dbl> <dbl>
#1 Obs2     1.9     2   2.1   0.6   1.3
#2 Obs3     1.3     1   0.5   0.9   1.6
  

Если есть и другие символьные столбцы, мы можем изменить select данные для подмножества

 df  %>% 
   slice(-1) %>%
   rowwise %>% 
   filter(sum(c_across(where(is.numeric)) > df %>%
             slice(1) %>%
             select(where(is.numeric))) >=3)
  

Или другой вариант с map

 library(purrr)
library(magrittr)
i1 <- map(df %>%
              select(where(is.numeric)),  ~ .x[-1] >  first(.x)) %>% 
        reduce(` `) %>% 
        is_greater_than(2)
df %>% 
     slice(-1) %>% 
     filter(i1)
  

Или base R с помощью rowSums

 df[-1,][rowSums(df[-1, -1] > df[1, -1][col(df[-1, -1])]) >=3,]
#  column  S1 S2  S3  S4  S5
#3   Obs2 1.9  2 2.1 0.6 1.3
#4   Obs3 1.3  1 0.5 0.9 1.6
  

Комментарии:

1. Спасибо, все они работают, но я бы тоже хотел их понять. Для опции (1- dplyr) какая функция устанавливает значение «больше, чем значение»?; для опции (2-map ) означает ли значение is_greater_than(2 ) больше значения в строке 2? для (3-base) где вы говорите «дайте значение 1, если оно больше порогового значения?. Извините за много вопросов, но я хотел бы учиться! Спасибо @akrun

2. @Ecg Для варианта 1 мы сначала устанавливаем подмножества строк, потому что это по строкам. Таким образом, строка с пороговыми данными строки передается непосредственно внутрь, чтобы выполнить соответствующее > с c_across помощью, т.е. ( df %>% slice(1) %>% select(-1)) и пороговое значение выполняется >=3 . Во втором случае мы перебираем числовые столбцы с map помощью подмножества первого элемента и проводим сравнение с остальными, создаем индекс (‘i1’) и используем его для подмножества строк.

3. Отлично, спасибо, внимательно прочитайте и постарайтесь понять. !

4. Я нахожу, что код с моими данными не работает, потому что мои «пороговые значения» являются десятичными, тогда как другие значения — нет. ТАКИМ образом, код не будет работать с чем-то вроде этого: < df1 <- data.frame(column=c(«threshold», «Obs1», «Obs2», «Obs3»), S1 = c(1.7,1,2,2), S2= c(1.3,0,0,3), S3=c(0.5,1,1,2), S4=c(1.2,1,2,2), S5=c(1.6,3,1,2)) > могу ли я отменить тот факт, что пороговые значения являются десятичными?

5. @Ecg Не ясно, когда вы говорите, что он не работает. Я попробовал ваш пример, и он работает для меня

Ответ №2:

Для дальнейшего использования: если вы работаете со столбцами, которые являются символьными, вам необходимо убедиться, что столбцы со значениями являются числовыми, если нет, преобразуйте их

 df <- type.convert(df, as.is = TRUE) 
  

и тогда это должно сработать

 df2 <- df %>% slice(-1) %>% rowwise %>% filter(sum(c_across(where(is.numeric)) > (df %>%slice(1))) >=3)