Цикл с фильтром (dplyr) по нескольким столбцам с несколькими значениями для соответствия

У меня есть следующий набор данных, «данные»:

       A1    A2    A3    A4    A5   
case1  1234  2234  223   4455  7334
case2  1254  2234  200   
case3  1234  9234  
case4  1274  5234  228   4655  2534
case5  1234  2634  273   7455  

Каждая строка представляет случай, а каждый столбец представляет атрибут кода для этого случая, где каждый случай может иметь несколько кодов или вообще не иметь кодов. Ни один случай не может иметь несколько экземпляров одного и того же кода.

Также важно то, что каждый код может состоять из 3 или 4 цифр, а 4-значные коды являются потомками 3-значных кодов. Например, «123» будет более широким кодом, чем «1234»; «4» указывает на более конкретный тип кода «123».

Моя первоначальная функция для извлечения ящиков с кодом «1234» была

dataf <- filter(data, A1:A5 == 1234)

, но оператор попытался выполнить оператор &, а не оператор ИЛИ, а это не то, что я ищу.

Итак, в настоящее время я фильтрую так:

dataf <- filter(data, A1 == 1234 | A2 == 1234 | A3 == 1234 | A4 == 1234 | A5 == 1234)

который отлично работает для одного конкретного кода, но количество ввода, если бы я хотел отфильтровать больше кодов, было бы непомерно высоким.

В конечном счете, я хотел бы запросить все столбцы A1: A5 для любых случаев, которые имеют коды, соответствующие любым значениям в диапазонах.

123:150

or

1230:1500

, так как запрос обоих этих диапазонов вернет мне случаи, которые соответствуют любым экземплярам как родительских кодов, так и дочерних кодов.


person Makaira Murakami    schedule 12.12.2014    source источник


Ответы (2)


Вы можете попробовать что-то вроде:

x <- c(123:150, 1230:1500)
filter(df, rowSums(mutate_each(df, funs(. %in% x))) >= 1L)
#   case   A1   A2  A3   A4   A5
#1 case1 1234 2234 223 4455 7334
#2 case2 1254 2234 200   NA   NA
#3 case3 1234 9234  NA   NA   NA
#4 case4 1274 5234 228 4655 2534
#5 case5 1234 2634 273 7455   NA

Если вы сделаете это для приведенного вами примера (используя только 1234 в качестве значения для проверки), это приведет к тому, что вы показали выше:

filter(df, rowSums(mutate_each(df, funs(. %in% 1234))) >= 1L)
#   case   A1   A2  A3   A4   A5
#1 case1 1234 2234 223 4455 7334
#2 case3 1234 9234  NA   NA   NA
#3 case5 1234 2634 273 7455   NA

Внутренняя функция создает data.frame логических значений:

mutate_each(df, funs(. %in% x))
#   case   A1    A2    A3    A4    A5
#1 FALSE TRUE FALSE FALSE FALSE FALSE
#2 FALSE TRUE FALSE FALSE FALSE FALSE
#3 FALSE TRUE FALSE FALSE FALSE FALSE
#4 FALSE TRUE FALSE FALSE FALSE FALSE
#5 FALSE TRUE FALSE FALSE FALSE FALSE

Что (почти) так же, как при использовании sapply

sapply(df, function(.) . %in% x)
#      case   A1    A2    A3    A4    A5
#[1,] FALSE TRUE FALSE FALSE FALSE FALSE
#[2,] FALSE TRUE FALSE FALSE FALSE FALSE
#[3,] FALSE TRUE FALSE FALSE FALSE FALSE
#[4,] FALSE TRUE FALSE FALSE FALSE FALSE
#[5,] FALSE TRUE FALSE FALSE FALSE FALSE

И затем вы используете rowSums, чтобы проверить для каждой строки, является ли хотя бы одно значение TRUE для соответствующего подмножества данных.

person talat    schedule 12.12.2014

Я думаю, что это проблема формата данных, поэтому сначала давайте приведем данные в правильный формат:

df <- read.table(text = '       A1    A2    A3    A4    A5   
case1  1234  2234  223   4455  7334
case2  1254  2234  200   NA    NA
case3  1234  9234  NA    NA    NA
case4  1274  5234  228   4655  2534
case5  1234  2634  273   7455  NA')

library(dplyr)
library(tidyr)
newdf <- df %>%
          mutate(case = rownames(df)) %>%
          gather(Anum, code, -case)

> head(newdf)
#   case Anum code
#1 case1   A1 1234
#2 case2   A1 1254
#3 case3   A1 1234
#4 case4   A1 1274
#5 case5   A1 1234
#6 case1   A2 2234

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

filtdf <- filter(newdf, code == 1234)
#  case Anum code
#1 case1   A1 1234
#2 case3   A1 1234
#3 case5   A1 1234

Чтобы получить диапазон кодов, это должно работать:

filter(newdf, code > 122 & code < 151)
person Nick DiQuattro    schedule 12.12.2014
comment
Эйс знал о reshape2::melt(), но не знал о tidyr::gather(). Спасибо. - person James Owers; 11.12.2015