Question

J'ai commencé à croire que les trames de données détiennent aucun avantage sur les matrices, sauf pour la commodité notationnelle. Cependant, j'ai remarqué cette bizarrerie lors de l'exécution unique sur des matrices et des trames de données:. Il semble courir plus vite sur une trame de données

a   = matrix(sample(2,10^6,replace = TRUE), ncol = 10)
b   = as.data.frame(a)

system.time({
    u1 = unique(a)
})
 user  system elapsed
1.840   0.000   1.846


system.time({
    u2 = unique(b)
})
 user  system elapsed
0.380   0.000   0.379

Les résultats de cadencement divergent sensiblement plus que le nombre de lignes augmente. Donc, il y a deux parties à cette question.

  1. Pourquoi est-ce plus lent pour une matrice? Il semble plus rapide de se convertir à une trame de données, exécutez unique, puis reconvertir.

  2. Y at-il raison de ne pas simplement unique envelopper dans myUnique, qui fait les conversions en partie # 1?


Note 1. Etant donné qu'une matrice est atomique, il semble que unique devrait être plus rapide pour une matrice, plutôt que plus lente. Être capable d'itérer sur de taille fixe, des blocs contigus de mémoire doit être généralement plus rapide que la course des blocs séparés sur des listes chaînées (je suppose que la façon dont les cadres de données sont mises en œuvre ...).

Note 2. Comme l'ont démontré les performances de data.table, en cours d'exécution unique sur une trame de données ou une matrice est une idée relativement mauvaise - voir la réponse par Matthew Dowle et les commentaires des temps relatifs. J'ai migré beaucoup d'objets à des tables de données, et cette performance est une autre raison de le faire. Ainsi, bien que les utilisateurs devraient être bien servis à adopter des tableaux de données, pour des raisons pédagogiques / communautaires, je vais laisser la question ouverte pour l'instant en ce qui concerne la pourquoi Cette mesure tient plus sur des objets de la matrice. Les réponses ci-dessous l'adresse ne déplacement de temps, et comment les autres peut-on obtenir de meilleures performances (à savoir des tableaux de données). La réponse à pourquoi est à portée de main - le code peut être trouvé par unique.data.frame et unique.matrix. :) explication Une anglaise de ce qu'il fait et pourquoi est tout ce qui fait défaut.

Était-ce utile?

La solution

  1. Dans cette mise en œuvre, unique.matrix est le même que unique.array

    > identical(unique.array, unique.matrix)

    [1] TRUE

  2. unique.array doit gérer des tableaux multidimensionnels qui nécessite un traitement supplémentaire à « effondrement » des dimensions supplémentaires (ces appels supplémentaires à paste()) qui ne sont pas nécessaires dans le cas 2 dimensions. La section clé du code est:

    collapse <- (ndim > 1L) && (prod(dx[-MARGIN]) > 1L)

    temp <- if (collapse) apply(x, MARGIN, function(x) paste(x, collapse = "\r"))

  3. unique.data.frame est optimisé pour le cas 2D, unique.matrix est pas. Il pourrait être, comme vous le suggérez, il est tout simplement pas dans la mise en œuvre actuelle.

Notez que dans tous les cas (unique. {Tableau, matrice, data.table}) où il y a plus d'une dimension, il est la représentation de chaîne qui est comparée pour l'unicité. Pour les nombres à virgule flottante ce moyen 15 chiffres décimaux si

NROW(unique(a <- matrix(rep(c(1, 1+4e-15), 2), nrow = 2)))

est 1 tandis que

NROW(unique(a <- matrix(rep(c(1, 1+5e-15), 2), nrow = 2)))

et

NROW(unique(a <- matrix(rep(c(1, 1+4e-15), 1), nrow = 2)))

sont à la fois 2. Êtes-vous que unique est ce que vous voulez?

Autres conseils

  1. Je ne sais pas, mais je suppose que parce matrix est un vecteur contigu, des copies de R dans des vecteurs de première colonne (comme un data.frame) parce que paste a besoin d'une liste de vecteurs. Notez que les deux sont lents parce que les deux paste d'utilisation.

  2. Peut-être parce que unique.data.table est déjà plusieurs fois plus rapide. S'il vous plaît mettre à niveau v1.6.7 en le téléchargeant à partir du référentiel R-Forge parce que le correctif a pour unique que vous soulevez dans cette question. data.table n'utilise pas paste faire unique.

