2013-04-05 59 views
4

我最近一直在處理大得多的數據集,並開始學習並遷移到data.table以提高聚合/分組的性能​​。我一直無法按預期得到某些表達式或函數。以下是我遇到麻煩的基本操作組示例。返回向量的data.table聚合,如scale()

library(data.table) 
category <- rep(1:10, 10) 
value <- rnorm(100) 
df <- data.frame(category, value) 
dt <- data.table(df) 

如果我想簡單地按類別計算每個組的平均值。這工作很容易。

dt[,mean(value),by="category"] 

    category   V1 
1:  1 -0.67555478 
2:  2 -0.50438413 
3:  3 0.29093723 
4:  4 -0.41684790 
5:  5 0.33921764 
6:  6 0.01970997 
7:  7 -0.23684245 
8:  8 -0.04280998 
9:  9 0.01838804 
10:  10 0.44295978 

我遇到的問題,如果我嘗試使用規模功能,甚至一個簡單的表達減去自身的價值。分組被忽略,我得到應用到每一行的函數/表達式。以下內容按類別返回所有100行而不是10個組。

dt[,scale(value),by="category"] 


dt[,value-mean(value),by="category"] 

我認爲重新創建比例作爲返回數值向量而不是矩陣的函數可能會有所幫助。

zScore <- function(x) { 
    z=(x-mean(x,na.rm=TRUE))/sd(x,na.rm = TRUE) 
    return(z) 
} 

dt[,zScore(value),by="category"] 

    category   V1 
    1:  1 -1.45114132 
    2:  1 -0.35304528 
    3:  1 -0.94075418 
    4:  1 1.44454416 
    5:  1 1.39448268 
    6:  1 0.55366652 
    .... 
97:  10 -0.43190602 
98:  10 -0.25409244 
99:  10 0.35496694 
100:  10 0.57323480 
    category   V1 

這還返回應用於所有行(N = 100)的zScore函數並忽略分組。爲了在使用mean()時獲得scale()或自定義函數以使用上面的分組,我錯過了什麼?

+7

'mean'返回1個值。 'scale'函數爲每個輸入返回一個縮放值。也就是說,'scale(1:5)'給出了5個值。'平均(1:5)'給出1個值。這有助於理解你的問題嗎? – Arun 2013-04-05 14:30:18

+0

您應用於'分組的'變量的函數應返回1值而不是向量。 – 2013-04-05 14:45:28

+0

這正是問題所在。我正在嘗試使用ddply的方式使用data.table。我如何使用data.table來等價地實現以下內容。在ddply? 'ddply(df,「category」,transform,zscorebycategory = zScore(value))' – Aaron 2013-04-05 15:38:35

回答

1

你聲稱data.table不組是錯誤的:

library(data.table) 
category <- rep(1:2, each=4) 
value <- c(rep(c(1:2),each=2),rep(c(4,10),each=2)) 
dt <- data.table(category, value) 

    category value 
1:  1  1 
2:  1  1 
3:  1  2 
4:  1  2 
5:  2  4 
6:  2  4 
7:  2 10 
8:  2 10 

dt[,value-mean(value),by=category] 
    category V1 
1:  1 -0.5 
2:  1 -0.5 
3:  1 0.5 
4:  1 0.5 
5:  2 -3.0 
6:  2 -3.0 
7:  2 3.0 
8:  2 3.0 

如果要縮放/變換這正是你想要的行爲,因爲這些操作定義返回相同大小的物體作爲輸入。

2

你已經澄清了該評論認爲,你想相同的行爲:

ddply(df,"category",transform, zscorebycategory=zScore(value)) 

這給:

category  value zscorebycategory 
1   1 0.28860691  0.31565682 
2   1 1.17473759  1.33282374 
3   1 0.06395503  0.05778463 
4   1 1.37825487  1.56643607 
etc 

的你給的數據表選項給出:

 category   V1 
    1:  1 0.31565682 
    2:  1 1.33282374 
    3:  1 0.05778463 
    4:  1 1.56643607 
    etc 

這是完全一樣的數據。但是,您也想重複結果中的value列,並使用更具描述性的內容重命名V1變量。 data.table會爲您提供結果中的分組變量以及您提供的表達式的結果。因此,讓修改給你想要的行:

dt[,zScore(value),by="category"] 

變爲:

dt[,list(value=value, zscorebycategory=zScore(value)),by="category"] 

凡在列表中的命名項目成爲結果列。

plyr = data.table(ddply(df,"category",transform, zscorebycategory=zScore(value))) 
dt = dt[,list(value=value, zscorebycategory=zScore(value)),by="category"] 
identical(plyr, dt) 
> TRUE 

(注意我轉換了您ddply data.frame結果爲data.table,允許identical命令工作)。

+0

這很好。謝謝彼得。我還有其他無關的數據問題,這些問題緩解了我對data.table已經有限的理解。使用我基本生成的數據集進行配對,每個人的幫助都能澄清事情。 – Aaron 2013-04-05 16:23:47

+0

乾杯,@Aaron。雖然我認爲@羅蘭在問題中的回答評論:'dt [,zscorebycategory:= zScore(value),by = category]'可能會更有效率,因爲':='會更新現有的表,而我的答案會創建一個新的一個。 – 2013-04-05 17:09:58