การวนซ้ำด้วยตัวกรอง (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)

แต่คำสั่งพยายามที่จะประเมินด้วยคำสั่ง & แทนที่จะเป็นคำสั่ง OR ซึ่งไม่ใช่สิ่งที่ฉันกำลังมองหา

ตอนนี้ฉันกำลังกรองดังนี้:

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