Perulangan dengan filter (dplyr) melalui beberapa kolom dengan beberapa nilai untuk dicocokkan

Saya memiliki kumpulan data berikut, 'data':

       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  

Setiap baris mewakili sebuah kasus dan setiap kolom mewakili atribut kode untuk kasus tersebut, dimana setiap kasus dapat memiliki beberapa kode atau tidak ada kode sama sekali. Tidak ada kasus yang dapat memiliki banyak contoh kode yang sama.

Yang juga penting adalah setiap kode dapat terdiri dari 3 atau 4 digit dan kode 4 digit tersebut merupakan turunan dari kode 3 digit tersebut. Misalnya, '123' merupakan kode yang lebih luas daripada '1234'; '4' menunjukkan jenis kode '123' yang lebih spesifik.

Fungsi asli saya untuk menarik kasus yang memiliki kode '1234' tadi

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

, tetapi pernyataan tersebut mencoba untuk mengevaluasi dengan pernyataan & daripada pernyataan OR, bukan itu yang saya cari.

Jadi saat ini saya memfilter seperti ini:

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

yang berfungsi dengan baik untuk satu kode tertentu, tetapi jumlah pengetikan jika saya ingin memfilter lebih banyak kode akan menjadi penghalang.

Pada akhirnya, yang ingin saya lakukan adalah menanyakan semua kolom A1:A5 untuk setiap kasus yang memiliki kode yang cocok dengan nilai apa pun dalam rentang tersebut

123:150

or

1230:1500

, karena menanyakan kedua rentang ini akan mengembalikan saya kasus yang cocok dengan kode induk dan kode anak mana pun.


person Makaira Murakami    schedule 12.12.2014    source sumber


Jawaban (2)


Anda dapat mencoba sesuatu seperti:

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

Jika Anda melakukannya untuk contoh yang Anda berikan (hanya menggunakan 1234 sebagai nilai yang akan diperiksa) maka akan menghasilkan apa yang Anda tampilkan di atas:

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

Fungsi bagian dalam menghasilkan data.frame nilai logis:

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

Yang mana (hampir) sama dengan saat menggunakan 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

Dan kemudian Anda menggunakan rowSums untuk memeriksa setiap baris apakah setidaknya satu nilai BENAR untuk membuat subset data yang sesuai.

person talat    schedule 12.12.2014

Saya pikir ini adalah masalah format data, jadi pertama-tama mari kita masukkan data ke dalam format yang benar:'

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

Sekarang Anda dapat menjalankan filter hanya pada satu kolom:

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

Untuk mendapatkan rentang kode Anda, ini akan berfungsi:

filter(newdf, code > 122 & code < 151)
person Nick DiQuattro    schedule 12.12.2014
comment
Ace, tahu tentang reshape2::melt() tapi tidak tidyr::gather(). Terima kasih. - person James Owers; 11.12.2015