2014-03-19 44 views
2

我的測量data.table特定值(其通過柱會發生變化),每個列具有較低的檢測極限,(和可能的檢測上限)Data.table濾除在每列

set.seed(1) 
dt <- data.table(id=1:5, A=rnorm(5), B=rnorm(5, mean=2), C=rnorm(5,mean=-1)) 
setkey(dt, id) 
# "randomly" disperse upper an lower limits to measurement columns 
dt[3,A := -5] 
dt[2,B := -3] 
dt[5,B := 7] 
dt[1,C := -10] 
dt 
    id   A   B   C 
1: 1 -0.6264538 1.179532 -10.0000000 
2: 2 0.1836433 -3.000000 -0.6101568 
3: 3 -5.0000000 2.738325 -1.6212406 
4: 4 1.5952808 2.575781 -3.2146999 
5: 5 0.3295078 7.000000 0.1249309 

我要篩選(設置爲NA)出值的dt每一列,其完全匹配另一個data.table列出的下部和上部測量限制:

limits <- data.table(measurement=LETTERS[1:3], lower=c(-5,-3,-10), 
        upper=c(NA, 7, NA)) 
setkey(limits, measurement) 
limits 
    measurement lower upper 
1:   A -5 NA 
2:   B -3  7 
3:   C -10 NA 

我的預期輸出是:

dt 
    id   A  B   C 
1: 1 -0.6264538 1.179532   NA 
2: 2 0.1836433  NA -0.6101568 
3: 3   NA 2.738325 -1.6212406 
4: 4 1.5952808 2.575781 -3.2146999 
5: 5 0.3295078  NA 0.1249309 

我是不是能夠建立一個很好的解決方案,這一點,所以目前我使用的for循環clungy來完成這項工作:

for (i in 1:nrow(dt)) { 
    for (j in 2:ncol(dt)) { 
    if (is.na(dt[i, j, with=F])) { 
     next 
    } else if (dt[i, j, with=F] == limits[names(dt)[j]][, lower]) { 
     dt[i, j := NA_real_, with=F] 
    } else if (is.na(limits[names(dt)[j]][, upper])) { 
     next 
    } else if (dt[i, j, with=F] == limits[names(dt)[j]][, upper]) { 
     dt[i, j := NA_real_, with=F] 
    } else { 
     next 
    } 
    } 
} 

但必須有更好更快的東西?我有一個玩的apply荷蘭國際集團的limitsdata.tabledt每行每列,但沒有取得任何結果。

回答

6

首先,我要limiits data.table如下:

require(reshape2) 
require(data.table) 
limits = dcast.data.table(melt(limits, id=1), variable ~ measurement) 

# variable A B C 
# 1: lower -5 -3 -10 
# 2: upper NA 7 NA 

然後你就可以匹配相應的列i和使用set如下與NA取代那些比賽:

for (i in 2:ncol(dt)) { 
    set(dt, i=which(dt[[i]] %in% limits[[i]]), j=i, value=NA_real_) 
} 

# id   A  B   C 
# 1: 1 -0.6264538 1.179532   NA 
# 2: 2 0.1836433  NA -0.6101568 
# 3: 3   NA 2.738325 -1.6212406 
# 4: 4 1.5952808 2.575781 -3.2146999 
# 5: 5 0.3295078  NA 0.1249309 
2

下面是一個替代:

dt[, 2:length(dt) := lapply(
    2:length(dt), 
    function(x) ifelse(.SD[[x]] %in% limits[x - 1, c(lower, upper)], NA, .SD[[x]]) 
) ] 

由於limits你行以相同的順序列在dt,你可以通過列循環:

id   A  B   C 
1: 1 -0.6264538 1.179532   NA 
2: 2 0.1836433  NA -0.6101568 
3: 3   NA 2.738325 -1.6212406 
4: 4 1.5952808 2.575781 -3.2146999 
5: 5 0.3295078  NA 0.1249309 
+0

+1。唯一的區別是在這裏,整個列正在被重新創建。在'set',只是那些條目匹配被替換(柱子不會被複制)。在確認之前和之後執行'sapply(dt,address)'。 – Arun

+0

@Arun,並沒有意識到這一點微妙的集合。總是從你那裏學習新的東西。 – BrodieG

+0

高興:)。在這種情況下,對於'+ set'是偉大的,因爲否則使用':=',而不是做一個副本,你不得不做的事:'DT [,A:= NA]' - 重複的'B和C' 。表達式必須在'i'中,基本上這些位置被替換而不復制。有意義真的:)。 – Arun