提问者:小点点

有没有更高效的match版本可以搜索重复排列的数字?


我有一个20行n列的数据集。我最初使用的是n=10000,但是我发现我需要使用一个更大的数字,可能是十倍以上。该数据集的每一列都是独立于其他列生成的,并且包含从1到20的整数的随机但有偏差的排列。我希望对整个数据集中每个数字的位置求和。换句话说,我想知道对于每个a和b,数字a在bth位置出现了多少次(即我的最终结果是一个20*20的值表)。

我相信我已经有了实现这个目标的代码。例如,我的计算机在不到两分钟的时间内处理了整个n=10000 cause(即,它为我提供了每个a和b的计数)。然而,n=100000和较小的n=50000花费的时间太长,以至于我的耐心耗尽了。我的大部分代码都非常简单,我确信效率低下是因为在下面几行中使用了< code>match(如上所述,< code>a 、< code>b和< code>n,其中< code>data是数据集):

list<-c()
  for(k in 1:n)
  {
    position<-match(a, data[,k])
    list<-c(list,position)
  }
  return(sum(list==b))

我该如何改善这一点?< code>match看起来非常慢,但是我看到的所有解决方案(示例)既不是通用的解决方案,也不适用于这种情况。

如果您希望对解决方案进行基准测试,replica(n,sample(20))将生成与我的数据集类似的列表。


共3个答案

匿名用户

我认为主要的瓶颈是你增加了循环中向量的大小。尝试在循环之前初始化它并分配向量中的值。

list_vec <- numeric(length = n)

for(k in 1:n) {
  list_vec[k] <- match(a, data[,k])
}

或使用 sapply

sapply(data, function(x) match(a, x))

匿名用户

使用< code>data.table的选项:

library(data.table)
DT <- data.table(ri=rep(1:20, n), v=as.vector(l))
dcast(DT, ri ~ v, length)

输出:

    ri   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20
 1:  1 499 506 481 507 434 498 537 493 495 474 504 506 545 499 492 467 510 527 507 519
 2:  2 506 513 473 521 520 492 508 518 469 520 491 463 495 520 499 526 502 481 492 491
 3:  3 481 499 510 480 506 499 493 522 512 507 516 484 516 482 536 476 509 477 500 495
 4:  4 502 498 519 532 493 522 481 515 542 488 471 496 466 443 460 505 531 481 532 523
 5:  5 497 468 523 492 475 430 502 491 526 514 490 528 460 498 471 557 488 547 521 522
 6:  6 514 505 497 506 533 505 482 462 536 508 482 533 505 497 527 496 479 479 479 475
 7:  7 525 522 511 476 502 536 508 486 495 452 493 506 507 498 530 498 475 478 498 504
 8:  8 544 450 521 528 491 497 534 503 504 497 506 464 485 501 511 467 478 484 523 512
 9:  9 442 515 515 507 496 515 460 537 528 510 490 500 526 510 499 508 497 517 465 463
10: 10 513 505 497 517 486 483 518 483 503 491 495 514 507 483 485 514 516 501 498 491
11: 11 480 530 491 486 503 507 517 487 467 499 504 497 496 521 499 444 525 511 500 536
12: 12 507 464 506 537 516 489 480 500 450 507 490 539 482 484 508 483 522 519 471 546
13: 13 501 527 521 443 510 527 507 507 492 547 486 465 515 544 504 472 502 529 456 445
14: 14 478 494 502 464 495 515 503 504 514 475 522 471 529 487 509 548 500 505 510 475
15: 15 489 513 488 505 532 487 506 525 438 530 534 497 494 475 491 494 468 499 544 491
16: 16 520 484 467 516 480 498 508 503 512 472 535 503 533 526 505 508 495 477 460 498
17: 17 512 465 491 514 516 469 487 485 491 465 522 550 494 514 506 542 508 476 490 503
18: 18 505 526 503 499 502 518 484 489 508 513 476 491 505 478 482 523 500 461 555 482
19: 19 528 508 492 488 513 513 493 474 500 510 467 474 463 543 482 495 523 522 505 507
20: 20 457 508 492 482 497 500 492 516 518 521 526 519 477 497 504 477 472 529 494 522

数据:

set.seed(0L)
n <- 1e4
l <- replicate(n, sample(20))

匿名用户

这在我两岁的Macbook Pro上花了大约1.4秒(尽管@chinsoon12的data.table解决方案要快得多——在我的机器上大约0.04秒):

library(tidyverse)

# Fake data matrix, 20 rows x 100,000 columns
n = 100000
set.seed(2)
d = replicate(n, sample(1:20))

# Convert to long data frame and count positions
d %>% 
  as_tibble() %>% 
  pivot_longer(cols=everything()) %>% 
  arrange(name) %>% 
  mutate(position = rep(1:20, n)) %>% 
  group_by(value, position) %>% 
  tally
   value position     n
   <int>    <int> <int>
 1     1        1  4901
 2     1        2  5031
 3     1        3  4980
 4     1        4  4997
 5     1        5  4959
 6     1        6  5004
 7     1        7  4888
 8     1        8  5021
 9     1        9  4970
10     1       10  4986
# … with 390 more rows