2015-12-01 45 views
1

我有一些具有非常不同範圍的功能的分組數據。我想按組標準化每個功能。另外,我想對任意大的特徵選擇(由名稱提供,例如下面的standardise.vars)。在R中做這件事的最好方法是什麼?使用R按組標準化/美白/重新縮放數據

我的做法至今在下面的例子愚蠢給出:

DT <- data.table(mtcars) 
group.vars <- c('cyl', 'am') 
setkeyv(DT, group.vars) 
standardise.vars <- c('disp','hp') 
mns <- DT[, lapply(.SD, mean), .SDcols = standardise.cols, by = group.vars] 
sds <- DT[, lapply(.SD, sd), .SDcols = standardise.cols, by = group.vars] 
merged <- merge(mns, sds, suffixes = c('.mean', '.sd')) 
DT[merged, ] 

這讓我以他們的手段和印刷旁邊標準差我規範化列。我現在需要對所有列x執行操作(x - x.mean)/x.std

 mpg cyl disp hp drat wt qsec vs am gear carb disp.mean hp.mean disp.sd hp.sd 
1: 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2 135.8667 84.66667 13.969371 19.65536 
2: 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2 135.8667 84.66667 13.969371 19.65536 
3: 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1 135.8667 84.66667 13.969371 19.65536 
... 

不過,我覺得這是一個不錯的辦法,而且我可以在一個步驟都實現了標準化。任何幫助,指向我的誤用data.table,或可能使用dplyr非常讚賞。

這種方法使用scale接近,但它不是一個很好的格式(從大約scale原因錯誤移除list(...)):

DT[, list(disp.scaled = list(scale(disp)), 
    hp.scaled = list(scale(hp))), by = .(cyl,am)] 

    cyl am              disp.scaled 
1: 4 0         0.7755062, 0.3531536,-1.1286597 
2: 4 1 0.7026252,-0.7282640,-0.8747715,-1.0994162,-0.7136133, 1.3033057, 
3: 6 0       1.1946100, 0.4570585,-0.8258343,-0.8258343 
4: 6 1         0.5773503, 0.5773503,-1.1547005 
5: 8 0 0.0331832, 0.0331832,-1.1391352,-1.1391352,-1.1391352, 1.5925615, 
6: 8 1            0.7071068,-0.7071068 
                  hp.scaled 
1:         -1.1532051, 0.5257259, 0.6274793 
2: 0.4910526,-0.7007155,-1.3186693,-0.7448550,-0.7007155, 0.4027735, 
3:      -0.5719714,-1.1167062, 0.8443388, 0.8443388 
4:         -0.5773503,-0.5773503, 1.1547005 
5: -0.5745432, 1.5237884,-0.4246623,-0.4246623,-0.4246623, 0.3247418, 
6:            -0.7071068, 0.7071068 

而且這種方法使用dplyr是非常接近,但在做一些奇怪的與group_by_(其與group_by作品):

ans <- DT %>% group_by(cyl, am) %>% 
    mutate_each_(funs(scale), standardise.vars) 
ans2 <- DT %>% group_by_(group.vars) %>% 
    mutate_each_(funs(scale), standardise.vars) 
truth <- filter(DT,am==0,cyl==4) %>% 
    transmute((disp - mean(disp))/sd(disp)) 
cbind(DT[,.(cyl,am,disp)], ans[,disp], ans2[,disp], truth)[1:3] 

    cyl am disp   V2  V3 (disp - mean(disp))/sd(disp) 
1: 4 0 146.7 0.7755062 1.546750     0.7755062 
2: 4 0 140.8 0.3531536 1.327187     0.3531536 
3: 4 0 120.1 -1.1286597 0.556857     -1.1286597 
+0

是的,但我可以將這個應用到列表的列表中嗎? – kungfujam

+0

道歉,如果我在這裏有點密集,但我看不到在lapply或scale中按組進行操作的選項。你介意在下面的答案中擴展你的解決方案嗎? – kungfujam

+0

我已經在上面添加了一個說明,如果有幫助的話。 – kungfujam

回答

2

說,我們希望通過在GROU變量以規範standardise.vars變量p通過group.vars定義:

DT <- data.table(mtcars) 
group.vars <- c('cyl', 'am') 
standardise.vars <- c('disp','hp') 

我覺得這個解決方案與dplyr解決它:

DT <- DT %>% group_by_(.dots=group.vars) %>% 
    mutate_each_(funs(scale), standardise.vars) 

以及物品是否完整,您可以通過data.table這樣做:

myscale <- function(x){ 
    (x - mean(x))/sd(x) 
} 
DT[, standardise.vars := lapply(.SD, myscale), .SDcols = standardise.vars, 
    by = group.vars, with = FALSE]