2017-08-15 101 views
0

我的數據是這樣data.table:計算百分所有數值變量

set.seed(1) 
dt <- data.table(id = c("A", "A", "B", "B","C", "C"), 
      var1 = c(1:6), 
      var2 = rnorm(6)) 

> dt 
    id var1  var2 
1: A 1 -0.6264538 
2: A 2 0.1836433 
3: B 3 -0.8356286 
4: B 4 1.5952808 
5: C 5 0.3295078 
6: C 6 -0.8204684 

與幾十個數字變量的。我想使用data.table來計算每個觀測值和每個數值變量的百分位數,同時保持密鑰標識符(id)完好無損。在dplyr我能做到這一點是這樣的:

mutate_if(dt, is.numeric, function(x) { ecdf(x)(x) }) 

    id  var1  var2 
1 A 0.1666667 0.5000000 
2 A 0.3333333 0.6666667 
3 B 0.5000000 0.1666667 
4 B 0.6666667 1.0000000 
5 C 0.8333333 0.8333333 
6 C 1.0000000 0.3333333 

我也將是高興的結果,包括原var1var2

什麼是最好的方法來解決這個問題?

感謝您的幫助!

+1

沒有時間解釋,但是這應該給你想要的東西沒有ID列:'DT [,lapply(.SD,函數(X)ECDF(X)(X)) ,.SDcols = sapply(dt,is.numeric)]'。然後你可以在後面加上id列。 – jav

+0

嘗試mutate_at(dat,vars(starts_with(「var」)),function(x){ecdf(x)(x)})或mutate_if(dat,is.numeric,function(x){ecdf(x )(x)})' –

+0

@jav,有沒有一種方法在結果中保留'id'?由於某種原因,簡單的綁定給我的結果與原始數據相比是不準確的 –

回答

2

你可以計算ecdf所有數字列在這樣一個單獨的數據表:

dt2 = as.data.table(lapply(dt,function(x){if(is.numeric(x)){ecdf(x)(x)}})) 

結果:

> dt2 
     var1  var2 
1: 0.1666667 0.8333333 
2: 0.3333333 0.3333333 
3: 0.5000000 0.6666667 
4: 0.6666667 1.0000000 
5: 0.8333333 0.1666667 
6: 1.0000000 0.5000000 

如果你想cbind這個結果原來的DT,你可以使用paste0更改列名稱:

colnames(dt2) = paste0("centile_",colnames(dt2)) 

結果:

> dt2 
    centile_var1 centile_var2 
1: 0.1666667 0.8333333 
2: 0.3333333 0.3333333 
3: 0.5000000 0.6666667 
4: 0.6666667 1.0000000 
5: 0.8333333 0.1666667 
6: 1.0000000 0.5000000 
+0

謝謝!它幾乎正是我所需要的:你的結果不包含'id',如果我簡單地嘗試'cbind',它會得到與原始數據不同的結果。有沒有辦法將結果保留下來? –

+2

只需在末尾添加'else'語句:'as.data.table(lapply(dt,function(x){if(is.numeric(x)){ecdf(x)(x)} else x}) )'。 – lmo

+0

@lmo,謝謝你的幫助! –