在大文件中更有效地替换因子水平

Replacing factor levels more efficiently in a huge file

我有一个包含 800000 行和 13000 列的文件。该文件如下所示:

        ID1 ID2 ID3 ID4 ID5
SNP1    AA  AA  AB  AA  BB
SNP2    AB  AA  BB  AA  AA
SNP3    BB  BB  BB  AB  BB
SNP4    AA  AA  BB  BB  AA
SNP5    AA  AA  AA  AA  AA

我想用数字替换字母(AA = 0、AB = 1 和 BB = 2)。 我所做的是: 数据[数据=="AA"] = 0 它在一个小示例中似乎工作正常,但在大文件中似乎不起作用。花了好几个小时。有没有更有效的方法呢? 非常感谢你。 宝拉

也许试试这个:

读入您的数据:

DF <- read.table(text = "ID1 ID2 ID3 ID4 ID5
SNP1    AA  AA  AB  AA  BB
SNP2    AB  AA  BB  AA  AA
SNP3    BB  BB  BB  AB  BB
SNP4    AA  AA  BB  BB  AA
SNP5    AA  AA  AA  AA  AA
", header = TRUE, sep = "", stringsAsFactors = FALSE) 

> str(DF)
'data.frame':   5 obs. of  5 variables:
 $ ID1: chr  "AA" "AB" "BB" "AA" ...
 $ ID2: chr  "AA" "AA" "BB" "AA" ...
 $ ID3: chr  "AB" "BB" "BB" "BB" ...
 $ ID4: chr  "AA" "AA" "AB" "BB" ...
 $ ID5: chr  "BB" "AA" "BB" "AA" ...

创建查找 table:

tab <- c("AA" = 0, "AB" = 1  , "BB" = 2)
> tab
AA AB BB 
 0  1  2

一些子赋值魔术:

> DF[] <- tab[as.matrix(DF)]
> DF
     ID1 ID2 ID3 ID4 ID5
SNP1   0   0   1   0   2
SNP2   1   0   2   0   0
SNP3   2   2   2   1   2
SNP4   0   0   2   2   0
SNP5   0   0   0   0   0
> str(DF)
'data.frame':   5 obs. of  5 variables:
 $ ID1: num  0 1 2 0 0
 $ ID2: num  0 0 2 0 0
 $ ID3: num  1 2 2 2 0
 $ ID4: num  0 0 1 2 0
 $ ID5: num  2 0 2 0 0

文件对于 R 来说可能太大,除非您使用 scan,这会使 IMO 变得过于复杂。使用 GNU 实用程序可以更好地处理这项工作。

如果您在 Windows 安装 MSYS:

http://www.mingw.org/wiki/Getting_Started

然后使用提到的sed替换文本:

cat <filename>  | sed "s/\bAA\b/0/g" | sed "s/\bBA\b/1/g" | sed "s/\bAB\b/1/g"  | sed "s/\bBB\b/2/g" > <newfile>

编辑:

如果您必须使用 R,您可能需要逐行读取文件,因为文件包含约 100 亿个条目,每个 3 个字符都是一个非常大的数据集!

请在此处查看 SO 线程以逐行读取文件:

reading a text file in R line by line

但是,我怀疑这会很慢。

假设您已设法打开文件并假设它是一个 data.framefactor 列,您可以使用因子已经是从 1 开始编号的数字列这一事实:

DF <- read.table(text = "ID1 ID2 ID3 ID4 ID5
SNP1    AA  AA  AB  AA  BB
SNP2    AB  AA  BB  AA  AA
SNP3    BB  BB  BB  AB  BB
SNP4    AA  AB  BB  BB  AA
SNP5    AA  AA  AA  AA  AA
", header = TRUE, sep = "") 

for (i in seq_along(DF)) {
  # check if the column levels are ordered correctly; if not
  # relevel the column
  if (!identical(levels(DF[[i]]), c("AA", "AB", "BB"))) {
    warning("Levels do not match in column ", i, ". Relevelling.")
    DF[[i]] <- factor(DF[[i]], levels=c("AA", "AB", "BB"))
  }
  # remove the class of the column: this basically makes an integer
  # column from the factor
  attr(DF[[i]], "class") <- NULL
  # substract 1 to get number from 0
  DF[[i]] <- DF[[i]] - 1
}

该代码检查级别编号是否正确,并在必要时重新级别。希望这不会经常发生,因为这会减慢速度。

可能是您的文件不适合内存,这将导致 Windows/Linux/... 使用磁盘进行内存存储。这将大大减慢速度。在那种情况下,您可能最好使用 ffbigmemory 等软件包。