基于一列重新编码数据帧 - 反过来

时间:2014-01-07 14:45:16

标签: r dataframe

我刚才问了这个问题(Recode dataframe based on one column),答案很有效。然而,现在,我几乎想要反过来。也就是说,我有一个(700k * 2000)的0/1/2或NA。在一个单独的数据框中,我有两列(Ref和Obs)。 0对应于Ref的两个实例,1是Ref的一个实例,Obs的一个实例和2是两个Obs。澄清一下,数据摘录:

 Genotype File --- 
 Ref Obs   
 A    G        
 T    C
 G    C
 Ref <- c("A", "T", "G")
 Obs <- c("G", "C", "C")

 Current Data---
 Sample.1     Sample.2  .... Sample.2000
 0              1                2
 0              0                0 
 0              NA               1

mat <- matrix(nrow=3, ncol=3)
mat[,1] <- c(0,0,0)
mat[,2] <- c(1,0,NA)
mat[,3] <- c(2,0,1)

 Desired Data format--- 
 Sample.1   Sample.1   Sample.2   Sample.2   Sample.2000   Sample.2000
    A         A           A           G          G              G
    T         T           T           T          T              T
    G         G           0           0          G              C

我认为这是对的。所需的数据格式对于每个样本具有两列(空格分隔)。这种格式的0(生物信息学家的plink ped文件)缺少数据。

3 个答案:

答案 0 :(得分:1)

主要假设:你的数据是3个元素的框架,即你想要将你的映射应用到前3行,然后是接下来的3行,依此类推,我认为这对于DNA帧是有意义的。如果你想要一个滚动的3元素窗口,这将不起作用(但可以修改代码使其工作)。这适用于任意数量的列,以及任意数量的3个行组:

# Make up a matrix with your properties (4 cols, 6 rows)

col <- 4L
frame <- 3L
mat <- matrix(sample(c(0:2, NA_integer_), 2 * frame * col, replace=T), ncol=col)

# Mapping data

Ref <- c("A", "T", "G")
Obs <- c("G", "C", "C")
map.base <- cbind(Ref, Obs)
num.to.let <- matrix(c(1, 1, 1, 2, 2, 2), byrow=T, ncol=2) # how many from each of ref obs

# Function to map 0,1,2,NA to Ref/Obs

re_map <- function(mat.small) {  # 3 row matrices, with col columns
  t(
    mapply(                      # iterate through each row in matrix
      function(vals, map, num.to.let) {
        vals.2 <- unlist(lapply(vals, function(x) map[num.to.let[x + 1L, ]]))
        ifelse(is.na(vals.2), 0, vals.2)
      },
      vals=split(mat.small, row(mat.small)),  # a row
      map=split(map.base, row(map.base)),     # the mapping for that row
      MoreArgs=list(num.to.let=num.to.let)    # general conversion of number to Obs/Ref
  ) ) 
}
# Split input data frame into 3 row matrices (assumes frame size 3),
# and apply mapping function to each group

mat.split <- split.data.frame(mat, sort(rep(1:(nrow(mat) / frame), frame)))
mat.res <- do.call(rbind, lapply(mat.split, re_map)) 
colnames(mat.res) <- paste0("Sample.", rep(1:ncol(mat), each=2))
print(mat.res, quote=FALSE)
#   Sample.1 Sample.1 Sample.2 Sample.2 Sample.3 Sample.3 Sample.4 Sample.4
# 1 G        G        A        G        G        G        G        G       
# 2 C        C        0        0        T        C        T        C       
# 3 0        0        G        C        G        G        G        G       
# 1 A        A        A        A        A        G        A        A       
# 2 C        C        C        C        T        C        C        C       
# 3 C        C        G        G        0        0        0        0       

答案 1 :(得分:0)

我不确定,但这可能是你需要的:

首先是相同的简单数据

geno <- data.frame(Ref = c("A", "T", "G"), Obs = c("G", "C", "C"))
data <- data.frame(s1 = c(0,0,0),s2 = c(1, 0, NA))

然后是几个功能:

f <- function(i , x, geno){
  x <- x[i]
  if(!is.na(x)){
    if (x == 0) {y <- geno[i , c(1,1)]}
    if (x == 1) {y <- geno[i, c(1,2)]}
    if (x == 2) {y <- geno[i, c(2,2)]}
  }
  else y <- c(0,0)
  names(y) <- c("s1", "s2")
  y
}

g <- function(x, geno){
 Reduce(rbind, lapply(1:length(x), FUN = f , x = x, geno = geno))
}

定义f()的方式可能不是最优雅的,但它可以完成工作

然后简单地以lapply方式将其作为forble循环运行

as.data.frame(Reduce(cbind, lapply(data , g , geno = geno )))

希望有所帮助

答案 2 :(得分:0)

这是基于答案中的示例数据的一种方式:

# create index
idx <- lapply(data, function(x) cbind((x > 1) + 1, (x > 0) + 1))

# list of matrices
lst <- lapply(idx, function(x) {
  tmp <- apply(x, 2, function(y) geno[cbind(seq_along(y), y)])
  replace(tmp, is.na(tmp), 0)
  })

# one data frame
as.data.frame(lst)

#   s1.1 s1.2 s2.1 s2.2
# 1    A    A    A    G
# 2    T    T    T    T
# 3    G    G    0    0