R中的hdf5文件,用于ID的快速随机访问

时间:2014-01-16 17:08:53

标签: r hdf5

让我们说我想将一个大尺寸的矩阵存储为HDF5文件,然后我想只读取一些ID的矩阵切片(ID我是指矩阵的行名,在我的例子中是独特的,所以他们可以作为ID)。有没有一种使用HDF5文件的快速方法?

实施例

my.mat = matrix(rnorm(400,2,1), nrow=100, ncol=4)
rownames(my.mat) = paste("id", c(1:100), sep="")

然后,我会做这样的事情:

h5createFile("test.h5")
h5createDataset(file="test.h5", dataset="dat", dim=c(100,4), not sure what goes here)

然后我想读取h5文件,但只能读取行ID,即只读取行,

rows.to.read= c("id4", "id10", "id40")

主要目标是使切片读数(通过切片读取,我的意思是ID读取)和尽可能快地写入整个HDF5文件,因为这些都是非常大的数据集。我想象一下,必须以row_name对它们进行哈希处理的方式存储它们,这样ID的检索可以快速进行,而无需对整个文档进行排序和/或扫描。

3 个答案:

答案 0 :(得分:2)

我刚学会使用rhdf5包。看起来,对于创建和索引没有dimnames的矩阵,操作实际上是直截了当的

library(rhdf5)
my.mat <- matrix(rnorm(400,2,1), nrow=100, ncol=4)
fl <- tempfile()
h5createFile(fl)
h5write(my.mat, fl, "mat")
h5read(fl, "mat", list(2:3, 3:4))
##           [,1]     [,2]
## [1,] 0.3199968 1.947390
## [2,] 1.3338179 2.623461
h5read(fl, "mat", list(2:3, NULL))
##          [,1]      [,2]      [,3]     [,4]
## [1,] 1.247648 -0.380762 0.3199968 1.947390
## [2,] 3.157954  1.334057 1.3338179 2.623461

看起来该软件包支持某些功能,例如,用于编写data.frame个对象,但我最终“滚动自己的”功能来创建和子集/选择具有dimnames的矩阵。这是write函数,它将HDF5属性添加到数据集

h5matrix_write <-
    function(obj, file, name, ...)
{
    if (!is.matrix(obj) || is.null(dimnames(obj)) ||
        any(sapply(dimnames(obj), is.null)))
        stop("'obj' must be a matrix with row and column names")

    fid <- if (file.exists(file))
        H5Fopen(file)
    else
        H5Fcreate(file)
    h5createDataset(fid, name, dim=dim(obj))
    did <- H5Dopen(fid, name)

    h5createAttribute(fid, "rownames", nrow(obj), storage.mode="character",
                      size=max(nchar(rownames(obj))))
    h5createAttribute(fid, "colnames", ncol(obj), storage.mode="character",
                      size=max(nchar(colnames(obj))))

    h5writeDataset(obj, fid, name)
    h5writeAttribute(rownames(obj), did, "rownames")
    h5writeAttribute(colnames(obj), did, "colnames")

    H5Dclose(did)
    H5Fclose(fid)

    file
}

为了读取子集,我检查索引是否是字符向量。如果是这样,我将索引识别到矩阵中并使用它来提取相关值

h5matrix_select <-
    function(file, name, i, j, ...)
{
    ## FIXME: doesn't handle logical subsetting
    fid <- H5Fopen(fl)
    did <- H5Dopen(fid, "mat")
    rownames <- H5Aread(H5Aopen(did, "rownames"))
    if (missing(i))
        i <- seq_along(rownames)
    else if (is.character(i)) {
        i <- match(i, rownames)
        if (any(is.na(i)))
            stop(sum(is.na(i)), " unknown row names")
    }
    rownames <- rownames[i]

    colnames <- H5Aread(H5Aopen(did, "colnames"))
    if (missing(j))
        j <- seq_along(colnames)
    else if (is.character(j)) {
        j <- match(j, colnames)
        if (any(is.na(j)))
            stop(sum(is.na(j)), " unknown colnames")
    }
    colnames <- colnames[j]

    value <- h5read(file, name, list(i, j))
    dimnames(value) <- list(rownames, colnames)
    value
}

行动中:

dimnames(my.mat) <- list(paste0("rid", seq_len(nrow(my.mat))),
                         paste0("cid", seq_len(ncol(my.mat))))
fl <- h5matrix_write(my.mat, tempfile(), "mat")
h5matrix_select(fl, "mat", 4:5, 2:3)
##           cid2      cid3
## rid4 0.4716097 2.3490782
## rid5 2.0896238 0.5141749
h5matrix_select(fl, "mat", 4:5)
##           cid1      cid2      cid3     cid4
## rid4 2.0947833 0.4716097 2.3490782 3.139687
## rid5 0.8258651 2.0896238 0.5141749 2.509301
set.seed(123)
h5matrix_select(fl, "mat", sample(rownames(my.mat), 3), 2:3)
##            cid2     cid3
## rid29 0.6694079 3.795752
## rid79 2.1635644 2.892343
## rid41 3.7779177 1.685139

h5read(fl, "mat", read.attributes=TRUE)读取所有内容;我认为@jimmyb中更简单的方法(将行名称存储为单独的变量)也适用于rhdf5。

在Bioconductor mailing list上询问有关Bioconductor包的问题是恰当的,其中包装作者可能更有可能看到它。

答案 1 :(得分:2)

您可以尝试使用h5r软件包,它的API比rhdf5软件包重量轻一些,但功能较少。

require(h5r)
my.mat = matrix(rnorm(400,2,1), nrow=100, ncol=4)
rnames = paste("id", c(1:100), sep="")

f = H5File("mymat.h5", 'w')
d = createH5Dataset(f, "mymat", my.mat)
r = createH5Dataset(f, "rnames", rnames)

然后按整数/序列进行切片/索引是预期的(而不是全部读入内存)

d[1:2,1:2]
     [,1]       [,2]
[1,] 2.777984  1.6040137
[2,] 3.406609 -0.5168481

目前,您必须跳过带有rownames的环,因为hdf5数据结构都是一种类型(忽略更复杂的hdf5类型)

d[match(rows.to.read, r[]),]
免责声明:我是h5r软件包的作者。

答案 2 :(得分:0)

查看http://www.bioconductor.org/packages/devel/bioc/manuals/rhdf5/man/rhdf5.pdf第13页,了解如何读取子集,特别是index的{​​{1}}参数。

这应该允许您读入子集。

该软件包不在CRAN中,但第一个答案是:How to deal with hdf5 files in R?应该可以帮助您获得所需的软件包本身。