=head1 NAME DBD::SQLite::Cookbook - The DBD::SQLite Cookbook =head1 DESCRIPTION This is the L cookbook. It is intended to provide a place to keep a variety of functions and formals for use in callback APIs in L. =head2 Variance This is a simple aggregate function which returns a variance. It is adapted from an example implementation in pysqlite. package variance; sub new { bless [], shift; } sub step { my ( $self, $value ) = @_; push @$self, $value; } sub finalize { my $self = $_[0]; my $n = @$self; # Variance is NULL unless there is more than one row return undef unless $n || $n == 1; my $mu = 0; foreach my $v ( @$self ) { $mu += $v; } $mu /= $n; my $sigma = 0; foreach my $v ( @$self ) { $sigma += ($x - $mu)**2; } $sigma = $sigma / ($n - 1); return $sigma; } # NOTE: If you use an older DBI (< 1.608), # use $dbh->func(..., "create_aggregate") instead. $dbh->sqlite_create_aggregate( "variance", 1, 'variance' ); The function can then be used as: SELECT group_name, variance(score) FROM results GROUP BY group_name; =head2 Variance (Memory Efficient) A more efficient variance function, optimized for memory usage at the expense of precision: package variance2; my $sum = 0; my $count = 0; my %hash; sub new { bless [], shift; } sub step { my ( $self, $value ) = @_; # by truncating and hashing, we can comsume many more data points $value = int($value); # change depending on need for precision # use sprintf for arbitrary fp precision if (defined $hash{$value}) { $hash{$value}++; } else { $hash{$value} = 1; } $sum += $value; $count++; } sub finalize { my $self = $_[0]; # Variance is NULL unless there is more than one row return undef unless $count > 1; # calculate avg my $mu = $sum / $count; my $sigma = 0; foreach my $h (keys %hash) { $sigma += (($h - $mu)**2) * $hash{$h}; } $sigma = $sigma / ($count - 1); return $sigma; } The function can then be used as: SELECT group_name, variance2(score) FROM results GROUP BY group_name; =head2 Variance (Highly Scalable) A third variable implementation, designed for arbitrarily large data sets: package variance; my $mu = 0; my $count = 0; my $S = 0 sub new { bless [], shift; } sub step { my ( $self, $value ) = @_; $count++; $delta = $value - $mu; $mu = $mu + $delta/$count $S = $S + $delta*($value - $mu); } sub finalize { my $self = $_[0]; return $S / ($count - 1); } The function can then be used as: SELECT group_name, variance3(score) FROM results GROUP BY group_name; =head1 SUPPORT Bugs should be reported via the CPAN bug tracker at L =head1 TO DO * Add more and varied cookbook recipes, until we have enough to turn them into a seperate CPAN distribution. * Create a series of tests scripts that validate the cookbook recipies. =head1 AUTHOR Adam Kennedy Eadamk@cpan.orgE =head1 COPYRIGHT Copyright 2009 Adam Kennedy. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. The full text of the license can be found in the LICENSE file included with this module.