我的问题很简单。我有一个数据框,每行有不同的数字,超过100列。第一列始终是非零数字。我想要做的是用行中的第一个数字(第一列的值)替换每行中的每个非零数字(第一列的值)用第一列中的值替换每行的值
我会在ifelse和for遍历该行迭代但必须有做一个简单的向量化方法...
我的问题很简单。我有一个数据框,每行有不同的数字,超过100列。第一列始终是非零数字。我想要做的是用行中的第一个数字(第一列的值)替换每行中的每个非零数字(第一列的值)用第一列中的值替换每行的值
我会在ifelse和for遍历该行迭代但必须有做一个简单的向量化方法...
另一种方法是使用sapply
,这比循环更有效。假设你的数据在数据帧df
:
df[,-1] <- sapply(df[,-1], function(x) {ind <- which(x!=0); x[ind] = df[ind,1]; return(x)})
在这里,我们应用function
过每除了第一列的df
所有列。在function
,x
是每个列的依次为:
which
零列的行索引。x
中的这些行设置为第一列df
的行中的对应值。注意的是,在功能操作都在列“量化”。也就是说,不在列的行上循环。 sapply
的结果是已处理列的矩阵,它将替换不是第一列的所有列df
。
请参阅this了解*apply
功能家族的优秀评论。
希望这会有所帮助。
非常好。谢谢。出于好奇,我们不能用apply来做每行而不是每列吗? –
'apply'用于跨数组的某个维度应用函数。看到[这个SO回答](http://stackoverflow.com/questions/3505701/r-grouping-functions-sapply-vs-lapply-vs-apply-vs-tapply-vs-by-vs-aggrega)为好审查'应用'功能家族。 – aichao
看起来像这样不会做我想要的,但它只是一个改变哪个= 0的情况。请记住,我想将所有** nonzeros **更改为每行的第一个数字。从我的iPad发布,所以没有尝试它 –
既然你的数据本来就不大,我建议你使用一个简单的循环
for (i in 1:nrow(mydata))
{
for (j in 2:ncol(mydata)
{
mydata[i,j]<- ifelse(mydata[i,j]==0 ,0 ,mydata[i,1])
}
}
谢谢你的回答。但是数据集实际上非常大,我正在寻找一种更加矢量化的方法。同样在你的解决方案中,第一列数据也不会被替换?我需要第一列保持完整。 –
如果我没有错,它应该是mydata [i,1]而不是mydata [1,j]在ifelse的末尾 –
对不起。这主要是因为此时多任务:)希望通过新的改变你的第二个问题得到解决。我同意这不是解决这个问题的最有效的方法。我有兴趣看到别人的答案,看看他们如何解决这个问题。 – MFR
假设你的数据帧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倍!
没有尝试复制和理解您的代码,但结果不是我想要的。我希望非零值得到每一行中第一个数字的值,您的解决方案将零变为第一个数字 –
我接受一个易于理解的解决方案,并且@aichao非常友好,可以提供详细的解释他的代码的运作。对我来说,作为一个初学者,比拥有绝对最好的表现更重要,这不是一场比赛,而是一个更多地了解r的练习。 –
发表一个适合测试和演示的例子。 –