2015-09-16 48 views
4

這似乎是它應該很容易,但我無法找到答案:(data.table的每一行我想歸這樣的data_table的每一行:正常化中的R

normalize <- function(x) { 
    s = sum(x) 
    if (s>0) { 
    return(x/s) 
    } else { 
    return 0 
    } 
} 

如何在data.table的每一行調用這個函數並獲得一個標準化的data.table?我可以做一個for循環,但這肯定不是正確的方法,據我所知,apply(data, 1, normalize)將把我的data.table到矩陣,這將是一個巨大的性能打擊。

+0

另一個解讀是:「在這裏使用data.table而不是矩陣會帶來巨大的性能提升」(而不是認爲「apply」會帶來它)。下面最好的答案是'rowSums',它仍然會將它強制轉換爲矩陣。 – Frank

+0

@Frank公平點。我試圖在一大組非常大的矩陣上做這件事,並且將fread()用於data.table比其他任何事情都快得多,所以我希望我可以留在data.table'域'中這很快。你是說我可能只是轉換爲矩陣並運行上面的'apply'命令,因爲沒有更快的方法來實現這一點? – Stan

+0

是的,我想你可能會轉換爲矩陣,並且使用'rowSums'和其他函數(無論出於何種原因)比相應的'apply'方法更快。我可以想象'rowMeans'和'col'的相同,但也有其他的。如果他們不同意我的話,希望別人會加入進來。 – Frank

回答

2

這裏是爲了避免強迫到矩陣的一種方法:

cols = names(DT) 
DT[, s := Reduce("+",.SD)] 
DT[s >= 0, (cols) := lapply(.SD,"/",s), .SDcols = cols] 
DT[s < 0, (cols) := 0] 
DT[, s := NULL] 

這是什麼,如果有一個很好的理由,我會做在矩陣上使用data.table(在後面的步驟中)。

+1

謝謝,這很有幫助! – Stan

0

這是我想出的。首先你需要編輯你的函數(我相信),以便它返回rep(0, length(x))而不僅僅是0

set.seed(123); DT <- data.table(x=rnorm(1e3), y=rnorm(1e3), z=rnorm(1e3)) 
> DT 
       x   y   z 
    1: -0.56047565 -0.99579872 -0.5116037 
    2: -0.23017749 -1.03995504 0.2369379 
    3: 1.55870831 -0.01798024 -0.5415892 
    4: 0.07050839 -0.13217513 1.2192276 
    5: 0.12928774 -2.54934277 0.1741359 
    ---         
996: -0.08997520 0.07664366 1.0609662 
997: 1.07051604 0.25516476 -0.4455056 
998: -1.35110039 0.27744682 -0.4291802 
999: -0.52261670 0.53685602 1.1890118 
1000: -0.24919068 -0.46048557 0.8342941 
> DT[, c('x', 'y', 'z') := as.list(normalize(c(x, y, z))), by=1:nrow(DT)]                    
> DT 
       x   y   z 
    1: 0.00000000 0.00000000 0.0000000 
    2: 0.00000000 0.00000000 0.0000000 
    3: 1.56005167 -0.01799574 -0.5420559 
    4: 0.06091117 -0.11418417 1.0532730 
    5: 0.00000000 0.00000000 0.0000000 
    ---         
996: -0.08588413 0.07315877 1.0127254 
997: 1.21625341 0.28990225 -0.5061557 
998: 0.00000000 0.00000000 0.0000000 
999: -0.43433718 0.44617122 0.9881660 
1000: -1.99963905 -3.69518205 6.6948211 
0

可能有一個更容易(和更快)的方式來做到這一點與應用程序,但此方法的作品。我認爲它也更具可讀性,但這只是我的看法。

# Creating sample data. 
myDF <- data.frame(a = seq(1, 50), b = seq(1, 100, 2) , c = seq(1, 200, 4)) 
# Going through each row and dividing its contents by the sum of that row. 
for (row in rownames(myDF)) { myDF[row, ] <- myDF[row, ]/sum(myDF[row, ]) } 

請注意,這確實需要您的rownames是數字,但。

7

考慮這個例子的數據集(下一次,請提供示例數據集中自己)

set.seed(123) 
DT <- data.table(x = rnorm(10), y = rnorm(10), z = rnorm(10)) 

我會嘗試通過行操作,避免使用rowSums vecotrize,像下面

DT[, names(DT) := {temp = rowSums(.SD) ; (.SD/temp) * (temp > 0)}] 
DT 
#    x   y   z 
# 1: 0.0000000 0.0000000 0.0000000 
# 2: 0.0000000 0.0000000 0.0000000 
# 3: 1.6697906 0.4293327 -1.0991233 
# 4: 0.0000000 0.0000000 0.0000000 
# 5: 0.0000000 0.0000000 0.0000000 
# 6: 0.9447911 0.9843707 -0.9291618 
# 7: 0.2565558 0.2771142 0.4663301 
# 8: 0.0000000 0.0000000 0.0000000 
# 9: 0.0000000 0.0000000 0.0000000 
# 10: -1.3289000 -1.4097961 3.7386962 

我創建temp的原因是爲了避免兩次運行rowSums(.SD)*(temp > 0)部分基本上是您的ifelse聲明。它返回的TRUE/FALSE邏輯載體,然後轉化爲1/0然後乘以針對(.SD/temp)

+1

謝謝,這就像一個魅力! – Stan