2016-08-03 62 views
0

我的問題很簡單。我有一個數據框,每行有不同的數字,超過100列。第一列始終是非零數字。我想要做的是用行中的第一個數字(第一列的值)替換每行中的每個非零數字(第一列的值)用第一列中的值替換每行的值

我會在ifelse和for遍歷該行迭代但必須有做一個簡單的向量化方法...

+0

發表一個適合測試和演示的例子。 –

回答

1

另一種方法是使用sapply,這比循環更有效。假設你的數據在數據幀df

df[,-1] <- sapply(df[,-1], function(x) {ind <- which(x!=0); x[ind] = df[ind,1]; return(x)}) 

在這裏,我們應用function過每除了第一列的df所有列。在functionx是每個列的依次爲:

  1. 首先發現了在使用which零列的行索引。
  2. x中的這些行設置爲第一列df的行中的對應值。
  3. 返回列

注意的是,在功能操作都在列「量化」。也就是說,不在列的行上循環。 sapply的結果是已處理列的矩陣,它將替換不是第一列的所有列df

請參閱this瞭解*apply功能家族的優秀評論。

希望這會有所幫助。

+0

非常好。謝謝。出於好奇,我們不能用apply來做每行而不是每列嗎? –

+0

'apply'用於跨數組的某個維度應用函數。看到[這個SO回答](http://stackoverflow.com/questions/3505701/r-grouping-functions-sapply-vs-lapply-vs-apply-vs-tapply-vs-by-vs-aggrega)爲好審查'應用'功能家族。 – aichao

+0

看起來像這樣不會做我想要的,但它只是一個改變哪個= 0的情況。請記住,我想將所有** nonzeros **更改爲每行的第一個數字。從我的iPad發佈,所以沒有嘗試它 –

1

既然你的數據本來就不大,我建議你使用一個簡單的循環

for (i in 1:nrow(mydata)) 
{ 
for (j in 2:ncol(mydata) 
    { 

    mydata[i,j]<- ifelse(mydata[i,j]==0 ,0 ,mydata[i,1]) 
    } 
} 
+0

謝謝你的回答。但是數據集實際上非常大,我正在尋找一種更加矢量化的方法。同樣在你的解決方案中,第一列數據也不會被替換?我需要第一列保持完整。 –

+0

如果我沒有錯,它應該是mydata [i,1]而不是mydata [1,j]在ifelse的末尾 –

+0

對不起。這主要是因爲此時多任務:)希望通過新的改變你的第二個問題得到解決。我同意這不是解決這個問題的最有效的方法。我有興趣看到別人的答案,看看他們如何解決這個問題。 – MFR

1

假設你的數據幀dat,我要給你一個全矢量解決方案:

mat <- as.matrix(dat[, -1]) 
pos <- which(mat != 0) 
mat[pos] <- rep(dat[[1]], times = ncol(mat))[pos] 
new_dat <- "colnames<-"(cbind.data.frame(dat[1], mat), colnames(dat)) 

set.seed(0) 
dat <- "colnames<-"(cbind.data.frame(1:5, matrix(sample(0:1, 25, TRUE), 5)), 
        c("val", letters[1:5])) 
# val a b c d e 
#1 1 1 0 0 1 1 
#2 2 0 1 0 0 1 
#3 3 0 1 0 1 0 
#4 4 1 1 1 1 1 
#5 5 1 1 0 0 0 

我上面的代碼給出:

# val a b c d e 
#1 1 1 0 0 1 1 
#2 2 0 2 0 0 2 
#3 3 0 3 0 3 0 
#4 4 4 4 4 4 4 
#5 5 5 5 0 0 0 

你想要一個基準?

set.seed(0) 
n <- 2000 ## use a 2000 * 2000 matrix 
dat <- "colnames<-"(cbind.data.frame(1:n, matrix(sample(0:1, n * n, TRUE), n)), 
        c("val", paste0("x",1:n))) 

## have to test my solution first, as aichao's solution overwrites `dat` 

## my solution 
system.time({mat <- as.matrix(dat[, -1]) 
      pos <- which(mat != 0) 
      mat[pos] <- rep(dat[[1]], times = ncol(mat))[pos] 
      "colnames<-"(cbind.data.frame(dat[1], mat), colnames(dat))}) 
# user system elapsed 
# 0.352 0.056 0.410 

## solution by aichao 
system.time(dat[,-1] <- sapply(dat[,-1], function(x) {ind <- which(x!=0); x[ind] = dat[ind,1]; x})) 
# user system elapsed 
# 7.804 0.108 7.919 

我的解決方案速度快20倍!

+0

沒有嘗試複製和理解您的代碼,但結果不是我想要的。我希望非零值得到每一行中第一個數字的值,您的解決方案將零變爲第一個數字 –

+1

我接受一個易於理解的解決方案,並且@aichao非常友好,可以提供詳細的解釋他的代碼的運作。對我來說,作爲一個初學者,比擁有絕對最好的表現更重要,這不是一場比賽,而是一個更多地瞭解r的練習。 –

相關問題