2013-05-29 8 views
6

У меня есть два кадра данных:Количество матчей между двумя строками

df.1 <- data.frame(loc = c('A','B','C','C'), person = c(1,2,3,4), str = c("door/window/table", "window/table/toilet/vase ", "TV/remote/phone/window", "book/vase/car/chair")) 

Таким образом,

loc person        str 
1 A  1   door/window/table 
2 B  2 window/table/toilet/vase 
3 C  3 TV/remote/phone/window 
4 C  4  book/vase/car/chair 

И,

df.2 <- data.frame(loc = c('A','B','C'), str = c("book/chair/chair", " table/remote/vase ", "window")) 

, который дает,

loc      str 
1 A book/chair/car 
2 B table/remote/vase 
3 C     window 

Я хочу создать переменную df.1$percentage, которая вычисляет проценты элементов в df.1$str, которые находятся в df.2$strредактировать по LOC, или:

loc person        str percentage 
1 A  1   door/window/table  0.00 
2 B  2 window/table/toilet/vase  0.50 
3 C  3 TV/remote/phone/window  0.25 
4 C  4  book/vase/car/chair  0.00 

(1 имеет 0/3, 2 имеет 2/4 матчей, 3 имеет 1/4, а 4 имеет 0/4)

Спасибо!

+0

Соответствующие элементы должны иметь один и тот же локаль? – Edward

+0

Прости, да. строки соответствия, используя 'loc'. Я отредактировал вопрос. – Lucarno

ответ

4

Как вы знаете, data.frame столбцы могут также держат списки (см Create a data.frame where a column is a list). Таким образом, вы можете разделить ваш str в списки слов:

df.1 <- transform(df.1, words.1 = I(strsplit(as.character(str), "/"))) 
df.2 <- transform(df.2, words.2 = I(strsplit(as.character(str), "/"))) 

Затем объедините данные:

m <- merge(df.1, df.2, by = "loc") 

И просто вычислить процент использования mapply:

transform(m, percentage = mapply(function(x, y) sum(x%in%y)/length(x), 
           words.1, words.2)) 
4

Кто-то, вероятно, может придумать умнее решение, но вот простой подход:

library(data.table) 
dt1 = data.table(df.1, key = "loc") # set the key to match by loc 
dt2 = data.table(df.2) 

dt1[, percentage := dt1[dt2][, # merge 
      # clean up spaces and convert to strings 
      `:=`(str = gsub(" ", "", as.character(str)), 
       str.1 = gsub(" ", "", as.character(str.1)))][, 
      # calculate the percentage for each row 
      lapply(1:.N, function(i) { 
       tmp = strsplit(str, "/")[[i]]; 
       sum(tmp %in% strsplit(str.1, "/")[[i]])/length(tmp) 
      }) 
    ]] 

dt1 
# loc person        str percentage 
#1: A  1   door/window/table   0 
#2: B  2 window/table/toilet/vase   0.5 
#3: C  3 TV/remote/phone/window  0.25 
#4: C  4  book/vase/car/chair   0 
2

Альтернативный способ,

test <- data.frame(str1 = df.1[1:nrow(df.2),]$str, str2 = df.2$str) 
df.1$percent <- NA 
getwords <- function(x) { gsub(" ","",unlist(strsplit(as.character(x),"/"))) } 
percent <- function(x,y) { 
sum(!is.na(unlist(sapply(getwords(x), function (d) grep(d, getwords(y))))))/ 
length(getwords(x)) 
} 
df.1[1:nrow(df.2),]$percent <- apply(test, 1, function(x) percent(x[1],x[2])) 

> df.1 
     loc person        str percent 

# A  1   door/window/table 0.00 
# B  2 window/table/toilet/vase  0.50 
# C  3 TV/remote/phone/window 0.25 
# C  4  book/vase/car/chair  NA 
Смежные вопросы