2017-07-18 116 views
0

我有兩個數據幀stu1和stu2。兩者都有匹配的ID列,但在其他列中有不同的變量。r匹配兩個數據幀中的數據,然後檢查另一列中匹配行的文本

例如,stu1

ID, Grade, Group, Age 
ad1, A, Green, 14 
bc1, B, Green, 13 
cd1, B, Blue, 14 
fs3, C, Red, 13 

stu2

ID, Prog, Loc, Year 
bc1, LSC1, Ext, 2013 
cd1, LSC1, Ext, 2013 
cd1, BSC1, Int, 2013 
ad1, BSC2, Int, 2012 
rs2, KHL4, Ext, 2014 

我試圖做的是檢查stu1學生ID是否存在stu2然後檢查是否在另一個文本相應行的列匹配我的字符串,例如Prog =='BSC*'然後在stu1中創建一個新列,其中聲明「是」或「否」。

所以,stu1結果應該是:

ID, Grade, Group, Age, BSCProg 
ad1, A, Green, 14, Yes 
bc1, B, Green, 13, No 
cd1, B, Blue, 14, Yes 
fs3, C, Red, 13, No 

我已經嘗試了多種不同的方式失敗,例如:

stu1$BSCProg <- ifelse(stu2[grepl("BSC", stu2$Prog) & match(paste0(stu1$ID), 
    paste0(stu1$ID)),], "Yes", "No") 

stu1$BSCProg <- ifelse(is.na(match(paste0(stu1$ID), 
    paste0(stu2$ID) & stu2[grepl("BSC", stu2$Prog),])),"No","Yes") 

stu1$BSCProg <- ifelse(stu1$ID %in% stu2$ID & grepl('BSC', stu2$Prog), "Yes", "No") 

回答

4

我會做到這一點通過合併兩個表,這樣就可以做列的比較。使用data.table

library(data.table) 

setDT(stu1) 
setDT(stu2) 

dat <- merge(stu1, 
      stu2[Prog %like% "BSC", .(ID, BSCProg = Prog)], 
      by = "ID", 
      all.x = TRUE) 

dat[, BSCProg := ifelse(is.na(BSCProg), "No", "Yes")] 

結果:

#  ID Grade Group Age BSCProg 
# 1: ad1  A Green 14  Yes 
# 2: bc1  B Green 13  No 
# 3: cd1  B Blue 14  Yes 
# 4: fs3  C Red 13  No 

解包了一下,第一步是將IDProg列合併來自stu2stu1Prog %like% "BSC"部分將僅合併Prog列中包含「BSC」的那些行作爲值的一部分。 BSCProg = Prog是要將列重命名爲最終所需。

完成此操作後,該列的值將爲NA或值如BSC1,BSC2。最後的聲明BSCProg := ifelse(is.na(BSCProg), "No", "Yes")將把任何NA更改爲「否」並將其他任何內容更改爲「是」。

+1

簡單,並且爲'%like%'+1 +1! – juan

+0

謝謝!這非常快,非常有幫助!你太棒了:-) – Leila

+0

非常感謝!我現在被要求爲每個程序創建新的列。只有5個程序,所以我能夠複製和粘貼代碼來更改搜索並每次添加新列。除此之外,爲了提高我的R技能,是否有更簡單更清晰的方式來添加額外的列來搜索其他程序(LSC,BSC 1和2,KHL1:4)?我試着玩弄現有的建議,但都失敗了。 – Leila

1

您可以通過merge第一ID,然後創建新的專欄。這裏是一個data.table解決方案:

library(data.table) 
setDT(stu1, key="ID") 
setDT(stu2, key="ID") 
stu1 = merge(stu1, stu2, all.x=TRUE) 
stu1[, BSCProg:=ifelse(grepl("^BSC", Prog), "Yes", "No")] 
+1

與我的相似,也是我最初的做法。問題出現在'stu2'中,在ID列中有'cd1'的重複,所以在合併'stu1'獲得一行後,有兩個'BSCProg'值。 –

+0

好趕上!我應該嘗試一下示例數據! – juan

+0

謝謝你也試試這個!如果我必須將額外的行添加到原始數據中,這可能會有所幫助(尚未詢問,但如果出現這種情況,也不會感到驚訝!)。乾杯! – Leila

0

A dplyrtidyr解決方案。 stu3是最終輸出。

library(dplyr) 
library(tidyr) 

stu1 <- data_frame(ID = c("ad1", "bc1", "cd1", "fs3"), 
        Grade = c("A", "B", "B", "C"), 
        Group = c("Green", "Green", "Blue", "Red"), 
        Age = c(14, 13, 14, 13)) 

stu2 <- data_frame(ID = c("bc1", "cd1", "cd1", "ad1", "rs2"), 
        Prog = c("LSC1", "LSC1", "BSC1", "BSC2", "KHL4"), 
        Loc = c("Ext", "Ext", "Int", "Int", "Ext"), 
        Year = c(2013, 2013, 2013, 2012, 2014)) 


stu3 <- stu1 %>% 
    full_join(stu2 %>% select(ID, Prog), by = "ID") %>% 
    mutate(BSCProg = ifelse(grepl("BSC", Prog), "Yes", "No")) %>% 
    drop_na(Grade) %>% 
    select(-Prog) %>% 
    group_by(ID) %>% 
    arrange(desc(BSCProg)) %>% 
    slice(1) 
+0

''left_join'不會比'full_join'更好嗎? – CPak

+0

@ChiPak因爲'stu2'有重複的'ID',比如'cd1'。 'left_join'將會丟失那些重複的行。 – www

+0

'left_join(stu1,select(stu2,ID,Prog),by =「ID」)'保留'cd1'。無論如何,只是一個建議。 – CPak

相關問題