2016-08-03 83 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的练习。 –