2014-04-08 16 views
15

Tôi có một dataframe,chuỗi động vật phù hợp với từng phần trong R

d<-data.frame(name=c("brown cat", "blue cat", "big lion", "tall tiger", 
        "black panther", "short cat", "red bird", 
        "short bird stuffed", "big eagle", "bad sparrow", 
        "dog fish", "head dog", "brown yorkie", 
        "lab short bulldog"), label=1:14) 

Tôi muốn tìm kiếm trên cột name và nếu những lời "mèo", "sư tử", "con hổ", và "con beo "xuất hiện, tôi muốn gán chuỗi ký tự feline cho cột mới và hàng tương ứng species.

Nếu những lời "bird", "eagle", and "sparrow" xuất hiện, tôi muốn gán chuỗi ký tự avian đến một cột mới và hàng species tương ứng.

Nếu từ "chó", "yorkie" và "bulldog" xuất hiện, tôi muốn gán chuỗi ký tự canine cho cột mới và hàng tương ứng species. Lý tưởng nhất, tôi sẽ lưu trữ nó trong một danh sách hoặc một cái gì đó tương tự mà tôi có thể giữ ở đầu của kịch bản, bởi vì như là các biến thể mới của các loài hiển thị trong thể loại tên, nó sẽ được tốt đẹp để có thể truy cập dễ dàng để cập nhật những gì đủ điều kiện là feline, aviancanine.

Câu hỏi này gần như được trả lời ở đây (How to create new column in dataframe based on partial string matching other column in R), nhưng không giải quyết được sự biến đổi nhiều tên hiện diện trong vấn đề này.

Trả lời

26

Có thể có giải pháp thanh lịch hơn thế này, nhưng bạn có thể sử dụng grep với | để chỉ định các kết quả trùng khớp thay thế.

d[grep("cat|lion|tiger|panther", d$name), "species"] <- "feline" 
d[grep("bird|eagle|sparrow", d$name), "species"] <- "avian" 
d[grep("dog|yorkie", d$name), "species"] <- "canine" 

Tôi cho rằng bạn có nghĩa là "chim" và bị bỏ rơi "bulldog" vì nó chứa "chó".

Bạn có thể muốn thêm ignore.case = TRUE vào grep.

đầu ra:

#     name label species 
#1   brown cat  1 feline 
#2   blue cat  2 feline 
#3   big lion  3 feline 
#4   tall tiger  4 feline 
#5  black panther  5 feline 
#6   short cat  6 feline 
#7   red bird  7 avian 
#8 short bird stuffed  8 avian 
#9   big eagle  9 avian 
#10  bad sparrow 10 avian 
#11   dog fish 11 canine 
#12   head dog 12 canine 
#13  brown yorkie 13 canine 
#14 lab short bulldog 14 canine 
2

Một cách thanh lịch-ish để làm điều này (tôi nói tao nhã-ish bởi vì, trong khi đó là cách thanh lịch nhất mà tôi biết, nó không phải là vĩ đại) là một cái gì đó như:

#Define the regexes at the beginning of the code 
regexes <- list(c("(cat|lion|tiger|panther)","feline"), 
       c("(bird|eagle|sparrow)","avian"), 
       c("(dog|yorkie|bulldog)","canine")) 

.... 


#Create a vector, the same length as the df 
output_vector <- character(nrow(d)) 

#For each regex.. 
for(i in seq_along(regexes)){ 

    #Grep through d$name, and when you find matches, insert the relevant 'tag' into 
    #The output vector 
    output_vector[grepl(x = d$name, pattern = regexes[[i]][1])] <- regexes[[i]][2] 

} 

#Insert that now-filled output vector into the dataframe 
d$species <- output_vector 

Ưu điểm của phương pháp này được nhiều lần

  1. Bạn chỉ phải thay đổi khung dữ liệu một lần trong toàn bộ quá trình, trong đó tăng tốc độ vòng lặp (khung dữ liệu không có sửa đổi tại chỗ; để sửa đổi một khung dữ liệu 3 lần, về cơ bản bạn đang relabelling và tái tạo nó 3 lần).
  2. Bằng cách xác định độ dài của véc tơ, vì chúng ta biết nó sẽ là gì, bạn tăng tốc độ thậm chí nhiều hơn bằng cách đảm bảo rằng vector đầu ra không bao giờ cần thêm bộ nhớ được phân bổ sau khi nó được tạo.
  3. Vì đó là vòng lặp, thay vì lặp lại, cuộc gọi thủ công, việc thêm nhiều hàng và danh mục vào đối tượng 'regexes' sẽ không yêu cầu sửa đổi thêm mã. Nó sẽ chạy như hiện nay.

Điểm bất lợi duy nhất - và điều này áp dụng, tôi nghĩ rằng hầu hết các giải pháp bạn có thể nhận được là nếu có gì đó khớp với nhiều mẫu, mẫu cuối cùng trong danh sách sẽ khớp với thẻ 'loài' .

+0

điểm tốt về việc liệu có thể có nhiều kết quả trùng khớp hay không. @ Brocolli-Rob: có thể có một cột TRUE/FALSE cho mỗi loài sẽ là phương pháp tốt hơn nếu tình huống này có khả năng trong tập dữ liệu của bạn. – ping

Các vấn đề liên quan