1
votes

Existe-t-il une version plus efficace de la correspondance pour rechercher des permutations répétées de nombres?

J'ai un ensemble de données avec 20 lignes et n colonnes. Je travaillais à l'origine avec n = 10000, mais j'ai constaté que je devais utiliser un nombre beaucoup plus grand, probablement plus de dix fois plus. Chaque colonne de cet ensemble de données est générée indépendamment des autres et contient une permutation aléatoire mais biaisée des nombres entiers de 1 à 20. Je souhaite additionner les emplacements de chaque nombre sur l'ensemble de données. En d'autres termes, je veux savoir combien de fois le nombre a est apparu en position b pour chaque a et b (c'est-à-dire que mon résultat final est une table de valeurs 20 * 20). qui atteint cet objectif. Par exemple, mon ordinateur gère toute la cause n = 10000 en moins de deux minutes (c'est-à-dire qu'il me donne le décompte pour chaque a et b). Cependant, n = 100000 et le moindre n = 50000 ont pris tellement de temps que ma patience s'est épuisée. La plupart de mon code est extrêmement simple et je suis convaincu que l'inefficacité réside dans l'utilisation de match dans les lignes suivantes ( a , b , et n sont comme décrit ci-dessus, data est l'ensemble de données):

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

comment puis-je améliorer cela? match semble être notoirement lent , mais toutes les solutions que j'ai vues ( exemple ) ne sont ni une solution générale ni applicable à ce cas.

Si vous souhaitez évaluer votre solution replicate (n, sample (20)) générera une liste similaire à mon ensemble de données.


4 commentaires

Salut J. Mini, il serait plus facile d'aider si vous fournissez un code de travail qui produit les résultats attendus.


@IanCampbell Cela semble être une complication inutile. Je l'ai isolé aux lignes que je crois fermement être les seules pertinentes et j'ai donné ce que je pense être un contexte adéquat. L'alternative augmenterait la quantité de code dans cette question à plusieurs reprises et le contexte supplémentaire requis pourrait potentiellement confondre le problème.


Je ne suis pas d'accord, avoir le résultat attendu offre la possibilité d'utiliser une technique orthogonale et de valider facilement le résultat, comme le montre @ chinsoon12.


Ce que @IanCampbell dit, c'est que vous devez donner un exemple de ce qu'est a , qu'est-ce que b et montrer quelle sortie vous obtenez de sum (list == b ) . Pas besoin d'augmenter ne serait-ce qu'une seule ligne de code, définissez simplement a et b .


5 Réponses :


2
votes

Je pense que le principal goulot d'étranglement est que vous augmentez la taille du vecteur dans la boucle. Essayez de l'initialiser avant la boucle et attribuez la valeur dans le vecteur.

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

Ou en utilisant sapply

list_vec <- numeric(length = n)

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


2 commentaires

Sauf erreur de ma part, ces deux blocs de code ne sont pas équivalents. Peut-être que vous vouliez apply (data, 2, function (x) match (a, x)) ?


apply (data, 2, fn) équivaut à sapply (data, fn) ou lapply (data, fn) .



1
votes

Une option utilisant data.table :

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

output:

    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

data: p >

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


0 commentaires

1
votes

Cela a pris environ 1,4 seconde sur mon Macbook Pro de deux ans (bien que la solution data.table de @ chinsoon12 soit beaucoup plus rapide - environ 0,04 seconde sur ma machine):

   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
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


0 commentaires

0
votes

Évitez de faire croître des objets dans une boucle et de tenir compte de l'initialisation puis de l'affectation aux objets. Considérez sapply ou légèrement plus rapide, vapply (qui vérifie le type et la longueur du retour):

myVec <- sapply(seq(n), function(k) match(a, data[,k]))
sum(myVec==b)

myVec <- vapply(seq(n), function(k) match(a, data[,k]), integer(1))
sum(myVec==b)


0 commentaires

1
votes

Si je comprends bien, cela peut être fait rapidement, sans aucun package:

n <- 10000
k <- 20
data <- replicate(n, sample(k))


## The result: a k times k array.
## E.g. result[1, 5] tells you how often 
## 5 appears in row 1.

result <- array(NA, dim = c(k, k))


for (i in 1:k) {
    tmp <- data[seq(i, to = length(data), by = k)]
    for (j in 1:k)
        result[i, j] <- sum(tmp == j)
}

Pour un million d'échantillons ( n == 1e6 ), il faut environ 2 secondes environ.


0 commentaires