我有一个5845 * 1095(行*列)数据框,如下所示:
9 286593 C C/C C/A A/A
9 334337 A A/A G/A A/A
9 390512 C C/C C/C C/C
c <- c("9", "286593", "C", "C/C", "C/A", "A/A")
d <- c("9", "334337", "A", "A/A", "G/A", "A/A")
e <- c("9", "390512", "C", "C/C", "C/C", "C/C")
dat <- data.frame(rbind(c,d,e))
我希望第三列中的值用于将列更改为右侧,因此如果(每行1)第3列为“C”,则第4列从“C / C”变为“0”因为它有相同的字母。一个字母匹配为“1”(可以是第一个或第二个字母),字母匹配不是“2”。
9 286593 C 0 1 2
9 334337 A 0 1 0
9 390512 C 0 0 0
c <- c("9", "286593", "C", "0", "1", "2")
d <- c("9", "334337", "A", "0", " 1", "0")
e <- c("9", "390512", "C", "0", "0", "0")
dat <- data.frame(rbind(c,d,e))
我有兴趣看到最好的方法,因为我想摆脱在 R 中使用嵌套For循环的习惯。
答案 0 :(得分:5)
首先是您的数据:
c <- c("9", "286593", "C", "C/C", "C/A", "A/A")
# Note: In your original data, you had a space in "G/A", which I did remove.
# If this was no mistake, we would also have to deal with the space.
d <- c("9", "334337", "A", "A/A", "G/A", "A/A")
e <- c("9", "390512", "C", "C/C", "C/C", "C/C")
dat <- data.frame(rbind(c,d,e))
现在我们生成一个包含所有可用字母的向量。
values <- c("A", "C", "G", "T")
dat$X3 <- factor(dat$X3, levels=values) # This way we just ensure that it will later on be possible to compare the reference values to our generated data.
# Generate all possible combinations of two letters
combinations <- expand.grid(f=values, s=values)
combinations <- cbind(combinations, v=with(combinations, paste(f, s, sep='/')))
main函数找到每列的每个组合的正确列,然后将其与参考列3进行比较。
compare <- function(col, val) {
m <- match(col, combinations$v)
2 - (combinations$f[m] == val) - (combinations$s[m] == val)
}
最后,我们使用apply在所有必须更改的列上运行该函数。您可能希望将6更改为实际的列数。
dat[,4:6] <- apply(dat[,4:6], 2, compare, val=dat[,3])
请注意,与迄今为止的其他解决方案相比,此解决方案不使用字符串比较,而是纯粹基于因子级别的方法。看看哪一个表现更好会很有趣。
我刚做了一些基准测试:
test replications elapsed relative user.self sys.self user.child sys.child
1 arun 1000000 2.881 1.116 2.864 0.024 0 0
2 fabio 1000000 2.593 1.005 2.558 0.030 0 0
3 roland 1000000 2.727 1.057 2.687 0.048 0 0
5 thilo 1000000 2.581 1.000 2.540 0.036 0 0
4 tyler 1000000 2.663 1.032 2.626 0.042 0 0
让我的版本略微更快。然而,差异几乎没有,所以你可能对每一种方法都很好。并且公平地说:我没有对添加额外因子水平的部分进行基准测试。这样做也可能会使我的版本失效。
答案 1 :(得分:4)
这是一种方法:
FUN <- function(x) {
a <- strsplit(as.character(unlist(x[-1])), "/")
b <- sapply(a, function(y) sum(y %in% as.character(unlist(x[1]))))
2 - b
}
dat[4:6] <- t(apply(dat[, 3:6], 1, FUN))
## > dat
## X1 X2 X3 X4 X5 X6
## c 9 286593 C 0 1 2
## d 9 334337 A 0 1 0
## e 9 390512 C 0 0 0
答案 2 :(得分:4)
这是使用apply
的一种方式:
out <- apply(dat[, -(1:2)], 1, function(x)
2 - grepl(x[1], x[-1]) -
x[-1] %in% paste(x[1], x[1], sep="/"))
cbind(dat[, (1:3)], t(out))
答案 3 :(得分:3)
此解决方案效率不高:
dat <- cbind(dat[,-(4:6)],
t(sapply(seq_len(nrow(dat)),function(i){
res <- dat[i,]
res[,4:6] <- lapply(res[,4:6],function(x) 2-sum(gregexpr(res[,3],x)[[1]]>0))
})))
# X1 X2 X3 X4 X5 X6
#c 9 286593 C 0 1 2
#d 9 334337 A 0 1 0
#e 9 390512 C 0 0 0
答案 4 :(得分:2)
丑陋,但它确实有效!
fff<-apply(dat[,4:ncol(dat)],2,substr,1,1)!=dat[,3]
ggg<-apply(dat[,4:ncol(dat)],2,substr,3,3)!=dat[,3]
final<-fff+ggg
cbind(dat,final)
X1 X2 X3 X4 X5 X6 X4 X5 X6
c 9 286593 C C/C C/A A/A 0 1 2
d 9 334337 A A/A G/A A/A 0 1 0
e 9 390512 C C/C C/C C/C 0 0 0
答案 5 :(得分:2)
对R-golf的另一个贡献:
cbind(dat[, 1:3],
apply(dat[, -(1:3)], 2, function(x) {
2 - (dat[[3]] == gsub('..$', '', x)) - (dat[[3]] == gsub('^..', '', x))
}))