在R中使用'fastmatch'包

Dan*_*der 1 r matching

我必须在大约10MM值的向量内找到1MM数值的索引.我找到了包fastmatch,但是当我使用该函数时fmatch(),我只返回第一个匹配的索引.

有人可以帮我使用这个功能找到所有的值,而不仅仅是第一个?我意识到这是一个基本问题,但在线文档非常稀疏,并且fmatch大大减少了计算时间.

非常感谢!


以下是一些示例数据 - 为了本练习的目的,让我们调用此数据框A:

              DateTime     Address       Type     ID
1  2014-03-04 20:21:03   982076970          1  2752394
2  2014-03-04 20:21:07 98174238211          1  2752394
3  2014-03-04 20:21:08 76126162197          1  2752394
4  2014-03-04 20:21:16  6718053253          1  2752394
5  2014-03-04 20:21:17 98210219176          1  2752510
6  2014-03-04 20:21:20  7622877100          1  2752510
7  2014-03-04 20:21:23  2425126157          1  2752510
8  2014-03-04 20:21:23  2425126157          1  2752510
9  2014-03-04 20:21:25   701838650          1  2752394
10 2014-03-04 20:21:27 98210219176          1  2752394
Run Code Online (Sandbox Code Playgroud)

我想要做的是找到Type每个的唯一值的数量Address.有数百万行数据,大约有1MM唯一的地址值...平均而言,每个地址在数据集中出现约6次.而且,虽然Type上面列出的值都是1,但它们可以从0:5获取任何值.我也意识到这些Address值很长,这增加了匹配所需的时间.

我尝试过以下方法:

uvals <- unique(A$Address)
utypes <- matrix(0,length(uvals),2)
utypes[,1] <- uvals

for (i in 1:length(unique(Address))) {
    b <- which(uvals[i] %in% A$Address)
    c <- length(unique(A$Type[b]))
    utypes[i,2] <- c
}
Run Code Online (Sandbox Code Playgroud)

但是,上面的代码效率不高 - 如果我循环超过1MM的值,我估计这需要10-15个小时.

我也在循环中试过这个......但它并没有快得多.

b <- which(A$Address == uvals[i])  
Run Code Online (Sandbox Code Playgroud)

我知道有一种更优雅/更快的方式,我对R来说相当新,并且会感激任何帮助.

Aru*_*run 5

这可以使用unique函数in data.table,然后是聚合来完成.我将使用或多或少的@Chinmay生成的示例数据来说明它:

创建样本数据:

set.seed(100L)
dat = data.frame(
         address = sample(1e6L, 1e7L, TRUE), 
           value = sample(1:5, 1e7L, TRUE, prob=c(0.5, 0.3, 0.1, 0.07, 0.03))
      )
Run Code Online (Sandbox Code Playgroud)

data.table解决方案:

require(data.table) ## >= 1.9.2
dat.u = unique(setDT(dat), by=c("address", "value"))
ans   = dat.u[, .N, by=address]
Run Code Online (Sandbox Code Playgroud)

说明:

  • setDT函数将a转换data.framedata.table 引用(速度非常快).
  • unique在data.table上运行的函数唤起了这个unique.data.table方法,与之相比,这个方法非常快base:::unique.现在,我们只有type每个人的唯一值address.
  • 剩下要做的就是聚合分组, address并获得每组中的观察数量.在by=address通过部分基团address.N是一个内置的data.table变量,其提供用于该组观测值的数目.

基准:

我将创建函数生成数据,data.tabledata.frame以基准data.table对答案dplyr由@beginneR提出的解决方案(一),虽然我没有看到需求arrange(.)出现,因此将跳过这一部分.

## function to create data
foo <- function(type = "df") {
    set.seed(100L)
    dat = data.frame(
             address = sample(1e6L, 1e7L, TRUE), 
               value = sample(1:5, 1e7L, TRUE, prob=c(0.5, 0.3, 0.1, 0.07, 0.03))
          )
    if (type == "dt") setDT(dat)
    dat
} 

## DT function
dt_sol <- function(x) {
    unique(x, by=c("address", "value"))[, .N, by=address]
}

## dplyr function
dplyr_sol <- function(x) {
    distinct(x) %>% group_by(address) %>% summarise(N = n_distinct(value))
}
Run Code Online (Sandbox Code Playgroud)

这里报告的时间是system.time(.)每个函数连续三次运行.

## benchmark timings in seconds
##        pkg   run-01   run-02   run-03                                 command
## data.table     2.4       2.3      2.4  system.time(ans1 <- dt_sol(foo("dt")))
##      dplyr    15.3      16.3     15.7   system.time(ans2 <- dplyr_sol(foo()))
Run Code Online (Sandbox Code Playgroud)

出于某种原因,dplyr通过分组变量自动对结果进行排序.因此,为了比较结果,我还将在以下结果中对它们进行排序data.table:

system.time(setkey(ans1, address)) ## 0.102 seconds
identical(as.data.frame(ans1), as.data.frame(ans2)) ## TRUE
Run Code Online (Sandbox Code Playgroud)

所以,data.table这里要快6倍.

请注意,bit64:::integer64也支持data.table- 因为您提到地址值太长,您也可以将它们存储为integer64.