【问题标题】:hdf5 file in R for fast random access by IDR 中的 hdf5 文件,用于通过 ID 进行快速随机访问
【发布时间】:2014-02-05 17:50:36
【问题描述】:

假设我想将一个大尺寸矩阵存储为 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 检索可以快速进行,而无需对整个文档进行排序和/或扫描。

【问题讨论】:

    标签: r hdf5


    【解决方案1】:

    查看 http://www.bioconductor.org/packages/devel/bioc/manuals/rhdf5/man/rhdf5.pdf 第 13 页了解如何读入子集,特别是 h5readindex 参数。

    这应该允许您读取子集。

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

    【讨论】:

    • 谢谢。我发现文档非常神秘。 INDEX:子集的索引列表。列表的长度必须与 HDF5 数组的维度扩展一致。每个列表元素都是索引的整数向量。等于 NULL 的列表元素选择此维度中的所有索引。计数是基于 R 风格的 1。这如何转化为按行名索引所有行?
    【解决方案2】:

    我只是在学习使用 rhdf5 包。看起来,对于没有暗名的矩阵的创建和索引,操作真的很简单

    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 对象,但我最终“滚动我自己的”函数来创建和子集/选择带有暗名的矩阵。下面是 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 包的问题是合适的,包作者可能更可能看到它。

    【讨论】:

      【解决方案3】:

      你可以试试 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
      

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

      d[match(rows.to.read, r[]),]
      

      免责声明:我是 h5r 包的作者。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-05-07
        • 1970-01-01
        • 1970-01-01
        • 2016-06-06
        • 1970-01-01
        • 2019-01-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多