Je recherche un package de statistiques pour Perl (cpan va bien) qui me permet d'ajouter des données progressivement au lieu de devoir passer une gamme complète de données. P>
Juste la moyenne, la médiane, STDDEV, max et min est nécessaire, rien de trop compliqué. p>
La raison en est que mon jeu de données est entièrement trop volumineux pour s'adapter à la mémoire. La source de données est dans une base de données MySQL, alors je ne fais que interroger un sous-ensemble des données et informer les statistiques pour eux, puis combinant tous les sous-ensembles gérables plus tard. P>
Si vous avez d'autres idées sur la façon de surmonter cette question, je serais beaucoup obligé! P>
7 Réponses :
Soyez prudent - ce module (selon la POD) est optimisé pour les données discrétisées par exemple. données d'une conversion A / D ayant un ensemble discret de valeurs possibles. Par exemple. Si vos données sont produites par un 8 bits A / D, vous n'avez que 256 valeurs possibles dans votre ensemble de données. Même si vous pourriez avoir un million de points de données, vous aurez seulement 256 valeurs différentes de ces millions de points.
Vous ne pouvez pas faire exactement STDDEV et une médiane, sauf si vous gardez le tout dans la mémoire Le reste sont complètement triviaux (pas besoin d'un module) à faire dans 3 à 5 lignes de perl.
STDDEV / MEDIAN peut être fait en 2 passes assez trivialement aussi bien (je viens de déployer un script qui a fait exactement ce que vous avez décrit, mais pour des raisons IP, je suis sûr que je ne suis pas autorisé à le poster comme exemple pour vous, désolé ) p> code d'échantillon: p>
re $ somme * 1.0 / $ compte code>, Perl ne fait pas partie des opérations dactylographiées de la manière dont c fonctionne; Le * 1.0 est inutile.
Ce n'est pas vrai. Vous pouvez calculer une moyenne de streaming et std. Dev. Les détails sur l'algorithme peuvent être trouvés sur Wikipedia: en.wikipedia.org/wiki/... a>
+1 au dernier commentaire. Bien que les formules dans ce wiki soient des approximations seulement, toujours, wow-cool!
Pourquoi ne demandez-vous pas simplement à la base de données des valeurs que vous essayez de calculer? p>
Parmi d'autres, MySQL fonctionne Groupe par (agrégat ) Fonctions . Pour les fonctions manquantes, tout ce dont vous avez besoin est Un peu SQL . p>
Bien que cela puisse être correct pour son projet, le calcul de la statistique est souvent fortement recommandé d'être déchargé au code de l'application, car il est beaucoup plus facile d'accabler les ressources du serveur d'applications que DB Server.
@DVK: Je ne suis pas sûr d'acheter cette objection. Les ressources nécessaires à l'exportation des Data i> nécessaires au serveur d'applications pour effectuer ses propres statistiques sont beaucoup plus grandes que de permettre au serveur DB de les calculer eux-mêmes?
PDL peut fournir une solution possible:
Regardez cette réponse précédente qui montre comment Pour obtenir signifie, std dev, etc . P>
Voici une partie pertinente du code répété ici: p>
Ceci est largement non testé, alors utilisez-vous avec soin. Comme j'ai une mauvaise mémoire, j'ai vérifié l'algorithme contre Wikipedia . Je ne suis pas au courant d'un algorithme de calculer la médiane d'un flux de chiffres, mais cela ne signifie pas qu'il n'y en a pas.
#!/usr/bin/perl use strict; use warnings; use MooseX::Declare; class SimpleStats { has 'min' => (is => 'rw', isa => 'Num', default => 9**9**9); has 'max' => (is => 'rw', isa => 'Num', default => -9**9**9); has 'A' => (is => 'rw', isa => 'Num', default => 0); has 'Q' => (is => 'rw', isa => 'Num', default => 0); has 'n' => (is => 'rw', isa => 'Int', default => 0); has 'n_nonzero' => (is => 'rw', isa => 'Int', default => 0); has 'sum_w' => (is => 'rw', isa => 'Int', default => 0); method add (Num $x, Num $w = 1) { $self->min($x) if $x < $self->min; $self->max($x) if $x > $self->max; my $n = $self->n; if ($n == 0) { $self->A($x); $self->sum_w($w); } else { my $A = $self->A; my $Q = $self->Q; my $sum_w_before = $self->sum_w; $self->sum_w($sum_w_before+$w); $self->A($A + ($x-$A) * $w/$self->sum_w); $self->Q($Q + $w*($x-$A)*($x-$self->A)); } $self->n($n+1); $self->n_nonzero($self->n_nonzero+1) if $w != 0; return(); } method mean () { $self->A } method sample_variance () { $self->Q * $self->n_nonzero() / ( ($self->n_nonzero-1) * $self->sum_w ) } method std_variance () { $self->Q / $self->sum_w } method std_dev () { sqrt($self->std_variance) } # slightly evil. Just don't reuse objects method reset () { %$self = %{__PACKAGE__->new()} } } package main; my $stats = SimpleStats->new; while (<STDIN>) { s/^\s+//; s/\s+$//; my ($x, $w) = split /\s+/, $_; if (defined $w) { $stats->add($x, $w); } else { $stats->add($x); } } print "Mean: ", $stats->mean, "\n"; print "Sample var: ", $stats->sample_variance, "\n"; print "Std var: ", $stats->std_variance, "\n"; print "Std dev: ", $stats->std_dev, "\n"; print "Entries: ", $stats->n, "\n"; print "Min: ", $stats->min, "\n"; print "Max: ", $stats->max, "\n";
@DVK: les algorithmes d'un laissez-passer pour calculer la moyenne et la déviation standard ici http: / /en.wikipedia.org/wiki/algorithms_for_calculant_variance#on-line_algorithm ne sont pas des approximations et sont plus solides de manière numérique que l'exemple que vous donnez. Voir Références sur cette page. P>
Je comprends que c'est 4 ans sur la route, mais au cas où n'importe qui est intéressé, il y a maintenant un Module pour l'efficacité de la mémoire Il divise l'échantillon en intervalles logarithmiques et ne cesse que les comptes touchés. Ainsi, une erreur relative fixe est introduite (la précision peut être ajustée dans NOUVEAU ()), mais de grandes quantités de données peuvent être traitées sans utiliser beaucoup de mémoire. P>