2014-03-07 90 views
2

使用for循環說我有一個查找表如下查找表與任意長度查詢而不中的R

dt <- data.frame(name=c("jack","jill","sam","dan"),age=c(20,14,28,13)) 

    name age 
1 jack 20 
2 jill 14 
3 sam 28 
4 dan 13 

現在我想以下矢量轉換成包含每個元素的年齡的矢量。

query1 <- c("jack","dan") 
query2 <- c("sam") 
query3 <- c("jack","sam", "dan") 

我可以建立下面的函數(我不喜歡)來完成這一任務,

get.age <- function(x) { 

    answer <- list() 
    for(i in 1:length(x)){ 
    answer[[i]]<- dt[dt$name==x[i],"age"] 
    } 
    ldply(answer)$V1 
} 

它得到這樣

> get.age(query1) 
[1] 20 13 
> get.age(query2) 
[1] 28 
> get.age(query3) 
[1] 20 28 13 

但是,我做的工作不喜歡解決方案,因爲它使用for循環和一些骯髒的黑客。理想情況下,我會想這樣做R-喜歡使用矢量操作這樣的(這似乎不工作)更

> dt[dt$name==c("jack","dan"),"age"] 
[1] 20 13 #worked 
> dt[dt$name==c("jack","sam"),"age"] 
[1] 20 # not the right answer 

以下解決方案的工作,但這需要我多少事情查找的先驗知識。

dt [dt $ name ==「jack」| DT $名稱==「山姆」,「年齡」]

[1] 20 28 

我想知道,可以處理的關鍵元素轉換,而無需使用for循環載體的任意大小的方法,如果有任何

+0

類似於:http://stackoverflow.com/questions/4135102/looking-up-values-in-r – Tyler

回答

3

對於真正的查找表,結果應該是查詢的長度,並且還處理查詢中的複製。使用match(...)的方法是這樣做的唯一的:

query4 <- c("jack","sam", "dan","sam","jack") 
dt[match(query4,dt$name),]$age 
# [1] 20 28 13 28 20 

這是因爲match(LHS,RHS)返回其包含匹配LHS的相應元件所述的RHS行數長度(左軸)的整數向量。

基於比較(==)的方法通常不起作用。這是因爲,當比較兩個向量時,R會嘗試複製較短的一個,但需要很多次才能使其長度與較長的長度相同,然後進行逐個元素的比較。因此,例如在dt$name==query1的情況下,RHS被重複兩次,並且比較結果在c("jack","jill","sam","dan")c("jack","dan","jack","dan")之間。

dt$name==query1 # RHS is: c("jack","dan","jack","dan") 
# [1] TRUE FALSE FALSE TRUE 
dt$name==query2 # RHS is: c("sam","sam","sam","sam") 
# [1] FALSE FALSE TRUE FALSE 
dt$name==query3 # RHS is: c("jack","sam", "dan","jack") with warning 
# [1] TRUE FALSE FALSE FALSE 
# with warning: longer object length is not a multiple of shorter object length 

在另一方面,使用LHS %in% RHS給出了長度(左軸)的結果和T或華氏度,這取決於該元素是否存在於RHS。

dt$name %in% query1 
# [1] TRUE FALSE FALSE TRUE 
query1 %in% dt$name 
# [1] TRUE TRUE 

注意,它看起來像df$name %in% query1df$name==query1給出相同的結果,但是這是query1神器後者比較被複制兩次。參見,例如:

dt$name %in% query3 
# [1] TRUE FALSE TRUE TRUE 
dt$name == query3 
# [1] TRUE FALSE FALSE FALSE 
3

你想要%的%,它返回用於子集的數據幀的邏輯載體

dt[dt$name %in% query3,"age"] 
+1

爲什麼這個得到downvoted?它到底是什麼,他是問對於 – JeremyS

2

有很多方法可以做到這一點,但我會扔出來一個我找到有用的。 match()@jlhoward's answer進一步詳細說明了我之前的==示例錯誤的原因。

> match(query1, dt$name) #these give us the index of the *first* matching value 
[1] 1 4 
> match(query2, dt$name) 
[1] 3 

> dt$age[match(query1, dt$name)] 
[1] 20 13 
> dt$age[match(query2, dt$name)] 
[1] 28 

您還可以使用%in%不像match這個返回存在於比較的元素TRUEFALSE(一定要拿到訂單正確的,dt$name %in% query1回報TRUE FALSE FALSE TRUEquery1 %in% dt$name回報TRUE TRUE

> dt[dt$name %in% query1, ][,'age',] 
[1] 20 13 

With dplyr您可以使用filter

> require(dplyr) 
> filter(dt, name %in% query1) 
    name age 
1 jack 20 
2 dan 13 
> filter(dt, name %in% query1)$age 
[1] 20 13 
+0

當我嘗試它'dt $ name == query1'和'query1 == dt $ name'返回相同的東西。 – jlhoward

+0

@jlhoward oops,你是對的。正如你指出的那樣,我正在考慮百分之%並寫作== ==(這是錯誤的)。 – Tyler