【问题标题】:Map vectors into integers in a bijective way以双射方式将向量映射为整数
【发布时间】:2016-01-08 23:52:27
【问题描述】:

我有 100,000 个 5 长度向量(下面的 VECTORS 列表),其元素是从一百万个值中选择的。

# dictionary
dictionary=seq(1:1e6)

# generate 100,000 5-length vectors whose elements are chosen from dictionary
VECTORS <- lapply(c(1:1e5), sample, x = dictionary, size =5)

我的问题是将每个完全相同的向量映射到一个整数,即我需要一个 mappy 函数来输入一个向量并产生一个整数。 例如mappy(c(58431, 976854, 661294, 460685, 341123))=15。你知道如何有效地做到这一点吗?

辅助问题:如果我的向量不再相同长度怎么办?

【问题讨论】:

  • 没有足够的整数来映射1e6^5可能的向量。
  • 看来match(VECTORS, unique(VECTORS)) 之类的东西也许会有所帮助

标签: r function dictionary hash


【解决方案1】:

我在这里假设您想要列表中的向量和整数之间的双射。一种方法是从向量的字符表示中创建一个因子变量。让我们从您的代码的可重现版本开始(我将使其成为一个更小的向量):

set.seed(144)
VECTORS <- replicate(1e2, sample(seq_len(1e6), 5), FALSE)

现在您可以从每个向量的字符表示中创建一个因子变量:

fvar <- factor(sapply(VECTORS, paste, collapse=" "))

现在我们在VECTORS 元素的字符串表示和整数之间有了一个双射:

vec <- c(894025, 153892, 98596, 218401, 36616)  # 15th element of VECTORS
which(levels(fvar) == paste(vec, collapse=" "))
# [1] 90
levels(fvar)[90]
# [1] "894025 153892 98596 218401 36616"
as.numeric(strsplit(levels(fvar)[90], " ")[[1]])
# [1] 894025 153892  98596 218401  36616

如果你想把它们包装成漂亮的函数:

id.from.vec <- function(vec) which(levels(fvar) == paste(vec, collapse=" "))
id.from.vec(c(894025, 153892, 98596, 218401, 36616))
# [1] 90

vec.from.id <- function(id) as.numeric(strsplit(levels(fvar)[id], " ")[[1]])
vec.from.id(90)
# [1] 894025 153892  98596 218401  36616

请注意,即使向量的长度不同,这也是开箱即用的。

【讨论】:

    【解决方案2】:

    带键的 data.table 具有很好的查找属性:

    library(data.table)
    set.seed(1)
    VECTORS <- lapply(seq(1e5), sample, x = 1e6, size = 5)
    VECmap  <- setkey(rbindlist(lapply(unique(VECTORS), as.list)))[, ID := .I]
    
    #             V1     V2     V3     V4     V5     ID
    #      1:     13 897309 366563 678873   6571      1
    #      2:     15 557977 640484 732531 848939      2
    #      3:     48  18120 911805 188728 805726      3
    #      4:     48 830301 862433 506297 877432      4
    #      5:     52 873436 824165  86251 576173      5
    #     ---                                          
    #  99996: 999911 583599 803402 240910 931996  99996
    #  99997: 999931 146505 287431 180259 230904  99997
    #  99998: 999937 175888 266336 874987 982951  99998
    #  99999: 999950 960139 455084 586956 875504  99999
    # 100000: 999993 191750 258982 518519  78087 100000
    
    mapVEC  <- function(...) VECmap[.(...)]$ID
    mapID   <- function(id) unlist(VECmap[ID==id,!"ID",with=FALSE], use.names=FALSE)
    
    # example usage
    mapVEC(52, 873436, 824165, 86251, 576173)
    # 5
    mapID(5)
    # 52 873436 824165  86251 576173
    

    评论 正如@Roland 所提到的,(a) 1..1e6 和 (b) all 来自 1.. 的不同数字的 5 长度序列之间的双射1e5 是不可能的,所以我只是猜测这就是 OP 所追求的。

    当您编写一个以... 作为参数的函数时,这意味着可以接受任意数量的未命名参数。在函数中,这些参数可以用... 引用,但也经常可以用c(...)list(...) 看到。在 data.table 中,.(...)list(...) 的别名。要查看编​​写函数的文档,请输入 help.start() 并点击进入“R 语言定义”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      • 2016-04-19
      • 2020-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-17
      相关资源
      最近更新 更多