a = matrix(sample(2,10^6,replace = TRUE), ncol = 10)
b = as.data.frame(a)
system.time(u1<-unique(a))
   user  system elapsed 
   2.98    0.00    2.99 
system.time(u2<-unique(b))
   user  system elapsed 
   0.99    0.00    0.99 
c = as.data.table(b)
system.time(u3<-unique(c))
   user  system elapsed 
   0.03    0.02    0.05  # 60 times faster than u1, 20 times faster than u2
identical(as.data.table(u2),u3)
[1] TRUE

En tentant de répondre à ma propre question, en particulier la partie 1, nous pouvons voir où le temps est passé en regardant les résultats de Rprof. J'ai couru ce nouveau, avec des éléments 5M.

Voici les résultats pour la première opération unique, (pour la matrice):

> summaryRprof("u1.txt")
$by.self
                     self.time self.pct total.time total.pct
"paste"                   5.70    52.58       5.96     54.98
"apply"                   2.70    24.91      10.68     98.52
"FUN"                     0.86     7.93       6.82     62.92
"lapply"                  0.82     7.56       1.00      9.23
"list"                    0.30     2.77       0.30      2.77
"!"                       0.14     1.29       0.14      1.29
"c"                       0.10     0.92       0.10      0.92
"unlist"                  0.08     0.74       1.08      9.96
"aperm.default"           0.06     0.55       0.06      0.55
"is.null"                 0.06     0.55       0.06      0.55
"duplicated.default"      0.02     0.18       0.02      0.18

$by.total
                     total.time total.pct self.time self.pct
"unique"                  10.84    100.00      0.00     0.00
"unique.matrix"           10.84    100.00      0.00     0.00
"apply"                   10.68     98.52      2.70    24.91
"FUN"                      6.82     62.92      0.86     7.93
"paste"                    5.96     54.98      5.70    52.58
"unlist"                   1.08      9.96      0.08     0.74
"lapply"                   1.00      9.23      0.82     7.56
"list"                     0.30      2.77      0.30     2.77
"!"                        0.14      1.29      0.14     1.29
"do.call"                  0.14      1.29      0.00     0.00
"c"                        0.10      0.92      0.10     0.92
"aperm.default"            0.06      0.55      0.06     0.55
"is.null"                  0.06      0.55      0.06     0.55
"aperm"                    0.06      0.55      0.00     0.00
"duplicated.default"       0.02      0.18      0.02     0.18

$sample.interval
[1] 0.02

$sampling.time
[1] 10.84

Et pour la trame de données:

> summaryRprof("u2.txt")
$by.self
                     self.time self.pct total.time total.pct
"paste"                   1.72    94.51       1.72     94.51
"[.data.frame"            0.06     3.30       1.82    100.00
"duplicated.default"      0.04     2.20       0.04      2.20

$by.total
                        total.time total.pct self.time self.pct
"[.data.frame"                1.82    100.00      0.06     3.30
"["                           1.82    100.00      0.00     0.00
"unique"                      1.82    100.00      0.00     0.00
"unique.data.frame"           1.82    100.00      0.00     0.00
"duplicated"                  1.76     96.70      0.00     0.00
"duplicated.data.frame"       1.76     96.70      0.00     0.00
"paste"                       1.72     94.51      1.72    94.51
"do.call"                     1.72     94.51      0.00     0.00
"duplicated.default"          0.04      2.20      0.04     2.20

$sample.interval
[1] 0.02

$sampling.time
[1] 1.82

Ce que nous constatons est que la version de la matrice passe beaucoup de temps sur apply, paste et lapply. En revanche, la simple version de trame de données fonctionne duplicated.data.frame et la plupart du temps est consacré à paste, agrégation vraisemblablement des résultats.

Bien que cela explique le temps va, il n'explique pas pourquoi ceux-ci ont différentes implémentations, ni les effets de simple changement d'un type d'objet à un autre.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top