【问题标题】:Scan each column in a data frame and then change values to binary format in R扫描数据框中的每一列,然后将值更改为 R 中的二进制格式
【发布时间】:2020-10-20 20:57:29
【问题描述】:

我有一个矩阵,其中行中有多个个体,列中有多个核苷酸(值)。它看起来像这样:

     [,1][,2][,3][,4] ...
ind1   a   c   a   a
ind2   a   c   t   t
ind3   a   g   g   c
ind4   a   g   g   g
.
.
.

现在我想忽略所有仅出现一个值的列(如上面第一列的示例),并用两个、三个和四个(不超过 4 个!)不同的核苷酸(值)转换每一列成二进制格式。最后应该是这样的:

     [,1] [,2]  [,3] ...
ind1  10   100   1000
ind2  10   010   0100
ind3  01   001   0010
ind4  01   001   0001
.
.
.

对我来说,如果有两个、三个或四个不同的值,获得相同的二进制代码才重要。 我已经在计算每列中出现了多少不同的值,但我不确定如何将值更改为二进制格式:

df <- apply(df, 2, function(x) length(unique(x)))

有人可以帮我吗?

【问题讨论】:

  • 不清楚如何获得 '01' '10' 的预期输出,其中第一列的列值只是 'a'
  • 不清楚预期的输出。可能是library(pryr);apply(df[-1], 2, function(x) {n &lt;- length(unique(x)); substr(pryr::bits(x), n, n + n-1)})

标签: r matrix


【解决方案1】:

这里有一些其他的尝试。自定义函数将通过apply 获取每一列。首先,您可以创建与列中唯一字符相对应的数值向量(使用unique,否则factor 将按字母顺序排列)。将生成一个最大数字长度的零字符串,然后将每个值对应的字符位置替换为“1”。

my_fun <- function(x) {
  vec <- as.numeric(factor(x, levels = unique(x)))
  vec_max <- max(na.omit(vec))
  lapply(vec, 
         function(y) ifelse(!is.na(y), 
                            sub(paste0("(.{", y - 1, "})."), 
                                "\\11", 
                                paste0(rep("0", vec_max), collapse = "")), 
                            NA))
}

m[] <- matrix(unlist(apply(m, 2, my_fun)))

输出

     [,1] [,2] [,3]  [,4]  
ind1 "1"  "10" "100" "1000"
ind2 "1"  "10" "010" "0100"
ind3 "1"  "01" "001" "0010"
ind4 "1"  "01" "001" "0001"

数据

m <- structure(c("a", "a", "a", "a", "c", "c", "g", "g", "a", "t", 
"g", "g", "a", "t", "c", "g"), .Dim = c(4L, 4L), .Dimnames = list(
    c("ind1", "ind2", "ind3", "ind4"), NULL))

【讨论】:

  • 非常感谢您帮助我,但我收到此错误:Error in rep("0", max(vec)) : invalid 'times' argument
  • 嗨,我尝试使用自己的数据。它对于dput(head(df)) 来说太大了,它有 543 行和 ~11000 列,也许这就是原因?
  • 是的,我确实有,但我使用的是[!is.na(x)]。这不起作用吗?当将 HA 粘贴到一个小矩阵中并运行您的命令时,它可以工作。
  • 我想忽略 NA。这可能吗?
  • @LukasMe 查看已编辑的答案 - 如果有帮助,请告诉我。如果缺少值,它将在结果中使用NA。此外,二进制结果的长度也会更短。我需要跑步,但我会在几个小时后再次签到。
【解决方案2】:

这是我的尝试:

r1 <- c("a","c","a","a")
r2 <- c("a","c","t","t")
r3 <- c("a","g","g","c")
r4 <- c("a","g","g","g")

n.mat <- rbind(r1,r2,r3,r4)

number_to_nucleotide_binary <- function(x,len) {
  out <- rep("0",len)
  out[x] <- "1"
  return(paste(out,collapse = ""))
}

nuc_to_binary <- function(x) {
  
  len <- length(unique(x))
  char <- sort(unique(x))
  out <- x
  
  if(len != 1) {
    pos <- match(x,char)
    out <- sapply(X = pos,FUN = function(x) {number_to_nucleotide_binary(x = x,len = len)})
  }
  
  return(out)
}

apply(X = n.mat,FUN = nuc_to_binary,MARGIN = 2)

输入:

   [,1] [,2] [,3] [,4]
r1 "a"  "c"  "a"  "a" 
r2 "a"  "c"  "t"  "t" 
r3 "a"  "g"  "g"  "c" 
r4 "a"  "g"  "g"  "g" 

输出:

     [,1] [,2] [,3]  [,4]  
[1,] "a"  "10" "100" "1000"
[2,] "a"  "10" "001" "0001"
[3,] "a"  "01" "010" "0100"
[4,] "a"  "01" "010" "0010"

【讨论】:

  • 您好,非常感谢您的帮助,但我希望只有1000 , 0100 , 0010 , 0001,但没有0011,但除此之外,您的命令效果很好!
  • 我已将代码编辑为更简单,并消除了对其他 SO 答案的依赖。希望这就是您所追求的 - 尽管 Ben 的答案更具可扩展性/优雅/简洁。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-23
  • 2023-01-10
  • 1970-01-01
  • 2016-12-23
  • 2018-12-03
相关资源
最近更新 更多